From 99d9b6cbb562c87e87ca0fc2a6465b387e486157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 7 Jul 2020 16:42:49 +0200 Subject: [PATCH 001/742] convert some .inverse to .__invert__ and make a global alias in magmas cat --- .../hecke_algebras/ariki_koike_algebra.py | 6 ++-- src/sage/algebras/iwahori_hecke_algebra.py | 6 ++-- src/sage/algebras/yokonuma_hecke_algebra.py | 7 ++--- ...eflection_or_generalized_coxeter_groups.py | 6 ++-- src/sage/categories/magmas.py | 30 +++++++++++++++++++ src/sage/combinat/affine_permutation.py | 8 ++--- src/sage/combinat/colored_permutations.py | 12 +++----- .../combinat/root_system/fundamental_group.py | 6 ++-- .../hyperbolic_space/hyperbolic_isometry.py | 8 ++--- src/sage/groups/abelian_gps/element_base.py | 14 ++++----- src/sage/groups/abelian_gps/values.py | 9 ++---- src/sage/groups/affine_gps/group_element.py | 10 +++---- src/sage/groups/group_exp.py | 6 ++-- src/sage/groups/group_semidirect_product.py | 11 +++---- src/sage/modular/pollack_stevens/sigma0.py | 8 +++-- src/sage/structure/element.pyx | 7 +---- 16 files changed, 75 insertions(+), 79 deletions(-) diff --git a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py index b78b7691e7b..2e4ddb6a4bd 100644 --- a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py +++ b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py @@ -1126,7 +1126,7 @@ def inverse_T(self, i): return self._from_dict({m: ~self._q, self.one_basis(): c}) class Element(CombinatorialFreeModule.Element): - def inverse(self): + def __invert__(self): r""" Return the inverse if ``self`` is a basis element. @@ -1135,7 +1135,7 @@ def inverse(self): sage: LT = algebras.ArikiKoike(3, 4).LT() sage: t = LT.T(1) * LT.T(2) * LT.T(3); t T[1,2,3] - sage: t.inverse() + sage: t.inverse() # indirect doctest (q^-3-3*q^-2+3*q^-1-1) + (q^-3-2*q^-2+q^-1)*T[3] + (q^-3-2*q^-2+q^-1)*T[2] + (q^-3-q^-2)*T[3,2] + (q^-3-2*q^-2+q^-1)*T[1] + (q^-3-q^-2)*T[1,3] @@ -1149,8 +1149,6 @@ def inverse(self): H = self.parent() return ~self[l,w] * H.prod(H.inverse_T(i) for i in reversed(w.reduced_word())) - __invert__ = inverse - class T(_Basis): r""" The basis of the Ariki-Koike algebra given by monomials of the diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index ae50b39a3e0..b779269b2f8 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1727,7 +1727,7 @@ class Element(CombinatorialFreeModule.Element): sage: T1.parent() Iwahori-Hecke algebra of type A2 in 1,-1 over Integer Ring in the T-basis """ - def inverse(self): + def __invert__(self): r""" Return the inverse if ``self`` is a basis element. @@ -1741,7 +1741,7 @@ def inverse(self): sage: R. = LaurentPolynomialRing(QQ) sage: H = IwahoriHeckeAlgebra("A2", q).T() sage: [T1,T2] = H.algebra_generators() - sage: x = (T1*T2).inverse(); x + sage: x = (T1*T2).inverse(); x # indirect doctest (q^-2)*T[2,1] + (q^-2-q^-1)*T[1] + (q^-2-q^-1)*T[2] + (q^-2-2*q^-1+1) sage: x*T1*T2 1 @@ -1766,8 +1766,6 @@ def inverse(self): return H.prod(H.inverse_generator(i) for i in reversed(w.reduced_word())) - __invert__ = inverse - standard = T class _KLHeckeBasis(_Basis): diff --git a/src/sage/algebras/yokonuma_hecke_algebra.py b/src/sage/algebras/yokonuma_hecke_algebra.py index dde7772e227..a8c74e25f0b 100644 --- a/src/sage/algebras/yokonuma_hecke_algebra.py +++ b/src/sage/algebras/yokonuma_hecke_algebra.py @@ -454,7 +454,7 @@ def inverse_g(self, i): return self.g(i) + (~self._q + self._q) * self.e(i) class Element(CombinatorialFreeModule.Element): - def inverse(self): + def __invert__(self): r""" Return the inverse if ``self`` is a basis element. @@ -463,7 +463,7 @@ def inverse(self): sage: Y = algebras.YokonumaHecke(3, 3) sage: t = prod(Y.t()); t t1*t2*t3 - sage: ~t + sage: t.inverse() # indirect doctest t1^2*t2^2*t3^2 sage: [3*~(t*g) for g in Y.g()] [(q^-1+q)*t2*t3^2 + (q^-1+q)*t1*t3^2 @@ -494,6 +494,3 @@ def inverse(self): c = ~self.coefficients()[0] telt = H.monomial( (tuple((H._d - e) % H._d for e in t), H._Pn.one()) ) return c * telt * H.prod(H.inverse_g(i) for i in reversed(w.reduced_word())) - - __invert__ = inverse - diff --git a/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py b/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py index 720d0097632..daa36275cf9 100644 --- a/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py +++ b/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py @@ -1141,7 +1141,7 @@ def _mul_(self, other): """ return self.apply_simple_reflections(other.reduced_word()) - def inverse(self): + def __invert__(self): """ Return the inverse of ``self``. @@ -1149,7 +1149,7 @@ def inverse(self): sage: W = WeylGroup(['B',7]) sage: w = W.an_element() - sage: u = w.inverse() + sage: u = w.inverse() # indirect doctest sage: u == ~w True sage: u * w == w * u @@ -1165,8 +1165,6 @@ def inverse(self): """ return self.parent().one().apply_simple_reflections(self.reduced_word_reverse_iterator()) - __invert__ = inverse - def apply_conjugation_by_simple_reflection(self, i): r""" Conjugate ``self`` by the ``i``-th simple reflection. diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index 8073599c0d3..7631a4fcd37 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -589,6 +589,36 @@ def _div_(left, right): """ return left * ~right + def __invert__(self): + r""" + Return the inverse of ``self``. + + The default implementation is to divide ``self.one()``. + + EXAMPLES:: + + sage: A = Matrix([[1, 0], [1, 1]]) + sage: ~A + [ 1 0] + [-1 1] + """ + return self._parent.one()._div_(self) + + def inverse(self): + """ + Return the inverse of ``self``. + + This an alias for inversion, defined in ``  invert__``. + + Element classes should implement ``  invert__`` only. + + EXAMPLES:: + + sage: AA(sqrt(~2)).inverse() + 1.414213562373095? + """ + return self.__invert__() + class SubcategoryMethods: @cached_method diff --git a/src/sage/combinat/affine_permutation.py b/src/sage/combinat/affine_permutation.py index f550c1413e0..33d24cc7c5f 100644 --- a/src/sage/combinat/affine_permutation.py +++ b/src/sage/combinat/affine_permutation.py @@ -161,21 +161,19 @@ def __mul__(self, q): return self.__rmul__(q) @cached_method - def inverse(self): + def __invert__(self): r""" Return the inverse affine permutation. EXAMPLES:: sage: p = AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9]) - sage: p.inverse() + sage: p.inverse() # indirect doctest Type A affine permutation with window [0, -1, 1, 6, 5, 4, 10, 11] """ - inv = [self.position(i) for i in range(1,len(self)+1)] + inv = [self.position(i) for i in range(1, len(self) + 1)] return type(self)(self.parent(), inv, check=False) - __invert__=inverse - def apply_simple_reflection(self, i, side='right'): r""" Apply a simple reflection. diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index 2227ee6f293..f0f7f58c023 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -97,7 +97,7 @@ def _mul_(self, other): p = self._perm._left_to_right_multiply_on_right(other._perm) return self.__class__(self.parent(), colors, p) - def inverse(self): + def __invert__(self): """ Return the inverse of ``self``. @@ -105,7 +105,7 @@ def inverse(self): sage: C = ColoredPermutations(4, 3) sage: s1,s2,t = C.gens() - sage: ~t + sage: ~t # indirect doctest [[0, 0, 3], [1, 2, 3]] sage: all(x * ~x == C.one() for x in C.gens()) True @@ -115,8 +115,6 @@ def inverse(self): tuple([-self._colors[i - 1] for i in ip]), # -1 for indexing ip) - __invert__ = inverse - def __eq__(self, other): """ Check equality. @@ -982,7 +980,7 @@ def _mul_(self, other): p = self._perm._left_to_right_multiply_on_right(other._perm) return self.__class__(self.parent(), colors, p) - def inverse(self): + def __invert__(self): """ Return the inverse of ``self``. @@ -991,7 +989,7 @@ def inverse(self): sage: S = SignedPermutations(4) sage: s1,s2,s3,s4 = S.gens() sage: x = s4*s1*s2*s3*s4 - sage: ~x + sage: ~x # indirect doctest [2, 3, -4, -1] sage: x * ~x == S.one() True @@ -1001,8 +999,6 @@ def inverse(self): tuple([self._colors[i - 1] for i in ip]), # -1 for indexing ip) - __invert__ = inverse - def __iter__(self): """ Iterate over ``self``. diff --git a/src/sage/combinat/root_system/fundamental_group.py b/src/sage/combinat/root_system/fundamental_group.py index 7c097ad7fe3..53117f4213c 100644 --- a/src/sage/combinat/root_system/fundamental_group.py +++ b/src/sage/combinat/root_system/fundamental_group.py @@ -249,7 +249,7 @@ def _repr_(self): """ return self.parent()._prefix + "[" + repr(self.value()) + "]" - def inverse(self): + def __invert__(self): r""" Return the inverse element of ``self``. @@ -257,7 +257,7 @@ def inverse(self): sage: from sage.combinat.root_system.fundamental_group import FundamentalGroupOfExtendedAffineWeylGroup sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',3,1]) - sage: F(1).inverse() + sage: F(1).inverse() # indirect doctest pi[3] sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['E',6,1], prefix="f") sage: F(1).inverse() @@ -266,8 +266,6 @@ def inverse(self): par = self.parent() return self.__class__(par, par.dual_node(self.value())) - __invert__ = inverse - def _richcmp_(self, x, op): r""" Compare ``self`` with `x`. diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py index 418e3eccbc5..bcdbde6063d 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py @@ -323,7 +323,7 @@ def matrix(self): """ return self._matrix - def inverse(self): + def __invert__(self): r""" Return the inverse of the isometry ``self``. @@ -331,13 +331,11 @@ def inverse(self): sage: UHP = HyperbolicPlane().UHP() sage: A = UHP.get_isometry(matrix(2,[4,1,3,2])) - sage: B = A.inverse() + sage: B = A.inverse() # indirect doctest sage: A*B == UHP.get_isometry(identity_matrix(2)) True """ - return self.__class__(self.domain(), self.matrix().inverse()) - - __invert__ = inverse + return self.__class__(self.domain(), self.matrix().__invert__()) def is_identity(self): """ diff --git a/src/sage/groups/abelian_gps/element_base.py b/src/sage/groups/abelian_gps/element_base.py index d5b93a3f918..c1eec7ecb1f 100644 --- a/src/sage/groups/abelian_gps/element_base.py +++ b/src/sage/groups/abelian_gps/element_base.py @@ -15,7 +15,7 @@ # Copyright (C) 2012 Volker Braun # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ########################################################################### from sage.structure.element import MultiplicativeGroupElement @@ -298,14 +298,14 @@ def __pow__(self, n): for e,order in zip(self._exponents, G.gens_orders()) ] return G.element_class(G, exponents) - def inverse(self): + def __invert__(self): """ - Returns the inverse element. + Return the inverse element. EXAMPLES:: sage: G. = AbelianGroup([0,5]) - sage: a.inverse() + sage: a.inverse() # indirect doctest a^-1 sage: a.__invert__() a^-1 @@ -319,12 +319,10 @@ def inverse(self): (-1, 4) """ G = self.parent() - exponents = [ (-e)%order if order!=0 else -e - for e,order in zip(self._exponents, G.gens_orders()) ] + exponents = [(-e) % order if order != 0 else -e + for e, order in zip(self._exponents, G.gens_orders())] return G.element_class(G, exponents) - __invert__ = inverse - def is_trivial(self): """ Test whether ``self`` is the trivial group element ``1``. diff --git a/src/sage/groups/abelian_gps/values.py b/src/sage/groups/abelian_gps/values.py index 288fb95b93c..e3d681af428 100644 --- a/src/sage/groups/abelian_gps/values.py +++ b/src/sage/groups/abelian_gps/values.py @@ -330,14 +330,14 @@ def __pow__(self, n): pow_self._value = pow(self.value(), m) return pow_self - def inverse(self): + def __invert__(self): """ Return the inverse element. EXAMPLES:: sage: G. = AbelianGroupWithValues([2,-1], [0,4]) - sage: a.inverse() + sage: a.inverse() # indirect doctest a^-1 sage: a.inverse().value() 1/2 @@ -350,13 +350,10 @@ def inverse(self): sage: (a*b).inverse().value() -1/2 """ - m = AbelianGroupElement.inverse(self) + m = AbelianGroupElement.__invert__(self) m._value = ~self.value() return m - __invert__ = inverse - - class AbelianGroupWithValues_class(AbelianGroup_class): """ diff --git a/src/sage/groups/affine_gps/group_element.py b/src/sage/groups/affine_gps/group_element.py index bc8257b5471..5b107cbc194 100644 --- a/src/sage/groups/affine_gps/group_element.py +++ b/src/sage/groups/affine_gps/group_element.py @@ -381,7 +381,7 @@ def _act_on_(self, x, self_on_left): if self_on_left: return self(x) - def inverse(self): + def __invert__(self): """ Return the inverse group element. @@ -399,19 +399,17 @@ def inverse(self): sage: ~g [1 1] [1] x |-> [0 1] x + [0] - sage: g * g.inverse() + sage: g * g.inverse() # indirect doctest [1 0] [0] x |-> [0 1] x + [0] sage: g * g.inverse() == g.inverse() * g == G(1) True """ parent = self.parent() - A = parent.matrix_space()(self._A.inverse()) - b = -A*self.b() + A = parent.matrix_space()(~self._A) + b = -A * self.b() return parent.element_class(parent, A, b, check=False) - __invert__ = inverse - def _richcmp_(self, other, op): """ Compare ``self`` with ``other``. diff --git a/src/sage/groups/group_exp.py b/src/sage/groups/group_exp.py index bf0db4aa837..3ffa13a6ebf 100644 --- a/src/sage/groups/group_exp.py +++ b/src/sage/groups/group_exp.py @@ -211,20 +211,18 @@ def __init__(self, parent, x): raise ValueError("%s is not an element of %s" % (x, parent._G)) ElementWrapper.__init__(self, parent, x) - def inverse(self): + def __invert__(self): r""" Invert the element ``self``. EXAMPLES:: sage: EZ = GroupExp()(ZZ) - sage: EZ(-3).inverse() + sage: EZ(-3).inverse() # indirect doctest 3 """ return GroupExpElement(self.parent(), -self.value) - __invert__ = inverse - def __mul__(self, x): r""" Multiply ``self`` by `x`. diff --git a/src/sage/groups/group_semidirect_product.py b/src/sage/groups/group_semidirect_product.py index d5b8b6b62de..cb99b637b91 100644 --- a/src/sage/groups/group_semidirect_product.py +++ b/src/sage/groups/group_semidirect_product.py @@ -58,9 +58,9 @@ def wrapper(prefix, s): return gstr return gstr + " * " + hstr - def inverse(self): + def __invert__(self): r""" - The inverse of ``self``. + Return the inverse of ``self``. EXAMPLES:: @@ -75,19 +75,16 @@ def inverse(self): s1*s2 * t[2*alpha[1] + 2*alpha[2]] sage: g.inverse() s2*s1 * t[2*alpha[1]] - """ par = self.parent() g = self.cartesian_projection(0) h = self.cartesian_projection(1) if par.act_to_right(): - return self.__class__(par,(~g, par._twist(g,~h))) + return self.__class__(par, (~g, par._twist(g, ~h))) else: hi = ~h - return self.__class__(par,(par._twist(hi,~g),hi)) - - __invert__ = inverse + return self.__class__(par, (par._twist(hi, ~g), hi)) def to_opposite(self): r""" diff --git a/src/sage/modular/pollack_stevens/sigma0.py b/src/sage/modular/pollack_stevens/sigma0.py index 6ff9b24b551..eed9e244cd2 100644 --- a/src/sage/modular/pollack_stevens/sigma0.py +++ b/src/sage/modular/pollack_stevens/sigma0.py @@ -295,15 +295,17 @@ def matrix(self): """ return self._mat - def inverse(self): + def __invert__(self): r""" - Return the inverse of self. This will raise an error if the result is not in the monoid. + Return the inverse of ``self``. + + This will raise an error if the result is not in the monoid. EXAMPLES:: sage: from sage.modular.pollack_stevens.sigma0 import Sigma0 sage: s = Sigma0(3)([1,4,3,13]) - sage: s.inverse() + sage: s.inverse() # indirect doctest [13 -4] [-3 1] sage: Sigma0(3)([1, 0, 0, 3]).inverse() diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index b1a64b9cbba..2e2f3d574b7 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -2555,12 +2555,6 @@ cdef class MultiplicativeGroupElement(MonoidElement): """ return self * ~right - def __invert__(self): - r""" - Return the inverse of ``self``. - """ - return self._parent.one() / self - def is_RingElement(x): """ @@ -2568,6 +2562,7 @@ def is_RingElement(x): """ return isinstance(x, RingElement) + cdef class RingElement(ModuleElement): cpdef _mul_(self, other): """ From 1a1ec14fcae40bc98284b74ef3a2d3d5e55461a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 7 Jul 2020 19:26:45 +0200 Subject: [PATCH 002/742] fix some details --- src/sage/categories/magmas.py | 4 ++-- src/sage/rings/number_field/class_group.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index 7631a4fcd37..9dbf5a25f25 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -608,9 +608,9 @@ def inverse(self): """ Return the inverse of ``self``. - This an alias for inversion, defined in ``  invert__``. + This an alias for inversion, defined in ``__invert__``. - Element classes should implement ``  invert__`` only. + Element classes should implement ``__invert__`` only. EXAMPLES:: diff --git a/src/sage/rings/number_field/class_group.py b/src/sage/rings/number_field/class_group.py index 46d0ca8c9d3..04e1b06983a 100644 --- a/src/sage/rings/number_field/class_group.py +++ b/src/sage/rings/number_field/class_group.py @@ -184,7 +184,7 @@ def inverse(self): sage: ~G(2, a) Fractional ideal class (2, a^2 + 2*a - 1) """ - m = AbelianGroupElement.inverse(self) + m = AbelianGroupElement.__invert__(self) m._value = (~self.ideal()).reduce_equiv() return m From 9d5692d26c4bf8ad4aa8eb1a9f2cbaab5f35b842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 7 Jul 2020 21:35:39 +0200 Subject: [PATCH 003/742] fix some doctests in polynomial quotient rings --- src/sage/rings/polynomial/polynomial_quotient_ring.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring.py b/src/sage/rings/polynomial/polynomial_quotient_ring.py index 05e3ff50a53..cdc294cff2d 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring.py @@ -320,7 +320,7 @@ class of the category, and store the current class of the quotient sage: isinstance(Q.an_element(),Q.element_class) True sage: [s for s in dir(Q.category().element_class) if not s.startswith('_')] - ['cartesian_product', 'inverse_of_unit', 'is_idempotent', 'is_one', 'is_unit', 'lift', 'powers'] + ['cartesian_product', 'inverse', 'inverse_of_unit', 'is_idempotent', 'is_one', 'is_unit', 'lift', 'powers'] sage: first_class = Q.__class__ We try to find out whether `Q` is a field. Indeed it is, and thus its category, @@ -338,6 +338,7 @@ class of the category, and store the current class of the quotient 'euclidean_degree', 'factor', 'gcd', + 'inverse', 'inverse_of_unit', 'is_idempotent', 'is_one', From fbc929ef8a01b017641838c47287e141ea96f8f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 8 Jul 2020 08:31:38 +0200 Subject: [PATCH 004/742] some pycodestyle details (breaking some lines after : and ;) --- src/sage/combinat/affine_permutation.py | 23 ++++++++++++------- .../polynomial/polynomial_quotient_ring.py | 9 +++++--- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/affine_permutation.py b/src/sage/combinat/affine_permutation.py index 33d24cc7c5f..0f67a89fa81 100644 --- a/src/sage/combinat/affine_permutation.py +++ b/src/sage/combinat/affine_permutation.py @@ -708,10 +708,14 @@ def maximal_cyclic_factor(self, typ='decreasing', side='right', verbose=False): T = [i] j = i for count in range(1,self.k): - if (typ[0],side[0]) == ('d','r'): j=(j+1)%(k+1) - if (typ[0],side[0]) == ('i','r'): j=(j-1)%(k+1) - if (typ[0],side[0]) == ('d','l'): j=(j-1)%(k+1) - if (typ[0],side[0]) == ('i','l'): j=(j+1)%(k+1) + if (typ[0],side[0]) == ('d','r'): + j=(j+1)%(k+1) + if (typ[0],side[0]) == ('i','r'): + j=(j-1)%(k+1) + if (typ[0],side[0]) == ('d','l'): + j=(j-1)%(k+1) + if (typ[0],side[0]) == ('i','l'): + j=(j+1)%(k+1) if y.has_descent(j, side): y=y.apply_simple_reflection(j,side) T.append(j%(k+1)) @@ -849,9 +853,10 @@ def to_lehmer_code(self, typ='decreasing', side='right'): a=self(i) for j in range(i-self.k, i): b=self(j) - #A small rotation is necessary for the reduced word from - #the lehmer code to match the element. - if a Date: Wed, 8 Jul 2020 08:37:23 +0200 Subject: [PATCH 005/742] fix one wrong use of parent --- src/sage/categories/magmas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index 9dbf5a25f25..58ccb1d2476 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -602,7 +602,7 @@ def __invert__(self): [ 1 0] [-1 1] """ - return self._parent.one()._div_(self) + return self.parent().one()._div_(self) def inverse(self): """ From 5e7e19afded220ad7e88b6362e7f98448a46df04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 19 Aug 2020 10:08:36 +0200 Subject: [PATCH 006/742] tentative fix, move inversion to monoids --- src/sage/categories/magmas.py | 30 ------------------------- src/sage/categories/monoids.py | 30 +++++++++++++++++++++++++ src/sage/monoids/free_monoid_element.py | 7 ++++-- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index ba6a5b7135f..89af2269084 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -589,36 +589,6 @@ def _div_(left, right): """ return left * ~right - def __invert__(self): - r""" - Return the inverse of ``self``. - - The default implementation is to divide ``self.one()``. - - EXAMPLES:: - - sage: A = Matrix([[1, 0], [1, 1]]) - sage: ~A - [ 1 0] - [-1 1] - """ - return self.parent().one()._div_(self) - - def inverse(self): - """ - Return the inverse of ``self``. - - This an alias for inversion, defined in ``__invert__``. - - Element classes should implement ``__invert__`` only. - - EXAMPLES:: - - sage: AA(sqrt(~2)).inverse() - 1.414213562373095? - """ - return self.__invert__() - class SubcategoryMethods: @cached_method diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index 42b55b8dda4..d598a6cecb3 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -313,6 +313,36 @@ def powers(self, n): l.append(x) return l + def __invert__(self): + r""" + Return the inverse of ``self``. + + The default implementation is to divide ``self.one()``. + + EXAMPLES:: + + sage: A = Matrix([[1, 0], [1, 1]]) + sage: ~A + [ 1 0] + [-1 1] + """ + return self.parent().one()._div_(self) + + def inverse(self): + """ + Return the inverse of ``self``. + + This an alias for inversion, defined in ``__invert__``. + + Element classes should implement ``__invert__`` only. + + EXAMPLES:: + + sage: AA(sqrt(~2)).inverse() + 1.414213562373095? + """ + return self.__invert__() + class Commutative(CategoryWithAxiom): r""" Category of commutative (abelian) monoids. diff --git a/src/sage/monoids/free_monoid_element.py b/src/sage/monoids/free_monoid_element.py index 549f9381e94..0da37bb9adf 100644 --- a/src/sage/monoids/free_monoid_element.py +++ b/src/sage/monoids/free_monoid_element.py @@ -21,7 +21,7 @@ # See the GNU General Public License for more details; the full text # is available at: # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from sage.rings.integer import Integer @@ -102,7 +102,7 @@ def __hash__(self): def __iter__(self): """ - Returns an iterator which yields tuples of variable and exponent. + Return an iterator which yields tuples of variable and exponent. EXAMPLES:: @@ -257,6 +257,9 @@ def _mul_(self, y): z._element_list = x_elt[:k] + [ m ] + y_elt[1:] return z + def __invert__(self): + raise NotImplementedError + def __len__(self): """ Return the degree of the monoid element ``self``, where each From bc7fe1e67d9788991fdb5f1487d14c3ac44a4f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 8 Nov 2020 10:17:19 +0100 Subject: [PATCH 007/742] add doctests in free_monoid_element --- src/sage/monoids/free_monoid_element.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sage/monoids/free_monoid_element.py b/src/sage/monoids/free_monoid_element.py index 7345a251464..9bdb03802df 100644 --- a/src/sage/monoids/free_monoid_element.py +++ b/src/sage/monoids/free_monoid_element.py @@ -48,7 +48,7 @@ class FreeMonoidElement(MonoidElement): sage: x**(-1) Traceback (most recent call last): ... - TypeError: bad operand type for unary ~: 'FreeMonoid_with_category.element_class' + NotimplementedError """ def __init__(self, F, x, check=True): """ @@ -255,6 +255,16 @@ def _mul_(self, y): return z def __invert__(self): + """ + EXAMPLES:: + + sage: a = FreeMonoid(5, 'a').gens() + sage: x = a[0]*a[1]*a[4]**3 + sage: x**(-1) + Traceback (most recent call last): + ... + NotimplementedError + """ raise NotImplementedError def __len__(self): From 0e35336b8ab50524db307c772f930ce144889672 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Tue, 10 Aug 2021 14:59:47 +0100 Subject: [PATCH 008/742] Addition of abel_jacobi methods and edits to architecture. This commit contains a large amount of work, combined together. 1) The structure of many method that use upstairs_edge have been changed to allow for the flexibilty that now an edge need not correspond to an edge of the voronoi diagram, but can instead be specified by a tuple (z_start, z_end). This mean that methods such as simple_vector_line_integral can now integrate along paths that are not part of the skeleton. 2) Methods for the calculation of the Abel-Jacobi map, namely _integrate_differentials_iteratively, _aj_based, abel_jacobi and reparameterise_differential_minpoly, have been added. 3) __init__ has been changed to now include the branchpoints of the output of cohomology_basis() in self.branch_locus. The branch locus of just self.f is now stored in self._f_branch locus. This is useful when calculating the Abel-Jacobi map. As a result the voronoi diagram for a given curve may now be different, and this is reflected in the examples and tests for certain methods. 4) A method for the upstairs graph has been added, which is useful when calculating the Abel-Jacobi map. 5) Matrix of integral values now writes the output of line integrals to self._integral_dict if the differentials are the cohomology basis. This saves on recalculation when calling the Abel-Jacobi map, which can be useful when calculating these integrals is slow. 6) Methods to help with the manipulation of divisors have been added. Namely the methods places_at_branch_locus, strong_approximation, and divisor_to_divisor_list. 7) A method reduce_over_period_lattice has been added to help with the interpretation of results from abel_jacobi, as these will be path dependent. --- .../riemann_surfaces/riemann_surface.py | 1271 +++++++++++++++-- 1 file changed, 1155 insertions(+), 116 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index a4ec7484d72..744e0163b13 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -79,8 +79,10 @@ from sage.matrix.special import block_matrix from sage.misc.cachefunc import cached_method from sage.misc.flatten import flatten +from sage.misc.functional import numerical_approx from sage.misc.misc_c import prod from sage.modules.free_module import VectorSpace +from sage.modules.free_module_integer import IntegerLattice from sage.numerical.gauss_legendre import integrate_vector, integrate_vector_N from sage.rings.complex_mpfr import ComplexField, CDF from sage.rings.integer_ring import ZZ @@ -90,7 +92,6 @@ from sage.rings.real_mpfr import RealField import sage.libs.mpmath.all as mpall - def voronoi_ghost(cpoints, n=6, CC=CDF): r""" Convert a set of complex points to a list of real tuples `(x,y)`, and @@ -322,6 +323,103 @@ def differential_basis_baker(f): if P.interior_contains(a)] +def find_closest_element(item, List): + r""" + Return the index of the closest element of a list. + + Given ``List`` and ``item``, return the index of the element ``l`` of ``List`` + which minimises ``(item-l).abs()``. If there are multiple such elements, the + first is returned. + + INPUT: + + - ``item`` -- value to minimise the distance to over the list. + + - ``List`` -- list. List to look for closest element in. + + EXAMPLES:: + + sage: i = 5 + sage: l = list(range(10)) + sage: i == find_closest_element(i, l) + + Note that this method does no checks on the input, but will fail for inputs + where the absolute value or subtraction do not make sense. + """ + dists = [(item-l).abs() for l in List] + return dists.index(min(dists)) + + +def reparameterise_differential_minpoly(minpoly, z0): + r""" + Rewrites a minimal polynomial to write is around `z_0`. + + Given a minimal polynomial `m(z,g)`, where `g` corresponds to a differential + on the surface (that is, it is represented as a rational function, and + implicitly carries a factor `dz`), we rewrite the minpoly in terms of + variables `\bar{z}, \bar{g}` s.t now `\bar{z}=0 \Leftrightarrow z=z_0`. + + INPUT: + + - ``minpoly`` -- a polynomial in two variables, where the first variables + corresponds to the base coordinate on the Riemann surface. + + - ``z0`` -- complex number of infinity. The point about which to + reparameterise. + + OUTPUT: + + A polynomial in two variables giving the reparameterise minimal polynomial. + + EXAMPLES: + + On the curve given by `w^2-z^3+1=0`, we have differential + `\frac{dz}{2w} = \frac{dz}{2\sqrt{z^3-1}}` + with minimal polynomial `g^2(z^3-1)-1/4=0`. We can make the substitution + `\bar{z}=z^{-1}` to parameterise the differential about `z=\Infty` as + `\frac{-\bar{z}^{-2} d\bar{z}}{2\sqrt{\bar{z}^{-3}-1}} = \frac{-d\bar{z}}{2\sqrt{\bar{z}(1-\bar{z}^3)}}`. + Hence the transformed differential should have minimal polynomial + `\bar{g}^2\bar{z}(1-\bar{z}^3)-1/4=0`, and we can check this:: + + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface + sage: R. = QQ[] + sage: S = RiemannSurface(w^2-z^3+1) + sage: minpoly = S._cohomology_basis_bounding_data[1][0][2] + sage: z0 = Infinity + sage: S.reparameterise_differential_minpoly(minpoly, z0) + -zbar^4*gbar^2 + zbar*gbar^2 - 1/4 + + We can further check that reparameterising about `0` is the identity + operation:: + + sage: S.reparameterise_differential_minpoly(minpoly, 0)(*minpoly.parent().gens())==minpoly + True + + .. NOTE:: + + As part of the routine, when reparameterising about infinity, a + rational function is reduced and then the numerator is taken. Over + an inexact ring this is numerically unstable, and so it is advisable + to only reparameterise about infinty over an exact ring. + """ + P = minpoly.parent() + F = PolynomialRing(P.base_ring(), [str(v)+"bar" for v in P.gens()]) + + try: + Inf = bool(z0==z0.parent()(Infinity)) + except TypeError: + Inf = False + + if Inf: + F = F.fraction_field() + mt = F(minpoly(F.gen(0)**(-1),-F.gen(0)**(+2)*F.gen(1))) + mt.reduce() + mt = mt.numerator() + else: + mt = minpoly(F.gen(0)+z0,F.gen(1)) + return mt + + class RiemannSurface(object): r""" Construct a Riemann Surface. This is specified by the zeroes of a bivariate @@ -379,11 +477,11 @@ class RiemannSurface(object): sage: K. = NumberField(t^2-t+3,embedding=CC(0.5+1.6*I)) sage: R. = K[] sage: f = y^2+y-(x^3+(1-a)*x^2-(2+a)*x-2) - sage: S = RiemannSurface(f,prec=100,differentials=[1]) + sage: S = RiemannSurface(f, prec=100, differentials=[1]) sage: A = S.endomorphism_basis() sage: len(A) 2 - sage: all( len(T.minpoly().roots(K)) > 0 for T in A) + sage: all(len(T.minpoly().roots(K)) > 0 for T in A) True TESTS: @@ -418,6 +516,8 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati # Initializations. self._prec = prec self._certification = certification + if not (integration_method=="heuristic" or integration_method=="rigorous"): + raise ValueError("Invalid integration method") self._integration_method = integration_method self._R = f.parent() if len(self._R.gens()) != 2: @@ -456,16 +556,55 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati # Compute the branch locus. Takes the square-free part of the discriminant # because of numerical issues. self.branch_locus = [] - for x in self._discriminant.factor(): - self.branch_locus += self._CCz(x[0](self._CCz.gen(), 0)).roots(multiplicities=False) + existing_factors = [x[0] for x in self._discriminant.factor()] + for fac in existing_factors: + self.branch_locus += self._CCz(fac(self._CCz.gen(), 0)).roots(multiplicities=False) + self._f_branch_locus = self.branch_locus + self._cohomology_basis_bounding_data = self._bounding_data(self.cohomology_basis(), + exact=True) + RBzg, bounding_data_list = self._cohomology_basis_bounding_data + minpoly_list = [bd[2] for bd in bounding_data_list] + # We now want to calculate the additional branchpoints associated to + # the differentials. + discriminants = [RBzg(self._discriminant(*RBzg.gens()))] + for minpoly in minpoly_list: + F = RBzg(minpoly) + dF = F.derivative(RBzg.gen(1)) + discriminants += [F.resultant(dF, RBzg.gen(1))] + combined_discriminant = lcm(discriminants)(*self._R.gens()) + self._differentials_branch_locus = [] + for x in combined_discriminant.factor(): + if not x[0] in existing_factors: + self._differentials_branch_locus += self._CCz(x[0](self._CCz.gen(), + 0)).roots(multiplicities=False) + # We add these branchpoints to the existing. + self.branch_locus = self.branch_locus+self._differentials_branch_locus + # We now want to also check whether Infinity is a branch point of any + # of the differentials. + # This will be useful when calculating the Abel-Jacobi map. + minpoly_list = [reparameterise_differential_minpoly(mp, Infinity) + for mp in minpoly_list] + discriminants = [] + for minpoly in minpoly_list: + F = RBzg(minpoly) + dF = F.derivative(RBzg.gen(1)) + discriminants += [F.resultant(dF, RBzg.gen(1))] + discriminant_about_infinity = RBzg(lcm(discriminants)) + if discriminant_about_infinity(0,0)==0: + self._differentials_branch_locus.append(self._CC(Infinity)) + # Voronoi diagram and the important points associated with it self.voronoi_diagram = Voronoi(voronoi_ghost(self.branch_locus, CC=self._CC)) self._vertices = [self._CC(x0, y0) for x0, y0 in self.voronoi_diagram.vertices] self._wvalues = [self.w_values(z0) for z0 in self._vertices] + # We arbitrarily, but sensibly, set the basepoint to be the rightmost vertex + self._basepoint = (self._vertices.index(sorted(self._vertices, + key=lambda z:z.real())[-1]), 0) self._Sn = SymmetricGroup(range(self.degree)) self._L = {} + self._integral_dict = {} self._fastcall_f = fast_callable(f, domain=self._CC) self._fastcall_dfdw = fast_callable(self._dfdw, domain=self._CC) self._fastcall_dfdz = fast_callable(self._dfdz, domain=self._CC) @@ -508,6 +647,12 @@ def w_values(self, z0): sage: S.w_values(0) # abs tol 1e-14 [-1.00000000000000*I, 1.00000000000000*I] + + Note that typically the method returns a list of length ``self.degree``, + but that at ramification points, this may no longer be true:: + + sage: S.w_values(1) # abs tol 1e-14 + [0.000000000000000] """ return self.f(z0,self._CCw.gen(0)).roots(multiplicities=False) @@ -568,7 +713,7 @@ def downstairs_graph(self): Return the Voronoi decomposition as a planar graph. The result of this routine can be useful to interpret the labelling of - the vertices. + the vertices. See also :meth:`upstairs_graph`. OUTPUT: @@ -582,22 +727,38 @@ def downstairs_graph(self): sage: S = RiemannSurface(f) sage: S.downstairs_graph() Graph on 11 vertices + """ + G = Graph(self.downstairs_edges()) + G.set_pos(dict(enumerate(list(v) for v in self._vertices))) + return G + + def upstairs_graph(self): + r""" + Return the graph of the upstairs edges. + + This method can be useful for generating paths in the surface between points labelled + by upstairs vertices, and verifying that a homology basis is likely computed correctly. + See also :meth:`downstairs_graph`. - Similarly one can form the graph of the upstairs edges, which is - visually rather less attractive but can be instructive to verify that a - homology basis is likely correctly computed.:: + OUTPUT: - sage: G = Graph(S.upstairs_edges()); G + The homotopy-continued Voronoi decomposition as a graph, with appropriate 3D embedding. + + EXAMPLES:: + + sage: R. = QQ[] + sage: S = Curve(w^2-z^4+1).riemann_surface() + sage: G = S.upstairs_graph(); G Graph on 22 vertices - sage: G.is_planar() - False sage: G.genus() 1 sage: G.is_connected() True """ - G = Graph(self.downstairs_edges()) - G.set_pos(dict(enumerate(list(v) for v in self._vertices))) + G = Graph(self.upstairs_edges()) + G.set_pos({(i,j): [self._vertices[i].real(), self._vertices[i].imag(), + self.w_values(self._vertices[i])[j].imag()] + for i in range(len(self._vertices)) for j in range(self.degree)}, dim=3) return G def _compute_delta(self, z1, epsilon, wvalues=None): @@ -653,7 +814,7 @@ def _compute_delta(self, z1, epsilon, wvalues=None): if wvalues is None: wvalues = self.w_values(z1) # For computation of rho. Need the branch locus + roots of a0. - badpoints = self.branch_locus + self._a0roots + badpoints = self._f_branch_locus + self._a0roots rho = min(abs(z1 - z) for z in badpoints) / 2 Y = max(abs(self._fastcall_dfdz(z1, wi)/self._fastcall_dfdw(z1, wi)) for wi in wvalues) @@ -674,7 +835,7 @@ def _compute_delta(self, z1, epsilon, wvalues=None): else: # Instead, we just compute the minimum distance between branch # points and the point in question. - return min(abs(b - z1) for b in self.branch_locus) / 2 + return min(abs(b - z1) for b in self._f_branch_locus) / 2 def homotopy_continuation(self, edge): r""" @@ -683,15 +844,18 @@ def homotopy_continuation(self, edge): INPUT: - - ``edge`` -- a tuple of integers indicating an edge of the Voronoi - diagram + - ``edge`` -- a tuple ``(z_start, z_end)`` indicating the straight line + over which to perform the homotopy continutation. OUTPUT: - A list of complex numbers corresponding to the points which are reached - when traversing along the direction of the edge. The ordering of these - points indicates how they have been permuted due to the weaving of the - curve. + A list containing the initialised continuation data. Each entry in the + list contains: the `t` values that entry corresponds to, a list of + complex numbers corresponding to the points which are reached when + continued along the edge when traversing along the direction of the + edge, and a value ``epsilon`` giving the minimumdistance between the + fibre values divided by 3. The ordering of these points indicates how + they have been permuted due to the weaving of the curve. EXAMPLES: @@ -707,15 +871,15 @@ def homotopy_continuation(self, edge): sage: sigma = S.edge_permutations()[edge1] sage: continued_values = S.homotopy_continuation(edge1) sage: stored_values = S.w_values(S._vertices[edge1[1]]) - sage: all( abs(continued_values[i]-stored_values[sigma(i)]) < 1e-8 for i in range(3)) + sage: all(abs(continued_values[i]-stored_values[sigma(i)]) < 1e-8 for i in range(3)) True """ - i0, i1 = edge + z_start, z_end = edge + z_start = self._CC(z_start) + z_end = self._CC(z_end) ZERO = self._RR.zero() ONE = self._RR.one() datastorage = [] - z_start = self._CC(self._vertices[i0]) - z_end = self._CC(self._vertices[i1]) path_length = abs(z_end - z_start) def path(t): @@ -744,9 +908,8 @@ def path(t): break currw = neww epsilon = min([abs(currw[i] - currw[j]) for i in range(1,n) for j in range(i)])/3 - datastorage += [(T,currw,epsilon)] - self._L[edge] = datastorage - return currw + datastorage += [(T, currw, epsilon)] + return datastorage def _determine_new_w(self, z0, oldw, epsilon): r""" @@ -808,6 +971,11 @@ def _determine_new_w(self, z0, oldw, epsilon): [-0.562337685361648 + 0.151166007149998*I, 0.640201585779414 - 1.48567225836436*I, -0.0778639004177661 + 1.33450625121437*I] + + .. NOTE:: + + Algorithmically, this method is nearly identical to :meth:`_newton_iteration`, + but this method takes a list of `w` values. """ # Tools of Newton iteration. F = self._fastcall_f @@ -948,10 +1116,13 @@ def upstairs_edges(self): # Lifts each edge individually. for e in self.downstairs_edges(): i0, i1 = e + d_edge = (self._vertices[i0], self._vertices[i1]) # Epsilon for checking w-value later. - epsilon = min([abs(self._wvalues[i1][i] - self._wvalues[i1][n-j-1]) for i in range(n) for j in range(n-i-1)])/3 + epsilon = min([abs(self._wvalues[i1][i] - self._wvalues[i1][n-j-1]) + for i in range(n) for j in range(n-i-1)])/3 # Homotopy continuation along e. - homotopycont = self.homotopy_continuation(e) + self._L[e] = self.homotopy_continuation(d_edge) + homotopycont = self._L[e][-1][1] for i in range(len(homotopycont)): # Checks over the w-values of the next point to check which it is. for j in range(len(self._wvalues[i1])): @@ -1030,17 +1201,17 @@ def edge_permutations(self) -> dict: (1, 2): (), (1, 3): (0,1), (1, 6): (), - (2, 0): (), - (2, 1): (), (2, 5): (0,1), - (3, 1): (0,1), (3, 4): (), - (4, 0): (), - (4, 3): (), - (5, 2): (0,1), (5, 7): (), - (6, 1): (), (6, 7): (), + (2, 0): (), + (4, 0): (), + (2, 1): (), + (3, 1): (0,1), + (6, 1): (), + (5, 2): (0,1), + (4, 3): (), (7, 5): (), (7, 6): ()} """ @@ -1073,21 +1244,28 @@ def monodromy_group(self): sage: f = z^3*w + w^3 + z sage: S = RiemannSurface(f) sage: G = S.monodromy_group(); G - [(0,1,2), (0,1), (0,2), (1,2), (1,2), (1,2), (0,1), (0,2), (0,2)] + [(0,2,1), (0,1), (1,2), (0,2), (0,2), (1,2), (0,2), (0,1), (), (), (), (), (), (), (), (1,2)] The permutations give the local monodromy generators for the branch points:: sage: list(zip(S.branch_locus + [unsigned_infinity], G)) #abs tol 0.0000001 - [(0.000000000000000, (0,1,2)), + [(0.000000000000000, (0,2,1)), (-1.31362670141929, (0,1)), - (-0.819032851784253 - 1.02703471138023*I, (0,2)), - (-0.819032851784253 + 1.02703471138023*I, (1,2)), - (0.292309440469772 - 1.28069133740100*I, (1,2)), + (-0.819032851784253 - 1.02703471138023*I, (1,2)), + (-0.819032851784253 + 1.02703471138023*I, (0,2)), + (0.292309440469772 - 1.28069133740100*I, (0,2)), (0.292309440469772 + 1.28069133740100*I, (1,2)), - (1.18353676202412 - 0.569961265016465*I, (0,1)), - (1.18353676202412 + 0.569961265016465*I, (0,2)), - (Infinity, (0,2))] + (1.18353676202412 - 0.569961265016465*I, (0,2)), + (1.18353676202412 + 0.569961265016465*I, (0,1)), + (-1.45036146591896, ()), + (-0.904285583009352 - 1.13393825501392*I, ()), + (-0.904285583009352 + 1.13393825501392*I, ()), + (0.322735787970535 - 1.41399787587734*I, ()), + (0.322735787970535 + 1.41399787587734*I, ()), + (1.30673052799829 - 0.629288255904939*I, ()), + (1.30673052799829 + 0.629288255904939*I, ()), + (Infinity, (1,2))] We can check the ramification by looking at the cycle lengths and verify it agrees with the Riemann-Hurwitz formula:: @@ -1308,21 +1486,25 @@ def direction(center, neighbour): bcycles[i] += [(P[self.genus + i][j], [x for x in cycles[j]] + [cycles[j][0]])] return acycles + bcycles - def make_zw_interpolator(self, upstairs_edge): + def make_zw_interpolator(self, upstairs_edge, initial_continuation=None): r""" - Given an upstairs edge for which continuation data has been stored, - return a function that computes `z(t),w(t)` , where `t` in `[0,1]` is a + Given a downstairs edge for which continuation data has been initialised, + return a function that computes `z(t), w(t)` , where `t` in `[0,1]` is a parametrization of the edge. INPUT: - - ``upstairs_edge`` -- a pair of integer tuples indicating an edge on - the upstairs graph of the surface + - ``upstairs_edge`` -- tuple. ``((z_start, sb), (z_end,))`` giving the + start and end values of the base coordinate along the straight-line + path and the starting branch. + + - ``initial_continuation`` -- list (default: None). Output of + ``homotopy_continuation`` initialising the continuation data. OUTPUT: - A tuple (g, d), where g is the function that computes the interpolation - along the edge and d is the difference of the z-values of the end and + A tuple ``(g, d)``, where ``g`` is the function that computes the interpolation + along the edge and ``d`` is the difference of the z-values of the end and start point. EXAMPLES:: @@ -1332,17 +1514,30 @@ def make_zw_interpolator(self, upstairs_edge): sage: f = w^2 - z^4 + 1 sage: S = RiemannSurface(f) sage: _ = S.homology_basis() - sage: g,d = S.make_zw_interpolator([(0,0),(1,0)]); - sage: all(f(*g(i*0.1)).abs() < 1e-13for i in range(10)) + sage: u_edge = [(0, 0), (1, 0)] + sage: d_edge = tuple(u[0] for u in u_edge) + sage: u_edge = [(S._vertices[i], j) for i, j in u_edge] + sage: initial_continuation = S._L[d_edge] + sage: g, d = S.make_zw_interpolator(u_edge, initial_continuation); + sage: all(f(*g(i*0.1)).abs() < 1e-13 for i in range(10)) True sage: abs((g(1)[0]-g(0)[0]) - d) < 1e-13 True + + .. NOTE:: + + The interpolator returned by this method can effectively hang if + either ``z_start`` or ``z_end`` are branchpoints. In these situations + it is better to take a different approach rather than continue to use + the interpolator. """ - eindex = tuple(u[0] for u in upstairs_edge) - i0, i1 = eindex - z_start = self._vertices[i0] - z_end = self._vertices[i1] - currL = self._L[eindex] + downstairs_edge = tuple(u[0] for u in upstairs_edge) + z_start, z_end = downstairs_edge + z_start = self._CC(z_start) + z_end = self._CC(z_end) + if initial_continuation==None: + initial_continuation = self.homotopy_continuation(downstairs_edge) + currL = initial_continuation windex = upstairs_edge[0][1] def w_interpolate(t): @@ -1370,7 +1565,7 @@ def w_interpolate(t): tnew = t while True: tnew = (t1 + tnew) / 2 - znew = (1-tnew)*self._vertices[i0]+tnew*self._vertices[i1] + znew = (1-tnew)*z_start+tnew*z_end try: neww1 = self._determine_new_w(znew, currL[i][1], epsilon) except ConvergenceError: @@ -1380,7 +1575,7 @@ def w_interpolate(t): break # once the loop has succeeded we insert our new value t1 = tnew - self._L[eindex].insert(i + 1, (t1, neww1, epsilon)) + currL.insert(i + 1, (t1, neww1, epsilon)) return w_interpolate, (z_end - z_start) def simple_vector_line_integral(self, upstairs_edge, differentials): @@ -1389,8 +1584,10 @@ def simple_vector_line_integral(self, upstairs_edge, differentials): INPUT: - - ``upstairs_edge`` -- a pair of integer tuples corresponding to an edge - of the upstairs graph. + - ``upstairs_edge`` -- tuple. Either a pair of integer tuples + corresponding to an edge of the upstairs graph, or a tuple + ``((z_start, sb), (z_end, ))`` as in the input of + ``make_zw_interpolator``. - ``differentials`` -- a list of polynomials; a polynomial `g` represents the differential `g(z,w)/(df/dw) dz` where `f(z,w)=0` is @@ -1418,9 +1615,21 @@ def simple_vector_line_integral(self, upstairs_edge, differentials): .. NOTE:: - Uses data that ``homology_basis`` initializes. + Uses data that :meth:`homology_basis` initializes, and may give incorrect + values if :meth:`homology_basis` has not initialized them. In practice + it is more efficient to set ``differentials`` to a fast-callable version + of differentials to speed up execution. """ - w_of_t, Delta_z = self.make_zw_interpolator(upstairs_edge) + d_edge = tuple(u[0] for u in upstairs_edge) + # Using a try-catch here allows us to retain a certain amount of back compatibility + # for users. + try: + initial_continuation = self._L[d_edge] + upstairs_edge = ((self._vertices[d_edge[0]], upstairs_edge[0][1]), + (self._vertices[d_edge[1]], )) + except KeyError: + initial_continuation = self.homotopy_continuation(d_edge) + w_of_t, Delta_z = self.make_zw_interpolator(upstairs_edge, initial_continuation) V = VectorSpace(self._CC, len(differentials)) def integrand(t): @@ -1459,7 +1668,7 @@ def cohomology_basis(self, option=1): """ if self.genus == 0: self._differentials = [] - return self._differentials[0] + return self._differentials #[0] if self._differentials is None: # Computes differentials from the adjointIdeal using Singular # First we homogenize @@ -1495,7 +1704,7 @@ def cohomology_basis(self, option=1): self._differentials = generators return self._differentials - def _bounding_data(self, differentials): + def _bounding_data(self, differentials, exact=False): r""" Compute the data required to bound a differential on a circle. @@ -1504,7 +1713,12 @@ def _bounding_data(self, differentials): INPUT: - - ``differentials`` -- The differentials for which to compute the bounding data. + - ``differentials`` -- list. The differentials for which to compute the + bounding data. + + - ``exact`` -- logical (default: False). Whether to return the minimal + polynomials over the exact base ring, or whether to return them over + ``self._CC``. OUTPUT: @@ -1512,7 +1726,7 @@ def _bounding_data(self, differentials): as well as a list containing the differential, its derivative, the minimal polynomial, and ``a0_info`` for each differential. Here ``a0_info`` is the leading coefficient and roots of the leading order - term of the minimal polynomial. + term of the minimal polynomial, calculated in ``self._CC``. EXAMPLES:: @@ -1530,8 +1744,21 @@ def _bounding_data(self, differentials): -0.500000000000000 - 0.866025403784439*I, -0.500000000000000 + 0.866025403784439*I]))]) + Note that ``self._bounding_data(self._cohomology_basis(), exact=True)`` + is stored in ``self._cohomology_basis_bounding_data``:: + + sage: S._cohomology_basis_bounding_data + (Multivariate Polynomial Ring in z, g over Rational Field, + [(1/(2*y), + (-3*z^2*g)/(2*z^3 - 2), + z^3*g^2 - g^2 - 1/4, + (1.00000000000000, + [1.00000000000000, + -0.500000000000000 - 0.866025403784439*I, + -0.500000000000000 + 0.866025403784439*I]))]) """ - # This copies previous work by NB, outputting the zipped list required for a certified line integral. + # This copies previous work by NB, outputting the zipped list required + # for a certified line integral. RB = self._R.base_ring() P = PolynomialRing(RB, 'Z') k = P.fraction_field() @@ -1540,13 +1767,14 @@ def _bounding_data(self, differentials): L = k.extension(fZW, 'Wb') dfdw_L = self._dfdw(P.gen(0), L.gen(0)) integrand_list = [h/self._dfdw for h in differentials] - # minpoly_univ gives the minimal polynomial for h, in variable x, with coefficients given by polynomials - # with coefficients in P (i.e. rational polynomials in Z). + # minpoly_univ gives the minimal polynomial for h, in variable x, with + # coefficients given by polynomials with coefficients in P (i.e. + # rational polynomials in Z). minpoly_univ = [(h(P.gen(0), L.gen(0))/dfdw_L).minpoly().numerator() for h in differentials] RBzg = PolynomialRing(RB, ['z', 'g']) - # The following line changes the variables in these minimal polynomials as Z -> z, x -> G, then evaluates - # at G = QQzg.gens(1) ( = g ) + # The following line changes the variables in these minimal polynomials + # as Z -> z, x -> G, then evaluates at G = QQzg.gens(1) ( = g ) RBzgG = PolynomialRing(RBzg, 'G') minpoly_list = [RBzgG([c(RBzg.gen(0)) for c in list(h)])(RBzg.gen(1)) for h in minpoly_univ] @@ -1558,7 +1786,6 @@ def _bounding_data(self, differentials): CCminpoly_list = [CCzg(h) for h in minpoly_list] a0_list = [P(h.leading_coefficient()) for h in minpoly_univ] - #CCa0_list = [self._CCz(a0) for a0 in a0_list] # Note that because the field over which the Riemann surface is defined # is embedded into CC, it has characteristic 0, and so we know the # irreducible factors are all separable, i.e. the roots have multiplicity @@ -1567,12 +1794,10 @@ def _bounding_data(self, differentials): flatten([self._CCz(F).roots(multiplicities=False)*m for F, m in a0.factor()])) for a0 in a0_list] - - #a0_list = [self._CCz(h.leading_coefficient()) for h in minpoly_univ] - #a0_info = [(a0.leading_coefficient(), flatten([[r]*n for r, n in a0.roots()])) for a0 in a0_list] - # Note that we are assuming here that the root finder is working correctly, which will need - # some thought. - return CCzg, list(zip(integrand_list, dgdz_list, CCminpoly_list, a0_info)) + if exact: + return RBzg, list(zip(integrand_list, dgdz_list, minpoly_list, a0_info)) + else: + return CCzg, list(zip(integrand_list, dgdz_list, CCminpoly_list, a0_info)) def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): r""" @@ -1585,8 +1810,10 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): INPUT: - - ``upstairs_edge`` -- a pair of integer tuples corresponding to an edge - of the upstairs graph. + - ``upstairs_edge`` -- tuple. Either a pair of integer tuples + corresponding to an edge of the upstairs graph, or a tuple + ``((z_start, sb), (z_end, ))`` as in the input of + ``make_zw_interpolator``. - ``differentials`` -- a list of polynomials; a polynomial `g` represents the differential `g(z,w)/(df/dw) dz` where `f(z,w)=0` is @@ -1594,7 +1821,7 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): - ``bounding_data`` -- tuple containing the data required for bounding the integrands. This should be in the form of the output from - ``_bounding_data``. + :meth:`_bounding_data`. OUTPUT: @@ -1620,8 +1847,9 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): .. NOTE:: - Uses data that ``homology_basis`` initializes. In practice is it is - more efficient to set ``differentials`` to a fast-callable version + Uses data that :meth:`homology_basis` initializes, and may give incorrect + values if :meth:`homology_basis` has not initialized them. In practice + it is more efficient to set ``differentials`` to a fast-callable version of differentials to speed up execution. .. TODO:: @@ -1643,17 +1871,28 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): entire line with one ellipse, then bounds along that ellipse with multiple circles. """ - # Note that this, in it's current formalism, makes no check that bounding data at all corresponds to - # the differentials given. The onus is then on the design of other funcions which use it. + # Note that this, in it's current formalism, makes no check that bounding + # data at all corresponds to the differentials given. The onus is then on + # the design of other funcions which use it. - # CCzg is required to be known as we need to know the ring which the minpolys lie in. + # CCzg is required to be known as we need to know the ring which the minpolys + # lie in. CCzg, bounding_data_list = bounding_data + + d_edge = tuple(u[0] for u in upstairs_edge) + # Using a try-catch here allows us to retain a certain amount of back + # compatibility for users. + try: + initial_continuation = self._L[d_edge] + upstairs_edge = ((self._vertices[d_edge[0]], upstairs_edge[0][1]), + (self._vertices[d_edge[1]], )) + except KeyError: + initial_continuation = self.homotopy_continuation(d_edge) - i0, _ = upstairs_edge[0] - i1, _ = upstairs_edge[1] - z0 = self._vertices[i0] - z1 = self._vertices[i1] - zwt, z1_minus_z0 = self.make_zw_interpolator(upstairs_edge) + zwt, z1_minus_z0 = self.make_zw_interpolator(upstairs_edge, + initial_continuation) + z0 = zwt(0)[0] + z1 = zwt(1)[0] # list of (centre, radius) pairs that still need to be processed ball_stack = [(self._RR(0.5), self._RR(0.5))] @@ -1672,30 +1911,34 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): while ball_stack: ct, rt = ball_stack.pop() cz = (1-ct)*z0+ct*z1 # This is the central z-value of our ball. - distances = [(cz-b).abs() for b in self.branch_locus] # Distance to the discriminant points + # Distance to the discriminant points + distances = [(cz-b).abs() for b in self.branch_locus] rho_z = min(distances) rho_t = rho_z/(z1-z0).abs() if rho_t > rt: rho_t = alpha*rho_t+(1-alpha)*rt # sqrt(rho_t*rt) could also work rho_z = rho_t*(z1-z0).abs() delta_z = (alpha*rho_t+(1-alpha)*rt)*(z1-z0).abs() - expr = rho_t/rt+((rho_t/rt)**2-1).sqrt() # Note this is really exp(arcosh(rho_t/rt)) + # Note this is really exp(arcosh(rho_t/rt)) + expr = rho_t/rt+((rho_t/rt)**2-1).sqrt() N = 3 cw = zwt(ct)[1] for g, dgdz, minpoly,(a0lc,a0roots) in bounding_data_list: z_1 = a0lc.abs()*prod((cz-r).abs()-rho_z for r in a0roots) n = minpoly.degree(CCzg.gen(1)) - # Note the structure of the code is currently s.t 'z' has to be the variable in - # the minpolys. - ai_new = [(minpoly.coefficient({CCzg.gen(1):i}))(z=cz+self._CCz.gen(0)) for i - in range(n)] - ai_pos = [ self._RRz([c.abs() for c in h.list()]) for h in ai_new] + # Note the structure of the code is currently s.t 'z' has to + # be the variable in the minpolys. + ai_new = [(minpoly.coefficient({CCzg.gen(1):i}))(z=cz+self._CCz.gen(0)) + for i in range(n)] + ai_pos = [self._RRz([c.abs() for c in h.list()]) + for h in ai_new] m = [a(rho_z)/z_1 for a in ai_pos] l = len(m) - M_tilde = 2*max((m[i].abs())**(1/self._RR(l-i)) for i in range(l)) + M_tilde = 2*max((m[i].abs())**(1/self._RR(l-i)) + for i in range(l)) cg = g(cz,cw) cdgdz = dgdz(cz,cg) - Delta = delta_z*cdgdz.abs()+ (delta_z**2)*M_tilde/(rho_z*(rho_z-delta_z)) + Delta = delta_z*cdgdz.abs() + (delta_z**2)*M_tilde/(rho_z*(rho_z-delta_z)) M = Delta #+ abs(cg) N_required = ((64*M/(15*(1-1/expr)*E_global)).log()/(2*expr.log())).ceil() N = max(N,N_required) @@ -1703,9 +1946,8 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): N = (K*(self._RR(N).sqrt()/K).ceil())**2 # Rounding is sensible as it allows the cache of nodes in # sage.numerical.gauss_legendre to be used. - # Quadratic rounding can be shown to be a sensible choice through the - # basic argument that nodes is quadratic in N - + # Quadratic rounding can be shown to be a sensible choice through + # the basic argument that nodes is quadratic in N ct_minus_rt = ct-rt two_rt = 2*rt def integrand(t): @@ -1755,6 +1997,13 @@ def matrix_of_integral_values(self, differentials, integration_method="heuristic sage: (m[0,0]/m[0,1]).algdep(3).degree() #curve is CM, so the period is quadratic 2 + .. NOTE:: + + If ``differentials is self.cohomology_basis()``, the calculations + of the integrals along the edges are written to `self._integral_dict``. + This is as this data will be required when computing the Abel-Jacobi + map, and so it is helpful to have is stored rather than recomputing. + """ cycles = self.homology_basis() @@ -1778,20 +2027,21 @@ def normalize_pairs(L): fcd = [fast_callable(omega, domain=self._CC) for omega in differentials] if integration_method=="heuristic": - line_int = lambda edge: self.simple_vector_line_integral(edge,fcd) + line_int = lambda edge: self.simple_vector_line_integral(edge, fcd) elif integration_method=="rigorous": bd = self._bounding_data(differentials) - line_int = lambda edge: self.rigorous_line_integral(edge,fcd,bd) + line_int = lambda edge: self.rigorous_line_integral(edge, fcd, bd) else: raise ValueError("Invalid integration method") - #integral_dict = {upstairs_edge: - # self.simple_vector_line_integral(upstairs_edge, - # differentials) - # for upstairs_edge in occurring_edges} - integral_dict = dict() - for upstairs_edge in occurring_edges: - integral_dict[upstairs_edge] = line_int(upstairs_edge) + if differentials is self.cohomology_basis(): + integral_dict = self._integral_dict + for upstairs_edge in occurring_edges: + if not upstairs_edge in integral_dict.keys(): + integral_dict[upstairs_edge] = line_int(upstairs_edge) + else: + integral_dict = {upstairs_edge: lint_int(upstairs_edge) + for upstairs_edge in occurring_edges} rows = [] for cycle in cycles: @@ -2338,6 +2588,795 @@ def __add__(self, other): """ return RiemannSurfaceSum([self, other]) + def _integrate_differentials_iteratively(self, upstairs_edge, cutoff_individually=False, raise_errors=True, prec=None): + r""" + Integrate the cohomology basis along a straight line edge. + + The cohomology basis is integrated along a straight line using a version + of the double exponential quadrature. This method of integrating the + cohomology basis is especially useful when integrating out to infinity, + or near roots of `self._dfdw`. In order to aid with convergence of the + method, two main modification to a standard integrator are made, most + importantly of which is the truncation of the integral near branch points, + where the first term in the Puiseux series of the integrands are used to + approximately bound the integral. The ``cutoff_individually`` parameter + allows the user to set whether that truncation is uniform over all the + integrands, which improves the complexity of the algorithm, but loses + the ability to gain benefits where integrands vanish to a high order at + the branchpoint. + + INPUT: + + - ``upstairs_edge`` -- tuple. A tuple of complex numbers of the form + ``((z_start, w_start), z_end)`` specifying the path to integrate + along, where ``z_start`` may be infinite, in which case ``w_start`` + must be an integer specifying the branch. + + - ``cutoff_individually`` -- boolean (default: False). Whether to truncate + the integrand uniformly or not. If ``None``, then no truncation is + applied. + + - ``raise_errors`` -- boolean (default: True). By default the code uses + convergence errors to ensure any answers returned are accurate. This + can be turned off to return answers faster that are not necessarily + correct. + + - ``prec`` -- integer (default: ``self._prec``). The precision to try + and achieve, defined as `2^{-\text{prec}+3}`. + + OUTPUT: + + Tuple ``(I, gs)`` where ``I`` is the vector of integrals, and ``gs`` are + the values of the differentials at ``z_end``. + + EXAMPLES: + + We know that for the surface given by `w^2-z^4-1` a cohomology basis is + given by `\frac{dz}{2w}`. One can verify analytically that + `\int_0^1 frac{dt}{\sqrt{1-t^4}}=\frac{\sqrt{\pi}\Gamma(5/4)}{\Gamma(3/4)}`, + and we check this with the integrator, being careful with signs:: + + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface + sage: R. = QQ[] + sage: S = RiemannSurface(w^2+z^4-1, prec=100) + sage: branch = 0 + sage: eps = S._RR(2)**(-S._prec) + sage: z_start = 1-eps + sage: z_end = 0 + sage: w_start = S.w_values(z_start)[0] + sage: s = sign(w_start) + sage: u_edge = ((z_start, w_start), z_end) + sage: J, _ = S._integrate_differentials_iteratively(u_edge) + sage: bool(J[0]+s*S._RR(sqrt(pi)*gamma(5/4)/gamma(3/4)/2)<1e-10) + True + + .. NOTE:: + + The cutoff methodology is calculating the first term in the Puiseux + series of the differentials about z_start. In future it may be + desirable to extend this further and use the truncated Puiseux series + entirely to integrate the differentials. + """ + (z_start, w_start), z_end = upstairs_edge + z_start = self._CC(z_start) + z_end = self._CC(z_end) + + if z_end==self._CC(Infinity): + raise NotImplementedError + + _, bounding_data_list = self._cohomology_basis_bounding_data + mp_list = [bd[2] for bd in bounding_data_list] + + # Parameterise so zbar=0 corresponds to z=z_start + mp_list = [reparameterise_differential_minpoly(mp, z_start) + for mp in mp_list] + + if z_start==self._CC(Infinity): + CCzg = PolynomialRing(self._CC, ['zbar','gbar']) + mp_list = [CCzg(mp) for mp in mp_list] + J = 1/z_end + endscale = -z_end**(-2) + def initialise(z, i): + DF = ComplexField(2*self._prec) + DFw = PolynomialRing(DF,'wbar') + z = DF(z) + R = DF(z**(-1)) + wR = DFw(self.f(R, DFw.gen(0))).roots(multiplicities=False)[w_start] + newg = -R**2*self.cohomology_basis()[i](R, wR)/self._dfdw(R, wR) + err = mp_list[i](z,newg).abs() + if err>tau: + rs = mp_list[i](z, DFw.gen(0)).roots(multiplicities=False) + sb = find_closest_element(newg, rs) + newg = rs[sb] + return newg + else: + CCzg = mp_list[0].parent() + J = z_end-z_start + endscale = 1 + def initialise(z, i): + newg = self.cohomology_basis()[i](z_start, w_start)/self._dfdw(z_start, w_start) + err = mp_list[i](z, newg).abs() + if err>tau: + rs = mp_list[i](z, self._CCw.gen(0)).roots(multiplicities=False) + sb = find_closest_element(newg, rs) + newg = rs[sb] + return newg + + fc_mp_list = [fast_callable(mp, domain=self._CC) for mp in mp_list] + fc_dmp_list = [fast_callable(mp.derivative(CCzg.gen(1)), domain=self._CC) + for mp in mp_list] + + if prec==None: + prec = self._prec + # tau here is playing the role of the desired error. + tau = self._RR(2)**(-prec+3) + ONE = self._RR(1) + LAMBDA = self._RR.pi()/2 + + if cutoff_individually==None: + cutoffs = [0] + cutoff_individually = False + else: + cutoffs = [] + A = PolynomialRing(self._CC,'xyz') + aes = [] + for mp in mp_list: + d = mp.dict() + mp = sum([d[k]*CCzg.gen(0)**k[0]*CCzg.gen(1)**k[1] + for k in d.keys() if d[k].abs()>tau]) + cst = min([iz for (iz, ig) in d.keys() if ig==0]) + a = QQ(max([(cst-iz)/ig for (iz,ig) in d.keys() if ig>0])) + sum_coeffs = sum([d[k]*A.gen(0)**k[1] for k in d.keys() + if ((k[1]==0 and k[0]==cst) or k[1]*a+k[0]-cst==0)]) + G = max([r.abs() for r in sum_coeffs.roots(multiplicities=False)]) + cutoffs.append(((a+1)*tau/G)**(1/self._CC(a+1))/J.abs()) + aes.append(a) + cutoff_individually = bool(not all(ai<=0 for ai in aes) and cutoff_individually) + + if raise_errors: + n_steps = self._prec-1 + def error_handle(out): + raise ConvergenceError("Newton iteration fails to converge") + else: + n_steps = 15 + def error_handle(out): + return out + + V = VectorSpace(self._CC, self.genus) + h = ONE + Nh = (-lambert_w(-1,-tau/2)/LAMBDA).log().ceil() + h0 = Nh*h + + if cutoff_individually: + z_fc_list = list(zip(fc_mp_list, fc_dmp_list)) + + def fv(hj, previous_estimate_and_validity): + u2 = LAMBDA*hj.sinh() + t = 1/(2*u2.exp()*u2.cosh()) + z0 = J*t + outg = [] + valid = self.genus*[True] + previous_estimate, validity = previous_estimate_and_validity + for i in range(self.genus): + co = cutoffs[i] + pv = validity[i] + if t=Ndelta and + (Ndelta.sign_mantissa_exponent()[2] + +self._prec) < newg.norm().sign_mantissa_exponent()[2]): + outg.append(newg) + break + delta = new_delta + Ndelta = Nnew_delta + newg-=delta + if j==99: + outg.append(error_handle(newg)) + fj = V(outg) + u1 = LAMBDA*hj.cosh() + w = u1/(2*u2.cosh()**2) + return (fj, valid), w*fj + + f0, v0 = fv(h0, (self.genus*[0], self.genus*[False])) + else: + cutoffs.append(1) + cutoff = min(cutoffs) + cutoff_z = J*cutoff + J -= cutoff_z + + def fv(hj, previous_estimate): + u2 = LAMBDA*hj.sinh() + t = 1/(2*u2.exp()*u2.cosh()) + z0 = cutoff_z+J*t + outg = [] + for F, dF, oldg in zip(fc_mp_list, fc_dmp_list, previous_estimate): + delta = F(z0, oldg) / dF(z0, oldg) + Ndelta = delta.norm() + newg = oldg - delta + for j in range(100): + new_delta = F(z0, newg) / dF(z0, newg) + Nnew_delta = new_delta.norm() + if (new_delta == 0) or (Nnew_delta>=Ndelta and + (Ndelta.sign_mantissa_exponent()[2] + +self._prec) < newg.norm().sign_mantissa_exponent()[2]): + outg.append(newg) + break + delta = new_delta + Ndelta = Nnew_delta + newg-=delta + if j==99: + outg.append(error_handle(newg)) + fj = V(outg) + u1 = LAMBDA*hj.cosh() + w = u1/(2*u2.cosh()**2) + return fj, w*fj + + u1, u2 = (LAMBDA*h0.cosh(),LAMBDA*h0.sinh()) + y, w = (1/(2*u2.exp()*u2.cosh()), u1/(2*u2.cosh()**2)) + z0 = cutoff_z+J*y + f0 = [initialise(z0, i) for i in range(self.genus)] + f0 = V(f0) + v0 = w*f0 + + D3_over_tau = v0.norm(Infinity) + D4 = D3_over_tau + results = [] + + for k in range(n_steps): + hj = h0 + val = v0 + fj = f0 + for j in range(2*Nh): + hj -= h + try: + fj, v = fv(hj, fj) + except ConvergenceError: + break + D3_over_tau = max(v.norm(Infinity), D3_over_tau) + val += v + if j==2*Nh-1: + results.append(h*val) + D4 = max(D4, v.norm(Infinity)) + if len(results)>2: + if results[-1] == results[-2] or results[2] == results[-3]: + D = tau + else: + D1 = (results[-1]-results[-2]).norm(Infinity) + D2 = (results[-1]-results[-3]).norm(Infinity) + D = min(ONE,max(D1**(D1.log()/D2.log()),D2**2,tau*D3_over_tau,D4,tau)) + + if D <= tau: + if cutoff_individually: + fj = fj[0] + return J*results[-1], endscale*fj + h /= 2 + Nh *= 2 + return error_handle((J*results[-1], endscale*fj)) + + def _aj_based(self, P): + r""" + Return the Abel-Jacobi map to ``P`` from ``self._basepoint``. + + Computes a representative of the Abel-Jacobi map from ``self._basepoint`` + to ``P`` via a well-chosen vertex ``V``. The representative given will be + dependent on the path chosen. + + INPUT: + + - ``P`` -- tuple. A pair giving the endpoint of the integral, either in + the form ``(z, w)`` or ``(Infinity, branch)``, where in the latter case + we are using the conventing that the `w` value over `\infty` is given by + the limit as ``z`` tends to `\infty` of ``self.w_values(z)[branch]``. + + OUTPUT: + + A vector of length ``self.genus``. + + EXAMPLES: + + As the output of ``_aj_based`` is difficult to intepret due to its path + dependency, we look at the output of :meth:`abel_jacobi`. We check for + two hyperelliptic curves that the Abel-Jacobi map between two branch + points is a 2-torsion point over the lattice:: + + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface + sage: R. = QQ[] + sage: S = RiemannSurface(y^2-x^3+1) + sage: divisor = [(-1, (Infinity, 0)), (1, (1, 0))] + sage: AJ = S.abel_jacobi(divisor) + sage: AJx2 = [2*z for z in AJ] + sage: bool(S.reduce_over_period_lattice(AJx2).norm()<1e-10) + True + sage: S = RiemannSurface(y^2-x^4+1) + sage: divisor = [(-1, (-1, 0)), (1, (1, 0))] + sage: AJ = S.abel_jacobi(divisor) + sage: AJx2 = [2*z for z in AJ] + sage: bool(S.reduce_over_period_lattice(AJx2).norm()<1e-10) + True + + """ + ##### + fcd = [fast_callable(h, domain = self._CC) for h in self.cohomology_basis()] + + if self._integration_method=="heuristic": + line_int = lambda edge: self.simple_vector_line_integral(edge, fcd) + else: + bd = self._cohomology_basis_bounding_data + line_int = lambda edge: self.rigorous_line_integral(edge, fcd, bd) + ##### + B = self._basepoint + zP, wP = P + + try: + Inf = bool(zP==zP.parent()(Infinity)) + except TypeError: + Inf = False + + if Inf: + zV = self._vertices[B[0]] + if zV==0: + zV += 1 + upstairs_edge = (P, zV) + ci = bool(self._CC(Infinity) in self._differentials_branch_locus) + AJ, endgs = self._integrate_differentials_iteratively(upstairs_edge, + cutoff_individually=ci) + AJ = -AJ + g0e = endgs[0] + ws = self.w_values(zV) + g0s = [self.cohomology_basis()[0](zV, wi)/self._dfdw(zV, wi) for wi in ws] + W_index = find_closest_element(g0e, g0s) + if (g0e - self.cohomology_basis()[0](zV, ws[W_index])/self._dfdw(zV, ws[W_index])).abs()>1e-10: + raise ConvergenceError("Integrand continuation failed to get representative values, higher precision requried.") + V_index = B[0] + else: + zP = self._CC(zP) + wP = self._CC(wP) + V_index = find_closest_element(zP, self._vertices) + b_index = find_closest_element(zP, self.branch_locus) + b = self.branch_locus[b_index] + + d1 = self._CC(1e-2)*max(b.abs() for b in self.branch_locus) + + # We choose the first vertex we want to go to. + # If the closest vertex is closer than the nearest branch point, just take that vertex + # otherwise we need something smarter. + delta = self._RR(2)**(-self._prec+1) + if not ((zP-self._vertices[V_index]).abs() < (zP-b).abs() or (zP-b).abs()<=delta): + region = self.voronoi_diagram.regions[self.voronoi_diagram.point_region[b_index]] + args = [(self._vertices[i]-zP).argument() - (b-zP).argument() for i in region] + suitable_vertex_indices = [region[i] + for i in range(len(region)) if args[i].abs()>self._RR.pi()/2] + suitable_vertices = [self._vertices[i] for i in suitable_vertex_indices] + if suitable_vertices==[]: + raise ValueError("There is no satisfactory choice of V for zP={}".format(zP)) + V_index = suitable_vertex_indices[find_closest_element(zP, suitable_vertices)] + ##### + zV = self._vertices[V_index] + d_edge = (zP, zV) + + if (zP-b).abs() >= d1 or b in self._differentials_branch_locus: + wP_index = find_closest_element(wP, self.w_values(zP)) + u_edge = ((zP, wP_index), (zV, )) + initial_continuation = self.homotopy_continuation(d_edge) + AJ = -line_int(u_edge) + + w_end = initial_continuation[-1][1][wP_index] + W_index = find_closest_element(w_end, self._wvalues[V_index]) + else: + zs = zP + ws = wP + + while self._dfdw(zs, ws).abs()==0: + zs = zs+delta*(zV-zs)/(zV-zs).abs()/2 + ws_list = self.w_values(zs) + wP_index = find_closest_element(ws, ws_list) + ws = ws_list[wP_index] + upstairs_edge = ((zs, ws), zV) + AJ, endgs = self._integrate_differentials_iteratively(upstairs_edge, + cutoff_individually=False) + AJ = -AJ + g0e = endgs[0] + + ws = self.w_values(zV) + g0s = [self.cohomology_basis()[0](zV, wi)/self._dfdw(zV, wi) for wi in ws] + W_index = find_closest_element(g0e, g0s) + if (g0e - self.cohomology_basis()[0](zV, ws[W_index])/self._dfdw(zV, ws[W_index])).abs()>1e-10: + raise ConvergenceError("Integrand continuation failed to get representative values, higher precision requried.") + + uV_index = (V_index, W_index) + ##### + G = self.upstairs_graph() + path = G.shortest_path(B, uV_index) + edges = [(path[i],path[i+1]) for i in range(len(path)-1)] + ##### + for e in edges: + if e[1][0]>e[0][0]: + s = 1 + else: + s = -1 + e = tuple(reversed(e)) + try: + AJ += s*self._integral_dict[e] + except KeyError: + Ie = line_int(e) + self._integral_dict[e] = Ie + AJ += s*Ie + return AJ + + def abel_jacobi(self, divisor, verbose=False): + r""" + Return the Abel-Jacobi map of ``divisor``. + + Returns a representative of the Abel-Jacobi map of a divisor with basepoint + ``self._basepoint``. + + INPUT: + + - ``divisor`` -- list. A list with each entry a tuple of the form ``(v, P)``, + where ``v`` is the valuation of the divisor at point ``P``, ``P`` as per + the input to :meth:`_aj_based`. + + - `` verbose`` -- logical (default: False). Whether to report the progress + of the computation, in terms of how many elements of the list ``divisor`` + have been completed. + + OUTPUT: + + A vector of length ``self.genus``. + + EXAMPLES: + + We can test that the Abel-Jacobi map between two branchpoints of a + superelliptic curve of degree `p` is a `p`-torsion point in the Jacobian:: + + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface + sage: R. = QQ[] + sage: p = 4 + sage: S = RiemannSurface(y^p-x^4+1, prec=100) + sage: divisor = [(-1, (-1, 0)), (1, (1, 0))] + sage: AJ = S.abel_jacobi(divisor) # long time (15 seconds) + sage: AJxp = [p*z for z in AJ] # long time + sage: bool(S.reduce_over_period_lattice(AJx2).norm()<1e-7) # long time + True + """ + ans = 0 + n = len(divisor) + for i in range(n): + v, p = divisor[i] + if verbose: + print("starting computation for p = {}".format(p)) + ans += v*self._aj_based(p) + if verbose: + print("Done, {}% complete".format(numerical_approx(100*(i+1)/n, 11))) + return ans + + def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None): + r""" + Reduce a vector over the period lattice. + + Given a vector of length ``self.genus``, this method returns a vector + in the same orbit of the period lattice that is short. There are two + possible methods, ``'svp'`` which returns a certified shortest vector, + but can be much slower for higher genus curves, and ``'ip'``, which is + faster but not guaranteed to return the shortest vector. In general the + latter will perform well when the lattice basis vectors are of similar + size. + + INPUT: + + - ``vector`` -- vector. A vector of length ``self.genus`` to reduce over + the lattice. + + - ``method`` -- string (default: ``'ip'``). String specifying the method + to use to reduce the vector. THe options are ``'ip'`` and ``'svp'``. + + - ``b`` -- integer (default provided): as for + :meth:`homomorphism_basis`, and used in its invocation if + (re)calculating said basis. + + - ``r`` -- integer (default: ``b/4``). as for + :meth:`homomorphism_basis`, and used in its invocation if + (re)calculating said basis. + + OUTPUT: + + Complex vector of length ``self.genus`` in the same orbit as ``vector`` + in the lattice. + + EXAMPLES: + + We can check that the lattice basis vectors themselves are reduced to + zero:: + + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface + sage: R. = QQ[] + sage: S = RiemannSurface(y^2-x^5+1) + sage: epsilon = S._RR(2)^(-S._prec+1) + sage: for vector in S.period_matrix().columns(): + ....: print(bool(S.reduce_over_period_lattice(vector).norm() 2**(self._prec-4): + raise ValueError("insufficient precision for b=%s" % b) + + def C2Z(v): + vR = [(S*z.real_part()).round() for z in v] + vR += [(S*z.imag_part()).round() for z in v] + return vR + + M = Matrix(ZZ, 2*self.genus, 2*self.genus, + [C2Z(c) for c in self.period_matrix().columns()]) + u = C2Z(vector) + L = IntegerLattice(M) + u = VR(u)-VR(L.closest_vector(u)) + reduced = VC([self._CC(u[i]+I*u[i+self.genus])/S for i in range(self.genus)]) + + elif method=="ip": + + def C2R(v): + return VR([z.real_part() for z in v]+[z.imag_part() for z in v]) + + u = C2R(vector) + basis_vecs = [C2R(c) for c in self.period_matrix().columns()] + M = Matrix([[ei.dot_product(ej) for ei in basis_vecs] for ej in basis_vecs]) + v_dot_e = VR([u.dot_product(e) for e in basis_vecs]) + coeffs = M.solve_right(v_dot_e) + u -= sum([t.round()*e for t, e in zip(coeffs, basis_vecs)]) + reduced = VC([self._CC(u[i]+I*u[i+self.genus]) for i in range(self.genus)]) + else: + raise ValueError("Must give a valid method.") + + return reduced + + def places_at_branch_locus(self): + r""" + Return the places above the branch locus. + + Returns a list of the of places above the branch locus. This must be + done over the base ring, and so the places are given in terms of the + factors of the discriminant. Currently, this method only works when + ``self._R.base_ring()==QQ`` as for other rings, the function field + for ``Curve(self.f)`` is not implemented. To go from these divisors to + a divisor list, see :meth:`divisor_to_divisor_list`. + + OUTPUT: + + List of places of the functions field ``Curve(self.f).function_field()``. + + EXAMPLES:: + + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface + sage: R. = QQ[] + sage: S = RiemannSurface(25*(x^4+y^4+1) - 34*(x^2*y^2+x^2+y^2)) + sage: S.places_at_branch_locus() + [Place (x - 2, (x - 2)*y, y^2 - 17/5, y^3 - 17/5*y), + Place (x + 2, (x + 2)*y, y^2 - 17/5, y^3 - 17/5*y), + Place (x - 1/2, (x - 1/2)*y, y^2 - 17/20, y^3 - 17/20*y), + Place (x + 1/2, (x + 1/2)*y, y^2 - 17/20, y^3 - 17/20*y), + Place (x^4 - 34/25*x^2 + 1, y, y^2, y^3), + Place (x^4 - 34/25*x^2 + 1, (x^4 - 34/25*x^2 + 1)*y, y^2 - 34/25*x^2 - 34/25, y^3 + (-34/25*x^2 - 34/25)*y)] + """ + BP = [] + K = self._R.base_ring() + if not K==QQ: + raise NotImplementedError + C = Curve(self.f) + KC = C.function_field() + g0, g1 = self._R.gens() + Kb = FunctionField(K, str(g0)) + MO = Kb.maximal_order() + BP = [] + for x in self._discriminant.factor(): + fac = x[0](g0, 0) + p0 = MO.ideal(fac).place() + BP += KC.places_above(p0) + return BP + + def strong_approximation(self, divisor, S): + r""" + Apply the method of strong approximation to a divisor. + + As described in [Neu2018]_, apply the method of strong approximation to + ``divisor`` with list of places to avoid ``S``. Currently, this method + only works when ``self._R.base_ring()==QQ`` as for other rings, the function + field for ``Curve(self.f)`` is not implemented. + + INPUT: + + - ``divisor`` -- an element of ``Curve(self.f).function_field().divisor_group()`` + + - ``S`` -- list. A list of places to avoid. + + OUTPUT: + + A tuple ``(S, B)``, where ``D`` is a new divisor, linearly equivalent + to ``divisor``, but not intersecting ``S``, and ``B`` is a list of tuples + ``(v, b)`` where ``b`` are the functions giving the linear equivalence, + added with multiplicity ``v``. + + EXAMPLES:: + + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface + sage: R. = QQ[] + sage: S = RiemannSurface(y^2-x^3+1) + sage: avoid = Curve(S.f).places_at_infinity() + sage: D = 1*avoid[0] + sage: S.strong_approximation(D, avoid) + (- Place (x - 2, (x - 2)*y) + + Place (x - 1, y) + + Place (x^2 + x + 1, y), + [(1, (1/(x - 2))*y)]) + """ + # One would standardly expect to run this with + # S = Curve(self.f).places_at_infinity() + # or + # S = Curve(self.f).places_at_infinity()+self.places_at_branch_locus() + # + # To avoid current implementation issues with going between divisors + # and divisor lists, we implement a method that handles only divisors + K = self._R.base_ring() + if not K==QQ: + raise NotImplementedError + C = Curve(self.f) + KC = C.function_field() + g0, g1 = self._R.gens() + Kb = FunctionField(K, str(g0)) + Pz = PolynomialRing(K, g0) + Pw = PolynomialRing(K, g1) + MO = Kb.maximal_order() + + D_base = -sum(S) + + rr = self._vertices[self._basepoint[0]].real() + rr = rr.ceil() + Fac = g0-K(rr) + p0 = MO.ideal(Fac).place() + q0 = KC.places_above(p0)[0] + + new_divisor = divisor + B = [] + for p in divisor.support(): + if p in S: + v = divisor.valuation(p) + i = S.index(p) + Q = S[i] + D = D_base+Q + if D==0: + ios = self.genus + else: + ios = len(D.basis_differential_space()) + while ios>0: + D += q0 + ios = len(D.basis_differential_space()) + LD = D.function_space() + V = LD[0] + a = LD[1] + b = 0 + for s in S: + LDps = (D+s).function_space() + Vps = LDps[0] + ebd = [LDps[2](a(g)) for g in V.gens()] + U = Vps.span(ebd) + Quot = Vps.quotient(U) + bs = LDps[1](Quot.lift(Quot.basis()[0])) + b += bs + B.append((v,b)) + new_divisor += v*b.divisor() + return new_divisor, B + + def divisor_to_divisor_list(self, divisor): + r""" + Turn a divisor into a list for :meth:`abel_jacobi`. + + Given ``divisor`` in ``Curve(self.f).function_field().divisor_group()``, + consisting of places above finite points in the base, return an equivalent + divisor list suitable for input into :meth:`abel_jacboi`. + + INPUT: + + - ``divisor`` -- an element of ``Curve(self.f).function_field().divisor_group()`` + + OUTPUT: + + A list with elements of the form ``(v, (z, w))`` representing the finite places. + + EXAMPLES:: + + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface + sage: R. = QQ[] + sage: S = RiemannSurface(y^2-x^3+1) + sage: D = sum(S.places_at_branch_locus()) + sage: S.divisor_to_divisor_list(D) + [(1, (-1.00000000000000, 0.000000000000000)), + (1, (0.500000000000000 - 0.866025403784439*I, 0.000000000000000)), + (1, (0.500000000000000 + 0.866025403784439*I, 0.000000000000000))] + + .. TODO:: + + Currently this method can only handle places above finite points in + the base. It would be useful to extend this to allow for places at + infinity. + """ + eps = self._RR(2)**(-self._prec+3) + dl = [] + for d in divisor.support(): + v = divisor.valuation(d) + gs = d._prime.gens() + gs = [self._R(gi) for gi in gs] + g0 = gs[0] + gis = gs[1:] + + rs = S._CCz(g0).roots() + rys = [] + + for r, m in rs: + ys = [] + for gi in gis: + ers = [gi(r,y).abs() for y in ys] + try: + ers = min(ers) + except: + ers = 1 + if not ers Date: Thu, 12 Aug 2021 10:20:00 +0100 Subject: [PATCH 009/742] Bug fixes and documentation changes. A collection of small changes from errors highlighted by doctests. --- .../riemann_surfaces/riemann_surface.py | 74 +++++++++++-------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 744e0163b13..951fd10276c 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -30,7 +30,7 @@ sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface sage: R. = QQ[] sage: f = x^4-x^3*y+2*x^3+2*x^2*y+2*x^2-2*x*y^2+4*x*y-y^3+3*y^2+2*y+1 - sage: S = RiemannSurface(f,prec=100) + sage: S = RiemannSurface(f, prec=100) sage: M = S.riemann_matrix() We test the usual properties, i.e., that the period matrix is symmetric and that @@ -70,8 +70,10 @@ # **************************************************************************** from scipy.spatial import Voronoi +from sage.arith.functions import lcm from sage.arith.misc import GCD, algdep from sage.ext.fast_callable import fast_callable +from sage.functions.log import lambert_w from sage.graphs.graph import Graph from sage.groups.matrix_gps.finitely_generated import MatrixGroup from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -85,11 +87,14 @@ from sage.modules.free_module_integer import IntegerLattice from sage.numerical.gauss_legendre import integrate_vector, integrate_vector_N from sage.rings.complex_mpfr import ComplexField, CDF +from sage.rings.function_field.constructor import FunctionField +from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.qqbar import number_field_elements_from_algebraics from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RealField +from sage.schemes.curves.constructor import Curve import sage.libs.mpmath.all as mpall def voronoi_ghost(cpoints, n=6, CC=CDF): @@ -339,9 +344,11 @@ def find_closest_element(item, List): EXAMPLES:: + sage: from sage.schemes.riemann_surfaces.riemann_surface import find_closest_element sage: i = 5 sage: l = list(range(10)) sage: i == find_closest_element(i, l) + True Note that this method does no checks on the input, but will fail for inputs where the absolute value or subtraction do not make sense. @@ -381,18 +388,18 @@ def reparameterise_differential_minpoly(minpoly, z0): Hence the transformed differential should have minimal polynomial `\bar{g}^2\bar{z}(1-\bar{z}^3)-1/4=0`, and we can check this:: - sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface, reparameterise_differential_minpoly sage: R. = QQ[] sage: S = RiemannSurface(w^2-z^3+1) sage: minpoly = S._cohomology_basis_bounding_data[1][0][2] sage: z0 = Infinity - sage: S.reparameterise_differential_minpoly(minpoly, z0) + sage: reparameterise_differential_minpoly(minpoly, z0) -zbar^4*gbar^2 + zbar*gbar^2 - 1/4 We can further check that reparameterising about `0` is the identity operation:: - sage: S.reparameterise_differential_minpoly(minpoly, 0)(*minpoly.parent().gens())==minpoly + sage: reparameterise_differential_minpoly(minpoly, 0)(*minpoly.parent().gens())==minpoly True .. NOTE:: @@ -869,7 +876,8 @@ def homotopy_continuation(self, edge): sage: S = RiemannSurface(f) sage: edge1 = sorted(S.edge_permutations())[0] sage: sigma = S.edge_permutations()[edge1] - sage: continued_values = S.homotopy_continuation(edge1) + sage: edge = [S._vertices[i] for i in edge1] + sage: continued_values = S.homotopy_continuation(edge)[-1][1] sage: stored_values = S.w_values(S._vertices[edge1[1]]) sage: all(abs(continued_values[i]-stored_values[sigma(i)]) < 1e-8 for i in range(3)) True @@ -947,7 +955,7 @@ def _determine_new_w(self, z0, oldw, epsilon): sage: z0 = S._vertices[0] sage: epsilon = 0.1 sage: oldw = S.w_values(z0) - sage: neww = S._determine_new_w(z0,oldw,epsilon); neww #abs tol 0.00000001 + sage: neww = S._determine_new_w(z0, oldw, epsilon); neww #abs tol 0.00000001 [-0.934613146929672 + 2.01088055918363*I, 0.934613146929672 - 2.01088055918363*I] @@ -964,13 +972,13 @@ def _determine_new_w(self, z0, oldw, epsilon): sage: g = z^3*w + w^3 + z sage: T = RiemannSurface(g) - sage: z0 = T._vertices[2]*(0.9) - T._vertices[15]*(0.1) + sage: z0 = T._vertices[2]*(0.9) - T._vertices[5]*(0.1) sage: epsilon = 0.5 sage: oldw = T.w_values(T._vertices[2]) - sage: T._determine_new_w(z0,oldw,epsilon) - [-0.562337685361648 + 0.151166007149998*I, - 0.640201585779414 - 1.48567225836436*I, - -0.0778639004177661 + 1.33450625121437*I] + sage: T._determine_new_w(z0, oldw, epsilon) + Traceback (most recent call last): + ... + ConvergenceError: Newton iteration escaped neighbourhood .. NOTE:: @@ -1056,11 +1064,13 @@ def _newton_iteration(self, z0, oldw, epsilon): sage: g = z^3*w + w^3 + z sage: T = RiemannSurface(g) - sage: z0 = T._vertices[2]*(0.9) - T._vertices[15]*(0.1) + sage: z0 = T._vertices[2]*(0.9) - T._vertices[5]*(0.1) sage: epsilon = 0.5 - sage: oldw = T.w_values(T._vertices[2])[0] + sage: oldw = T.w_values(T._vertices[2])[1] sage: T._newton_iteration(z0, oldw, epsilon) - -0.562337685361648 + 0.151166007149998*I + Traceback (most recent call last): + ... + ConvergenceError: Newton iteration escaped neighbourhood """ F = self._fastcall_f dF = self._fastcall_dfdw @@ -1153,12 +1163,12 @@ def _edge_permutation(self, edge): sage: f = z^3*w + w^3 + z sage: S = RiemannSurface(f) - Compute the edge permutation of (1,2) on the Voronoi diagram:: + Compute the edge permutation of (2, 9) on the Voronoi diagram:: - sage: S._edge_permutation((1,2)) - (0,2,1) + sage: S._edge_permutation((2, 9)) + (1,2) - This indicates that while traversing along the direction of `(5,16)`, + This indicates that while traversing along the direction of `(2, 9)`, the 2nd and 3rd layers of the Riemann surface are interchanging. """ if edge in self.downstairs_edges(): @@ -1201,17 +1211,17 @@ def edge_permutations(self) -> dict: (1, 2): (), (1, 3): (0,1), (1, 6): (), - (2, 5): (0,1), - (3, 4): (), - (5, 7): (), - (6, 7): (), (2, 0): (), - (4, 0): (), (2, 1): (), + (2, 5): (0,1), (3, 1): (0,1), - (6, 1): (), - (5, 2): (0,1), + (3, 4): (), + (4, 0): (), (4, 3): (), + (5, 2): (0,1), + (5, 7): (), + (6, 1): (), + (6, 7): (), (7, 5): (), (7, 6): ()} """ @@ -1749,7 +1759,7 @@ def _bounding_data(self, differentials, exact=False): sage: S._cohomology_basis_bounding_data (Multivariate Polynomial Ring in z, g over Rational Field, - [(1/(2*y), + [(1/(2*w), (-3*z^2*g)/(2*z^3 - 2), z^3*g^2 - g^2 - 1/4, (1.00000000000000, @@ -1841,8 +1851,7 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): sage: _ = S.homology_basis() sage: differentials = S.cohomology_basis() sage: bounding_data = S._bounding_data(differentials) - sage: S.rigorous_line_integral([(0,0), (1,0)], differentials, - bounding_data) + sage: S.rigorous_line_integral([(0,0), (1,0)], differentials, bounding_data) # abs tol 1e-10 (1.80277751848459e-16 - 0.352971844594760*I) .. NOTE:: @@ -2211,7 +2220,8 @@ def path(t): P += line3d([path(t[0])+(t[1][i].imag_part(),) for t in T],color=color,thickness=thickness) for z,ws in zip(self._vertices,self._wvalues): for w in ws: - P += point3d([z.real_part(),z.imag_part(),w.imag_part()],color="purple", size=20) + P += point3d([z.real_part(), z.imag_part(), w.imag_part()], + color="purple", size=20) return P def endomorphism_basis(self, b=None, r=None): @@ -2889,7 +2899,8 @@ def _aj_based(self, P): As the output of ``_aj_based`` is difficult to intepret due to its path dependency, we look at the output of :meth:`abel_jacobi`. We check for two hyperelliptic curves that the Abel-Jacobi map between two branch - points is a 2-torsion point over the lattice:: + points is a 2-torsion point over the lattice. Note we must remember to + reduce over the period lattice, as results are path dependent:: sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface sage: R. = QQ[] @@ -2897,6 +2908,8 @@ def _aj_based(self, P): sage: divisor = [(-1, (Infinity, 0)), (1, (1, 0))] sage: AJ = S.abel_jacobi(divisor) sage: AJx2 = [2*z for z in AJ] + sage: vector(AJx2).norm() # abs tol 1e-10 + 2.4286506478875809114000865640 sage: bool(S.reduce_over_period_lattice(AJx2).norm()<1e-10) True sage: S = RiemannSurface(y^2-x^4+1) @@ -3128,6 +3141,7 @@ def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None): VR = VectorSpace(self._RR, 2*self.genus) VC = VectorSpace(self._CC, self.genus) + I = self._CC(0,-1) if method=="svp": H = max(max(z.real_part().abs() for z in vector), From 81164656a2e46b19d23f5db672d819cd3971f77a Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Thu, 12 Aug 2021 13:59:01 +0100 Subject: [PATCH 010/742] Document fixes. --- .../schemes/riemann_surfaces/riemann_surface.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 951fd10276c..2f20b79341e 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -739,6 +739,7 @@ def downstairs_graph(self): G.set_pos(dict(enumerate(list(v) for v in self._vertices))) return G + @cached_method def upstairs_graph(self): r""" Return the graph of the upstairs edges. @@ -1379,8 +1380,7 @@ def homology_basis(self): if self.genus == 0: return [] - edgesu = self.upstairs_edges() - cycles = Graph(edgesu).cycle_basis() + cycles = self.upstairs_graph().cycle_basis() # Computing the Gram matrix. cn = len(cycles) # Forming a list of lists of zeroes. @@ -2904,7 +2904,8 @@ def _aj_based(self, P): sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface sage: R. = QQ[] - sage: S = RiemannSurface(y^2-x^3+1) + sage: p = 100 + sage: S = RiemannSurface(y^2-x^3+1, prec=p) sage: divisor = [(-1, (Infinity, 0)), (1, (1, 0))] sage: AJ = S.abel_jacobi(divisor) sage: AJx2 = [2*z for z in AJ] @@ -2912,7 +2913,7 @@ def _aj_based(self, P): 2.4286506478875809114000865640 sage: bool(S.reduce_over_period_lattice(AJx2).norm()<1e-10) True - sage: S = RiemannSurface(y^2-x^4+1) + sage: S = RiemannSurface(y^2-x^4+1, prec=p) sage: divisor = [(-1, (-1, 0)), (1, (1, 0))] sage: AJ = S.abel_jacobi(divisor) sage: AJx2 = [2*z for z in AJ] @@ -3342,9 +3343,9 @@ def divisor_to_divisor_list(self, divisor): sage: S = RiemannSurface(y^2-x^3+1) sage: D = sum(S.places_at_branch_locus()) sage: S.divisor_to_divisor_list(D) - [(1, (-1.00000000000000, 0.000000000000000)), - (1, (0.500000000000000 - 0.866025403784439*I, 0.000000000000000)), - (1, (0.500000000000000 + 0.866025403784439*I, 0.000000000000000))] + [(1, (1.00000000000000, 0.000000000000000)), + (1, (-0.500000000000000 - 0.866025403784439*I, 0.000000000000000)), + (1, (-0.500000000000000 + 0.866025403784439*I, 0.000000000000000))] .. TODO:: @@ -3361,7 +3362,7 @@ def divisor_to_divisor_list(self, divisor): g0 = gs[0] gis = gs[1:] - rs = S._CCz(g0).roots() + rs = self._CCz(g0).roots() rys = [] for r, m in rs: From 6f7f5da36dc34ecfd53389f19025a1520c6ffac3 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Thu, 12 Aug 2021 14:30:15 +0100 Subject: [PATCH 011/742] Documentation fixes --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 2f20b79341e..e02ecfedbff 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3042,7 +3042,7 @@ def abel_jacobi(self, divisor, verbose=False): where ``v`` is the valuation of the divisor at point ``P``, ``P`` as per the input to :meth:`_aj_based`. - - `` verbose`` -- logical (default: False). Whether to report the progress + - ``verbose`` -- logical (default: False). Whether to report the progress of the computation, in terms of how many elements of the list ``divisor`` have been completed. From d437a21416845f98ac8138084a3b79c0a74e9344 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Fri, 13 Aug 2021 10:34:01 +0100 Subject: [PATCH 012/742] Documentation and bug fixes. --- .../riemann_surfaces/riemann_surface.py | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index e02ecfedbff..3b08f78a954 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -55,6 +55,45 @@ sage: all(len(a.minpoly().roots(K)) == a.minpoly().degree() for a in A) True +We can look at an extended example of the Abel-Jacobi functionality. We will +show that the sum of the intersections of a bitangent to a quadratic is a +half-canonical divisor. We will use the Edge quartic as the example, which has +bitangent `x=1/2`. + + sage: f = 25*(x^4+y^4+1) - 34*(x^2*y^2+x^2+y^2) + sage: S = RiemannSurface(f) + sage: BL = S.places_at_branch_locus(); BL + [Place (x - 2, (x - 2)*y, y^2 - 17/5, y^3 - 17/5*y), + Place (x + 2, (x + 2)*y, y^2 - 17/5, y^3 - 17/5*y), + Place (x - 1/2, (x - 1/2)*y, y^2 - 17/20, y^3 - 17/20*y), + Place (x + 1/2, (x + 1/2)*y, y^2 - 17/20, y^3 - 17/20*y), + Place (x^4 - 34/25*x^2 + 1, y, y^2, y^3), + Place (x^4 - 34/25*x^2 + 1, (x^4 - 34/25*x^2 + 1)*y, y^2 - 34/25*x^2 - 34/25, y^3 + (-34/25*x^2 - 34/25)*y)] + +We can read off out the output of ``places_at_branch_locus`` to choose our +divisor, and we can calculate the canonical divisor using curve functionality:: + + sage: D = 1*BL[2] + sage: from sage.schemes.curves.constructor import Curve + sage: C = Curve(f) + sage: F = C.function_field() + sage: K = (F(x).differential()).divisor() + +Note we could check using exact techniques that `2D=K`:: + + sage: Z = K-2*D + sage: (Z.degree()==0, len(Z.basis_differential_space())==S.genus, len(Z.basis_function_space())==1) + (True, True, True) + +We can also check this using our Abel-Jacobi functions:: + + sage: avoid = C.places_at_infinity() + sage: Zeq, _ = S.strong_approximation(Z, avoid) + sage: Zlist = S.divisor_to_divisor_list(Zeq) + sage: AJ = S.abel_jacobi(Zlist) # long time (50 seconds) + sage: S.reduce_over_period_lattice(AJ).norm()<1e-10 # long time + True + REFERENCES: The initial version of this code was developed alongside [BSZ2019]_. @@ -3353,6 +3392,8 @@ def divisor_to_divisor_list(self, divisor): the base. It would be useful to extend this to allow for places at infinity. """ + # If this error bound is too restrictive, this method might fail and + # not return. One might want to change the way this error is handled. eps = self._RR(2)**(-self._prec+3) dl = [] for d in divisor.support(): @@ -3373,7 +3414,7 @@ def divisor_to_divisor_list(self, divisor): ers = min(ers) except: ers = 1 - if not ers Date: Fri, 13 Aug 2021 17:09:32 +0100 Subject: [PATCH 013/742] Documentation changes and slight refactoring Fast-callables of the cohomology basis have been stored to the main object to reduce the time to compute the Abel-Jacobi map (only slightly), and fixes for the documentation. --- .../riemann_surfaces/riemann_surface.py | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 0b1903d2406..a108ac3871a 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -17,6 +17,9 @@ period lattice numerically, by determining integer (near) solutions to the relevant approximate linear equations. +One can also calculate the Abel-Jacobi map on the Riemann surface, and there +is basic functionality to interface with divisors of curves to facilitate this. + AUTHORS: - Alexandre Zotine, Nils Bruin (2017-06-10): initial version @@ -58,7 +61,7 @@ We can look at an extended example of the Abel-Jacobi functionality. We will show that the sum of the intersections of a bitangent to a quadratic is a half-canonical divisor. We will use the Edge quartic as the example, which has -bitangent `x=1/2`. +bitangent `x=1/2`:: sage: f = 25*(x^4+y^4+1) - 34*(x^2*y^2+x^2+y^2) sage: S = RiemannSurface(f) @@ -705,6 +708,8 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati self._fastcall_f = fast_callable(f, domain=self._CC) self._fastcall_dfdw = fast_callable(self._dfdw, domain=self._CC) self._fastcall_dfdz = fast_callable(self._dfdz, domain=self._CC) + self._fastcall_cohomology_basis = [fast_callable(h, domain = self._CC) + for h in self.cohomology_basis()] def __repr__(self): r""" @@ -1866,7 +1871,7 @@ def _bounding_data(self, differentials, exact=False): sage: S._cohomology_basis_bounding_data (Multivariate Polynomial Ring in z, g over Rational Field, - [(1/(2*w), + [(1/(2*y), (-3*z^2*g)/(2*z^3 - 2), z^3*g^2 - g^2 - 1/4, (1.00000000000000, @@ -2165,7 +2170,12 @@ def normalize_pairs(L): occurring_edges.update(*[normalize_pairs(p[1]) for h in cycles for p in h]) - fcd = [fast_callable(omega, domain=self._CC) for omega in differentials] + if differentials is self.cohomology_basis(): + fcd = self._fastcall_cohomology_basis + integral_dict = self._integral_dict + else: + fcd = [fast_callable(omega, domain=self._CC) for omega in differentials] + integral_dict = dict() if integration_method=="heuristic": line_int = lambda edge: self.simple_vector_line_integral(edge, fcd) @@ -2175,14 +2185,9 @@ def normalize_pairs(L): else: raise ValueError("Invalid integration method") - if differentials is self.cohomology_basis(): - integral_dict = self._integral_dict - for upstairs_edge in occurring_edges: - if not upstairs_edge in integral_dict.keys(): - integral_dict[upstairs_edge] = line_int(upstairs_edge) - else: - integral_dict = {upstairs_edge: lint_int(upstairs_edge) - for upstairs_edge in occurring_edges} + for upstairs_edge in occurring_edges: + if not upstairs_edge in integral_dict.keys(): + integral_dict[upstairs_edge] = line_int(upstairs_edge) rows = [] for cycle in cycles: @@ -3054,7 +3059,7 @@ def _aj_based(self, P): """ ##### - fcd = [fast_callable(h, domain = self._CC) for h in self.cohomology_basis()] + fcd = self._fastcall_cohomology_basis if self._integration_method=="heuristic": line_int = lambda edge: self.simple_vector_line_integral(edge, fcd) From 822a47b117cad0f5117e38e8c9f6f37f3871e50c Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Mon, 16 Aug 2021 10:35:05 +0100 Subject: [PATCH 014/742] Methodology changes based on comment 11 --- .../riemann_surfaces/riemann_surface.py | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index a108ac3871a..0005252a56e 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -678,7 +678,7 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati self._differentials_branch_locus += self._CCz(x[0](self._CCz.gen(), 0)).roots(multiplicities=False) # We add these branchpoints to the existing. - self.branch_locus = self.branch_locus+self._differentials_branch_locus + #self.branch_locus = self.branch_locus+self._differentials_branch_locus # We now want to also check whether Infinity is a branch point of any # of the differentials. # This will be useful when calculating the Abel-Jacobi map. @@ -3097,8 +3097,12 @@ def _aj_based(self, P): V_index = find_closest_element(zP, self._vertices) b_index = find_closest_element(zP, self.branch_locus) b = self.branch_locus[b_index] - - d1 = self._CC(1e-2)*max(b.abs() for b in self.branch_locus) + #bl = self.branch_locus+self._differentials_branch_locus + #b_index = find_closest_element(zP, bl) + #b = bl[b_index] + + scale = max(b.abs() for b in self.branch_locus) + d1 = self._CC(1e-2)*scale # We choose the first vertex we want to go to. # If the closest vertex is closer than the nearest branch point, just take that vertex @@ -3108,17 +3112,17 @@ def _aj_based(self, P): region = self.voronoi_diagram.regions[self.voronoi_diagram.point_region[b_index]] args = [(self._vertices[i]-zP).argument() - (b-zP).argument() for i in region] suitable_vertex_indices = [region[i] - for i in range(len(region)) if args[i].abs()>self._RR.pi()/2] + for i in range(len(region)) if args[i].abs()-self._RR.pi()/2>=-self._RR(1e-15)] suitable_vertices = [self._vertices[i] for i in suitable_vertex_indices] if suitable_vertices==[]: raise ValueError("There is no satisfactory choice of V for zP={}".format(zP)) V_index = suitable_vertex_indices[find_closest_element(zP, suitable_vertices)] ##### zV = self._vertices[V_index] - d_edge = (zP, zV) if (zP-b).abs() >= d1 or b in self._differentials_branch_locus: wP_index = find_closest_element(wP, self.w_values(zP)) + d_edge = (zP, zV) u_edge = ((zP, wP_index), (zV, )) initial_continuation = self.homotopy_continuation(d_edge) AJ = -line_int(u_edge) @@ -3129,6 +3133,23 @@ def _aj_based(self, P): zs = zP ws = wP + ##### + # Here we need a block of code to change the vertex if the path + # from zP to zV would go through a ramification point of the integrands + fl = [c for c in self._differentials_branch_locus if not c==self._CC(Infinity)] + ts = [((c-zP)*(zV-zP).conjugate()).real()/(zP-zV).norm()**2 + for c in fl] + ds = [(fl[i]-zP-ts[i]*(zV-zP)).abs() + for i in range(len(ts)) if (ts[i]>=0 and ts[i]<=1)] + while (len(ds)>=1 and min(ds)=0 and ts[i]<=1)] + ##### + while self._dfdw(zs, ws).abs()==0: zs = zs+delta*(zV-zs)/(zV-zs).abs()/2 ws_list = self.w_values(zs) From bc92b3c7212f534f1ccceccae7e5565ddbe93aac Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Mon, 16 Aug 2021 11:16:38 +0100 Subject: [PATCH 015/742] Documentation changes Examples needed to be fixed given a change in the nature of the code in the last commit. --- .../riemann_surfaces/riemann_surface.py | 81 +++++++++++-------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 0005252a56e..8a03dd9e440 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -561,24 +561,44 @@ class RiemannSurface(object): sage: Sr = RiemannSurface(f, prec=p, integration_method='rigorous') sage: from sage.numerical.gauss_legendre import nodes sage: nodes.cache.clear() - sage: %time Rh = Sh.riemann_matrix() # random | long time (2 seconds) - CPU times: user 2.38 s, sys: 36 µs, total: 2.38 s - Wall time: 2.38 s + sage: %time Rh = Sh.riemann_matrix() # random | long time (1 second) + CPU times: user 795 ms, sys: 0 ns, total: 795 ms + Wall time: 799 ms sage: nodes.cache.clear() - sage: %time Rr = Sr.riemann_matrix() # random | long time (3 seconds) - CPU times: user 2.67 s, sys: 66 µs, total: 2.67 s - Wall time: 2.67 s - sage: p = 200 + sage: %time Rr = Sr.riemann_matrix() # random | long time (2 seconds) + CPU times: user 1.75 s, sys: 0 ns, total: 1.75 s + Wall time: 1.75 s + sage: p = 500 sage: Sh = RiemannSurface(f, prec=p, integration_method='heuristic') sage: Sr = RiemannSurface(f, prec=p, integration_method='rigorous') sage: nodes.cache.clear() - sage: %time Rh = Sh.riemann_matrix() # random | long time (7 seconds) - CPU times: user 7.12 s, sys: 4.01 ms, total: 7.13 s - Wall time: 7.13 s + sage: %time Rh = Sh.riemann_matrix() # random | long time (8 seconds) + CPU times: user 8.43 s, sys: 0 ns, total: 8.43 s + Wall time: 8.43 ss sage: nodes.cache.clear() - sage: %time Rr = Sr.riemann_matrix() # random | long time (5 seconds) - CPU times: user 4.91 s, sys: 9 µs, total: 4.91 s - Wall time: 4.91 s + sage: %time Rr = Sr.riemann_matrix() # random | long time (10 seconds) + CPU times: user 9.69 s, sys: 0 ns, total: 9.69 s + Wall time: 9.69 s + + Note that for the above curve, the branch points are evenly distributed, and + hence the implicit assumptions in the heuristic method are more sensible, + meaning that a higher precision is required to see the heuristic method + being significantly slower than the rigorous method. For a worse conditioned + curve, this effect is more pronounced:: + + sage: q = 1/10 + sage: f = y^2-(x^2-2*x+1+q^2)*(x^2+2*x+1+q^2) + sage: p = 500 + sage: Sh = RiemannSurface(f, prec=p, integration_method='heuristic') + sage: Sr = RiemannSurface(f, prec=p, integration_method='rigorous') + sage: nodes.cache.clear() + sage: %time Rh = Sh.riemann_matrix() # random | long time (7 second) + CPU times: user 7.45 s, sys: 0 ns, total: 7.45 s + Wall time: 7.44 s + sage: nodes.cache.clear() + sage: %time Rr = Sr.riemann_matrix() # random | long time (2 second) + CPU times: user 1.5 s, sys: 0 ns, total: 1.5 s + Wall time: 1.5 s This disparity in timings can get increasingly worse, and testing has shown that even for random quadrics the heuristic method can be as bad as 30 times @@ -1068,7 +1088,7 @@ def _determine_new_w(self, z0, oldw, epsilon): sage: g = z^3*w + w^3 + z sage: T = RiemannSurface(g) - sage: z0 = T._vertices[2]*(0.9) - T._vertices[5]*(0.1) + sage: z0 = T._vertices[2]*(0.9) + 0.3*I sage: epsilon = 0.5 sage: oldw = T.w_values(T._vertices[2]) sage: T._determine_new_w(z0, oldw, epsilon) @@ -1160,7 +1180,7 @@ def _newton_iteration(self, z0, oldw, epsilon): sage: g = z^3*w + w^3 + z sage: T = RiemannSurface(g) - sage: z0 = T._vertices[2]*(0.9) - T._vertices[5]*(0.1) + sage: z0 = T._vertices[2]*(0.9) + 0.3*I sage: epsilon = 0.5 sage: oldw = T.w_values(T._vertices[2])[1] sage: T._newton_iteration(z0, oldw, epsilon) @@ -1259,10 +1279,10 @@ def _edge_permutation(self, edge): sage: f = z^3*w + w^3 + z sage: S = RiemannSurface(f) - Compute the edge permutation of (2, 9) on the Voronoi diagram:: + Compute the edge permutation of (1, 2) on the Voronoi diagram:: - sage: S._edge_permutation((2, 9)) - (1,2) + sage: S._edge_permutation((1, 2)) + (0,2,1) This indicates that while traversing along the direction of `(2, 9)`, the 2nd and 3rd layers of the Riemann surface are interchanging. @@ -1350,28 +1370,21 @@ def monodromy_group(self): sage: f = z^3*w + w^3 + z sage: S = RiemannSurface(f) sage: G = S.monodromy_group(); G - [(0,2,1), (0,1), (1,2), (0,2), (0,2), (1,2), (0,2), (0,1), (), (), (), (), (), (), (), (1,2)] + [(0,1,2), (0,1), (0,2), (1,2), (1,2), (1,2), (0,1), (0,2), (0,2)] The permutations give the local monodromy generators for the branch points:: sage: list(zip(S.branch_locus + [unsigned_infinity], G)) #abs tol 0.0000001 - [(0.000000000000000, (0,2,1)), + [(0.000000000000000, (0,1,2)), (-1.31362670141929, (0,1)), - (-0.819032851784253 - 1.02703471138023*I, (1,2)), - (-0.819032851784253 + 1.02703471138023*I, (0,2)), - (0.292309440469772 - 1.28069133740100*I, (0,2)), + (-0.819032851784253 - 1.02703471138023*I, (0,2)), + (-0.819032851784253 + 1.02703471138023*I, (1,2)), + (0.292309440469772 - 1.28069133740100*I, (1,2)), (0.292309440469772 + 1.28069133740100*I, (1,2)), - (1.18353676202412 - 0.569961265016465*I, (0,2)), - (1.18353676202412 + 0.569961265016465*I, (0,1)), - (-1.45036146591896, ()), - (-0.904285583009352 - 1.13393825501392*I, ()), - (-0.904285583009352 + 1.13393825501392*I, ()), - (0.322735787970535 - 1.41399787587734*I, ()), - (0.322735787970535 + 1.41399787587734*I, ()), - (1.30673052799829 - 0.629288255904939*I, ()), - (1.30673052799829 + 0.629288255904939*I, ()), - (Infinity, (1,2))] + (1.18353676202412 - 0.569961265016465*I, (0,1)), + (1.18353676202412 + 0.569961265016465*I, (0,2)), + (Infinity, (0,2))] We can check the ramification by looking at the cycle lengths and verify it agrees with the Riemann-Hurwitz formula:: @@ -1715,7 +1728,7 @@ def simple_vector_line_integral(self, upstairs_edge, differentials): sage: M = S.riemann_matrix() sage: differentials = S.cohomology_basis() - sage: S.simple_vector_line_integral([(0,0),(1,0)], differentials) #abs tol 0.00000001 + sage: S.simple_vector_line_integral([(0, 0), (1, 0)], differentials) #abs tol 0.00000001 (1.14590610929717e-16 - 0.352971844594760*I) .. NOTE:: From 1ef9823e8fdc8c386f77c46bd66a5a2019044581 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Sat, 21 Aug 2021 12:32:18 +0100 Subject: [PATCH 016/742] Typo fixes. Fixing typos identified by a run of tox. --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 9e34a7af9eb..c2730db86f9 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -449,7 +449,7 @@ def reparameterise_differential_minpoly(minpoly, z0): As part of the routine, when reparameterising about infinity, a rational function is reduced and then the numerator is taken. Over an inexact ring this is numerically unstable, and so it is advisable - to only reparameterise about infinty over an exact ring. + to only reparameterise about infinity over an exact ring. """ P = minpoly.parent() F = PolynomialRing(P.base_ring(), [str(v)+"bar" for v in P.gens()]) @@ -1853,7 +1853,7 @@ def _bounding_data(self, differentials, exact=False): the list corresponds to an element of ``differentials``. Introducing the notation ``RBzg = PolynomialRing(self._R, ['z','g'])`` and ``CCzg = PolynomialRing(self._CC, ['z','g'])``, we have that: - - ``Rzg`` is either ``RBzg`` or ``CCzg`` depending on the vlaue of + - ``Rzg`` is either ``RBzg`` or ``CCzg`` depending on the value of ``exact``, - ``g`` is the full rational function in ``self._R.fraction_field()`` giving the differential, @@ -3044,7 +3044,7 @@ def _aj_based(self, P): EXAMPLES: - As the output of ``_aj_based`` is difficult to intepret due to its path + As the output of ``_aj_based`` is difficult to interpret due to its path dependency, we look at the output of :meth:`abel_jacobi`. We check for two hyperelliptic curves that the Abel-Jacobi map between two branch points is a 2-torsion point over the lattice. Note we must remember to @@ -3100,7 +3100,7 @@ def _aj_based(self, P): g0s = [self.cohomology_basis()[0](zV, wi)/self._dfdw(zV, wi) for wi in ws] W_index = find_closest_element(g0e, g0s) if (g0e - self.cohomology_basis()[0](zV, ws[W_index])/self._dfdw(zV, ws[W_index])).abs()>1e-10: - raise ConvergenceError("Integrand continuation failed to get representative values, higher precision requried.") + raise ConvergenceError("Integrand continuation failed to get representative values, higher precision required.") V_index = B[0] else: zP = self._CC(zP) @@ -3176,7 +3176,7 @@ def _aj_based(self, P): g0s = [self.cohomology_basis()[0](zV, wi)/self._dfdw(zV, wi) for wi in ws] W_index = find_closest_element(g0e, g0s) if (g0e - self.cohomology_basis()[0](zV, ws[W_index])/self._dfdw(zV, ws[W_index])).abs()>1e-10: - raise ConvergenceError("Integrand continuation failed to get representative values, higher precision requried.") + raise ConvergenceError("Integrand continuation failed to get representative values, higher precision required.") uV_index = (V_index, W_index) ##### From fb194e3d18ab30e08f1f56180eb18ad1e525d1c7 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Sat, 21 Aug 2021 13:05:18 +0100 Subject: [PATCH 017/742] Minor method change. A small change was made in the rigorous_line_integral to avoid some unnecessary subtractions. --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index c2730db86f9..e621dad61cf 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -2083,11 +2083,11 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): # Distance to the discriminant points distances = [(cz-b).abs() for b in self.branch_locus] rho_z = min(distances) - rho_t = rho_z/(z1-z0).abs() + rho_t = rho_z/(z1_minus_z0).abs() if rho_t > rt: rho_t = alpha*rho_t+(1-alpha)*rt # sqrt(rho_t*rt) could also work rho_z = rho_t*(z1-z0).abs() - delta_z = (alpha*rho_t+(1-alpha)*rt)*(z1-z0).abs() + delta_z = (alpha*rho_t+(1-alpha)*rt)*(z1_minus_z0).abs() expr = rho_t/rt+((rho_t/rt)**2-1).sqrt() # Note this is really exp(arcosh(rho_t/rt)) N = 3 cw = zwt(ct)[1] From 068afafbbd26c4e134e810e05c279ceb6900dbc0 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Sat, 21 Aug 2021 15:09:27 +0100 Subject: [PATCH 018/742] Minor formatting edit. --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index e621dad61cf..ec8320fd9d0 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -2932,7 +2932,7 @@ def fv(hj, previous_estimate_and_validity): for j in range(100): new_delta = F(z0, newg) / dF(z0, newg) Nnew_delta = new_delta.norm() - if (new_delta == 0) or (Nnew_delta>=Ndelta and + if (new_delta == 0) or (Nnew_delta >= Ndelta and (Ndelta.sign_mantissa_exponent()[2] +self._prec) < newg.norm().sign_mantissa_exponent()[2]): outg.append(newg) @@ -2966,7 +2966,7 @@ def fv(hj, previous_estimate): for j in range(100): new_delta = F(z0, newg) / dF(z0, newg) Nnew_delta = new_delta.norm() - if (new_delta == 0) or (Nnew_delta>=Ndelta and + if (new_delta == 0) or (Nnew_delta >= Ndelta and (Ndelta.sign_mantissa_exponent()[2] +self._prec) < newg.norm().sign_mantissa_exponent()[2]): outg.append(newg) From b3c83bdb1c431c91e143af0b64417c2a45c7e139 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Sun, 22 Aug 2021 11:31:10 +0100 Subject: [PATCH 019/742] Minor formatting changes --- .../riemann_surfaces/riemann_surface.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index ec8320fd9d0..706f1ff6322 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -93,8 +93,8 @@ sage: avoid = C.places_at_infinity() sage: Zeq, _ = S.strong_approximation(Z, avoid) sage: Zlist = S.divisor_to_divisor_list(Zeq) - sage: AJ = S.abel_jacobi(Zlist) # long time (50 seconds) - sage: S.reduce_over_period_lattice(AJ).norm()<1e-10 # long time + sage: AJ = S.abel_jacobi(Zlist) # long time (50 seconds) + sage: S.reduce_over_period_lattice(AJ).norm() < 1e-10 # long time True REFERENCES: @@ -781,7 +781,7 @@ def w_values(self, z0): Note that typically the method returns a list of length ``self.degree``, but that at ramification points, this may no longer be true:: - sage: S.w_values(1) # abs tol 1e-14 + sage: S.w_values(1) # abs tol 1e-14 [0.000000000000000] """ return self.f(z0,self._CCw.gen(0)).roots(multiplicities=False) @@ -1986,7 +1986,7 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): sage: _ = S.homology_basis() sage: differentials = S.cohomology_basis() sage: bounding_data = S._bounding_data(differentials) - sage: S.rigorous_line_integral([(0,0), (1,0)], differentials, bounding_data) # abs tol 1e-10 + sage: S.rigorous_line_integral([(0,0), (1,0)], differentials, bounding_data) # abs tol 1e-10 (1.80277751848459e-16 - 0.352971844594760*I) .. NOTE:: @@ -3057,15 +3057,15 @@ def _aj_based(self, P): sage: divisor = [(-1, (Infinity, 0)), (1, (1, 0))] sage: AJ = S.abel_jacobi(divisor) sage: AJx2 = [2*z for z in AJ] - sage: vector(AJx2).norm() # abs tol 1e-10 + sage: vector(AJx2).norm() # abs tol 1e-10 2.4286506478875809114000865640 - sage: bool(S.reduce_over_period_lattice(AJx2).norm()<1e-10) + sage: bool(S.reduce_over_period_lattice(AJx2).norm() < 1e-10) True sage: S = RiemannSurface(y^2-x^4+1, prec=p) sage: divisor = [(-1, (-1, 0)), (1, (1, 0))] sage: AJ = S.abel_jacobi(divisor) sage: AJx2 = [2*z for z in AJ] - sage: bool(S.reduce_over_period_lattice(AJx2).norm()<1e-10) + sage: bool(S.reduce_over_period_lattice(AJx2).norm() < 1e-10) True """ @@ -3229,9 +3229,9 @@ def abel_jacobi(self, divisor, verbose=False): sage: p = 4 sage: S = RiemannSurface(y^p-x^4+1, prec=100) sage: divisor = [(-1, (-1, 0)), (1, (1, 0))] - sage: AJ = S.abel_jacobi(divisor) # long time (15 seconds) - sage: AJxp = [p*z for z in AJ] # long time - sage: bool(S.reduce_over_period_lattice(AJx2).norm()<1e-7) # long time + sage: AJ = S.abel_jacobi(divisor) # long time (15 seconds) + sage: AJxp = [p*z for z in AJ] # long time + sage: bool(S.reduce_over_period_lattice(AJx2).norm()<1e-7) # long time True """ ans = 0 From c44941741db4edbf488fa8d72af6a5481dab34b5 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Wed, 8 Sep 2021 15:09:44 +0100 Subject: [PATCH 020/742] Error bound improved. Using the tighter error bound from Rabinowitz, " Rough and ready error estimates in Gaussian integration of analytic functions", the value for the N required in the rigorous integration was reduced. --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 706f1ff6322..96f6af79fba 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -2108,7 +2108,7 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): cdgdz = dgdz(cz,cg) Delta = delta_z*cdgdz.abs() + (delta_z**2)*M_tilde/(rho_z*(rho_z-delta_z)) M = Delta - N_required = ((64*M/(15*(1-1/expr)*E_global)).log()/(2*expr.log())).ceil() + N_required = ((M*(self._RR.pi()+64/(15*(expr**2-1)))/E_global).log()/(2*expr.log())).ceil() N = max(N,N_required) N = (K*(self._RR(N).sqrt()/K).ceil())**2 From 7bd64d78134bd7442577e0dbe3eff16d6d8c0171 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Tue, 26 Oct 2021 11:13:04 +0100 Subject: [PATCH 021/742] Typo fixes --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 96f6af79fba..5d03a21f30f 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3035,7 +3035,7 @@ def _aj_based(self, P): - ``P`` -- tuple. A pair giving the endpoint of the integral, either in the form ``(z, w)`` or ``(Infinity, branch)``, where in the latter case - we are using the conventing that the `w` value over `\infty` is given by + we are using the convention that the `w` value over `\infty` is given by the limit as ``z`` tends to `\infty` of ``self.w_values(z)[branch]``. OUTPUT: From d8b063f44a10945597e487017225f7b0cf5b8b62 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Wed, 3 Nov 2021 16:11:04 +0000 Subject: [PATCH 022/742] Updates and bug fixes. The divisor_to_divisor_list method was made more general, and the reduce_over_period_lattice was made to allow for the period matrix to be normalised (helpful if calculating the RCV). The _aj_based method was updated to deal with errors caused when the point take the map to was already a vertex. --- .../riemann_surfaces/riemann_surface.py | 171 ++++++++++-------- 1 file changed, 98 insertions(+), 73 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 5d03a21f30f..37eacce9252 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3106,77 +3106,82 @@ def _aj_based(self, P): zP = self._CC(zP) wP = self._CC(wP) V_index = find_closest_element(zP, self._vertices) - b_index = find_closest_element(zP, self.branch_locus) - b = self.branch_locus[b_index] - #bl = self.branch_locus+self._differentials_branch_locus - #b_index = find_closest_element(zP, bl) - #b = bl[b_index] - - scale = max(b.abs() for b in self.branch_locus) - d1 = self._CC(1e-2)*scale - - # We choose the first vertex we want to go to. - # If the closest vertex is closer than the nearest branch point, just take that vertex - # otherwise we need something smarter. - delta = self._RR(2)**(-self._prec+1) - if not ((zP-self._vertices[V_index]).abs() < (zP-b).abs() or (zP-b).abs()<=delta): - region = self.voronoi_diagram.regions[self.voronoi_diagram.point_region[b_index]] - args = [(self._vertices[i]-zP).argument() - (b-zP).argument() for i in region] - suitable_vertex_indices = [region[i] - for i in range(len(region)) if args[i].abs()-self._RR.pi()/2>=-self._RR(1e-15)] - suitable_vertices = [self._vertices[i] for i in suitable_vertex_indices] - if suitable_vertices==[]: - raise ValueError("There is no satisfactory choice of V for zP={}".format(zP)) - V_index = suitable_vertex_indices[find_closest_element(zP, suitable_vertices)] - ##### - zV = self._vertices[V_index] - - if (zP-b).abs() >= d1 or b in self._differentials_branch_locus: - wP_index = find_closest_element(wP, self.w_values(zP)) - d_edge = (zP, zV) - u_edge = ((zP, wP_index), (zV, )) - initial_continuation = self.homotopy_continuation(d_edge) - AJ = -line_int(u_edge) - - w_end = initial_continuation[-1][1][wP_index] - W_index = find_closest_element(w_end, self._wvalues[V_index]) - else: - zs = zP - ws = wP + if zP==self._vertices[V_index]: + W_index = find_closest_element(wP, self._wvalues[V_index]) + AJ = 0 + else: + b_index = find_closest_element(zP, self.branch_locus) + b = self.branch_locus[b_index] + #bl = self.branch_locus+self._differentials_branch_locus + #b_index = find_closest_element(zP, bl) + #b = bl[b_index] + + scale = max(b.abs() for b in self.branch_locus) + d1 = self._CC(1e-2)*scale + + # We choose the first vertex we want to go to. + # If the closest vertex is closer than the nearest branch point, just take that vertex + # otherwise we need something smarter. + delta = self._RR(2)**(-self._prec+1) + if not ((zP-self._vertices[V_index]).abs() < (zP-b).abs() or (zP-b).abs()<=delta): + region = self.voronoi_diagram.regions[self.voronoi_diagram.point_region[b_index]] + args = [(self._vertices[i]-zP).argument() - (b-zP).argument() for i in region] + suitable_vertex_indices = [region[i] + for i in range(len(region)) if args[i].abs()-self._RR.pi()/2>=-self._RR(1e-15)] + suitable_vertices = [self._vertices[i] for i in suitable_vertex_indices] + if suitable_vertices==[]: + raise ValueError("There is no satisfactory choice of V for zP={}".format(zP)) + V_index = suitable_vertex_indices[find_closest_element(zP, suitable_vertices)] ##### - # Here we need a block of code to change the vertex if the path - # from zP to zV would go through a ramification point of the integrands - fl = [c for c in self._differentials_branch_locus if not c==self._CC(Infinity)] - ts = [((c-zP)*(zV-zP).conjugate()).real()/(zP-zV).norm()**2 - for c in fl] - ds = [(fl[i]-zP-ts[i]*(zV-zP)).abs() - for i in range(len(ts)) if (ts[i]>=0 and ts[i]<=1)] - while (len(ds)>=1 and min(ds)= d1 or b in self._differentials_branch_locus: + wP_index = find_closest_element(wP, self.w_values(zP)) + d_edge = (zP, zV) + u_edge = ((zP, wP_index), (zV, )) + initial_continuation = self.homotopy_continuation(d_edge) + AJ = -line_int(u_edge) + + w_end = initial_continuation[-1][1][wP_index] + W_index = find_closest_element(w_end, self._wvalues[V_index]) + else: + zs = zP + ws = wP + + ##### + # Here we need a block of code to change the vertex if the path + # from zP to zV would go through a ramification point of the integrands + fl = [c for c in self._differentials_branch_locus if not c==self._CC(Infinity)] ts = [((c-zP)*(zV-zP).conjugate()).real()/(zP-zV).norm()**2 for c in fl] ds = [(fl[i]-zP-ts[i]*(zV-zP)).abs() for i in range(len(ts)) if (ts[i]>=0 and ts[i]<=1)] - ##### - - while self._dfdw(zs, ws).abs()==0: - zs = zs+delta*(zV-zs)/(zV-zs).abs()/2 - ws_list = self.w_values(zs) - wP_index = find_closest_element(ws, ws_list) - ws = ws_list[wP_index] - upstairs_edge = ((zs, ws), zV) - AJ, endgs = self._integrate_differentials_iteratively(upstairs_edge, - cutoff_individually=False) - AJ = -AJ - g0e = endgs[0] + while (len(ds)>=1 and min(ds)=0 and ts[i]<=1)] + ##### + + while self._dfdw(zs, ws).abs()==0: + zs = zs+delta*(zV-zs)/(zV-zs).abs()/2 + ws_list = self.w_values(zs) + wP_index = find_closest_element(ws, ws_list) + ws = ws_list[wP_index] + upstairs_edge = ((zs, ws), zV) + AJ, endgs = self._integrate_differentials_iteratively(upstairs_edge, + cutoff_individually=False) + AJ = -AJ + g0e = endgs[0] - ws = self.w_values(zV) - g0s = [self.cohomology_basis()[0](zV, wi)/self._dfdw(zV, wi) for wi in ws] - W_index = find_closest_element(g0e, g0s) - if (g0e - self.cohomology_basis()[0](zV, ws[W_index])/self._dfdw(zV, ws[W_index])).abs()>1e-10: - raise ConvergenceError("Integrand continuation failed to get representative values, higher precision required.") + ws = self.w_values(zV) + g0s = [self.cohomology_basis()[0](zV, wi)/self._dfdw(zV, wi) for wi in ws] + W_index = find_closest_element(g0e, g0s) + if (g0e - self.cohomology_basis()[0](zV, ws[W_index])/self._dfdw(zV, ws[W_index])).abs()>1e-10: + raise ConvergenceError("Integrand continuation failed to get representative values, higher precision required.") uV_index = (V_index, W_index) ##### @@ -3245,7 +3250,7 @@ def abel_jacobi(self, divisor, verbose=False): print("Done, {}% complete".format(numerical_approx(100*(i+1)/n, 11))) return ans - def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None): + def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None, normalised=False): r""" Reduce a vector over the period lattice. @@ -3272,6 +3277,10 @@ def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None): - ``r`` -- integer (default: ``b/4``). as for :meth:`homomorphism_basis`, and used in its invocation if (re)calculating said basis. + + - ``normalised`` -- logical (default: ``False``). Whether to use the + period matrix with the differentials normalised s.t. the `A`-matrix + is the identity. OUTPUT: @@ -3312,6 +3321,12 @@ def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None): VR = VectorSpace(self._RR, 2*self.genus) VC = VectorSpace(self._CC, self.genus) I = self._CC(0,-1) + PM = self.period_matrix() + + if normalised: + AM = PM[:,0:g] + AInv = numerical_inverse(AM) + PM = AInv*PM if method=="svp": H = max(max(z.real_part().abs() for z in vector), @@ -3330,7 +3345,7 @@ def C2Z(v): return vR M = Matrix(ZZ, 2*self.genus, 2*self.genus, - [C2Z(c) for c in self.period_matrix().columns()]) + [C2Z(c) for c in PM.columns()]) u = C2Z(vector) L = IntegerLattice(M) u = VR(u)-VR(L.closest_vector(u)) @@ -3342,7 +3357,7 @@ def C2R(v): return VR([z.real_part() for z in v]+[z.imag_part() for z in v]) u = C2R(vector) - basis_vecs = [C2R(c) for c in self.period_matrix().columns()] + basis_vecs = [C2R(c) for c in PM.columns()] M = Matrix([[ei.dot_product(ej) for ei in basis_vecs] for ej in basis_vecs]) v_dot_e = VR([u.dot_product(e) for e in basis_vecs]) coeffs = M.solve_right(v_dot_e) @@ -3414,7 +3429,7 @@ def strong_approximation(self, divisor, S): OUTPUT: - A tuple ``(S, B)``, where ``D`` is a new divisor, linearly equivalent + A tuple ``(D, B)``, where ``D`` is a new divisor, linearly equivalent to ``divisor``, but not intersecting ``S``, and ``B`` is a list of tuples ``(v, b)`` where ``b`` are the functions giving the linear equivalence, added with multiplicity ``v``. @@ -3526,12 +3541,20 @@ def divisor_to_divisor_list(self, divisor): # not return. One might want to change the way this error is handled. eps = self._RR(2)**(-self._prec+3) dl = [] + + PZ = PolynomialRing(S._R.base(), 'z').fraction_field() + RF = PolynomialRing(PZ, 'w') + for d in divisor.support(): v = divisor.valuation(d) gs = d._prime.gens() - gs = [self._R(gi) for gi in gs] - g0 = gs[0] - gis = gs[1:] + + g0 = self._R(gs[0]) + gis = [sum([PZ(gi.list()[i])*RF.gen()**i + for i in range(len(gi.list()))]) for gi in gs[1:]] + #gs = [self._R(gi) for gi in gs] + #g0 = gs[0] + #gis = gs[1:] rs = self._CCz(g0).roots() rys = [] @@ -3539,13 +3562,15 @@ def divisor_to_divisor_list(self, divisor): for r, m in rs: ys = [] for gi in gis: - ers = [gi(r,y).abs() for y in ys] + ers = [gi(y, r).abs() for y in ys] + #ers = [gi(r,y).abs() for y in ys] try: ers = min(ers) except: ers = 1 if not ers<=eps: - poly = self._CCw(gi(r, self._CCw.gen(0))) + poly = self._CCw(gi(self._CCw.gen(0), r)) + #poly = self._CCw(gi(r, self._CCw.gen(0))) if poly==0: nys = [] else: From 61be2ca9bcef1b01e74cba93f25503c6620b0052 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Thu, 2 Dec 2021 12:26:39 +0000 Subject: [PATCH 023/742] Fixed error causing bugs with reduce_over_period_lattice --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 37eacce9252..bbb09e2def6 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3320,7 +3320,7 @@ def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None, normal VR = VectorSpace(self._RR, 2*self.genus) VC = VectorSpace(self._CC, self.genus) - I = self._CC(0,-1) + I = self._CC(0, 1) PM = self.period_matrix() if normalised: From 3ba04e72f297b22f4951a90f799a894a2a4adede Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 11 Jan 2022 13:41:34 +0100 Subject: [PATCH 024/742] Trac 32921: add optional keyword-only argument inhomogeneities --- src/sage/combinat/k_regular_sequence.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index b06b55b02fe..ac333ca8203 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -834,6 +834,10 @@ def from_recurrence(self, *args, **kwds): - ``offset`` -- an integer (default: ``0``). See explanation of ``equations`` above. + - ``inhomogeneities`` -- a dictionary mapping integers ``r`` to the + inhomogeneity `g_r` as given in [HKL2021]_, Corollary D. All + inhomogeneities have to be regular sequences from ``self``. + OUTPUT: a :class:`kRegularSequence` EXAMPLES: @@ -1749,7 +1753,7 @@ def parse_direct_arguments(self, M, m, coeffs, initial_values): return (M, m, coeffs, initial_values) - def parameters(self, M, m, coeffs, initial_values, offset=0): + def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}): r""" Determine parameters from recurrence relations as admissible in :meth:`kRegularSequenceSpace.from_recurrence`. @@ -1789,7 +1793,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0): (3, 0): 10, (3, 1): 11}, initial_values={0: 1, 1: 2, 2: 1, 3: 4, 4: 12, 5: 30, 6: 48, 7: 66, 8: 75, 9: 204, 10: 333, 11: 462, 12: 216, 13: 594, -6: 0, -5: 0, -4: 0, -3: 0, -2: 0, -1: 0}, - offset=1, n1=3) + offset=1, n1=3, inhomogeneities={}) .. SEEALSO:: @@ -1815,13 +1819,14 @@ def parameters(self, M, m, coeffs, initial_values, offset=0): sage: RP.parameters(1, 0, {(0, 0): 1}, ....: {0: 1, 1: 0}, 0) recurrence_rules(M=1, m=0, l=0, u=0, ll=0, uu=0, dim=1, - coeffs={(0, 0): 1}, initial_values={0: 1, 1: 0}, offset=0, n1=0) + coeffs={(0, 0): 1}, initial_values={0: 1, 1: 0}, offset=0, n1=0, + inhomogeneities={}) Finally, also for the zero-sequence the output is as expected:: sage: RP.parameters(1, 0, {}, {0: 0}, 0) recurrence_rules(M=1, m=0, l=0, u=0, ll=0, uu=0, dim=1, - coeffs={}, initial_values={0: 0}, offset=0, n1=0) + coeffs={}, initial_values={0: 0}, offset=0, n1=0, inhomogeneities={}) :: @@ -1829,7 +1834,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0): ....: {(0, 0): 0, (1, 1): 0}, {0: 0}, 0) recurrence_rules(M=1, m=0, l=0, u=0, ll=0, uu=0, dim=1, coeffs={(0, 0): 0, (1, 1): 0}, initial_values={0: 0}, - offset=0, n1=0) + offset=0, n1=0, inhomogeneities={}) """ from collections import namedtuple @@ -1875,11 +1880,12 @@ def parameters(self, M, m, coeffs, initial_values, offset=0): recurrence_rules = namedtuple('recurrence_rules', ['M', 'm', 'l', 'u', 'll', 'uu', 'dim', - 'coeffs', 'initial_values', 'offset', 'n1']) + 'coeffs', 'initial_values', 'offset', 'n1', + 'inhomogeneities']) return recurrence_rules(M=M, m=m, l=l, u=u, ll=ll, uu=uu, dim=dim, coeffs=coeffs, initial_values=initial_values, - offset=offset, n1=n1) + offset=offset, n1=n1, inhomogeneities=inhomogeneities) def values(self, *, M, m, l, u, ll, coeffs, initial_values, last_value_needed, offset): From 976ac29663f1d0583c4cb05675840718993c8f48 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 11 Jan 2022 15:06:33 +0100 Subject: [PATCH 025/742] Trac 32921: add inhomogeneities to values-method --- src/sage/combinat/k_regular_sequence.py | 41 ++++++++++++++++--------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index ac333ca8203..cd0d9ae912d 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1876,7 +1876,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) initial_values = self.values( M=M, m=m, l=l, u=u, ll=ll, coeffs=coeffs, initial_values=initial_values, last_value_needed=last_value_needed, - offset=offset) + offset=offset, inhomogeneities=inhomogeneities) recurrence_rules = namedtuple('recurrence_rules', ['M', 'm', 'l', 'u', 'll', 'uu', 'dim', @@ -1888,7 +1888,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) offset=offset, n1=n1, inhomogeneities=inhomogeneities) def values(self, *, M, m, l, u, ll, coeffs, - initial_values, last_value_needed, offset): + initial_values, last_value_needed, offset, inhomogeneities): r""" Determine enough values of the corresponding recursive sequence by applying the recurrence relations given in :meth:`kRegularSequenceSpace.from_recurrence` @@ -1913,6 +1913,10 @@ def values(self, *, M, m, l, u, ll, coeffs, - ``last_value_needed`` -- last initial value which is needed to determine the linear representation + - ``inhomogeneities`` -- a dictionary mapping integers ``r`` to the + inhomogeneity `g_r` as given in [HKL2021]_, Corollary D. All + inhomogeneities have to be regular sequences from ``self``. + OUTPUT: A dictionary mapping integers ``n`` to the ``n``-th value of the @@ -1927,7 +1931,7 @@ def values(self, *, M, m, l, u, ll, coeffs, sage: RP.values(M=1, m=0, l=0, u=1, ll=0, ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, ....: initial_values={0: 0, 1: 1, 2: 1}, last_value_needed=20, - ....: offset=0) + ....: offset=0, inhomogeneities={}) {0: 0, 1: 1, 2: 1, 3: 2, 4: 1, 5: 3, 6: 2, 7: 3, 8: 1, 9: 4, 10: 3, 11: 5, 12: 2, 13: 5, 14: 3, 15: 4, 16: 1, 17: 5, 18: 4, 19: 7, 20: 3} @@ -1942,7 +1946,7 @@ def values(self, *, M, m, l, u, ll, coeffs, sage: RP.values(M=1, m=0, l=0, u=1, ll=0, ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, ....: initial_values={0: 0, 1: 2}, last_value_needed=20, - ....: offset=0) + ....: offset=0, inhomogeneities={}) {0: 0, 1: 2, 2: 2, 3: 4, 4: 2, 5: 6, 6: 4, 7: 6, 8: 2, 9: 8, 10: 6, 11: 10, 12: 4, 13: 10, 14: 6, 15: 8, 16: 2, 17: 10, 18: 8, 19: 14, 20: 6} @@ -1951,7 +1955,8 @@ def values(self, *, M, m, l, u, ll, coeffs, sage: RP.values(M=1, m=0, l=0, u=1, ll=0, ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: initial_values={}, last_value_needed=20, offset=0) + ....: initial_values={}, last_value_needed=20, offset=0, + ....: inhomogeneities={}) Traceback (most recent call last): ... ValueError: Initial values for arguments in [0, 1] are missing. @@ -1960,7 +1965,8 @@ def values(self, *, M, m, l, u, ll, coeffs, sage: RP.values(M=1, m=0, l=0, u=1, ll=0, ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, - ....: initial_values={0: 0}, last_value_needed=20, offset=0) + ....: initial_values={0: 0}, last_value_needed=20, offset=0, + ....: inhomogeneities={}) Traceback (most recent call last): ... ValueError: Initial values for arguments in [1] are missing. @@ -1970,7 +1976,7 @@ def values(self, *, M, m, l, u, ll, coeffs, sage: RP.values(M=1, m=0, l=0, u=1, ll=0, ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, ....: initial_values={0: 0, 2: 1}, last_value_needed=20, - ....: offset=0) + ....: offset=0, inhomogeneities={}) Traceback (most recent call last): ... ValueError: Initial values for arguments in [1] are missing. @@ -1980,7 +1986,7 @@ def values(self, *, M, m, l, u, ll, coeffs, sage: RP.values(M=1, m=0, l=0, u=1, ll=0, ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, ....: initial_values={0: 0, 1: 2, 2:0}, last_value_needed=20, - ....: offset=0) + ....: offset=0, inhomogeneities={}) Traceback (most recent call last): ... ValueError: Initial value for argument 2 does not match with the given @@ -1991,7 +1997,7 @@ def values(self, *, M, m, l, u, ll, coeffs, sage: RP.values(M=1, m=0, l=-2, u=2, ll=-2, ....: coeffs={(0, -2): 1, (0, 2): 1, (1, -2): 1, (1, 2): 1}, ....: initial_values={0: 0, 1: 2, 2: 4, 3: 3, 4: 2}, - ....: last_value_needed=20, offset=2) + ....: last_value_needed=20, offset=2, inhomogeneities={}) {-2: 0, -1: 0, 0: 0, 1: 2, 2: 4, 3: 3, 4: 2, 5: 2, 6: 4, 7: 4, 8: 8, 9: 8, 10: 7, 11: 7, 12: 10, 13: 10, 14: 10, 15: 10, 16: 11, 17: 11, 18: 11, 19: 11, 20: 18} @@ -2000,14 +2006,14 @@ def values(self, *, M, m, l, u, ll, coeffs, sage: RP.values(M=1, m=0, l=0, u=0, ll=0, ....: coeffs={}, initial_values={}, last_value_needed=10, - ....: offset=0) + ....: offset=0, inhomogeneities={}) {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0} :: sage: RP.values(M=1, m=0, l=0, u=0, ll=0, ....: coeffs={(0, 0): 0, (1, 1): 0}, initial_values={}, - ....: last_value_needed=10, offset=0) + ....: last_value_needed=10, offset=0, inhomogeneities={}) {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0} """ from sage.arith.srange import srange @@ -2027,6 +2033,13 @@ def coeff(r, k): except KeyError: return 0 + @cached_function + def inhomogeneity(r, n): + try: + return inhomogeneities[r][n] + except KeyError: + return 0 + def f(n): f_n = values[n] if f_n is not None and f_n != "pending": @@ -2041,7 +2054,7 @@ def f(n): missing_values.append(n) return sum([coeff(r, j)*f(k**m*q + j) for j in srange(l, u + 1) - if coeff(r, j)]) + if coeff(r, j)]) + inhomogeneity(r, q) for n in srange(last_value_needed + 1): values.update({n: f(n)}) @@ -2053,8 +2066,8 @@ def f(n): for n in keys_initial: q, r = ZZ(n).quo_rem(k**M) if (q >= offset and - values[n] != sum([coeff(r, j)*values[k**m*q + j] - for j in srange(l, u + 1)])): + values[n] != (sum([coeff(r, j)*values[k**m*q + j] + for j in srange(l, u + 1)])) + inhomogeneity(r, q)): raise ValueError("Initial value for argument %s does not match with " "the given recurrence relations." % (n,)) from None From 6837137025804030468632ac713d9e4023169dd2 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 11 Jan 2022 15:55:41 +0100 Subject: [PATCH 026/742] Trac #32921: add inhomogeneities to left-method --- src/sage/combinat/k_regular_sequence.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index cd0d9ae912d..d5dbc4f19e2 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2407,8 +2407,9 @@ def left(self, recurrence_rules): sage: from collections import namedtuple sage: from sage.combinat.k_regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) - sage: RRD = namedtuple('recurrence_rules_dim', ['dim']) - sage: recurrence_rules = RRD(dim=5) + sage: RRD = namedtuple('recurrence_rules_dim', + ....: ['dim', 'inhomogeneities']) + sage: recurrence_rules = RRD(dim=5, inhomogeneities={}) sage: RP.left(recurrence_rules) (1, 0, 0, 0, 0) @@ -2416,8 +2417,20 @@ def left(self, recurrence_rules): :meth:`kRegularSequenceSpace.from_recurrence` """ + from sage.functions.other import floor from sage.modules.free_module_element import vector + dim = recurrence_rules.dim + inhomogeneities = recurrence_rules.inhomogeneities + + if not all(S.is_trivial_zero() for S in inhomogeneities.values()): + k = self.k + M = recurrence_rules.M + m = recurrence_rules.m + ll = recurrence_rules.ll + uu = recurrence_rules.uu + dim = dim + (floor((k**(M-1) - k**m + uu)/k**M) - floor(ll/k**M) + 1) * \ + sum(S.mu[0].ncols() for S in inhomogeneities.values()) return vector([1] + (dim - 1)*[0]) From 22c5f0bd80da7e4961e404b628348776a11e9d49 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 11 Jan 2022 16:12:43 +0100 Subject: [PATCH 027/742] Trac #32921: add inhomogeneities to right-method --- src/sage/combinat/k_regular_sequence.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index d5dbc4f19e2..5a81d7babe6 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2487,14 +2487,31 @@ def right(self, recurrence_rules): sage: RP.right(UB_rules) (1, 1, 2, 1, 2, 2, 4, 2, 4, 6, 0, 4, 4, 1, 0, 0) """ + from itertools import chain + from sage.arith.srange import srange + from sage.functions.other import floor from sage.modules.free_module_element import vector n1 = recurrence_rules.n1 + inhomogeneities = recurrence_rules.inhomogeneities right = self.v_eval_n(recurrence_rules, 0) if n1 >= 1: right = vector(list(right) + [1] + (n1 - 1)*[0]) + if not all(S.is_trivial_zero() for S in inhomogeneities.values()): + k = self.k + M = recurrence_rules.M + m = recurrence_rules.m + ll = recurrence_rules.ll + uu = recurrence_rules.uu + lower = floor(ll/k**M) + upper = floor((k**(M-1) - k**m + uu)/k**M) + shifted_inhomogeneities = [S.subsequence(1, b) + for S in inhomogeneities.values() + for b in srange(lower, upper + 1)] + right = vector(chain(right, *[S.right for S in shifted_inhomogeneities])) + return right def __call__(self, *args, **kwds): From 53c6b584251663e8c8edc2adeea043c94d1cdeb7 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 11 Jan 2022 21:08:50 +0100 Subject: [PATCH 028/742] Trac #32921: first draft for matrices --- src/sage/combinat/k_regular_sequence.py | 41 +++++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 5a81d7babe6..570da8e98d7 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2331,9 +2331,10 @@ def matrix(self, recurrence_rules, rem, correct_offset=True): :meth:`kRegularSequenceSpace.from_recurrence` """ from sage.arith.srange import srange + from sage.functions.other import floor from sage.matrix.constructor import Matrix from sage.matrix.matrix_space import MatrixSpace - from sage.matrix.special import block_matrix, zero_matrix + from sage.matrix.special import block_matrix, block_diagonal_matrix, zero_matrix from sage.modules.free_module_element import vector coefficient_ring = self.coefficient_ring @@ -2347,6 +2348,7 @@ def matrix(self, recurrence_rules, rem, correct_offset=True): n1 = recurrence_rules.n1 dim_without_corr = dim - n1 coeffs = recurrence_rules.coeffs + inhomogeneities = recurrence_rules.inhomogeneities ind = self.ind(M, m, ll, uu) @cached_function @@ -2372,9 +2374,7 @@ def entry(i, kk): mat = Matrix(coefficient_ring, dim_without_corr, dim_without_corr, entry) - if n1 == 0 or not correct_offset: - return mat - else: + if n1 > 0 and correct_offset: W = Matrix(coefficient_ring, dim_without_corr, 0) for i in srange(n1): W = W.augment( @@ -2386,8 +2386,36 @@ def entry(i, kk): J = J.stack(vector([int(j*k == i - rem) for j in srange(n1)])) Mat = MatrixSpace(coefficient_ring, dim, dim) - return Mat(block_matrix([[mat, W], - [zero_matrix(n1, dim_without_corr), J]])) + mat = Mat(block_matrix([[mat, W], + [zero_matrix(n1, dim_without_corr), J]])) + + if not all(S.is_trivial_zero() for S in inhomogeneities.values()): + lower = floor(ll/k**M) + upper = floor((k**(M-1) - k**m + uu)/k**M) + shifted_inhomogeneities = {} + current_row = 0 + for i in inhomogeneities.keys(): + for b in srange(lower, upper + 1): + S_b = inhomogeneities[i].subsequence(1, b) + shifted_inhomogeneities.update({(i, b): (S_b, current_row)}) + current_row += S_b.mu[0].ncols() + + mat = block_diagonal_matrix(mat, *[S[0].mu[rem] + for S in shifted_inhomogeneities.values()]) + + for i in srange(dim): + j, d = ind[i] + if j == M - 1: + rem_d = k**(M-1)*rem + (d%k**M) + dd = d // k**M + if rem_d < k**M and rem_d in inhomogeneities.keys(): + mat[ind[(j, d)], + dim + shifted_inhomogeneities[(rem_d, dd)][1]] = 1 + elif rem_d >= k**M and rem_d - k in inhomogeneities.keys(): + mat[ind[(j, d)], + dim + shifted_inhomogeneities[(rem_d - k, dd+1)][1]] = 1 + + return mat def left(self, recurrence_rules): r""" @@ -2488,6 +2516,7 @@ def right(self, recurrence_rules): (1, 1, 2, 1, 2, 2, 4, 2, 4, 6, 0, 4, 4, 1, 0, 0) """ from itertools import chain + from sage.arith.srange import srange from sage.functions.other import floor from sage.modules.free_module_element import vector From 9a3996450ddcbe542dd1d723b629fed5e64f462d Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 11 Jan 2022 21:09:29 +0100 Subject: [PATCH 029/742] Trac #32921: add examples/tests --- src/sage/combinat/k_regular_sequence.py | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 570da8e98d7..0fc919a5d06 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -879,6 +879,43 @@ def from_recurrence(self, *args, **kwds): ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3) 2-regular sequence 1, 2, 2, 4, 2, 4, 6, 0, 4, 4, ... + Binary sum of digits `S(n)`, characterized by the recurrence relations + `S(4n) = S(2n)`, `S(4n + 1) = S(2n + 1)`, `S(4n + 2) = S(2n + 1)` and + `S(4n + 3) = -S(2n) + 2S(2n + 1)`:: + + sage: S = Seq2.from_recurrence([ + ....: f(4*n) == f(2*n), + ....: f(4*n + 1) == f(2*n + 1), + ....: f(4*n + 2) == f(2*n + 1), + ....: f(4*n + 3) == -f(2*n) + 2*f(2*n + 1), + ....: f(0) == 0, f(1) == 1], f, n) + sage: S + 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... + + In order to check if this sequence is indeed the binary sum of digits, + we construct directly via its linear representation and compare it + with ``S``:: + + sage: S2 = Seq2( + ....: (Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), + ....: left=vector([0, 1]), right=vector([1, 0])) + sage: (S - S2).is_trivial_zero() + True + + Alternatively, we can also use the simpler but inhomogeneous recurrence relations + `S(2n) = S(n)` and `S(2n+1) = S(n) + 1` via direct parameters:: + + sage: one = Seq2((Matrix([[1]]), Matrix([[1]])), + ....: left=vector([1]), right=vector([1])) + sage: S = Seq2.from_recurrence(M=1, m=0, + ....: coeffs={(0, 0): 1, (1, 0): 1}, + ....: initial_values={0: 0, 1: 1}, + ....: inhomogeneities={1: one}) + sage: S + 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... + sage: (S - S2).is_trivial_zero() + True + Number of Non-Zero Elements in the Generalized Pascal's Triangle (see [LRS2017]_):: sage: Seq2 = kRegularSequenceSpace(2, QQ) From cee66a6c936867734af47fcd84bbb45d6a144974 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 11 Jan 2022 21:09:49 +0100 Subject: [PATCH 030/742] Trac #32921: add keywords to old test --- src/sage/combinat/k_regular_sequence.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 0fc919a5d06..69bd77ddd09 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -930,12 +930,12 @@ def from_recurrence(self, *args, **kwds): Finally, the same sequence can also be obtained via direct parameters without symbolic equations:: - sage: Seq2.from_recurrence(2, 1, - ....: {(0, 0): 5/3, (0, 1): -1/3, - ....: (1, 0): 4/3, (1, 1): 1/3, - ....: (2, 0): 1/3, (2, 1): 4/3, - ....: (3, 0): -1/3, (3, 1): 5/3}, - ....: {0: 1, 1: 2}) + sage: Seq2.from_recurrence(M=2, m=1, + ....: coeffs={(0, 0): 5/3, (0, 1): -1/3, + ....: (1, 0): 4/3, (1, 1): 1/3, + ....: (2, 0): 1/3, (2, 1): 4/3, + ....: (3, 0): -1/3, (3, 1): 5/3}, + ....: initial_values={0: 1, 1: 2}) 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... TESTS:: From b1f2b71238369da6398e5fe9ef115a7408ddd16d Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 11 Jan 2022 21:11:50 +0100 Subject: [PATCH 031/742] Trac #32921: use is_trivial_zero in old example --- src/sage/combinat/k_regular_sequence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 69bd77ddd09..c8ce7627fdc 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1007,7 +1007,7 @@ def from_recurrence(self, *args, **kwds): ....: g(22) == 22, g(23) == 23, g(24) == 24, g(25) == 25, ....: g(26) == 26, g(27) == 27, g(28) == 28, g(29) == 29, ....: g(30) == 30, g(31) == 31], g, m, offset=8) - sage: all([S[i] == T[i] for i in srange(1000)]) + sage: (S - T).is_trivial_zero() True Zero-sequence with non-zero initial values:: From 7e4ac4415aa093b0df9f969716e4e9d7b99e7028 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 11 Jan 2022 22:24:13 +0100 Subject: [PATCH 032/742] Trac #32921: add random example with imhomogeneities only --- src/sage/combinat/k_regular_sequence.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index c8ce7627fdc..d18a01422cd 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1025,6 +1025,18 @@ def from_recurrence(self, *args, **kwds): ....: f(2*n) == 0, f(2*n + 1) == 0, ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3], f, n, offset=2) 2-regular sequence 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, ... + + :: + + sage: S = Seq2((random_matrix(ZZ, 3, 3), random_matrix(ZZ, 3, 3)), + ....: left=vector([randint(-2, 2) for i in srange(3)]), + ....: right=vector([randint(-2, 2) for i in srange(3)])) + sage: T = Seq2.from_recurrence(M=3, m=2, + ....: coeffs={}, + ....: initial_values={0: S[0]}, + ....: inhomogeneities={i: S.subsequence(2**3, i) for i in srange(2**3)}) + sage: all(S[i] == T[i] for i in srange(100)) + True """ RP = RecurrenceParser(self.k, self.coefficient_ring()) mu, left, right = RP(*args, **kwds) From 59479e5a75184ada8c463c728e8416e633a34304 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 12 Jan 2022 14:50:56 +0100 Subject: [PATCH 033/742] Trac #32921: add some tests --- src/sage/combinat/k_regular_sequence.py | 26 +++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index d18a01422cd..71e2b2229be 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -849,9 +849,10 @@ def from_recurrence(self, *args, **kwds): n sage: function('f') f - sage: Seq2.from_recurrence([ + sage: SB = Seq2.from_recurrence([ ....: f(2*n) == f(n), f(2*n + 1) == f(n) + f(n + 1), ....: f(0) == 0, f(1) == 1], f, n) + sage: SB 2-regular sequence 0, 1, 1, 2, 1, 3, 2, 3, 1, 4, ... Number of Odd Entries in Pascal's Triangle:: @@ -919,12 +920,13 @@ def from_recurrence(self, *args, **kwds): Number of Non-Zero Elements in the Generalized Pascal's Triangle (see [LRS2017]_):: sage: Seq2 = kRegularSequenceSpace(2, QQ) - sage: Seq2.from_recurrence([ + sage: P = Seq2.from_recurrence([ ....: f(4*n) == 5/3*f(2*n) - 1/3*f(2*n + 1), ....: f(4*n + 1) == 4/3*f(2*n) + 1/3*f(2*n + 1), ....: f(4*n + 2) == 1/3*f(2*n) + 4/3*f(2*n + 1), ....: f(4*n + 3) == -1/3*f(2*n) + 5/3*f(2*n + 1), ....: f(0) == 1, f(1) == 2], f, n) + sage: P 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... Finally, the same sequence can also be obtained via direct parameters @@ -1037,6 +1039,26 @@ def from_recurrence(self, *args, **kwds): ....: inhomogeneities={i: S.subsequence(2**3, i) for i in srange(2**3)}) sage: all(S[i] == T[i] for i in srange(100)) True + + Connection between the Stern--Brocot sequence and the number + of non-zero elements in the generalized Pascal's triangle (see + [LRS2017]_):: + + sage: U = Seq2.from_recurrence(M=1, m=0, + ....: coeffs={(0, 0): 1}, + ....: initial_values={0: 0, 1: 1}, + ....: inhomogeneities={1: P}) + sage: (U - Seq2(SB)).is_trivial_zero() + True + + :: + + sage: U = Seq2.from_recurrence(M=1, m=0, + ....: coeffs={}, + ....: initial_values={0: 0, 1: 1}, + ....: inhomogeneities={0: SB, 1: P}) + sage: (U - Seq2(SB)).is_trivial_zero() + True """ RP = RecurrenceParser(self.k, self.coefficient_ring()) mu, left, right = RP(*args, **kwds) From 6bc9c110a540f54bfc791fcca8cd95cc1b4bd77b Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 12 Jan 2022 15:15:24 +0100 Subject: [PATCH 034/742] Trac #32921: minor modifications in tests --- src/sage/combinat/k_regular_sequence.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 71e2b2229be..034fa00c77b 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -894,7 +894,7 @@ def from_recurrence(self, *args, **kwds): 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... In order to check if this sequence is indeed the binary sum of digits, - we construct directly via its linear representation and compare it + we construct it directly via its linear representation and compare it with ``S``:: sage: S2 = Seq2( @@ -1030,6 +1030,7 @@ def from_recurrence(self, *args, **kwds): :: + sage: set_random_seed() sage: S = Seq2((random_matrix(ZZ, 3, 3), random_matrix(ZZ, 3, 3)), ....: left=vector([randint(-2, 2) for i in srange(3)]), ....: right=vector([randint(-2, 2) for i in srange(3)])) From 60f76025f9b90da18da7c59a1f72f4b998c0be39 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 12 Jan 2022 15:16:20 +0100 Subject: [PATCH 035/742] Trac #32921: fix issue for left vector --- src/sage/combinat/k_regular_sequence.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 034fa00c77b..2b7bdf7cf3e 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2517,6 +2517,7 @@ def left(self, recurrence_rules): :meth:`kRegularSequenceSpace.from_recurrence` """ + from sage.arith.srange import srange from sage.functions.other import floor from sage.modules.free_module_element import vector @@ -2529,8 +2530,11 @@ def left(self, recurrence_rules): m = recurrence_rules.m ll = recurrence_rules.ll uu = recurrence_rules.uu - dim = dim + (floor((k**(M-1) - k**m + uu)/k**M) - floor(ll/k**M) + 1) * \ - sum(S.mu[0].ncols() for S in inhomogeneities.values()) + lower = floor(ll/k**M) + upper = floor((k**(M-1) - k**m + uu)/k**M) + dim = dim + sum(inhomogeneities[i].subsequence(1, b, minimize=False).mu[0].ncols() + for i in inhomogeneities.keys() + for b in srange(lower, upper + 1)) return vector([1] + (dim - 1)*[0]) From 49363c791a40883dc4fb3ab8d3aa50d21dbf61bd Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 12 Jan 2022 15:17:22 +0100 Subject: [PATCH 036/742] Trac #32921: deactivate minimization for now --- src/sage/combinat/k_regular_sequence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 2b7bdf7cf3e..595b2f15c25 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2468,7 +2468,7 @@ def entry(i, kk): current_row = 0 for i in inhomogeneities.keys(): for b in srange(lower, upper + 1): - S_b = inhomogeneities[i].subsequence(1, b) + S_b = inhomogeneities[i].subsequence(1, b, minimize=False) shifted_inhomogeneities.update({(i, b): (S_b, current_row)}) current_row += S_b.mu[0].ncols() @@ -2612,7 +2612,7 @@ def right(self, recurrence_rules): uu = recurrence_rules.uu lower = floor(ll/k**M) upper = floor((k**(M-1) - k**m + uu)/k**M) - shifted_inhomogeneities = [S.subsequence(1, b) + shifted_inhomogeneities = [S.subsequence(1, b, minimize=False) for S in inhomogeneities.values() for b in srange(lower, upper + 1)] right = vector(chain(right, *[S.right for S in shifted_inhomogeneities])) From a65412ee40bcea65ad212ee3d15eda0dea0bb511 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 12 Jan 2022 16:07:54 +0100 Subject: [PATCH 037/742] Trac #32921: shift parts from right to v_eval_n --- src/sage/combinat/k_regular_sequence.py | 32 ++++++++++--------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 595b2f15c25..455a01f4270 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2246,10 +2246,20 @@ def v_eval_n(self, recurrence_rules, n): uu = recurrence_rules.uu dim = recurrence_rules.dim - recurrence_rules.n1 initial_values = recurrence_rules.initial_values + inhomogeneities = recurrence_rules.inhomogeneities ind = self.ind(M, m, ll, uu) - return vector( - [initial_values[k**ind[i][0]*n + ind[i][1]] for i in srange(dim)]) + v = vector([initial_values[k**ind[i][0]*n + ind[i][1]] for i in srange(dim)]) + + if not all(S.is_trivial_zero() for S in inhomogeneities.values()): + lower = floor(ll/k**M) + upper = floor((k**(M-1) - k**m + uu)/k**M) + shifted_inhomogeneities = [S.subsequence(1, b, minimize=False) + for S in inhomogeneities.values() + for b in srange(lower, upper + 1)] + v = vector(chain(v, *[S.right for S in shifted_inhomogeneities])) + + return v def matrix(self, recurrence_rules, rem, correct_offset=True): r""" @@ -2591,32 +2601,14 @@ def right(self, recurrence_rules): sage: RP.right(UB_rules) (1, 1, 2, 1, 2, 2, 4, 2, 4, 6, 0, 4, 4, 1, 0, 0) """ - from itertools import chain - - from sage.arith.srange import srange - from sage.functions.other import floor from sage.modules.free_module_element import vector n1 = recurrence_rules.n1 - inhomogeneities = recurrence_rules.inhomogeneities right = self.v_eval_n(recurrence_rules, 0) if n1 >= 1: right = vector(list(right) + [1] + (n1 - 1)*[0]) - if not all(S.is_trivial_zero() for S in inhomogeneities.values()): - k = self.k - M = recurrence_rules.M - m = recurrence_rules.m - ll = recurrence_rules.ll - uu = recurrence_rules.uu - lower = floor(ll/k**M) - upper = floor((k**(M-1) - k**m + uu)/k**M) - shifted_inhomogeneities = [S.subsequence(1, b, minimize=False) - for S in inhomogeneities.values() - for b in srange(lower, upper + 1)] - right = vector(chain(right, *[S.right for S in shifted_inhomogeneities])) - return right def __call__(self, *args, **kwds): From e10abb3160fdc6a1fc11850cd8afcdb106a8de89 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 12 Jan 2022 16:08:41 +0100 Subject: [PATCH 038/742] Trac #32921: fix offset correction --- src/sage/combinat/k_regular_sequence.py | 42 ++++++++++++++----------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 455a01f4270..58df4bfe328 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2236,7 +2236,10 @@ def v_eval_n(self, recurrence_rules, n): :meth:`kRegularSequenceSpace.from_recurrence` """ + from itertools import chain + from sage.arith.srange import srange + from sage.functions.other import floor from sage.modules.free_module_element import vector k = self.k @@ -2456,21 +2459,6 @@ def entry(i, kk): mat = Matrix(coefficient_ring, dim_without_corr, dim_without_corr, entry) - if n1 > 0 and correct_offset: - W = Matrix(coefficient_ring, dim_without_corr, 0) - for i in srange(n1): - W = W.augment( - self.v_eval_n(recurrence_rules, k*i + rem) - - mat*self.v_eval_n(recurrence_rules, i)) - - J = Matrix(coefficient_ring, 0, n1) - for i in srange(n1): - J = J.stack(vector([int(j*k == i - rem) for j in srange(n1)])) - - Mat = MatrixSpace(coefficient_ring, dim, dim) - mat = Mat(block_matrix([[mat, W], - [zero_matrix(n1, dim_without_corr), J]])) - if not all(S.is_trivial_zero() for S in inhomogeneities.values()): lower = floor(ll/k**M) upper = floor((k**(M-1) - k**m + uu)/k**M) @@ -2485,17 +2473,35 @@ def entry(i, kk): mat = block_diagonal_matrix(mat, *[S[0].mu[rem] for S in shifted_inhomogeneities.values()]) - for i in srange(dim): + for i in srange(dim_without_corr): j, d = ind[i] if j == M - 1: rem_d = k**(M-1)*rem + (d%k**M) dd = d // k**M if rem_d < k**M and rem_d in inhomogeneities.keys(): mat[ind[(j, d)], - dim + shifted_inhomogeneities[(rem_d, dd)][1]] = 1 + dim_without_corr + shifted_inhomogeneities[(rem_d, dd)][1]] = 1 elif rem_d >= k**M and rem_d - k in inhomogeneities.keys(): mat[ind[(j, d)], - dim + shifted_inhomogeneities[(rem_d - k, dd+1)][1]] = 1 + dim_without_corr + shifted_inhomogeneities[(rem_d - k, dd+1)][1]] = 1 + + dim += current_row + dim_without_corr += current_row + + if n1 > 0 and correct_offset: + W = Matrix(coefficient_ring, dim_without_corr, 0) + for i in srange(n1): + W = W.augment( + self.v_eval_n(recurrence_rules, k*i + rem) - + mat*self.v_eval_n(recurrence_rules, i)) + + J = Matrix(coefficient_ring, 0, n1) + for i in srange(n1): + J = J.stack(vector([int(j*k == i - rem) for j in srange(n1)])) + + Mat = MatrixSpace(coefficient_ring, dim, dim) + mat = Mat(block_matrix([[mat, W], + [zero_matrix(n1, dim_without_corr), J]])) return mat From 268fe7c625a54c94566bb5fcf6c98daf0a06bff3 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 12 Jan 2022 16:09:06 +0100 Subject: [PATCH 039/742] Trac #32921: add further example --- src/sage/combinat/k_regular_sequence.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 58df4bfe328..421ee90154a 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -864,7 +864,7 @@ def from_recurrence(self, *args, **kwds): Number of Unbordered Factors in the Thue--Morse Sequence:: - sage: Seq2.from_recurrence([ + sage: UB = Seq2.from_recurrence([ ....: f(8*n) == 2*f(4*n), ....: f(8*n + 1) == f(4*n + 1), ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3), @@ -878,6 +878,7 @@ def from_recurrence(self, *args, **kwds): ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3) + sage: UB 2-regular sequence 1, 2, 2, 4, 2, 4, 6, 0, 4, 4, ... Binary sum of digits `S(n)`, characterized by the recurrence relations @@ -1060,6 +1061,28 @@ def from_recurrence(self, *args, **kwds): ....: inhomogeneities={0: SB, 1: P}) sage: (U - Seq2(SB)).is_trivial_zero() True + + Number of Unbordered Factors in the Thue--Morse Sequence, but partly + encoded with inhomogeneities:: + + sage: UB2 = Seq2.from_recurrence([ + ....: f(8*n) == 2*f(4*n), + ....: f(8*n + 1) == f(4*n + 1), + ....: f(8*n + 2) == f(4*n + 1), + ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2), + ....: f(8*n + 4) == 2*f(4*n + 2), + ....: f(8*n + 5) == f(4*n + 3), + ....: f(8*n + 6) == -f(4*n + 1), + ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3), + ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2, + ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4, + ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, + ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, + ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3, + ....: inhomogeneities={2: UB.subsequence(4, 3), 3: -UB.subsequence(4, 1), + ....: 6: UB.subsequence(4, 2) + UB.subsequence(4, 3)}) + sage: (UB2 - Seq2(UB)).is_trivial_zero() + True """ RP = RecurrenceParser(self.k, self.coefficient_ring()) mu, left, right = RP(*args, **kwds) From 54bc5db1008b6b186d5ffbeefc4a82b83aeef988 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 12 Jan 2022 16:21:58 +0100 Subject: [PATCH 040/742] Trac #32921: simplify construction of matrix --- src/sage/combinat/k_regular_sequence.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 421ee90154a..4785558241c 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2496,17 +2496,16 @@ def entry(i, kk): mat = block_diagonal_matrix(mat, *[S[0].mu[rem] for S in shifted_inhomogeneities.values()]) - for i in srange(dim_without_corr): - j, d = ind[i] - if j == M - 1: - rem_d = k**(M-1)*rem + (d%k**M) - dd = d // k**M - if rem_d < k**M and rem_d in inhomogeneities.keys(): - mat[ind[(j, d)], - dim_without_corr + shifted_inhomogeneities[(rem_d, dd)][1]] = 1 - elif rem_d >= k**M and rem_d - k in inhomogeneities.keys(): - mat[ind[(j, d)], - dim_without_corr + shifted_inhomogeneities[(rem_d - k, dd+1)][1]] = 1 + for i in srange(dim_without_corr - k**(M-1) + k**m - uu + ll - 1, dim_without_corr): + j, d = ind[i] # j = M - 1 + rem_d = k**(M-1)*rem + (d%k**M) + dd = d // k**M + if rem_d < k**M and rem_d in inhomogeneities.keys(): + mat[ind[(j, d)], + dim_without_corr + shifted_inhomogeneities[(rem_d, dd)][1]] = 1 + elif rem_d >= k**M and rem_d - k in inhomogeneities.keys(): + mat[ind[(j, d)], + dim_without_corr + shifted_inhomogeneities[(rem_d - k, dd+1)][1]] = 1 dim += current_row dim_without_corr += current_row From 25d53987b491f848d23038ff2b885cf768f86d6e Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 12 Jan 2022 16:22:37 +0100 Subject: [PATCH 041/742] Trac #32921: add inhomogeneities to docstring --- src/sage/combinat/k_regular_sequence.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 4785558241c..1994a7a3ad9 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1874,6 +1874,11 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) - ``initial_values`` -- a dictionary mapping integers ``n`` to the ``n``-th value of the sequence + - ``inhomogeneities`` -- (default: ``{}``) a dictionary + mapping integers ``r`` to the inhomogeneity `g_r` as given + in [HKL2021]_, Corollary D. All inhomogeneities have to be + regular sequences from ``self``. + EXAMPLES:: sage: from sage.combinat.k_regular_sequence import RecurrenceParser From 997c5ccc4ad2901716a241cadd14e0130954d149 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 18 Jan 2022 12:20:50 +0100 Subject: [PATCH 042/742] Trac #32921, review item 2: mention default value --- src/sage/combinat/k_regular_sequence.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index eebecf7bff3..febb65ca8d0 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -831,12 +831,13 @@ def from_recurrence(self, *args, **kwds): Optional keyword-only argument: - - ``offset`` -- an integer (default: ``0``). See explanation of + - ``offset`` -- (default: ``0``) an integer. See explanation of ``equations`` above. - - ``inhomogeneities`` -- a dictionary mapping integers ``r`` to the - inhomogeneity `g_r` as given in [HKL2021]_, Corollary D. All - inhomogeneities have to be regular sequences from ``self``. + - ``inhomogeneities`` -- (default: ``{}``) a dictionary + mapping integers ``r`` to the inhomogeneity `g_r` as given + in [HKL2021]_, Corollary D. All inhomogeneities have to be + regular sequences from ``self``. OUTPUT: a :class:`kRegularSequence` From dd4f2f6b19e051ac1a781d4efa76814fec3805b5 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 18 Jan 2022 12:24:37 +0100 Subject: [PATCH 043/742] Trac #32921, review item 3: adapt descrition of output --- src/sage/combinat/k_regular_sequence.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index febb65ca8d0..6ef9c4b1856 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1910,10 +1910,8 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) - ``initial_values`` -- a dictionary mapping integers ``n`` to the ``n``-th value of the sequence - - ``inhomogeneities`` -- (default: ``{}``) a dictionary - mapping integers ``r`` to the inhomogeneity `g_r` as given - in [HKL2021]_, Corollary D. All inhomogeneities have to be - regular sequences from ``self``. + - ``inhomogeneities`` -- a dictionary mapping integers ``r`` + to the inhomogeneity `g_r` as given in [HKL2021]_, Corollary D. EXAMPLES:: From 87a3cfb225259a0ab25b3e297d3e505f32c2d66b Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 18 Jan 2022 12:27:01 +0100 Subject: [PATCH 044/742] Trac #32921, review item 4: adapt description of input --- src/sage/combinat/k_regular_sequence.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 6ef9c4b1856..7ba462d678e 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2053,9 +2053,8 @@ def values(self, *, M, m, l, u, ll, coeffs, - ``last_value_needed`` -- last initial value which is needed to determine the linear representation - - ``inhomogeneities`` -- a dictionary mapping integers ``r`` to the - inhomogeneity `g_r` as given in [HKL2021]_, Corollary D. All - inhomogeneities have to be regular sequences from ``self``. + - ``inhomogeneities`` -- a dictionary mapping integers ``r`` + to the inhomogeneity `g_r` as given in [HKL2021]_, Corollary D. OUTPUT: From f4356b2b0cce709290d6a8ee999ed55df9315f7c Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 18 Jan 2022 12:34:24 +0100 Subject: [PATCH 045/742] Trac #32921, review item 9: fix index --- src/sage/combinat/k_regular_sequence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 7ba462d678e..611ecd5fc99 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2547,9 +2547,9 @@ def entry(i, kk): if rem_d < k**M and rem_d in inhomogeneities.keys(): mat[ind[(j, d)], dim_without_corr + shifted_inhomogeneities[(rem_d, dd)][1]] = 1 - elif rem_d >= k**M and rem_d - k in inhomogeneities.keys(): + elif rem_d >= k**M and rem_d - k**M in inhomogeneities.keys(): mat[ind[(j, d)], - dim_without_corr + shifted_inhomogeneities[(rem_d - k, dd+1)][1]] = 1 + dim_without_corr + shifted_inhomogeneities[(rem_d - k**M, dd+1)][1]] = 1 dim += current_row dim_without_corr += current_row From 03cc1b4caad89f039af2baa15617408239f36c5e Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 18 Jan 2022 12:40:01 +0100 Subject: [PATCH 046/742] Trac #32921, review item 14: use one_hadamard --- src/sage/combinat/k_regular_sequence.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 611ecd5fc99..93ff8711f08 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -908,8 +908,7 @@ def from_recurrence(self, *args, **kwds): Alternatively, we can also use the simpler but inhomogeneous recurrence relations `S(2n) = S(n)` and `S(2n+1) = S(n) + 1` via direct parameters:: - sage: one = Seq2((Matrix([[1]]), Matrix([[1]])), - ....: left=vector([1]), right=vector([1])) + sage: one = Seq2.one_hadamard() sage: S = Seq2.from_recurrence(M=1, m=0, ....: coeffs={(0, 0): 1, (1, 0): 1}, ....: initial_values={0: 0, 1: 1}, From 97fbbddce43f807744c524057d74d47009d5c459 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 18 Jan 2022 16:55:40 +0100 Subject: [PATCH 047/742] Trac #32921, review item 5: fix missing n --- src/sage/combinat/k_regular_sequence.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 93ff8711f08..c84aedb6507 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2307,6 +2307,7 @@ def v_eval_n(self, recurrence_rules, n): from sage.arith.srange import srange from sage.functions.other import floor from sage.modules.free_module_element import vector + from sage.rings.integer_ring import ZZ k = self.k M = recurrence_rules.M @@ -2321,12 +2322,11 @@ def v_eval_n(self, recurrence_rules, n): v = vector([initial_values[k**ind[i][0]*n + ind[i][1]] for i in srange(dim)]) if not all(S.is_trivial_zero() for S in inhomogeneities.values()): - lower = floor(ll/k**M) - upper = floor((k**(M-1) - k**m + uu)/k**M) - shifted_inhomogeneities = [S.subsequence(1, b, minimize=False) - for S in inhomogeneities.values() - for b in srange(lower, upper + 1)] - v = vector(chain(v, *[S.right for S in shifted_inhomogeneities])) + Seq = list(inhomogeneities.values())[0].parent() + W = Seq.indices() + shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) + vv = [(S._mu_of_word_(W(ZZ(n).digits(k))) * S.right) for S in shifted_inhomogeneities] + v = vector(chain(v, *vv)) return v From f4807380ee9414931cc9c006f3df48c01b1fe3f1 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 18 Jan 2022 17:26:32 +0100 Subject: [PATCH 048/742] Trac #32921, review item 12: write new method --- src/sage/combinat/k_regular_sequence.py | 74 +++++++++++++++++++++---- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index c84aedb6507..1df6975a627 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2273,6 +2273,66 @@ def ind(self, M, m, ll, uu): return ind + def shifted_inhomogeneities(self, recurrence_rules): + r""" + Return a list of all needed shifted inhomogeineities as described + in the proof of Coroallary D in [HKL2021]_. + + INPUT: + + - ``recurrence_rules`` -- a namedtuple generated by + :meth:`parameters` + + OUTPUT: a list + + EXAMPLES:: + + sage: from collections import namedtuple + sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: RP = RecurrenceParser(2, ZZ) + sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), + ....: left=vector([0, 1]), right=vector([1, 0])) + sage: S + 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... + sage: RR = namedtuple('recurrence_rules', + ....: ['M', 'm', 'll', 'uu', 'inhomogeneities']) + sage: recurrence_rules = RR(M=3, m=0, ll=-8, uu=14, + ....: inhomogeneities={0: S}) + sage: RP.shifted_inhomogeneities(recurrence_rules) + [2-regular sequence 0, 0, 1, 1, 2, 1, 2, 2, 3, 1, ..., + 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ..., + 2-regular sequence 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, ..., + 2-regular sequence 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, ...] + + .. SEEALSO:: + + :meth:`kRegularSequenceSpace.from_recurrence` + """ + from sage.arith.srange import srange + from sage.functions.other import floor + + k = self.k + M = recurrence_rules.M + m = recurrence_rules.m + ll = recurrence_rules.ll + uu = recurrence_rules.uu + inhomogeneities = recurrence_rules.inhomogeneities + + lower = floor(ll/k**M) + upper = floor((k**(M-1) - k**m + uu)/k**M) + + shifted_inhomogeneities = [S.subsequence(1, b) + for S in inhomogeneities.values() + for b in srange(lower, upper + 1)] + + CR = self.coefficient_ring + assert(all([S.left[0] == CR(1) for S in shifted_inhomogeneities]) and + all([all(a == CR(0) for a in S.left[1:]) + for S in shifted_inhomogeneities])) + + return shifted_inhomogeneities + def v_eval_n(self, recurrence_rules, n): r""" Return the vector `v(n)` as given in [HKL2021]_, Theorem A. @@ -2532,7 +2592,7 @@ def entry(i, kk): current_row = 0 for i in inhomogeneities.keys(): for b in srange(lower, upper + 1): - S_b = inhomogeneities[i].subsequence(1, b, minimize=False) + S_b = inhomogeneities[i].subsequence(1, b) shifted_inhomogeneities.update({(i, b): (S_b, current_row)}) current_row += S_b.mu[0].ncols() @@ -2606,16 +2666,8 @@ def left(self, recurrence_rules): inhomogeneities = recurrence_rules.inhomogeneities if not all(S.is_trivial_zero() for S in inhomogeneities.values()): - k = self.k - M = recurrence_rules.M - m = recurrence_rules.m - ll = recurrence_rules.ll - uu = recurrence_rules.uu - lower = floor(ll/k**M) - upper = floor((k**(M-1) - k**m + uu)/k**M) - dim = dim + sum(inhomogeneities[i].subsequence(1, b, minimize=False).mu[0].ncols() - for i in inhomogeneities.keys() - for b in srange(lower, upper + 1)) + shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) + dim = dim + sum(S.mu[0].ncols() for S in shifted_inhomogeneities) return vector([1] + (dim - 1)*[0]) From 48ebcc4ea03461fec7be47ba7c0a2c39ca380338 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 18 Jan 2022 17:30:15 +0100 Subject: [PATCH 049/742] Trac #32921, review item 12: modify method for matrix-construction (could be reverted) --- src/sage/combinat/k_regular_sequence.py | 47 +++++++++++++------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 1df6975a627..bb4b8a250c0 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2300,10 +2300,10 @@ def shifted_inhomogeneities(self, recurrence_rules): sage: recurrence_rules = RR(M=3, m=0, ll=-8, uu=14, ....: inhomogeneities={0: S}) sage: RP.shifted_inhomogeneities(recurrence_rules) - [2-regular sequence 0, 0, 1, 1, 2, 1, 2, 2, 3, 1, ..., - 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ..., - 2-regular sequence 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, ..., - 2-regular sequence 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, ...] + {(0, -1): (2-regular sequence 0, 0, 1, 1, 2, 1, 2, 2, 3, 1, ..., 0), + (0, 0): (2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ..., 4), + (0, 1): (2-regular sequence 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, ..., 6), + (0, 2): (2-regular sequence 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, ..., 9)} .. SEEALSO:: @@ -2322,14 +2322,18 @@ def shifted_inhomogeneities(self, recurrence_rules): lower = floor(ll/k**M) upper = floor((k**(M-1) - k**m + uu)/k**M) - shifted_inhomogeneities = [S.subsequence(1, b) - for S in inhomogeneities.values() - for b in srange(lower, upper + 1)] + shifted_inhomogeneities = {} + current_row = 0 + for i in inhomogeneities.keys(): + for b in srange(lower, upper + 1): + S_b = inhomogeneities[i].subsequence(1, b) + shifted_inhomogeneities.update({(i, b): (S_b, current_row)}) + current_row += S_b.mu[0].ncols() CR = self.coefficient_ring - assert(all([S.left[0] == CR(1) for S in shifted_inhomogeneities]) and - all([all(a == CR(0) for a in S.left[1:]) - for S in shifted_inhomogeneities])) + assert(all([S[0].left[0] == CR(1) for S in shifted_inhomogeneities.values()]) and + all([all(a == CR(0) for a in S[0].left[1:]) + for S in shifted_inhomogeneities.values()])) return shifted_inhomogeneities @@ -2384,7 +2388,7 @@ def v_eval_n(self, recurrence_rules, n): if not all(S.is_trivial_zero() for S in inhomogeneities.values()): Seq = list(inhomogeneities.values())[0].parent() W = Seq.indices() - shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) + shifted_inhomogeneities = [S[0] for S in self.shifted_inhomogeneities(recurrence_rules).values()] vv = [(S._mu_of_word_(W(ZZ(n).digits(k))) * S.right) for S in shifted_inhomogeneities] v = vector(chain(v, *vv)) @@ -2586,15 +2590,7 @@ def entry(i, kk): mat = Matrix(coefficient_ring, dim_without_corr, dim_without_corr, entry) if not all(S.is_trivial_zero() for S in inhomogeneities.values()): - lower = floor(ll/k**M) - upper = floor((k**(M-1) - k**m + uu)/k**M) - shifted_inhomogeneities = {} - current_row = 0 - for i in inhomogeneities.keys(): - for b in srange(lower, upper + 1): - S_b = inhomogeneities[i].subsequence(1, b) - shifted_inhomogeneities.update({(i, b): (S_b, current_row)}) - current_row += S_b.mu[0].ncols() + shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) mat = block_diagonal_matrix(mat, *[S[0].mu[rem] for S in shifted_inhomogeneities.values()]) @@ -2610,8 +2606,10 @@ def entry(i, kk): mat[ind[(j, d)], dim_without_corr + shifted_inhomogeneities[(rem_d - k**M, dd+1)][1]] = 1 - dim += current_row - dim_without_corr += current_row + dim_of_inhom = shifted_inhomogeneities[list(shifted_inhomogeneities)[-1]][1] + \ + shifted_inhomogeneities[list(shifted_inhomogeneities)[-1]][0].mu[0].ncols() + dim += dim_of_inhom + dim_without_corr += dim_of_inhom if n1 > 0 and correct_offset: W = Matrix(coefficient_ring, dim_without_corr, 0) @@ -2667,7 +2665,10 @@ def left(self, recurrence_rules): if not all(S.is_trivial_zero() for S in inhomogeneities.values()): shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) - dim = dim + sum(S.mu[0].ncols() for S in shifted_inhomogeneities) + dim += shifted_inhomogeneities[list(shifted_inhomogeneities)[-1]][1] + \ + shifted_inhomogeneities[ + list(shifted_inhomogeneities)[-1] + ][0].mu[0].ncols() return vector([1] + (dim - 1)*[0]) From b6740008ea69b15e7f7172fda758a9e3f10db8f8 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 19 Jan 2022 10:13:28 +0100 Subject: [PATCH 050/742] Trac #32921, review item 10: add minimize=True --- src/sage/combinat/k_regular_sequence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index bb4b8a250c0..bef2dc82e15 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2326,7 +2326,7 @@ def shifted_inhomogeneities(self, recurrence_rules): current_row = 0 for i in inhomogeneities.keys(): for b in srange(lower, upper + 1): - S_b = inhomogeneities[i].subsequence(1, b) + S_b = inhomogeneities[i].subsequence(1, b, minimize=True) shifted_inhomogeneities.update({(i, b): (S_b, current_row)}) current_row += S_b.mu[0].ncols() From df04b444b3eaf5de44317d9ea7b3594afa81b784 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 19 Jan 2022 11:00:25 +0100 Subject: [PATCH 051/742] Trac #32921: use assert really as statement... --- src/sage/combinat/k_regular_sequence.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index bef2dc82e15..78617de9b64 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2331,9 +2331,9 @@ def shifted_inhomogeneities(self, recurrence_rules): current_row += S_b.mu[0].ncols() CR = self.coefficient_ring - assert(all([S[0].left[0] == CR(1) for S in shifted_inhomogeneities.values()]) and - all([all(a == CR(0) for a in S[0].left[1:]) - for S in shifted_inhomogeneities.values()])) + assert (all([S[0].left[0] == CR(1) for S in shifted_inhomogeneities.values()]) and + all([all(a == CR(0) for a in S[0].left[1:]) + for S in shifted_inhomogeneities.values()])) return shifted_inhomogeneities From 8d1721dcb7fb3151aaed203df1c12c29bec1e3c2 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 19 Jan 2022 13:13:04 +0100 Subject: [PATCH 052/742] Trac #32921, review item 10: simplify assert --- src/sage/combinat/k_regular_sequence.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 78617de9b64..071f63bb99a 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2331,9 +2331,8 @@ def shifted_inhomogeneities(self, recurrence_rules): current_row += S_b.mu[0].ncols() CR = self.coefficient_ring - assert (all([S[0].left[0] == CR(1) for S in shifted_inhomogeneities.values()]) and - all([all(a == CR(0) for a in S[0].left[1:]) - for S in shifted_inhomogeneities.values()])) + assert all([S[0].left[0] == CR(1) and S[0].left[1:] == vector(len(S[0].left[1:])*[CR(0)]) + for S in shifted_inhomogeneities.values()]) return shifted_inhomogeneities From 1f73dfe2651b411f0ba1bb083e9a5e8a42d08ba2 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 19 Jan 2022 13:41:31 +0100 Subject: [PATCH 053/742] Trac #32921, review item 10: mention standard unit vector in documentation --- src/sage/combinat/k_regular_sequence.py | 1 + src/sage/combinat/recognizable_series.py | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 071f63bb99a..7a284946778 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2311,6 +2311,7 @@ def shifted_inhomogeneities(self, recurrence_rules): """ from sage.arith.srange import srange from sage.functions.other import floor + from sage.modules.free_module_element import vector k = self.k M = recurrence_rules.M diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index 8c65e0356ff..f0be8b5af61 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -931,6 +931,12 @@ def minimized(self): This method implements the minimization algorithm presented in Chapter 2 of [BR2010a]_. + .. NOTE:: + + Due to the algorithm, the vector :meth:`RecognizableSeries.left` + is always `(1, 0, \ldots, 0)`, i.e., the first vector of the + standard basis. + EXAMPLES:: sage: from itertools import islice @@ -948,6 +954,8 @@ def minimized(self): [3 0] [ 0 1] [6 1], [-6 5], (1, 0), (0, 1) ) + sage: M.left == vector([1, 0]) + True sage: all(c == d and v == w ....: for (c, v), (d, w) in islice(zip(iter(S), iter(M)), 20)) True From e505a43b4c68c8b9d6f3fd61557afbc490391c34 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 19 Jan 2022 14:13:34 +0100 Subject: [PATCH 054/742] Trac #32921, review item 6: fix upper bound --- src/sage/combinat/k_regular_sequence.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 7a284946778..9f3dbd72f38 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2297,13 +2297,15 @@ def shifted_inhomogeneities(self, recurrence_rules): 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... sage: RR = namedtuple('recurrence_rules', ....: ['M', 'm', 'll', 'uu', 'inhomogeneities']) - sage: recurrence_rules = RR(M=3, m=0, ll=-8, uu=14, + sage: recurrence_rules = RR(M=3, m=0, ll=-14, uu=14, ....: inhomogeneities={0: S}) sage: RP.shifted_inhomogeneities(recurrence_rules) - {(0, -1): (2-regular sequence 0, 0, 1, 1, 2, 1, 2, 2, 3, 1, ..., 0), - (0, 0): (2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ..., 4), - (0, 1): (2-regular sequence 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, ..., 6), - (0, 2): (2-regular sequence 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, ..., 9)} + {(0, -2): (2-regular sequence 0, 0, 0, 1, 1, 2, 1, 2, 2, 3, ..., 0), + (0, -1): (2-regular sequence 0, 0, 1, 1, 2, 1, 2, 2, 3, 1, ..., 5), + (0, 0): (2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ..., 9), + (0, 1): (2-regular sequence 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, ..., 11), + (0, 2): (2-regular sequence 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, ..., 14), + (0, 3): (2-regular sequence 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, ..., 18)} .. SEEALSO:: @@ -2321,7 +2323,7 @@ def shifted_inhomogeneities(self, recurrence_rules): inhomogeneities = recurrence_rules.inhomogeneities lower = floor(ll/k**M) - upper = floor((k**(M-1) - k**m + uu)/k**M) + upper = floor((k**(M-1) - k**m + uu)/k**M) + 1 shifted_inhomogeneities = {} current_row = 0 From 0f2f415753c7f0d9922903cf692245af24f1ee70 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 19 Jan 2022 16:44:22 +0100 Subject: [PATCH 055/742] Trac #32921: fix copy/paste error in test... --- src/sage/combinat/k_regular_sequence.py | 39 ++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 9f3dbd72f38..994ab374c98 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1069,7 +1069,7 @@ def from_recurrence(self, *args, **kwds): ....: f(8*n) == 2*f(4*n), ....: f(8*n + 1) == f(4*n + 1), ....: f(8*n + 2) == f(4*n + 1), - ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2), + ....: f(8*n + 3) == f(4*n + 2), ....: f(8*n + 4) == 2*f(4*n + 2), ....: f(8*n + 5) == f(4*n + 3), ....: f(8*n + 6) == -f(4*n + 1), @@ -2307,6 +2307,43 @@ def shifted_inhomogeneities(self, recurrence_rules): (0, 2): (2-regular sequence 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, ..., 14), (0, 3): (2-regular sequence 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, ..., 18)} + TESTS:: + + sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: var('n') + n + sage: function('f') + f + sage: UB = Seq2.from_recurrence([ + ....: f(8*n) == 2*f(4*n), + ....: f(8*n + 1) == f(4*n + 1), + ....: f(8*n + 2) == f(4*n + 1) + f(4*n + 3), + ....: f(8*n + 3) == -f(4*n + 1) + f(4*n + 2), + ....: f(8*n + 4) == 2*f(4*n + 2), + ....: f(8*n + 5) == f(4*n + 3), + ....: f(8*n + 6) == -f(4*n + 1) + f(4*n + 2) + f(4*n + 3), + ....: f(8*n + 7) == 2*f(4*n + 1) + f(4*n + 3), + ....: f(0) == 1, f(1) == 2, f(2) == 2, f(3) == 4, f(4) == 2, + ....: f(5) == 4, f(6) == 6, f(7) == 0, f(8) == 4, f(9) == 4, + ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, + ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, + ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3) + sage: recurrence_rules_UB = RR(M=3, m=2, ll=0, uu=9, + ....: inhomogeneities={2: UB.subsequence(4, 3), 3: -UB.subsequence(4, 1), + ....: 6: UB.subsequence(4, 2) + UB.subsequence(4, 3)}) + sage: RP.shifted_inhomogeneities(recurrence_rules_UB) + {(2, 0): (2-regular sequence 4, 0, 4, 4, 0, 8, 4, 4, 4, 8, ..., 0), + (2, 1): (2-regular sequence 0, 4, 4, 0, 8, 4, 4, 4, 8, 0, ..., 6), + (2, 2): (2-regular sequence 4, 4, 0, 8, 4, 4, 4, 8, 0, 16, ..., 14), + (3, 0): (2-regular sequence -2, -4, -4, 0, -4, -4, 0, -4, -4, 0, ..., 23), + (3, 1): (2-regular sequence -4, -4, 0, -4, -4, 0, -4, -4, 0, -4, ..., 29), + (3, 2): (2-regular sequence -4, 0, -4, -4, 0, -4, -4, 0, -4, -8, ..., 35), + (6, 0): (2-regular sequence 6, 6, 8, 8, 8, 12, 8, 12, 8, 12, ..., 43), + (6, 1): (2-regular sequence 6, 8, 8, 8, 12, 8, 12, 8, 12, 12, ..., 49), + (6, 2): (2-regular sequence 8, 8, 8, 12, 8, 12, 8, 12, 12, 24, ..., 56)} + sage: RP.shifted_inhomogeneities(recurrence_rules_UB)[(6, 2)][0].mu[0].ncols() + 9 + .. SEEALSO:: :meth:`kRegularSequenceSpace.from_recurrence` From f5b81af717f080c65bc827b0e2a5b4b479741de1 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 19 Jan 2022 16:47:10 +0100 Subject: [PATCH 056/742] Trac #32921: simplify construction of matrix and right vector --- src/sage/combinat/k_regular_sequence.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 994ab374c98..3c784bafac2 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2428,7 +2428,8 @@ def v_eval_n(self, recurrence_rules, n): Seq = list(inhomogeneities.values())[0].parent() W = Seq.indices() shifted_inhomogeneities = [S[0] for S in self.shifted_inhomogeneities(recurrence_rules).values()] - vv = [(S._mu_of_word_(W(ZZ(n).digits(k))) * S.right) for S in shifted_inhomogeneities] + vv = [(S.coefficient_of_word(W(ZZ(n).digits(k)), multiply_left=False)) + for S in shifted_inhomogeneities] v = vector(chain(v, *vv)) return v @@ -2639,11 +2640,10 @@ def entry(i, kk): rem_d = k**(M-1)*rem + (d%k**M) dd = d // k**M if rem_d < k**M and rem_d in inhomogeneities.keys(): - mat[ind[(j, d)], - dim_without_corr + shifted_inhomogeneities[(rem_d, dd)][1]] = 1 + mat[i, dim_without_corr + shifted_inhomogeneities[(rem_d, dd)][1]] = 1 elif rem_d >= k**M and rem_d - k**M in inhomogeneities.keys(): - mat[ind[(j, d)], - dim_without_corr + shifted_inhomogeneities[(rem_d - k**M, dd+1)][1]] = 1 + mat[i, dim_without_corr + + shifted_inhomogeneities[(rem_d - k**M, dd + 1)][1]] = 1 dim_of_inhom = shifted_inhomogeneities[list(shifted_inhomogeneities)[-1]][1] + \ shifted_inhomogeneities[list(shifted_inhomogeneities)[-1]][0].mu[0].ncols() From 6294eb114ffee5e44c76a2092b5a4476055bbf16 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 19 Jan 2022 19:26:45 +0100 Subject: [PATCH 057/742] Trac #32921: allow constants as inhomogeneities, add tests for input --- src/sage/combinat/k_regular_sequence.py | 60 ++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 3c784bafac2..a0c1c9a3bc1 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -837,7 +837,7 @@ def from_recurrence(self, *args, **kwds): - ``inhomogeneities`` -- (default: ``{}``) a dictionary mapping integers ``r`` to the inhomogeneity `g_r` as given in [HKL2021]_, Corollary D. All inhomogeneities have to be - regular sequences from ``self``. + regular sequences from ``self`` or elements of ``coefficient_ring``. OUTPUT: a :class:`kRegularSequence` @@ -908,14 +908,13 @@ def from_recurrence(self, *args, **kwds): Alternatively, we can also use the simpler but inhomogeneous recurrence relations `S(2n) = S(n)` and `S(2n+1) = S(n) + 1` via direct parameters:: - sage: one = Seq2.one_hadamard() - sage: S = Seq2.from_recurrence(M=1, m=0, + sage: S3 = Seq2.from_recurrence(M=1, m=0, ....: coeffs={(0, 0): 1, (1, 0): 1}, ....: initial_values={0: 0, 1: 1}, - ....: inhomogeneities={1: one}) - sage: S + ....: inhomogeneities={1: 1}) + sage: S3 2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ... - sage: (S - S2).is_trivial_zero() + sage: (S3 - S2).is_trivial_zero() True Number of Non-Zero Elements in the Generalized Pascal's Triangle (see [LRS2017]_):: @@ -1934,6 +1933,37 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) TESTS:: + sage: var('n') + n + sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0, + ....: {-1: 0, 1: 0, 10: 0, I: 0, n: 0}) + Traceback (most recent call last): + ... + ValueError: Indices [-1, 10, I, n] for inhomogeneities are + no integers between 0 and 1. + + :: + + sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0, + ....: {0: n}) + Traceback (most recent call last): + ... + ValueError: Inhomogeneities {0: n} are neither 2-regular sequences + nor elements of Integer Ring. + + :: + + sage: Seq3 = kRegularSequenceSpace(3, ZZ) + sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0, + ....: {0: Seq3.some_elements()[0]}) + Traceback (most recent call last): + ... + ValueError: Inhomogeneities {0: 3-regular sequence 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, ...} are neither 2-regular sequences nor elements of + Integer Ring. + + :: + sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0) Traceback (most recent call last): ... @@ -1971,6 +2001,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) """ from collections import namedtuple + from sage.arith.srange import srange from sage.functions.other import ceil, floor coefficient_ring = self.coefficient_ring @@ -1993,6 +2024,23 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) n1 = offset - floor(ll/k**M) dim = (k**M - 1)/(k - 1) + (M - m)*(uu - ll - k**m + 1) + n1 + if inhomogeneities: + invalid_indices = [i for i in inhomogeneities + if i not in srange(k**M)] + if invalid_indices: + raise ValueError(f"Indices {invalid_indices} for inhomogeneities are no " + f"integers between 0 and {k**M - 1}.") + Seq = kRegularSequenceSpace(k, coefficient_ring) + inhomogeneities.update({i: inhomogeneities[i] * Seq.one_hadamard() + for i in inhomogeneities + if inhomogeneities[i] in coefficient_ring}) + invalid = {i: inhomogeneities[i] for i in inhomogeneities + if not (isinstance(inhomogeneities[i].parent(), kRegularSequenceSpace) and + inhomogeneities[i].parent().k == k)} + if invalid: + raise ValueError(f"Inhomogeneities {invalid} are neither {k}-regular " + f"sequences nor elements of {coefficient_ring}.") + if not initial_values: raise ValueError("No initial values are given.") keys_initial = initial_values.keys() From 94b183a4c1fc7988843ee6927ea43f9fe55321f3 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Fri, 21 Jan 2022 14:58:19 +0100 Subject: [PATCH 058/742] Trac #32921: rewrite construction of matrix, left, right --- src/sage/combinat/k_regular_sequence.py | 69 ++++++++++++++----------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index a0c1c9a3bc1..3a5fa06a690 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2410,19 +2410,9 @@ def shifted_inhomogeneities(self, recurrence_rules): lower = floor(ll/k**M) upper = floor((k**(M-1) - k**m + uu)/k**M) + 1 - shifted_inhomogeneities = {} - current_row = 0 - for i in inhomogeneities.keys(): - for b in srange(lower, upper + 1): - S_b = inhomogeneities[i].subsequence(1, b, minimize=True) - shifted_inhomogeneities.update({(i, b): (S_b, current_row)}) - current_row += S_b.mu[0].ncols() - - CR = self.coefficient_ring - assert all([S[0].left[0] == CR(1) and S[0].left[1:] == vector(len(S[0].left[1:])*[CR(0)]) - for S in shifted_inhomogeneities.values()]) - - return shifted_inhomogeneities + return {i: inhomogeneities[i].subsequence(1, {b: 1 for b in srange(lower, upper + 1)}, + minimize=False) + for i in inhomogeneities} def v_eval_n(self, recurrence_rules, n): r""" @@ -2475,9 +2465,9 @@ def v_eval_n(self, recurrence_rules, n): if not all(S.is_trivial_zero() for S in inhomogeneities.values()): Seq = list(inhomogeneities.values())[0].parent() W = Seq.indices() - shifted_inhomogeneities = [S[0] for S in self.shifted_inhomogeneities(recurrence_rules).values()] + shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) vv = [(S.coefficient_of_word(W(ZZ(n).digits(k)), multiply_left=False)) - for S in shifted_inhomogeneities] + for S in shifted_inhomogeneities.values()] v = vector(chain(v, *vv)) return v @@ -2633,6 +2623,8 @@ def matrix(self, recurrence_rules, rem, correct_offset=True): :meth:`kRegularSequenceSpace.from_recurrence` """ + from itertools import chain + from sage.arith.srange import srange from sage.functions.other import floor from sage.matrix.constructor import Matrix @@ -2679,24 +2671,41 @@ def entry(i, kk): if not all(S.is_trivial_zero() for S in inhomogeneities.values()): shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) + lower = floor(ll/k**M) + upper = floor((k**(M-1) - k**m + uu)/k**M) + 1 - mat = block_diagonal_matrix(mat, *[S[0].mu[rem] - for S in shifted_inhomogeneities.values()]) - - for i in srange(dim_without_corr - k**(M-1) + k**m - uu + ll - 1, dim_without_corr): - j, d = ind[i] # j = M - 1 + def wanted_inhomogeneity(row): + j, d = ind[row] + if j != M - 1: + return (None, None) rem_d = k**(M-1)*rem + (d%k**M) dd = d // k**M if rem_d < k**M and rem_d in inhomogeneities.keys(): - mat[i, dim_without_corr + shifted_inhomogeneities[(rem_d, dd)][1]] = 1 + return (rem_d, dd) elif rem_d >= k**M and rem_d - k**M in inhomogeneities.keys(): - mat[i, dim_without_corr + - shifted_inhomogeneities[(rem_d - k**M, dd + 1)][1]] = 1 + return (rem_d - k**M, dd + 1) + else: + return (None, None) + + def left_for_inhomogeneity(wanted): + return list(chain(*[(wanted[1] == i and wanted[0] == r)*inhomogeneities[r].left + for r in inhomogeneities + for i in srange(lower, upper + 1)])) + + def matrix_row(row): + wanted = wanted_inhomogeneity(row) + return list(mat[row]) + left_for_inhomogeneity(wanted) + + mat = Matrix([matrix_row(row) for row in srange(dim_without_corr)]) + mat_inhomog = block_diagonal_matrix([S.mu[rem] + for S in shifted_inhomogeneities.values()]) + + mat = block_matrix([[mat], + [block_matrix([[zero_matrix(mat_inhomog.nrows(), dim_without_corr), + mat_inhomog]])]]) - dim_of_inhom = shifted_inhomogeneities[list(shifted_inhomogeneities)[-1]][1] + \ - shifted_inhomogeneities[list(shifted_inhomogeneities)[-1]][0].mu[0].ncols() - dim += dim_of_inhom - dim_without_corr += dim_of_inhom + dim_without_corr = mat.ncols() + dim = dim_without_corr + n1 if n1 > 0 and correct_offset: W = Matrix(coefficient_ring, dim_without_corr, 0) @@ -2752,10 +2761,8 @@ def left(self, recurrence_rules): if not all(S.is_trivial_zero() for S in inhomogeneities.values()): shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) - dim += shifted_inhomogeneities[list(shifted_inhomogeneities)[-1]][1] + \ - shifted_inhomogeneities[ - list(shifted_inhomogeneities)[-1] - ][0].mu[0].ncols() + dim += sum(shifted_inhomogeneities[i].mu[0].ncols() + for i in shifted_inhomogeneities) return vector([1] + (dim - 1)*[0]) From 27a8f5ddac30badfc9a19249361efdb0ca97f68f Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Fri, 21 Jan 2022 14:59:15 +0100 Subject: [PATCH 059/742] Trac #32921: adapt tests --- src/sage/combinat/k_regular_sequence.py | 34 ++++++++++--------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 3a5fa06a690..745cd835be1 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2030,6 +2030,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) if invalid_indices: raise ValueError(f"Indices {invalid_indices} for inhomogeneities are no " f"integers between 0 and {k**M - 1}.") + Seq = kRegularSequenceSpace(k, coefficient_ring) inhomogeneities.update({i: inhomogeneities[i] * Seq.one_hadamard() for i in inhomogeneities @@ -2346,14 +2347,9 @@ def shifted_inhomogeneities(self, recurrence_rules): sage: RR = namedtuple('recurrence_rules', ....: ['M', 'm', 'll', 'uu', 'inhomogeneities']) sage: recurrence_rules = RR(M=3, m=0, ll=-14, uu=14, - ....: inhomogeneities={0: S}) + ....: inhomogeneities={0: S, 1: S}) sage: RP.shifted_inhomogeneities(recurrence_rules) - {(0, -2): (2-regular sequence 0, 0, 0, 1, 1, 2, 1, 2, 2, 3, ..., 0), - (0, -1): (2-regular sequence 0, 0, 1, 1, 2, 1, 2, 2, 3, 1, ..., 5), - (0, 0): (2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ..., 9), - (0, 1): (2-regular sequence 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, ..., 11), - (0, 2): (2-regular sequence 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, ..., 14), - (0, 3): (2-regular sequence 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, ..., 18)} + {0: 2-regular sequence 4, 5, 7, 9, 11, 11, 11, 12, 13, 13, ...} TESTS:: @@ -2376,21 +2372,17 @@ def shifted_inhomogeneities(self, recurrence_rules): ....: f(10) == 4, f(11) == 4, f(12) == 12, f(13) == 0, f(14) == 4, ....: f(15) == 4, f(16) == 8, f(17) == 4, f(18) == 8, f(19) == 0, ....: f(20) == 8, f(21) == 4, f(22) == 4, f(23) == 8], f, n, offset=3) + sage: inhomogeneities={2: UB.subsequence(4, 3), 3: -UB.subsequence(4, 1), + ....: 6: UB.subsequence(4, 2) + UB.subsequence(4, 3)} sage: recurrence_rules_UB = RR(M=3, m=2, ll=0, uu=9, - ....: inhomogeneities={2: UB.subsequence(4, 3), 3: -UB.subsequence(4, 1), - ....: 6: UB.subsequence(4, 2) + UB.subsequence(4, 3)}) - sage: RP.shifted_inhomogeneities(recurrence_rules_UB) - {(2, 0): (2-regular sequence 4, 0, 4, 4, 0, 8, 4, 4, 4, 8, ..., 0), - (2, 1): (2-regular sequence 0, 4, 4, 0, 8, 4, 4, 4, 8, 0, ..., 6), - (2, 2): (2-regular sequence 4, 4, 0, 8, 4, 4, 4, 8, 0, 16, ..., 14), - (3, 0): (2-regular sequence -2, -4, -4, 0, -4, -4, 0, -4, -4, 0, ..., 23), - (3, 1): (2-regular sequence -4, -4, 0, -4, -4, 0, -4, -4, 0, -4, ..., 29), - (3, 2): (2-regular sequence -4, 0, -4, -4, 0, -4, -4, 0, -4, -8, ..., 35), - (6, 0): (2-regular sequence 6, 6, 8, 8, 8, 12, 8, 12, 8, 12, ..., 43), - (6, 1): (2-regular sequence 6, 8, 8, 8, 12, 8, 12, 8, 12, 12, ..., 49), - (6, 2): (2-regular sequence 8, 8, 8, 12, 8, 12, 8, 12, 12, 24, ..., 56)} - sage: RP.shifted_inhomogeneities(recurrence_rules_UB)[(6, 2)][0].mu[0].ncols() - 9 + ....: inhomogeneities=inhomogeneities) + sage: shifted_inhomog = RP.shifted_inhomogeneities(recurrence_rules_UB) + sage: shifted_inhomog + {2: 2-regular sequence 8, 8, 8, 12, 12, 16, 12, 16, 12, 24, ..., + 3: 2-regular sequence -10, -8, -8, -8, -8, -8, -8, -8, -8, -12, ..., + 6: 2-regular sequence 20, 22, 24, 28, 28, 32, 28, 32, 32, 48, ...} + sage: shifted_inhomog[2].mu[0].ncols() == 3*inhomogeneities[2].mu[0].ncols() + True .. SEEALSO:: From 56c548f480aa47798f4576813532e2a1610b2477 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Fri, 21 Jan 2022 15:43:32 +0100 Subject: [PATCH 060/742] Trac #32921: add some further doctests --- src/sage/combinat/k_regular_sequence.py | 36 ++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index b8756cc8649..a6687caa12e 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1194,6 +1194,14 @@ def from_recurrence(self, *args, **kwds): ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3], f, n, offset=2) 2-regular sequence 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, ... + Check if inhomogeneities `0` do not change the sequence:: + + sage: Seq2.from_recurrence([ + ....: f(2*n) == 0, f(2*n + 1) == 0, + ....: f(0) == 1, f(1) == 1, f(2) == 2, f(3) == 3], f, n, offset=2, + ....: inhomogeneities={0: 0, 1: Seq2.zero()}) + 2-regular sequence 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, ... + :: sage: set_random_seed() @@ -2084,14 +2092,15 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) sage: RP.parameters(2, 1, ....: {(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4, ....: (1, 1): 5, (2, -2): 9, (2, 0): 7, (2, 1): 8, (3, -2): 12, - ....: (3, 0): 10, (3, 1): 11}, {0: 1, 1: 2, 2: 1, 3: 4}, 0) + ....: (3, 0): 10, (3, 1): 11}, {0: 1, 1: 2, 2: 1, 3: 4}, 0, {0: 1}) recurrence_rules(M=2, m=1, l=-2, u=1, ll=-6, uu=3, dim=14, coeffs={(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4, (1, 1): 5, (2, -2): 9, (2, 0): 7, (2, 1): 8, (3, -2): 12, (3, 0): 10, (3, 1): 11}, initial_values={0: 1, 1: 2, 2: 1, 3: 4, - 4: 12, 5: 30, 6: 48, 7: 66, 8: 75, 9: 204, 10: 333, 11: 462, - 12: 216, 13: 594, -6: 0, -5: 0, -4: 0, -3: 0, -2: 0, -1: 0}, - offset=1, n1=3, inhomogeneities={}) + 4: 13, 5: 30, 6: 48, 7: 66, 8: 77, 9: 208, 10: 340, 11: 472, + 12: 220, 13: 600, -6: 0, -5: 0, -4: 0, -3: 0, -2: 0, -1: 0}, + offset=1, n1=3, inhomogeneities={0: 2-regular sequence 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, ...}) .. SEEALSO:: @@ -2368,6 +2377,15 @@ def values(self, *, M, m, l, u, ll, coeffs, ....: coeffs={(0, 0): 0, (1, 1): 0}, initial_values={}, ....: last_value_needed=10, offset=0, inhomogeneities={}) {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0} + + :: + + sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: RP.values(M=1, m=0, l=0, u=0, ll=0, + ....: coeffs={(0, 0): 0, (1, 1): 0}, initial_values={}, + ....: last_value_needed=10, offset=0, + ....: inhomogeneities={0: Seq2.one_hadamard()}) + {0: 1, 1: 0, 2: 1, 3: 0, 4: 1, 5: 0, 6: 1, 7: 0, 8: 1, 9: 0, 10: 1} """ from sage.arith.srange import srange from sage.rings.integer_ring import ZZ @@ -2906,6 +2924,16 @@ def left(self, recurrence_rules): sage: RP.left(recurrence_rules) (1, 0, 0, 0, 0) + :: + + sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: RRD = namedtuple('recurrence_rules_dim', + ....: ['M', 'm', 'll', 'uu', 'dim', 'inhomogeneities']) + sage: recurrence_rules = RRD(M=3, m=2, ll=0, uu=9, dim=5, + ....: inhomogeneities={0: Seq2.one_hadamard()}) + sage: RP.left(recurrence_rules) + (1, 0, 0, 0, 0, 0, 0, 0) + .. SEEALSO:: :meth:`kRegularSequenceSpace.from_recurrence` From aa2fb415e3a6b38665728e4b8a9b1f9007cec013 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Sat, 22 Jan 2022 13:14:56 +0100 Subject: [PATCH 061/742] Trac #32921, review item 15: list --> dictionary --- src/sage/combinat/k_regular_sequence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index a6687caa12e..ff1c21c2886 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2508,7 +2508,7 @@ def ind(self, M, m, ll, uu): def shifted_inhomogeneities(self, recurrence_rules): r""" - Return a list of all needed shifted inhomogeineities as described + Return a dictionary of all needed shifted inhomogeineities as described in the proof of Coroallary D in [HKL2021]_. INPUT: @@ -2516,7 +2516,7 @@ def shifted_inhomogeneities(self, recurrence_rules): - ``recurrence_rules`` -- a namedtuple generated by :meth:`parameters` - OUTPUT: a list + OUTPUT: a dictionary EXAMPLES:: From 26c86880ced304d452651e1714baaf2adc2c3afd Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Sat, 22 Jan 2022 13:16:10 +0100 Subject: [PATCH 062/742] Trac #32921, review item 16: fix typo --- src/sage/combinat/k_regular_sequence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index ff1c21c2886..510d462bf45 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2508,7 +2508,7 @@ def ind(self, M, m, ll, uu): def shifted_inhomogeneities(self, recurrence_rules): r""" - Return a dictionary of all needed shifted inhomogeineities as described + Return a dictionary of all needed shifted inhomogeneities as described in the proof of Coroallary D in [HKL2021]_. INPUT: From 7983b5ef45366a3d4332afd3f2679da4ddcc96b6 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Sat, 22 Jan 2022 13:20:34 +0100 Subject: [PATCH 063/742] Trac #32921, review item 18: rephrase docstring --- src/sage/combinat/recognizable_series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index f0be8b5af61..9351a06e3ee 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -933,7 +933,7 @@ def minimized(self): .. NOTE:: - Due to the algorithm, the vector :meth:`RecognizableSeries.left` + Due to the algorithm, the left vector of the result is always `(1, 0, \ldots, 0)`, i.e., the first vector of the standard basis. From 7b0e213ffe866b137f907ce54dfdd4f9f4237c4e Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Sat, 22 Jan 2022 13:23:21 +0100 Subject: [PATCH 064/742] Trac #32921, review item 19: simplify condition in left_for_inhomogeneity --- src/sage/combinat/k_regular_sequence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 510d462bf45..0340cefd7a9 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2864,7 +2864,7 @@ def wanted_inhomogeneity(row): return (None, None) def left_for_inhomogeneity(wanted): - return list(chain(*[(wanted[1] == i and wanted[0] == r)*inhomogeneities[r].left + return list(chain(*[(wanted == (r, i))*inhomogeneities[r].left for r in inhomogeneities for i in srange(lower, upper + 1)])) From 613976a29dbcaae177245b3a8e6fd769ef7a760e Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Sat, 22 Jan 2022 13:26:41 +0100 Subject: [PATCH 065/742] Trac #32921, review item 20 --- src/sage/combinat/k_regular_sequence.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 0340cefd7a9..8f5756b83cb 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2870,15 +2870,15 @@ def left_for_inhomogeneity(wanted): def matrix_row(row): wanted = wanted_inhomogeneity(row) - return list(mat[row]) + left_for_inhomogeneity(wanted) + return left_for_inhomogeneity(wanted) - mat = Matrix([matrix_row(row) for row in srange(dim_without_corr)]) + mat_upper_right = Matrix([matrix_row(row) for row in srange(dim_without_corr)]) mat_inhomog = block_diagonal_matrix([S.mu[rem] for S in shifted_inhomogeneities.values()]) - mat = block_matrix([[mat], - [block_matrix([[zero_matrix(mat_inhomog.nrows(), dim_without_corr), - mat_inhomog]])]]) + mat = block_matrix([[mat, mat_upper_right], + [zero_matrix(mat_inhomog.nrows(), dim_without_corr), + mat_inhomog]]) dim_without_corr = mat.ncols() dim = dim_without_corr + n1 From afa97f1a7bcf0b8fa0821ec975427cda84f5f3ea Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Sat, 22 Jan 2022 13:28:41 +0100 Subject: [PATCH 066/742] Trac #32921, review item 21: remove unnecessary condition --- src/sage/combinat/k_regular_sequence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 8f5756b83cb..ce0ca66bc37 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2856,9 +2856,9 @@ def wanted_inhomogeneity(row): return (None, None) rem_d = k**(M-1)*rem + (d%k**M) dd = d // k**M - if rem_d < k**M and rem_d in inhomogeneities.keys(): + if rem_d < k**M: return (rem_d, dd) - elif rem_d >= k**M and rem_d - k**M in inhomogeneities.keys(): + elif rem_d >= k**M: return (rem_d - k**M, dd + 1) else: return (None, None) From bcb5c255881ea527efb2401759f54afe240e57fb Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Sat, 22 Jan 2022 13:31:23 +0100 Subject: [PATCH 067/742] Trac #32921, review item 22: simplify left_for_inhomogeneity --- src/sage/combinat/k_regular_sequence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index ce0ca66bc37..247f152a32b 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2864,8 +2864,8 @@ def wanted_inhomogeneity(row): return (None, None) def left_for_inhomogeneity(wanted): - return list(chain(*[(wanted == (r, i))*inhomogeneities[r].left - for r in inhomogeneities + return list(chain(*[(wanted == (r, i))*inhomogeneity.left + for r, inhomogeneity in inhomogeneities.items() for i in srange(lower, upper + 1)])) def matrix_row(row): From fdb70b75c19cd0a220e4665bfaa84c60ee6ec868 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Mon, 24 Jan 2022 13:32:40 +0100 Subject: [PATCH 068/742] Trac #32921, review item 1: use sequence with well-chosen linear representation --- src/sage/combinat/k_regular_sequence.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 247f152a32b..dfe4479478d 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1204,15 +1204,15 @@ def from_recurrence(self, *args, **kwds): :: - sage: set_random_seed() - sage: S = Seq2((random_matrix(ZZ, 3, 3), random_matrix(ZZ, 3, 3)), - ....: left=vector([randint(-2, 2) for i in srange(3)]), - ....: right=vector([randint(-2, 2) for i in srange(3)])) + sage: S = Seq2([matrix([[3/2, -1, 1], [0, 1/2, 1/2], [0, -1, 2]]), + ....: matrix([[-1, 0, 1], [1, 5, -5], [-4, 0, 0]])], + ....: left=vector([1, 2, 3]), + ....: right=vector([0, 1, 1])) sage: T = Seq2.from_recurrence(M=3, m=2, ....: coeffs={}, ....: initial_values={0: S[0]}, ....: inhomogeneities={i: S.subsequence(2**3, i) for i in srange(2**3)}) - sage: all(S[i] == T[i] for i in srange(100)) + sage: (S - T).is_trivial_zero() True Connection between the Stern--Brocot sequence and the number From 34850f6b3811528862b0c4dc496c644198d2719a Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 1 Feb 2022 20:06:43 +0100 Subject: [PATCH 069/742] Trac #32921, review item 17: use @cached_method --- src/sage/combinat/k_regular_sequence.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index dfe4479478d..92c0eb4b03d 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2506,6 +2506,12 @@ def ind(self, M, m, ll, uu): return ind + @cached_method(key=lambda self, recurrence_rules: + (recurrence_rules.M, + recurrence_rules.m, + recurrence_rules.ll, + recurrence_rules.uu, + tuple(recurrence_rules.inhomogeneities.items()))) def shifted_inhomogeneities(self, recurrence_rules): r""" Return a dictionary of all needed shifted inhomogeneities as described From af9f496fe3d3d863bc36f48a4d1db71b8210a2b0 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Tue, 1 Feb 2022 20:27:18 +0100 Subject: [PATCH 070/742] Trac #32921, review item 15: add description for output --- src/sage/combinat/k_regular_sequence.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 92c0eb4b03d..699ddfc2b22 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2522,7 +2522,17 @@ def shifted_inhomogeneities(self, recurrence_rules): - ``recurrence_rules`` -- a namedtuple generated by :meth:`parameters` - OUTPUT: a dictionary + OUTPUT: + + A dictionary mapping `r` to the regular sequence + `\sum_i g_r(n + i)` for `g_r` as given in [HKL2021]_, Corollary D, + and `i` between `\lfloor\ell'/k^{M}\rfloor` and + `\lfloor (k^{M-1} - k^{m} + u')/k^{M}\rfloor + 1`; see [HKL2021]_, + proof of Corollary D. The first blocks of the corresponding + vector-valued sequence (obtained from its linear + representation) correspond to the sequences `g_r(n + i)` where + `i` is as in the sum above; the remaining blocks consist of + other shifts which are required for the regular sequence. EXAMPLES:: From 736259b76ac2ce42de34a80d24b988233b319056 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Thu, 14 Oct 2021 12:42:04 +0800 Subject: [PATCH 071/742] warn when is_prime() is used on field elements --- src/sage/arith/misc.py | 56 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 664e3ba924f..c940893ed8f 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -471,10 +471,19 @@ def factorial(n, algorithm='gmp'): def is_prime(n): r""" - Return ``True`` if `n` is a prime number, and ``False`` otherwise. + Determine whether `n` is a prime element of its parent ring. - Use a provable primality test or a strong pseudo-primality test depending - on the global :mod:`arithmetic proof flag `. + Exceptional special cases: + + - For integers, determine whether `n` is a *positive* prime. + - For number fields except `\QQ`, determine whether `n` + is a prime element *of the maximal order*. + + ALGORITHM: + + For integers, this function uses a provable primality test + or a strong pseudo-primality test depending on the global + :mod:`arithmetic proof flag `. INPUT: @@ -505,18 +514,57 @@ def is_prime(n): sage: is_prime(-2) False + :: + sage: a = 2**2048 + 981 sage: is_prime(a) # not tested - takes ~ 1min sage: proof.arithmetic(False) sage: is_prime(a) # instantaneous! True sage: proof.arithmetic(True) + + TESTS: + + Make sure the warning from :trac:`25046` works as intended:: + + sage: is_prime(7/1) + doctest:warning + ... + UserWarning: Testing primality in Rational Field, which is a field, hence the result will always be False. To test whether n is a prime integer, use is_prime(ZZ(n)) or ZZ(n).is_prime(). Using n.is_prime() instead will silence this warning. + False + sage: ZZ(7/1).is_prime() + True + sage: QQ(7/1).is_prime() + False + + However, number fields redefine ``.is_prime()`` in an + incompatible fashion (cf. :trac:`32340`) and we should + not warn:: + + sage: K. = NumberField(x^2+1) + sage: is_prime(1+i) + True """ try: - return n.is_prime() + ret = n.is_prime() except (AttributeError, NotImplementedError): return ZZ(n).is_prime() + R = n.parent() + if R.is_field(): + # number fields redefine .is_prime(), see #32340 + from sage.rings.number_field.number_field import NumberField_generic + if not isinstance(R, NumberField_generic): + import warnings + s = f'Testing primality in {R}, which is a field, ' \ + 'hence the result will always be False. ' + if R is QQ: + s += 'To test whether n is a prime integer, use ' \ + 'is_prime(ZZ(n)) or ZZ(n).is_prime(). ' + s += 'Using n.is_prime() instead will silence this warning.' + warnings.warn(s) + + return ret def is_pseudoprime(n): r""" From 0866d861ef3e112f048328d7b5c8d884d9ff5324 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Wed, 2 Mar 2022 11:41:54 +0000 Subject: [PATCH 072/742] Typo fix --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index bbb09e2def6..44422d073ba 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3542,7 +3542,7 @@ def divisor_to_divisor_list(self, divisor): eps = self._RR(2)**(-self._prec+3) dl = [] - PZ = PolynomialRing(S._R.base(), 'z').fraction_field() + PZ = PolynomialRing(self._R.base(), 'z').fraction_field() RF = PolynomialRing(PZ, 'w') for d in divisor.support(): From d8ccc5a55fd7afa9c3fe4ad8604e6522453bd07d Mon Sep 17 00:00:00 2001 From: Dennis Jahn Date: Thu, 14 Apr 2022 09:30:47 +0200 Subject: [PATCH 073/742] added flag to bruhat_lower_covers_reflections() similar to bruhat_lower_covers and bruhat_upper_covers, this fixed a bug only appearing while using the permutation implementation - see doctest --- src/sage/categories/coxeter_groups.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 58f80fa120e..0025d1bb255 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -2176,12 +2176,25 @@ def bruhat_lower_covers_reflections(self): sage: w.bruhat_lower_covers_reflections() [(s1*s2*s1, s1*s2*s3*s2*s1), (s3*s2*s1, s2), (s3*s1*s2, s1)] + TESTS: + + Check bug discovered in :trac:`32669` is fixed:: + + sage: W = CoxeterGroup(['A',3], implementation='permutation') + sage: W.w0.bruhat_lower_covers_reflections() + [((1,3,7,9)(2,11,6,10)(4,8,5,12), (2,5)(3,9)(4,6)(8,11)(10,12)), + ((1,11)(3,10)(4,9)(5,7)(6,12), (1,4)(2,8)(3,5)(7,10)(9,11)), + ((1,9,7,3)(2,10,6,11)(4,12,5,8), (1,7)(2,4)(5,6)(8,10)(11,12))] """ - i = self.first_descent() + i = self.first_descent(side='right') if i is None: return [] - wi = self.apply_simple_reflection(i) - return [(u.apply_simple_reflection(i), r.apply_conjugation_by_simple_reflection(i)) for u, r in wi.bruhat_lower_covers_reflections() if not u.has_descent(i)] + [(wi, self.parent().simple_reflection(i))] + wi = self.apply_simple_reflection(i, side='right') + return [(u.apply_simple_reflection(i, side='right'), + r.apply_conjugation_by_simple_reflection(i)) + for u,r in wi.bruhat_lower_covers_reflections() + if not u.has_descent(i, side='right')] + [ + (wi, self.parent().simple_reflection(i))] def lower_cover_reflections(self, side='right'): r""" From 84b5726017c226182cf917441afc347f22dc1b94 Mon Sep 17 00:00:00 2001 From: Dennis Jahn Date: Thu, 14 Apr 2022 09:31:25 +0200 Subject: [PATCH 074/742] added the method bruhat_cone including references --- .../root_system/reflection_group_real.py | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/sage/combinat/root_system/reflection_group_real.py b/src/sage/combinat/root_system/reflection_group_real.py index 310e9f5305b..38bfee60855 100644 --- a/src/sage/combinat/root_system/reflection_group_real.py +++ b/src/sage/combinat/root_system/reflection_group_real.py @@ -27,6 +27,11 @@ - Christian Stump (initial version 2011--2015) +REFERENCES: + +.. [Dye] Dyer. *Bruhat intervals, polyhedral cones and Kazhdan-Lusztig-Stanley polynomials*. Math.Z., 215(2):223-236, 1994. +.. [JahStu] Jahn and Stump. *Bruhat intervals, subword complexes and brick polyhedra for finite Coxeter groups*. Preprint, available at :arxiv:`2103.03715`, 2021. + .. WARNING:: Uses the GAP3 package *Chevie* which is available as an @@ -706,6 +711,90 @@ def simple_root_index(self, i): [0, 1, 2] """ return self._index_set_inverse[i] + + def bruhat_cone(self, x, y, side='upper', backend='cdd'): + r""" + Return the (upper or lower) Bruhat cone associated to the interval ``[x,y]``. + + To a cover relation `v \prec w` in strong Bruhat order you can assign a positive + root `\beta` given by the unique reflection `s_\beta` such that `s_\beta v = w`. + + The upper Bruhat cone of the interval `[x,y]` is the non-empty, polyhedral cone generated + by the roots corresponding to `x \prec a` for all atoms `a` in the interval. + The lower Bruhat cone of the interval `[x,y]` is the non-empty, polyhedral cone generated + by the roots corresponding to `c \prec y` for all coatoms `c` in the interval. + + INPUT: + + - ``x`` - an element in the group `W` + + - ``y`` - an element in the group `W` + + - ``side`` (default: ``'upper'``) -- must be one of the following: + + * ``'upper'`` - return the upper Bruhat cone of the interval [``x``, ``y``] + * ``'lower'`` - return the lower Bruhat cone of the interval [``x``, ``y``] + + - ``backend`` -- string (default: ``'cdd'``); the backend to use to create the polyhedron + + EXAMPLES:: + + sage: W = ReflectionGroup(['A',2]) # optional - gap3 + sage: x = W.from_reduced_word([1]) # optional - gap3 + sage: y = W.w0 # optional - gap3 + sage: W.bruhat_cone(x, y) # optional - gap3 + A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays + + sage: W = ReflectionGroup(['E',6]) # optional - gap3 + sage: x = W.one() # optional - gap3 + sage: y = W.w0 # optional - gap3 + sage: W.bruhat_cone(x, y, side='lower') # optional - gap3 + A 6-dimensional polyhedron in QQ^6 defined as the convex hull of 1 vertex and 6 rays + + TESTS:: + + sage: W = ReflectionGroup(['A',2]) # optional - gap3 + sage: x = W.one() # optional - gap3 + sage: y = W.w0 # optional - gap3 + sage: W.bruhat_cone(x, y, side='nonsense') # optional - gap3 + Traceback (most recent call last): + ... + ValueError: side must be either 'upper' or 'lower' + + REFERENCES: + + - [Dye]_ + - [JahStu]_ + """ + if side == 'upper': + roots = [self.reflection_to_positive_root(x * r * x.inverse()) + for z, r in x.bruhat_upper_covers_reflections() + if z.bruhat_le(y)] + elif side == 'lower': + roots = [self.reflection_to_positive_root(y * r * y.inverse()) + for z, r in y.bruhat_lower_covers_reflections() + if x.bruhat_le(z)] + else: + raise ValueError("side must be either 'upper' or 'lower'") + + from sage.geometry.polyhedron.constructor import Polyhedron + if self.is_crystallographic(): + return Polyhedron(vertices=[[0] * self.rank()], + rays=roots, + ambient_dim=self.rank(), + backend=backend) + if backend == 'cdd': + from warnings import warn + warn("Using floating point numbers for roots of unity. This might cause numerical errors!") + from sage.rings.real_double import RDF as base_ring + else: + from sage.rings.qqbar import AA as base_ring + + return Polyhedron(vertices=[[0] * self.rank()], + rays=roots, + ambient_dim=self.rank(), + base_ring=base_ring, + backend=backend) class Element(RealReflectionGroupElement, ComplexReflectionGroup.Element): From 8180f9639e4bd555a25e4d7202bba020472f9376 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Thu, 14 Apr 2022 10:38:39 +0100 Subject: [PATCH 075/742] Removed old comments and fixed a pycodestyle-minimal error --- .../schemes/riemann_surfaces/riemann_surface.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 2e0ff063901..e90943bcb8b 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3552,9 +3552,6 @@ def divisor_to_divisor_list(self, divisor): g0 = self._R(gs[0]) gis = [sum([PZ(gi.list()[i])*RF.gen()**i for i in range(len(gi.list()))]) for gi in gs[1:]] - #gs = [self._R(gi) for gi in gs] - #g0 = gs[0] - #gis = gs[1:] rs = self._CCz(g0).roots() rys = [] @@ -3562,15 +3559,14 @@ def divisor_to_divisor_list(self, divisor): for r, m in rs: ys = [] for gi in gis: - ers = [gi(y, r).abs() for y in ys] - #ers = [gi(r,y).abs() for y in ys] - try: - ers = min(ers) - except: + # This test is a bit clunky, it surely can be made more efficient. + if len(ys): + ers = min([gi(y, r).abs() for y in ys]) + else: ers = 1 + if not ers<=eps: poly = self._CCw(gi(self._CCw.gen(0), r)) - #poly = self._CCw(gi(r, self._CCw.gen(0))) if poly==0: nys = [] else: From 54acc94c441b29a94c03d77fbc3f409db09d526c Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Thu, 14 Apr 2022 10:42:53 +0100 Subject: [PATCH 076/742] Fixed logicals to remove pycodestyle-minimal error --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index e90943bcb8b..cca389f4b8c 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -1661,7 +1661,7 @@ def make_zw_interpolator(self, upstairs_edge, initial_continuation=None): z_start, z_end = downstairs_edge z_start = self._CC(z_start) z_end = self._CC(z_end) - if initial_continuation==None: + if initial_continuation is None: initial_continuation = self.homotopy_continuation(downstairs_edge) currL = initial_continuation windex = upstairs_edge[0][1] @@ -2864,14 +2864,14 @@ def initialise(z, i): fc_dmp_list = [fast_callable(mp.derivative(CCzg.gen(1)), domain=self._CC) for mp in mp_list] - if prec==None: + if prec is None: prec = self._prec # tau here is playing the role of the desired error. tau = self._RR(2)**(-prec+3) ONE = self._RR(1) LAMBDA = self._RR.pi()/2 - if cutoff_individually==None: + if cutoff_individually is None: cutoffs = [0] cutoff_individually = False else: From 2569965fd33576eafede32a4081b93dca2e186ab Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Thu, 14 Apr 2022 12:14:33 +0100 Subject: [PATCH 077/742] Fixed errors highlighted by chapoton --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index cca389f4b8c..02128458ba7 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3207,7 +3207,7 @@ def abel_jacobi(self, divisor, verbose=False): r""" Return the Abel-Jacobi map of ``divisor``. - Returns a representative of the Abel-Jacobi map of a divisor with basepoint + Return a representative of the Abel-Jacobi map of a divisor with basepoint ``self._basepoint``. INPUT: @@ -3324,7 +3324,7 @@ def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None, normal PM = self.period_matrix() if normalised: - AM = PM[:,0:g] + AM = PM[:, 0:self.genus] AInv = numerical_inverse(AM) PM = AInv*PM @@ -3372,7 +3372,7 @@ def places_at_branch_locus(self): r""" Return the places above the branch locus. - Returns a list of the of places above the branch locus. This must be + Return a list of the of places above the branch locus. This must be done over the base ring, and so the places are given in terms of the factors of the discriminant. Currently, this method only works when ``self._R.base_ring()==QQ`` as for other rings, the function field @@ -3461,8 +3461,6 @@ def strong_approximation(self, divisor, S): KC = C.function_field() g0, g1 = self._R.gens() Kb = FunctionField(K, str(g0)) - Pz = PolynomialRing(K, g0) - Pw = PolynomialRing(K, g1) MO = Kb.maximal_order() D_base = -sum(S) From 268865ae60170d1b4677d9a77e9bdbf7841d7fa1 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Wed, 27 Apr 2022 12:18:50 +0100 Subject: [PATCH 078/742] Replaced slow doctest --- .../riemann_surfaces/riemann_surface.py | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 02128458ba7..e783b0b1296 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -59,32 +59,31 @@ True We can look at an extended example of the Abel-Jacobi functionality. We will -show that the sum of the intersections of a bitangent to a quadratic is a -half-canonical divisor. We will use the Edge quartic as the example, which has -bitangent `x=1/2`:: +demonstrate a particular half-canonical divisor on Klein's Curve, known in +the literature.:: - sage: f = 25*(x^4+y^4+1) - 34*(x^2*y^2+x^2+y^2) - sage: S = RiemannSurface(f) + sage: f = x^3*y + y^3 + x + sage: S = RiemannSurface(f, integration_method='rigorous') sage: BL = S.places_at_branch_locus(); BL - [Place (x - 2, (x - 2)*y, y^2 - 17/5, y^3 - 17/5*y), - Place (x + 2, (x + 2)*y, y^2 - 17/5, y^3 - 17/5*y), - Place (x - 1/2, (x - 1/2)*y, y^2 - 17/20, y^3 - 17/20*y), - Place (x + 1/2, (x + 1/2)*y, y^2 - 17/20, y^3 - 17/20*y), - Place (x^4 - 34/25*x^2 + 1, y, y^2, y^3), - Place (x^4 - 34/25*x^2 + 1, (x^4 - 34/25*x^2 + 1)*y, y^2 - 34/25*x^2 - 34/25, y^3 + (-34/25*x^2 - 34/25)*y)] + [Place (x, y, y^2), + Place (x^7 + 27/4, y + 4/9*x^5, y^2 + 4/3*x^3), + Place (x^7 + 27/4, y - 2/9*x^5, y^2 + 1/3*x^3)] We can read off out the output of ``places_at_branch_locus`` to choose our divisor, and we can calculate the canonical divisor using curve functionality:: - sage: D = 1*BL[2] + sage: P0 = 1*BL[0] sage: from sage.schemes.curves.constructor import Curve sage: C = Curve(f) sage: F = C.function_field() - sage: K = (F(x).differential()).divisor() + sage: K = (F(x).differential()).divisor() - F(f.derivative(y)).divisor() + sage: Pinf, Pinf_prime = C.places_at_infinity() + sage: if K-3*Pinf-1*Pinf_prime: Pinf, Pinf_prime = (Pinf_prime, Pinf); + sage: D = P0 + 2*Pinf - Pinf_prime Note we could check using exact techniques that `2D=K`:: - sage: Z = K-2*D + sage: Z = K - 2*D sage: (Z.degree()==0, len(Z.basis_differential_space())==S.genus, len(Z.basis_function_space())==1) (True, True, True) @@ -93,7 +92,7 @@ sage: avoid = C.places_at_infinity() sage: Zeq, _ = S.strong_approximation(Z, avoid) sage: Zlist = S.divisor_to_divisor_list(Zeq) - sage: AJ = S.abel_jacobi(Zlist) # long time (50 seconds) + sage: AJ = S.abel_jacobi(Zlist) # long time (1 second) sage: S.reduce_over_period_lattice(AJ).norm() < 1e-10 # long time True @@ -3236,7 +3235,7 @@ def abel_jacobi(self, divisor, verbose=False): sage: divisor = [(-1, (-1, 0)), (1, (1, 0))] sage: AJ = S.abel_jacobi(divisor) # long time (15 seconds) sage: AJxp = [p*z for z in AJ] # long time - sage: bool(S.reduce_over_period_lattice(AJx2).norm()<1e-7) # long time + sage: bool(S.reduce_over_period_lattice(AJxp).norm()<1e-7) # long time True """ ans = 0 From fae3882ed318d1d7126b877d6f7765280213a467 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 6 May 2022 22:05:31 -0700 Subject: [PATCH 079/742] pkgs/sagemath-{objects,categories}: Replace duplication of sagmath-{environment,repl} contents by extras-require --- pkgs/sage-setup/setup.cfg | 1 + pkgs/sagemath-categories/setup.cfg.m4 | 14 +++--------- pkgs/sagemath-categories/tox.ini | 2 ++ pkgs/sagemath-objects/MANIFEST.in | 29 ++++--------------------- pkgs/sagemath-objects/pyproject.toml.m4 | 1 + pkgs/sagemath-objects/setup.cfg.m4 | 14 +++--------- 6 files changed, 14 insertions(+), 47 deletions(-) diff --git a/pkgs/sage-setup/setup.cfg b/pkgs/sage-setup/setup.cfg index 197fc6791dc..9ce8cd85d1f 100644 --- a/pkgs/sage-setup/setup.cfg +++ b/pkgs/sage-setup/setup.cfg @@ -20,6 +20,7 @@ classifiers = Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering :: Mathematics diff --git a/pkgs/sagemath-categories/setup.cfg.m4 b/pkgs/sagemath-categories/setup.cfg.m4 index 6b2b00d5525..4b2744c0de1 100644 --- a/pkgs/sagemath-categories/setup.cfg.m4 +++ b/pkgs/sagemath-categories/setup.cfg.m4 @@ -21,6 +21,7 @@ classifiers = Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering :: Mathematics @@ -35,14 +36,5 @@ install_requires = cysignals \ | sed "2,\$s/^/ /;"')dnl -scripts = - bin/sage - bin/sage-env - bin/sage-eval - bin/sage-fixdoctests - bin/sage-ipython - bin/sage-python - bin/sage-run - bin/sage-runtests - bin/sage-venv-config - bin/sage-version.sh +[options.extras_require] +test = sagemath-repl diff --git a/pkgs/sagemath-categories/tox.ini b/pkgs/sagemath-categories/tox.ini index 75f86b99908..66b8dd041b9 100644 --- a/pkgs/sagemath-categories/tox.ini +++ b/pkgs/sagemath-categories/tox.ini @@ -14,6 +14,8 @@ envlist = deps = !norequirements: -rrequirements.txt +extras = test + setenv = # Sage scripts such as sage-runtests like to use $HOME/.sage HOME={envdir} diff --git a/pkgs/sagemath-objects/MANIFEST.in b/pkgs/sagemath-objects/MANIFEST.in index ac4460f2404..5799c779057 100644 --- a/pkgs/sagemath-objects/MANIFEST.in +++ b/pkgs/sagemath-objects/MANIFEST.in @@ -1,15 +1,10 @@ prune sage graft sage/cpython -graft sage_setup # FIXME: Vendor it until we have made a new sage_setup release -include sage/env.py # FIXME: sage_setup must be changed so it does not depend on it -include sage/version.py # FIXME: likewise -include sage/misc/package_dir.p* # For sage_setup include VERSION.txt global-include all__sagemath_objects.py -graft sage/features graft sage/structure include sage/categories/action.* include sage/categories/algebra_functor.* @@ -82,26 +77,10 @@ graft sage/libs/gmp # sage/misc/latex -- this should really go to another package -## For doctesting -- this duplication will be removed in #28925 -global-include all__sagemath_repl.py -include bin/sage -include bin/sage-env -include bin/sage-env-config -include bin/sage-python -include bin/sage-runtests -graft sage/doctest -include sage/misc/temporary_file.* -include sage/misc/randstate.* -include sage/misc/misc.* # walltime, cputime -# graft sage/features -include sage/misc/package.* -include sage/misc/sagedoc.py -include sage/misc/banner.py -include sage/misc/sage_input.py -include sage/misc/sage_eval.py - -graft sage/repl -graft sage/server +## FIXME: Needed for doctesting +include sage/misc/randstate.* # used in sage.doctest +include sage/misc/misc.* # walltime, cputime used in sage.doctest + global-exclude *.c global-exclude *.cpp diff --git a/pkgs/sagemath-objects/pyproject.toml.m4 b/pkgs/sagemath-objects/pyproject.toml.m4 index 0a0149b9e45..c13665be51d 100644 --- a/pkgs/sagemath-objects/pyproject.toml.m4 +++ b/pkgs/sagemath-objects/pyproject.toml.m4 @@ -5,6 +5,7 @@ requires = [ setuptools \ wheel \ sage_setup \ + sagemath_environment \ cython \ gmpy2 \ cysignals \ diff --git a/pkgs/sagemath-objects/setup.cfg.m4 b/pkgs/sagemath-objects/setup.cfg.m4 index e5d409eb737..0b48f8038b5 100644 --- a/pkgs/sagemath-objects/setup.cfg.m4 +++ b/pkgs/sagemath-objects/setup.cfg.m4 @@ -21,6 +21,7 @@ classifiers = Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering :: Mathematics @@ -35,14 +36,5 @@ install_requires = cysignals \ | sed "2,\$s/^/ /;"')dnl -scripts = - bin/sage - bin/sage-env - bin/sage-eval - bin/sage-fixdoctests - bin/sage-ipython - bin/sage-python - bin/sage-run - bin/sage-runtests - bin/sage-venv-config - bin/sage-version.sh +[options.extras_require] +test = sagemath-repl From 714f2a9411ea2703a193ac99b281acf5b6f11a8b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 6 May 2022 22:53:47 -0700 Subject: [PATCH 080/742] build/pkgs/sagemath_*/dependencies: Update --- build/pkgs/sagemath_categories/dependencies | 2 +- build/pkgs/sagemath_environment/dependencies | 2 +- build/pkgs/sagemath_environment/install-requires.txt | 2 +- build/pkgs/sagemath_objects/dependencies | 3 +-- build/pkgs/sagemath_repl/dependencies | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) mode change 120000 => 100644 build/pkgs/sagemath_categories/dependencies mode change 120000 => 100644 build/pkgs/sagemath_environment/dependencies mode change 120000 => 100644 build/pkgs/sagemath_repl/dependencies diff --git a/build/pkgs/sagemath_categories/dependencies b/build/pkgs/sagemath_categories/dependencies deleted file mode 120000 index 55c209e6418..00000000000 --- a/build/pkgs/sagemath_categories/dependencies +++ /dev/null @@ -1 +0,0 @@ -../sagemath_objects/dependencies \ No newline at end of file diff --git a/build/pkgs/sagemath_categories/dependencies b/build/pkgs/sagemath_categories/dependencies new file mode 100644 index 00000000000..3f72fc83c3a --- /dev/null +++ b/build/pkgs/sagemath_categories/dependencies @@ -0,0 +1 @@ +FORCE $(PYTHON) cysignals gmpy2 sagemath_objects | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK)), tox sagemath_repl) diff --git a/build/pkgs/sagemath_environment/dependencies b/build/pkgs/sagemath_environment/dependencies deleted file mode 120000 index 55c209e6418..00000000000 --- a/build/pkgs/sagemath_environment/dependencies +++ /dev/null @@ -1 +0,0 @@ -../sagemath_objects/dependencies \ No newline at end of file diff --git a/build/pkgs/sagemath_environment/dependencies b/build/pkgs/sagemath_environment/dependencies new file mode 100644 index 00000000000..9501748f273 --- /dev/null +++ b/build/pkgs/sagemath_environment/dependencies @@ -0,0 +1 @@ +FORCE $(PYTHON) | $(PYTHON_TOOLCHAIN) build diff --git a/build/pkgs/sagemath_environment/install-requires.txt b/build/pkgs/sagemath_environment/install-requires.txt index bea4334d7e4..2a9064d9451 100644 --- a/build/pkgs/sagemath_environment/install-requires.txt +++ b/build/pkgs/sagemath_environment/install-requires.txt @@ -1 +1 @@ -sagemath-environment == 9.6rc3.post2 +sagemath-environment ~= 9.6rc3 diff --git a/build/pkgs/sagemath_objects/dependencies b/build/pkgs/sagemath_objects/dependencies index d77d7c9ee02..83c0fc9dd8a 100644 --- a/build/pkgs/sagemath_objects/dependencies +++ b/build/pkgs/sagemath_objects/dependencies @@ -1,4 +1,3 @@ -FORCE $(PYTHON) cysignals gmpy2 ipython | $(PYTHON_TOOLCHAIN) sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK)), tox) +FORCE $(PYTHON) cysignals gmpy2 | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK)), tox sagemath_repl) # FORCE: Always run the spkg-install script -# ipython - for the doctester diff --git a/build/pkgs/sagemath_repl/dependencies b/build/pkgs/sagemath_repl/dependencies deleted file mode 120000 index 55c209e6418..00000000000 --- a/build/pkgs/sagemath_repl/dependencies +++ /dev/null @@ -1 +0,0 @@ -../sagemath_objects/dependencies \ No newline at end of file diff --git a/build/pkgs/sagemath_repl/dependencies b/build/pkgs/sagemath_repl/dependencies new file mode 100644 index 00000000000..ee9270d6271 --- /dev/null +++ b/build/pkgs/sagemath_repl/dependencies @@ -0,0 +1 @@ +FORCE $(PYTHON) sagemath_objects ipython | $(PYTHON_TOOLCHAIN) build $(and $(filter-out no,$(SAGE_CHECK)), tox) From 6bf9279e3e4a87f984f93c08fcaf4ec621e0e672 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 7 May 2022 09:47:33 -0700 Subject: [PATCH 081/742] WIP --- build/pkgs/sagemath_objects/spkg-install | 4 +++- pkgs/sagemath-categories/tox.ini | 21 ++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/build/pkgs/sagemath_objects/spkg-install b/build/pkgs/sagemath_objects/spkg-install index 5c2ab2350c4..00a5540ae2f 100755 --- a/build/pkgs/sagemath_objects/spkg-install +++ b/build/pkgs/sagemath_objects/spkg-install @@ -29,5 +29,7 @@ wheel=$(cd "$DIST_DIR" && sdh_store_wheel . && echo $wheel) ls -l "$wheel" if [ "$SAGE_CHECK" != no ]; then - tox -v -e sagepython-norequirements --installpkg "$wheel" + # tox 3.x does not handle extras when using --installpkg. https://github.com/tox-dev/tox/issues/1576 + # We use --force-dep instead to make sagemath-repl available + tox -r -v -e sagepython-norequirements-sagewheels-nopypi --installpkg $wheel --force-dep sagemath-repl fi diff --git a/pkgs/sagemath-categories/tox.ini b/pkgs/sagemath-categories/tox.ini index 66b8dd041b9..2d3f502613f 100644 --- a/pkgs/sagemath-categories/tox.ini +++ b/pkgs/sagemath-categories/tox.ini @@ -16,18 +16,29 @@ deps = extras = test +passenv = + # Variables set by .homebrew-build-env + CPATH + LIBRARY_PATH + PKG_CONFIG_PATH + # Parallel build + SAGE_NUM_THREADS + # SAGE_VENV only for finding the wheels + sagewheels: SAGE_VENV + # Location of the wheels + sagewheels: SAGE_SPKG_WHEELS + setenv = # Sage scripts such as sage-runtests like to use $HOME/.sage HOME={envdir} - -passenv = - SAGE_NUM_THREADS - SAGE_NUM_THREADS_PARALLEL + # We supply pip options by environment variables so that they + # apply both to the installation of the dependencies and of the package + sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + nopypi: PIP_NO_INDEX=true whitelist_externals = bash - commands = # Beware of the treacherous non-src layout. "./sage/" shadows the install sage package. {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); import sage.cpython.builtin_types, sage.cpython.cython_metaclass, sage.cpython.debug, sage.structure.all, sage.categories.all' From 0b4d1fd9f24725603e760354db275f2c14ebae8c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 7 May 2022 19:50:43 -0700 Subject: [PATCH 082/742] pkgs/sagemath-objects: Disable use of the Sage doctester --- build/pkgs/sagemath_objects/dependencies | 2 +- pkgs/sagemath-objects/setup.cfg.m4 | 4 +++- pkgs/sagemath-objects/tox.ini | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/build/pkgs/sagemath_objects/dependencies b/build/pkgs/sagemath_objects/dependencies index 83c0fc9dd8a..48ad049fa0c 100644 --- a/build/pkgs/sagemath_objects/dependencies +++ b/build/pkgs/sagemath_objects/dependencies @@ -1,3 +1,3 @@ -FORCE $(PYTHON) cysignals gmpy2 | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK)), tox sagemath_repl) +FORCE $(PYTHON) cysignals gmpy2 | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK)), tox) # FORCE: Always run the spkg-install script diff --git a/pkgs/sagemath-objects/setup.cfg.m4 b/pkgs/sagemath-objects/setup.cfg.m4 index 0b48f8038b5..25f60b69677 100644 --- a/pkgs/sagemath-objects/setup.cfg.m4 +++ b/pkgs/sagemath-objects/setup.cfg.m4 @@ -37,4 +37,6 @@ install_requires = | sed "2,\$s/^/ /;"')dnl [options.extras_require] -test = sagemath-repl +# Currently we do not use the sage doctester to test sagemath-objects, +# so we do not list sagemath-repl here. +test = diff --git a/pkgs/sagemath-objects/tox.ini b/pkgs/sagemath-objects/tox.ini index ad243c5e830..727254cf844 100644 --- a/pkgs/sagemath-objects/tox.ini +++ b/pkgs/sagemath-objects/tox.ini @@ -31,7 +31,7 @@ commands = {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); from sage.all__sagemath_objects import *' - bash -c 'cd bin && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_objects --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' + #bash -c 'cd bin && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_objects --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' [testenv:sagepython] passenv = From bbd9f057337eb6fdd70cc216e9c6821604e29a95 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 7 May 2022 19:51:48 -0700 Subject: [PATCH 083/742] build/pkgs/sagemath_objects/spkg-install: tox --force-dep does not work, remove --- build/pkgs/sagemath_objects/spkg-install | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build/pkgs/sagemath_objects/spkg-install b/build/pkgs/sagemath_objects/spkg-install index 00a5540ae2f..68a490cdc28 100755 --- a/build/pkgs/sagemath_objects/spkg-install +++ b/build/pkgs/sagemath_objects/spkg-install @@ -29,7 +29,5 @@ wheel=$(cd "$DIST_DIR" && sdh_store_wheel . && echo $wheel) ls -l "$wheel" if [ "$SAGE_CHECK" != no ]; then - # tox 3.x does not handle extras when using --installpkg. https://github.com/tox-dev/tox/issues/1576 - # We use --force-dep instead to make sagemath-repl available - tox -r -v -e sagepython-norequirements-sagewheels-nopypi --installpkg $wheel --force-dep sagemath-repl + tox -r -v -e sagepython-norequirements-sagewheels-nopypi --installpkg $wheel fi From f6a2ee2ff88ea773eba04196717b2f793c53e85b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 7 May 2022 19:52:34 -0700 Subject: [PATCH 084/742] pkgs/sagemath-*/tox.ini: Add sagepython-norequirements-sagewheels-nopypi --- pkgs/sagemath-categories/tox.ini | 2 ++ pkgs/sagemath-environment/tox.ini | 34 ++++++++++++++++++++++++------- pkgs/sagemath-objects/tox.ini | 22 ++++++++++++++++---- pkgs/sagemath-repl/tox.ini | 29 ++++++++++++++++++++++---- 4 files changed, 72 insertions(+), 15 deletions(-) diff --git a/pkgs/sagemath-categories/tox.ini b/pkgs/sagemath-categories/tox.ini index 2d3f502613f..9bb09d5822e 100644 --- a/pkgs/sagemath-categories/tox.ini +++ b/pkgs/sagemath-categories/tox.ini @@ -13,6 +13,8 @@ envlist = [testenv] deps = !norequirements: -rrequirements.txt + # tox 3.x does not handle extras when using --installpkg. https://github.com/tox-dev/tox/issues/1576 + sagemath-repl extras = test diff --git a/pkgs/sagemath-environment/tox.ini b/pkgs/sagemath-environment/tox.ini index f28e260b196..e926daf4052 100644 --- a/pkgs/sagemath-environment/tox.ini +++ b/pkgs/sagemath-environment/tox.ini @@ -7,22 +7,42 @@ # pkgs/sagemath-environment/.tox/python/bin/python # [tox] -isolated_build = True +envlist = + sagepython-norequirements [testenv] -deps = -rrequirements.txt +deps = + !norequirements: -rrequirements.txt + +passenv = + # Variables set by .homebrew-build-env + CPATH + LIBRARY_PATH + PKG_CONFIG_PATH + # Parallel build + SAGE_NUM_THREADS + # SAGE_VENV only for finding the wheels + sagewheels: SAGE_VENV + # Location of the wheels + sagewheels: SAGE_SPKG_WHEELS setenv = # Sage scripts such as sage-runtests like to use $HOME/.sage HOME={envdir} - -passenv = - SAGE_NUM_THREADS - SAGE_NUM_THREADS_PARALLEL + # We supply pip options by environment variables so that they + # apply both to the installation of the dependencies and of the package + sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + nopypi: PIP_NO_INDEX=true whitelist_externals = bash commands = # Beware of the treacherous non-src layout. "./sage/" shadows the installed sage package. - python -c 'import sys; "" in sys.path and sys.path.remove(""); from sage.features.all import all_features; print(sorted(all_features(), key=lambda x: x.name)); import sage.misc.package' + {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); from sage.features.all import all_features; print(sorted(all_features(), key=lambda x: x.name)); import sage.misc.package' + +[testenv:sagepython] +passenv = + SAGE_VENV + +basepython = {env:SAGE_VENV}/bin/python3 diff --git a/pkgs/sagemath-objects/tox.ini b/pkgs/sagemath-objects/tox.ini index 727254cf844..8630047dc83 100644 --- a/pkgs/sagemath-objects/tox.ini +++ b/pkgs/sagemath-objects/tox.ini @@ -14,13 +14,27 @@ envlist = deps = !norequirements: -rrequirements.txt +extras = test + +passenv = + # Variables set by .homebrew-build-env + CPATH + LIBRARY_PATH + PKG_CONFIG_PATH + # Parallel build + SAGE_NUM_THREADS + # SAGE_VENV only for finding the wheels + sagewheels: SAGE_VENV + # Location of the wheels + sagewheels: SAGE_SPKG_WHEELS + setenv = # Sage scripts such as sage-runtests like to use $HOME/.sage HOME={envdir} - -passenv = - SAGE_NUM_THREADS - SAGE_NUM_THREADS_PARALLEL + # We supply pip options by environment variables so that they + # apply both to the installation of the dependencies and of the package + sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + nopypi: PIP_NO_INDEX=true whitelist_externals = bash diff --git a/pkgs/sagemath-repl/tox.ini b/pkgs/sagemath-repl/tox.ini index 0405938001f..f81f72d8df9 100644 --- a/pkgs/sagemath-repl/tox.ini +++ b/pkgs/sagemath-repl/tox.ini @@ -7,18 +7,33 @@ # pkgs/sagemath-repl/.tox/python/bin/python # [tox] +envlist = + sagepython-norequirements + isolated_build = True [testenv] deps = -rrequirements.txt +passenv = + # Variables set by .homebrew-build-env + CPATH + LIBRARY_PATH + PKG_CONFIG_PATH + # Parallel build + SAGE_NUM_THREADS + # SAGE_VENV only for finding the wheels + sagewheels: SAGE_VENV + # Location of the wheels + sagewheels: SAGE_SPKG_WHEELS + setenv = # Sage scripts such as sage-runtests like to use $HOME/.sage HOME={envdir} - -passenv = - SAGE_NUM_THREADS - SAGE_NUM_THREADS_PARALLEL + # We supply pip options by environment variables so that they + # apply both to the installation of the dependencies and of the package + sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + nopypi: PIP_NO_INDEX=true whitelist_externals = bash @@ -28,3 +43,9 @@ commands = python -c 'import sys; "" in sys.path and sys.path.remove(""); import sage.repl.all; import sage.doctest.all' bash -c 'cd bin && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_repl --optional=sage $SAGE_SRC/sage/repl $SAGE_SRC/sage/doctest $SAGE_SRC/sage/misc/sage_input.py $SAGE_SRC/sage/misc/sage_eval.py || echo "(lots of doctest failures are expected)"' + +[testenv:sagepython] +passenv = + SAGE_VENV + +basepython = {env:SAGE_VENV}/bin/python3 From ffed24504c651ba645d7e02db81b859be11f8626 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 7 May 2022 21:58:23 -0700 Subject: [PATCH 085/742] build/pkgs/sagemath_objects/spkg-install: Remove workaround for missing ensurepip --- build/pkgs/sagemath_objects/spkg-install | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/build/pkgs/sagemath_objects/spkg-install b/build/pkgs/sagemath_objects/spkg-install index 68a490cdc28..b21c198671b 100755 --- a/build/pkgs/sagemath_objects/spkg-install +++ b/build/pkgs/sagemath_objects/spkg-install @@ -19,11 +19,7 @@ export PIP_FIND_LINKS="file://$SAGE_SPKG_WHEELS" # (Important because sagemath-objects uses MANIFEST.in for filtering.) # Do not install the wheel. DIST_DIR="$(mktemp -d)" -if ! python3 -m build --outdir "$DIST_DIR"/dist .; then - # This happens on Debian without python3-venv installed - "ensurepip" is missing - echo "Falling back to --no-isolation" - python3 -m build --no-isolation --outdir "$DIST_DIR"/dist . || sdh_die "Failure building sdist and wheel" -fi +python3 -m build --outdir "$DIST_DIR"/dist . || sdh_die "Failure building sdist and wheel" wheel=$(cd "$DIST_DIR" && sdh_store_wheel . && echo $wheel) ls -l "$wheel" From e3be906d84b88025c0f15bd4d1b7df6e811876d1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 7 May 2022 22:56:29 -0700 Subject: [PATCH 086/742] .github/workflows/build.yml: Install python3-venv --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4982cf61e25..bc69cfe12e7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,11 +22,11 @@ jobs: - name: Prepare id: prepare run: | + # Install test tools + apt-get install -y git python3-venv # Reuse built SAGE_LOCAL contained in the Docker image ./bootstrap ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv --enable-editable --enable-download-from-upstream-url - # Install test tools - apt-get install -y git - name: Build and test modularized distributions if: always() && steps.prepare.outcome == 'success' From 5f311f52c2baf028fd9782dc46d4fe659f2db9c8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 7 May 2022 23:14:53 -0700 Subject: [PATCH 087/742] build/pkgs/sagemath_*/dependencies: Fix SAGE_CHECK dependencies --- build/pkgs/sagemath_categories/dependencies | 2 +- build/pkgs/sagemath_environment/dependencies | 2 +- build/pkgs/sagemath_objects/dependencies | 2 +- build/pkgs/sagemath_repl/dependencies | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sagemath_categories/dependencies b/build/pkgs/sagemath_categories/dependencies index 3f72fc83c3a..5ca174c27cd 100644 --- a/build/pkgs/sagemath_categories/dependencies +++ b/build/pkgs/sagemath_categories/dependencies @@ -1 +1 @@ -FORCE $(PYTHON) cysignals gmpy2 sagemath_objects | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK)), tox sagemath_repl) +FORCE $(PYTHON) cysignals gmpy2 sagemath_objects | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK_sagemath_categories)), tox sagemath_repl) diff --git a/build/pkgs/sagemath_environment/dependencies b/build/pkgs/sagemath_environment/dependencies index 9501748f273..6acb9a872a4 100644 --- a/build/pkgs/sagemath_environment/dependencies +++ b/build/pkgs/sagemath_environment/dependencies @@ -1 +1 @@ -FORCE $(PYTHON) | $(PYTHON_TOOLCHAIN) build +FORCE $(PYTHON) | $(PYTHON_TOOLCHAIN) build $(and $(filter-out no,$(SAGE_CHECK_sagemath_environment)), tox) diff --git a/build/pkgs/sagemath_objects/dependencies b/build/pkgs/sagemath_objects/dependencies index 48ad049fa0c..d1ce1288973 100644 --- a/build/pkgs/sagemath_objects/dependencies +++ b/build/pkgs/sagemath_objects/dependencies @@ -1,3 +1,3 @@ -FORCE $(PYTHON) cysignals gmpy2 | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK)), tox) +FORCE $(PYTHON) cysignals gmpy2 | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK_sagemath_objects)), tox) # FORCE: Always run the spkg-install script diff --git a/build/pkgs/sagemath_repl/dependencies b/build/pkgs/sagemath_repl/dependencies index ee9270d6271..6321b39ed17 100644 --- a/build/pkgs/sagemath_repl/dependencies +++ b/build/pkgs/sagemath_repl/dependencies @@ -1 +1 @@ -FORCE $(PYTHON) sagemath_objects ipython | $(PYTHON_TOOLCHAIN) build $(and $(filter-out no,$(SAGE_CHECK)), tox) +FORCE $(PYTHON) sagemath_objects ipython | $(PYTHON_TOOLCHAIN) build $(and $(filter-out no,$(SAGE_CHECK_sagemath_repl)), tox) From c264e7ff3e9d2603690649632233458e6c6d774a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 7 May 2022 23:41:55 -0700 Subject: [PATCH 088/742] build/make/Makefile.in: Handle SAGE_CHECK... for script packages --- build/make/Makefile.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/make/Makefile.in b/build/make/Makefile.in index 6b168c12e1f..9ddd6d1005a 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -381,7 +381,7 @@ define SET_SAGE_CHECK $(eval SAGE_CHECK_$(1) := $(2)) endef # Set defaults -$(foreach pkgname, $(NORMAL_PACKAGES),\ +$(foreach pkgname, $(NORMAL_PACKAGES) $(SCRIPT_PACKAGES),\ $(eval $(call SET_SAGE_CHECK,$(pkgname),$(SAGE_CHECK)))) # Parsing the SAGE_CHECK_PACKAGES variable: @@ -411,7 +411,7 @@ $(foreach clause, $(SAGE_CHECK_PACKAGES_sep), \ $(eval $(call SET_SAGE_CHECK,$(subst ?,,$(clause)),warn)), \ $(eval $(call SET_SAGE_CHECK,$(clause),yes))))) debug-check: - @echo $(foreach pkgname, $(NORMAL_PACKAGES), SAGE_CHECK_$(pkgname) = $(SAGE_CHECK_$(pkgname))) + @echo $(foreach pkgname, $(NORMAL_PACKAGES) $(SCRIPT_PACKAGES), SAGE_CHECK_$(pkgname) = $(SAGE_CHECK_$(pkgname))) #============================================================================== @@ -623,7 +623,7 @@ $(1)-$(4)-no-deps: . '$$(SAGE_ROOT)/build/bin/sage-build-env' && \ SAGE_SPKG_WHEELS=$$($(4))/var/lib/sage/wheels \ SAGE_INST_LOCAL=$$($(4)) \ - sage-logger -p '$$(SAGE_ROOT)/build/pkgs/$(1)/spkg-install' '$$(SAGE_LOGS)/$(1)-$(2).log' && \ + sage-logger -p 'SAGE_CHECK=$$(SAGE_CHECK_$(1)) $$(SAGE_ROOT)/build/pkgs/$(1)/spkg-install' '$$(SAGE_LOGS)/$(1)-$(2).log' && \ touch "$$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2)"; \ else \ echo; \ From de18ba016a167ca0595baef9c8871a38f70deb74 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 8 May 2022 00:26:07 -0700 Subject: [PATCH 089/742] build/bin/sage-build-env[-config]: Do not override SAGE_EDITABLE if it is set already --- build/bin/sage-build-env | 4 ++++ build/bin/sage-build-env-config.in | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/build/bin/sage-build-env b/build/bin/sage-build-env index ddda5ce212d..ed999b703f0 100644 --- a/build/bin/sage-build-env +++ b/build/bin/sage-build-env @@ -27,6 +27,10 @@ if [ "x$SAGE_BUILD_ENV_SOURCED" = "x" ]; then if [ "x$SAGE_DEBUG" = "x" ]; then export SAGE_DEBUG="$CONFIGURED_SAGE_DEBUG" fi + # Likewise for SAGE_EDITABLE + if [ "x$SAGE_EDITABLE" = "x" ]; then + export SAGE_EDITABLE="$CONFIGURED_SAGE_EDITABLE" + fi # This is usually blank if the system GMP is used, or $SAGE_LOCAL otherwise if [ -n "$SAGE_GMP_PREFIX" ]; then diff --git a/build/bin/sage-build-env-config.in b/build/bin/sage-build-env-config.in index 92e7dadba06..58d6bd5e5d7 100644 --- a/build/bin/sage-build-env-config.in +++ b/build/bin/sage-build-env-config.in @@ -57,4 +57,4 @@ export SAGE_SUITESPARSE_PREFIX="@SAGE_SUITESPARSE_PREFIX@" export SAGE_CONFIGURE_FFLAS_FFPACK="@SAGE_CONFIGURE_FFLAS_FFPACK@" -export SAGE_EDITABLE="@SAGE_EDITABLE@" +export CONFIGURED_SAGE_EDITABLE="@SAGE_EDITABLE@" From 4d972a419bed3d7314822af02f6a846ca019ba26 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 8 May 2022 01:13:42 -0700 Subject: [PATCH 090/742] src/sage/misc/lazy_import.pyx: Do not fail if sage.features cannot be imported --- src/sage/misc/lazy_import.pyx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 5c43efa97ac..ed90cf9b3e7 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -68,7 +68,10 @@ from warnings import warn import inspect from . import sageinspect -from sage.features import FeatureNotPresentError +try: + from sage.features import FeatureNotPresentError +except ImportError: + FeatureNotPresentError = () cdef inline obj(x): if type(x) is LazyImport: @@ -252,6 +255,7 @@ cdef class LazyImport(object): self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name) except ImportError as e: if self._feature: + from sage.features import FeatureNotPresentError raise FeatureNotPresentError(self._feature, reason=f'Importing {self._name} failed: {e}') raise From 828e42b4a873861f3caf75e738efbf980450d5f2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 8 May 2022 05:30:15 -0700 Subject: [PATCH 091/742] build/pkgs/sagemath_repl/install-requires.txt: New --- build/pkgs/sagemath_repl/install-requires.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 build/pkgs/sagemath_repl/install-requires.txt diff --git a/build/pkgs/sagemath_repl/install-requires.txt b/build/pkgs/sagemath_repl/install-requires.txt new file mode 100644 index 00000000000..d81a6e1675a --- /dev/null +++ b/build/pkgs/sagemath_repl/install-requires.txt @@ -0,0 +1 @@ +sagemath-repl From 86d04c72607030fb483d594e8db2effdf0eeaf80 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 8 May 2022 05:34:44 -0700 Subject: [PATCH 092/742] build/pkgs/sagemath_*/dependencies: Remove FORCE --- build/pkgs/sagemath_categories/dependencies | 2 +- build/pkgs/sagemath_environment/dependencies | 2 +- build/pkgs/sagemath_objects/dependencies | 4 +--- build/pkgs/sagemath_repl/dependencies | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/build/pkgs/sagemath_categories/dependencies b/build/pkgs/sagemath_categories/dependencies index 5ca174c27cd..8084ffef958 100644 --- a/build/pkgs/sagemath_categories/dependencies +++ b/build/pkgs/sagemath_categories/dependencies @@ -1 +1 @@ -FORCE $(PYTHON) cysignals gmpy2 sagemath_objects | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK_sagemath_categories)), tox sagemath_repl) +$(PYTHON) cysignals gmpy2 sagemath_objects | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK_sagemath_categories)), tox sagemath_repl) diff --git a/build/pkgs/sagemath_environment/dependencies b/build/pkgs/sagemath_environment/dependencies index 6acb9a872a4..942ea0d61e3 100644 --- a/build/pkgs/sagemath_environment/dependencies +++ b/build/pkgs/sagemath_environment/dependencies @@ -1 +1 @@ -FORCE $(PYTHON) | $(PYTHON_TOOLCHAIN) build $(and $(filter-out no,$(SAGE_CHECK_sagemath_environment)), tox) +$(PYTHON) | $(PYTHON_TOOLCHAIN) build $(and $(filter-out no,$(SAGE_CHECK_sagemath_environment)), tox) diff --git a/build/pkgs/sagemath_objects/dependencies b/build/pkgs/sagemath_objects/dependencies index d1ce1288973..a6341a04e7e 100644 --- a/build/pkgs/sagemath_objects/dependencies +++ b/build/pkgs/sagemath_objects/dependencies @@ -1,3 +1 @@ -FORCE $(PYTHON) cysignals gmpy2 | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK_sagemath_objects)), tox) - -# FORCE: Always run the spkg-install script +$(PYTHON) cysignals gmpy2 | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK_sagemath_objects)), tox) diff --git a/build/pkgs/sagemath_repl/dependencies b/build/pkgs/sagemath_repl/dependencies index 6321b39ed17..fd34bf2ba44 100644 --- a/build/pkgs/sagemath_repl/dependencies +++ b/build/pkgs/sagemath_repl/dependencies @@ -1 +1 @@ -FORCE $(PYTHON) sagemath_objects ipython | $(PYTHON_TOOLCHAIN) build $(and $(filter-out no,$(SAGE_CHECK_sagemath_repl)), tox) +$(PYTHON) sagemath_objects ipython | $(PYTHON_TOOLCHAIN) build $(and $(filter-out no,$(SAGE_CHECK_sagemath_repl)), tox) From d35579ebbe88c4e6101f09c9fb77faf9463448d1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 12:19:37 -0700 Subject: [PATCH 093/742] src/doc/en/developer/packaging_sage_library.rst: Add sagemath-repl --- src/doc/en/developer/packaging_sage_library.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/en/developer/packaging_sage_library.rst b/src/doc/en/developer/packaging_sage_library.rst index 7b756aedcc2..079f6bf3de8 100644 --- a/src/doc/en/developer/packaging_sage_library.rst +++ b/src/doc/en/developer/packaging_sage_library.rst @@ -489,13 +489,13 @@ Hierarchy of distribution packages return edge(start, end, linestyle='dashed') g = Graphics() g += (node("sage_conf", (0.5,0)) + extras_require((0.5,0),(0.5,1))) - g += (node("sagemath-objects", (1.5,0)) + edge((1.5,0),(1.5,1))) + g += (node("sagemath-objects", (1.5,0)) + edge((1.5,0),(0.67,2)) + edge((1.5,0),(1.5,1))) g += (node("sagemath-environment", (0.5,1)) - + edge((0.5,1),(0,2)) + edge((0.5,1),(1,2)) + edge((0.5,1),(2,2))) + + edge((0.5,1),(0,2)) + edge((0.5,1),(0.67,2)) + edge((0.5,1),(1.33,2)) + edge((0.5,1),(2,2))) g += (node("sagemath-categories", (1.5,1)) + edge((1.5,1),(0,2)) + edge((1.5,1),(1,2)) + edge((1.5,1),(2,2))) - g += (node("sagemath-graphs", (0,2)) + node("sagemath-polyhedra", (1,2)) + node("sagemath-singular", (2,2)) + - edge((0,2),(0,3)) + edge((0,2),(1,3)) + edge((1,2),(1,3)) + edge((2,2),(2,3))) + g += (node("sagemath-graphs", (0,2)) + node("sagemath-repl", (0.67,2)) + node("sagemath-polyhedra", (1.33,2)) + node("sagemath-singular", (2,2)) + + edge((0,2),(0,3)) + edge((0,2),(1,3)) + edge((0.67,2),(1,3)) + edge((1.33,2),(1,3)) + edge((2,2),(2,3))) g += (node("sagemath-tdlib", (0,3)) + node("sagemath-standard-no-symbolics", (1,3)) + node("sagemath-symbolics", (2,3)) + edge((1,3),(1,4)) + edge((2,3),(1,4))) g += node("sagemath-standard", (1,4)) From ad92f89267e418b93fbb9ef4fb4b79fa36d0e7f4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 12:33:46 -0700 Subject: [PATCH 094/742] src/doc/en/developer/packaging_sage_library.rst: Adjust arrows --- src/doc/en/developer/packaging_sage_library.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/en/developer/packaging_sage_library.rst b/src/doc/en/developer/packaging_sage_library.rst index 079f6bf3de8..4bc9836ab64 100644 --- a/src/doc/en/developer/packaging_sage_library.rst +++ b/src/doc/en/developer/packaging_sage_library.rst @@ -489,15 +489,15 @@ Hierarchy of distribution packages return edge(start, end, linestyle='dashed') g = Graphics() g += (node("sage_conf", (0.5,0)) + extras_require((0.5,0),(0.5,1))) - g += (node("sagemath-objects", (1.5,0)) + edge((1.5,0),(0.67,2)) + edge((1.5,0),(1.5,1))) + g += (node("sagemath-objects", (1.5,0)) + edge((1.5,0),(0.75,2)) + edge((1.5,0),(1.5,1))) g += (node("sagemath-environment", (0.5,1)) - + edge((0.5,1),(0,2)) + edge((0.5,1),(0.67,2)) + edge((0.5,1),(1.33,2)) + edge((0.5,1),(2,2))) - g += (node("sagemath-categories", (1.5,1)) + edge((1.5,1),(0,2)) + - edge((1.5,1),(1,2)) + edge((1.5,1),(2,2))) + + edge((0.5,1),(0,2)) + edge((0.5,1),(0.6,2)) + edge((0.5,1),(1.25,2)) + edge((0.5,1),(1.8,2))) + g += (node("sagemath-categories", (1.5,1)) + + edge((1.5,1),(0.2,2)) + edge((1.5,1),(1.41,2)) + edge((1.5,1),(2,2))) g += (node("sagemath-graphs", (0,2)) + node("sagemath-repl", (0.67,2)) + node("sagemath-polyhedra", (1.33,2)) + node("sagemath-singular", (2,2)) + - edge((0,2),(0,3)) + edge((0,2),(1,3)) + edge((0.67,2),(1,3)) + edge((1.33,2),(1,3)) + edge((2,2),(2,3))) + edge((0,2),(0,3)) + edge((0,2),(0.75,3)) + edge((0.67,2),(1,3)) + edge((1.33,2),(1.25,3)) + edge((2,2),(2,3))) g += (node("sagemath-tdlib", (0,3)) + node("sagemath-standard-no-symbolics", (1,3)) + node("sagemath-symbolics", (2,3)) + - edge((1,3),(1,4)) + edge((2,3),(1,4))) + edge((1,3),(1,4)) + edge((1.8,3),(1.25,4))) g += node("sagemath-standard", (1,4)) sphinx_plot(g, figsize=(8, 4), axes=False) From 1d2bd0888c5a96e5bdc410788a62c53ac588b760 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 12:43:31 -0700 Subject: [PATCH 095/742] src/doc/en/developer/packaging_sage_library.rst: Put nodes on top of arrows --- .../en/developer/packaging_sage_library.rst | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/doc/en/developer/packaging_sage_library.rst b/src/doc/en/developer/packaging_sage_library.rst index 4bc9836ab64..0522454226e 100644 --- a/src/doc/en/developer/packaging_sage_library.rst +++ b/src/doc/en/developer/packaging_sage_library.rst @@ -484,20 +484,21 @@ Hierarchy of distribution packages def node(label, pos): return text(label, (3*pos[0],2*pos[1]), background_color='pink', color='black') def edge(start, end, **kwds): - return arrow((3*start[0],2*start[1]+.5),(3*end[0],2*end[1]-.5), arrowsize=2, **kwds) + return arrow((3*start[0],2*start[1]),(3*end[0],2*end[1]-.28), arrowsize=2, **kwds) def extras_require(start, end): return edge(start, end, linestyle='dashed') g = Graphics() - g += (node("sage_conf", (0.5,0)) + extras_require((0.5,0),(0.5,1))) - g += (node("sagemath-objects", (1.5,0)) + edge((1.5,0),(0.75,2)) + edge((1.5,0),(1.5,1))) - g += (node("sagemath-environment", (0.5,1)) - + edge((0.5,1),(0,2)) + edge((0.5,1),(0.6,2)) + edge((0.5,1),(1.25,2)) + edge((0.5,1),(1.8,2))) - g += (node("sagemath-categories", (1.5,1)) + - edge((1.5,1),(0.2,2)) + edge((1.5,1),(1.41,2)) + edge((1.5,1),(2,2))) - g += (node("sagemath-graphs", (0,2)) + node("sagemath-repl", (0.67,2)) + node("sagemath-polyhedra", (1.33,2)) + node("sagemath-singular", (2,2)) + - edge((0,2),(0,3)) + edge((0,2),(0.75,3)) + edge((0.67,2),(1,3)) + edge((1.33,2),(1.25,3)) + edge((2,2),(2,3))) - g += (node("sagemath-tdlib", (0,3)) + node("sagemath-standard-no-symbolics", (1,3)) + node("sagemath-symbolics", (2,3)) + - edge((1,3),(1,4)) + edge((1.8,3),(1.25,4))) + g += (extras_require((0.5,0),(0.5,1)) + node("sage_conf", (0.5,0))) + g += (edge((1.5,0),(0.75,2)) + edge((1.5,0),(1.5,1)) + + node("sagemath-objects", (1.5,0))) + g += (edge((0.5,1),(0,2)) + edge((0.5,1),(0.6,2)) + edge((0.5,1),(1.25,2)) + edge((0.5,1),(1.8,2)) + + node("sagemath-environment", (0.5,1))) + g += (edge((1.5,1),(0.2,2)) + edge((1.5,1),(1.41,2)) + edge((1.5,1),(2,2)) + + node("sagemath-categories", (1.5,1))) + g += (edge((0,2),(0,3)) + edge((0,2),(0.75,3)) + edge((0.67,2),(1,3)) + edge((1.33,2),(1.25,3)) + edge((2,2),(2,3)) + + node("sagemath-graphs", (0,2)) + node("sagemath-repl", (0.67,2)) + node("sagemath-polyhedra", (1.33,2)) + node("sagemath-singular", (2,2))) + g += (edge((1,3),(1,4)) + edge((2,3),(1.2,4)) + + node("sagemath-tdlib", (0,3)) + node("sagemath-standard-no-symbolics", (1,3)) + node("sagemath-symbolics", (2,3))) g += node("sagemath-standard", (1,4)) sphinx_plot(g, figsize=(8, 4), axes=False) From 85c7d38b2c47e60b07ce000c5840591537668951 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 13:05:10 -0700 Subject: [PATCH 096/742] src/doc/en/developer/packaging_sage_library.rst: Add links and short descriptions of the modularized distributions --- pkgs/sagemath-environment/README.rst | 2 +- .../en/developer/packaging_sage_library.rst | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/pkgs/sagemath-environment/README.rst b/pkgs/sagemath-environment/README.rst index f5c52660ca8..488b5534235 100644 --- a/pkgs/sagemath-environment/README.rst +++ b/pkgs/sagemath-environment/README.rst @@ -8,7 +8,7 @@ About SageMath "Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, and MATLAB" - Copyright (C) 2005-2020 The Sage Development Team + Copyright (C) 2005-2022 The Sage Development Team https://www.sagemath.org diff --git a/src/doc/en/developer/packaging_sage_library.rst b/src/doc/en/developer/packaging_sage_library.rst index 0522454226e..7ed73ed6fe4 100644 --- a/src/doc/en/developer/packaging_sage_library.rst +++ b/src/doc/en/developer/packaging_sage_library.rst @@ -505,6 +505,28 @@ Hierarchy of distribution packages Solid arrows indicate ``install_requires``, i.e., a declared runtime dependency. Dashed arrows indicate ``extras_require``, i.e., a declared optional runtime dependency. +Not shown in the diagram are build dependencies and optional dependencies for testing. + +- `sage_conf `_ is a configuration + module. It provides the configuration variable settings determined by the + ``configure`` script. + +- `sagemath-environment `_ + provides the connection to the system and software environment. It includes + :mod:`sage.env`, :mod:`sage.features`, :mod:`sage.misc.package_dir`, etc. + +- `sagemath-objects `_ + provides a small fundamental subset of the modules of the Sage library, + in particular all of :mod:`sage.structure`, a small portion of :mod:`sage.categories`, + and a portion of :mod:`sage.misc`. + +- `sagemath-categories `_ + provides a small subset of the modules of the Sage library, building upon sagemath-objects. + It provides all of :mod:`sage.categories` and a small portion of :mod:`sage.rings`. + +- `sagemath-repl `_ provides + the IPython kernel and Sage preparser (:mod:`sage.repl`), + the Sage doctester (:mod:`sage.doctest`), and some related modules from :mod:`sage.misc`. Testing distribution packages From e019add9a8540b8213dfc563e8e4bda04777282c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 13:13:51 -0700 Subject: [PATCH 097/742] pkgs/sagemath-environment/README.rst: Update --- pkgs/sagemath-environment/README.rst | 2 +- pkgs/sagemath-repl/README.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/sagemath-environment/README.rst b/pkgs/sagemath-environment/README.rst index 488b5534235..7c71698734a 100644 --- a/pkgs/sagemath-environment/README.rst +++ b/pkgs/sagemath-environment/README.rst @@ -20,4 +20,4 @@ The traditional and recommended way to install SageMath is from source via Sage- About this experimental pip-installable source distribution ----------------------------------------------------------- -This pip-installable source distribution `sagemath-environment` is an experimental distribution of a small part of the Sage Library. Use at your own risk. It provides a small, fundamental subset of the modules of the Sage library ("sagelib", `sagemath-standard`), providing the connection to the system and software environment. +This pip-installable source distribution `sagemath-environment` is an experimental distribution of a small part of the Sage Library. Use at your own risk. It provides a small, fundamental subset of the modules of the Sage library ("sagelib", `sagemath-standard`), providing the connection to the system and software environment. It also includes the `sage` script for launching the Sage REPL and accessing various developer tools (see `sage --help`). diff --git a/pkgs/sagemath-repl/README.rst b/pkgs/sagemath-repl/README.rst index c240fbc1bac..1e0af5c4e7e 100644 --- a/pkgs/sagemath-repl/README.rst +++ b/pkgs/sagemath-repl/README.rst @@ -8,7 +8,7 @@ About SageMath "Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, and MATLAB" - Copyright (C) 2005-2020 The Sage Development Team + Copyright (C) 2005-2022 The Sage Development Team https://www.sagemath.org From baef20627799f92bcc9dc7efe921a110361a5f0c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 17:43:55 -0700 Subject: [PATCH 098/742] pkgs/sagemath-{objects,categories}: Update dependencies --- pkgs/sagemath-categories/pyproject.toml.m4 | 15 ++++++++++++++- pkgs/sagemath-categories/setup.cfg.m4 | 6 +----- pkgs/sagemath-objects/setup.cfg.m4 | 3 --- 3 files changed, 15 insertions(+), 9 deletions(-) mode change 120000 => 100644 pkgs/sagemath-categories/pyproject.toml.m4 diff --git a/pkgs/sagemath-categories/pyproject.toml.m4 b/pkgs/sagemath-categories/pyproject.toml.m4 deleted file mode 120000 index b65c0df8a46..00000000000 --- a/pkgs/sagemath-categories/pyproject.toml.m4 +++ /dev/null @@ -1 +0,0 @@ -../sagemath-objects/pyproject.toml.m4 \ No newline at end of file diff --git a/pkgs/sagemath-categories/pyproject.toml.m4 b/pkgs/sagemath-categories/pyproject.toml.m4 new file mode 100644 index 00000000000..0afd7849de5 --- /dev/null +++ b/pkgs/sagemath-categories/pyproject.toml.m4 @@ -0,0 +1,14 @@ +[build-system] +# Minimum requirements for the build system to execute. +requires = [ + esyscmd(`sage-get-system-packages install-requires-toml \ + setuptools \ + wheel \ + sage_setup \ + sagemath_environment \ + sagemath_objects \ + cython \ + gmpy2 \ + cysignals \ + ')] +build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-categories/setup.cfg.m4 b/pkgs/sagemath-categories/setup.cfg.m4 index 4b2744c0de1..7f4ab27c56e 100644 --- a/pkgs/sagemath-categories/setup.cfg.m4 +++ b/pkgs/sagemath-categories/setup.cfg.m4 @@ -29,11 +29,7 @@ classifiers = python_requires = >=3.7, <3.11 install_requires = esyscmd(`sage-get-system-packages install-requires \ - cython \ - pkgconfig \ - ipython \ - gmpy2 \ - cysignals \ + sagemath_objects \ | sed "2,\$s/^/ /;"')dnl [options.extras_require] diff --git a/pkgs/sagemath-objects/setup.cfg.m4 b/pkgs/sagemath-objects/setup.cfg.m4 index 25f60b69677..1c801a6ca24 100644 --- a/pkgs/sagemath-objects/setup.cfg.m4 +++ b/pkgs/sagemath-objects/setup.cfg.m4 @@ -29,9 +29,6 @@ classifiers = python_requires = >=3.7, <3.11 install_requires = esyscmd(`sage-get-system-packages install-requires \ - cython \ - pkgconfig \ - ipython \ gmpy2 \ cysignals \ | sed "2,\$s/^/ /;"')dnl From 83e9c9acd59eecfd724ccc20afe55d9ae5a13f9e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 17:53:52 -0700 Subject: [PATCH 099/742] pkgs/sagemath-{objects,categories}/bin: Remove --- pkgs/sagemath-categories/bin | 1 - pkgs/sagemath-objects/bin/sage | 1 - pkgs/sagemath-objects/bin/sage-env | 1 - pkgs/sagemath-objects/bin/sage-eval | 1 - pkgs/sagemath-objects/bin/sage-fixdoctests | 1 - pkgs/sagemath-objects/bin/sage-ipython | 1 - pkgs/sagemath-objects/bin/sage-python | 1 - pkgs/sagemath-objects/bin/sage-run | 1 - pkgs/sagemath-objects/bin/sage-runtests | 1 - pkgs/sagemath-objects/bin/sage-venv-config | 1 - pkgs/sagemath-objects/bin/sage-version.sh | 1 - 11 files changed, 11 deletions(-) delete mode 120000 pkgs/sagemath-categories/bin delete mode 120000 pkgs/sagemath-objects/bin/sage delete mode 120000 pkgs/sagemath-objects/bin/sage-env delete mode 120000 pkgs/sagemath-objects/bin/sage-eval delete mode 120000 pkgs/sagemath-objects/bin/sage-fixdoctests delete mode 120000 pkgs/sagemath-objects/bin/sage-ipython delete mode 120000 pkgs/sagemath-objects/bin/sage-python delete mode 120000 pkgs/sagemath-objects/bin/sage-run delete mode 120000 pkgs/sagemath-objects/bin/sage-runtests delete mode 120000 pkgs/sagemath-objects/bin/sage-venv-config delete mode 120000 pkgs/sagemath-objects/bin/sage-version.sh diff --git a/pkgs/sagemath-categories/bin b/pkgs/sagemath-categories/bin deleted file mode 120000 index 1956438021b..00000000000 --- a/pkgs/sagemath-categories/bin +++ /dev/null @@ -1 +0,0 @@ -../sagemath-objects/bin \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage b/pkgs/sagemath-objects/bin/sage deleted file mode 120000 index 028392920ce..00000000000 --- a/pkgs/sagemath-objects/bin/sage +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-env b/pkgs/sagemath-objects/bin/sage-env deleted file mode 120000 index e35bf8a4000..00000000000 --- a/pkgs/sagemath-objects/bin/sage-env +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-env \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-eval b/pkgs/sagemath-objects/bin/sage-eval deleted file mode 120000 index ac096cd38f1..00000000000 --- a/pkgs/sagemath-objects/bin/sage-eval +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-eval \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-fixdoctests b/pkgs/sagemath-objects/bin/sage-fixdoctests deleted file mode 120000 index 3d394f77c44..00000000000 --- a/pkgs/sagemath-objects/bin/sage-fixdoctests +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-fixdoctests \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-ipython b/pkgs/sagemath-objects/bin/sage-ipython deleted file mode 120000 index 00b3d2b0c50..00000000000 --- a/pkgs/sagemath-objects/bin/sage-ipython +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-ipython \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-python b/pkgs/sagemath-objects/bin/sage-python deleted file mode 120000 index 26d8bde2c71..00000000000 --- a/pkgs/sagemath-objects/bin/sage-python +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-python \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-run b/pkgs/sagemath-objects/bin/sage-run deleted file mode 120000 index a2bce45f085..00000000000 --- a/pkgs/sagemath-objects/bin/sage-run +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-run \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-runtests b/pkgs/sagemath-objects/bin/sage-runtests deleted file mode 120000 index 8e3dbbaf100..00000000000 --- a/pkgs/sagemath-objects/bin/sage-runtests +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-runtests \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-venv-config b/pkgs/sagemath-objects/bin/sage-venv-config deleted file mode 120000 index d1e0d8ec19b..00000000000 --- a/pkgs/sagemath-objects/bin/sage-venv-config +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-venv-config \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-version.sh b/pkgs/sagemath-objects/bin/sage-version.sh deleted file mode 120000 index 46cfd0287a5..00000000000 --- a/pkgs/sagemath-objects/bin/sage-version.sh +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-version.sh \ No newline at end of file From f0a4b81b215c852bc2341be2802cfe987e103e92 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 19:45:22 -0700 Subject: [PATCH 100/742] pkgs/sagemath-categories/MANIFEST.in.m4: Remove duplication with sagemath-objects --- pkgs/sagemath-categories/MANIFEST.in.m4 | 32 ++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/pkgs/sagemath-categories/MANIFEST.in.m4 b/pkgs/sagemath-categories/MANIFEST.in.m4 index 3a9b1d9bff1..55c355aef41 100644 --- a/pkgs/sagemath-categories/MANIFEST.in.m4 +++ b/pkgs/sagemath-categories/MANIFEST.in.m4 @@ -1,12 +1,34 @@ dnl MANIFEST.in is generated from this file by SAGE_ROOT/bootstrap via m4. +prune sage -dnl Include all from sagemath-objects (via m4 include) -include(`../sagemath_objects/src/MANIFEST.in') - -# Extra in sagemath-categories: global-include all__sagemath_categories.py graft sage/categories +# Exclude what is already shipped in sagemath-objects +exclude sage/categories/action.* +exclude sage/categories/algebra_functor.* +exclude sage/categories/basic.* +exclude sage/categories/cartesian_product.* +exclude sage/categories/category*.* +exclude sage/categories/covariant_functorial_construction.* +exclude sage/categories/functor.* +exclude sage/categories/homset.* +exclude sage/categories/homsets.* +exclude sage/categories/map.* +exclude sage/categories/morphism.* +exclude sage/categories/isomorphic_objects.* +exclude sage/categories/objects.* +exclude sage/categories/primer.* +exclude sage/categories/pushout.* +exclude sage/categories/quotients.* +exclude sage/categories/realizations.* +exclude sage/categories/sets_cat.* +exclude sage/categories/sets_with_partial_maps.* +exclude sage/categories/subobjects.* +exclude sage/categories/subquotients.* +exclude sage/categories/with_realizations.* +# Exclude to make it a namespace package exclude sage/categories/__init__.py + include sage/misc/prandom.* # dep of sage/rings/ring include sage/rings/ideal.* include sage/rings/ring.* @@ -17,8 +39,6 @@ graft sage/typeset # dep of sage.categories.tensor global-exclude *.c global-exclude *.cpp -include sage/cpython/debugimpl.c -include sage/misc/inherit_comparison_impl.c global-exclude __pycache__ global-exclude *.py[co] From bcdaf8a6b57d462ef07b7bcb4c3ef0e472eed7f0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 19:45:50 -0700 Subject: [PATCH 101/742] pkgs/sagemath*/MANIFEST.in: Some global-excludes etc --- pkgs/sagemath-categories/MANIFEST.in.m4 | 4 ++++ pkgs/sagemath-objects/MANIFEST.in | 4 ++++ pkgs/sagemath-repl/MANIFEST.in | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/pkgs/sagemath-categories/MANIFEST.in.m4 b/pkgs/sagemath-categories/MANIFEST.in.m4 index 55c355aef41..6a8e262bce0 100644 --- a/pkgs/sagemath-categories/MANIFEST.in.m4 +++ b/pkgs/sagemath-categories/MANIFEST.in.m4 @@ -44,3 +44,7 @@ global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-objects/MANIFEST.in b/pkgs/sagemath-objects/MANIFEST.in index 5799c779057..433c5cdd9b5 100644 --- a/pkgs/sagemath-objects/MANIFEST.in +++ b/pkgs/sagemath-objects/MANIFEST.in @@ -91,3 +91,7 @@ global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-repl/MANIFEST.in b/pkgs/sagemath-repl/MANIFEST.in index 9bee69fd999..c54f63b15ee 100644 --- a/pkgs/sagemath-repl/MANIFEST.in +++ b/pkgs/sagemath-repl/MANIFEST.in @@ -11,4 +11,11 @@ include sage/misc/sage_eval.py include VERSION.txt +global-exclude __pycache__ global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist From 4e700bc3f749b96dffa718f30b7d088ebbd4e34a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 20:08:08 -0700 Subject: [PATCH 102/742] pkgs/sagemath-objects/setup.cfg.m4: Add *.h files explicitly as package_data --- pkgs/sagemath-objects/setup.cfg.m4 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pkgs/sagemath-objects/setup.cfg.m4 b/pkgs/sagemath-objects/setup.cfg.m4 index 1c801a6ca24..8d0d9ebfa62 100644 --- a/pkgs/sagemath-objects/setup.cfg.m4 +++ b/pkgs/sagemath-objects/setup.cfg.m4 @@ -37,3 +37,14 @@ install_requires = # Currently we do not use the sage doctester to test sagemath-objects, # so we do not list sagemath-repl here. test = + + +[options.package_data] +sage.cpython = + pyx_visit.h + string_impl.h + cython_metaclass.h + python_debug.h + +sage.rings = + integer_fake.h From 9f6799e0570843276fccc8fe52f709217688d70b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 20:49:55 -0700 Subject: [PATCH 103/742] pkgs/sagemath-categories/MANIFEST.in.m4: Include VERSION.txt --- pkgs/sagemath-categories/MANIFEST.in.m4 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/sagemath-categories/MANIFEST.in.m4 b/pkgs/sagemath-categories/MANIFEST.in.m4 index 6a8e262bce0..9e588428458 100644 --- a/pkgs/sagemath-categories/MANIFEST.in.m4 +++ b/pkgs/sagemath-categories/MANIFEST.in.m4 @@ -1,6 +1,8 @@ dnl MANIFEST.in is generated from this file by SAGE_ROOT/bootstrap via m4. prune sage +include VERSION.txt + global-include all__sagemath_categories.py graft sage/categories # Exclude what is already shipped in sagemath-objects From 1b584272f8430d1740c6ad924d6bcbd5c11af8b8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 21:22:01 -0700 Subject: [PATCH 104/742] pkgs/*/tox.ini: Use {tempdir} to avoid the non-src layout issues, not the now removed bin/ --- pkgs/sagemath-categories/tox.ini | 2 +- pkgs/sagemath-objects/tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/sagemath-categories/tox.ini b/pkgs/sagemath-categories/tox.ini index 9bb09d5822e..2b59a5ef9ef 100644 --- a/pkgs/sagemath-categories/tox.ini +++ b/pkgs/sagemath-categories/tox.ini @@ -48,7 +48,7 @@ commands = # Test that importing sage.categories.all initializes categories {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); from sage.categories.all import *; SimplicialComplexes(); FunctionFields()' - bash -c 'cd bin && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_categories --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' + bash -c 'cd {temp_dir} && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_categories --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' [testenv:sagepython] passenv = diff --git a/pkgs/sagemath-objects/tox.ini b/pkgs/sagemath-objects/tox.ini index 8630047dc83..96983056162 100644 --- a/pkgs/sagemath-objects/tox.ini +++ b/pkgs/sagemath-objects/tox.ini @@ -45,7 +45,7 @@ commands = {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); from sage.all__sagemath_objects import *' - #bash -c 'cd bin && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_objects --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' + #bash -c 'cd {temp_dir} && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_objects --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' [testenv:sagepython] passenv = From fc7427b8558d150bc53d5ccb6ae29a2b9fe084ca Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 21:48:02 -0700 Subject: [PATCH 105/742] pkgs/sagemath-{objects,categories}: Remove vendored sage_setup --- pkgs/sagemath-categories/sage_setup | 1 - pkgs/sagemath-objects/sage_setup | 1 - 2 files changed, 2 deletions(-) delete mode 120000 pkgs/sagemath-categories/sage_setup delete mode 120000 pkgs/sagemath-objects/sage_setup diff --git a/pkgs/sagemath-categories/sage_setup b/pkgs/sagemath-categories/sage_setup deleted file mode 120000 index 88b8133df49..00000000000 --- a/pkgs/sagemath-categories/sage_setup +++ /dev/null @@ -1 +0,0 @@ -../../src/sage_setup \ No newline at end of file diff --git a/pkgs/sagemath-objects/sage_setup b/pkgs/sagemath-objects/sage_setup deleted file mode 120000 index 88b8133df49..00000000000 --- a/pkgs/sagemath-objects/sage_setup +++ /dev/null @@ -1 +0,0 @@ -../../src/sage_setup \ No newline at end of file From e547f1d77bee2a9547b84a2df76b7ecdfc6bcfce Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 9 May 2022 21:55:48 -0700 Subject: [PATCH 106/742] pkgs/sagemath-objects/MANIFEST.in: Move sage.misc.randstate, .prandom here from sage-categories --- pkgs/sagemath-categories/MANIFEST.in.m4 | 1 - pkgs/sagemath-objects/MANIFEST.in | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkgs/sagemath-categories/MANIFEST.in.m4 b/pkgs/sagemath-categories/MANIFEST.in.m4 index 9e588428458..390c7e5759f 100644 --- a/pkgs/sagemath-categories/MANIFEST.in.m4 +++ b/pkgs/sagemath-categories/MANIFEST.in.m4 @@ -31,7 +31,6 @@ exclude sage/categories/with_realizations.* # Exclude to make it a namespace package exclude sage/categories/__init__.py -include sage/misc/prandom.* # dep of sage/rings/ring include sage/rings/ideal.* include sage/rings/ring.* graft sage/typeset # dep of sage.categories.tensor diff --git a/pkgs/sagemath-objects/MANIFEST.in b/pkgs/sagemath-objects/MANIFEST.in index 433c5cdd9b5..7c316790fa8 100644 --- a/pkgs/sagemath-objects/MANIFEST.in +++ b/pkgs/sagemath-objects/MANIFEST.in @@ -62,6 +62,9 @@ graft sage/docs # dep of sage/misc/lazy_import include sage/misc/persist.* include sage/misc/sage_unittest.* # dep of sage/misc/persist +include sage/misc/randstate.* # used in sage.doctest +include sage/misc/prandom.* # dep of sage/rings/ring + include sage/ext/stdsage.pxd include sage/sets/pythonclass.* include sage/arith/power.* @@ -78,7 +81,6 @@ graft sage/libs/gmp ## FIXME: Needed for doctesting -include sage/misc/randstate.* # used in sage.doctest include sage/misc/misc.* # walltime, cputime used in sage.doctest From 39cf556bf2a50492bf879e3ed9a6318f768de06a Mon Sep 17 00:00:00 2001 From: Sophia Elia Date: Fri, 20 May 2022 12:56:38 -0700 Subject: [PATCH 107/742] first changes. simplified rational example in fixed_subpolytopes. --- src/sage/geometry/polyhedron/base_QQ.py | 27 ++++++++++--------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/sage/geometry/polyhedron/base_QQ.py b/src/sage/geometry/polyhedron/base_QQ.py index 95c4f4e2b1a..af193c20934 100644 --- a/src/sage/geometry/polyhedron/base_QQ.py +++ b/src/sage/geometry/polyhedron/base_QQ.py @@ -860,22 +860,17 @@ def fixed_subpolytope(self, vertex_permutation): The next example shows that fixed_subpolytope works for rational polytopes:: - sage: P = Polyhedron(vertices = [[0,0],[3/2,0],[3/2,3/2],[0,3/2]], backend ='normaliz') # optional - pynormaliz - sage: P.vertices() # optional - pynormaliz - (A vertex at (0, 0), - A vertex at (0, 3/2), - A vertex at (3/2, 0), - A vertex at (3/2, 3/2)) - sage: G = P.restricted_automorphism_group(output = 'permutation');G # optional - pynormaliz - Permutation Group with generators [(1,2), (0,1)(2,3), (0,3)] - sage: len(G) # optional - pynormaliz - 8 - sage: G[2] # optional - pynormaliz - (0,1)(2,3) - sage: fixed_set = P.fixed_subpolytope(G[2]); fixed_set # optional - pynormaliz - A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices - sage: fixed_set.vertices() # optional - pynormaliz - (A vertex at (0, 3/4), A vertex at (3/2, 3/4)) + sage: P = Polyhedron(vertices=[[0],[1/2]], backend='normaliz') # optional - pynormaliz + sage: P.vertices() # optional - pynormaliz + (A vertex at (0), A vertex at (1/2)) + sage: G = P.restricted_automorphism_group(output='permutation');G # optional - pynormaliz + Permutation Group with generators [(0,1)] + sage: len(G) # optional - pynormaliz + 2 + sage: fixed_set = P.fixed_subpolytope(G.gens()[0]); fixed_set # optional - pynormaliz + A 0-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex + sage: fixed_set.vertices_list() # optional - pynormaliz + [[1/4]] """ if self.is_empty(): raise NotImplementedError('empty polyhedra are not supported') From b5402d06f7a69f2580d7120cb760d199648046d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 24 May 2022 09:54:02 +0200 Subject: [PATCH 108/742] fix typos in errors --- src/sage/monoids/free_monoid_element.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/monoids/free_monoid_element.py b/src/sage/monoids/free_monoid_element.py index c6b88e5c9f7..23a6cc709c7 100644 --- a/src/sage/monoids/free_monoid_element.py +++ b/src/sage/monoids/free_monoid_element.py @@ -48,7 +48,7 @@ class FreeMonoidElement(MonoidElement): sage: x**(-1) Traceback (most recent call last): ... - NotimplementedError + NotImplementedError """ def __init__(self, F, x, check=True): """ @@ -274,7 +274,7 @@ def __invert__(self): sage: x**(-1) Traceback (most recent call last): ... - NotimplementedError + NotImplementedError """ raise NotImplementedError From 9e8b89913fac5b6fde62cc3233be88559ed9d88d Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 25 May 2022 10:23:55 +0200 Subject: [PATCH 109/742] pyflakes: remove unused imports --- src/sage/combinat/k_regular_sequence.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 8b304c7c5b4..4fdf9300a73 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2596,7 +2596,6 @@ def shifted_inhomogeneities(self, recurrence_rules): """ from sage.arith.srange import srange from sage.functions.other import floor - from sage.modules.free_module_element import vector k = self.k M = recurrence_rules.M @@ -2644,7 +2643,6 @@ def v_eval_n(self, recurrence_rules, n): from itertools import chain from sage.arith.srange import srange - from sage.functions.other import floor from sage.modules.free_module_element import vector from sage.rings.integer_ring import ZZ @@ -2956,8 +2954,6 @@ def left(self, recurrence_rules): :meth:`kRegularSequenceSpace.from_recurrence` """ - from sage.arith.srange import srange - from sage.functions.other import floor from sage.modules.free_module_element import vector dim = recurrence_rules.dim From 3bcf07215a259dadc74eaa5c6949dc0e12c8400a Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Wed, 25 May 2022 10:37:44 +0200 Subject: [PATCH 110/742] fix some error from resolving the merge conflict --- src/sage/combinat/k_regular_sequence.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 4fdf9300a73..71c071db68f 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2914,7 +2914,9 @@ def matrix_row(row): J = J.stack(vector([int(j*k == i - rem) for j in srange(n1)])) Z = zero_matrix(coefficient_ring, n1, dim_without_corr) - return block_matrix([[mat, W], [Z, J]], subdivide=False) + mat = block_matrix([[mat, W], [Z, J]], subdivide=False) + + return mat def left(self, recurrence_rules): r""" From bc77bfd8f3d6cf4fcbf65beb5493e85944f3d7f0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 11:28:51 -0700 Subject: [PATCH 111/742] bootstrap-conda: Write an additional comment --- bootstrap-conda | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap-conda b/bootstrap-conda index 92aea50f939..7dd6b701128 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -59,6 +59,7 @@ for pkg in $BOOTSTRAP_PACKAGES; do echo " - $pkg" >> environment.yml done sed 's/name: sage-build/name: sage/' environment.yml > src/environment.yml +echo " # Additional packages providing all dependencies for the Sage library" >> src/environment.yml for pkg in $SAGELIB_SYSTEM_PACKAGES; do echo " - $pkg" >> src/environment.yml done From 4c2adf7e74f3783564bd88a78d786bc35c346932 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 11:59:08 -0700 Subject: [PATCH 112/742] bootstrap-conda: Rewrite using fewer redirects --- bootstrap-conda | 76 +++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/bootstrap-conda b/bootstrap-conda index 7dd6b701128..3cb23bfbac9 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -46,36 +46,50 @@ for PKG_BASE in $(sage-package list --has-file distros/conda.txt); do fi done echo >&2 $0:$LINENO: generate conda enviroment files -echo "name: sage-build" > environment.yml -echo "channels:" >> environment.yml -echo " - conda-forge" >> environment.yml -echo " - nodefaults" >> environment.yml -echo "dependencies:" >> environment.yml -for pkg in $SYSTEM_PACKAGES; do - echo " - $pkg" >> environment.yml -done -echo " # Packages needed for ./bootstrap" >> environment.yml -for pkg in $BOOTSTRAP_PACKAGES; do - echo " - $pkg" >> environment.yml -done -sed 's/name: sage-build/name: sage/' environment.yml > src/environment.yml -echo " # Additional packages providing all dependencies for the Sage library" >> src/environment.yml -for pkg in $SAGELIB_SYSTEM_PACKAGES; do - echo " - $pkg" >> src/environment.yml -done -sed 's/name: sage/name: sage-dev/' src/environment.yml > src/environment-dev.yml -echo " # Additional dev tools" >> src/environment-dev.yml -echo " - openssh" >> src/environment-dev.yml -echo " - pycodestyle" >> src/environment-dev.yml -echo " - pytest" >> src/environment-dev.yml +( + echo "name: sage-build" + echo "channels:" + echo " - conda-forge" + echo " - nodefaults" + echo "dependencies:" + for pkg in $SYSTEM_PACKAGES; do + echo " - $pkg" + done + echo " # Packages needed for ./bootstrap" + for pkg in $BOOTSTRAP_PACKAGES; do + echo " - $pkg" + done +) > environment.yml -cp environment.yml environment-optional.yml - echo " # optional packages" >> environment-optional.yml -for pkg in $OPTIONAL_SYSTEM_PACKAGES; do - echo " - $pkg" >> environment-optional.yml +( + sed 's/name: sage-build/name: sage/' environment.yml + echo " # Additional packages providing all dependencies for the Sage library" + for pkg in $SAGELIB_SYSTEM_PACKAGES; do + echo " - $pkg" done -cp src/environment.yml src/environment-optional.yml - echo " # optional packages" >> src/environment-optional.yml -for pkg in $OPTIONAL_SYSTEM_PACKAGES $SAGELIB_OPTIONAL_SYSTEM_PACKAGES; do - echo " - $pkg" >> src/environment-optional.yml -done +) > src/environment.yml + +DEVELOP_SYSTEM_PACKAGES="openssh pycodestyle pytest" +( + sed 's/name: sage/name: sage-dev/' src/environment.yml + echo " # Additional dev tools" + for pkg in $DEVELOP_SYSTEM_PACKAGES; do + echo " - $pkg" + done +) > src/environment-dev.yml + +( + cat environment.yml + echo " # optional packages" + for pkg in $OPTIONAL_SYSTEM_PACKAGES; do + echo " - $pkg" + done +) > environment-optional.yml + +( + cat src/environment.yml + echo " # optional packages" + for pkg in $OPTIONAL_SYSTEM_PACKAGES $SAGELIB_OPTIONAL_SYSTEM_PACKAGES; do + echo " - $pkg" + done +) > src/environment-optional.yml From ac2c48db84c1a59e333552e5abfcdc3229fb9084 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 16 May 2022 15:10:34 -0700 Subject: [PATCH 113/742] build/pkgs/git_trac_command: New --- build/pkgs/git_trac_command/SPKG.rst | 14 ++++++++++++++ build/pkgs/git_trac_command/requirements.txt | 1 + build/pkgs/git_trac_command/trees.txt | 1 + build/pkgs/git_trac_command/type | 1 + 4 files changed, 17 insertions(+) create mode 100644 build/pkgs/git_trac_command/SPKG.rst create mode 100644 build/pkgs/git_trac_command/requirements.txt create mode 100644 build/pkgs/git_trac_command/trees.txt create mode 100644 build/pkgs/git_trac_command/type diff --git a/build/pkgs/git_trac_command/SPKG.rst b/build/pkgs/git_trac_command/SPKG.rst new file mode 100644 index 00000000000..d8da01bd818 --- /dev/null +++ b/build/pkgs/git_trac_command/SPKG.rst @@ -0,0 +1,14 @@ +git_trac_command: Provides the subcommand "git trac" +==================================================== + +Description +----------- + +This module implements a subcommand ``git trac``. +See https://doc.sagemath.org/html/en/developer/git_trac.html + + +Upstream Contact +---------------- + +https://github.com/sagemath/git-trac-command diff --git a/build/pkgs/git_trac_command/requirements.txt b/build/pkgs/git_trac_command/requirements.txt new file mode 100644 index 00000000000..4f36b5eae53 --- /dev/null +++ b/build/pkgs/git_trac_command/requirements.txt @@ -0,0 +1 @@ +git+https://github.com/sagemath/git-trac-command diff --git a/build/pkgs/git_trac_command/trees.txt b/build/pkgs/git_trac_command/trees.txt new file mode 100644 index 00000000000..b268580307d --- /dev/null +++ b/build/pkgs/git_trac_command/trees.txt @@ -0,0 +1 @@ +# Users should install this manually in their environment. It should not be installed in SAGE_VENV diff --git a/build/pkgs/git_trac_command/type b/build/pkgs/git_trac_command/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/git_trac_command/type @@ -0,0 +1 @@ +optional From 4a0b6f47a798a00643f51827da229e913cd8680d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 16 May 2022 16:44:16 -0700 Subject: [PATCH 114/742] bootstrap-conda: Also generate pip: lines --- bootstrap-conda | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/bootstrap-conda b/bootstrap-conda index 3cb23bfbac9..260c8751312 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -93,3 +93,21 @@ DEVELOP_SYSTEM_PACKAGES="openssh pycodestyle pytest" echo " - $pkg" done ) > src/environment-optional.yml +( + echo >&4 " - pip:" + echo >&5 " - pip:" + for PKG_BASE in $(sage-package list --has-file requirements.txt --no-file distros/conda.txt); do + PKG_SCRIPTS=build/pkgs/$PKG_BASE + SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/requirements.txt + PKG_TYPE=$(cat $PKG_SCRIPTS/type) + if [ -n "PKG_SYSTEM_PACKAGES" ]; then + case "$PKG_BASE:$PKG_TYPE" in + $DEVELOP_SPKG_PATTERN:*) FD=4;; + *) FD=5;; + esac + ${STRIP_COMMENTS} $SYSTEM_PACKAGES_FILE | while read -r line; do + [ -n "$line" ] && echo >&$FD " - $line" + done + fi + done +) 4>> src/environment-dev.yml 5>> src/environment-optional.yml From ef01ba46603937842a3a6d984c3bf5baa8e8997d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 16 May 2022 17:08:24 -0700 Subject: [PATCH 115/742] bootstrap-conda: Do not include packages that declare SAGERUNTIME as a dependency --- bootstrap-conda | 4 +++- build/pkgs/sage_flatsurf/dependencies | 2 +- build/pkgs/slabbe/dependencies | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/bootstrap-conda b/bootstrap-conda index 260c8751312..3337bca58d3 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -100,7 +100,9 @@ DEVELOP_SYSTEM_PACKAGES="openssh pycodestyle pytest" PKG_SCRIPTS=build/pkgs/$PKG_BASE SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/requirements.txt PKG_TYPE=$(cat $PKG_SCRIPTS/type) - if [ -n "PKG_SYSTEM_PACKAGES" ]; then + if grep -q SAGERUNTIME $PKG_SCRIPTS/dependencies 2>/dev/null; then + : # cannot install packages that depend on the Sage library + else case "$PKG_BASE:$PKG_TYPE" in $DEVELOP_SPKG_PATTERN:*) FD=4;; *) FD=5;; diff --git a/build/pkgs/sage_flatsurf/dependencies b/build/pkgs/sage_flatsurf/dependencies index 951fd368f40..4c62fdd4fef 100644 --- a/build/pkgs/sage_flatsurf/dependencies +++ b/build/pkgs/sage_flatsurf/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) surface_dynamics +$(PYTHON) | $(PYTHON_TOOLCHAIN) surface_dynamics $(SAGERUNTIME) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/slabbe/dependencies b/build/pkgs/slabbe/dependencies index 0738c2d7777..05ba0d8954b 100644 --- a/build/pkgs/slabbe/dependencies +++ b/build/pkgs/slabbe/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) +$(PYTHON) | $(PYTHON_TOOLCHAIN) $(SAGERUNTIME) ---------- All lines of this file are ignored except the first. From 8e511f232585f98f18befe40945be71964b21d41 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 29 May 2022 15:43:21 -0700 Subject: [PATCH 116/742] bootstrap-conda: Hardcode git_trac_command as a devel package --- bootstrap-conda | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap-conda b/bootstrap-conda index 3337bca58d3..d8c76e3f1ee 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -8,6 +8,7 @@ export PATH="$(pwd)/build/bin:$PATH" STRIP_COMMENTS="sed s/#.*//;" RECOMMENDED_SPKG_PATTERN="@(_recommended$(for a in $(head -n 1 build/pkgs/_recommended/dependencies); do echo -n "|"$a; done))" +DEVELOP_SPKG_PATTERN="git_trac_command" BOOTSTRAP_PACKAGES=$(echo $(${STRIP_COMMENTS} build/pkgs/_bootstrap/distros/conda.txt)) SYSTEM_PACKAGES= From 491b5b439dad3c412fbdd27287b809f970e14eb9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 29 May 2022 22:16:59 -0700 Subject: [PATCH 117/742] pkgs/sagemath-*/VERSION.txt: Bump versions --- pkgs/sage-setup/VERSION.txt | 2 +- pkgs/sagemath-categories/VERSION.txt | 2 +- pkgs/sagemath-environment/VERSION.txt | 2 +- pkgs/sagemath-objects/VERSION.txt | 2 +- pkgs/sagemath-repl/VERSION.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index 24562793a28..325b114bff4 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -9.6.rc3 +9.7.beta2.dev0 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index 24562793a28..325b114bff4 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -9.6.rc3 +9.7.beta2.dev0 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index 27f66583915..325b114bff4 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -9.6.rc3.post2 +9.7.beta2.dev0 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index be2310e2ea1..325b114bff4 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -9.6.rc3.post4 +9.7.beta2.dev0 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index 24562793a28..325b114bff4 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -9.6.rc3 +9.7.beta2.dev0 From 9ea9712a8a0090fe91785c06c97ded902da569c1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 29 May 2022 22:17:22 -0700 Subject: [PATCH 118/742] Makefile (pypi-wheels): Add sagemath-environment, sagemath-repl explicitly --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d945f5fe5e1..25a56fa7383 100644 --- a/Makefile +++ b/Makefile @@ -94,7 +94,7 @@ pypi-sdists: sage_setup # Ensuring wheels are present, even for packages that may have been installed # as editable. Until we have better uninstallation of script packages, we # just remove the timestamps, which will lead to rebuilds of the packages. -PYPI_WHEEL_PACKAGES = sage_sws2rst sage_setup sagemath_objects sagemath_categories +PYPI_WHEEL_PACKAGES = sage_sws2rst sage_setup sagemath_environment sagemath_objects sagemath_repl sagemath_categories pypi-wheels: for a in $(PYPI_WHEEL_PACKAGES); do \ rm -f venv/var/lib/sage/installed/$$a-*; \ From 1954bab489b2d3a7c0615174514642263b6ef8b0 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Mon, 30 May 2022 15:43:54 +0200 Subject: [PATCH 119/742] use zero sequence instead of Seq3.some_elements()[0] in some test --- src/sage/combinat/k_regular_sequence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 71c071db68f..8cb5ad1393b 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2136,7 +2136,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) sage: Seq3 = kRegularSequenceSpace(3, ZZ) sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0, - ....: {0: Seq3.some_elements()[0]}) + ....: {0: Seq3.zero()}) Traceback (most recent call last): ... ValueError: Inhomogeneities {0: 3-regular sequence 0, 0, 0, 0, 0, 0, From 5695619b23e5e635824460a61bc65fb8d3e08799 Mon Sep 17 00:00:00 2001 From: Gabriel Lipnik Date: Mon, 30 May 2022 15:51:05 +0200 Subject: [PATCH 120/742] add subdivide=False two times --- src/sage/combinat/k_regular_sequence.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 8cb5ad1393b..5e58f3d64bd 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2893,11 +2893,12 @@ def matrix_row(row): mat_upper_right = Matrix([matrix_row(row) for row in srange(dim_without_corr)]) mat_inhomog = block_diagonal_matrix([S.mu[rem] - for S in shifted_inhomogeneities.values()]) + for S in shifted_inhomogeneities.values()], + subdivide=False) mat = block_matrix([[mat, mat_upper_right], [zero_matrix(mat_inhomog.nrows(), dim_without_corr), - mat_inhomog]]) + mat_inhomog]], subdivide=False) dim_without_corr = mat.ncols() dim = dim_without_corr + n1 From e2b9b0f8dfc51e6174c0743756470ba78b0c8db2 Mon Sep 17 00:00:00 2001 From: Sophia Elia Date: Mon, 30 May 2022 10:15:56 -0700 Subject: [PATCH 121/742] fixing doctests in baseQQ and backendnormaliz --- .../geometry/polyhedron/backend_normaliz.py | 23 ++++++++++--------- src/sage/geometry/polyhedron/base_QQ.py | 21 +++++++++-------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index e53560aa7ca..8af630eae3d 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -2296,10 +2296,9 @@ class functions. sage: P = Polyhedron(vertices=[[0,0,1],[0,0,-1],[1,0,1],[-1,0,-1],[0,1,1], # optional - pynormaliz ....: [0,-1,-1],[1,1,1],[-1,-1,-1]],backend='normaliz') # optional - pynormaliz sage: K = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: G = K.subgroup(gens = [K[6]]); G # optional - pynormaliz - Subgroup generated by [(0,2)(1,3)(4,6)(5,7)] of (Permutation Group with generators [(2,4)(3,5), (1,2)(5,6), (0,1)(2,3)(4,5)(6,7), (0,7)(1,3)(2,5)(4,6)]) + sage: G = K.subgroup(gens = [K([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz sage: conj_reps = G.conjugacy_classes_representatives() # optional - pynormaliz - sage: Dict = P.permutations_to_matrices(conj_reps, acting_group = G) # optional - pynormaliz + sage: Dict = P.permutations_to_matrices(conj_reps, acting_group = G) # optional - pynormaliz sage: list(Dict.keys())[0] # optional - pynormaliz (0,2)(1,3)(4,6)(5,7) sage: list(Dict.values())[0] # optional - pynormaliz @@ -2503,13 +2502,15 @@ class functions of the acting group. A character `\rho` is effective if The `H^*` series of the two-dimensional permutahedron under the action of the symmetric group is effective:: - sage: p2 = polytopes.permutahedron(3, backend = 'normaliz') # optional - pynormaliz - sage: G = p2.restricted_automorphism_group(output='permutation') # optional - pynormaliz - sage: H = G.subgroup(gens=[G.gens()[1],G.gens()[2]]) # optional - pynormaliz - sage: H.order() # optional - pynormaliz - 6 - sage: [Hstar, Hlin] = [p2.Hstar_function(H), p2.Hstar_function(H, output = 'Hstar_as_lin_comb')] # optional - pynormaliz - sage: p2._is_effective_normaliz(Hstar,Hlin) # optional - pynormaliz + sage: p3 = polytopes.permutahedron(3, backend = 'normaliz') # optional - pynormaliz + sage: G = p3.restricted_automorphism_group(output='permutation') # optional - pynormaliz + sage: reflection12 = G([(0,2),(1,4),(3,5)]) # optional - pynormaliz + sage: reflection23 = G([(0,1),(2,3),(4,5)]) # optional - pynormaliz + sage: S3 = G.subgroup(gens=[reflection12, reflection23]) # optional - pynormaliz + sage: S3.is_isomorphic(SymmetricGroup(3)) # optional - pynormaliz + True + sage: [Hstar, Hlin] = [p3.Hstar_function(S3), p3.Hstar_function(S3, output = 'Hstar_as_lin_comb')] # optional - pynormaliz + sage: p3._is_effective_normaliz(Hstar,Hlin) # optional - pynormaliz True If the `H^*`-series is not polynomial, then it is not effective:: @@ -2517,7 +2518,7 @@ class functions of the acting group. A character `\rho` is effective if sage: P = Polyhedron(vertices=[[0,0,1],[0,0,-1],[1,0,1],[-1,0,-1],[0,1,1], # optional - pynormaliz ....: [0,-1,-1],[1,1,1],[-1,-1,-1]],backend='normaliz') # optional - pynormaliz sage: G = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: H = G.subgroup(gens = [G[6]]) # optional - pynormaliz + sage: H = G.subgroup(gens = [G([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz sage: Hstar = P.Hstar_function(H); Hstar # optional - pynormaliz (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) sage: Hstar_lin = P.Hstar_function(H, output = 'Hstar_as_lin_comb') # optional - pynormaliz diff --git a/src/sage/geometry/polyhedron/base_QQ.py b/src/sage/geometry/polyhedron/base_QQ.py index af193c20934..71076224a1f 100644 --- a/src/sage/geometry/polyhedron/base_QQ.py +++ b/src/sage/geometry/polyhedron/base_QQ.py @@ -1041,8 +1041,7 @@ class functions. sage: P = Polyhedron(vertices=[[0,0,1],[0,0,-1],[1,0,1],[-1,0,-1],[0,1,1], # optional - pynormaliz ....: [0,-1,-1],[1,1,1],[-1,-1,-1]],backend='normaliz') # optional - pynormaliz sage: K = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: G = K.subgroup(gens = [K[6]]); G # optional - pynormaliz - Subgroup generated by [(0,2)(1,3)(4,6)(5,7)] of (Permutation Group with generators [(2,4)(3,5), (1,2)(5,6), (0,1)(2,3)(4,5)(6,7), (0,7)(1,3)(2,5)(4,6)]) + sage: G = K.subgroup(gens = [K([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz sage: conj_reps = G.conjugacy_classes_representatives() # optional - pynormaliz sage: Dict = P.permutations_to_matrices(conj_reps, acting_group = G) # optional - pynormaliz sage: list(Dict.keys())[0] # optional - pynormaliz @@ -1161,13 +1160,15 @@ class functions of the acting group. A character `\rho` is effective if The `H^*` series of the two-dimensional permutahedron under the action of the symmetric group is effective:: - sage: p2 = polytopes.permutahedron(3, backend = 'normaliz') # optional - pynormaliz - sage: G = p2.restricted_automorphism_group(output='permutation') # optional - pynormaliz - sage: H = G.subgroup(gens=[G.gens()[1],G.gens()[2]]) # optional - pynormaliz - sage: H.order() # optional - pynormaliz - 6 - sage: [Hstar, Hlin] = [p2.Hstar_function(H), p2.Hstar_function(H, output = 'Hstar_as_lin_comb')] # optional - pynormaliz - sage: p2.is_effective(Hstar,Hlin) # optional - pynormaliz + sage: p3 = polytopes.permutahedron(3, backend = 'normaliz') # optional - pynormaliz + sage: G = p3.restricted_automorphism_group(output='permutation') # optional - pynormaliz + sage: reflection12 = G([(0,2),(1,4),(3,5)]) # optional - pynormaliz + sage: reflection23 = G([(0,1),(2,3),(4,5)]) # optional - pynormaliz + sage: S3 = G.subgroup(gens=[reflection12, reflection23]) # optional - pynormaliz + sage: S3.is_isomorphic(SymmetricGroup(3)) # optional - pynormaliz + True + sage: [Hstar, Hlin] = [p3.Hstar_function(S3), p3.Hstar_function(S3, output = 'Hstar_as_lin_comb')] # optional - pynormaliz + sage: p3.is_effective(Hstar,Hlin) # optional - pynormaliz True If the `H^*`-series is not polynomial, then it is not effective:: @@ -1175,7 +1176,7 @@ class functions of the acting group. A character `\rho` is effective if sage: P = Polyhedron(vertices=[[0,0,1],[0,0,-1],[1,0,1],[-1,0,-1],[0,1,1], # optional - pynormaliz ....: [0,-1,-1],[1,1,1],[-1,-1,-1]],backend='normaliz') # optional - pynormaliz sage: G = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: H = G.subgroup(gens = [G[6]]) # optional - pynormaliz + sage: H = G.subgroup(gens = [G([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz sage: Hstar = P.Hstar_function(H); Hstar # optional - pynormaliz (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) sage: Hstar_lin = P.Hstar_function(H, output = 'Hstar_as_lin_comb') # optional - pynormaliz From 938a6b4a32e9ca4a3c5a83e30498a2f5ee283064 Mon Sep 17 00:00:00 2001 From: Sophia Elia Date: Mon, 30 May 2022 12:33:57 -0700 Subject: [PATCH 122/742] rewrote tests that were dependent on ording of conjugacy classes representatives --- .../geometry/polyhedron/backend_normaliz.py | 5 ++-- src/sage/geometry/polyhedron/base.py | 12 ++++---- src/sage/geometry/polyhedron/base_QQ.py | 29 +++++++------------ 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 8af630eae3d..c9b17470d86 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -2275,8 +2275,9 @@ class functions. sage: S = polytopes.simplex(3, backend = 'normaliz'); S # optional - pynormaliz A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices - sage: G = S.restricted_automorphism_group(output = 'permutation'); G # optional - pynormaliz - Permutation Group with generators [(2,3), (1,2), (0,1)] + sage: G = S.restricted_automorphism_group(output = 'permutation'); # optional - pynormaliz + sage: G.is_isomorphic(SymmetricGroup(4)) # optional - pynormaliz + True sage: len(G) # optional - pynormaliz 24 sage: Hstar = S._Hstar_function_normaliz(G); Hstar # optional - pynormaliz diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 338c9ca0700..9b4692edf44 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -990,11 +990,12 @@ def permutations_to_matrices(self, conj_class_reps, acting_group=None, additiona sage: aut_square = square.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz sage: conj_reps = aut_square.conjugacy_classes_representatives() # optional - pynormaliz sage: gens_dict = square.permutations_to_matrices(conj_reps); # optional - pynormaliz - sage: conj_reps[1],gens_dict[conj_reps[1]] # optional - pynormaliz + sage: rotation_180 = aut_square([(0,3),(1,2)]) # optional - pynormaliz + sage: rotation_180,gens_dict[rotation_180] # optional - pynormaliz ( - [0 1 0] - [1 0 0] - (1,2), [0 0 1] + [-1 0 0] + [ 0 -1 0] + (0,3)(1,2), [ 0 0 1] ) This example tests the functionality for additional elements:: @@ -1002,8 +1003,7 @@ def permutations_to_matrices(self, conj_class_reps, acting_group=None, additiona sage: C = polytopes.cross_polytope(2) sage: G = C.restricted_automorphism_group(output = 'permutation') sage: conj_reps = G.conjugacy_classes_representatives() - sage: add_elt = G[6]; add_elt - (0,2,3,1) + sage: add_elt = G([(0,2,3,1)]) sage: dict = C.permutations_to_matrices(conj_reps,additional_elts = [add_elt]) sage: dict[add_elt] [ 0 1 0] diff --git a/src/sage/geometry/polyhedron/base_QQ.py b/src/sage/geometry/polyhedron/base_QQ.py index 71076224a1f..0efcb15f1a2 100644 --- a/src/sage/geometry/polyhedron/base_QQ.py +++ b/src/sage/geometry/polyhedron/base_QQ.py @@ -846,13 +846,9 @@ def fixed_subpolytope(self, vertex_permutation): You can obtain non-trivial examples:: - sage: fsp1 = Cube.fixed_subpolytope(reprs[8]);fsp1 # optional - pynormaliz - A 0-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex - sage: fsp1.vertices() # optional - pynormaliz - (A vertex at (0, 0, 0),) - sage: fsp2 = Cube.fixed_subpolytope(reprs[3]);fsp2 # optional - pynormaliz + sage: fsp = Cube.fixed_subpolytope(AG([(0,1),(2,3),(4,5),(6,7)]));fsp # optional - pynormaliz A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices - sage: fsp2.vertices() # optional - pynormaliz + sage: fsp.vertices() # optional - pynormaliz (A vertex at (-1, -1, 0), A vertex at (-1, 1, 0), A vertex at (1, -1, 0), @@ -938,14 +934,10 @@ def fixed_subpolytopes(self, conj_class_reps): sage: aut_p = p.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz sage: aut_p.order() # optional - pynormaliz 8 - sage: conj_list = aut_p.conjugacy_classes_representatives(); conj_list # optional - pynormaliz - [(), (1,2), (0,1)(2,3), (0,1,3,2), (0,3)(1,2)] - sage: p.fixed_subpolytopes(conj_list) # optional - pynormaliz - {(): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices, - (1,2): A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices, - (0,1)(2,3): A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices, - (0,1,3,2): A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, - (0,3)(1,2): A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex} + sage: conj_list = aut_p.conjugacy_classes_representatives(); # optional - pynormaliz + sage: fixedpolytopes_dictionary = p.fixed_subpolytopes(conj_list) # optional - pynormaliz + sage: fixedpolytopes_dictionary[aut_p([(0,3),(1,2)])] # optional - pynormaliz + A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex TESTS:: @@ -1020,10 +1012,9 @@ class functions. sage: S = polytopes.simplex(3, backend = 'normaliz'); S # optional - pynormaliz A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices - sage: G = S.restricted_automorphism_group(output = 'permutation'); G # optional - pynormaliz - Permutation Group with generators [(2,3), (1,2), (0,1)] - sage: len(G) # optional - pynormaliz - 24 + sage: G = S.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz + sage: G.is_isomorphic(SymmetricGroup(4)) # optional - pynormaliz + True sage: Hstar = S._Hstar_function_normaliz(G); Hstar # optional - pynormaliz chi_4 sage: G.character_table() # optional - pynormaliz @@ -1043,7 +1034,7 @@ class functions. sage: K = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz sage: G = K.subgroup(gens = [K([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz sage: conj_reps = G.conjugacy_classes_representatives() # optional - pynormaliz - sage: Dict = P.permutations_to_matrices(conj_reps, acting_group = G) # optional - pynormaliz + sage: Dict = P.permutations_to_matrices(conj_reps, acting_group = G) # optional - pynormaliz sage: list(Dict.keys())[0] # optional - pynormaliz (0,2)(1,3)(4,6)(5,7) sage: list(Dict.values())[0] # optional - pynormaliz From 5217fb665c98849c8c63de009ae4b2958f1173d8 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Thu, 16 Jun 2022 11:03:19 +0200 Subject: [PATCH 123/742] reduced characteristic polynomial --- .../skew_polynomial_finite_order.pxd | 1 + .../skew_polynomial_finite_order.pyx | 96 +++++++++++++++++-- 2 files changed, 90 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd b/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd index ab22926414f..438773a39ef 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd +++ b/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd @@ -2,6 +2,7 @@ from sage.rings.polynomial.skew_polynomial_element cimport SkewPolynomial_generi cdef class SkewPolynomial_finite_order_dense (SkewPolynomial_generic_dense): cdef _norm + cdef _charpoly cdef _optbound cdef _matphir_c(self) diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx index e61f20e17f3..90f8ab9324a 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx @@ -71,6 +71,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): """ SkewPolynomial_generic_dense.__init__ (self, parent, x, check, construct, **kwds) self._norm = None + self._charpoly = None self._optbound = None @@ -130,10 +131,6 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): Return the matrix of the multiplication by ``self`` on `K[X,\sigma]` considered as a free module over `K[X^r]` (here `r` is the order of `\sigma`). - - .. WARNING:: - - Does not work if self is not monic. """ from sage.matrix.constructor import matrix cdef Py_ssize_t i, j, deb, k, r = self.parent()._order @@ -144,15 +141,15 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): cdef Polk = PolynomialRing (base_ring, 'xr') cdef list M = [ ] cdef list l = self.list() - for j from 0 <= j < r: - for i from 0 <= i < r: + for j in range(r): + for i in range(r): if i < j: pol = [ zero ] deb = i-j+r else: pol = [ ] deb = i-j - for k from deb <= k <= d by r: + for k in range(deb, d+1, r): pol.append(l[k]) M.append(Polk(pol)) for i from 0 <= i <= d: @@ -213,6 +210,10 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): sage: b = S.random_element(degree=7) sage: a.reduced_trace() + b.reduced_trace() == (a+b).reduced_trace() True + + .. SEEALSO:: + + :meth:`reduced_norm', :meth:`reduced_charpoly' """ order = self.parent()._order twisting_morphism = self.parent().twisting_morphism() @@ -312,6 +313,10 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): polynomial of the left multiplication by `X` on the quotient `K[X,\sigma] / K[X,\sigma] P` (which is a `K`-vector space of dimension `d`). + + .. SEEALSO:: + + :meth:`reduced_trace', :meth:`reduced_charpoly' """ if self._norm is None: if self.is_zero(): @@ -335,6 +340,83 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): center = self.parent().center(name=var) return center(self._norm) + def reduced_charpoly(self, var=None): + r""" + Return the reduced characteristic of this skew polynomial. + + INPUT: + + - ``var`` -- a string, a pair of strings or ``None`` + (default: ``None``); the variable names used for the + characteristic polynomial and the center + + .. NOTE:: + + The result is cached. + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['u', Frob] + sage: a = u^3 + (2*t^2 + 3)*u^2 + (4*t^2 + t + 4)*u + 2*t^2 + 2 + sage: chi = a.reduced_charpoly() + sage: chi + x^3 + (2*z + 1)*x^2 + (3*z^2 + 4*z)*x + 4*z^3 + z^2 + 1 + + The reduced characteristic polynomial has coefficients in the center + of `S`, which is itself a univariate polynomial ring in the variable + `z = u^3` over `\GF{5}`. Hence it appears as a bivariate polynomial. + + sage: chi.parent() + Univariate Polynomial Ring in x over Univariate Polynomial Ring in z over Finite Field of size 5 + + The constant coefficient of the reduced characteristic polynomial is + the reduced norm, up to a sign:: + + sage: chi[0] == -a.reduced_norm() + True + + Its coefficient of degree `\deg(a) - 1` is the opposite of the reduced + trace:: + + sage: chi[2] == -a.reduced_trace() + True + + By default, the name of the variable of the reduced characteristic + polynomial is ``x`` and the name of central variable is usually ``z`` + (see :meth:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_finite_order.center` + for more details about this). + The user can speciify a different names if desired:: + + sage: a.reduced_charpoly(var='T') # variable name for the caracteristic polynomial + T^3 + (2*z + 1)*T^2 + (3*z^2 + 4*z)*T + 4*z^3 + z^2 + 1 + + sage: a.reduced_charpoly(var=('T', 'c')) + T^3 + (2*c + 1)*T^2 + (3*c^2 + 4*c)*T + 4*c^3 + c^2 + 1 + + .. SEEALSO:: + + :meth:`reduced_trace', :meth:`reduced_norm' + """ + if self._charpoly is None: + parent = self._parent + section = parent._embed_constants.section() + M = self._matmul_c() + chi = M.charpoly() + self._charpoly = [ tuple(c.list()) for c in chi.list() ] + if self._norm is not None: + self._norm = self._charpoly[-1] + varcenter = None + if var is None: + varcharpoly = 'x' + elif isinstance(var, (tuple, list)) and len(var) == 2: + (varcharpoly, varcenter) = var + else: + varcharpoly = var + center = self.parent().center(name=varcenter) + coeffs = [ center(c) for c in self._charpoly ] + return PolynomialRing(center, name=varcharpoly)(coeffs) def is_central(self): r""" From 849b203a191760859d4a07ae1fd6d2f4ef2811dc Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Fri, 17 Jun 2022 06:58:37 +0200 Subject: [PATCH 124/742] small fixes --- .../skew_polynomial_finite_order.pyx | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx index 90f8ab9324a..b21e2eb37db 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx @@ -88,7 +88,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): cdef k = parent.base_ring() cdef RingElement zero = k(0) cdef RingElement one = k(1) - cdef list line, phir = [ ] + cdef list line, phir = [] if r < d: for i from 0 <= i < d-r: line = d * [zero] @@ -139,17 +139,17 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): cdef RingElement minusone = base_ring(-1) cdef RingElement zero = base_ring(0) cdef Polk = PolynomialRing (base_ring, 'xr') - cdef list M = [ ] + cdef list M = [] cdef list l = self.list() for j in range(r): for i in range(r): if i < j: - pol = [ zero ] + pol = [zero] deb = i-j+r else: - pol = [ ] + pol = [] deb = i-j - for k in range(deb, d+1, r): + for k from deb <= k <= d by r: pol.append(l[k]) M.append(Polk(pol)) for i from 0 <= i <= d: @@ -213,11 +213,11 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): .. SEEALSO:: - :meth:`reduced_norm', :meth:`reduced_charpoly' + :meth:`reduced_norm`, :meth:`reduced_charpoly` """ order = self.parent()._order twisting_morphism = self.parent().twisting_morphism() - coeffs = [ ] + coeffs = [] for i in range(0, self.degree()+1, order): tr = c = self._coeffs[i] for _ in range(order-1): @@ -316,7 +316,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): .. SEEALSO:: - :meth:`reduced_trace', :meth:`reduced_charpoly' + :meth:`reduced_trace`, :meth:`reduced_charpoly` """ if self._norm is None: if self.is_zero(): @@ -342,7 +342,8 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): def reduced_charpoly(self, var=None): r""" - Return the reduced characteristic of this skew polynomial. + Return the reduced characteristic polynomial of this + skew polynomial. INPUT: @@ -387,7 +388,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): polynomial is ``x`` and the name of central variable is usually ``z`` (see :meth:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_finite_order.center` for more details about this). - The user can speciify a different names if desired:: + The user can speciify different names if desired:: sage: a.reduced_charpoly(var='T') # variable name for the caracteristic polynomial T^3 + (2*z + 1)*T^2 + (3*z^2 + 4*z)*T + 4*z^3 + z^2 + 1 @@ -397,14 +398,14 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): .. SEEALSO:: - :meth:`reduced_trace', :meth:`reduced_norm' + :meth:`reduced_trace`, :meth:`reduced_norm` """ if self._charpoly is None: parent = self._parent section = parent._embed_constants.section() M = self._matmul_c() chi = M.charpoly() - self._charpoly = [ tuple(c.list()) for c in chi.list() ] + self._charpoly = [tuple(c.list()) for c in chi.list()] if self._norm is not None: self._norm = self._charpoly[-1] varcenter = None @@ -415,7 +416,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): else: varcharpoly = var center = self.parent().center(name=varcenter) - coeffs = [ center(c) for c in self._charpoly ] + coeffs = [center(c) for c in self._charpoly] return PolynomialRing(center, name=varcharpoly)(coeffs) def is_central(self): @@ -568,7 +569,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): except ValueError: bound = self._matphir_c().minimal_polynomial() section = self._parent._embed_constants.section() - self._optbound = [ section(x) for x in bound.list() ] + self._optbound = [section(x) for x in bound.list()] return center(self._optbound) From 80b2e688c5a6cad698fc50ea02355bda77e7c852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 20 Jun 2022 16:26:50 +0200 Subject: [PATCH 125/742] factorisation of symbolic polynomials --- src/sage/symbolic/ginac/normal.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/symbolic/ginac/normal.cpp b/src/sage/symbolic/ginac/normal.cpp index 2d34d8f16f2..b7e17b81186 100644 --- a/src/sage/symbolic/ginac/normal.cpp +++ b/src/sage/symbolic/ginac/normal.cpp @@ -1221,8 +1221,6 @@ bool factor(const ex& the_ex, ex& res_ex) den = normalized.op(1); ex res_den; bool dres = factorpoly(den, res_den); - if (not nres and not dres) - return false; if (not nres) res_ex = num; if (not dres) From b41c93f6e7d42c69684bcbaad3cbc0e822f76e51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 22 Jun 2022 10:40:13 +0200 Subject: [PATCH 126/742] adding doctest for 33640 --- src/sage/symbolic/expression.pyx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index eecf2951e0b..5ba5d76430b 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -11885,6 +11885,11 @@ cdef class Expression(Expression_abc): x + sqrt(x) sage: factor((x + sqrt(x))/(x - sqrt(x))) (x + sqrt(x))/(x - sqrt(x)) + + Check that :trac:`33640` is fixed:: + + sage: ((x + 1)^2 - 2*x - 1).factor() + x^2 """ from sage.calculus.calculus import symbolic_expression_from_maxima_string cdef GEx x From 2019f4791f0bc6edf6c9f35a1ae618206d02623b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Jun 2022 13:51:30 -0700 Subject: [PATCH 127/742] bootstrap-conda: Also check dependencies_order_only --- bootstrap-conda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap-conda b/bootstrap-conda index d8c76e3f1ee..2631dc8723f 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -101,7 +101,7 @@ DEVELOP_SYSTEM_PACKAGES="openssh pycodestyle pytest" PKG_SCRIPTS=build/pkgs/$PKG_BASE SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/requirements.txt PKG_TYPE=$(cat $PKG_SCRIPTS/type) - if grep -q SAGERUNTIME $PKG_SCRIPTS/dependencies 2>/dev/null; then + if grep -q SAGERUNTIME $PKG_SCRIPTS/dependencies $PKG_SCRIPTS/dependencies_order_only 2>/dev/null; then : # cannot install packages that depend on the Sage library else case "$PKG_BASE:$PKG_TYPE" in From 119baaf65cf80ebb90f31b533339e30f828015a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 30 Jun 2022 11:40:53 +0200 Subject: [PATCH 128/742] 33002: tikz method of polyhedron can now output a TikzPicture object --- src/sage/geometry/polyhedron/base6.py | 53 +++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/base6.py b/src/sage/geometry/polyhedron/base6.py index b569f40613d..4a455bbffa4 100644 --- a/src/sage/geometry/polyhedron/base6.py +++ b/src/sage/geometry/polyhedron/base6.py @@ -475,7 +475,8 @@ def show(self, **kwds): def tikz(self, view=[0, 0, 1], angle=0, scale=1, edge_color='blue!95!black', facet_color='blue!95!black', - opacity=0.8, vertex_color='green', axis=False): + opacity=0.8, vertex_color='green', axis=False, + output_type='LatexExpr'): r""" Return a string ``tikz_pic`` consisting of a tikz picture of ``self`` according to a projection ``view`` and an angle ``angle`` @@ -496,10 +497,14 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, - ``opacity`` - real number (default: 0.8) between 0 and 1 giving the opacity of the front facets. - ``axis`` - Boolean (default: False) draw the axes at the origin or not. + - ``output_type`` - string (default: ``None``), valid values are + ``None``, ``'LatexExpr'`` and ``'TikzPicture'``, whether to + return a LatexExpr object (which inherits from Python str) or a + ``TikzPicture`` object from module :mod:`sage.misc.latex_standalone` OUTPUT: - - LatexExpr -- containing the TikZ picture. + - LatexExpr object or TikzPicture object .. NOTE:: @@ -563,10 +568,52 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, %% \coordinate (-1.00000, -1.00000, 0.00000) at (-1.00000, -1.00000, 0.00000); \coordinate (-1.00000, 0.00000, -1.00000) at (-1.00000, 0.00000, -1.00000); + + When output type is a :class:`sage.misc.latex_standalone.TikzPicture`:: + + sage: co = polytopes.cuboctahedron() + sage: t = co.tikz([674,108,-731], 112, output_type='TikzPicture') + sage: t + \documentclass[tikz]{standalone} + \begin{document} + \begin{tikzpicture}% + [x={(0.249656cm, -0.577639cm)}, + y={(0.777700cm, -0.358578cm)}, + z={(-0.576936cm, -0.733318cm)}, + scale=1.000000, + ... + Use print to see the full content. + ... + \node[vertex] at (1.00000, 0.00000, 1.00000) {}; + \node[vertex] at (1.00000, 1.00000, 0.00000) {}; + %% + %% + \end{tikzpicture} + \end{document} + sage: path_to_file = t.pdf() # not tested + """ - return self.projection().tikz(view, angle, scale, + tikz_string = self.projection().tikz(view, angle, scale, edge_color, facet_color, opacity, vertex_color, axis) + # set default value + if output_type is None: + # we may want to raise a deprecation warning here + # to announce that the default will later change + # to 'TikzPicture' + output_type = 'LatexExpr' + + # return + if output_type == 'LatexExpr': + return tikz_string + elif output_type == 'TikzPicture': + from sage.misc.latex_standalone import TikzPicture + return TikzPicture(tikz_string, standalone_config=None, + usepackage=None, usetikzlibrary=None, macros=None, + use_sage_preamble=False) + else: + raise ValueError("output_type (='{}') must be 'LatexExpr' or" + " 'TikzPicture'".format(output_type)) def _rich_repr_(self, display_manager, **kwds): r""" From 33afbd3bfabb2198836daf99e01e72ef2a73883a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Wed, 6 Jul 2022 16:22:52 +0200 Subject: [PATCH 129/742] 33002: moving the LatexExpr vs TikzPicture output type choice inside method projection().tikz() instead of tikz() --- src/sage/geometry/polyhedron/base6.py | 37 ++++---------- src/sage/geometry/polyhedron/plot.py | 74 ++++++++++++++++++++++++--- 2 files changed, 78 insertions(+), 33 deletions(-) diff --git a/src/sage/geometry/polyhedron/base6.py b/src/sage/geometry/polyhedron/base6.py index 4a455bbffa4..0d6202722c7 100644 --- a/src/sage/geometry/polyhedron/base6.py +++ b/src/sage/geometry/polyhedron/base6.py @@ -476,9 +476,10 @@ def show(self, **kwds): def tikz(self, view=[0, 0, 1], angle=0, scale=1, edge_color='blue!95!black', facet_color='blue!95!black', opacity=0.8, vertex_color='green', axis=False, - output_type='LatexExpr'): + output_type=None): r""" - Return a string ``tikz_pic`` consisting of a tikz picture of ``self`` + Return a tikz picture of ``self`` as a string or as a + :class:`~sage.misc.latex_standalone.TikzPicture` according to a projection ``view`` and an angle ``angle`` obtained via the threejs viewer. ``self`` must be bounded. @@ -497,10 +498,11 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, - ``opacity`` - real number (default: 0.8) between 0 and 1 giving the opacity of the front facets. - ``axis`` - Boolean (default: False) draw the axes at the origin or not. - - ``output_type`` - string (default: ``None``), valid values are - ``None``, ``'LatexExpr'`` and ``'TikzPicture'``, whether to - return a LatexExpr object (which inherits from Python str) or a - ``TikzPicture`` object from module :mod:`sage.misc.latex_standalone` + - ``output_type`` - string (default: ``None``), valid values + are ``None`` (deprecated), ``'LatexExpr'`` and ``'TikzPicture'``, + whether to return a LatexExpr object (which inherits from Python + str) or a ``TikzPicture`` object from module + :mod:`sage.misc.latex_standalone` OUTPUT: @@ -593,27 +595,10 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, sage: path_to_file = t.pdf() # not tested """ - tikz_string = self.projection().tikz(view, angle, scale, + return self.projection().tikz(view, angle, scale, edge_color, facet_color, - opacity, vertex_color, axis) - # set default value - if output_type is None: - # we may want to raise a deprecation warning here - # to announce that the default will later change - # to 'TikzPicture' - output_type = 'LatexExpr' - - # return - if output_type == 'LatexExpr': - return tikz_string - elif output_type == 'TikzPicture': - from sage.misc.latex_standalone import TikzPicture - return TikzPicture(tikz_string, standalone_config=None, - usepackage=None, usetikzlibrary=None, macros=None, - use_sage_preamble=False) - else: - raise ValueError("output_type (='{}') must be 'LatexExpr' or" - " 'TikzPicture'".format(output_type)) + opacity, vertex_color, axis, + output_type=output_type) def _rich_repr_(self, display_manager, **kwds): r""" diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index df157066c43..d85c5524e83 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1228,11 +1228,13 @@ def render_3d(self, point_opts=None, line_opts=None, polygon_opts=None): def tikz(self, view=[0, 0, 1], angle=0, scale=1, edge_color='blue!95!black', facet_color='blue!95!black', - opacity=0.8, vertex_color='green', axis=False): + opacity=0.8, vertex_color='green', axis=False, + output_type=None): r""" - Return a string ``tikz_pic`` consisting of a tikz picture of ``self`` + Return a tikz picture of ``self`` as a string or as a + :class:`~sage.misc.latex_standalone.TikzPicture` according to a projection ``view`` and an angle ``angle`` - obtained via Jmol through the current state property. + obtained via the threejs viewer. INPUT: @@ -1249,10 +1251,15 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, - ``opacity`` - real number (default: 0.8) between 0 and 1 giving the opacity of the front facets. - ``axis`` - Boolean (default: False) draw the axes at the origin or not. + - ``output_type`` - string (default: ``None``), valid values + are ``None`` (deprecated), ``'LatexExpr'`` and ``'TikzPicture'``, + whether to return a LatexExpr object (which inherits from Python + str) or a ``TikzPicture`` object from module + :mod:`sage.misc.latex_standalone` OUTPUT: - - LatexExpr -- containing the TikZ picture. + - LatexExpr object or TikzPicture object .. NOTE:: @@ -1328,6 +1335,29 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, ... NotImplementedError: The polytope has to live in 2 or 3 dimensions. + Using :class:`~sage.misc.latex_standalone.TikzPicture` as output type:: + + sage: P3 = Polyhedron(vertices=[[-1, -1, 2],[-1, 2, -1],[2, -1, -1]]) + sage: t = P3.projection().tikz([0.5,-1,-0.1], 55, scale=3, edge_color='blue!95!black',facet_color='orange!95!black', opacity=0.7, vertex_color='yellow', axis=True, output_type='TikzPicture') + sage: t + \documentclass[tikz]{standalone} + \begin{document} + \begin{tikzpicture}% + [x={(0.658184cm, -0.242192cm)}, + y={(-0.096240cm, 0.912008cm)}, + z={(-0.746680cm, -0.331036cm)}, + scale=3.000000, + ... + Use print to see the full content. + ... + \node[vertex] at (-1.00000, 2.00000, -1.00000) {}; + \node[vertex] at (2.00000, -1.00000, -1.00000) {}; + %% + %% + \end{tikzpicture} + \end{document} + sage: t.pdf(view=False) # not tested + .. TODO:: Make it possible to draw Schlegel diagram for 4-polytopes. :: @@ -1347,15 +1377,45 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, elif self.polyhedron_dim < 2 or self.polyhedron_dim > 3: raise NotImplementedError("The polytope has to be 2 or 3-dimensional.") elif self.polyhedron_ambient_dim == 2: # self is a polygon in 2-space - return self._tikz_2d(scale, edge_color, facet_color, opacity, + tikz_string = self._tikz_2d(scale, edge_color, facet_color, opacity, vertex_color, axis) elif self.polyhedron_dim == 2: # self is a polygon in 3-space - return self._tikz_2d_in_3d(view, angle, scale, edge_color, + tikz_string = self._tikz_2d_in_3d(view, angle, scale, edge_color, facet_color, opacity, vertex_color, axis) else: # self is a 3-polytope in 3-space - return self._tikz_3d_in_3d(view, angle, scale, edge_color, + tikz_string = self._tikz_3d_in_3d(view, angle, scale, edge_color, facet_color, opacity, vertex_color, axis) + # set default value + if output_type is None: + from sage.misc.superseded import deprecation + msg = ("Since SageMath 5.13 (ticket #12083), the method .tikz() " + "of a polyhedron returns an object of type ``LatexExpr`` " + "which is a Python str. Since SageMath 9.7, this " + "default behavior of returning an object of type " + "LatexExpr is deprecated as the default output will soon " + "change to an object of type ``TikzPicture`` from the " + "module sage.misc.latex_standalone (newly introduced in " + "SageMath 9.6). Please update your code to specify the " + "desired output type as ``.tikz(output_type='LatexExpr')`` " + "to keep the old behavior or " + "``.tikz(output_type='TikzPicture')`` to use " + "the future default behavior.") + deprecation(33002, msg) + output_type = 'LatexExpr' + + # return + if output_type == 'LatexExpr': + return tikz_string + elif output_type == 'TikzPicture': + from sage.misc.latex_standalone import TikzPicture + return TikzPicture(tikz_string, standalone_config=None, + usepackage=None, usetikzlibrary=None, macros=None, + use_sage_preamble=False) + else: + raise ValueError("output_type (='{}') must be 'LatexExpr' or" + " 'TikzPicture'".format(output_type)) + def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): r""" Return a string ``tikz_pic`` consisting of a tikz picture of From a1d598991a123c9ad1f7e812a1ef1daa6889f0b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Wed, 6 Jul 2022 17:07:09 +0200 Subject: [PATCH 130/742] 33002: adapting the doctests with the new behavior thus also avoiding deprecation warnings --- .../geometry/polytope_tikz.rst | 37 ++++-- .../geometry/visualization.rst | 23 +++- src/sage/geometry/polyhedron/base6.py | 37 ++++-- src/sage/geometry/polyhedron/plot.py | 112 ++++++++++++------ 4 files changed, 139 insertions(+), 70 deletions(-) diff --git a/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst b/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst index 9fb6be2700e..4d4d5bdc593 100644 --- a/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst +++ b/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst @@ -15,8 +15,9 @@ paper. TikZ is a very versatile tool to draw in scientific documents and Sage can deal easily with 3-dimensional polytopes. Finally sagetex makes everything work together nicely between Sage, TikZ and LaTeX. Since version 6.3 of Sage, there is a function for (projection -of) polytopes to output a TikZ picture of the polytope. This short -tutorial shows how it all works. +of) polytopes to output a TikZ picture of the polytope. Since Version 9.7 of SageMath, +the tikz output can be a ``TikzPicture`` object from the sage module +``sage.misc.latex_standalone``. This short tutorial shows how it all works. Instructions """""""""""" @@ -30,21 +31,23 @@ To put an image of a 3D-polytope in LaTeX using TikZ and Sage, simply follow the - Visualize the polytope P using the command ``P.show(aspect_ratio=1)`` - This will open an interactive view in your default browser, where you can rotate the polytope. - Once the desired view angle is found, click on the information icon in the lower right-hand corner and select *Get Viewpoint*. This will copy a string of the form '[x,y,z],angle' to your local clipboard. -- Go back to Sage and type ``Img = P.tikz([x,y,z],angle)``. You can paste the string here to save some typing. +- Go back to Sage and type ``Img = P.tikz([x,y,z],angle,output_type='LatexExpr')``. You can paste the string here to save some typing. - *Img* now contains a Sage object of type ``LatexExpr`` containing the raw TikZ picture of your polytope -Then, you can either copy-paste it to your article by typing ``Img`` in Sage or save it to a file, by doing +Alternatively, you can save the tikz image to a file, by doing .. CODE-BLOCK:: python - f = open('Img_poly.tex','w') - f.write(Img) - f.close() + Img = P.tikz([x,y,z], angle, output_type='TikzPicture') + Img.tex('Img_poly.tex') + Img.tex('Img_poly.tex', content_only=True) + Img.pdf('Img_poly.pdf') .. end of output Then in the pwd (present working directory of sage, the one of your article) -you will have a file named ``Img_poly.tex`` containing the tikzpicture of your polytope. +you will have a file named ``Img_poly.tex`` and ``Img_poly.pdf`` containing the +tikzpicture of the polytope ``P``. Customization """"""""""""" @@ -57,6 +60,9 @@ You can customize the polytope using the following options in the command ``P.ti - ``vertex_color`` : string (default: ``green``) representing colors which tikz recognize, - ``opacity`` : real number (default: ``0.8``) between 0 and 1 giving the opacity of the front facets, - ``axis`` : Boolean (default: ``False``) draw the axes at the origin or not. +- ``output_type`` : string (default: ``None``) ``None``, ``'LatexExpr'`` or + ``'TikzPicture'``, the type of the output. Since SageMath 9.7, the value ``None`` is deprecated + as the default value will soon be changed from ``'LatexExpr'`` to ``'TikzPicture'``. Examples """""""" @@ -80,15 +86,20 @@ When you found a good angle, follow the above procedure to obtain the values :: - Img = P.tikz([674,108,-731],112) + Img = P.tikz([674,108,-731], 112, output_type='TikzPicture') .. end of output +Note: the ``output_type='TikzPicture'`` is necessary since SagMath 9.7 to avoid +a deprecation warning message since the default output type will soon change +from a ``LatexExpr`` (Python str) to a ``TikzPicture`` object (allowing more +versatility, like being able to view it directly in the Jupyter notebook). + Or you may want to customize using the command :: - Img = P.tikz([674,108,-731],112,scale=2, edge_color='orange',facet_color='red',vertex_color='blue',opacity=0.4) + Img = P.tikz([674,108,-731],112,scale=2, edge_color='orange',facet_color='red',vertex_color='blue',opacity=0.4, output_type='TikzPicture') .. end of output @@ -134,7 +145,7 @@ some possibilities. .. CODE-BLOCK:: latex - \sagestr{(polytopes.permutahedron(4)).tikz([4,5,6],45,scale=0.75, facet_color='red',vertex_color='yellow',opacity=0.3)} + \sagestr{(polytopes.permutahedron(4)).tikz([4,5,6],45,scale=0.75, facet_color='red',vertex_color='yellow',opacity=0.3, output_type='LatexExpr')} .. end of output @@ -142,8 +153,8 @@ some possibilities. .. CODE-BLOCK:: latex - \newcommand{\polytopeimg}[4]{\sagestr{(#1).tikz(#2,#3,#4)}} - \newcommand{\polytopeimgopt}[9]{\sagestr{(#1).tikz(#2,#3,#4,#5,#6,#7,#8,#9)}} + \newcommand{\polytopeimg}[4]{\sagestr{(#1).tikz(#2,#3,#4,output_type='LatexExpr')}} + \newcommand{\polytopeimgopt}[9]{\sagestr{(#1).tikz(#2,#3,#4,#5,#6,#7,#8,#9,output_type='LatexExpr')}} .. end of output diff --git a/src/doc/en/thematic_tutorials/geometry/visualization.rst b/src/doc/en/thematic_tutorials/geometry/visualization.rst index ac7412e665c..438b6cff4c8 100644 --- a/src/doc/en/thematic_tutorials/geometry/visualization.rst +++ b/src/doc/en/thematic_tutorials/geometry/visualization.rst @@ -113,11 +113,22 @@ This method returns a tikz picture of the polytope (must be 2 or :: sage: c = polytopes.cube() - sage: c.tikz().splitlines()[:5] - ['\\begin{tikzpicture}%', - '\t[x={(1.000000cm, 0.000000cm)},', - '\ty={(-0.000000cm, 1.000000cm)},', - '\tz={(0.000000cm, -0.000000cm)},', - '\tscale=1.000000,'] + sage: c.tikz(output_type='TikzPicture') + \documentclass[tikz]{standalone} + \begin{document} + \begin{tikzpicture}% + [x={(1.000000cm, 0.000000cm)}, + y={(-0.000000cm, 1.000000cm)}, + z={(0.000000cm, -0.000000cm)}, + scale=1.000000, + ... + Use print to see the full content. + ... + \node[vertex] at (-1.00000, -1.00000, 1.00000) {}; + \node[vertex] at (-1.00000, 1.00000, 1.00000) {}; + %% + %% + \end{tikzpicture} + \end{document} .. end of output diff --git a/src/sage/geometry/polyhedron/base6.py b/src/sage/geometry/polyhedron/base6.py index 0d6202722c7..94e8aa668fa 100644 --- a/src/sage/geometry/polyhedron/base6.py +++ b/src/sage/geometry/polyhedron/base6.py @@ -50,7 +50,10 @@ class Polyhedron_base6(Polyhedron_base5): sage: P = polytopes.cube() sage: Polyhedron_base6.plot(P) Graphics3d Object - sage: Polyhedron_base6.tikz(P) + sage: print(Polyhedron_base6.tikz(P, output_type='TikzPicture')) + \RequirePackage{luatex85} + \documentclass[tikz]{standalone} + \begin{document} \begin{tikzpicture}% [x={(1.000000cm, 0.000000cm)}, y={(-0.000000cm, 1.000000cm)}, @@ -127,6 +130,7 @@ class Polyhedron_base6(Polyhedron_base5): %% %% \end{tikzpicture} + \end{document} sage: Q = polytopes.hypercube(4) sage: Polyhedron_base6.show(Q) @@ -544,18 +548,25 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, EXAMPLES:: sage: co = polytopes.cuboctahedron() - sage: Img = co.tikz([0,0,1], 0) - sage: print('\n'.join(Img.splitlines()[:9])) + sage: Img = co.tikz([0,0,1], 0, output_type='TikzPicture') + sage: Img + \documentclass[tikz]{standalone} + \begin{document} \begin{tikzpicture}% - [x={(1.000000cm, 0.000000cm)}, - y={(0.000000cm, 1.000000cm)}, - z={(0.000000cm, 0.000000cm)}, - scale=1.000000, - back/.style={loosely dotted, thin}, - edge/.style={color=blue!95!black, thick}, - facet/.style={fill=blue!95!black,fill opacity=0.800000}, - vertex/.style={inner sep=1pt,circle,draw=green!25!black,fill=green!75!black,thick}] - sage: print('\n'.join(Img.splitlines()[12:21])) + [x={(1.000000cm, 0.000000cm)}, + y={(0.000000cm, 1.000000cm)}, + z={(0.000000cm, 0.000000cm)}, + scale=1.000000, + ... + Use print to see the full content. + ... + \node[vertex] at (1.00000, 0.00000, 1.00000) {}; + \node[vertex] at (1.00000, 1.00000, 0.00000) {}; + %% + %% + \end{tikzpicture} + \end{document} + sage: print('\n'.join(Img.content().splitlines()[12:21])) %% with the command: ._tikz_3d_in_3d and parameters: %% view = [0, 0, 1] %% angle = 0 @@ -565,7 +576,7 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, %% opacity = 0.8 %% vertex_color = green %% axis = False - sage: print('\n'.join(Img.splitlines()[22:26])) + sage: print('\n'.join(Img.content().splitlines()[22:26])) %% Coordinate of the vertices: %% \coordinate (-1.00000, -1.00000, 0.00000) at (-1.00000, -1.00000, 0.00000); diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index d85c5524e83..6bd567c68fc 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1292,19 +1292,56 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, EXAMPLES:: sage: P1 = polytopes.small_rhombicuboctahedron() - sage: Image1 = P1.projection().tikz([1,3,5], 175, scale=4) + sage: Image1 = P1.projection().tikz([1,3,5], 175, scale=4, output_type='TikzPicture') sage: type(Image1) - - sage: print('\n'.join(Image1.splitlines()[:4])) + + sage: Image1 + \documentclass[tikz]{standalone} + \begin{document} \begin{tikzpicture}% - [x={(-0.939161cm, 0.244762cm)}, - y={(0.097442cm, -0.482887cm)}, - z={(0.329367cm, 0.840780cm)}, - sage: with open('polytope-tikz1.tex', 'w') as f: # not tested - ....: _ = f.write(Image1) + [x={(-0.939161cm, 0.244762cm)}, + y={(0.097442cm, -0.482887cm)}, + z={(0.329367cm, 0.840780cm)}, + scale=4.000000, + ... + Use print to see the full content. + ... + \node[vertex] at (-2.41421, 1.00000, -1.00000) {}; + \node[vertex] at (-2.41421, -1.00000, 1.00000) {}; + %% + %% + \end{tikzpicture} + \end{document} + sage: _ = Image1.tex('polytope-tikz1.tex') # not tested + sage: _ = Image1.png('polytope-tikz1.png') # not tested + sage: _ = Image1.pdf('polytope-tikz1.pdf') # not tested + sage: _ = Image1.svg('polytope-tikz1.svg') # not tested + + A second example:: sage: P2 = Polyhedron(vertices=[[1, 1],[1, 2],[2, 1]]) - sage: Image2 = P2.projection().tikz(scale=3, edge_color='blue!95!black', facet_color='orange!95!black', opacity=0.4, vertex_color='yellow', axis=True) + sage: Image2 = P2.projection().tikz(scale=3, edge_color='blue!95!black', facet_color='orange!95!black', opacity=0.4, vertex_color='yellow', axis=True, output_type='TikzPicture') + sage: Image2 + \documentclass[tikz]{standalone} + \begin{document} + \begin{tikzpicture}% + [scale=3.000000, + back/.style={loosely dotted, thin}, + edge/.style={color=blue!95!black, thick}, + facet/.style={fill=orange!95!black,fill opacity=0.400000}, + ... + Use print to see the full content. + ... + \node[vertex] at (1.00000, 2.00000) {}; + \node[vertex] at (2.00000, 1.00000) {}; + %% + %% + \end{tikzpicture} + \end{document} + + The second example using a LatexExpr as output type:: + + sage: Image2 = P2.projection().tikz(scale=3, edge_color='blue!95!black', facet_color='orange!95!black', opacity=0.4, vertex_color='yellow', axis=True, output_type='LatexExpr') sage: type(Image2) sage: print('\n'.join(Image2.splitlines()[:4])) @@ -1315,31 +1352,13 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, sage: with open('polytope-tikz2.tex', 'w') as f: # not tested ....: _ = f.write(Image2) + A third example:: + sage: P3 = Polyhedron(vertices=[[-1, -1, 2],[-1, 2, -1],[2, -1, -1]]) sage: P3 A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 3 vertices - sage: Image3 = P3.projection().tikz([0.5,-1,-0.1], 55, scale=3, edge_color='blue!95!black',facet_color='orange!95!black', opacity=0.7, vertex_color='yellow', axis=True) - sage: print('\n'.join(Image3.splitlines()[:4])) - \begin{tikzpicture}% - [x={(0.658184cm, -0.242192cm)}, - y={(-0.096240cm, 0.912008cm)}, - z={(-0.746680cm, -0.331036cm)}, - sage: with open('polytope-tikz3.tex', 'w') as f: # not tested - ....: _ = f.write(Image3) - - sage: P = Polyhedron(vertices=[[1,1,0,0],[1,2,0,0],[2,1,0,0],[0,0,1,0],[0,0,0,1]]) - sage: P - A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices - sage: P.projection().tikz() - Traceback (most recent call last): - ... - NotImplementedError: The polytope has to live in 2 or 3 dimensions. - - Using :class:`~sage.misc.latex_standalone.TikzPicture` as output type:: - - sage: P3 = Polyhedron(vertices=[[-1, -1, 2],[-1, 2, -1],[2, -1, -1]]) - sage: t = P3.projection().tikz([0.5,-1,-0.1], 55, scale=3, edge_color='blue!95!black',facet_color='orange!95!black', opacity=0.7, vertex_color='yellow', axis=True, output_type='TikzPicture') - sage: t + sage: Image3 = P3.projection().tikz([0.5,-1,-0.1], 55, scale=3, edge_color='blue!95!black',facet_color='orange!95!black', opacity=0.7, vertex_color='yellow', axis=True, output_type='TikzPicture') + sage: Image3 \documentclass[tikz]{standalone} \begin{document} \begin{tikzpicture}% @@ -1356,7 +1375,20 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, %% \end{tikzpicture} \end{document} - sage: t.pdf(view=False) # not tested + sage: _ = Image3.tex('polytope-tikz3.tex') # not tested + sage: _ = Image3.png('polytope-tikz3.png') # not tested + sage: _ = Image3.pdf('polytope-tikz3.pdf') # not tested + sage: _ = Image3.svg('polytope-tikz3.svg') # not tested + + A fourth example:: + + sage: P = Polyhedron(vertices=[[1,1,0,0],[1,2,0,0],[2,1,0,0],[0,0,1,0],[0,0,0,1]]) + sage: P + A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices + sage: P.projection().tikz(output_type='TikzPicture') + Traceback (most recent call last): + ... + NotImplementedError: The polytope has to live in 2 or 3 dimensions. .. TODO:: @@ -1365,7 +1397,7 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, sage: P=Polyhedron(vertices=[[1,1,0,0],[1,2,0,0],[2,1,0,0],[0,0,1,0],[0,0,0,1]]) sage: P A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices - sage: P.projection().tikz() + sage: P.projection().tikz(output_type='TikzPicture') Traceback (most recent call last): ... NotImplementedError: The polytope has to live in 2 or 3 dimensions. @@ -1454,9 +1486,9 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): Scientific notation is not used in the output (:trac:`16519`):: - sage: P=Polyhedron([[2*10^-10,0],[0,1],[1,0]],base_ring=QQ) - sage: tikzstr=P.projection().tikz() - sage: 'e-10' in tikzstr + sage: P = Polyhedron([[2*10^-10,0],[0,1],[1,0]],base_ring=QQ) + sage: tikz = P.projection().tikz(output_type='TikzPicture') + sage: 'e-10' in tikz.content() False .. NOTE:: @@ -1582,9 +1614,11 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, sage: with open('polytope-tikz3.tex', 'w') as f: # not tested ....: _ = f.write(Image) + :: + sage: p = Polyhedron(vertices=[[1,0,0],[0,1,0],[0,0,1]]) sage: proj = p.projection() - sage: Img = proj.tikz([1,1,1],130,axis=True) + sage: Img = proj.tikz([1,1,1],130,axis=True, output_type='LatexExpr') sage: print('\n'.join(Img.splitlines()[12:21])) %% with the command: ._tikz_2d_in_3d and parameters: %% view = [1, 1, 1] @@ -1730,8 +1764,10 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, sage: with open('polytope-tikz1.tex', 'w') as f: # not tested ....: _ = f.write(Image) + :: + sage: Associahedron = Polyhedron(vertices=[[1,0,1],[1,0,0],[1,1,0],[0,0,-1],[0,1,0],[-1,0,0],[0,1,1],[0,0,1],[0,-1,0]]).polar() - sage: ImageAsso = Associahedron.projection().tikz([-15,-755,-655], 116, scale=1) + sage: ImageAsso = Associahedron.projection().tikz([-15,-755,-655], 116, scale=1, output_type='LatexExpr') sage: print('\n'.join(ImageAsso.splitlines()[12:30])) %% with the command: ._tikz_3d_in_3d and parameters: %% view = [-15, -755, -655] From 4ef07a9544b35713cb4fd182211c40965de086fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 7 Jul 2022 10:03:17 +0200 Subject: [PATCH 131/742] 33002: shorter deprecation message --- .../geometry/polytope_tikz.rst | 4 ++-- src/sage/geometry/polyhedron/plot.py | 17 ++++++----------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst b/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst index 4d4d5bdc593..4dbd6839ca0 100644 --- a/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst +++ b/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst @@ -15,8 +15,8 @@ paper. TikZ is a very versatile tool to draw in scientific documents and Sage can deal easily with 3-dimensional polytopes. Finally sagetex makes everything work together nicely between Sage, TikZ and LaTeX. Since version 6.3 of Sage, there is a function for (projection -of) polytopes to output a TikZ picture of the polytope. Since Version 9.7 of SageMath, -the tikz output can be a ``TikzPicture`` object from the sage module +of) polytopes to output a TikZ picture of the polytope. Since version 9.7 of +SageMath, the tikz output can be a ``TikzPicture`` object from the sage module ``sage.misc.latex_standalone``. This short tutorial shows how it all works. Instructions diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 6bd567c68fc..d0ae10da640 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1421,17 +1421,12 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, # set default value if output_type is None: from sage.misc.superseded import deprecation - msg = ("Since SageMath 5.13 (ticket #12083), the method .tikz() " - "of a polyhedron returns an object of type ``LatexExpr`` " - "which is a Python str. Since SageMath 9.7, this " - "default behavior of returning an object of type " - "LatexExpr is deprecated as the default output will soon " - "change to an object of type ``TikzPicture`` from the " - "module sage.misc.latex_standalone (newly introduced in " - "SageMath 9.6). Please update your code to specify the " - "desired output type as ``.tikz(output_type='LatexExpr')`` " - "to keep the old behavior or " - "``.tikz(output_type='TikzPicture')`` to use " + msg = ("The default type of the returned object will soon be " + "changed from `sage.misc.latex.LatexExpr` to " + "`sage.misc.latex_standalone.TikzPicture`. Please " + "update your code to specify the desired output type as " + "`.tikz(output_type='LatexExpr')` to keep the old " + "behavior or `.tikz(output_type='TikzPicture')` to use " "the future default behavior.") deprecation(33002, msg) output_type = 'LatexExpr' From 57aff708ab601cf3d320ff029191721cd7ff4594 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Jul 2022 16:06:23 -0700 Subject: [PATCH 132/742] build/pkgs/latte_int/patches/6dbf7f07d5c9e1f3afe793f782d191d4465088ae.patch: New --- ...7f07d5c9e1f3afe793f782d191d4465088ae.patch | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 build/pkgs/latte_int/patches/6dbf7f07d5c9e1f3afe793f782d191d4465088ae.patch diff --git a/build/pkgs/latte_int/patches/6dbf7f07d5c9e1f3afe793f782d191d4465088ae.patch b/build/pkgs/latte_int/patches/6dbf7f07d5c9e1f3afe793f782d191d4465088ae.patch new file mode 100644 index 00000000000..308456304d7 --- /dev/null +++ b/build/pkgs/latte_int/patches/6dbf7f07d5c9e1f3afe793f782d191d4465088ae.patch @@ -0,0 +1,79 @@ +From 6dbf7f07d5c9e1f3afe793f782d191d4465088ae Mon Sep 17 00:00:00 2001 +From: Matthias Koeppe +Date: Thu, 7 Jul 2022 15:42:35 -0700 +Subject: [PATCH] Remove dynamic exception specifications to conform to ISO + C++17 + +--- + code/latte/ExponentialSubst.cpp | 2 -- + code/latte/ExponentialSubst.h | 6 ++---- + code/latte/sqlite/IntegrationDB.cpp | 2 +- + code/latte/sqlite/IntegrationDB.h | 2 +- + 4 files changed, 4 insertions(+), 8 deletions(-) + +diff --git a/code/latte/ExponentialSubst.cpp b/code/latte/ExponentialSubst.cpp +index a839b820..bcbfa934 100644 +--- a/code/latte/ExponentialSubst.cpp ++++ b/code/latte/ExponentialSubst.cpp +@@ -57,7 +57,6 @@ mpq_vector + computeExponentialResidueWeights(const vec_ZZ &generic_vector, + mpz_class &prod_ray_scalar_products, + const listCone *cone, int numOfVars) +- throw(NotGenericException) + { + // Compute dimension; can be smaller than numOfVars + int dimension = 0; +@@ -95,7 +94,6 @@ computeExponentialResidueWeights(const vec_ZZ &generic_vector, + mpq_vector + computeExponentialResidueWeights(const vec_ZZ &generic_vector, + const listCone *cone, int numOfVars) +- throw(NotGenericException) + { + mpz_class prod_ray_scalar_products; + return computeExponentialResidueWeights(generic_vector, +diff --git a/code/latte/ExponentialSubst.h b/code/latte/ExponentialSubst.h +index c9fa4ace..43a4ab63 100644 +--- a/code/latte/ExponentialSubst.h ++++ b/code/latte/ExponentialSubst.h +@@ -58,13 +58,11 @@ class Exponential_Single_Cone_Parameters + mpq_vector /* FIXME: This version can probably go away */ + computeExponentialResidueWeights(const vec_ZZ &generic_vector, + mpz_class &prod_ray_scalar_products, +- const listCone *cone, int numOfVars) +- throw(NotGenericException); ++ const listCone *cone, int numOfVars); + + mpq_vector + computeExponentialResidueWeights(const vec_ZZ &generic_vector, +- const listCone *cone, int numOfVars) +- throw(NotGenericException); ++ const listCone *cone, int numOfVars); + + ZZ + scalar_power(const vec_ZZ &generic_vector, +diff --git a/code/latte/sqlite/IntegrationDB.cpp b/code/latte/sqlite/IntegrationDB.cpp +index ab8df535..c1dde830 100644 +--- a/code/latte/sqlite/IntegrationDB.cpp ++++ b/code/latte/sqlite/IntegrationDB.cpp +@@ -1277,7 +1277,7 @@ void IntegrationDB::insertSpecficPolytopeIntegrationTest(string polymakeFile, i + * @parm filePath: to the latte-style polynomial. + * @return rowid of the inserted row. + */ +-int IntegrationDB::insertPolynomial(int dim, int degree, const char*filePath) throw(SqliteDBexception) ++int IntegrationDB::insertPolynomial(int dim, int degree, const char*filePath) + { + if ( doesPolynomialExist(filePath)) + throw SqliteDBexception(string("insertPolynomial::Polynomial ")+filePath+" already exist"); +diff --git a/code/latte/sqlite/IntegrationDB.h b/code/latte/sqlite/IntegrationDB.h +index d690a832..ce8cfac6 100644 +--- a/code/latte/sqlite/IntegrationDB.h ++++ b/code/latte/sqlite/IntegrationDB.h +@@ -67,7 +67,7 @@ class IntegrationDB: public SqliteDB + int insertIntegrationTest(int polynomialID, int polytopeID); + void insertIntegrationTest(int dim, int degree, int vertexCount, int count); + void insertSpecficPolytopeIntegrationTest(string polymakeFile, int degree, int count); +- int insertPolynomial(int dim, int degree, const char*filePath) throw(SqliteDBexception); ++ int insertPolynomial(int dim, int degree, const char*filePath); + + int insertPolytope(int dim, int vertexCount, int simple, int dualRowID, const char* latteFilePath, const char* polymakeFilePath); + From 7a71bbe3d90d3da65814da6c6c53f0686c51f9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 21 Jul 2022 16:45:37 +0200 Subject: [PATCH 133/742] 33002: fixing small remarks in polytope_tikz.rst --- src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst b/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst index 4dbd6839ca0..a0c98ea3836 100644 --- a/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst +++ b/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst @@ -32,7 +32,7 @@ To put an image of a 3D-polytope in LaTeX using TikZ and Sage, simply follow the - This will open an interactive view in your default browser, where you can rotate the polytope. - Once the desired view angle is found, click on the information icon in the lower right-hand corner and select *Get Viewpoint*. This will copy a string of the form '[x,y,z],angle' to your local clipboard. - Go back to Sage and type ``Img = P.tikz([x,y,z],angle,output_type='LatexExpr')``. You can paste the string here to save some typing. -- *Img* now contains a Sage object of type ``LatexExpr`` containing the raw TikZ picture of your polytope +- *Img* now contains a Sage object of type ``LatexExpr`` containing the raw TikZ picture of your polytope. Alternatively, you can save the tikz image to a file, by doing @@ -46,7 +46,7 @@ Alternatively, you can save the tikz image to a file, by doing .. end of output Then in the pwd (present working directory of sage, the one of your article) -you will have a file named ``Img_poly.tex`` and ``Img_poly.pdf`` containing the +you will have two files named ``Img_poly.tex`` and ``Img_poly.pdf`` containing the tikzpicture of the polytope ``P``. Customization From 62f69ae4f3b5bef46d4e657d7507c84f65f7a429 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Jul 2022 16:54:47 -0700 Subject: [PATCH 134/742] build/bin/sage-spkg-installcheck, build/sage_bootstrap/installcheck.py: New --- build/bin/sage-spkg-installcheck | 24 ++++ build/sage_bootstrap/installcheck.py | 158 +++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100755 build/bin/sage-spkg-installcheck create mode 100644 build/sage_bootstrap/installcheck.py diff --git a/build/bin/sage-spkg-installcheck b/build/bin/sage-spkg-installcheck new file mode 100755 index 00000000000..a8ef89ba2aa --- /dev/null +++ b/build/bin/sage-spkg-installcheck @@ -0,0 +1,24 @@ +#!/usr/bin/env sage-bootstrap-python + +# usage: sage-spkg-installcheck [-h] PKG [SAGE_LOCAL] +# +# Check shared libraries that are part of an installed package. +# +# positional arguments: +# PKG the name of the package to uninstall +# SAGE_LOCAL the path to SAGE_LOCAL (default: value of the $SAGE_LOCAL +# environment variable if set; exits otherwise) +# +# optional arguments: +# -h, --help show this help message and exit + + +try: + import sage_bootstrap +except ImportError: + import os, sys + sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) + import sage_bootstrap + +from sage_bootstrap.installcheck import run +run() diff --git a/build/sage_bootstrap/installcheck.py b/build/sage_bootstrap/installcheck.py new file mode 100644 index 00000000000..a6f350e424b --- /dev/null +++ b/build/sage_bootstrap/installcheck.py @@ -0,0 +1,158 @@ +""" +Command-line script for checking an installed SPKG in $SAGE_LOCAL. +""" + +# **************************************************************************** +# Copyright (C) 2017 Erik M. Bray +# 2022 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 __future__ import print_function + +import glob +import json +import os +import shutil +import subprocess +import sys +import argparse + +from .env import SAGE_ROOT + +pth = os.path +PKGS = pth.join(SAGE_ROOT, 'build', 'pkgs') +"""Directory where all spkg sources are found.""" + + +def installcheck(spkg_name, sage_local, verbose=False): + """ + Given a package name and path to SAGE_LOCAL, check the installation of the package + in SAGE_LOCAL. + """ + + # The default path to this directory; however its value should be read + # from the environment if possible + spkg_inst = pth.join(sage_local, 'var', 'lib', 'sage', 'installed') + + # Find all stamp files for the package; there should be only one, but if + # there is somehow more than one we'll work with the most recent and delete + # the rest + pattern = pth.join(spkg_inst, '{0}-*'.format(spkg_name)) + stamp_files = sorted(glob.glob(pattern), key=pth.getmtime) + + if stamp_files: + stamp_file = stamp_files[-1] + else: + stamp_file = None + + spkg_meta = {} + if stamp_file: + try: + with open(stamp_file) as f: + spkg_meta = json.load(f) + except (OSError, ValueError): + pass + + if 'files' not in spkg_meta: + if stamp_file: + print("Old-style or corrupt stamp file '{0}'" + .format(stamp_file), file=sys.stderr) + else: + print("Package '{0}' is currently not installed in '{1}'" + .format(spkg_name, sage_local), file=sys.stderr) + else: + files = spkg_meta['files'] + if not files: + print("Warning: No files to check for " + "'{0}'".format(spkg_name), file=sys.stderr) + + for f in files: + if f.endswith(('.so', '.dylib')): + if verbose: + print("Checking shared library file '{0}'" + .format(f), file=sys.stderr) + elif f.endswith('.whl'): + if verbose: + print("Checking wheel file '{0}'" + .format(f), file=sys.stderr) + + +def dir_type(path): + """ + A custom argument 'type' for directory paths. + """ + + if path and not pth.isdir(path): + raise argparse.ArgumentTypeError( + "'{0}' is not a directory".format(path)) + + return path + + +def spkg_type(pkg): + """ + A custom argument 'type' for spkgs--checks whether the given package name + is a known spkg. + """ + pkgbase = pth.join(PKGS, pkg) + + if not pth.isdir(pkgbase): + raise argparse.ArgumentTypeError( + "'{0}' is not a known spkg".format(pkg)) + + return pkg + + +def make_parser(): + """Returns the command-line argument parser for sage-spkg-installcheck.""" + + doc_lines = __doc__.strip().splitlines() + + parser = argparse.ArgumentParser( + description=doc_lines[0], + epilog='\n'.join(doc_lines[1:]).strip(), + formatter_class=argparse.RawDescriptionHelpFormatter) + + parser.add_argument('spkg', type=spkg_type, help='the spkg to check') + parser.add_argument('sage_local', type=dir_type, nargs='?', + default=os.environ.get('SAGE_LOCAL'), + help='the SAGE_LOCAL path (default: the $SAGE_LOCAL ' + 'environment variable if set)') + parser.add_argument('-v', '--verbose', action='store_true', + help='verbose output showing all files removed') + parser.add_argument('--debug', action='store_true', help=argparse.SUPPRESS) + + return parser + + +def run(argv=None): + parser = make_parser() + + args = parser.parse_args(argv if argv is not None else sys.argv[1:]) + + if args.sage_local is None: + print('Error: SAGE_LOCAL must be specified either at the command ' + 'line or in the $SAGE_LOCAL environment variable', + file=sys.stderr) + sys.exit(1) + + try: + installcheck(args.spkg, args.sage_local, + verbose=args.verbose) + except Exception as exc: + print("Error during installcheck of '{0}': {1}".format( + args.spkg, exc), file=sys.stderr) + + if args.debug: + raise + + sys.exit(1) + + +if __name__ == '__main__': + run() From 243f985d99a83fabcf003d6fd8eb908123e47f47 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Jul 2022 17:21:31 -0700 Subject: [PATCH 135/742] build/pkgs/auditwheel_or_delocate: New --- build/pkgs/auditwheel_or_delocate/SPKG.rst | 22 +++++++++++++++++++ .../pkgs/auditwheel_or_delocate/dependencies | 4 ++++ .../auditwheel_or_delocate/requirements.txt | 2 ++ build/pkgs/auditwheel_or_delocate/type | 1 + 4 files changed, 29 insertions(+) create mode 100644 build/pkgs/auditwheel_or_delocate/SPKG.rst create mode 100644 build/pkgs/auditwheel_or_delocate/dependencies create mode 100644 build/pkgs/auditwheel_or_delocate/requirements.txt create mode 100644 build/pkgs/auditwheel_or_delocate/type diff --git a/build/pkgs/auditwheel_or_delocate/SPKG.rst b/build/pkgs/auditwheel_or_delocate/SPKG.rst new file mode 100644 index 00000000000..845a8da1c24 --- /dev/null +++ b/build/pkgs/auditwheel_or_delocate/SPKG.rst @@ -0,0 +1,22 @@ +auditwheel_or_delocate: Repair wheels on Linux or macOS +======================================================= + +Description +----------- + +This package represents auditwheel on Linux +and delocate on macOS. + +License +------- + +MIT + +BSD 2-clause + +Upstream Contact +---------------- + +https://pypi.org/project/auditwheel/ + +https://pypi.org/project/delocate/ diff --git a/build/pkgs/auditwheel_or_delocate/dependencies b/build/pkgs/auditwheel_or_delocate/dependencies new file mode 100644 index 00000000000..0738c2d7777 --- /dev/null +++ b/build/pkgs/auditwheel_or_delocate/dependencies @@ -0,0 +1,4 @@ +$(PYTHON) | $(PYTHON_TOOLCHAIN) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/auditwheel_or_delocate/requirements.txt b/build/pkgs/auditwheel_or_delocate/requirements.txt new file mode 100644 index 00000000000..365b7415e16 --- /dev/null +++ b/build/pkgs/auditwheel_or_delocate/requirements.txt @@ -0,0 +1,2 @@ +delocate; sys_platform == 'darwin' +auditwheel; sys_platform != 'darwin' diff --git a/build/pkgs/auditwheel_or_delocate/type b/build/pkgs/auditwheel_or_delocate/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/auditwheel_or_delocate/type @@ -0,0 +1 @@ +optional From 00ec17bfe4dab2e710f942c00e8a706de7f57d57 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Jul 2022 17:46:24 -0700 Subject: [PATCH 136/742] build/sage_bootstrap/installcheck.py: Implement for macOS --- build/sage_bootstrap/installcheck.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/sage_bootstrap/installcheck.py b/build/sage_bootstrap/installcheck.py index a6f350e424b..48d069a7205 100644 --- a/build/sage_bootstrap/installcheck.py +++ b/build/sage_bootstrap/installcheck.py @@ -72,14 +72,21 @@ def installcheck(spkg_name, sage_local, verbose=False): "'{0}'".format(spkg_name), file=sys.stderr) for f in files: + f = os.path.join(sage_local, f) if f.endswith(('.so', '.dylib')): if verbose: print("Checking shared library file '{0}'" .format(f), file=sys.stderr) + from delocate.libsana import _tree_libs_from_libraries, _filter_system_libs + _tree_libs_from_libraries([f], + lib_filt_func=_filter_system_libs, + copy_filt_func=lambda path: True) elif f.endswith('.whl'): if verbose: print("Checking wheel file '{0}'" .format(f), file=sys.stderr) + from delocate import wheel_libs + wheel_libs(f) def dir_type(path): From b2033b96d9d92258c74add5acb75f1007a319feb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Jul 2022 18:36:07 -0700 Subject: [PATCH 137/742] build/sage_bootstrap/installcheck.py: Do not warn if there are no files to check --- build/sage_bootstrap/installcheck.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/build/sage_bootstrap/installcheck.py b/build/sage_bootstrap/installcheck.py index 48d069a7205..d81f91f4601 100644 --- a/build/sage_bootstrap/installcheck.py +++ b/build/sage_bootstrap/installcheck.py @@ -67,9 +67,6 @@ def installcheck(spkg_name, sage_local, verbose=False): .format(spkg_name, sage_local), file=sys.stderr) else: files = spkg_meta['files'] - if not files: - print("Warning: No files to check for " - "'{0}'".format(spkg_name), file=sys.stderr) for f in files: f = os.path.join(sage_local, f) From eb4778041ca6529078a0455a1c575a2bf4cdb7b1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Jul 2022 18:36:30 -0700 Subject: [PATCH 138/742] build/sage_bootstrap/installcheck.py: Skip pure Python wheels --- build/sage_bootstrap/installcheck.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/sage_bootstrap/installcheck.py b/build/sage_bootstrap/installcheck.py index d81f91f4601..c452548f570 100644 --- a/build/sage_bootstrap/installcheck.py +++ b/build/sage_bootstrap/installcheck.py @@ -78,6 +78,9 @@ def installcheck(spkg_name, sage_local, verbose=False): _tree_libs_from_libraries([f], lib_filt_func=_filter_system_libs, copy_filt_func=lambda path: True) + elif f.endswith('-any.whl'): + # pure Python wheel, nothing to check + pass elif f.endswith('.whl'): if verbose: print("Checking wheel file '{0}'" From 30d9b5ff2523d19340db166e86faf3b48a6863a9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Jul 2022 18:36:47 -0700 Subject: [PATCH 139/742] build/make/Makefile.in (list-broken-packages): New --- build/make/Makefile.in | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/build/make/Makefile.in b/build/make/Makefile.in index c32b8d98554..42b041b69b5 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -391,6 +391,27 @@ _clean-broken-gcc: package=$${package%%-*}; \ $(MAKE) $$package-SAGE_LOCAL-uninstall $$package-SAGE_VENV-uninstall +list-broken-packages: auditwheel_or_delocate + @broken_packages=; \ + for tree in "$(SAGE_LOCAL)" "$(SAGE_VENV)"; do \ + for stampfile in $$tree/$(SPKG_INST_RELDIR)/*; do \ + if [ -s $$stampfile ]; then \ + echo 2>&1 "# Checking $$stampfile"; \ + package_with_version=$${stampfile##*/}; \ + package=$${package_with_version%-*}; \ + if ! $(SAGE_VENV)/bin/python3 $(SAGE_ROOT)/build/bin/sage-spkg-installcheck --verbose $$package $$tree; then \ + broken_packages="$$broken_packages $$package"; \ + echo $$package; \ + fi; \ + fi; \ + done; \ + done; \ + if [ -n "$$broken_packages" ]; then \ + echo 2>&1 "Uninstall broken packages by typing:"; \ + echo 2>&1 " make $$(for package in $$broken_packages; do echo $$package-clean; done)"; \ + fi + + #============================================================================== # Setting SAGE_CHECK... variables #============================================================================== From e6679a7ccd91afec50ba25feb29c41b8a673d3ec Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Jul 2022 18:58:16 -0700 Subject: [PATCH 140/742] build/sage_bootstrap/installcheck.py: Only warn when delocate is not available --- build/sage_bootstrap/installcheck.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/build/sage_bootstrap/installcheck.py b/build/sage_bootstrap/installcheck.py index c452548f570..d2c6821da3f 100644 --- a/build/sage_bootstrap/installcheck.py +++ b/build/sage_bootstrap/installcheck.py @@ -21,6 +21,7 @@ import subprocess import sys import argparse +from warnings import warn from .env import SAGE_ROOT @@ -74,10 +75,14 @@ def installcheck(spkg_name, sage_local, verbose=False): if verbose: print("Checking shared library file '{0}'" .format(f), file=sys.stderr) - from delocate.libsana import _tree_libs_from_libraries, _filter_system_libs - _tree_libs_from_libraries([f], - lib_filt_func=_filter_system_libs, - copy_filt_func=lambda path: True) + try: + from delocate.libsana import _tree_libs_from_libraries, _filter_system_libs + except ImportError: + warnings.warn('delocate is not available, so nothing is actually checked') + else: + _tree_libs_from_libraries([f], + lib_filt_func=_filter_system_libs, + copy_filt_func=lambda path: True) elif f.endswith('-any.whl'): # pure Python wheel, nothing to check pass @@ -85,8 +90,12 @@ def installcheck(spkg_name, sage_local, verbose=False): if verbose: print("Checking wheel file '{0}'" .format(f), file=sys.stderr) - from delocate import wheel_libs - wheel_libs(f) + try: + from delocate import wheel_libs + except ImportError: + warnings.warn('delocate is not available, so nothing is actually checked') + else: + wheel_libs(f) def dir_type(path): From 3d9448863b0cdfc5847d0aeb8ae675ccebc00b95 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Jul 2022 18:58:46 -0700 Subject: [PATCH 141/742] build/make/Makefile.in (list-broken-packages): Parallelize it --- build/make/Makefile.in | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/build/make/Makefile.in b/build/make/Makefile.in index 42b041b69b5..105ae4052af 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -391,24 +391,24 @@ _clean-broken-gcc: package=$${package%%-*}; \ $(MAKE) $$package-SAGE_LOCAL-uninstall $$package-SAGE_VENV-uninstall +%-installcheck: + @stampfile=$@; \ + stampfile=$${stampfile%-installcheck}; \ + if [ -s $$stampfile ]; then \ + echo >&2 "# Checking $$stampfile"; \ + package_with_version=$${stampfile##*/}; \ + package=$${package_with_version%%-*}; \ + if ! $(SAGE_VENV)/bin/python3 $(SAGE_ROOT)/build/bin/sage-spkg-installcheck --verbose $$package $$tree; then \ + broken_packages="$$broken_packages $$package"; \ + echo $$package; \ + fi; \ + fi; + list-broken-packages: auditwheel_or_delocate - @broken_packages=; \ - for tree in "$(SAGE_LOCAL)" "$(SAGE_VENV)"; do \ - for stampfile in $$tree/$(SPKG_INST_RELDIR)/*; do \ - if [ -s $$stampfile ]; then \ - echo 2>&1 "# Checking $$stampfile"; \ - package_with_version=$${stampfile##*/}; \ - package=$${package_with_version%-*}; \ - if ! $(SAGE_VENV)/bin/python3 $(SAGE_ROOT)/build/bin/sage-spkg-installcheck --verbose $$package $$tree; then \ - broken_packages="$$broken_packages $$package"; \ - echo $$package; \ - fi; \ - fi; \ - done; \ - done; \ + @broken_packages=$$($(MAKE) -s $(patsubst %,%-installcheck,$(wildcard $(SAGE_LOCAL)/$(SPKG_INST_RELDIR)/* $(SAGE_VENV)/$(SPKG_INST_RELDIR)/*))); \ if [ -n "$$broken_packages" ]; then \ - echo 2>&1 "Uninstall broken packages by typing:"; \ - echo 2>&1 " make $$(for package in $$broken_packages; do echo $$package-clean; done)"; \ + echo >&2 "Uninstall broken packages by typing:"; \ + echo >&2 " make -k $$(echo $$(for package in $$broken_packages; do echo $$package-clean; done))"; \ fi From 6881409206960ce37a2e1e29450a9c29fe61c1ec Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Jul 2022 20:03:24 -0700 Subject: [PATCH 142/742] build/make/Makefile.in (list-broken-packages): Show uninstallation commands that actually work --- build/make/Makefile.in | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/build/make/Makefile.in b/build/make/Makefile.in index 105ae4052af..e998518bc05 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -396,19 +396,26 @@ _clean-broken-gcc: stampfile=$${stampfile%-installcheck}; \ if [ -s $$stampfile ]; then \ echo >&2 "# Checking $$stampfile"; \ + tree=$${stampfile%%/$(SPKG_INST_RELDIR)/*}; \ package_with_version=$${stampfile##*/}; \ package=$${package_with_version%%-*}; \ - if ! $(SAGE_VENV)/bin/python3 $(SAGE_ROOT)/build/bin/sage-spkg-installcheck --verbose $$package $$tree; then \ - broken_packages="$$broken_packages $$package"; \ - echo $$package; \ + if ! $(SAGE_VENV)/bin/python3 $(SAGE_ROOT)/build/bin/sage-spkg-installcheck --verbose $$package; then \ + case "$$tree" in \ + "$(SAGE_LOCAL)") tree="";; \ + "$(SAGE_VENV)") tree="\\\$$SAGE_VENV";; \ + *) tree="$$tree";; \ + esac; \ + echo " ./sage --buildsh -c \"sage-spkg-uninstall $$package $$tree\";"; \ fi; \ fi; list-broken-packages: auditwheel_or_delocate - @broken_packages=$$($(MAKE) -s $(patsubst %,%-installcheck,$(wildcard $(SAGE_LOCAL)/$(SPKG_INST_RELDIR)/* $(SAGE_VENV)/$(SPKG_INST_RELDIR)/*))); \ - if [ -n "$$broken_packages" ]; then \ + @fix_broken_packages=$$($(MAKE) -s $(patsubst %,%-installcheck,$(wildcard $(SAGE_LOCAL)/$(SPKG_INST_RELDIR)/* $(SAGE_VENV)/$(SPKG_INST_RELDIR)/*))); \ + if [ -n "$$fix_broken_packages" ]; then \ + echo >&2 ; \ echo >&2 "Uninstall broken packages by typing:"; \ - echo >&2 " make -k $$(echo $$(for package in $$broken_packages; do echo $$package-clean; done))"; \ + echo >&2 ; \ + echo >&2 "$$fix_broken_packages"; \ fi From b5a7d05fd49da94e179b5b9c7e8ed00ff7c903a1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Jul 2022 20:33:05 -0700 Subject: [PATCH 143/742] build/make/Makefile.in (list-broken-packages): Use targets %-SAGE_LOCAL-uninstall, %-SAGE_VENV-uninstall when possible --- build/make/Makefile.in | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/build/make/Makefile.in b/build/make/Makefile.in index e998518bc05..1b0eea338d3 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -401,11 +401,10 @@ _clean-broken-gcc: package=$${package_with_version%%-*}; \ if ! $(SAGE_VENV)/bin/python3 $(SAGE_ROOT)/build/bin/sage-spkg-installcheck --verbose $$package; then \ case "$$tree" in \ - "$(SAGE_LOCAL)") tree="";; \ - "$(SAGE_VENV)") tree="\\\$$SAGE_VENV";; \ - *) tree="$$tree";; \ + "$(SAGE_LOCAL)") echo " make $$package-SAGE_LOCAL-uninstall;";; \ + "$(SAGE_VENV)") echo " make $$package-SAGE_VENV-uninstall;";; \ + *) echo " ./sage --buildsh -c \"sage-spkg-uninstall $$package $$tree\";";; \ esac; \ - echo " ./sage --buildsh -c \"sage-spkg-uninstall $$package $$tree\";"; \ fi; \ fi; From 6a73497b7a8d5148627643589921ca2549b4ea9b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Jul 2022 20:44:53 -0700 Subject: [PATCH 144/742] build/make/Makefile.in (list-broken-packages): Fix up --- build/make/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/make/Makefile.in b/build/make/Makefile.in index 1b0eea338d3..b00ec8bc1cb 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -399,7 +399,7 @@ _clean-broken-gcc: tree=$${stampfile%%/$(SPKG_INST_RELDIR)/*}; \ package_with_version=$${stampfile##*/}; \ package=$${package_with_version%%-*}; \ - if ! $(SAGE_VENV)/bin/python3 $(SAGE_ROOT)/build/bin/sage-spkg-installcheck --verbose $$package; then \ + if ! $(SAGE_VENV)/bin/python3 $(SAGE_ROOT)/build/bin/sage-spkg-installcheck --verbose $$package $$tree; then \ case "$$tree" in \ "$(SAGE_LOCAL)") echo " make $$package-SAGE_LOCAL-uninstall;";; \ "$(SAGE_VENV)") echo " make $$package-SAGE_VENV-uninstall;";; \ From 400eaee762e33cdc28c46ef7587d6f889c5cda22 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 21 Jul 2022 16:01:08 -0700 Subject: [PATCH 145/742] build/sage_bootstrap/installclean.py: Clarify that the sage_local argument is SAGE_LOCAL or SAGE_VENV --- build/sage_bootstrap/installcheck.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build/sage_bootstrap/installcheck.py b/build/sage_bootstrap/installcheck.py index d2c6821da3f..3a3238f5819 100644 --- a/build/sage_bootstrap/installcheck.py +++ b/build/sage_bootstrap/installcheck.py @@ -1,5 +1,5 @@ """ -Command-line script for checking an installed SPKG in $SAGE_LOCAL. +Command-line script for checking an installed SPKG in an installation tree ($SAGE_LOCAL, $SAGE_VENV). """ # **************************************************************************** @@ -32,8 +32,8 @@ def installcheck(spkg_name, sage_local, verbose=False): """ - Given a package name and path to SAGE_LOCAL, check the installation of the package - in SAGE_LOCAL. + Given a package name and path to an installation tree (SAGE_LOCAL or SAGE_VENV), + check the installation of the package in that tree. """ # The default path to this directory; however its value should be read @@ -137,7 +137,7 @@ def make_parser(): parser.add_argument('spkg', type=spkg_type, help='the spkg to check') parser.add_argument('sage_local', type=dir_type, nargs='?', default=os.environ.get('SAGE_LOCAL'), - help='the SAGE_LOCAL path (default: the $SAGE_LOCAL ' + help='the path of the installation tree (default: the $SAGE_LOCAL ' 'environment variable if set)') parser.add_argument('-v', '--verbose', action='store_true', help='verbose output showing all files removed') @@ -152,7 +152,7 @@ def run(argv=None): args = parser.parse_args(argv if argv is not None else sys.argv[1:]) if args.sage_local is None: - print('Error: SAGE_LOCAL must be specified either at the command ' + print('Error: An installation tree must be specified either at the command ' 'line or in the $SAGE_LOCAL environment variable', file=sys.stderr) sys.exit(1) From ef9226bc1717bc579bdeddfb84f77c158a6ce516 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 23 Jul 2022 14:53:06 -0700 Subject: [PATCH 146/742] build/sage_bootstrap/installcheck.py: Implement for Linux --- .../auditwheel_or_delocate/requirements.txt | 2 +- build/sage_bootstrap/installcheck.py | 60 +++++++++++++++---- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/build/pkgs/auditwheel_or_delocate/requirements.txt b/build/pkgs/auditwheel_or_delocate/requirements.txt index 365b7415e16..5d409e519cd 100644 --- a/build/pkgs/auditwheel_or_delocate/requirements.txt +++ b/build/pkgs/auditwheel_or_delocate/requirements.txt @@ -1,2 +1,2 @@ -delocate; sys_platform == 'darwin' +delocate auditwheel; sys_platform != 'darwin' diff --git a/build/sage_bootstrap/installcheck.py b/build/sage_bootstrap/installcheck.py index 3a3238f5819..83f28c07c6d 100644 --- a/build/sage_bootstrap/installcheck.py +++ b/build/sage_bootstrap/installcheck.py @@ -21,7 +21,7 @@ import subprocess import sys import argparse -from warnings import warn +import warnings from .env import SAGE_ROOT @@ -30,6 +30,16 @@ """Directory where all spkg sources are found.""" +def check_lib_auditwheel(f, verbose=False): + from auditwheel.lddtree import lddtree + for lib, info in lddtree(f)["libs"].items(): + if verbose: + print('- {0}: {1}'.format(lib, info["realpath"]), file=sys.stderr) + if info["realpath"] is None: + raise RuntimeError('Shared library {0} needed by {1} is not found' + .format(lib, f)) + + def installcheck(spkg_name, sage_local, verbose=False): """ Given a package name and path to an installation tree (SAGE_LOCAL or SAGE_VENV), @@ -75,14 +85,20 @@ def installcheck(spkg_name, sage_local, verbose=False): if verbose: print("Checking shared library file '{0}'" .format(f), file=sys.stderr) - try: - from delocate.libsana import _tree_libs_from_libraries, _filter_system_libs - except ImportError: - warnings.warn('delocate is not available, so nothing is actually checked') + if sys.platform == 'darwin': + try: + from delocate.libsana import _tree_libs_from_libraries, _filter_system_libs + except ImportError: + warnings.warn('delocate is not available, so nothing is actually checked') + else: + _tree_libs_from_libraries([f], + lib_filt_func=_filter_system_libs, + copy_filt_func=lambda path: True) else: - _tree_libs_from_libraries([f], - lib_filt_func=_filter_system_libs, - copy_filt_func=lambda path: True) + try: + check_lib_auditwheel(f, verbose=False) + except ImportError: + warnings.warn('auditwheel is not available, so nothing is actually checked') elif f.endswith('-any.whl'): # pure Python wheel, nothing to check pass @@ -90,12 +106,30 @@ def installcheck(spkg_name, sage_local, verbose=False): if verbose: print("Checking wheel file '{0}'" .format(f), file=sys.stderr) - try: - from delocate import wheel_libs - except ImportError: - warnings.warn('delocate is not available, so nothing is actually checked') + if sys.platform == 'darwin': + try: + from delocate import wheel_libs + except ImportError: + warnings.warn('delocate is not available, so nothing is actually checked') + else: + wheel_libs(f) else: - wheel_libs(f) + try: + from delocate.tmpdirs import TemporaryDirectory + from delocate.tools import zip2dir + except ImportError: + warnings.warn('delocate is not available, so nothing is actually checked') + else: + try: + with TemporaryDirectory() as tmpdir: + zip2dir(f, tmpdir) + for dirpath, dirnames, basenames in os.walk(tmpdir): + for base in basenames: + if base.endswith('.so'): + depending_path = os.path.realpath(os.path.join(dirpath, base)) + check_lib_auditwheel(depending_path, verbose=False) + except ImportError: + warnings.warn('auditwheel is not available, so nothing is actually checked') def dir_type(path): From 47b7146756157e7f6dc0fcc3df9898b7f706b542 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 25 Jul 2022 13:37:38 -0700 Subject: [PATCH 147/742] build/pkgs/sagemath_*/dependencies_check: Move test dependencies here --- build/pkgs/sagemath_categories/dependencies | 2 +- build/pkgs/sagemath_categories/dependencies_check | 1 + build/pkgs/sagemath_environment/dependencies | 2 +- build/pkgs/sagemath_environment/dependencies_check | 1 + build/pkgs/sagemath_repl/dependencies | 2 +- build/pkgs/sagemath_repl/dependencies_check | 1 + 6 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 build/pkgs/sagemath_categories/dependencies_check create mode 100644 build/pkgs/sagemath_environment/dependencies_check create mode 100644 build/pkgs/sagemath_repl/dependencies_check diff --git a/build/pkgs/sagemath_categories/dependencies b/build/pkgs/sagemath_categories/dependencies index 8084ffef958..b8d566d84de 100644 --- a/build/pkgs/sagemath_categories/dependencies +++ b/build/pkgs/sagemath_categories/dependencies @@ -1 +1 @@ -$(PYTHON) cysignals gmpy2 sagemath_objects | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig build $(and $(filter-out no,$(SAGE_CHECK_sagemath_categories)), tox sagemath_repl) +$(PYTHON) cysignals gmpy2 sagemath_objects | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig python_build diff --git a/build/pkgs/sagemath_categories/dependencies_check b/build/pkgs/sagemath_categories/dependencies_check new file mode 100644 index 00000000000..7d2fe6c3064 --- /dev/null +++ b/build/pkgs/sagemath_categories/dependencies_check @@ -0,0 +1 @@ +tox sagemath_repl diff --git a/build/pkgs/sagemath_environment/dependencies b/build/pkgs/sagemath_environment/dependencies index 942ea0d61e3..605611e7a21 100644 --- a/build/pkgs/sagemath_environment/dependencies +++ b/build/pkgs/sagemath_environment/dependencies @@ -1 +1 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) build $(and $(filter-out no,$(SAGE_CHECK_sagemath_environment)), tox) +$(PYTHON) | $(PYTHON_TOOLCHAIN) python_build diff --git a/build/pkgs/sagemath_environment/dependencies_check b/build/pkgs/sagemath_environment/dependencies_check new file mode 100644 index 00000000000..053148f8486 --- /dev/null +++ b/build/pkgs/sagemath_environment/dependencies_check @@ -0,0 +1 @@ +tox diff --git a/build/pkgs/sagemath_repl/dependencies b/build/pkgs/sagemath_repl/dependencies index fd34bf2ba44..6c22cd39e91 100644 --- a/build/pkgs/sagemath_repl/dependencies +++ b/build/pkgs/sagemath_repl/dependencies @@ -1 +1 @@ -$(PYTHON) sagemath_objects ipython | $(PYTHON_TOOLCHAIN) build $(and $(filter-out no,$(SAGE_CHECK_sagemath_repl)), tox) +$(PYTHON) sagemath_objects ipython | $(PYTHON_TOOLCHAIN) python_build diff --git a/build/pkgs/sagemath_repl/dependencies_check b/build/pkgs/sagemath_repl/dependencies_check new file mode 100644 index 00000000000..053148f8486 --- /dev/null +++ b/build/pkgs/sagemath_repl/dependencies_check @@ -0,0 +1 @@ +tox From 69488872662d969576005c7157deae166aea986d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 25 Jul 2022 15:33:51 -0700 Subject: [PATCH 148/742] build/pkgs/sagemath_repl/install-requires.txt: Add missing file --- build/pkgs/sagemath_repl/install-requires.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 build/pkgs/sagemath_repl/install-requires.txt diff --git a/build/pkgs/sagemath_repl/install-requires.txt b/build/pkgs/sagemath_repl/install-requires.txt new file mode 100644 index 00000000000..40b60fa7bd0 --- /dev/null +++ b/build/pkgs/sagemath_repl/install-requires.txt @@ -0,0 +1,2 @@ +# This file is updated on every release by the sage-update-version script +sagemath-repl ~= 9.7b6 From a5c1c0c2cd812b0d9c7c2ee9ce1a97d2d7d9e3b8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 25 Jul 2022 18:12:29 -0700 Subject: [PATCH 149/742] pkgs/sagemath-{categories,repl,objects}: Use sage -t --initial --- pkgs/sagemath-categories/tox.ini | 2 +- pkgs/sagemath-objects/tox.ini | 2 +- pkgs/sagemath-repl/tox.ini | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/sagemath-categories/tox.ini b/pkgs/sagemath-categories/tox.ini index 60cdfe4ca7c..85e0a6991de 100644 --- a/pkgs/sagemath-categories/tox.ini +++ b/pkgs/sagemath-categories/tox.ini @@ -33,7 +33,7 @@ commands = # Test that importing sage.categories.all initializes categories {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); from sage.categories.all import *; SimplicialComplexes(); FunctionFields()' - bash -c 'cd bin && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_categories --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' + bash -c 'cd bin && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --initial --environment=sage.all__sagemath_categories --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' [testenv:sagepython] passenv = diff --git a/pkgs/sagemath-objects/tox.ini b/pkgs/sagemath-objects/tox.ini index 727254cf844..1cce07df5a2 100644 --- a/pkgs/sagemath-objects/tox.ini +++ b/pkgs/sagemath-objects/tox.ini @@ -31,7 +31,7 @@ commands = {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); from sage.all__sagemath_objects import *' - #bash -c 'cd bin && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_objects --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' + #bash -c 'cd bin && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_objects --initial --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' [testenv:sagepython] passenv = diff --git a/pkgs/sagemath-repl/tox.ini b/pkgs/sagemath-repl/tox.ini index d766fa55f74..89da819d7fd 100644 --- a/pkgs/sagemath-repl/tox.ini +++ b/pkgs/sagemath-repl/tox.ini @@ -31,7 +31,7 @@ commands = # Beware of the treacherous non-src layout. "./sage/" shadows the installed sage package. {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); import sage.repl.all; import sage.doctest.all' - bash -c 'cd bin && SAGE_SRC=$({envpython} -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_repl --optional=sage $SAGE_SRC/sage/repl $SAGE_SRC/sage/doctest $SAGE_SRC/sage/misc/sage_input.py $SAGE_SRC/sage/misc/sage_eval.py || echo "(lots of doctest failures are expected)"' + bash -c 'cd bin && SAGE_SRC=$({envpython} -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_repl --initial --optional=sage $SAGE_SRC/sage/repl $SAGE_SRC/sage/doctest $SAGE_SRC/sage/misc/sage_input.py $SAGE_SRC/sage/misc/sage_eval.py || echo "(lots of doctest failures are expected)"' [testenv:sagepython] passenv = From a9eaae57c9cf70c8bc0ed2968beb584906134927 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 26 Jul 2022 15:32:29 -0700 Subject: [PATCH 150/742] tox.ini, build/bin/write-dockerfile.sh: Add 'tox -e docker-...-incremental' --- build/bin/write-dockerfile.sh | 22 +++++++++++++++++----- tox.ini | 7 ++++++- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/build/bin/write-dockerfile.sh b/build/bin/write-dockerfile.sh index bf3afa3947f..5de4a1987fe 100755 --- a/build/bin/write-dockerfile.sh +++ b/build/bin/write-dockerfile.sh @@ -34,6 +34,13 @@ echo "# to simplify writing scripts that customize this file" ADD="ADD $__CHOWN" RUN=RUN case $SYSTEM in + none) + # No system packages to install + cat < Date: Tue, 26 Jul 2022 16:40:40 -0700 Subject: [PATCH 151/742] tox.ini: Add comment --- tox.ini | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tox.ini b/tox.ini index 9e4b3e2338d..31c9441b0b6 100644 --- a/tox.ini +++ b/tox.ini @@ -7,6 +7,12 @@ # # This will do a complete build of the Sage distribution in a Docker container, which will take a while. # +# To do an incremental build based on the latest build of a beta version on GitHub Actions: +# +# $ tox -e docker-fedora-31-standard-incremental +# +# This will download a large (multi-gigabyte) Docker image from GitHub Packages (ghcr.io). +# # Specific 'make' targets can be given as additional arguments after "--". # For example, to only run the configuration phase: # From 4c0d7f50b18f78ce561eccfc3a6c1196887dc226 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 27 Jul 2022 00:53:11 -0700 Subject: [PATCH 152/742] tox.ini: Use FROM_DOCKER_REPOSITORY --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 31c9441b0b6..1de5af78246 100644 --- a/tox.ini +++ b/tox.ini @@ -148,7 +148,7 @@ passenv = docker: DOCKER_PUSH_REPOSITORY # If set, we symlink this file into {envdir}/.docker/; this can be used for providing credentials for pushing docker: DOCKER_CONFIG_FILE - docker-incremental: FROM_DOCKER_REPO + docker-incremental: FROM_DOCKER_REPOSITORY docker-incremental: FROM_DOCKER_TARGET docker-incremental: FROM_DOCKER_TAG local: MAKE @@ -457,7 +457,7 @@ setenv = # Resulting full image:tag name # docker: FULL_BASE_IMAGE_AND_TAG={env:ARCH_IMAGE_PREFIX:}{env:BASE_IMAGE}{env:ARCH_IMAGE_SUFFIX:}:{env:ARCH_TAG_PREFIX:}{env:BASE_TAG}{env:ARCH_TAG_SUFFIX:} - docker-incremental: FULL_BASE_IMAGE_AND_TAG={env:FROM_DOCKER_REPO:ghcr.io/sagemath/sage/sage-}$(echo {envname} | sed 's/-incremental//')-{env:FROM_DOCKER_TARGET:with-targets}:{env:FROM_DOCKER_TAG:dev} + docker-incremental: FULL_BASE_IMAGE_AND_TAG={env:FROM_DOCKER_REPOSITORY:ghcr.io/sagemath/sage/}sage-$(echo {envname} | sed 's/-incremental//')-{env:FROM_DOCKER_TARGET:with-targets}:{env:FROM_DOCKER_TAG:dev} docker-incremental: SYSTEM=none # docker-nobootstrap: BOOTSTRAP=./bootstrap -D From a07874d2f2443785cc0a295d2d8989ab380d79d2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 27 Jul 2022 09:56:20 -0700 Subject: [PATCH 153/742] build/bin/write-dockerfile.sh: In incremental build, keep logs --- build/bin/write-dockerfile.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/bin/write-dockerfile.sh b/build/bin/write-dockerfile.sh index 5de4a1987fe..0d207c68e52 100755 --- a/build/bin/write-dockerfile.sh +++ b/build/bin/write-dockerfile.sh @@ -220,7 +220,7 @@ cat < Date: Thu, 28 Jul 2022 15:09:16 -0700 Subject: [PATCH 154/742] tox.ini (docker-incremental): Do not include '-incremental' in the Docker image name --- tox.ini | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tox.ini b/tox.ini index 1de5af78246..b3188982a5f 100644 --- a/tox.ini +++ b/tox.ini @@ -636,9 +636,10 @@ commands = docker-{arm64,armhf}: docker run --rm --privileged multiarch/qemu-user-static:register --reset docker: bash -c 'if [ x"{env:DOCKER_CONFIG_FILE:}" != x ]; then mkdir -p {envdir}/.docker && ln -sf $(realpath "{env:DOCKER_CONFIG_FILE:}") {envdir}/.docker/; fi' docker: bash -c 'for docker_target in {env:DOCKER_TARGETS:with-targets}; do \ - docker: BUILD_IMAGE={env:DOCKER_PUSH_REPOSITORY:}sage-{envname}-$docker_target; \ - docker: BUILD_TAG=$BUILD_IMAGE:$(git describe --dirty --always); \ - docker: TAG_ARGS=$(echo --tag $BUILD_TAG; for tag in {env:EXTRA_DOCKER_TAGS:}; do echo --tag $BUILD_IMAGE:$tag; done); \ + docker: BUILD_IMAGE_STEM=sage-$(echo {envname} | sed s/-incremental//); \ + docker: BUILD_IMAGE=$DOCKER_PUSH_REPOSITORY$BUILD_IMAGE_STEM-$docker_target; \ + docker: BUILD_TAG=$(git describe --dirty --always); \ + docker: TAG_ARGS=$(for tag in $BUILD_TAG {env:EXTRA_DOCKER_TAGS:}; do echo --tag $BUILD_IMAGE:$tag; done); \ docker: DOCKER_BUILDKIT={env:DOCKER_BUILDKIT:0} \ docker: docker build . -f {envdir}/Dockerfile \ docker: --target $docker_target \ @@ -652,11 +653,11 @@ commands = docker: --build-arg TARGETS_OPTIONAL="{env:TARGETS_OPTIONAL:ptest}" \ docker: {env:EXTRA_DOCKER_BUILD_ARGS:}; status=$?; \ docker: if [ $status != 0 ]; then \ - docker: BUILD_TAG="$BUILD_TAG-failed"; docker commit $(docker ps -l -q) $BUILD_TAG; PUSH_TAGS=$BUILD_TAG; \ + docker: BUILD_TAG="$BUILD_TAG-failed"; docker commit $(docker ps -l -q) $BUILD_IMAGE:$BUILD_TAG; PUSH_TAGS=$BUILD_IMAGE:$BUILD_TAG; \ docker: else \ - docker: PUSH_TAGS=$(echo $BUILD_TAG; for tag in {env:EXTRA_DOCKER_TAGS:}; do echo "$BUILD_IMAGE:$tag"; done); \ + docker: PUSH_TAGS=$(echo $BUILD_IMAGE:$BUILD_TAG; for tag in {env:EXTRA_DOCKER_TAGS:}; do echo "$BUILD_IMAGE:$tag"; done); \ docker: fi; \ - docker: echo $BUILD_TAG >> {envdir}/Dockertags; \ + docker: echo $BUILD_IMAGE:$BUILD_TAG >> {envdir}/Dockertags; \ docker: if [ x"{env:DOCKER_PUSH_REPOSITORY:}" != x ]; then \ docker: echo Pushing $PUSH_TAGS; \ docker: for tag in $PUSH_TAGS; do \ From a627ce685f4ac30ba9660f66b24fae246209c5d1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 28 Jul 2022 19:04:22 -0700 Subject: [PATCH 155/742] src/sage/rings/qqbar.py (AlgebraicNumber_base._maxima_init_): New --- src/sage/rings/qqbar.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 7db32272b26..3c0830c23c7 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -4710,6 +4710,35 @@ def radical_expression(self): roots = candidates interval_field = interval_field.to_prec(interval_field.prec() * 2) + def _maxima_init_(self, I=None): + r""" + EXAMPLES:: + + sage: maxima(QQbar(sqrt(5/2))) + sqrt(5)/sqrt(2) + sage: maxima(AA(-sqrt(5))) + -sqrt(5) + sage: QQbar(sqrt(-2))._maxima_init_() + Traceback (most recent call last): + ... + NotImplementedError: conversion implemented only for square roots of nonnegative rationals + """ + try: + return self._rational_()._maxima_init_(I) + except ValueError: + pass + try: + square_QQ = (self ** 2)._rational_() + except ValueError: + raise NotImplementedError('conversion implemented only for square roots of nonnegative rationals') + else: + if square_QQ < 0: + raise NotImplementedError('conversion implemented only for square roots of nonnegative rationals') + if self >= 0: + return 'sqrt(' + square_QQ._maxima_init_() + ')' + else: + return '-sqrt(' + square_QQ._maxima_init_() + ')' + class AlgebraicNumber(AlgebraicNumber_base): r""" From 6204a76d0ec2cbc3cd350cd82f77b2b3ec8088c0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 28 Jul 2022 21:22:39 -0700 Subject: [PATCH 156/742] src/sage/rings/qqbar.py (AlgebraicNumber_base._maxima_init_): Fixup --- src/sage/rings/qqbar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 3c0830c23c7..eadc0689385 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -4724,7 +4724,7 @@ def _maxima_init_(self, I=None): NotImplementedError: conversion implemented only for square roots of nonnegative rationals """ try: - return self._rational_()._maxima_init_(I) + return self._rational_()._maxima_init_() except ValueError: pass try: From 3e560cf5b30377da9d3122427f81f9b0ef93c5c4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 28 Jul 2022 21:25:00 -0700 Subject: [PATCH 157/742] src/sage/rings/qqbar.py: Add doctest --- src/sage/rings/qqbar.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index eadc0689385..7da3e3fa415 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -4714,6 +4714,8 @@ def _maxima_init_(self, I=None): r""" EXAMPLES:: + sage: maxima(AA(7)) + 7 sage: maxima(QQbar(sqrt(5/2))) sqrt(5)/sqrt(2) sage: maxima(AA(-sqrt(5))) From 58f4cd1c63b7d7a8aee04de5d8c53a7fac27d061 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 28 Jul 2022 22:55:42 -0700 Subject: [PATCH 158/742] src/sage/rings/qqbar.py (AlgebraicNumber_base._maxima_init_): Generalize using radical_expression --- src/sage/rings/qqbar.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 7da3e3fa415..9e865493bf9 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -4717,29 +4717,26 @@ def _maxima_init_(self, I=None): sage: maxima(AA(7)) 7 sage: maxima(QQbar(sqrt(5/2))) - sqrt(5)/sqrt(2) + sqrt(10)/2 sage: maxima(AA(-sqrt(5))) -sqrt(5) - sage: QQbar(sqrt(-2))._maxima_init_() + sage: maxima(QQbar(sqrt(-2))) + sqrt(2)*%i + sage: maxima(AA(2+sqrt(5))) + sqrt(5)+2 + sage: maxima(QQ[x](x^7 - x - 1).roots(AA, False)[0]) Traceback (most recent call last): ... - NotImplementedError: conversion implemented only for square roots of nonnegative rationals + NotImplementedError: cannot find radical expression """ try: return self._rational_()._maxima_init_() except ValueError: pass - try: - square_QQ = (self ** 2)._rational_() - except ValueError: - raise NotImplementedError('conversion implemented only for square roots of nonnegative rationals') - else: - if square_QQ < 0: - raise NotImplementedError('conversion implemented only for square roots of nonnegative rationals') - if self >= 0: - return 'sqrt(' + square_QQ._maxima_init_() + ')' - else: - return '-sqrt(' + square_QQ._maxima_init_() + ')' + rad = self.radical_expression() + if isinstance(rad.parent(), sage.rings.abc.SymbolicRing): + return rad._maxima_init_() + raise NotImplementedError('cannot find radical expression') class AlgebraicNumber(AlgebraicNumber_base): From b354a3873b4c6fac29dee7bbd5fbf3ef6a35d8f5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 31 Jul 2022 22:22:22 -0700 Subject: [PATCH 159/742] tox.ini, .github/workflows/docker.yml: Reimplement -incremental via SKIP_SYSTEM_PACKAGES --- build/bin/write-dockerfile.sh | 105 +++++++++++++++------------------- tox.ini | 2 +- 2 files changed, 48 insertions(+), 59 deletions(-) diff --git a/build/bin/write-dockerfile.sh b/build/bin/write-dockerfile.sh index 0d207c68e52..98d422cbe98 100755 --- a/build/bin/write-dockerfile.sh +++ b/build/bin/write-dockerfile.sh @@ -33,25 +33,12 @@ echo "# the :comments: separate the generated file into sections" echo "# to simplify writing scripts that customize this file" ADD="ADD $__CHOWN" RUN=RUN -case $SYSTEM in - none) - # No system packages to install - cat < /bin/dash; # but some of the scripts in /opt/conda/etc/conda/activate.d # from conda-forge (as of 2020-01-27) contain bash-isms: @@ -173,11 +160,13 @@ EOF exit 1 ;; esac -case $SYSTEM in - none) - ;; - *) - cat < Date: Wed, 27 Jul 2022 17:46:14 -0700 Subject: [PATCH 160/742] build/bin/write-dockerfile.sh: Do not use persistent env var PACKAGES (except on nix) --- build/bin/write-dockerfile.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/bin/write-dockerfile.sh b/build/bin/write-dockerfile.sh index 98d422cbe98..85412cfb474 100755 --- a/build/bin/write-dockerfile.sh +++ b/build/bin/write-dockerfile.sh @@ -114,6 +114,7 @@ EOF cat < Date: Wed, 27 Jul 2022 18:28:52 -0700 Subject: [PATCH 161/742] tox.ini (ubuntu-jammy, debian-bookworm, fedora-35, fedora-36): Do not IGNORE_MISSING_SYSTEM_PACKAGES --- tox.ini | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index 61e4f19b09c..75e982a741c 100644 --- a/tox.ini +++ b/tox.ini @@ -211,7 +211,6 @@ setenv = ubuntu-bionic: IGNORE_MISSING_SYSTEM_PACKAGES=yes ubuntu-focal: BASE_TAG=focal ubuntu-jammy: BASE_TAG=jammy - ubuntu-jammy: IGNORE_MISSING_SYSTEM_PACKAGES=yes ubuntu-kinetic: BASE_TAG=kinetic ubuntu-kinetic: IGNORE_MISSING_SYSTEM_PACKAGES=yes # @@ -228,7 +227,6 @@ setenv = debian-bullseye: BASE_TAG=bullseye debian-bullseye: IGNORE_MISSING_SYSTEM_PACKAGES=yes debian-bookworm: BASE_TAG=bookworm - debian-bookworm: IGNORE_MISSING_SYSTEM_PACKAGES=yes debian-sid: BASE_TAG=sid # # https://hub.docker.com/u/linuxmintd @@ -268,9 +266,9 @@ setenv = fedora-34: BASE_TAG=34 fedora-34: IGNORE_MISSING_SYSTEM_PACKAGES=no fedora-35: BASE_TAG=35 - fedora-35: IGNORE_MISSING_SYSTEM_PACKAGES=yes + fedora-35: IGNORE_MISSING_SYSTEM_PACKAGES=no fedora-36: BASE_TAG=36 - fedora-36: IGNORE_MISSING_SYSTEM_PACKAGES=yes + fedora-36: IGNORE_MISSING_SYSTEM_PACKAGES=no fedora-37: BASE_TAG=37 fedora-37: IGNORE_MISSING_SYSTEM_PACKAGES=yes # From 326f61dc6ff96d15019954b55f4de87298f5e96c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 28 Jul 2022 16:40:37 -0700 Subject: [PATCH 162/742] Replace tox-optional, tox-experimental.yml by use of reusable workflow in ci-linux.yml --- .github/workflows/ci-linux.yml | 98 +++++++++++++++++++- .github/workflows/ci-macos.yml | 2 +- .github/workflows/docker.yml | 27 +++++- .github/workflows/tox-experimental.yml | 123 ------------------------- .github/workflows/tox-optional.yml | 123 ------------------------- build/bin/write-dockerfile.sh | 1 + tox.ini | 1 + 7 files changed, 125 insertions(+), 250 deletions(-) delete mode 100644 .github/workflows/tox-experimental.yml delete mode 100644 .github/workflows/tox-optional.yml diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index b405d335ab5..44471c39ca5 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -33,15 +33,111 @@ env: jobs: - docker: + docker-pre: uses: ./.github/workflows/docker.yml with: + # Build from scratch + docker_targets: "with-system-packages configured with-targets-pre" # FIXME: duplicated from env.TARGETS targets_pre: all-sage-local + tox_packages_factors: >- + ["minimal", + "standard", + "maximal", + ] + docker_push_repository: ghcr.io/${{ github.repository }}/ + + docker: + needs: [docker-pre] + uses: ./.github/workflows/docker.yml + with: + # Build incrementally from previous stage (docker-pre) + incremental: true + from_docker_repository: ghcr.io/${{ github.repository }}/ + from_docker_target: "with-targets-pre" + docker_targets: "with-targets with-targets-optional" + # FIXME: duplicated from env.TARGETS targets: build doc-html targets_optional: ptest docker_push_repository: ghcr.io/${{ github.repository }}/ + docker-optional-0-o: + needs: [docker-pre] + uses: ./.github/workflows/docker.yml + with: + incremental: true + from_docker_repository: ghcr.io/${{ github.repository }}/ + from_docker_target: "with-targets-pre" + tox_packages_factors: >- + ["maximal"] + docker_targets: "with-targets-optional" + targets_optional: >- + $( echo $(export PATH=build/bin:$PATH + && (for a in spkg-install.in spkg-install requirements.txt; do + sage-package list :optional: + --has-file $a + --no-file huge + --no-file has_nonfree_dependencies; + done) | grep -v ^_ | grep -v sagemath_doc | grep ^[0-o] ) ) + + docker-optional-p-z: + needs: [docker-pre] + uses: ./.github/workflows/docker.yml + with: + incremental: true + from_docker_repository: ghcr.io/${{ github.repository }}/ + from_docker_target: "with-targets-pre" + tox_packages_factors: >- + ["maximal"] + docker_targets: "with-targets-optional" + targets_optional: >- + $( echo $(export PATH=build/bin:$PATH + && (for a in spkg-install.in spkg-install requirements.txt; do + sage-package list :optional: + --has-file $a + --no-file huge + --no-file has_nonfree_dependencies; + done) | grep -v ^_ | grep -v sagemath_doc | grep ^[p-z] ) ) + + docker-experimental-0-o: + needs: [docker-pre] + uses: ./.github/workflows/docker.yml + with: + incremental: true + from_docker_repository: ghcr.io/${{ github.repository }}/ + from_docker_target: "with-targets-pre" + tox_packages_factors: >- + ["maximal"] + docker_targets: "with-targets-optional" + targets_optional: >- + $( echo $(export PATH=build/bin:$PATH + && (for a in spkg-install.in spkg-install requirements.txt; do + sage-package list :experimental: + --has-file $a + --no-file huge + --no-file has_nonfree_dependencies; + done) | grep -v ^_ | grep -v sagemath_doc | grep ^[0-o] ) ) + + docker-experimental-p-z: + needs: [docker-pre] + uses: ./.github/workflows/docker.yml + with: + incremental: true + from_docker_repository: ghcr.io/${{ github.repository }}/ + from_docker_target: "with-targets-pre" + tox_packages_factors: >- + ["maximal"] + docker_targets: "with-targets-optional" + targets_optional: >- + $( echo $(export PATH=build/bin:$PATH + && (for a in spkg-install.in spkg-install requirements.txt; do + sage-package list :experimental: + --has-file $a + --no-file huge + --no-file has_nonfree_dependencies; + done) | grep -v ^_ | grep -v sagemath_doc | grep ^[p-z] ) ) + + local-ubuntu: runs-on: ubuntu-latest diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml index 49b97aa6e08..54edd8fdb5f 100644 --- a/.github/workflows/ci-macos.yml +++ b/.github/workflows/ci-macos.yml @@ -76,7 +76,7 @@ jobs: # For doctesting, we use a lower parallelization to avoid timeouts. run: | case "${{ matrix.stage }}" in - 1) export TARGETS_PRE="all-sage-local" TARGETS="all-sage-local" TARGETS_OPTIONAL="" + 1) export TARGETS_PRE="all-sage-local" TARGETS="all-sage-local" TARGETS_OPTIONAL="build/make/Makefile" ;; 2) export TARGETS_PRE="all-sage-local" TARGETS="build doc-html" TARGETS_OPTIONAL="ptest" ;; diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 23cab40539d..b9d96a87890 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -76,6 +76,25 @@ on: required: false type: string # + # Incremental builds + # + docker_targets: + default: "with-system-packages configured with-targets-pre with-targets with-targets-optional" + type: string + incremental: + default: false + type: boolean + from_docker_repository: + required: false + type: string + from_docker_target: + required: false + type: string + from_docker_tag: + required: false + default: "$BUILD_TAG" + type: string + # # For use in upstream CIs # upstream_artifact: @@ -104,12 +123,16 @@ jobs: tox_system_factor: ${{ fromJson(inputs.tox_system_factors) }} tox_packages_factor: ${{ fromJson(inputs.tox_packages_factors) }} env: - TOX_ENV: docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} + TOX_ENV: "docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }}${{ inputs.incremental && '-incremental' || '' }}" LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-tox-docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} - DOCKER_TARGETS: with-system-packages configured with-targets-pre with-targets with-targets-optional + DOCKER_TARGETS: ${{ inputs.docker_targets }} TARGETS_PRE: ${{ inputs.targets_pre }} TARGETS: ${{ inputs.targets }} TARGETS_OPTIONAL: ${{ inputs.targets_optional }} + FROM_DOCKER_REPOSITORY: ${{ inputs.from_docker_repository }} + FROM_DOCKER_TARGET: ${{ inputs.from_docker_target }} + FROM_DOCKER_TAG: ${{ inputs.from_docker_tag }} + steps: - name: Check out SageMath uses: actions/checkout@v2 diff --git a/.github/workflows/tox-experimental.yml b/.github/workflows/tox-experimental.yml deleted file mode 100644 index 3abeec4a775..00000000000 --- a/.github/workflows/tox-experimental.yml +++ /dev/null @@ -1,123 +0,0 @@ -name: Test experimental packages with tox - -## This GitHub Actions workflow runs SAGE_ROOT/tox.ini with select environments, -## whenever a GitHub pull request is opened or synchronized in a repository -## where GitHub Actions are enabled. -## -## It builds and checks some sage spkgs as defined in TARGETS. -## -## A job succeeds if there is no error. -## -## The build is run with "make V=0", so the build logs of individual packages are suppressed. -## -## At the end, all package build logs that contain an error are printed out. -## -## After all jobs have finished (or are canceled) and a short delay, -## tar files of all logs are made available as "build artifacts". - -#on: [push, pull_request] - -on: - pull_request: - types: [opened, synchronize] - push: - tags: - - '*' - workflow_dispatch: - # Allow to run manually - -env: - TARGETS_PRE: build/make/Makefile - TARGETS: build/make/Makefile - # TARGETS_OPTIONAL see below - -jobs: - docker: - runs-on: ubuntu-latest - strategy: - fail-fast: false - max-parallel: 6 - matrix: - tox_system_factor: [ubuntu-trusty-toolchain-gcc_9, ubuntu-xenial-toolchain-gcc_9, ubuntu-bionic, ubuntu-focal, ubuntu-jammy, ubuntu-kinetic, debian-stretch, debian-buster, debian-bullseye, debian-bookworm, debian-sid, linuxmint-19, linuxmint-19.3, linuxmint-20.1, linuxmint-20.2, linuxmint-20.3, linuxmint-21, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, fedora-35, fedora-36, fedora-37, centos-7-devtoolset-gcc_11, centos-stream-8, gentoo-python3.9, gentoo-python3.10, archlinux-latest, opensuse-15.3, opensuse-tumbleweed, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-i386-devtoolset-gcc_11] - tox_packages_factor: [maximal] - targets_pattern: [0-g, h-o, p, q-z] - env: - TOX_ENV: docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} - LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-tox-docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} - DOCKER_TARGETS: configured with-targets with-targets-optional - # Test all non-dummy experimental packages, but do not test huge packages - # and do not test packages that require external software - TARGETS_OPTIONAL: "$( echo $(export PATH=build/bin:$PATH && (for a in spkg-install.in spkg-install requirements.txt; do sage-package list :experimental: --has-file $a --no-file huge --no-file has_nonfree_dependencies; done) | grep -v ^_ | grep -v sagemath_doc | grep '^[${{ matrix.targets_pattern }}]' ) )" - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 500 - - name: fetch tags - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* - - name: free disk space - run: | - df -h - sudo swapoff -a - sudo rm -f /swapfile - sudo apt-get clean - docker rmi $(docker image ls -aq) - echo "Largest packages:" - dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -n | tail -n 50 - sudo apt-get --fix-broken --yes remove $(dpkg-query -f '${Package}\n' -W | grep -E '^(ghc-|google-cloud-sdk|google-chrome|firefox|mysql-server|dotnet-sdk|hhvm|mono)') || echo "(error ignored)" - df -h - - name: Install test prerequisites - run: | - sudo DEBIAN_FRONTEND=noninteractive apt-get update - sudo DEBIAN_FRONTEND=noninteractive apt-get install tox - sudo apt-get clean - df -h - - name: Try to login to ghcr.io - # https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable - run: | - TOKEN="${{ secrets.DOCKER_PKG_GITHUB_TOKEN }}" - if [ -z "$TOKEN" ]; then - TOKEN="${{ secrets.GITHUB_TOKEN }}" - fi - if echo "$TOKEN" | docker login ghcr.io -u ${{ github.actor }} --password-stdin; then - echo "DOCKER_PUSH_REPOSITORY=ghcr.io/${{ github.repository }}/" >> $GITHUB_ENV - echo "DOCKER_CONFIG_FILE=$HOME/.docker/config.json" >> $GITHUB_ENV - fi - # From the docker documentation via .ci/update-env.sh: - # "A tag name must be valid ASCII and may - # contain lowercase and uppercase letters, digits, underscores, periods and - # dashes. A tag name may not start with a period or a dash and may contain a - # maximum of 128 characters." - EXTRA_DOCKER_TAGS=`echo $GITHUB_REF_NAME | tr -d '[:space:]' | tr -c '[:alnum:]_.-' '-' | sed 's/^[-.]*//' | cut -c1-128` - shopt -s extglob - case "$GITHUB_REF_NAME" in - +([0-9]).+([0-9])?(.+([0-9])) ) - EXTRA_DOCKER_TAGS="latest dev $EXTRA_DOCKER_TAGS";; - +([0-9]).+([0-9])?(.+([0-9])).@(beta|rc)+([0-9]) ) - EXTRA_DOCKER_TAGS="dev $EXTRA_DOCKER_TAGS";; - esac - echo "EXTRA_DOCKER_TAGS=$EXTRA_DOCKER_TAGS" >> $GITHUB_ENV - - run: | - set -o pipefail; EXTRA_DOCKER_BUILD_ARGS="--build-arg USE_MAKEFLAGS=\"-k V=0 SAGE_NUM_THREADS=3\"" tox -e $TOX_ENV -- $TARGETS 2>&1 | sed "/^configure: notice:/s|^|::warning file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;/^configure: warning:/s|^|::warning file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;/^configure: error:/s|^|::error file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;" - - name: Copy logs from the docker image or build container - run: | - mkdir -p "artifacts/$LOGS_ARTIFACT_NAME" - cp -r .tox/$TOX_ENV/Dockerfile .tox/$TOX_ENV/log "artifacts/$LOGS_ARTIFACT_NAME" - if [ -f .tox/$TOX_ENV/Dockertags ]; then CONTAINERS=$(docker create $(tail -1 .tox/$TOX_ENV/Dockertags) /bin/bash || true); fi - if [ -n "$CONTAINERS" ]; then for CONTAINER in $CONTAINERS; do for ARTIFACT in /sage/logs; do docker cp $CONTAINER:$ARTIFACT artifacts/$LOGS_ARTIFACT_NAME && HAVE_LOG=1; done; if [ -n "$HAVE_LOG" ]; then break; fi; done; fi - if: always() - - uses: actions/upload-artifact@v1 - with: - path: artifacts - name: ${{ env.LOGS_ARTIFACT_NAME }} - if: always() - - name: Print out logs for immediate inspection - # and markup the output with GitHub Actions logging commands - run: | - .github/workflows/scan-logs.sh "artifacts/$LOGS_ARTIFACT_NAME" - if: always() - - name: List docker images - run: | - if [ -f .tox/$TOX_ENV/Dockertags ]; then - cat .tox/$TOX_ENV/Dockertags - fi - if: always() diff --git a/.github/workflows/tox-optional.yml b/.github/workflows/tox-optional.yml deleted file mode 100644 index 72b63ef61c3..00000000000 --- a/.github/workflows/tox-optional.yml +++ /dev/null @@ -1,123 +0,0 @@ -name: Test optional packages with tox - -## This GitHub Actions workflow runs SAGE_ROOT/tox.ini with select environments, -## whenever a GitHub pull request is opened or synchronized in a repository -## where GitHub Actions are enabled. -## -## It builds and checks some sage spkgs as defined in TARGETS. -## -## A job succeeds if there is no error. -## -## The build is run with "make V=0", so the build logs of individual packages are suppressed. -## -## At the end, all package build logs that contain an error are printed out. -## -## After all jobs have finished (or are canceled) and a short delay, -## tar files of all logs are made available as "build artifacts". - -#on: [push, pull_request] - -on: - pull_request: - types: [opened, synchronize] - push: - tags: - - '*' - workflow_dispatch: - # Allow to run manually - -env: - TARGETS_PRE: build/make/Makefile - TARGETS: build/make/Makefile - # TARGETS_OPTIONAL see below - -jobs: - docker: - runs-on: ubuntu-latest - strategy: - fail-fast: false - max-parallel: 6 - matrix: - tox_system_factor: [ubuntu-trusty-toolchain-gcc_9, ubuntu-xenial-toolchain-gcc_9, ubuntu-bionic, ubuntu-focal, ubuntu-jammy, ubuntu-kinetic, debian-stretch, debian-buster, debian-bullseye, debian-bookworm, debian-sid, linuxmint-19, linuxmint-19.3, linuxmint-20.1, linuxmint-20.2, linuxmint-20.3, linuxmint-21, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, fedora-35, fedora-36, fedora-37, centos-7-devtoolset-gcc_11, centos-stream-8, gentoo-python3.9, gentoo-python3.10, archlinux-latest, opensuse-15.3, opensuse-tumbleweed, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-i386-devtoolset-gcc_11] - tox_packages_factor: [maximal] - targets_pattern: [0-g, h-o, p, q-z] - env: - TOX_ENV: docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} - LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-tox-docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} - DOCKER_TARGETS: configured with-targets with-targets-optional - # Test all non-dummy optional packages, but do not test huge packages - # and do not test packages that require external software - TARGETS_OPTIONAL: "$( echo $(export PATH=build/bin:$PATH && (for a in spkg-install.in spkg-install requirements.txt; do sage-package list :optional: --has-file $a --no-file huge --no-file has_nonfree_dependencies; done) | grep -v ^_ | grep -v sagemath_doc | grep '^[${{ matrix.targets_pattern }}]' ) )" - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 500 - - name: fetch tags - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* - - name: free disk space - run: | - df -h - sudo swapoff -a - sudo rm -f /swapfile - sudo apt-get clean - docker rmi $(docker image ls -aq) - echo "Largest packages:" - dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -n | tail -n 50 - sudo apt-get --fix-broken --yes remove $(dpkg-query -f '${Package}\n' -W | grep -E '^(ghc-|google-cloud-sdk|google-chrome|firefox|mysql-server|dotnet-sdk|hhvm|mono)') || echo "(error ignored)" - df -h - - name: Install test prerequisites - run: | - sudo DEBIAN_FRONTEND=noninteractive apt-get update - sudo DEBIAN_FRONTEND=noninteractive apt-get install tox - sudo apt-get clean - df -h - - name: Try to login to ghcr.io - # https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable - run: | - TOKEN="${{ secrets.DOCKER_PKG_GITHUB_TOKEN }}" - if [ -z "$TOKEN" ]; then - TOKEN="${{ secrets.GITHUB_TOKEN }}" - fi - if echo "$TOKEN" | docker login ghcr.io -u ${{ github.actor }} --password-stdin; then - echo "DOCKER_PUSH_REPOSITORY=ghcr.io/${{ github.repository }}/" >> $GITHUB_ENV - echo "DOCKER_CONFIG_FILE=$HOME/.docker/config.json" >> $GITHUB_ENV - fi - # From the docker documentation via .ci/update-env.sh: - # "A tag name must be valid ASCII and may - # contain lowercase and uppercase letters, digits, underscores, periods and - # dashes. A tag name may not start with a period or a dash and may contain a - # maximum of 128 characters." - EXTRA_DOCKER_TAGS=`echo $GITHUB_REF_NAME | tr -d '[:space:]' | tr -c '[:alnum:]_.-' '-' | sed 's/^[-.]*//' | cut -c1-128` - shopt -s extglob - case "$GITHUB_REF_NAME" in - +([0-9]).+([0-9])?(.+([0-9])) ) - EXTRA_DOCKER_TAGS="latest dev $EXTRA_DOCKER_TAGS";; - +([0-9]).+([0-9])?(.+([0-9])).@(beta|rc)+([0-9]) ) - EXTRA_DOCKER_TAGS="dev $EXTRA_DOCKER_TAGS";; - esac - echo "EXTRA_DOCKER_TAGS=$EXTRA_DOCKER_TAGS" >> $GITHUB_ENV - - run: | - set -o pipefail; EXTRA_DOCKER_BUILD_ARGS="--build-arg USE_MAKEFLAGS=\"-k V=0 SAGE_NUM_THREADS=3\"" tox -e $TOX_ENV -- $TARGETS 2>&1 | sed "/^configure: notice:/s|^|::warning file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;/^configure: warning:/s|^|::warning file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;/^configure: error:/s|^|::error file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;" - - name: Copy logs from the docker image or build container - run: | - mkdir -p "artifacts/$LOGS_ARTIFACT_NAME" - cp -r .tox/$TOX_ENV/Dockerfile .tox/$TOX_ENV/log "artifacts/$LOGS_ARTIFACT_NAME" - if [ -f .tox/$TOX_ENV/Dockertags ]; then CONTAINERS=$(docker create $(tail -1 .tox/$TOX_ENV/Dockertags) /bin/bash || true); fi - if [ -n "$CONTAINERS" ]; then for CONTAINER in $CONTAINERS; do for ARTIFACT in /sage/logs; do docker cp $CONTAINER:$ARTIFACT artifacts/$LOGS_ARTIFACT_NAME && HAVE_LOG=1; done; if [ -n "$HAVE_LOG" ]; then break; fi; done; fi - if: always() - - uses: actions/upload-artifact@v1 - with: - path: artifacts - name: ${{ env.LOGS_ARTIFACT_NAME }} - if: always() - - name: Print out logs for immediate inspection - # and markup the output with GitHub Actions logging commands - run: | - .github/workflows/scan-logs.sh "artifacts/$LOGS_ARTIFACT_NAME" - if: always() - - name: List docker images - run: | - if [ -f .tox/$TOX_ENV/Dockertags ]; then - cat .tox/$TOX_ENV/Dockertags - fi - if: always() diff --git a/build/bin/write-dockerfile.sh b/build/bin/write-dockerfile.sh index 85412cfb474..0653c164a06 100755 --- a/build/bin/write-dockerfile.sh +++ b/build/bin/write-dockerfile.sh @@ -129,6 +129,7 @@ EOF ;; opensuse*) UPDATE="zypper refresh &&" + EXISTS="zypper --quiet install --no-confirm --auto-agree-with-licenses --no-recommends --download-only > /dev/null" INSTALL="zypper --ignore-unknown install --no-confirm --auto-agree-with-licenses --no-recommends --details" ;; conda*) diff --git a/tox.ini b/tox.ini index 75e982a741c..917b9254d09 100644 --- a/tox.ini +++ b/tox.ini @@ -141,6 +141,7 @@ passenv = docker: EXTRA_DOCKER_TAGS # Use DOCKER_BUILDKIT=1 for new version - for which unfortunately we cannot save failed builds as an image docker: DOCKER_BUILDKIT + docker: BUILDKIT_INLINE_CACHE # Set for example to "with-system-packages configured with-targets-pre with-targets" # to tag intermediate images. docker: DOCKER_TARGETS From 31c4722cb7f540f517d8dab60d67c5f173db42a4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 29 Jul 2022 03:26:59 -0700 Subject: [PATCH 163/742] .github/workflows/ci-linux.yml: Run following stages even when a job in the previous stage fails --- .github/workflows/ci-linux.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index 44471c39ca5..70585815747 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -48,6 +48,7 @@ jobs: docker_push_repository: ghcr.io/${{ github.repository }}/ docker: + if: ${{ always() }} needs: [docker-pre] uses: ./.github/workflows/docker.yml with: @@ -62,6 +63,7 @@ jobs: docker_push_repository: ghcr.io/${{ github.repository }}/ docker-optional-0-o: + if: ${{ always() }} needs: [docker-pre] uses: ./.github/workflows/docker.yml with: @@ -81,6 +83,7 @@ jobs: done) | grep -v ^_ | grep -v sagemath_doc | grep ^[0-o] ) ) docker-optional-p-z: + if: ${{ always() }} needs: [docker-pre] uses: ./.github/workflows/docker.yml with: @@ -100,6 +103,7 @@ jobs: done) | grep -v ^_ | grep -v sagemath_doc | grep ^[p-z] ) ) docker-experimental-0-o: + if: ${{ always() }} needs: [docker-pre] uses: ./.github/workflows/docker.yml with: @@ -119,6 +123,7 @@ jobs: done) | grep -v ^_ | grep -v sagemath_doc | grep ^[0-o] ) ) docker-experimental-p-z: + if: ${{ always() }} needs: [docker-pre] uses: ./.github/workflows/docker.yml with: From a6ee7a59e10f0be55c84bac109c0739f163e3968 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 29 Jul 2022 18:21:17 -0700 Subject: [PATCH 164/742] .github/workflows/ci-linux.yml: Use success() || failure() --- .github/workflows/ci-linux.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index 70585815747..4f740dc1f36 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -48,7 +48,7 @@ jobs: docker_push_repository: ghcr.io/${{ github.repository }}/ docker: - if: ${{ always() }} + if: ${{ success() || failure() }} needs: [docker-pre] uses: ./.github/workflows/docker.yml with: @@ -63,7 +63,7 @@ jobs: docker_push_repository: ghcr.io/${{ github.repository }}/ docker-optional-0-o: - if: ${{ always() }} + if: ${{ success() || failure() }} needs: [docker-pre] uses: ./.github/workflows/docker.yml with: @@ -83,7 +83,7 @@ jobs: done) | grep -v ^_ | grep -v sagemath_doc | grep ^[0-o] ) ) docker-optional-p-z: - if: ${{ always() }} + if: ${{ success() || failure() }} needs: [docker-pre] uses: ./.github/workflows/docker.yml with: @@ -103,7 +103,7 @@ jobs: done) | grep -v ^_ | grep -v sagemath_doc | grep ^[p-z] ) ) docker-experimental-0-o: - if: ${{ always() }} + if: ${{ success() || failure() }} needs: [docker-pre] uses: ./.github/workflows/docker.yml with: @@ -123,7 +123,7 @@ jobs: done) | grep -v ^_ | grep -v sagemath_doc | grep ^[0-o] ) ) docker-experimental-p-z: - if: ${{ always() }} + if: ${{ success() || failure() }} needs: [docker-pre] uses: ./.github/workflows/docker.yml with: From f2b52ef90dfd97128c2f458d5fe5c2dd6cf188e3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 30 Jul 2022 09:28:30 -0700 Subject: [PATCH 165/742] .github/workflows/ci-linux.yml: First run all 'standard' jobs, then 'minimal', ... --- .github/workflows/ci-linux.yml | 65 ++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index 4f740dc1f36..ce19a0c4e86 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -33,7 +33,7 @@ env: jobs: - docker-pre: + docker-pre-standard: uses: ./.github/workflows/docker.yml with: # Build from scratch @@ -41,15 +41,12 @@ jobs: # FIXME: duplicated from env.TARGETS targets_pre: all-sage-local tox_packages_factors: >- - ["minimal", - "standard", - "maximal", - ] + ["standard"] docker_push_repository: ghcr.io/${{ github.repository }}/ - docker: + docker-standard: if: ${{ success() || failure() }} - needs: [docker-pre] + needs: [docker-pre-standard] uses: ./.github/workflows/docker.yml with: # Build incrementally from previous stage (docker-pre) @@ -60,11 +57,57 @@ jobs: # FIXME: duplicated from env.TARGETS targets: build doc-html targets_optional: ptest + tox_packages_factors: >- + ["standard"] + docker_push_repository: ghcr.io/${{ github.repository }}/ + + docker-pre-minimal: + if: ${{ success() || failure() }} + # It does not really "need" it. + needs: [docker-standard] + uses: ./.github/workflows/docker.yml + with: + # Build from scratch + docker_targets: "with-system-packages configured with-targets-pre" + # FIXME: duplicated from env.TARGETS + targets_pre: all-sage-local + tox_packages_factors: >- + ["minimal"] + docker_push_repository: ghcr.io/${{ github.repository }}/ + + docker-minimal: + if: ${{ success() || failure() }} + needs: [docker-pre-minimal] + uses: ./.github/workflows/docker.yml + with: + # Build incrementally from previous stage (docker-pre) + incremental: true + from_docker_repository: ghcr.io/${{ github.repository }}/ + from_docker_target: "with-targets-pre" + docker_targets: "with-targets with-targets-optional" + # FIXME: duplicated from env.TARGETS + targets: build doc-html + targets_optional: ptest + tox_packages_factors: >- + ["minimal] + docker_push_repository: ghcr.io/${{ github.repository }}/ + + docker-pre-maximal: + if: ${{ success() || failure() }} + needs: [docker-minimal] + uses: ./.github/workflows/docker.yml + with: + # Build from scratch + docker_targets: "with-system-packages configured with-targets-pre" + # FIXME: duplicated from env.TARGETS + targets_pre: all-sage-local + tox_packages_factors: >- + ["maximal"] docker_push_repository: ghcr.io/${{ github.repository }}/ docker-optional-0-o: if: ${{ success() || failure() }} - needs: [docker-pre] + needs: [docker-pre-maximal] uses: ./.github/workflows/docker.yml with: incremental: true @@ -84,7 +127,7 @@ jobs: docker-optional-p-z: if: ${{ success() || failure() }} - needs: [docker-pre] + needs: [docker-optional-0-o] uses: ./.github/workflows/docker.yml with: incremental: true @@ -104,7 +147,7 @@ jobs: docker-experimental-0-o: if: ${{ success() || failure() }} - needs: [docker-pre] + needs: [docker-optional-p-z] uses: ./.github/workflows/docker.yml with: incremental: true @@ -124,7 +167,7 @@ jobs: docker-experimental-p-z: if: ${{ success() || failure() }} - needs: [docker-pre] + needs: [docker-experimental-0-o] uses: ./.github/workflows/docker.yml with: incremental: true From ca6d16398420c242228656c04373b7e920684100 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 30 Jul 2022 09:45:21 -0700 Subject: [PATCH 166/742] .github/workflows/ci-linux.yml: Rename stages --- .github/workflows/ci-linux.yml | 38 +++++++++++++++++----------------- .github/workflows/docker.yml | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index ce19a0c4e86..c0df79de3a5 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -33,7 +33,7 @@ env: jobs: - docker-pre-standard: + standard-pre: uses: ./.github/workflows/docker.yml with: # Build from scratch @@ -44,12 +44,12 @@ jobs: ["standard"] docker_push_repository: ghcr.io/${{ github.repository }}/ - docker-standard: + standard: if: ${{ success() || failure() }} - needs: [docker-pre-standard] + needs: [standard-pre] uses: ./.github/workflows/docker.yml with: - # Build incrementally from previous stage (docker-pre) + # Build incrementally from previous stage (pre) incremental: true from_docker_repository: ghcr.io/${{ github.repository }}/ from_docker_target: "with-targets-pre" @@ -61,10 +61,10 @@ jobs: ["standard"] docker_push_repository: ghcr.io/${{ github.repository }}/ - docker-pre-minimal: + minimal-pre: if: ${{ success() || failure() }} # It does not really "need" it. - needs: [docker-standard] + needs: [standard] uses: ./.github/workflows/docker.yml with: # Build from scratch @@ -75,12 +75,12 @@ jobs: ["minimal"] docker_push_repository: ghcr.io/${{ github.repository }}/ - docker-minimal: + minimal: if: ${{ success() || failure() }} - needs: [docker-pre-minimal] + needs: [minimal-pre] uses: ./.github/workflows/docker.yml with: - # Build incrementally from previous stage (docker-pre) + # Build incrementally from previous stage (pre) incremental: true from_docker_repository: ghcr.io/${{ github.repository }}/ from_docker_target: "with-targets-pre" @@ -92,9 +92,9 @@ jobs: ["minimal] docker_push_repository: ghcr.io/${{ github.repository }}/ - docker-pre-maximal: + maximal-pre: if: ${{ success() || failure() }} - needs: [docker-minimal] + needs: [minimal] uses: ./.github/workflows/docker.yml with: # Build from scratch @@ -105,9 +105,9 @@ jobs: ["maximal"] docker_push_repository: ghcr.io/${{ github.repository }}/ - docker-optional-0-o: + optional-0-o: if: ${{ success() || failure() }} - needs: [docker-pre-maximal] + needs: [maximal-pre] uses: ./.github/workflows/docker.yml with: incremental: true @@ -125,9 +125,9 @@ jobs: --no-file has_nonfree_dependencies; done) | grep -v ^_ | grep -v sagemath_doc | grep ^[0-o] ) ) - docker-optional-p-z: + optional-p-z: if: ${{ success() || failure() }} - needs: [docker-optional-0-o] + needs: [optional-0-o] uses: ./.github/workflows/docker.yml with: incremental: true @@ -145,9 +145,9 @@ jobs: --no-file has_nonfree_dependencies; done) | grep -v ^_ | grep -v sagemath_doc | grep ^[p-z] ) ) - docker-experimental-0-o: + experimental-0-o: if: ${{ success() || failure() }} - needs: [docker-optional-p-z] + needs: [optional-p-z] uses: ./.github/workflows/docker.yml with: incremental: true @@ -165,9 +165,9 @@ jobs: --no-file has_nonfree_dependencies; done) | grep -v ^_ | grep -v sagemath_doc | grep ^[0-o] ) ) - docker-experimental-p-z: + experimental-p-z: if: ${{ success() || failure() }} - needs: [docker-experimental-0-o] + needs: [experimental-0-o] uses: ./.github/workflows/docker.yml with: incremental: true diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index b9d96a87890..79fd279963c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -68,7 +68,7 @@ on: ] max_parallel: type: number - default: 20 + default: 24 # # Publishing to GitHub Packages # From 5713937de7ed72810013e0856b7ac0cca0d9b3e8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 2 Aug 2022 21:54:51 -0700 Subject: [PATCH 167/742] sage -package list --has-file, --no-file: Handle disjunctions --- .github/workflows/ci-linux.yml | 38 ++++------------------------ .github/workflows/ci-macos.yml | 4 +-- build/sage_bootstrap/cmdline.py | 4 +-- build/sage_bootstrap/expand_class.py | 8 ++++-- 4 files changed, 15 insertions(+), 39 deletions(-) diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index c0df79de3a5..d5935789219 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -116,14 +116,8 @@ jobs: tox_packages_factors: >- ["maximal"] docker_targets: "with-targets-optional" - targets_optional: >- - $( echo $(export PATH=build/bin:$PATH - && (for a in spkg-install.in spkg-install requirements.txt; do - sage-package list :optional: - --has-file $a - --no-file huge - --no-file has_nonfree_dependencies; - done) | grep -v ^_ | grep -v sagemath_doc | grep ^[0-o] ) ) + targets_optional: '$(echo $(export PATH=build/bin:$PATH && sage-package list :optional: --has-file "spkg-install.in|spkg-install|requirements.txt" --no-file "huge|has_nonfree_dependencies" | grep -v sagemath_doc | grep ^[0-o]))' + optional-p-z: if: ${{ success() || failure() }} @@ -136,14 +130,7 @@ jobs: tox_packages_factors: >- ["maximal"] docker_targets: "with-targets-optional" - targets_optional: >- - $( echo $(export PATH=build/bin:$PATH - && (for a in spkg-install.in spkg-install requirements.txt; do - sage-package list :optional: - --has-file $a - --no-file huge - --no-file has_nonfree_dependencies; - done) | grep -v ^_ | grep -v sagemath_doc | grep ^[p-z] ) ) + targets_optional: '$(echo $(export PATH=build/bin:$PATH && sage-package list :optional: --has-file "spkg-install.in|spkg-install|requirements.txt" --no-file "huge|has_nonfree_dependencies" | grep -v sagemath_doc | grep ^[p-z]))' experimental-0-o: if: ${{ success() || failure() }} @@ -156,14 +143,7 @@ jobs: tox_packages_factors: >- ["maximal"] docker_targets: "with-targets-optional" - targets_optional: >- - $( echo $(export PATH=build/bin:$PATH - && (for a in spkg-install.in spkg-install requirements.txt; do - sage-package list :experimental: - --has-file $a - --no-file huge - --no-file has_nonfree_dependencies; - done) | grep -v ^_ | grep -v sagemath_doc | grep ^[0-o] ) ) + targets_optional: '$(echo $(export PATH=build/bin:$PATH && sage-package list :experimental: --has-file "spkg-install.in|spkg-install|requirements.txt" --no-file "huge|has_nonfree_dependencies" | grep -v sagemath_doc | grep ^[0-o]))' experimental-p-z: if: ${{ success() || failure() }} @@ -176,15 +156,7 @@ jobs: tox_packages_factors: >- ["maximal"] docker_targets: "with-targets-optional" - targets_optional: >- - $( echo $(export PATH=build/bin:$PATH - && (for a in spkg-install.in spkg-install requirements.txt; do - sage-package list :experimental: - --has-file $a - --no-file huge - --no-file has_nonfree_dependencies; - done) | grep -v ^_ | grep -v sagemath_doc | grep ^[p-z] ) ) - + targets_optional: '$(echo $(export PATH=build/bin:$PATH && sage-package list :experimental: --has-file "spkg-install.in|spkg-install|requirements.txt" --no-file "huge|has_nonfree_dependencies" | grep -v sagemath_doc | grep ^[p-z]))' local-ubuntu: diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml index 54edd8fdb5f..d2df2268199 100644 --- a/.github/workflows/ci-macos.yml +++ b/.github/workflows/ci-macos.yml @@ -83,12 +83,12 @@ jobs: 2-optional*) export TARGETS_PRE="build/make/Makefile" TARGETS="build/make/Makefile" targets_pattern="${{ matrix.stage }}" targets_pattern="${targets_pattern#2-optional-}" - export TARGETS_OPTIONAL=$( echo $(export PATH=build/bin:$PATH && (for a in spkg-install.in spkg-install requirements.txt; do sage-package list :optional: --has-file $a --no-file huge --no-file has_nonfree_dependencies; done) | grep -v ^_ | grep -v sagemath_doc | grep "^[$targets_pattern]" ) ) + export TARGETS_OPTIONAL=$( echo $(export PATH=build/bin:$PATH && sage-package list :optional: --has-file 'spkg-install.in|spkg-install|requirements.txt' --no-file huge|has_nonfree_dependencies | grep -v sagemath_doc | grep "^[$targets_pattern]" ) ) ;; 2-experimental*) export TARGETS_PRE="build/make/Makefile" TARGETS="build/make/Makefile" targets_pattern="${{ matrix.stage }}" targets_pattern="${targets_pattern#2-experimental-}" - export TARGETS_OPTIONAL=$( echo $(export PATH=build/bin:$PATH && (for a in spkg-install.in spkg-install requirements.txt; do sage-package list :experimental: --has-file $a --no-file huge --no-file has_nonfree_dependencies; done) | grep -v ^_ | grep -v sagemath_doc | grep "^[$targets_pattern]" ) ) + export TARGETS_OPTIONAL=$( echo $(export PATH=build/bin:$PATH && sage-package list :experimental: --has-file 'spkg-install.in|spkg-install|requirements.txt' --no-file huge|has_nonfree_dependencies | grep -v sagemath_doc | grep "^[$targets_pattern]" ) ) ;; esac MAKE="make -j12" tox -e $TOX_ENV -- SAGE_NUM_THREADS=4 $TARGETS diff --git a/build/sage_bootstrap/cmdline.py b/build/sage_bootstrap/cmdline.py index 8c0515c0ede..4a39ecba7cc 100644 --- a/build/sage_bootstrap/cmdline.py +++ b/build/sage_bootstrap/cmdline.py @@ -206,11 +206,11 @@ def make_parser(): parser_list.add_argument( '--has-file', action='append', default=[], metavar='FILENAME', dest='has_files', help=('only include packages that have this file in their metadata directory ' - '(examples: SPKG.rst, spkg-configure.m4, distros/debian.txt)')) + '(examples: SPKG.rst, spkg-configure.m4, distros/debian.txt, spkg-install|spkg-install.in)')) parser_list.add_argument( '--no-file', action='append', default=[], metavar='FILENAME', dest='no_files', help=('only include packages that do not have this file in their metadata directory ' - '(examples: huge, patches)')) + '(examples: huge, patches, huge|has_nonfree_dependencies)')) parser_list.add_argument( '--exclude', action='append', default=[], metavar='PACKAGE_NAME', help='exclude package from list') diff --git a/build/sage_bootstrap/expand_class.py b/build/sage_bootstrap/expand_class.py index 555513905a4..10ec907d0fa 100644 --- a/build/sage_bootstrap/expand_class.py +++ b/build/sage_bootstrap/expand_class.py @@ -32,9 +32,13 @@ def __init__(self, *package_names_or_classes, **filters): def included_in_filter(pkg): if pkg.name in excluded: return False - if not all(pkg.has_file(filename) for filename in filenames): + if not all(any(pkg.has_file(filename) + for filename in filename_disjunction.split('|')) + for filename_disjunction in filenames): return False - return not any(pkg.has_file(filename) for filename in no_filenames) + return not any(any(pkg.has_file(filename) + for filename in no_filename_disjunction.split('|')) + for no_filename_disjunction in no_filenames) for package_name_or_class in package_names_or_classes: if package_name_or_class == ':all:': From 3dc668ec8d13ccfb2d756337448815ca3904db42 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 3 Aug 2022 16:09:28 -0700 Subject: [PATCH 168/742] build/pkgs/pip: Update to 22.2.2 --- build/pkgs/pip/checksums.ini | 6 +++--- build/pkgs/pip/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/pip/checksums.ini b/build/pkgs/pip/checksums.ini index 35d4f6fde7b..a13af9996c7 100644 --- a/build/pkgs/pip/checksums.ini +++ b/build/pkgs/pip/checksums.ini @@ -1,5 +1,5 @@ tarball=pip-VERSION.tar.gz -sha1=be5b671f4868816c6ad2e09258c22bdb3fc82775 -md5=6ec06d38c3aed5d22bcbbbfbf7114d6a -cksum=3372144553 +sha1=ed6e6d191a686b4f989a1dbb2640737a1123f24f +md5=05bb8c0607721d171e9eecf22a8c5cc6 +cksum=4023376185 upstream_url=https://pypi.io/packages/source/p/pip/pip-VERSION.tar.gz diff --git a/build/pkgs/pip/package-version.txt b/build/pkgs/pip/package-version.txt index 30ed8778377..637c2a16439 100644 --- a/build/pkgs/pip/package-version.txt +++ b/build/pkgs/pip/package-version.txt @@ -1 +1 @@ -22.1.2 +22.2.2 From c599e491b1e994bd631371d12da74a9b9166e6ba Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Fri, 5 Aug 2022 08:44:39 +0200 Subject: [PATCH 169/742] 34282: initial --- src/sage/features/latex.py | 42 ++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py index b8915502582..733a75df9d7 100644 --- a/src/sage/features/latex.py +++ b/src/sage/features/latex.py @@ -13,6 +13,9 @@ # **************************************************************************** from . import StaticFile, Executable, FeatureTestResult, FeatureNotPresentError +from sage.features.join_feature import JoinFeature + +latex_url = 'https://www.latex-project.org/' class latex(Executable): r""" @@ -32,8 +35,7 @@ def __init__(self): sage: isinstance(latex(), latex) True """ - Executable.__init__(self, "latex", executable="latex", - url="https://www.latex-project.org/") + Executable.__init__(self, "latex", executable="latex", url=latex_url) def is_functional(self): r""" @@ -92,8 +94,7 @@ def __init__(self): sage: isinstance(pdflatex(), pdflatex) True """ - Executable.__init__(self, "pdflatex", executable="pdflatex", - url="https://www.latex-project.org/") + Executable.__init__(self, "pdflatex", executable="pdflatex", url=latex_url) class xelatex(Executable): r""" @@ -113,8 +114,8 @@ def __init__(self): sage: isinstance(xelatex(), xelatex) True """ - Executable.__init__(self, "xelatex", executable="xelatex", - url="https://www.latex-project.org/") + Executable.__init__(self, "xelatex", executable="xelatex", url=latex_url) + class lualatex(Executable): r""" @@ -134,11 +135,10 @@ def __init__(self): sage: isinstance(lualatex(), lualatex) True """ - Executable.__init__(self, "lualatex", executable="lualatex", - url="https://www.latex-project.org/") + Executable.__init__(self, "lualatex", executable="lualatex", url=latex_url) -class TeXFile(StaticFile): +class TeXFile(StaticFile, JoinFeature): r""" A :class:`sage.features.Feature` describing the presence of a TeX file @@ -151,6 +151,14 @@ class TeXFile(StaticFile): FeatureTestResult('nonexisting', False) """ def __init__(self, name, filename, **kwds): + r""" + EXAMPLES:: + + sage: from sage.features.latex import LaTeXPackage, pdflatex + sage: LaTeXPackage("tkz-graph")._features + [Feature('pdflatex')] + """ + JoinFeature.__init__(self, name, [pdflatex()], url=latex_url) # see :trac:`34282` StaticFile.__init__(self, name, filename, search_path=[], **kwds) def absolute_filename(self) -> str: @@ -174,6 +182,22 @@ def absolute_filename(self) -> str: raise FeatureNotPresentError(self, reason="{filename!r} not found by kpsewhich".format(filename=self.filename)) + def _is_present(self): + r""" + Test for the presence of the TeX-file. + + EXAMPLES:: + + sage: from sage.features.latex import LaTeXPackage, pdflatex + sage: f = LaTeXPackage("tkz-graph") + sage: g = pdflatex() + sage: bool(f.is_present()) == bool(g.is_present()) # indirect doctest + True + """ + test = JoinFeature._is_present(self) + if not test: + return test + return super(TeXFile, self)._is_present() class LaTeXPackage(TeXFile): r""" From a004e002d8353e08e5d1f7d6601ac2d434c50f30 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 5 Aug 2022 20:24:59 -0700 Subject: [PATCH 170/742] build/pkgs/python_build/distros/conda.txt: New --- build/pkgs/python_build/distros/conda.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 build/pkgs/python_build/distros/conda.txt diff --git a/build/pkgs/python_build/distros/conda.txt b/build/pkgs/python_build/distros/conda.txt new file mode 100644 index 00000000000..378eac25d31 --- /dev/null +++ b/build/pkgs/python_build/distros/conda.txt @@ -0,0 +1 @@ +build From d508d7bff7e4d2fce3e097b58ba4726aa973b65d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 5 Aug 2022 20:58:57 -0700 Subject: [PATCH 171/742] build/pkgs: Add many more distros/conda.txt files --- build/pkgs/appnope/distros/conda.txt | 1 + build/pkgs/beniget/conda.txt | 1 + build/pkgs/distlib/distros/conda.txt | 1 + build/pkgs/fastjsonschema/distros/conda.txt | 1 + build/pkgs/hatchling/distros/conda.txt | 1 + build/pkgs/matplotlib_inline/distros/conda.txt | 1 + build/pkgs/nest_asyncio/distros/conda.txt | 1 + build/pkgs/ply/distros/conda.txt | 1 + build/pkgs/pure_eval/distros/conda.txt | 1 + build/pkgs/py/distros/conda.txt | 1 + build/pkgs/soupsieve/distros/conda.txt | 1 + build/pkgs/stack_data/distros/conda.txt | 1 + build/pkgs/toml/distros/conda.txt | 1 + 13 files changed, 13 insertions(+) create mode 100644 build/pkgs/appnope/distros/conda.txt create mode 100644 build/pkgs/beniget/conda.txt create mode 100644 build/pkgs/distlib/distros/conda.txt create mode 100644 build/pkgs/fastjsonschema/distros/conda.txt create mode 100644 build/pkgs/hatchling/distros/conda.txt create mode 100644 build/pkgs/matplotlib_inline/distros/conda.txt create mode 100644 build/pkgs/nest_asyncio/distros/conda.txt create mode 100644 build/pkgs/ply/distros/conda.txt create mode 100644 build/pkgs/pure_eval/distros/conda.txt create mode 100644 build/pkgs/py/distros/conda.txt create mode 100644 build/pkgs/soupsieve/distros/conda.txt create mode 100644 build/pkgs/stack_data/distros/conda.txt create mode 100644 build/pkgs/toml/distros/conda.txt diff --git a/build/pkgs/appnope/distros/conda.txt b/build/pkgs/appnope/distros/conda.txt new file mode 100644 index 00000000000..010137fae0e --- /dev/null +++ b/build/pkgs/appnope/distros/conda.txt @@ -0,0 +1 @@ +appnope diff --git a/build/pkgs/beniget/conda.txt b/build/pkgs/beniget/conda.txt new file mode 100644 index 00000000000..8b5faaea7c2 --- /dev/null +++ b/build/pkgs/beniget/conda.txt @@ -0,0 +1 @@ +beniget diff --git a/build/pkgs/distlib/distros/conda.txt b/build/pkgs/distlib/distros/conda.txt new file mode 100644 index 00000000000..f68bb07272d --- /dev/null +++ b/build/pkgs/distlib/distros/conda.txt @@ -0,0 +1 @@ +distlib diff --git a/build/pkgs/fastjsonschema/distros/conda.txt b/build/pkgs/fastjsonschema/distros/conda.txt new file mode 100644 index 00000000000..7a8bdf5369b --- /dev/null +++ b/build/pkgs/fastjsonschema/distros/conda.txt @@ -0,0 +1 @@ +python-fastjsonschema diff --git a/build/pkgs/hatchling/distros/conda.txt b/build/pkgs/hatchling/distros/conda.txt new file mode 100644 index 00000000000..1685d03c212 --- /dev/null +++ b/build/pkgs/hatchling/distros/conda.txt @@ -0,0 +1 @@ +hatchling diff --git a/build/pkgs/matplotlib_inline/distros/conda.txt b/build/pkgs/matplotlib_inline/distros/conda.txt new file mode 100644 index 00000000000..7b78209dd96 --- /dev/null +++ b/build/pkgs/matplotlib_inline/distros/conda.txt @@ -0,0 +1 @@ +matplotlib-inline diff --git a/build/pkgs/nest_asyncio/distros/conda.txt b/build/pkgs/nest_asyncio/distros/conda.txt new file mode 100644 index 00000000000..875c8427e6c --- /dev/null +++ b/build/pkgs/nest_asyncio/distros/conda.txt @@ -0,0 +1 @@ +nest-asyncio diff --git a/build/pkgs/ply/distros/conda.txt b/build/pkgs/ply/distros/conda.txt new file mode 100644 index 00000000000..90412f06833 --- /dev/null +++ b/build/pkgs/ply/distros/conda.txt @@ -0,0 +1 @@ +ply diff --git a/build/pkgs/pure_eval/distros/conda.txt b/build/pkgs/pure_eval/distros/conda.txt new file mode 100644 index 00000000000..e50c81f634f --- /dev/null +++ b/build/pkgs/pure_eval/distros/conda.txt @@ -0,0 +1 @@ +pure_eval diff --git a/build/pkgs/py/distros/conda.txt b/build/pkgs/py/distros/conda.txt new file mode 100644 index 00000000000..edfce786a4d --- /dev/null +++ b/build/pkgs/py/distros/conda.txt @@ -0,0 +1 @@ +py diff --git a/build/pkgs/soupsieve/distros/conda.txt b/build/pkgs/soupsieve/distros/conda.txt new file mode 100644 index 00000000000..9eb997f7a10 --- /dev/null +++ b/build/pkgs/soupsieve/distros/conda.txt @@ -0,0 +1 @@ +soupsieve diff --git a/build/pkgs/stack_data/distros/conda.txt b/build/pkgs/stack_data/distros/conda.txt new file mode 100644 index 00000000000..09e7428c13d --- /dev/null +++ b/build/pkgs/stack_data/distros/conda.txt @@ -0,0 +1 @@ +stack_data diff --git a/build/pkgs/toml/distros/conda.txt b/build/pkgs/toml/distros/conda.txt new file mode 100644 index 00000000000..bd79a658fe7 --- /dev/null +++ b/build/pkgs/toml/distros/conda.txt @@ -0,0 +1 @@ +toml From 098a8e7a9a473a437a8dc12902fb1571b4450da0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 5 Aug 2022 21:02:42 -0700 Subject: [PATCH 172/742] build/pkgs: Add some more distros/conda.txt files --- build/pkgs/executing/distros/conda.txt | 1 + build/pkgs/tzdata/distros/conda.txt | 1 + 2 files changed, 2 insertions(+) create mode 100644 build/pkgs/executing/distros/conda.txt create mode 100644 build/pkgs/tzdata/distros/conda.txt diff --git a/build/pkgs/executing/distros/conda.txt b/build/pkgs/executing/distros/conda.txt new file mode 100644 index 00000000000..a920f2c56c3 --- /dev/null +++ b/build/pkgs/executing/distros/conda.txt @@ -0,0 +1 @@ +executing diff --git a/build/pkgs/tzdata/distros/conda.txt b/build/pkgs/tzdata/distros/conda.txt new file mode 100644 index 00000000000..0883ff0705b --- /dev/null +++ b/build/pkgs/tzdata/distros/conda.txt @@ -0,0 +1 @@ +tzdata From c56aa71a7c48b63754554f9449152197123f6c1c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 5 Aug 2022 21:03:08 -0700 Subject: [PATCH 173/742] bootstrap-conda: Also add pip lines when install-requires.txt is present --- bootstrap-conda | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bootstrap-conda b/bootstrap-conda index 9ad39468e5d..cc9f02d0ec6 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -97,9 +97,12 @@ DEVELOP_SYSTEM_PACKAGES="openssh pycodestyle pytest" ( echo >&4 " - pip:" echo >&5 " - pip:" - for PKG_BASE in $(sage-package list --has-file requirements.txt --no-file distros/conda.txt); do + for PKG_BASE in $(sage-package list :standard: :optional: --has-file requirements.txt --no-file distros/conda.txt) $(sage-package list :standard: :optional: --has-file install-requires.txt --no-file requirements.txt --no-file distros/conda.txt); do PKG_SCRIPTS=build/pkgs/$PKG_BASE SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/requirements.txt + if [ ! -f $SYSTEM_PACKAGES_FILE ]; then + SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/install-requires.txt + fi PKG_TYPE=$(cat $PKG_SCRIPTS/type) if grep -q SAGERUNTIME $PKG_SCRIPTS/dependencies $PKG_SCRIPTS/dependencies_order_only 2>/dev/null; then : # cannot install packages that depend on the Sage library From c13eaf1176c9067b220927a4cc57c7bf901c0ef7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 5 Aug 2022 22:17:24 -0700 Subject: [PATCH 174/742] build/pkgs: Add even more distros/conda.txt files --- build/pkgs/appdirs/distros/conda.txt | 1 + build/pkgs/argon2_cffi/distros/conda.txt | 1 + build/pkgs/asttokens/distros/conda.txt | 1 + build/pkgs/backports_zoneinfo/distros/conda.txt | 1 + build/pkgs/charset_normalizer/distros/conda.txt | 1 + build/pkgs/cppy/distros/conda.txt | 1 + build/pkgs/debugpy/distros/conda.txt | 1 + build/pkgs/deprecation/distros/conda.txt | 1 + build/pkgs/dot2tex/distros/conda.txt | 1 + build/pkgs/editables/distros/conda.txt | 1 + build/pkgs/filelock/distros/conda.txt | 1 + build/pkgs/flit_core/distros/conda.txt | 1 + build/pkgs/fonttools/distros/conda.txt | 1 + build/pkgs/gast/distros/conda.txt | 1 + build/pkgs/idna/distros/conda.txt | 1 + build/pkgs/importlib_resources/distros/conda.txt | 1 + build/pkgs/jupyter_jsmol/distros/conda.txt | 1 + build/pkgs/jupyterlab_pygments/distros/conda.txt | 1 + build/pkgs/mathics/distros/conda.txt | 1 + build/pkgs/nbclient/distros/conda.txt | 1 + build/pkgs/palettable/distros/conda.txt | 1 + build/pkgs/pathspec/distros/conda.txt | 1 + build/pkgs/pint/distros/conda.txt | 1 + build/pkgs/platformdirs/distros/conda.txt | 1 + build/pkgs/pluggy/distros/conda.txt | 1 + build/pkgs/poetry_core/distros/conda.txt | 1 + build/pkgs/pythran/distros/conda.txt | 1 + build/pkgs/pytz_deprecation_shim/distros/conda.txt | 1 + build/pkgs/setuptools_scm_git_archive/distros/conda.txt | 1 + build/pkgs/texttable/distros/conda.txt | 1 + build/pkgs/tinycss2/distros/conda.txt | 1 + build/pkgs/tomli/distros/conda.txt | 1 + build/pkgs/tomlkit/distros/conda.txt | 1 + build/pkgs/typing_extensions/distros/conda.txt | 1 + build/pkgs/urllib3/distros/conda.txt | 1 + build/pkgs/virtualenv/distros/conda.txt | 1 + 36 files changed, 36 insertions(+) create mode 100644 build/pkgs/appdirs/distros/conda.txt create mode 100644 build/pkgs/argon2_cffi/distros/conda.txt create mode 100644 build/pkgs/asttokens/distros/conda.txt create mode 100644 build/pkgs/backports_zoneinfo/distros/conda.txt create mode 100644 build/pkgs/charset_normalizer/distros/conda.txt create mode 100644 build/pkgs/cppy/distros/conda.txt create mode 100644 build/pkgs/debugpy/distros/conda.txt create mode 100644 build/pkgs/deprecation/distros/conda.txt create mode 100644 build/pkgs/dot2tex/distros/conda.txt create mode 100644 build/pkgs/editables/distros/conda.txt create mode 100644 build/pkgs/filelock/distros/conda.txt create mode 100644 build/pkgs/flit_core/distros/conda.txt create mode 100644 build/pkgs/fonttools/distros/conda.txt create mode 100644 build/pkgs/gast/distros/conda.txt create mode 100644 build/pkgs/idna/distros/conda.txt create mode 100644 build/pkgs/importlib_resources/distros/conda.txt create mode 100644 build/pkgs/jupyter_jsmol/distros/conda.txt create mode 100644 build/pkgs/jupyterlab_pygments/distros/conda.txt create mode 100644 build/pkgs/mathics/distros/conda.txt create mode 100644 build/pkgs/nbclient/distros/conda.txt create mode 100644 build/pkgs/palettable/distros/conda.txt create mode 100644 build/pkgs/pathspec/distros/conda.txt create mode 100644 build/pkgs/pint/distros/conda.txt create mode 100644 build/pkgs/platformdirs/distros/conda.txt create mode 100644 build/pkgs/pluggy/distros/conda.txt create mode 100644 build/pkgs/poetry_core/distros/conda.txt create mode 100644 build/pkgs/pythran/distros/conda.txt create mode 100644 build/pkgs/pytz_deprecation_shim/distros/conda.txt create mode 100644 build/pkgs/setuptools_scm_git_archive/distros/conda.txt create mode 100644 build/pkgs/texttable/distros/conda.txt create mode 100644 build/pkgs/tinycss2/distros/conda.txt create mode 100644 build/pkgs/tomli/distros/conda.txt create mode 100644 build/pkgs/tomlkit/distros/conda.txt create mode 100644 build/pkgs/typing_extensions/distros/conda.txt create mode 100644 build/pkgs/urllib3/distros/conda.txt create mode 100644 build/pkgs/virtualenv/distros/conda.txt diff --git a/build/pkgs/appdirs/distros/conda.txt b/build/pkgs/appdirs/distros/conda.txt new file mode 100644 index 00000000000..d64bc321a11 --- /dev/null +++ b/build/pkgs/appdirs/distros/conda.txt @@ -0,0 +1 @@ +appdirs diff --git a/build/pkgs/argon2_cffi/distros/conda.txt b/build/pkgs/argon2_cffi/distros/conda.txt new file mode 100644 index 00000000000..d05a5eb79fb --- /dev/null +++ b/build/pkgs/argon2_cffi/distros/conda.txt @@ -0,0 +1 @@ +argon2-cffi diff --git a/build/pkgs/asttokens/distros/conda.txt b/build/pkgs/asttokens/distros/conda.txt new file mode 100644 index 00000000000..7adf4c51fd2 --- /dev/null +++ b/build/pkgs/asttokens/distros/conda.txt @@ -0,0 +1 @@ +asttokens diff --git a/build/pkgs/backports_zoneinfo/distros/conda.txt b/build/pkgs/backports_zoneinfo/distros/conda.txt new file mode 100644 index 00000000000..5a8be642f33 --- /dev/null +++ b/build/pkgs/backports_zoneinfo/distros/conda.txt @@ -0,0 +1 @@ +backports.zoneinfo diff --git a/build/pkgs/charset_normalizer/distros/conda.txt b/build/pkgs/charset_normalizer/distros/conda.txt new file mode 100644 index 00000000000..5f964199cd0 --- /dev/null +++ b/build/pkgs/charset_normalizer/distros/conda.txt @@ -0,0 +1 @@ +charset-normalizer diff --git a/build/pkgs/cppy/distros/conda.txt b/build/pkgs/cppy/distros/conda.txt new file mode 100644 index 00000000000..9d2b4aaeee0 --- /dev/null +++ b/build/pkgs/cppy/distros/conda.txt @@ -0,0 +1 @@ +cppy diff --git a/build/pkgs/debugpy/distros/conda.txt b/build/pkgs/debugpy/distros/conda.txt new file mode 100644 index 00000000000..2802a6b1b1c --- /dev/null +++ b/build/pkgs/debugpy/distros/conda.txt @@ -0,0 +1 @@ +debugpy diff --git a/build/pkgs/deprecation/distros/conda.txt b/build/pkgs/deprecation/distros/conda.txt new file mode 100644 index 00000000000..4ba9b7530ed --- /dev/null +++ b/build/pkgs/deprecation/distros/conda.txt @@ -0,0 +1 @@ +deprecation diff --git a/build/pkgs/dot2tex/distros/conda.txt b/build/pkgs/dot2tex/distros/conda.txt new file mode 100644 index 00000000000..4d0a832a550 --- /dev/null +++ b/build/pkgs/dot2tex/distros/conda.txt @@ -0,0 +1 @@ +dot2tex diff --git a/build/pkgs/editables/distros/conda.txt b/build/pkgs/editables/distros/conda.txt new file mode 100644 index 00000000000..35c51715e64 --- /dev/null +++ b/build/pkgs/editables/distros/conda.txt @@ -0,0 +1 @@ +editables diff --git a/build/pkgs/filelock/distros/conda.txt b/build/pkgs/filelock/distros/conda.txt new file mode 100644 index 00000000000..83c2e35706e --- /dev/null +++ b/build/pkgs/filelock/distros/conda.txt @@ -0,0 +1 @@ +filelock diff --git a/build/pkgs/flit_core/distros/conda.txt b/build/pkgs/flit_core/distros/conda.txt new file mode 100644 index 00000000000..14ccfd92035 --- /dev/null +++ b/build/pkgs/flit_core/distros/conda.txt @@ -0,0 +1 @@ +flit-core diff --git a/build/pkgs/fonttools/distros/conda.txt b/build/pkgs/fonttools/distros/conda.txt new file mode 100644 index 00000000000..d32bfca1a29 --- /dev/null +++ b/build/pkgs/fonttools/distros/conda.txt @@ -0,0 +1 @@ +fonttools diff --git a/build/pkgs/gast/distros/conda.txt b/build/pkgs/gast/distros/conda.txt new file mode 100644 index 00000000000..beb259c8453 --- /dev/null +++ b/build/pkgs/gast/distros/conda.txt @@ -0,0 +1 @@ +gast diff --git a/build/pkgs/idna/distros/conda.txt b/build/pkgs/idna/distros/conda.txt new file mode 100644 index 00000000000..c40472e6fc2 --- /dev/null +++ b/build/pkgs/idna/distros/conda.txt @@ -0,0 +1 @@ +idna diff --git a/build/pkgs/importlib_resources/distros/conda.txt b/build/pkgs/importlib_resources/distros/conda.txt new file mode 100644 index 00000000000..2b0146fc669 --- /dev/null +++ b/build/pkgs/importlib_resources/distros/conda.txt @@ -0,0 +1 @@ +importlib-resources diff --git a/build/pkgs/jupyter_jsmol/distros/conda.txt b/build/pkgs/jupyter_jsmol/distros/conda.txt new file mode 100644 index 00000000000..9465bfb8e0c --- /dev/null +++ b/build/pkgs/jupyter_jsmol/distros/conda.txt @@ -0,0 +1 @@ +jupyter-jsmol diff --git a/build/pkgs/jupyterlab_pygments/distros/conda.txt b/build/pkgs/jupyterlab_pygments/distros/conda.txt new file mode 100644 index 00000000000..23254749a23 --- /dev/null +++ b/build/pkgs/jupyterlab_pygments/distros/conda.txt @@ -0,0 +1 @@ +jupyterlab_pygments diff --git a/build/pkgs/mathics/distros/conda.txt b/build/pkgs/mathics/distros/conda.txt new file mode 100644 index 00000000000..800ac5e8aa4 --- /dev/null +++ b/build/pkgs/mathics/distros/conda.txt @@ -0,0 +1 @@ +mathics3 diff --git a/build/pkgs/nbclient/distros/conda.txt b/build/pkgs/nbclient/distros/conda.txt new file mode 100644 index 00000000000..66ffbb0ca10 --- /dev/null +++ b/build/pkgs/nbclient/distros/conda.txt @@ -0,0 +1 @@ +nbclient diff --git a/build/pkgs/palettable/distros/conda.txt b/build/pkgs/palettable/distros/conda.txt new file mode 100644 index 00000000000..646dd7426bb --- /dev/null +++ b/build/pkgs/palettable/distros/conda.txt @@ -0,0 +1 @@ +palettable diff --git a/build/pkgs/pathspec/distros/conda.txt b/build/pkgs/pathspec/distros/conda.txt new file mode 100644 index 00000000000..6486958df08 --- /dev/null +++ b/build/pkgs/pathspec/distros/conda.txt @@ -0,0 +1 @@ +pathspec diff --git a/build/pkgs/pint/distros/conda.txt b/build/pkgs/pint/distros/conda.txt new file mode 100644 index 00000000000..45f523a5a6e --- /dev/null +++ b/build/pkgs/pint/distros/conda.txt @@ -0,0 +1 @@ +pint diff --git a/build/pkgs/platformdirs/distros/conda.txt b/build/pkgs/platformdirs/distros/conda.txt new file mode 100644 index 00000000000..67fd014bbdd --- /dev/null +++ b/build/pkgs/platformdirs/distros/conda.txt @@ -0,0 +1 @@ +platformdirs diff --git a/build/pkgs/pluggy/distros/conda.txt b/build/pkgs/pluggy/distros/conda.txt new file mode 100644 index 00000000000..11bdb5c1f5f --- /dev/null +++ b/build/pkgs/pluggy/distros/conda.txt @@ -0,0 +1 @@ +pluggy diff --git a/build/pkgs/poetry_core/distros/conda.txt b/build/pkgs/poetry_core/distros/conda.txt new file mode 100644 index 00000000000..9b1f9e3fa7d --- /dev/null +++ b/build/pkgs/poetry_core/distros/conda.txt @@ -0,0 +1 @@ +poetry-core diff --git a/build/pkgs/pythran/distros/conda.txt b/build/pkgs/pythran/distros/conda.txt new file mode 100644 index 00000000000..86d056b339f --- /dev/null +++ b/build/pkgs/pythran/distros/conda.txt @@ -0,0 +1 @@ +pythran diff --git a/build/pkgs/pytz_deprecation_shim/distros/conda.txt b/build/pkgs/pytz_deprecation_shim/distros/conda.txt new file mode 100644 index 00000000000..2fd546ce62e --- /dev/null +++ b/build/pkgs/pytz_deprecation_shim/distros/conda.txt @@ -0,0 +1 @@ +pytz-deprecation-shim diff --git a/build/pkgs/setuptools_scm_git_archive/distros/conda.txt b/build/pkgs/setuptools_scm_git_archive/distros/conda.txt new file mode 100644 index 00000000000..538474ff946 --- /dev/null +++ b/build/pkgs/setuptools_scm_git_archive/distros/conda.txt @@ -0,0 +1 @@ +setuptools-scm-git-archive diff --git a/build/pkgs/texttable/distros/conda.txt b/build/pkgs/texttable/distros/conda.txt new file mode 100644 index 00000000000..5d54c8a784d --- /dev/null +++ b/build/pkgs/texttable/distros/conda.txt @@ -0,0 +1 @@ +texttable diff --git a/build/pkgs/tinycss2/distros/conda.txt b/build/pkgs/tinycss2/distros/conda.txt new file mode 100644 index 00000000000..29992f20d2c --- /dev/null +++ b/build/pkgs/tinycss2/distros/conda.txt @@ -0,0 +1 @@ +tinycss2 diff --git a/build/pkgs/tomli/distros/conda.txt b/build/pkgs/tomli/distros/conda.txt new file mode 100644 index 00000000000..aab392a3ac2 --- /dev/null +++ b/build/pkgs/tomli/distros/conda.txt @@ -0,0 +1 @@ +tomli diff --git a/build/pkgs/tomlkit/distros/conda.txt b/build/pkgs/tomlkit/distros/conda.txt new file mode 100644 index 00000000000..8141b831035 --- /dev/null +++ b/build/pkgs/tomlkit/distros/conda.txt @@ -0,0 +1 @@ +tomlkit diff --git a/build/pkgs/typing_extensions/distros/conda.txt b/build/pkgs/typing_extensions/distros/conda.txt new file mode 100644 index 00000000000..5fd4f05f341 --- /dev/null +++ b/build/pkgs/typing_extensions/distros/conda.txt @@ -0,0 +1 @@ +typing_extensions diff --git a/build/pkgs/urllib3/distros/conda.txt b/build/pkgs/urllib3/distros/conda.txt new file mode 100644 index 00000000000..a42590bebea --- /dev/null +++ b/build/pkgs/urllib3/distros/conda.txt @@ -0,0 +1 @@ +urllib3 diff --git a/build/pkgs/virtualenv/distros/conda.txt b/build/pkgs/virtualenv/distros/conda.txt new file mode 100644 index 00000000000..66072c76450 --- /dev/null +++ b/build/pkgs/virtualenv/distros/conda.txt @@ -0,0 +1 @@ +virtualenv From 1c47261840fcee978b7471ff648a2b39eecde5fa Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 5 Aug 2022 22:20:04 -0700 Subject: [PATCH 175/742] bootstrap-conda: Do not include pip lines for packages for which we have source directories --- bootstrap-conda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap-conda b/bootstrap-conda index cc9f02d0ec6..06c81e21521 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -97,7 +97,7 @@ DEVELOP_SYSTEM_PACKAGES="openssh pycodestyle pytest" ( echo >&4 " - pip:" echo >&5 " - pip:" - for PKG_BASE in $(sage-package list :standard: :optional: --has-file requirements.txt --no-file distros/conda.txt) $(sage-package list :standard: :optional: --has-file install-requires.txt --no-file requirements.txt --no-file distros/conda.txt); do + for PKG_BASE in $((sage-package list :standard: :optional: --has-file requirements.txt --no-file distros/conda.txt --no-file src; sage-package list :standard: :optional: --has-file install-requires.txt --no-file requirements.txt --no-file distros/conda.txt --no-file src) | sort); do PKG_SCRIPTS=build/pkgs/$PKG_BASE SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/requirements.txt if [ ! -f $SYSTEM_PACKAGES_FILE ]; then From 6d067200c54e48597c262695b866cc3c321ff766 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 5 Aug 2022 22:23:24 -0700 Subject: [PATCH 176/742] build/pkgs: Add even more distros/conda.txt files (fixup) --- build/pkgs/beniget/{ => distros}/conda.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename build/pkgs/beniget/{ => distros}/conda.txt (100%) diff --git a/build/pkgs/beniget/conda.txt b/build/pkgs/beniget/distros/conda.txt similarity index 100% rename from build/pkgs/beniget/conda.txt rename to build/pkgs/beniget/distros/conda.txt From 6a51349cb1bf1ef2b2b00a9815efe17e559c21db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 6 Aug 2022 13:49:06 +0200 Subject: [PATCH 177/742] modernize super in asymptotics and crystals --- src/sage/combinat/crystals/affine.py | 6 +- .../combinat/crystals/affine_factorization.py | 2 +- src/sage/combinat/crystals/alcove_path.py | 12 ++- src/sage/combinat/crystals/bkk_crystals.py | 4 +- src/sage/combinat/crystals/direct_sum.py | 3 +- .../combinat/crystals/elementary_crystals.py | 8 +- src/sage/combinat/crystals/fast_crystals.py | 10 +-- .../fully_commutative_stable_grothendieck.py | 5 +- .../crystals/generalized_young_walls.py | 6 +- .../combinat/crystals/induced_structure.py | 3 +- .../combinat/crystals/infinity_crystals.py | 9 +- src/sage/combinat/crystals/kac_modules.py | 5 +- .../combinat/crystals/kyoto_path_model.py | 2 +- src/sage/combinat/crystals/letters.pyx | 9 +- src/sage/combinat/crystals/littelmann_path.py | 5 +- .../combinat/crystals/monomial_crystals.py | 8 +- src/sage/combinat/crystals/pbw_crystal.py | 2 +- .../crystals/polyhedral_realization.py | 3 +- src/sage/combinat/crystals/subcrystal.py | 12 +-- src/sage/combinat/crystals/tensor_product.py | 5 +- .../crystals/tensor_product_element.pyx | 6 +- src/sage/combinat/crystals/virtual_crystal.py | 10 +-- src/sage/rings/asymptotic/asymptotic_ring.py | 83 +++---------------- ...otics_multivariate_generating_functions.py | 12 +-- .../asymptotic/growth_group_cartesian.py | 10 +-- src/sage/rings/asymptotic/misc.py | 22 ++--- src/sage/rings/asymptotic/term_monoid.py | 6 +- 27 files changed, 105 insertions(+), 163 deletions(-) diff --git a/src/sage/combinat/crystals/affine.py b/src/sage/combinat/crystals/affine.py index 65df64542b0..813492aad80 100644 --- a/src/sage/combinat/crystals/affine.py +++ b/src/sage/combinat/crystals/affine.py @@ -78,7 +78,7 @@ def __classcall__(cls, cartan_type, *args, **options): True """ ct = CartanType(cartan_type) - return super(AffineCrystalFromClassical, cls).__classcall__(cls, ct, *args, **options) + return super().__classcall__(cls, ct, *args, **options) def __init__(self, cartan_type, classical_crystal, category=None): """ @@ -397,7 +397,7 @@ def epsilon0(self): sage: [x.epsilon0() for x in A.list()] [1, 0, 0] """ - return super(AffineCrystalFromClassicalElement, self).epsilon(0) + return super().epsilon(0) def epsilon(self, i): """ @@ -436,7 +436,7 @@ def phi0(self): sage: [x.phi0() for x in A.list()] [0, 0, 1] """ - return super(AffineCrystalFromClassicalElement, self).phi(0) + return super().phi(0) def phi(self, i): r""" diff --git a/src/sage/combinat/crystals/affine_factorization.py b/src/sage/combinat/crystals/affine_factorization.py index 1bc568aeb71..2499a05a5f9 100644 --- a/src/sage/combinat/crystals/affine_factorization.py +++ b/src/sage/combinat/crystals/affine_factorization.py @@ -117,7 +117,7 @@ def __classcall_private__(cls, w, n, x = None, k = None): w0 = W.from_reduced_word(w[0].from_kbounded_to_reduced_word(k)) w1 = W.from_reduced_word(w[1].from_kbounded_to_reduced_word(k)) w = w0*(w1.inverse()) - return super(AffineFactorizationCrystal, cls).__classcall__(cls, w, n, x) + return super().__classcall__(cls, w, n, x) def __init__(self, w, n, x = None): r""" diff --git a/src/sage/combinat/crystals/alcove_path.py b/src/sage/combinat/crystals/alcove_path.py index e72e6a394e8..912e4797d02 100644 --- a/src/sage/combinat/crystals/alcove_path.py +++ b/src/sage/combinat/crystals/alcove_path.py @@ -276,10 +276,8 @@ def __classcall_private__(cls, starting_weight, cartan_type=None, if not starting_weight.is_dominant(): raise ValueError("{0} is not a dominant weight".format(starting_weight)) - - return super(CrystalOfAlcovePaths, cls).__classcall__(cls, - starting_weight, highest_weight_crystal) - + return super().__classcall__(cls, starting_weight, + highest_weight_crystal) def __init__(self, starting_weight, highest_weight_crystal): r""" @@ -1153,7 +1151,7 @@ def __classcall_private__(cls, cartan_type): True """ cartan_type = CartanType(cartan_type) - return super(InfinityCrystalOfAlcovePaths, cls).__classcall__(cls, cartan_type) + return super().__classcall__(cls, cartan_type) def __init__(self, cartan_type): """ @@ -1394,6 +1392,7 @@ def projection(self, k=None): A = CrystalOfAlcovePaths(self.parent()._cartan_type, [k]*n) return A(tuple([A._R(rt, h + k*s(rt)) for rt,h in self.value])) + class RootsWithHeight(UniqueRepresentation, Parent): r""" Data structure of the ordered pairs `(\beta,k)`, @@ -1462,8 +1461,7 @@ def __classcall_private__(cls, starting_weight, cartan_type = None): offset = R.index_set()[Integer(0)] starting_weight = P.sum(starting_weight[j-offset]*Lambda[j] for j in R.index_set()) - return super(RootsWithHeight, cls).__classcall__(cls, starting_weight) - + return super().__classcall__(cls, starting_weight) def __init__(self, weight): r""" diff --git a/src/sage/combinat/crystals/bkk_crystals.py b/src/sage/combinat/crystals/bkk_crystals.py index 622fbb9e350..15e795ca484 100644 --- a/src/sage/combinat/crystals/bkk_crystals.py +++ b/src/sage/combinat/crystals/bkk_crystals.py @@ -61,7 +61,7 @@ def __classcall_private__(cls, ct, shape): shape = _Partitions(shape) if len(shape) > ct.m + 1 and shape[ct.m+1] > ct.n + 1: raise ValueError("invalid hook shape") - return super(CrystalOfBKKTableaux, cls).__classcall__(cls, ct, shape) + return super().__classcall__(cls, ct, shape) def __init__(self, ct, shape): r""" @@ -135,7 +135,7 @@ def genuine_highest_weight_vectors(self, index_set=None): """ if index_set is None or index_set == self.index_set(): return self.module_generators - return super(CrystalOfBKKTableaux, self).genuine_highest_weight_vectors(index_set) + return super().genuine_highest_weight_vectors(index_set) class Element(CrystalOfBKKTableauxElement): pass diff --git a/src/sage/combinat/crystals/direct_sum.py b/src/sage/combinat/crystals/direct_sum.py index 84676264822..da2ce05bee2 100644 --- a/src/sage/combinat/crystals/direct_sum.py +++ b/src/sage/combinat/crystals/direct_sum.py @@ -22,6 +22,7 @@ from sage.structure.element_wrapper import ElementWrapper from sage.structure.element import get_coercion_model + class DirectSumOfCrystals(DisjointUnionEnumeratedSets): r""" Direct sum of crystals. @@ -114,7 +115,7 @@ def __classcall_private__(cls, crystals, facade=True, keepkey=False, category=No else: ret.append(x) category = Category.meet([Category.join(c.categories()) for c in ret]) - return super(DirectSumOfCrystals, cls).__classcall__(cls, + return super().__classcall__(cls, Family(ret), facade=facade, keepkey=keepkey, category=category) def __init__(self, crystals, facade, keepkey, category, **options): diff --git a/src/sage/combinat/crystals/elementary_crystals.py b/src/sage/combinat/crystals/elementary_crystals.py index b3d01c09249..607206c52f6 100644 --- a/src/sage/combinat/crystals/elementary_crystals.py +++ b/src/sage/combinat/crystals/elementary_crystals.py @@ -258,7 +258,7 @@ def __classcall_private__(cls, cartan_type, weight=None): weight = cartan_type cartan_type = weight.parent().cartan_type() cartan_type = CartanType(cartan_type) - return super(TCrystal, cls).__classcall__(cls, cartan_type, weight) + return super().__classcall__(cls, cartan_type, weight) def __init__(self, cartan_type, weight): r""" @@ -514,7 +514,7 @@ def __classcall_private__(cls, cartan_type, weight=None, dual=False): weight = cartan_type cartan_type = weight.parent().cartan_type() cartan_type = CartanType(cartan_type) - return super(RCrystal, cls).__classcall__(cls, cartan_type, weight, dual) + return super().__classcall__(cls, cartan_type, weight, dual) def __init__(self, cartan_type, weight, dual): r""" @@ -789,7 +789,7 @@ def __classcall_private__(cls, cartan_type, i): cartan_type = CartanType(cartan_type) if i not in cartan_type.index_set(): raise ValueError('i must an element of the index set') - return super(ElementaryCrystal, cls).__classcall__(cls, cartan_type, i) + return super().__classcall__(cls, cartan_type, i) def __init__(self, cartan_type, i): r""" @@ -1091,7 +1091,7 @@ def __classcall_private__(cls, cartan_type, P=None): P = cartan_type.root_system().ambient_space() if P is None: P = cartan_type.root_system().weight_lattice() - return super(ComponentCrystal, cls).__classcall__(cls, cartan_type, P) + return super().__classcall__(cls, cartan_type, P) def __init__(self, cartan_type, P): r""" diff --git a/src/sage/combinat/crystals/fast_crystals.py b/src/sage/combinat/crystals/fast_crystals.py index 2f964bb60de..9899f87122b 100644 --- a/src/sage/combinat/crystals/fast_crystals.py +++ b/src/sage/combinat/crystals/fast_crystals.py @@ -1,4 +1,4 @@ -r""" +sr""" Fast Rank Two Crystals """ # **************************************************************************** @@ -105,7 +105,7 @@ def __classcall__(cls, cartan_type, shape, format = "string"): if len(shape) > 2: raise ValueError("The shape must have length <=2") shape = shape + (0,)*(2-len(shape)) - return super(FastCrystal, cls).__classcall__(cls, cartan_type, shape, format) + return super().__classcall__(cls, cartan_type, shape, format) def __init__(self, ct, shape, format): """ @@ -116,7 +116,7 @@ def __init__(self, ct, shape, format): sage: TestSuite(C).run() """ Parent.__init__(self, category = ClassicalCrystals()) -# super(FastCrystal, self).__init__(category = FiniteEnumeratedSets()) +# super().__init__(category = FiniteEnumeratedSets()) self._cartan_type = ct if ct[1] != 2: raise NotImplementedError @@ -167,9 +167,9 @@ def __init__(self, ct, shape, format): self.rename("The fast crystal for %s2 with shape [%s,%s]"%(ct[0],l1_str,l2_str)) self.module_generators = [self(0)] # self._list = ClassicalCrystal.list(self) - self._list = super(FastCrystal, self).list() + self._list = super().list() # self._digraph = ClassicalCrystal.digraph(self) - self._digraph = super(FastCrystal, self).digraph() + self._digraph = super().digraph() self._digraph_closure = self.digraph().transitive_closure() def _type_a_init(self, l1, l2): diff --git a/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py b/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py index e2f9d09bd45..df9805e07b3 100644 --- a/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py +++ b/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py @@ -309,6 +309,7 @@ def to_increasing_hecke_biword(self): L[0] += [j+1]*len(self.value[-j-1]) return L + class DecreasingHeckeFactorizations(UniqueRepresentation, Parent): """ Set of decreasing factorizations in the 0-Hecke monoid. @@ -358,7 +359,7 @@ def __classcall_private__(cls, w, factors, excess): w = H.from_reduced_word(w.reduced_word()) if (not w.reduced_word()) and excess!=0: raise ValueError("excess must be 0 for the empty word") - return super(DecreasingHeckeFactorizations, cls).__classcall__(cls, w, factors, excess) + return super().__classcall__(cls, w, factors, excess) def __init__(self, w, factors, excess): """ @@ -520,7 +521,7 @@ def __classcall_private__(cls, w, factors, excess, shape=False): w = H.from_reduced_word(w.reduced_word()) if (not w.reduced_word()) and excess!=0: raise ValueError("excess must be 0 for the empty word") - return super(FullyCommutativeStableGrothendieckCrystal, cls).__classcall__(cls, w, factors, excess) + return super().__classcall__(cls, w, factors, excess) def __init__(self, w, factors, excess): """ diff --git a/src/sage/combinat/crystals/generalized_young_walls.py b/src/sage/combinat/crystals/generalized_young_walls.py index 60c47154c8e..0d30991e00e 100644 --- a/src/sage/combinat/crystals/generalized_young_walls.py +++ b/src/sage/combinat/crystals/generalized_young_walls.py @@ -834,7 +834,7 @@ def __classcall_private__(cls, n, category=None): sage: Yinf is Yinf2 True """ - return super(InfinityCrystalOfGeneralizedYoungWalls,cls).__classcall__(cls,n,category) + return super().__classcall__(cls,n,category) def __init__(self, n, category): r""" @@ -1028,7 +1028,7 @@ def __classcall_private__(cls, n, La): True """ La = RootSystem(['A',n,1]).weight_lattice(extended=True)(La) - return super(CrystalOfGeneralizedYoungWalls, cls).__classcall__(cls, n, La) + return super().__classcall__(cls, n, La) def __init__(self, n, La): r""" @@ -1067,6 +1067,6 @@ def __iter__(self): sage: next(x) [0] """ - for c in super(CrystalOfGeneralizedYoungWalls, self).__iter__(): + for c in super().__iter__(): if c.in_highest_weight_crystal(self.hw): yield c diff --git a/src/sage/combinat/crystals/induced_structure.py b/src/sage/combinat/crystals/induced_structure.py index 1e89220f3ea..a2265e8df71 100644 --- a/src/sage/combinat/crystals/induced_structure.py +++ b/src/sage/combinat/crystals/induced_structure.py @@ -27,6 +27,7 @@ from sage.structure.parent import Parent from sage.structure.element_wrapper import ElementWrapper + class InducedCrystal(UniqueRepresentation, Parent): r""" A crystal induced from an injection. @@ -120,7 +121,7 @@ def __classcall_private__(cls, X, phi, inverse=None, from_crystal=False): if from_crystal: return InducedFromCrystal(X, phi, inverse) - return super(InducedCrystal, cls).__classcall__(cls, X, phi, inverse) + return super().__classcall__(cls, X, phi, inverse) def __init__(self, X, phi, inverse): """ diff --git a/src/sage/combinat/crystals/infinity_crystals.py b/src/sage/combinat/crystals/infinity_crystals.py index 0edf826c73e..7fa7e5f7a2d 100644 --- a/src/sage/combinat/crystals/infinity_crystals.py +++ b/src/sage/combinat/crystals/infinity_crystals.py @@ -206,7 +206,7 @@ def __classcall_private__(cls, cartan_type): return InfinityCrystalOfTableauxTypeD(cartan_type) if cartan_type.type() == 'Q': return DualInfinityQueerCrystalOfTableaux(cartan_type) - return super(InfinityCrystalOfTableaux, cls).__classcall__(cls, cartan_type) + return super().__classcall__(cls, cartan_type) def __init__(self, cartan_type): """ @@ -288,7 +288,7 @@ def _coerce_map_from_(self, P): or isinstance(P, InfinityCrystalOfNonSimplyLacedRC))): from sage.combinat.rigged_configurations.bij_infinity import FromRCIsomorphism return FromRCIsomorphism(Hom(P, self)) - return super(InfinityCrystalOfTableaux, self)._coerce_map_from_(P) + return super()._coerce_map_from_(P) class Element(InfinityCrystalOfTableauxElement): r""" @@ -605,7 +605,7 @@ def __classcall_private__(cls, cartan_type): sage: B is B2 True """ - return super(InfinityCrystalOfTableauxTypeD, cls).__classcall__(cls, CartanType(cartan_type)) + return super().__classcall__(cls, CartanType(cartan_type)) @cached_method def module_generator(self): @@ -633,6 +633,7 @@ class Element(InfinityCrystalOfTableauxElementTypeD, InfinityCrystalOfTableaux.E """ pass + ######################################################### ## Queer superalgebra @@ -650,7 +651,7 @@ def __classcall_private__(cls, cartan_type): True """ cartan_type = CartanType(cartan_type) - return super(DualInfinityQueerCrystalOfTableaux, cls).__classcall__(cls, cartan_type) + return super().__classcall__(cls, cartan_type) def __init__(self, cartan_type): """ diff --git a/src/sage/combinat/crystals/kac_modules.py b/src/sage/combinat/crystals/kac_modules.py index f6244cd4158..90edd27d93d 100644 --- a/src/sage/combinat/crystals/kac_modules.py +++ b/src/sage/combinat/crystals/kac_modules.py @@ -62,7 +62,7 @@ def __classcall_private__(cls, cartan_type): sage: S1 is S2 True """ - return super(CrystalOfOddNegativeRoots, cls).__classcall__(cls, CartanType(cartan_type)) + return super().__classcall__(cls, CartanType(cartan_type)) def __init__(self, cartan_type): """ @@ -430,6 +430,7 @@ def weight(self): e = WLR.basis() return WLR.sum(-e[i]+e[j] for (i,j) in self.value) + class CrystalOfKacModule(UniqueRepresentation, Parent): r""" Crystal of a Kac module. @@ -530,7 +531,7 @@ def __classcall_private__(cls, cartan_type, la, mu): cartan_type = CartanType(cartan_type) la = _Partitions(la) mu = _Partitions(mu) - return super(CrystalOfKacModule, cls).__classcall__(cls, cartan_type, la, mu) + return super().__classcall__(cls, cartan_type, la, mu) def __init__(self, cartan_type, la, mu): """ diff --git a/src/sage/combinat/crystals/kyoto_path_model.py b/src/sage/combinat/crystals/kyoto_path_model.py index 12d3af264a6..6ee4d0e58a4 100644 --- a/src/sage/combinat/crystals/kyoto_path_model.py +++ b/src/sage/combinat/crystals/kyoto_path_model.py @@ -227,7 +227,7 @@ def __classcall_private__(cls, crystals, weight, P=None): enumerate(P.simple_coroots()) ) != level: raise ValueError( "{} is not a level {} weight".format(weight, level) ) - return super(KyotoPathModel, cls).__classcall__(cls, crystals, weight, P) + return super().__classcall__(cls, crystals, weight, P) def __init__(self, crystals, weight, P): """ diff --git a/src/sage/combinat/crystals/letters.pyx b/src/sage/combinat/crystals/letters.pyx index 8a06939ce07..ccd57d461bf 100644 --- a/src/sage/combinat/crystals/letters.pyx +++ b/src/sage/combinat/crystals/letters.pyx @@ -116,6 +116,7 @@ def CrystalOfLetters(cartan_type, element_print_style=None, dual=None): else: raise NotImplementedError + class ClassicalCrystalOfLetters(UniqueRepresentation, Parent): r""" A generic class for classical crystals of letters. @@ -166,7 +167,7 @@ class ClassicalCrystalOfLetters(UniqueRepresentation, Parent): C = CrystalOfNakajimaMonomials(cartan_type, la) hw = C.highest_weight_vector() self.module_generators = (self._element_constructor_(hw),) - self._list = [x for x in super(ClassicalCrystalOfLetters, self).__iter__()] + self._list = [x for x in super().__iter__()] elif cartan_type.type() == 'F': from sage.combinat.crystals.monomial_crystals import CrystalOfNakajimaMonomials from sage.combinat.root_system.root_system import RootSystem @@ -174,7 +175,7 @@ class ClassicalCrystalOfLetters(UniqueRepresentation, Parent): C = CrystalOfNakajimaMonomials(cartan_type, la) hw = C.highest_weight_vector() self.module_generators = (self._element_constructor_(hw),) - self._list = [x for x in super(ClassicalCrystalOfLetters, self).__iter__()] + self._list = [x for x in super().__iter__()] else: self.module_generators = (self._element_constructor_(1),) if cartan_type.type() == 'G': @@ -2520,7 +2521,7 @@ class CrystalOfBKKLetters(ClassicalCrystalOfLetters): if dual is None: dual = False ct = CartanType(ct) - return super(CrystalOfBKKLetters, cls).__classcall__(cls, ct, dual) + return super().__classcall__(cls, ct, dual) def __init__(self, ct, dual): """ @@ -2613,7 +2614,7 @@ class CrystalOfQueerLetters(ClassicalCrystalOfLetters): The queer crystal of letters for q(3) """ ct = CartanType(ct) - return super(CrystalOfQueerLetters, cls).__classcall__(cls, ct) + return super().__classcall__(cls, ct) def __init__(self, ct): """ diff --git a/src/sage/combinat/crystals/littelmann_path.py b/src/sage/combinat/crystals/littelmann_path.py index 9eb8ecd6dcd..2ddd6f3c461 100644 --- a/src/sage/combinat/crystals/littelmann_path.py +++ b/src/sage/combinat/crystals/littelmann_path.py @@ -702,7 +702,8 @@ def __classcall_private__(cls, weight): raise ValueError("The weight should be in the non-extended weight lattice!") La = weight.parent().basis() weight = weight - weight.level() * La[0] / La[0].level() - return super(CrystalOfLSPaths, cls).__classcall__(cls, weight, starting_weight_parent = weight.parent()) + return super().__classcall__(cls, weight, + starting_weight_parent=weight.parent()) @cached_method def maximal_vector(self): @@ -1208,7 +1209,7 @@ def __classcall_private__(cls, cartan_type): True """ cartan_type = CartanType(cartan_type) - return super(InfinityCrystalOfLSPaths, cls).__classcall__(cls, cartan_type) + return super().__classcall__(cls, cartan_type) def __init__(self, cartan_type): """ diff --git a/src/sage/combinat/crystals/monomial_crystals.py b/src/sage/combinat/crystals/monomial_crystals.py index 43d71f16747..9accb0195e5 100644 --- a/src/sage/combinat/crystals/monomial_crystals.py +++ b/src/sage/combinat/crystals/monomial_crystals.py @@ -836,7 +836,7 @@ def __classcall_private__(cls, ct, c=None): cartan_type = CartanType(ct) n = len(cartan_type.index_set()) c = InfinityCrystalOfNakajimaMonomials._normalize_c(c, n) - M = super(InfinityCrystalOfNakajimaMonomials, cls).__classcall__(cls, cartan_type, c) + M = super().__classcall__(cls, cartan_type, c) M.set_variables('Y') return M @@ -1074,7 +1074,7 @@ def f(self, i): """ if self.phi(i) == 0: return None - return super(CrystalOfNakajimaMonomialsElement, self).f(i) + return super().f(i) def weight(self): r""" @@ -1197,7 +1197,7 @@ def __classcall_private__(cls, cartan_type, La=None, c=None): La = RootSystem(cartan_type).weight_lattice()(La) n = len(cartan_type.index_set()) c = InfinityCrystalOfNakajimaMonomials._normalize_c(c, n) - return super(CrystalOfNakajimaMonomials, cls).__classcall__(cls, cartan_type, La, c) + return super().__classcall__(cls, cartan_type, La, c) def __init__(self, ct, La, c): r""" @@ -1252,6 +1252,6 @@ def cardinality(self): """ if not self.cartan_type().is_finite(): return Infinity - return super(InfinityCrystalOfNakajimaMonomials, self).cardinality() + return super().cardinality() Element = CrystalOfNakajimaMonomialsElement diff --git a/src/sage/combinat/crystals/pbw_crystal.py b/src/sage/combinat/crystals/pbw_crystal.py index 1803b501f9e..4a313c8fa78 100644 --- a/src/sage/combinat/crystals/pbw_crystal.py +++ b/src/sage/combinat/crystals/pbw_crystal.py @@ -401,7 +401,7 @@ def __classcall__(cls, cartan_type): cartan_type = CartanType(cartan_type) if not cartan_type.is_finite(): raise NotImplementedError("only implemented for finite types") - return super(PBWCrystal, cls).__classcall__(cls, cartan_type) + return super().__classcall__(cls, cartan_type) def __init__(self, cartan_type): """ diff --git a/src/sage/combinat/crystals/polyhedral_realization.py b/src/sage/combinat/crystals/polyhedral_realization.py index 2860eec417c..a709284149f 100644 --- a/src/sage/combinat/crystals/polyhedral_realization.py +++ b/src/sage/combinat/crystals/polyhedral_realization.py @@ -25,6 +25,7 @@ from sage.combinat.crystals.elementary_crystals import ElementaryCrystal from sage.combinat.root_system.cartan_type import CartanType + class InfinityCrystalAsPolyhedralRealization(TensorProductOfCrystals): r""" The polyhedral realization of `B(\infty)`. @@ -156,7 +157,7 @@ def __classcall_private__(cls, cartan_type, seq=None): seq = tuple(seq) if set(seq) != set(cartan_type.index_set()): raise ValueError("the support of seq is not the index set") - return super(InfinityCrystalAsPolyhedralRealization, cls).__classcall__(cls, cartan_type, seq) + return super().__classcall__(cls, cartan_type, seq) def __init__(self, cartan_type, seq): """ diff --git a/src/sage/combinat/crystals/subcrystal.py b/src/sage/combinat/crystals/subcrystal.py index 9881a021e27..22e22453488 100644 --- a/src/sage/combinat/crystals/subcrystal.py +++ b/src/sage/combinat/crystals/subcrystal.py @@ -159,11 +159,11 @@ def __classcall_private__(cls, ambient, contained=None, generators=None, generators, cartan_type, index_set, category) # We need to give these as optional arguments so it unpickles correctly - return super(Subcrystal, cls).__classcall__(cls, ambient, contained, - tuple(generators), - cartan_type=cartan_type, - index_set=tuple(index_set), - category=category) + return super().__classcall__(cls, ambient, contained, + tuple(generators), + cartan_type=cartan_type, + index_set=tuple(index_set), + category=category) def __init__(self, ambient, contained, generators, cartan_type, index_set, category): """ @@ -291,7 +291,7 @@ def cardinality(self): if self in FiniteCrystals(): return Integer(len(self.list())) try: - card = super(Subcrystal, self).cardinality() + card = super().cardinality() except AttributeError: raise NotImplementedError("unknown cardinality") if card == infinity: diff --git a/src/sage/combinat/crystals/tensor_product.py b/src/sage/combinat/crystals/tensor_product.py index c15eac03795..18d80008ccb 100644 --- a/src/sage/combinat/crystals/tensor_product.py +++ b/src/sage/combinat/crystals/tensor_product.py @@ -689,6 +689,7 @@ class FullTensorProductOfQueerSuperCrystals(FullTensorProductOfCrystals, QueerSu class Element(TensorProductOfQueerSuperCrystalsElement): pass + ######################################################### ## Crystal of tableaux @@ -931,7 +932,7 @@ def __classcall_private__(cls, cartan_type, shapes = None, shape = None): raise ValueError("shapes should all be partitions or half-integer partitions") if spin_shapes == shapes: shapes = tuple(_Partitions(shape) if shape[n1-1] in NN else shape for shape in shapes) - return super(CrystalOfTableaux, cls).__classcall__(cls, cartan_type, shapes) + return super().__classcall__(cls, cartan_type, shapes) # Handle the construction of a crystals of spin tableaux # Caveat: this currently only supports all shapes being half @@ -979,7 +980,7 @@ def __init__(self, cartan_type, shapes): sage: T = crystals.Tableaux(['A',3], shape = [2,2]) sage: TestSuite(T).run() """ -# super(CrystalOfTableaux, self).__init__(category = FiniteEnumeratedSets()) +# super().__init__(category = FiniteEnumeratedSets()) Parent.__init__(self, category = ClassicalCrystals()) self.letters = CrystalOfLetters(cartan_type) self.shapes = shapes diff --git a/src/sage/combinat/crystals/tensor_product_element.pyx b/src/sage/combinat/crystals/tensor_product_element.pyx index b7f60016ecc..fad1ced578d 100644 --- a/src/sage/combinat/crystals/tensor_product_element.pyx +++ b/src/sage/combinat/crystals/tensor_product_element.pyx @@ -478,6 +478,7 @@ cdef class TensorProductOfCrystalsElement(ImmutableListWithParent): return self._set_index(-k, crystal) return None + cdef class TensorProductOfRegularCrystalsElement(TensorProductOfCrystalsElement): """ Element class for a tensor product of regular crystals. @@ -1651,6 +1652,7 @@ cdef class TensorProductOfQueerSuperCrystalsElement(TensorProductOfRegularCrysta x = x.f(i) return string_length + cdef class InfinityQueerCrystalOfTableauxElement(TensorProductOfQueerSuperCrystalsElement): def __init__(self, parent, list, row_lengths=[]): """ @@ -1673,7 +1675,7 @@ cdef class InfinityQueerCrystalOfTableauxElement(TensorProductOfQueerSuperCrysta row_lengths.append(len(row)) list = ret self._row_lengths = row_lengths - super(InfinityQueerCrystalOfTableauxElement, self).__init__(parent, list) + super().__init__(parent, list) def _repr_(self): r""" @@ -1768,7 +1770,7 @@ cdef class InfinityQueerCrystalOfTableauxElement(TensorProductOfQueerSuperCrysta [[4, 4, 4, 4, 4, 3, 2, 1], [3, 3, 3, 3], [2, 2, 1], [1]] sage: t.e(-1) """ - ret = super(InfinityQueerCrystalOfTableauxElement, self).e(i) + ret = super().e(i) if ret is None: return None ( ret)._row_lengths = self._row_lengths diff --git a/src/sage/combinat/crystals/virtual_crystal.py b/src/sage/combinat/crystals/virtual_crystal.py index a537a64bfb8..0283b4a9543 100644 --- a/src/sage/combinat/crystals/virtual_crystal.py +++ b/src/sage/combinat/crystals/virtual_crystal.py @@ -23,14 +23,13 @@ # # http://www.gnu.org/licenses/ #**************************************************************************** - - from sage.categories.crystals import Crystals from sage.categories.finite_crystals import FiniteCrystals from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.crystals.subcrystal import Subcrystal from sage.sets.family import Family + class VirtualCrystal(Subcrystal): r""" A virtual crystal `V` of an ambient crystal `\widehat{B}` is a crystal @@ -195,9 +194,10 @@ def __classcall_private__(cls, ambient, virtualization, scaling_factors, if ambient in FiniteCrystals() or isinstance(contained, frozenset): category = category.Finite() - return super(Subcrystal, cls).__classcall__(cls, ambient, virtualization, scaling_factors, - contained, tuple(generators), cartan_type, - tuple(index_set), category) + return super().__classcall__(cls, ambient, virtualization, + scaling_factors, contained, + tuple(generators), cartan_type, + tuple(index_set), category) def __init__(self, ambient, virtualization, scaling_factors, contained, generators, cartan_type, index_set, category): diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index ed8504ebc95..4c5deb5ce21 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -428,7 +428,6 @@ class NoConvergenceError(RuntimeError): A special :python:`RuntimeError` which is raised when an algorithm does not converge/stop. """ - pass class AsymptoticExpansion(CommutativeAlgebraElement): @@ -666,7 +665,7 @@ def __init__(self, parent, summands, simplify=True, convert=True): sage: 1 + (-1)^x + 2^x + (-2)^x 2^x + 2^x*(-1)^x + (-1)^x + 1 """ - super(AsymptoticExpansion, self).__init__(parent=parent) + super().__init__(parent=parent) from sage.data_structures.mutable_poset import MutablePoset if not isinstance(summands, MutablePoset): @@ -716,7 +715,6 @@ def summands(self): """ return self._summands_ - def __hash__(self): r""" A hash value for this element. @@ -736,7 +734,6 @@ def __hash__(self): """ return hash(str(self)) - def __bool__(self): r""" Return whether this asymptotic expansion is not identically zero. @@ -761,8 +758,6 @@ def __bool__(self): """ return bool(self._summands_) - - def __eq__(self, other): r""" Return whether this asymptotic expansion is equal to ``other``. @@ -805,7 +800,6 @@ def __eq__(self, other): except (TypeError, ValueError): return False - def __ne__(self, other): r""" Return whether this asymptotic expansion is not equal to ``other``. @@ -838,7 +832,6 @@ def __ne__(self, other): """ return not self == other - def has_same_summands(self, other): r""" Return whether this asymptotic expansion and ``other`` have the @@ -887,7 +880,6 @@ def has_same_summands(self, other): lambda self, other: self._has_same_summands_(other)) - def _has_same_summands_(self, other): r""" Return whether this :class:`AsymptoticExpansion` has the same @@ -961,7 +953,6 @@ def _simplify_(self): """ self._summands_.merge(reverse=True) - def _repr_(self, latex=False): r""" A representation string for this asymptotic expansion. @@ -996,7 +987,6 @@ def _repr_(self, latex=False): return '0' return s - def _latex_(self): r""" A LaTeX-representation string for this asymptotic expansion. @@ -1015,7 +1005,6 @@ def _latex_(self): """ return self._repr_(latex=True) - def show(self): r""" Pretty-print this asymptotic expansion. @@ -1162,7 +1151,6 @@ def _add_(self, other): return self.parent()(self.summands.union(other.summands), simplify=True, convert=False) - def _sub_(self, other): r""" Subtract ``other`` from this asymptotic expansion. @@ -1191,7 +1179,6 @@ def _sub_(self, other): """ return self + self.parent().coefficient_ring(-1)*other - def _mul_term_(self, term): r""" Helper method: multiply this asymptotic expansion by the @@ -1408,10 +1395,8 @@ def __invert__(self, precision=None): return result._mul_term_(imax_elem) - invert = __invert__ - def truncate(self, precision=None): r""" Truncate this asymptotic expansion. @@ -1704,7 +1689,7 @@ def __pow__(self, exponent, precision=None): except (TypeError, ValueError): pass else: - return super(AsymptoticExpansion, self).__pow__(exponent) + return super().__pow__(exponent) from sage.rings.rational_field import QQ try: @@ -1926,7 +1911,6 @@ def sqrt(self, precision=None): from sage.rings.rational_field import QQ return self.pow(QQ(1)/QQ(2), precision=precision) - def O(self): r""" Convert all terms in this asymptotic expansion to `O`-terms. @@ -1972,7 +1956,6 @@ def O(self): return sum(self.parent().create_summand('O', growth=element) for element in self.summands.maximal_elements()) - def log(self, base=None, precision=None, locals=None): r""" The logarithm of this asymptotic expansion. @@ -2106,7 +2089,6 @@ def log(self, base=None, precision=None, locals=None): return result - def is_exact(self): r""" Return whether all terms of this expansion are exact. @@ -2132,7 +2114,6 @@ def is_exact(self): """ return all(T.is_exact() for T in self.summands) - def is_little_o_of_one(self): r""" Return whether this expansion is of order `o(1)`. @@ -2173,7 +2154,6 @@ def is_little_o_of_one(self): """ return all(term.is_little_o_of_one() for term in self.summands.maximal_elements()) - def rpow(self, base, precision=None, locals=None): r""" Return the power of ``base`` to this asymptotic expansion. @@ -2290,7 +2270,6 @@ def inverted_factorials(): return result * large_result - def _main_term_relative_error_(self, return_inverse_main_term=False): r""" Split this asymptotic expansion into `m(1+x)` with `x=o(1)`. @@ -2363,7 +2342,6 @@ def _main_term_relative_error_(self, return_inverse_main_term=False): else: return (max_elem, x) - @staticmethod def _power_series_(coefficients, start, ratio, ratio_start, precision): r""" @@ -2438,7 +2416,6 @@ def _power_series_(coefficients, start, ratio, ratio_start, precision): result = new_result return result - def exp(self, precision=None): r""" Return the exponential of (i.e., the power of `e` to) this asymptotic expansion. @@ -2508,7 +2485,6 @@ def exp(self, precision=None): """ return self.rpow('e', precision=precision) - def substitute(self, rules=None, domain=None, **kwds): r""" Substitute the given ``rules`` in this asymptotic expansion. @@ -2669,7 +2645,7 @@ def substitute(self, rules=None, domain=None, **kwds): # init and process keyword arguments gens = self.parent().gens() - locals = kwds or dict() + locals = kwds or {} # update with rules if isinstance(rules, dict): @@ -2784,7 +2760,6 @@ def _substitute_(self, rules): from .misc import substitute_raise_exception substitute_raise_exception(self, e) - def compare_with_values(self, variable, function, values, rescaled=True, ring=RIF): """ @@ -2944,7 +2919,6 @@ def function(arg): return points - def plot_comparison(self, variable, function, values, rescaled=True, ring=RIF, relative_tolerance=0.025, **kwargs): r""" @@ -3041,7 +3015,6 @@ def plot_comparison(self, variable, function, values, rescaled=True, return list_plot(points, **kwargs) - def symbolic_expression(self, R=None): r""" Return this asymptotic expansion as a symbolic expression. @@ -3096,10 +3069,8 @@ def symbolic_expression(self, R=None): for g in self.parent().gens()), domain=R) - _symbolic_ = symbolic_expression # will be used by SR._element_constructor_ - def map_coefficients(self, f, new_coefficient_ring=None): r""" Return the asymptotic expansion obtained by applying ``f`` to @@ -3154,7 +3125,6 @@ def mapping(term): S.map(mapping) return P(S, simplify=False, convert=False) - def factorial(self): r""" Return the factorial of this asymptotic expansion. @@ -3256,7 +3226,6 @@ def factorial(self): 'Cannot build the factorial of {} since it is not ' 'univariate.'.format(self)) - def variable_names(self): r""" Return the names of the variables of this asymptotic expansion. @@ -3291,7 +3260,6 @@ def variable_names(self): from itertools import groupby return tuple(v for v, _ in groupby(vars)) - def _singularity_analysis_(self, var, zeta, precision=None): r""" Return the asymptotic growth of the coefficients of some @@ -3597,7 +3565,6 @@ class AsymptoticRing(Algebra, UniqueRepresentation, WithLocals): # enable the category framework for elements Element = AsymptoticExpansion - @staticmethod def __classcall__(cls, growth_group=None, coefficient_ring=None, names=None, category=None, default_prec=None, @@ -3736,12 +3703,11 @@ def format_names(N): if locals is not None: locals = cls._convert_locals_(locals) - return super(AsymptoticRing, - cls).__classcall__(cls, growth_group, coefficient_ring, - category=category, - default_prec=default_prec, - term_monoid_factory=term_monoid_factory, - locals=locals) + return super().__classcall__(cls, growth_group, coefficient_ring, + category=category, + default_prec=default_prec, + term_monoid_factory=term_monoid_factory, + locals=locals) def __init__(self, growth_group, coefficient_ring, category, default_prec, @@ -3770,9 +3736,8 @@ def __init__(self, growth_group, coefficient_ring, self._default_prec_ = default_prec self._term_monoid_factory_ = term_monoid_factory self._locals_ = locals - super(AsymptoticRing, self).__init__(base_ring=coefficient_ring, - category=category) - + super().__init__(base_ring=coefficient_ring, + category=category) @property def growth_group(self): @@ -3791,7 +3756,6 @@ def growth_group(self): """ return self._growth_group_ - @property def coefficient_ring(self): r""" @@ -3805,7 +3769,6 @@ def coefficient_ring(self): """ return self._coefficient_ring_ - @property def default_prec(self): r""" @@ -3826,7 +3789,6 @@ def default_prec(self): """ return self._default_prec_ - @property def term_monoid_factory(self): r""" @@ -3844,7 +3806,6 @@ def term_monoid_factory(self): """ return self._term_monoid_factory_ - def term_monoid(self, type): r""" Return the term monoid of this asymptotic ring of specified ``type``. @@ -3874,7 +3835,6 @@ def term_monoid(self, type): TermMonoid = self.term_monoid_factory return TermMonoid(type, asymptotic_ring=self) - def change_parameter(self, **kwds): r""" Return an asymptotic ring with a change in one or more of the given parameters. @@ -3908,7 +3868,7 @@ def change_parameter(self, **kwds): """ parameters = ('growth_group', 'coefficient_ring', 'default_prec', 'term_monoid_factory') - values = dict() + values = {} category = self.category() values['category'] = category locals = self._locals_ @@ -3998,7 +3958,6 @@ def _create_element_in_extension_(self, term, old_term_parent=None): coefficient_ring=term.parent().coefficient_ring) return parent(term, simplify=False, convert=False) - def _element_constructor_(self, data, simplify=True, convert=True): r""" Convert a given object to this asymptotic ring. @@ -4223,7 +4182,6 @@ def _element_constructor_(self, data, simplify=True, convert=True): return self.create_summand('exact', data) - def _coerce_map_from_(self, R): r""" Return whether ``R`` coerces into this asymptotic ring. @@ -4277,7 +4235,6 @@ def _coerce_map_from_(self, R): self.coefficient_ring.has_coerce_map_from(R.coefficient_ring): return True - def _repr_(self): r""" A representation string of this asymptotic ring. @@ -4303,7 +4260,6 @@ def _repr_(self): G = repr(self.growth_group) return 'Asymptotic Ring %s over %s' % (G, self.coefficient_ring) - def _an_element_(self): r""" Return an element of this asymptotic ring. @@ -4330,7 +4286,6 @@ def _an_element_(self): return self(E.an_element(), simplify=False, convert=False)**3 + \ self(O.an_element(), simplify=False, convert=False) - def some_elements(self): r""" Return some elements of this term monoid. @@ -4369,7 +4324,6 @@ def some_elements(self): for e, o in cantor_product( E.some_elements(), O.some_elements())) - def gens(self): r""" Return a tuple with generators of this asymptotic ring. @@ -4404,7 +4358,6 @@ def gens(self): coefficient=self.coefficient_ring(1)) for g in self.growth_group.gens_monomial()) - def gen(self, n=0): r""" Return the ``n``-th generator of this asymptotic ring. @@ -4425,7 +4378,6 @@ def gen(self, n=0): """ return self.gens()[n] - def ngens(self): r""" Return the number of generators of this asymptotic ring. @@ -4446,7 +4398,6 @@ def ngens(self): """ return len(self.growth_group.gens_monomial()) - def coefficients_of_generating_function(self, function, singularities, precision=None, return_singular_expansions=False, error_term=None): @@ -4592,7 +4543,6 @@ def coefficients_of_generating_function(self, function, singularities, precision else: return result - def create_summand(self, type, data=None, **kwds): r""" Create a simple asymptotic expansion consisting of a single @@ -4686,7 +4636,6 @@ def create_summand(self, type, data=None, **kwds): except ZeroCoefficientError: return self.zero() - def variable_names(self): r""" Return the names of the variables. @@ -4703,7 +4652,6 @@ def variable_names(self): """ return self.growth_group.variable_names() - def construction(self): r""" Return the construction of this asymptotic ring. @@ -4822,7 +4770,6 @@ class AsymptoticRingFunctor(ConstructionFunctor): rank = 13 - def __init__(self, growth_group, default_prec=None, category=None, term_monoid_factory=None, locals=None, @@ -4848,9 +4795,7 @@ def __init__(self, growth_group, self._locals_ = locals from sage.categories.rings import Rings - super(ConstructionFunctor, self).__init__( - Rings(), Rings()) - + super().__init__(Rings(), Rings()) def _repr_(self): r""" @@ -4877,7 +4822,6 @@ def _repr_(self): return '{}<{}>'.format(self.cls.__name__, self.growth_group._repr_(condense=True)) - def _apply_functor(self, coefficient_ring): r""" Apply this functor to the given ``coefficient_ring``. @@ -4930,7 +4874,6 @@ def _apply_functor(self, coefficient_ring): kwds[parameter] = value return self.cls(**kwds) - def merge(self, other): r""" Merge this functor with ``other`` if possible. @@ -5027,7 +4970,6 @@ def merge(self, other): category=category, cls=self.cls) - def __eq__(self, other): r""" Return whether this functor is equal to ``other``. @@ -5057,7 +4999,6 @@ def __eq__(self, other): and self._category_ == other._category_ and self.cls == other.cls) - def __ne__(self, other): r""" Return whether this functor is not equal to ``other``. diff --git a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py index e80235a7d9d..ec4c5ce878f 100644 --- a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +++ b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py @@ -336,7 +336,7 @@ def __init__(self, parent, numerator, denominator_factored, reduce=True): sage: f = FFPD(x, df) sage: TestSuite(f).run() """ - super(FractionWithFactoredDenominator, self).__init__(parent) + super().__init__(parent) from sage.rings.semirings.non_negative_integer_semiring import NN self._numerator = parent._numerator_ring(numerator) @@ -1940,7 +1940,7 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, sub_final=[Tstar, atP], rekey=AA) Phitu_derivs = diff_all(Phitu, T, N - 1 + v, sub=hderivs1, sub_final=[Tstar, atP], - zero_order=v + 1 , rekey=BB) + zero_order=v + 1, rekey=BB) AABB_derivs = At_derivs AABB_derivs.update(Phitu_derivs) AABB_derivs[AA] = At.subs(Tstar).subs(atP) @@ -2007,7 +2007,7 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, AABB_derivs[BB] = Phitu.subs(Tstar).subs(atP) if verbose: print("Computing second order differential operator actions...") - DD = diff_op(AA, BB, AABB_derivs, T, a_inv, 1 , N) + DD = diff_op(AA, BB, AABB_derivs, T, a_inv, 1, N) # Plug above into asymptotic formula. L = [] @@ -3066,8 +3066,8 @@ def __classcall_private__(cls, denominator_ring, numerator_ring=None, category=N 'denominator ring {}'.format( numerator_ring, denominator_ring)) category = Rings().or_subcategory(category) - return super(FractionWithFactoredDenominatorRing, cls).__classcall__(cls, - denominator_ring, numerator_ring, category) + return super().__classcall__(cls, denominator_ring, + numerator_ring, category) def __init__(self, denominator_ring, numerator_ring=None, category=None): r""" @@ -3792,7 +3792,7 @@ def subs_all(f, sub, simplify=False): sage: var('x, y') (x, y) sage: a = {'foo': x**2 + y**2, 'bar': x - y} - sage: b = {x: 1 , y: 2} + sage: b = {x: 1, y: 2} sage: subs_all(a, b) {'bar': -1, 'foo': 5} """ diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 3f2e6d7e692..645d9723e68 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -512,7 +512,7 @@ def convert_factors(data, raw_data): # room for other parents (e.g. polynomial ring et al.) try: - return super(GenericProduct, self)._element_constructor_(data) + return super()._element_constructor_(data) except (TypeError, ValueError): pass if isinstance(data, (tuple, list, CartesianProduct.Element)): @@ -1441,9 +1441,7 @@ def __init__(self, sets, category, **kwargs): sage: type(GrowthGroup('x^ZZ * log(x)^ZZ')) # indirect doctest """ - super(UnivariateProduct, self).__init__( - sets, category, order='lex', **kwargs) - + super().__init__(sets, category, order='lex', **kwargs) CartesianProduct = CartesianProductGrowthGroups @@ -1474,8 +1472,6 @@ def __init__(self, sets, category, **kwargs): sage: type(GrowthGroup('x^ZZ * y^ZZ')) # indirect doctest """ - super(MultivariateProduct, self).__init__( - sets, category, order='product', **kwargs) - + super().__init__(sets, category, order='product', **kwargs) CartesianProduct = CartesianProductGrowthGroups diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 33388f9f183..8117d8ede30 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -17,7 +17,7 @@ ============================== """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Daniel Krenn # # This program is free software: you can redistribute it and/or modify @@ -25,8 +25,7 @@ # 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.sage_object import SageObject @@ -269,7 +268,7 @@ def is_balanced(s): return False return bool(open == 0) - factors = list() + factors = [] balanced = True if string and op is not None and string.startswith(op): raise ValueError("'%s' is invalid since it starts with a '%s'." % @@ -357,10 +356,8 @@ def add_parentheses(s, op): if any(sig in s for sig in signals) or latex and s.startswith(r'\frac'): if latex: return r'\left({}\right)'.format(s) - else: - return '({})'.format(s) - else: - return s + return '({})'.format(s) + return s return add_parentheses(left, op) + op + add_parentheses(right, op) @@ -843,7 +840,7 @@ def __init__(self, asymptotic_ring=None, var=None, exact_part=0): exact_part = asymptotic_ring.zero() self.exact_part = exact_part - super(NotImplementedOZero, self).__init__(message) + super().__init__(message) class NotImplementedBZero(NotImplementedError): @@ -913,7 +910,7 @@ def __init__(self, asymptotic_ring=None, var=None, exact_part=0): exact_part = asymptotic_ring.zero() self.exact_part = exact_part - super(NotImplementedBZero, self).__init__(message) + super().__init__(message) def transform_category(category, @@ -1081,7 +1078,7 @@ def __getitem__(self, key): """ try: - return super(Locals, self).__getitem__(key) + return super().__getitem__(key) except KeyError as ke: try: return self.default_locals()[key] @@ -1188,8 +1185,7 @@ def _convert_locals_(locals): """ if locals is None: return Locals() - else: - return Locals(locals) + return Locals(locals) def locals(self, locals=None): r""" diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 36b3d2e4f33..b5b39091371 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -1864,7 +1864,7 @@ def _element_constructor_(self, data, *args, **kwds): f'takes one positional argument, ' f'another positional argument is deprecated, ' f'but {len(args)+1} were given') - elif len(args) == 1: + if len(args) == 1: from sage.misc.superseded import deprecation deprecation(32215, "Passing 'coefficient' as a positional argument is deprecated; " @@ -4877,7 +4877,7 @@ def _absorb_(self, other): if not (self.growth >= other.growth): raise ArithmeticError(f'{self} cannot absorb {other}') - valid_from_new = dict() + valid_from_new = {} for variable_name in set().union(self.valid_from.keys(), other.valid_from.keys()): if variable_name in self.valid_from and other.valid_from: valid_from_new[variable_name] = (max(self.valid_from[variable_name], other.valid_from[variable_name])) @@ -5339,7 +5339,7 @@ def __init__(self, name, sage: type(MyTermMonoid('B', G, QQ)) """ - super(TermMonoidFactory, self).__init__(name) + super().__init__(name) if exact_term_monoid_class is None: exact_term_monoid_class = ExactTermMonoid From cc504c598b2358603025df90f8c8ebce315c327f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 6 Aug 2022 18:10:56 +0200 Subject: [PATCH 178/742] oops --- src/sage/combinat/crystals/fast_crystals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/crystals/fast_crystals.py b/src/sage/combinat/crystals/fast_crystals.py index 9899f87122b..86e3d39cfc3 100644 --- a/src/sage/combinat/crystals/fast_crystals.py +++ b/src/sage/combinat/crystals/fast_crystals.py @@ -1,4 +1,4 @@ -sr""" +r""" Fast Rank Two Crystals """ # **************************************************************************** From f6bf70bca1123ec6f9be720da698558caf3e4ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 6 Aug 2022 19:03:32 +0200 Subject: [PATCH 179/742] fixing some W391 (removing empty final lines) --- src/sage/algebras/lie_algebras/subalgebra.py | 3 --- src/sage/all_cmdline.py | 9 +++------ src/sage/calculus/predefined.py | 1 - src/sage/coding/grs_code.py | 1 - src/sage/coding/self_dual_codes.py | 8 +++----- src/sage/crypto/classical_cipher.py | 13 ++++--------- src/sage/crypto/mq/mpolynomialsystemgenerator.py | 9 ++++----- src/sage/ext_data/nbconvert/postprocess.py | 4 +--- src/sage/finance/markov_multifractal.py | 1 - src/sage/functions/orthogonal_polys.py | 2 +- src/sage/game_theory/parser.py | 3 +-- src/sage/games/hexad.py | 1 - src/sage/homology/algebraic_topological_model.py | 4 +--- src/sage/homology/chain_complex.py | 1 - src/sage/homology/chain_homotopy.py | 4 ++-- src/sage/homology/homology_group.py | 7 ++----- .../homology/homology_vector_space_with_basis.py | 4 +--- src/sage/homology/koszul_complex.py | 5 ++--- src/sage/homology/matrix_utils.py | 4 +--- src/sage/homology/simplicial_complex_homset.py | 1 - src/sage/interfaces/axiom.py | 1 - src/sage/interfaces/gap.py | 1 - src/sage/interfaces/gnuplot.py | 4 ---- src/sage/interfaces/macaulay2.py | 2 -- src/sage/interfaces/mupad.py | 1 - src/sage/interfaces/mwrank.py | 1 - src/sage/interfaces/polymake.py | 1 - src/sage/interfaces/primecount.py | 1 - src/sage/interfaces/qepcad.py | 2 -- src/sage/interfaces/scilab.py | 1 - src/sage/interfaces/sympy.py | 3 +-- src/sage/libs/gap/all.py | 4 ---- src/sage/libs/gap/test_long.py | 12 ++++-------- src/sage/libs/lrcalc/lrcalc.py | 2 +- src/sage/libs/mpmath/all.py | 9 ++++----- src/sage/logic/logicparser.py | 4 +--- 36 files changed, 37 insertions(+), 97 deletions(-) diff --git a/src/sage/algebras/lie_algebras/subalgebra.py b/src/sage/algebras/lie_algebras/subalgebra.py index baa633c1cb7..90779eb91fc 100644 --- a/src/sage/algebras/lie_algebras/subalgebra.py +++ b/src/sage/algebras/lie_algebras/subalgebra.py @@ -5,7 +5,6 @@ - Eero Hakavuori (2018-08-29): initial version """ - # **************************************************************************** # Copyright (C) 2018 Eero Hakavuori # @@ -15,7 +14,6 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.algebras.lie_algebras.lie_algebra_element import LieSubalgebraElementWrapper from sage.categories.lie_algebras import LieAlgebras from sage.categories.homset import Hom @@ -975,4 +973,3 @@ def adjoint_matrix(self, sparse=False): return matrix(self.base_ring(), [M.coordinate_vector(P.bracket(self, b).to_vector(sparse=sparse)) for b in basis], sparse=sparse).transpose() - diff --git a/src/sage/all_cmdline.py b/src/sage/all_cmdline.py index 644d3f2c863..81c56b018ab 100644 --- a/src/sage/all_cmdline.py +++ b/src/sage/all_cmdline.py @@ -3,21 +3,18 @@ This is all.py (load all sage functions) plus set-up for the Sage commandline. """ - -#***************************************************************************** +# **************************************************************************** # 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/ +# **************************************************************************** sage_mode = 'cmdline' from sage.all import * from sage.calculus.predefined import x sage.misc.session.init() - diff --git a/src/sage/calculus/predefined.py b/src/sage/calculus/predefined.py index ea677fe15da..8e7f499b1ae 100644 --- a/src/sage/calculus/predefined.py +++ b/src/sage/calculus/predefined.py @@ -48,4 +48,3 @@ X = _var('X') Y = _var('Y') Z = _var('Z') - diff --git a/src/sage/coding/grs_code.py b/src/sage/coding/grs_code.py index 840152f75f9..230a4a1f7ee 100644 --- a/src/sage/coding/grs_code.py +++ b/src/sage/coding/grs_code.py @@ -2389,4 +2389,3 @@ def decoding_radius(self): GRSErrorErasureDecoder._decoder_type = {"error-erasure", "always-succeed"} GeneralizedReedSolomonCode._registered_decoders["KeyEquationSyndrome"] = GRSKeyEquationSyndromeDecoder GRSKeyEquationSyndromeDecoder._decoder_type = {"hard-decision", "always-succeed"} - diff --git a/src/sage/coding/self_dual_codes.py b/src/sage/coding/self_dual_codes.py index 199db9257a7..a0974add584 100644 --- a/src/sage/coding/self_dual_codes.py +++ b/src/sage/coding/self_dual_codes.py @@ -81,7 +81,7 @@ - [HP2003] \W. C. Huffman, V. Pless, Fundamentals of Error-Correcting Codes, Cambridge Univ. Press, 2003. -- [P] \V. Pless, "A classification of self-orthogonal codes over GF(2)", +- [P] \V. Pless, *A classification of self-orthogonal codes over GF(2)*, Discrete Math 3 (1972) 209-246. """ @@ -97,6 +97,7 @@ _F = GF(2) + def _MS(n): r""" For internal use; returns the floor(n/2) x n matrix space over GF(2). @@ -162,6 +163,7 @@ def _matId(n): Id.append(MSn.identity_matrix()) return Id + def _MS2(n): r""" For internal use; returns the floor(n/2) x floor(n/2) matrix space over GF(2). @@ -933,7 +935,3 @@ def self_dual_binary_codes(n): "3":self_dual_codes_22_3,"4":self_dual_codes_22_4,"5":self_dual_codes_22_5,\ "6":self_dual_codes_22_6} return self_dual_codes - - - - diff --git a/src/sage/crypto/classical_cipher.py b/src/sage/crypto/classical_cipher.py index 0fe8c6b9434..72ea18a3117 100644 --- a/src/sage/crypto/classical_cipher.py +++ b/src/sage/crypto/classical_cipher.py @@ -1,19 +1,18 @@ """ Classical Ciphers """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 David Kohel # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ -#***************************************************************************** - +# https://www.gnu.org/licenses/ +# **************************************************************************** from .cipher import SymmetricKeyCipher from sage.monoids.string_monoid_element import StringMonoidElement from sage.modules.free_module import FreeModule + class AffineCipher(SymmetricKeyCipher): r""" Affine cipher class. This is the class that does the actual work of @@ -574,7 +573,3 @@ def inverse(self): E = self.parent() K = E.inverse_key(self.key()) return E(K) - - - - diff --git a/src/sage/crypto/mq/mpolynomialsystemgenerator.py b/src/sage/crypto/mq/mpolynomialsystemgenerator.py index 9dd861ed469..3c0bb6b349c 100644 --- a/src/sage/crypto/mq/mpolynomialsystemgenerator.py +++ b/src/sage/crypto/mq/mpolynomialsystemgenerator.py @@ -2,11 +2,12 @@ Abstract base class for generators of polynomial systems AUTHOR: - Martin Albrecht -""" +Martin Albrecht +""" from sage.structure.sage_object import SageObject + class MPolynomialSystemGenerator(SageObject): """ Abstract base class for generators of polynomial systems. @@ -26,8 +27,7 @@ def __getattr__(self, attr): if attr == "R": self.R = self.ring() return self.R - else: - raise AttributeError("'%s' object has no attribute '%s'"%(self.__class__,attr)) + raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__,attr)) def varformatstr(self, name): """ @@ -196,4 +196,3 @@ def random_element(self): NotImplementedError """ raise NotImplementedError - diff --git a/src/sage/ext_data/nbconvert/postprocess.py b/src/sage/ext_data/nbconvert/postprocess.py index f36497fb73f..524c5b213a6 100755 --- a/src/sage/ext_data/nbconvert/postprocess.py +++ b/src/sage/ext_data/nbconvert/postprocess.py @@ -11,7 +11,6 @@ - Thierry Monteil (2018): initial version. """ - import sys import re @@ -27,7 +26,7 @@ # processing new_file = '' -for i,line in enumerate(lines): +for i, line in enumerate(lines): if line.startswith(' # ') and not wrong_title_fixed: new_file += re.sub('^ # ', '', line) new_file += '=' * (len(line) - 4) + '\n' @@ -44,4 +43,3 @@ # write new file with open(file_name, 'w') as f: f.write(new_file) - diff --git a/src/sage/finance/markov_multifractal.py b/src/sage/finance/markov_multifractal.py index 99b5968f051..6206f56b304 100644 --- a/src/sage/finance/markov_multifractal.py +++ b/src/sage/finance/markov_multifractal.py @@ -276,4 +276,3 @@ def simulations(self, n, k=1): ## OUTPUT: ## m0, sigma, gamma_kbar, b ## """ - diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 28f23f35ddf..012b05fa028 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -3028,5 +3028,5 @@ def eval_recursive(self, k, x, a, b, n, *args, **kwds): Hm2 = C * hahn.eval_recursive(k-2, x, a, b, n) return (Hm1 - Hm2) / A -hahn = Func_hahn() +hahn = Func_hahn() diff --git a/src/sage/game_theory/parser.py b/src/sage/game_theory/parser.py index 87b0676fecc..80d90d9a5cf 100644 --- a/src/sage/game_theory/parser.py +++ b/src/sage/game_theory/parser.py @@ -1,7 +1,6 @@ """ Parser For gambit And lrs Nash Equilibria """ - # **************************************************************************** # Copyright (C) 2014 James Campbell james.campbell@tanti.org.uk # 2015 Vincent Knight @@ -13,6 +12,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** + class Parser(): r""" A class for parsing the outputs of different algorithms called in other @@ -298,4 +298,3 @@ def format_gambit(self, gambit_game): nice_stuff.append(profile) return nice_stuff - diff --git a/src/sage/games/hexad.py b/src/sage/games/hexad.py index dff95e8e6b8..710513207a7 100644 --- a/src/sage/games/hexad.py +++ b/src/sage/games/hexad.py @@ -711,4 +711,3 @@ def blackjack_move(self, L0): return str(x) + ' --> ' + str(y) + ". The total went from " + str(total) + " to " + str(total - x + y) + "." print("This is a hexad. \n There is no winning move, so make a random legal move.") return L0 - diff --git a/src/sage/homology/algebraic_topological_model.py b/src/sage/homology/algebraic_topological_model.py index b14de9bdfa3..f89a1529dd9 100644 --- a/src/sage/homology/algebraic_topological_model.py +++ b/src/sage/homology/algebraic_topological_model.py @@ -12,7 +12,6 @@ - John H. Palmieri (2015-09) """ - ######################################################################## # Copyright (C) 2015 John H. Palmieri # @@ -20,7 +19,7 @@ # 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/ ######################################################################## # TODO: cythonize this. @@ -590,4 +589,3 @@ def conditionally_sparse(m): iota = ChainComplexMorphism(iota_data, M, C) phi = ChainContraction(phi_data, pi, iota) return phi, M - diff --git a/src/sage/homology/chain_complex.py b/src/sage/homology/chain_complex.py index 99fa87c9751..044379c0b28 100644 --- a/src/sage/homology/chain_complex.py +++ b/src/sage/homology/chain_complex.py @@ -2238,4 +2238,3 @@ def scalar(a): from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.homology.chain_complex', 'ChainComplex', ChainComplex_class) - diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index feac17c26b7..16a1c385edc 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -39,13 +39,14 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ######################################################################## from sage.categories.morphism import Morphism from sage.categories.homset import Hom from sage.homology.chain_complex_morphism import ChainComplexMorphism + # In a perfect world, this would inherit from something like # "TwoMorphism" rather than "Morphism"... class ChainHomotopy(Morphism): @@ -581,4 +582,3 @@ def dual(self): deg = self.domain().degree_of_differential() matrices = {i-deg: matrix_dict[i].transpose() for i in matrix_dict} return ChainContraction(matrices, self.iota().dual(), self.pi().dual()) - diff --git a/src/sage/homology/homology_group.py b/src/sage/homology/homology_group.py index adfac7717a0..0b27087a362 100644 --- a/src/sage/homology/homology_group.py +++ b/src/sage/homology/homology_group.py @@ -5,7 +5,6 @@ group that prints itself in a way that is suitable for homology groups. """ - ######################################################################## # Copyright (C) 2013 John H. Palmieri # Volker Braun @@ -14,7 +13,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ######################################################################## from sage.modules.free_module import VectorSpace @@ -182,6 +181,4 @@ def HomologyGroup(n, base_ring, invfac=None): invfac = [0] * (n - len(invfac)) + invfac elif len(invfac) > n: raise ValueError("invfac (={}) must have length n (={})".format(invfac, n)) - M = HomologyGroup_class(n, invfac) - return M - + return HomologyGroup_class(n, invfac) diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index 8861ee20ad9..63a80657917 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -14,7 +14,6 @@ - John H. Palmieri, Travis Scrimshaw (2015-09) """ - ######################################################################## # Copyright (C) 2015 John H. Palmieri # Travis Scrimshaw @@ -23,7 +22,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ######################################################################## from sage.misc.cachefunc import cached_method @@ -871,4 +870,3 @@ def sum_indices(k, i_k_plus_one, S_k_plus_one): return [[S_k]] return [[i_k] + l for i_k in range(S_k, i_k_plus_one) for l in sum_indices(k-1, i_k, S_k)] - diff --git a/src/sage/homology/koszul_complex.py b/src/sage/homology/koszul_complex.py index c83605db2f5..858d5a71283 100644 --- a/src/sage/homology/koszul_complex.py +++ b/src/sage/homology/koszul_complex.py @@ -1,7 +1,6 @@ """ Koszul Complexes """ - ######################################################################## # Copyright (C) 2014 Travis Scrimshaw # @@ -9,7 +8,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ######################################################################## from sage.structure.unique_representation import UniqueRepresentation @@ -22,6 +21,7 @@ import itertools + class KoszulComplex(ChainComplex_class, UniqueRepresentation): r""" A Koszul complex. @@ -166,4 +166,3 @@ def _repr_(self): if not self._elements: return "Trivial Koszul complex over {}".format(self.base_ring()) return "Koszul complex defined by {} over {}".format(self._elements, self.base_ring()) - diff --git a/src/sage/homology/matrix_utils.py b/src/sage/homology/matrix_utils.py index 1f2b583fc54..b1edc656e58 100644 --- a/src/sage/homology/matrix_utils.py +++ b/src/sage/homology/matrix_utils.py @@ -5,7 +5,6 @@ with the differentials thought of as matrices. This module contains some utility functions for this purpose. """ - ######################################################################## # Copyright (C) 2013 John H. Palmieri # @@ -13,7 +12,7 @@ # 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/ ######################################################################## # TODO: this module is a clear candidate for cythonizing. Need to @@ -203,4 +202,3 @@ def dhsw_snf(mat, verbose=False): if len(ed) < rows: return ed + [0]*(rows - len(ed)) return ed[:rows] - diff --git a/src/sage/homology/simplicial_complex_homset.py b/src/sage/homology/simplicial_complex_homset.py index 6a9d78f69f1..f5b54a59dc2 100644 --- a/src/sage/homology/simplicial_complex_homset.py +++ b/src/sage/homology/simplicial_complex_homset.py @@ -10,4 +10,3 @@ sage.topology.simplicial_complex_homset.is_SimplicialComplexHomset) SimplicialComplexHomset = deprecated_function_alias(31925, sage.topology.simplicial_complex_homset.SimplicialComplexHomset) - diff --git a/src/sage/interfaces/axiom.py b/src/sage/interfaces/axiom.py index c6ef330ae63..fa0334cfd4f 100644 --- a/src/sage/interfaces/axiom.py +++ b/src/sage/interfaces/axiom.py @@ -993,4 +993,3 @@ def axiom_console(): if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%axiom magics instead.') os.system('axiom -nox') - diff --git a/src/sage/interfaces/gap.py b/src/sage/interfaces/gap.py index c34fe530c34..ba175d4e340 100644 --- a/src/sage/interfaces/gap.py +++ b/src/sage/interfaces/gap.py @@ -1814,4 +1814,3 @@ def gap_console(): cmd, _ = gap_command(use_workspace_cache=False) cmd += ' ' + os.path.join(SAGE_EXTCODE,'gap','console.g') os.system(cmd) - diff --git a/src/sage/interfaces/gnuplot.py b/src/sage/interfaces/gnuplot.py index d93f6b33fb4..8ab14c75e1c 100644 --- a/src/sage/interfaces/gnuplot.py +++ b/src/sage/interfaces/gnuplot.py @@ -196,7 +196,3 @@ def gnuplot_console(): if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%gnuplot magics instead.') os.system('gnuplot') - - - - diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 2389aa7ab10..45f1a13e198 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -1866,7 +1866,6 @@ def macaulay2_console(): os.system('M2') - def reduce_load_macaulay2(): """ Used for reconstructing a copy of the Macaulay2 interpreter from a pickle. @@ -1878,4 +1877,3 @@ def reduce_load_macaulay2(): Macaulay2 """ return macaulay2 - diff --git a/src/sage/interfaces/mupad.py b/src/sage/interfaces/mupad.py index 077ef21e70d..a27b2d4d25f 100644 --- a/src/sage/interfaces/mupad.py +++ b/src/sage/interfaces/mupad.py @@ -693,4 +693,3 @@ def __doctest_cleanup(): """ import sage.interfaces.quit sage.interfaces.quit.expect_quitall() - diff --git a/src/sage/interfaces/mwrank.py b/src/sage/interfaces/mwrank.py index 636b7d6d961..384438d4a2a 100644 --- a/src/sage/interfaces/mwrank.py +++ b/src/sage/interfaces/mwrank.py @@ -362,4 +362,3 @@ def mwrank_console(): if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%mwrank magics instead.') os.system('mwrank') - diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index e335f33ae0a..82787d4eb02 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -2739,4 +2739,3 @@ def reduce_load_Polymake(): polymake = polymake_jupymake else: polymake = polymake_expect - diff --git a/src/sage/interfaces/primecount.py b/src/sage/interfaces/primecount.py index e037cb2794d..e647bf9b980 100644 --- a/src/sage/interfaces/primecount.py +++ b/src/sage/interfaces/primecount.py @@ -3,4 +3,3 @@ from sage.misc.lazy_import import lazy_import lazy_import("primecountpy.primecount", ['phi', 'nth_prime', 'prime_pi', 'prime_pi_128'], deprecation=(32894, "the module sage.interfaces.primecount is deprecated - use primecountpy.primecount instead")) - diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index 549877b392d..2378f765c8c 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -2752,6 +2752,4 @@ def sample_point_dict(self): """ points = self.sample_point() vars = self._parent._varlist - return dict([(vars[i], points[i]) for i in range(len(points))]) - diff --git a/src/sage/interfaces/scilab.py b/src/sage/interfaces/scilab.py index c1144d40ab0..c9e0daa1027 100644 --- a/src/sage/interfaces/scilab.py +++ b/src/sage/interfaces/scilab.py @@ -561,4 +561,3 @@ def scilab_version(): 'scilab-...' """ return str(scilab('getversion()')).strip() - diff --git a/src/sage/interfaces/sympy.py b/src/sage/interfaces/sympy.py index 74764b13716..2c847d56892 100644 --- a/src/sage/interfaces/sympy.py +++ b/src/sage/interfaces/sympy.py @@ -1181,7 +1181,7 @@ def sympy_set_to_list(set, vars): elif isinstance(set, (Union, Interval)): x = vars[0] if isinstance(set, Interval): - left,right,lclosed,rclosed = set._args + left, right, lclosed, rclosed = set._args if lclosed: rel1 = [x._sage_() > left._sage_()] else: @@ -1198,4 +1198,3 @@ def sympy_set_to_list(set, vars): if isinstance(set, Union): return [sympy_set_to_list(iv, vars) for iv in set._args] return set - diff --git a/src/sage/libs/gap/all.py b/src/sage/libs/gap/all.py index fd40910d9e7..e69de29bb2d 100644 --- a/src/sage/libs/gap/all.py +++ b/src/sage/libs/gap/all.py @@ -1,4 +0,0 @@ - - - - diff --git a/src/sage/libs/gap/test_long.py b/src/sage/libs/gap/test_long.py index 5a929ab4585..262db5ad287 100644 --- a/src/sage/libs/gap/test_long.py +++ b/src/sage/libs/gap/test_long.py @@ -3,7 +3,6 @@ These stress test the garbage collection inside GAP """ - from sage.libs.gap.libgap import libgap @@ -26,8 +25,8 @@ def test_loop_2(): sage: from sage.libs.gap.test_long import test_loop_2 sage: test_loop_2() # long time (10s on sage.math, 2013) """ - G =libgap.FreeGroup(2) - a,b = G.GeneratorsOfGroup() + G = libgap.FreeGroup(2) + a, b = G.GeneratorsOfGroup() for i in range(100): rel = libgap([a**2, b**2, a*b*a*b]) H = G / rel @@ -47,12 +46,9 @@ def test_loop_3(): sage: test_loop_3() # long time (31s on sage.math, 2013) """ G = libgap.FreeGroup(2) - (a,b) = G.GeneratorsOfGroup() + a, b = G.GeneratorsOfGroup() for i in range(300000): - lis=libgap([]) + lis = libgap([]) lis.Add(a ** 2) lis.Add(b ** 2) lis.Add(b * a) - - - diff --git a/src/sage/libs/lrcalc/lrcalc.py b/src/sage/libs/lrcalc/lrcalc.py index b541bfacd89..cf50d52a927 100644 --- a/src/sage/libs/lrcalc/lrcalc.py +++ b/src/sage/libs/lrcalc/lrcalc.py @@ -192,6 +192,7 @@ from sage.rings.integer import Integer import lrcalc + def _lrcalc_dict_to_sage(result): r""" Translate from lrcalc output format to Sage expected format. @@ -517,4 +518,3 @@ def lrskew(outer, inner, weight=None, maxrows=-1): w[j] += 1 if w == wt: yield ST.from_shape_and_word(shape, [i+1 for i in data]) - diff --git a/src/sage/libs/mpmath/all.py b/src/sage/libs/mpmath/all.py index c8d60c91142..cae40f79314 100644 --- a/src/sage/libs/mpmath/all.py +++ b/src/sage/libs/mpmath/all.py @@ -14,13 +14,12 @@ # Use mpmath internal functions for constants, to avoid unnecessary overhead _constants_funcs = { - 'glaisher' : glaisher_fixed, - 'khinchin' : khinchin_fixed, - 'twinprime' : twinprime_fixed, - 'mertens' : mertens_fixed + 'glaisher': glaisher_fixed, + 'khinchin': khinchin_fixed, + 'twinprime': twinprime_fixed, + 'mertens': mertens_fixed } def eval_constant(name, ring): prec = ring.precision() + 20 return ring(_constants_funcs[name](prec)) >> prec - diff --git a/src/sage/logic/logicparser.py b/src/sage/logic/logicparser.py index 08d9eb9c90d..b854f416127 100644 --- a/src/sage/logic/logicparser.py +++ b/src/sage/logic/logicparser.py @@ -82,7 +82,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** import string @@ -703,5 +703,3 @@ def apply_func(tree, func): lval = tree[1] rval = tree[2] return func([tree[0], lval, rval]) - - From b19a6aa1e86fa17a4d4c1ee0934780126ead2fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 7 Aug 2022 10:43:28 +0200 Subject: [PATCH 180/742] fix in crystal of letters --- src/sage/combinat/crystals/letters.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/crystals/letters.pyx b/src/sage/combinat/crystals/letters.pyx index ccd57d461bf..8eec7d22067 100644 --- a/src/sage/combinat/crystals/letters.pyx +++ b/src/sage/combinat/crystals/letters.pyx @@ -167,7 +167,7 @@ class ClassicalCrystalOfLetters(UniqueRepresentation, Parent): C = CrystalOfNakajimaMonomials(cartan_type, la) hw = C.highest_weight_vector() self.module_generators = (self._element_constructor_(hw),) - self._list = [x for x in super().__iter__()] + self._list = list(super(ClassicalCrystalOfLetters, self).__iter__()) elif cartan_type.type() == 'F': from sage.combinat.crystals.monomial_crystals import CrystalOfNakajimaMonomials from sage.combinat.root_system.root_system import RootSystem @@ -175,7 +175,7 @@ class ClassicalCrystalOfLetters(UniqueRepresentation, Parent): C = CrystalOfNakajimaMonomials(cartan_type, la) hw = C.highest_weight_vector() self.module_generators = (self._element_constructor_(hw),) - self._list = [x for x in super().__iter__()] + self._list = list(super(ClassicalCrystalOfLetters, self).__iter__()) else: self.module_generators = (self._element_constructor_(1),) if cartan_type.type() == 'G': From d4bf07b52c849cbe8e3ec2782994beb7e156d121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 7 Aug 2022 19:04:49 +0200 Subject: [PATCH 181/742] fix wrong change --- src/sage/combinat/crystals/monomial_crystals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/crystals/monomial_crystals.py b/src/sage/combinat/crystals/monomial_crystals.py index 9accb0195e5..5179ffd1a76 100644 --- a/src/sage/combinat/crystals/monomial_crystals.py +++ b/src/sage/combinat/crystals/monomial_crystals.py @@ -1252,6 +1252,6 @@ def cardinality(self): """ if not self.cartan_type().is_finite(): return Infinity - return super().cardinality() + return super(InfinityCrystalOfNakajimaMonomials, self).cardinality() Element = CrystalOfNakajimaMonomialsElement From 7358dc2e601061c28ad2d0a1cfbb16c6ce317f8c Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 8 Aug 2022 19:34:34 +0200 Subject: [PATCH 182/742] 34282: dd spkg='texlive', refactoring, pycodestyle --- src/sage/features/latex.py | 53 ++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py index 733a75df9d7..cf65aea6afc 100644 --- a/src/sage/features/latex.py +++ b/src/sage/features/latex.py @@ -16,8 +16,10 @@ from sage.features.join_feature import JoinFeature latex_url = 'https://www.latex-project.org/' +latex_spkg = 'texlive' -class latex(Executable): + +class LaTeX(Executable): r""" A :class:`~sage.features.Feature` describing the presence of ``latex`` @@ -27,7 +29,7 @@ class latex(Executable): sage: latex().is_present() # optional - latex FeatureTestResult('latex', True) """ - def __init__(self): + def __init__(self, name): r""" TESTS:: @@ -35,7 +37,7 @@ def __init__(self): sage: isinstance(latex(), latex) True """ - Executable.__init__(self, "latex", executable="latex", url=latex_url) + Executable.__init__(self, name, executable=name, spkg=latex_spkg, url=latex_url) def is_functional(self): r""" @@ -64,7 +66,7 @@ def is_functional(self): # running latex from subprocess import run - cmd = ['latex', '-interaction=nonstopmode', filename_tex] + cmd = [self.name, '-interaction=nonstopmode', filename_tex] cmd = ' '.join(cmd) result = run(cmd, shell=True, cwd=base, capture_output=True, text=True) @@ -73,10 +75,32 @@ def is_functional(self): return FeatureTestResult(self, True) else: return FeatureTestResult(self, False, reason="Running latex on " - "a sample file returned non-zero " - "exit status {}".format(result.returncode)) + "a sample file returned non-zero " + "exit status {}".format(result.returncode)) + + +class latex(LaTeX): + r""" + A :class:`~sage.features.Feature` describing the presence of ``latex`` + + EXAMPLES:: + + sage: from sage.features.latex import latex + sage: latex().is_present() # optional - latex + FeatureTestResult('latex', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.latex import latex + sage: isinstance(latex(), latex) + True + """ + LaTeX.__init__(self, "latex") -class pdflatex(Executable): + +class pdflatex(LaTeX): r""" A :class:`~sage.features.Feature` describing the presence of ``pdflatex`` @@ -94,9 +118,10 @@ def __init__(self): sage: isinstance(pdflatex(), pdflatex) True """ - Executable.__init__(self, "pdflatex", executable="pdflatex", url=latex_url) + LaTeX.__init__(self, "pdflatex") + -class xelatex(Executable): +class xelatex(LaTeX): r""" A :class:`~sage.features.Feature` describing the presence of ``xelatex`` @@ -114,10 +139,10 @@ def __init__(self): sage: isinstance(xelatex(), xelatex) True """ - Executable.__init__(self, "xelatex", executable="xelatex", url=latex_url) + LaTeX.__init__(self, "xelatex") -class lualatex(Executable): +class lualatex(LaTeX): r""" A :class:`~sage.features.Feature` describing the presence of ``lualatex`` @@ -135,7 +160,7 @@ def __init__(self): sage: isinstance(lualatex(), lualatex) True """ - Executable.__init__(self, "lualatex", executable="lualatex", url=latex_url) + LaTeX.__init__(self, "lualatex") class TeXFile(StaticFile, JoinFeature): @@ -158,7 +183,8 @@ def __init__(self, name, filename, **kwds): sage: LaTeXPackage("tkz-graph")._features [Feature('pdflatex')] """ - JoinFeature.__init__(self, name, [pdflatex()], url=latex_url) # see :trac:`34282` + JoinFeature.__init__(self, name, [pdflatex()], + spkg=latex_spkg, url=latex_url) # see :trac:`34282` StaticFile.__init__(self, name, filename, search_path=[], **kwds) def absolute_filename(self) -> str: @@ -199,6 +225,7 @@ def _is_present(self): return test return super(TeXFile, self)._is_present() + class LaTeXPackage(TeXFile): r""" A :class:`sage.features.Feature` describing the presence of a LaTeX package From 9bf5ba9ca610bcd9178c1a9574a8640d9fa5d444 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 9 Aug 2022 13:49:21 +0200 Subject: [PATCH 183/742] trac #34313: clean strongly_regular_db.pyx - part 3 --- src/sage/graphs/strongly_regular_db.pyx | 230 ++++++++++++------------ 1 file changed, 119 insertions(+), 111 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 027011ac677..53864cb24ee 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -532,6 +532,7 @@ def is_goethals_seidel(int v, int k, int l, int mu): from sage.graphs.generators.families import GoethalsSeidelGraph return [GoethalsSeidelGraph, k_bibd, r_bibd] + @cached_function def is_NOodd(int v, int k, int l, int mu): r""" @@ -587,20 +588,21 @@ def is_NOodd(int v, int k, int l, int mu): return r += 1 s += 1 - if abs(r)>abs(s): + if abs(r) > abs(s): (r, s) = (s, r) # r=-eq^(n-1) s= eq^(n-1)(q-2) q = 2 - s//r p, t = is_prime_power(q, get_data=True) pp, kk = is_prime_power(abs(r), get_data=True) - if p == pp and t != 0: - n = kk//t + 1 - e = 1 if v == (q**n)*(q**n+1)//2 else -1 - if (v == (q**n)*(q**n+e)//2 and - k == (q**n-e)*(q**(n-1)+e) and - l == 2*(q**(2*n-2)-1)+e*q**(n-1)*(q-1) and - mu == 2*q**(n-1)*(q**(n-1)+e)): + if p == pp and t: + n = kk//t + 1 + e = 1 if v == (q**n)*(q**n + 1)//2 else -1 + if (v == (q**n)*(q**n + e)//2 and + k == (q**n - e)*(q**(n - 1) + e) and + l == 2*(q**(2*n - 2) - 1) + e*q**(n - 1)*(q - 1) and + mu == 2*q**(n - 1)*(q**(n - 1) + e)): from sage.graphs.generators.classical_geometries import NonisotropicOrthogonalPolarGraph - return (NonisotropicOrthogonalPolarGraph, 2*n+1, q, '+' if e==1 else '-') + return (NonisotropicOrthogonalPolarGraph, 2*n + 1, q, '+' if e == 1 else '-') + @cached_function def is_NOperp_F5(int v, int k, int l, int mu): @@ -644,18 +646,19 @@ def is_NOperp_F5(int v, int k, int l, int mu): r, s = eigenvalues(v, k, l, mu) # 2*e*5**(n-1), -e*5**(n-1); note exceptional case n=1 if r is None: return - if abs(r)0 else -1 + e = 1 if r > 0 else -1 p, n = is_prime_power(abs(r), get_data=True) - if (3 == p and n != 0): + if 3 == p and n: n += 1 - if (v == 3**(n-1)*(3**n-e)//2 and - k == 3**(n-1)*(3**(n-1)-e)//2 and - l == 3**(n-2)*(3**(n-1)+e)//2 and - mu == 3**(n-1)*(3**(n-2)-e)//2): + if (v == 3**(n - 1)*(3**n - e)//2 and + k == 3**(n - 1)*(3**(n - 1) - e)//2 and + l == 3**(n - 2)*(3**(n - 1) + e)//2 and + mu == 3**(n - 1)*(3**(n - 2) - e)//2): from sage.graphs.generators.classical_geometries import NonisotropicOrthogonalPolarGraph - return (NonisotropicOrthogonalPolarGraph, 2*n, 3, '+' if e==1 else '-') + return (NonisotropicOrthogonalPolarGraph, 2*n, 3, '+' if e == 1 else '-') + @cached_function def is_NU(int v, int k, int l, int mu): @@ -805,29 +810,30 @@ def is_NU(int v, int k, int l, int mu): return r += 1 s += 1 - if abs(r)>abs(s): + if abs(r) > abs(s): (r, s) = (s, r) p, t = is_prime_power(abs(r), get_data=True) - if p==2: # it can be that q=2, then we'd have r>s now + if p == 2: # it can be that q=2, then we'd have r>s now pp, kk = is_prime_power(abs(s), get_data=True) - if pp==2 and kk>0: + if pp == 2 and kk > 0: (r, s) = (s, r) p, t = is_prime_power(abs(r), get_data=True) - if r==1: + if r == 1: return - kr = k//(r-1) # eq^{n-1}+1 - e = 1 if kr>0 else -1 + kr = k//(r-1) # eq^{n-1}+1 + e = 1 if kr > 0 else -1 q = (kr-1)//r pp, kk = is_prime_power(q, get_data=True) - if p == pp and kk != 0: - n = t//kk + 2 - if (v == q**(n-1)*(q**n - e)//(q + 1) and - k == (q**(n-1) + e)*(q**(n-2) - e) and - l == q**(2*n-5)*(q+1) - e*q**(n-2)*(q-1) - 2 and - mu == q**(n-3)*(q + 1)*(q**(n-2) - e)): + if p == pp and kk: + n = t//kk + 2 + if (v == q**(n - 1)*(q**n - e)//(q + 1) and + k == (q**(n - 1) + e)*(q**(n - 2) - e) and + l == q**(2*n - 5)*(q + 1) - e*q**(n - 2)*(q - 1) - 2 and + mu == q**(n - 3)*(q + 1)*(q**(n - 2) - e)): from sage.graphs.generators.classical_geometries import NonisotropicUnitaryPolarGraph return (NonisotropicUnitaryPolarGraph, n, q) + @cached_function def is_haemers(int v, int k, int l, int mu): r""" @@ -862,13 +868,14 @@ def is_haemers(int v, int k, int l, int mu): cdef int q, n, p p, n = is_prime_power(mu, get_data=True) q = mu - if 2 == p and n != 0: - if (v == q**2*(q+2) and - k == q*(q+1)-1 and - l == q-2): + if 2 == p and n: + if (v == q**2*(q + 2) and + k == q*(q + 1) - 1 and + l == q - 2): from sage.graphs.generators.classical_geometries import HaemersGraph return (HaemersGraph, q) + @cached_function def is_cossidente_penttila(int v, int k, int l, int mu): r""" @@ -905,15 +912,16 @@ def is_cossidente_penttila(int v, int k, int l, int mu): sage: t = is_cossidente_penttila(5,5,5,5); t """ cdef int q, n, p - q = 2*l+3 + q = 2*l + 3 p, n = is_prime_power(q, get_data=True) - if 2 < p and n != 0: - if (v == (q**3+1)*(q+1)//2 and - k == (q**2+1)*(q-1)//2 and - mu == (q-1)**2//2): + if 2 < p and n: + if (v == (q**3 + 1)*(q + 1)//2 and + k == (q**2 + 1)*(q - 1)//2 and + mu == (q - 1)**2//2): from sage.graphs.generators.classical_geometries import CossidentePenttilaGraph return (CossidentePenttilaGraph, q) + @cached_function def is_complete_multipartite(int v, int k, int l, int mu): r""" @@ -952,9 +960,9 @@ def is_complete_multipartite(int v, int k, int l, int mu): sage: g.is_strongly_regular(parameters=True) (20, 16, 12, 16) """ - if v>k: - r = v//(v-k) # number of parts (of size v-k each) - if l==(v-k)*(r-2) and k==mu and v == r*(v-k): + if v > k: + r = v//(v - k) # number of parts (of size v-k each) + if l == (v - k)*(r - 2) and k == mu and v == r*(v - k): from sage.graphs.generators.basic import CompleteMultipartiteGraph def CompleteMultipartiteSRG(nparts, partsize): @@ -1005,10 +1013,10 @@ def is_polhill(int v, int k, int l, int mu): [. at ...>] """ if (v, k, l, mu) not in [(1024, 231, 38, 56), - (1024, 264, 56, 72), - (1024, 297, 76, 90), - (1024, 330, 98, 110), - (1024, 462, 206, 210)]: + (1024, 264, 56, 72), + (1024, 297, 76, 90), + (1024, 330, 98, 110), + (1024, 462, 206, 210)]: return from itertools import product @@ -1019,7 +1027,7 @@ def is_polhill(int v, int k, int l, int mu): def additive_cayley(vertices): g = Graph() g.add_vertices(vertices[0].parent()) - edges = [(x,x+vv) + edges = [(x, x + vv) for vv in set(vertices) for x in g] g.add_edges(edges) @@ -1027,21 +1035,19 @@ def is_polhill(int v, int k, int l, int mu): return g # D is a Partial Difference Set of (Z4)^2, see section 2. - G = cartesian_product([IntegerModRing(4),IntegerModRing(4)]) - D = [ - [(2,0),(0,1),(0,3),(1,1),(3,3)], - [(1,0),(3,0),(0,2),(1,3),(3,1)], - [(1,2),(3,2),(2,1),(2,3),(2,2)] - ] + G = cartesian_product([IntegerModRing(4), IntegerModRing(4)]) + D = [[(2, 0), (0, 1), (0, 3), (1, 1), (3, 3)], + [(1, 0), (3, 0), (0, 2), (1, 3), (3, 1)], + [(1, 2), (3, 2), (2, 1), (2, 3), (2, 2)]] D = [[G(e) for e in x] for x in D] # The K_i are hyperplanes partitionning the nonzero elements of # GF(2^s)^2. See section 6. s = 3 G1 = GF(2**s,'x') - Gp = cartesian_product([G1,G1]) - K = [Gp((x,1)) for x in G1]+[Gp((1,0))] - K = [[x for x in Gp if x[0]*uu+x[1]*vv == 0] for (uu,vv) in K] + Gp = cartesian_product([G1, G1]) + K = [Gp((x, 1)) for x in G1] + [Gp((1, 0))] + K = [[x for x in Gp if x[0]*uu + x[1]*vv == 0] for (uu, vv) in K] # We now define the P_{i,j}. see section 6. @@ -1066,15 +1072,15 @@ def is_polhill(int v, int k, int l, int mu): P[2,4] = list(xrange((-1) + 2**(s-2)+3 , 2**(s-1)+1)) + [2**(s-1)+2**(s-2)+1,1] P[3,4] = list(xrange((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+1)) + [2**(s-2)+1,0] - R = {x:copy(P[x]) for x in P} + R = {x: copy(P[x]) for x in P} for x in P: P[x] = [K[i] for i in P[x]] - P[x] = set(sum(P[x],[])).difference([Gp((0,0))]) + P[x] = set(sum(P[x], [])).difference([Gp((0, 0))]) - P[1,4].add(Gp((0,0))) - P[2,4].add(Gp((0,0))) - P[3,4].add(Gp((0,0))) + P[1, 4].add(Gp((0, 0))) + P[2, 4].add(Gp((0, 0))) + P[3, 4].add(Gp((0, 0))) # We now define the R_{i,j}. see *end* of section 6. @@ -1085,39 +1091,40 @@ def is_polhill(int v, int k, int l, int mu): for x in R: R[x] = [K[i] for i in R[x]] - R[x] = set(sum(R[x],[])).difference([Gp((0,0))]) + R[x] = set(sum(R[x], [])).difference([Gp((0, 0))]) - R[1,3].add(Gp((0,0))) - R[2,4].add(Gp((0,0))) - R[3,4].add(Gp((0,0))) + R[1, 3].add(Gp((0, 0))) + R[2, 4].add(Gp((0, 0))) + R[3, 4].add(Gp((0, 0))) # Dabcd = Da, Db, Dc, Dd (cf. p273) # D1234 = D1, D2, D3, D4 (cf. p276) Dabcd = [] D1234 = [] - Gprod = cartesian_product([G,Gp]) - for DD,PQ in [(Dabcd,P), (D1234,R)]: - for i in range(1,5): - Dtmp = [product([G.zero()],PQ[0,i]), - product(D[0],PQ[1,i]), - product(D[1],PQ[2,i]), - product(D[2],PQ[3,i])] + Gprod = cartesian_product([G, Gp]) + for DD,PQ in [(Dabcd, P), (D1234, R)]: + for i in range(1, 5): + Dtmp = [product([G.zero()], PQ[0, i]), + product(D[0], PQ[1, i]), + product(D[1], PQ[2, i]), + product(D[2], PQ[3, i])] Dtmp = map(set, Dtmp) Dtmp = [Gprod(e) for e in sum(map(list, Dtmp), [])] DD.append(Dtmp) # Now that we have the data, we can return the graphs. if k == 231: - return [lambda :additive_cayley(Dabcd[0])] + return [lambda: additive_cayley(Dabcd[0])] if k == 264: - return [lambda :additive_cayley(D1234[2])] + return [lambda: additive_cayley(D1234[2])] if k == 297: - return [lambda :additive_cayley(D1234[0]+D1234[1]+D1234[2]).complement()] + return [lambda: additive_cayley(D1234[0] + D1234[1] + D1234[2]).complement()] if k == 330: - return [lambda :additive_cayley(Dabcd[0]+Dabcd[1]+Dabcd[2]).complement()] + return [lambda: additive_cayley(Dabcd[0] + Dabcd[1] + Dabcd[2]).complement()] if k == 462: - return [lambda :additive_cayley(Dabcd[0]+Dabcd[1])] + return [lambda: additive_cayley(Dabcd[0] + Dabcd[1])] + def is_RSHCD(int v, int k, int l, int mu): r""" @@ -1143,11 +1150,11 @@ def is_RSHCD(int v, int k, int l, int mu): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 27, 10, 12) - """ if SRG_from_RSHCD(v, k, l, mu, existence=True) is True: return [SRG_from_RSHCD, v, k, l, mu] + def SRG_from_RSHCD(v, k, l, mu, existence=False, check=True): r""" Return a `(v,k,l,mu)`-strongly regular graph from a RSHCD @@ -1195,29 +1202,29 @@ def SRG_from_RSHCD(v, k, l, mu, existence=False, check=True): Traceback (most recent call last): ... ValueError: I do not know how to build a (784, 0, 14, 38)-SRG from a RSHCD - """ from sage.combinat.matrices.hadamard_matrix import regular_symmetric_hadamard_matrix_with_constant_diagonal - sgn = lambda x: 1 if x>=0 else -1 + sgn = lambda x: 1 if x >= 0 else -1 n = v a = (n-4*mu)//2 e = 2*k - n + 1 + a t = abs(a//2) - if (e**2 == 1 and - k == (n-1-a+e)/2 and - l == (n-2*a)/4 - (1-e) and - mu== (n-2*a)/4 and - regular_symmetric_hadamard_matrix_with_constant_diagonal(n,sgn(a)*e,existence=True) is True): + if (e**2 == 1 and + k == (n-1-a+e)/2 and + l == (n-2*a)/4 - (1-e) and + mu== (n-2*a)/4 and + regular_symmetric_hadamard_matrix_with_constant_diagonal(n, sgn(a)*e, existence=True) is True): if existence: return True from sage.matrix.constructor import identity_matrix as I - from sage.matrix.constructor import ones_matrix as J + from sage.matrix.constructor import ones_matrix as J - H = regular_symmetric_hadamard_matrix_with_constant_diagonal(n,sgn(a)*e) + H = regular_symmetric_hadamard_matrix_with_constant_diagonal(n, sgn(a)*e) if list(H.column(0)[1:]).count(1) == k: H = -H - G = Graph((J(n)-I(n)-H+H[0,0]*I(n))/2,loops=False,multiedges=False,format="adjacency_matrix") + G = Graph((J(n) - I(n) - H + H[0, 0]*I(n)) / 2, + loops=False, multiedges=False, format="adjacency_matrix") if check: assert G.is_strongly_regular(parameters=True) == (v, k, l, mu) return G @@ -1226,6 +1233,7 @@ def SRG_from_RSHCD(v, k, l, mu, existence=False, check=True): return False raise ValueError("I do not know how to build a {}-SRG from a RSHCD".format((v, k, l, mu))) + @cached_function def is_unitary_polar(int v, int k, int l, int mu): r""" @@ -1273,7 +1281,7 @@ def is_unitary_polar(int v, int k, int l, int mu): q = k//mu if q*mu != k or q < 2: return - p,t = is_prime_power(q, get_data=True) + p, t = is_prime_power(q, get_data=True) if p**t != q or t % 2: return # at this point we know that we should have U(n,q) for some n and q=p^t, t even @@ -1281,22 +1289,22 @@ def is_unitary_polar(int v, int k, int l, int mu): q_pow_d_minus_one = r+1 else: q_pow_d_minus_one = -s-1 - ppp,ttt = is_prime_power(q_pow_d_minus_one, get_data=True) + ppp, ttt = is_prime_power(q_pow_d_minus_one, get_data=True) d = ttt//t + 1 if ppp != p or (d-1)*t != ttt: return t //= 2 # U(2d+1,q); write q^(1/2) as p^t - if (v == (q**d - 1)*((q**d)*p**t + 1)//(q - 1) and - k == q*(q**(d-1) - 1)*((q**d)//(p**t) + 1)//(q - 1) and - l == q*q*(q**(d-2)-1)*((q**(d-1))//(p**t) + 1)//(q - 1) + q - 1): + if (v == (q**d - 1)*((q**d)*p**t + 1)//(q - 1) and + k == q*(q**(d-1) - 1)*((q**d)//(p**t) + 1)//(q - 1) and + l == q*q*(q**(d-2)-1)*((q**(d-1))//(p**t) + 1)//(q - 1) + q - 1): from sage.graphs.generators.classical_geometries import UnitaryPolarGraph return (UnitaryPolarGraph, 2*d+1, p**t) # U(2d,q); - if (v == (q**d - 1)*((q**d)//(p**t) + 1)//(q - 1) and - k == q*(q**(d-1) - 1)*((q**(d-1))//(p**t) + 1)//(q - 1) and - l == q*q*(q**(d-2)-1)*((q**(d-2))//(p**t) + 1)//(q - 1) + q - 1): + if (v == (q**d - 1)*((q**d)//(p**t) + 1)//(q - 1) and + k == q*(q**(d-1) - 1)*((q**(d-1))//(p**t) + 1)//(q - 1) and + l == q*q*(q**(d-2)-1)*((q**(d-2))//(p**t) + 1)//(q - 1) + q - 1): from sage.graphs.generators.classical_geometries import UnitaryPolarGraph return (UnitaryPolarGraph, 2*d, p**t) From 08e2a2703f1baca4f50b5303f588d9dd490572fe Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 9 Aug 2022 14:22:11 +0200 Subject: [PATCH 184/742] trac #34314: clean strongly_regular_db.pyx - part 4 --- src/sage/graphs/strongly_regular_db.pyx | 137 +++++++++++++----------- 1 file changed, 73 insertions(+), 64 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 53864cb24ee..22ddb7b035f 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -47,6 +47,7 @@ from libc.stdint cimport uint_fast32_t cdef dict _brouwer_database = None _small_srg_database = None + @cached_function def is_paley(int v, int k, int l, int mu): r""" @@ -72,12 +73,13 @@ def is_paley(int v, int k, int l, int mu): (13, 6, 2, 3) sage: t = is_paley(5,5,5,5); t """ - if (v%4 == 1 and is_prime_power(v) and - k == (v-1)//2 and - l == (v-5)//4 and - mu == (v-1)//4): + if (v % 4 == 1 and is_prime_power(v) and + k == (v - 1)//2 and + l == (v - 5)//4 and + mu == (v - 1)//4): from sage.graphs.generators.families import PaleyGraph - return (PaleyGraph,v) + return (PaleyGraph, v) + @cached_function def is_mathon_PC_srg(int v, int k, int l, int mu): @@ -119,21 +121,21 @@ def is_mathon_PC_srg(int v, int k, int l, int mu): sage: t = is_mathon_PC_srg(4*mu+1,2*mu,mu-1,mu); t """ cdef int t - if (v%4 == 1 and - k == (v-1)//2 and - l == (v-5)//4 and - mu == (v-1)//4): + if (v % 4 == 1 and + k == (v - 1)//2 and + l == (v - 5)//4 and + mu == (v - 1)//4): from sage.rings.integer_ring import ZZ K = ZZ['x'] x = K.gen() - rpoly = (w for w in (x*(4*x*(4*x-1)-1) - mu).roots() if w[0] > 0) + rpoly = (w for w in (x*(4*x*(4*x - 1) - 1) - mu).roots() if w[0] > 0) try: t = next(rpoly)[0] - if (is_prime_power(4*t-1) and - is_prime_power(4*t+1)): # extra assumption in TODO! + if (is_prime_power(4*t - 1) and + is_prime_power(4*t + 1)): # extra assumption in TODO! from sage.graphs.generators.families import \ MathonPseudocyclicStronglyRegularGraph - return (MathonPseudocyclicStronglyRegularGraph,t) + return (MathonPseudocyclicStronglyRegularGraph, t) except StopIteration: pass @@ -167,16 +169,19 @@ def is_muzychuk_S6(int v, int k, int l, int mu): """ cdef int n, d from sage.rings.integer_ring import ZZ - n_list = [n for n in range(l-1) if ZZ(n).is_prime_power()] + n_list = [n for n in range(l - 1) if ZZ(n).is_prime_power()] for n in n_list: d = 2 - while n**d * ((n**d-1)//(n-1)+1) <= v: - if v == n**d * ((n**d-1)//(n-1)+1) and k == n**(d-1)*(n**d-1)//(n-1) - 1\ - and l == mu - 2 and mu == n**(d-1) * (n**(d-1)-1) // (n-1): + while n**d * ((n**d - 1)//(n - 1) + 1) <= v: + if (v == n**d * ((n**d - 1)//(n - 1) + 1) and + k == n**(d - 1)*(n**d - 1)//(n - 1) - 1 and + l == mu - 2 and + mu == n**(d - 1) * (n**(d - 1) - 1)//(n - 1)): from sage.graphs.generators.families import MuzychukS6Graph return (MuzychukS6Graph, n, d) d += 1 + @cached_function def is_orthogonal_array_block_graph(int v, int k, int l, int mu): r""" @@ -232,19 +237,20 @@ def is_orthogonal_array_block_graph(int v, int k, int l, int mu): m, n = latin_squares_graph_parameters(v, k, l, mu) except Exception: return - if orthogonal_array(m,n,existence=True) is True: + if orthogonal_array(m, n, existence=True) is True: from sage.graphs.generators.intersection import OrthogonalArrayBlockGraph - return (lambda m,n : OrthogonalArrayBlockGraph(m, n), m,n) + return (lambda m, n: OrthogonalArrayBlockGraph(m, n), m, n) - elif n>2 and skew_hadamard_matrix(n+1, existence=True) is True: - if m==(n+1)/2: + elif n > 2 and skew_hadamard_matrix(n+1, existence=True) is True: + if m == (n + 1)/2: from sage.graphs.generators.families import SquaredSkewHadamardMatrixGraph as G - elif m==(n-1)//2: + elif m == (n - 1)//2: from sage.graphs.generators.families import PasechnikGraph as G else: return return (G, (n+1)//4) + @cached_function def is_johnson(int v, int k, int l, int mu): r""" @@ -276,10 +282,11 @@ def is_johnson(int v, int k, int l, int mu): # J(n,m) has parameters v = m(m – 1)/2, k = 2(m – 2), λ = m – 2, μ = 4. m = l + 2 if (mu == 4 and - k == 2*(m-2) and - v == m*(m-1)//2): + k == 2*(m - 2) and + v == m*(m - 1)//2): from sage.graphs.generators.families import JohnsonGraph - return (lambda m: JohnsonGraph(m,2), m) + return (lambda m: JohnsonGraph(m, 2), m) + @cached_function def is_steiner(int v, int k, int l, int mu): @@ -317,15 +324,16 @@ def is_steiner(int v, int k, int l, int mu): if mu <= 1 or not is_square(mu): return m = int(sqrt(mu)) - n = (k*(m-1))//m+m + n = (k*(m - 1))//m + m - if (v == (n*(n-1))/(m*(m-1)) and - k == m*(n-m)/(m-1) and - l == (m-1)**2 + (n-1)/(m-1)-2 and - balanced_incomplete_block_design(n,m,existence=True) is True): + if (v == (n*(n - 1))/(m*(m - 1)) and + k == m*(n - m)/(m - 1) and + l == (m - 1)**2 + (n - 1)/(m - 1) - 2 and + balanced_incomplete_block_design(n, m, existence=True) is True): from sage.graphs.generators.intersection import IntersectionGraph return (lambda n, m: IntersectionGraph([frozenset(b) for b in balanced_incomplete_block_design(n, m)]), n, m) + @cached_function def is_affine_polar(int v, int k, int l, int mu): r""" @@ -361,25 +369,25 @@ def is_affine_polar(int v, int k, int l, int mu): # # VO−(2e,q) has parameters v = q^(2e), k = (q^(e−1) - 1)(q^e + 1), λ = # q(q^(e−2) - 1)(q^(e−1) + 1) + q − 2, μ = q^(e−1)(q^(e−1) - 1) - if (not is_square(v) or - not is_prime_power(v)): + if not is_square(v) or not is_prime_power(v): return - prime,power = is_prime_power(v,get_data=True) - if power%2: + prime, power = is_prime_power(v, get_data=True) + if power % 2: return for e in divisors(power/2): q = prime**(power//(2*e)) assert v == q**(2*e) - if (k == (q**(e-1) + 1)*(q**e-1) and - l == q*(q**(e-2) + 1)*(q**(e-1)-1)+q-2 and - mu== q**(e-1)*(q**(e-1) + 1)): + if (k == (q**(e - 1) + 1)*(q**e - 1) and + l == q*(q**(e - 2) + 1)*(q**(e - 1) - 1) + q - 2 and + mu == q**(e - 1)*(q**(e - 1) + 1)): from sage.graphs.generators.classical_geometries import AffineOrthogonalPolarGraph - return (lambda d,q : AffineOrthogonalPolarGraph(d,q,sign='+'),2*e,q) - if (k == (q**(e-1) - 1)*(q**e+1) and - l == q*(q**(e-2)- 1)*(q**(e-1)+1)+q-2 and - mu== q**(e-1)*(q**(e-1) - 1)): + return (lambda d, q: AffineOrthogonalPolarGraph(d, q, sign='+'), 2*e, q) + if (k == (q**(e - 1) - 1)*(q**e + 1) and + l == q*(q**(e - 2) - 1)*(q**(e - 1) + 1) + q - 2 and + mu == q**(e - 1)*(q**(e - 1) - 1)): from sage.graphs.generators.classical_geometries import AffineOrthogonalPolarGraph - return (lambda d,q : AffineOrthogonalPolarGraph(d,q,sign='-'),2*e,q) + return (lambda d, q: AffineOrthogonalPolarGraph(d, q, sign='-'), 2*e, q) + @cached_function def is_orthogonal_polar(int v, int k, int l, int mu): @@ -427,35 +435,36 @@ def is_orthogonal_polar(int v, int k, int l, int mu): q_pow_m_minus_one = -s-1 if abs(s) > r else r+1 if is_prime_power(q_pow_m_minus_one): - prime,power = is_prime_power(q_pow_m_minus_one,get_data=True) + prime, power = is_prime_power(q_pow_m_minus_one, get_data=True) for d in divisors(power): q = prime**d - m = (power//d)+1 + m = (power//d) + 1 # O(2m+1,q) - if (v == (q**(2*m)-1)//(q-1) and - k == q*(q**(2*m-2)-1)//(q-1) and - l == q**2*(q**(2*m-4)-1)//(q-1) + q-1 and - mu== (q**(2*m-2)-1)//(q-1)): + if (v == (q**(2*m) - 1)//(q - 1) and + k == q*(q**(2*m - 2) - 1)//(q - 1) and + l == q**2*(q**(2*m - 4) - 1)//(q - 1) + q - 1 and + mu == (q**(2*m - 2) - 1)//(q - 1)): from sage.graphs.generators.classical_geometries import OrthogonalPolarGraph return (OrthogonalPolarGraph, 2*m+1, q, "") # O^+(2m,q) - if (v == (q**(2*m-1)-1)//(q-1) + q**(m-1) and - k == q*(q**(2*m-3)-1)//(q-1) + q**(m-1) and - k == q**(2*m-3) + l + 1 and - mu== k//q): + if (v == (q**(2*m - 1) - 1)//(q - 1) + q**(m - 1) and + k == q*(q**(2*m - 3) - 1)//(q - 1) + q**(m - 1) and + k == q**(2*m - 3) + l + 1 and + mu == k//q): from sage.graphs.generators.classical_geometries import OrthogonalPolarGraph return (OrthogonalPolarGraph, 2*m, q, "+") # O^+(2m+1,q) - if (v == (q**(2*m-1)-1)//(q-1) - q**(m-1) and - k == q*(q**(2*m-3)-1)//(q-1) - q**(m-1) and - k == q**(2*m-3) + l + 1 and - mu== k//q): + if (v == (q**(2*m - 1) - 1)//(q - 1) - q**(m - 1) and + k == q*(q**(2*m - 3) - 1)//(q - 1) - q**(m - 1) and + k == q**(2*m - 3) + l + 1 and + mu == k//q): from sage.graphs.generators.classical_geometries import OrthogonalPolarGraph return (OrthogonalPolarGraph, 2*m, q, "-") + @cached_function def is_goethals_seidel(int v, int k, int l, int mu): r""" @@ -520,15 +529,15 @@ def is_goethals_seidel(int v, int k, int l, int mu): # - the number of vertices v is equal to v_bibd*(r_bibd+1) # - the degree k of the graph is equal to k=(v+r_bibd-1)/2 - r_bibd = k - (v-1-k) - v_bibd = v//(r_bibd+1) - k_bibd = (v_bibd-1)//r_bibd + 1 if r_bibd>0 else -1 + r_bibd = k - (v - 1 - k) + v_bibd = v//(r_bibd + 1) + k_bibd = (v_bibd - 1)//r_bibd + 1 if r_bibd > 0 else -1 - if (v == v_bibd*(r_bibd+1) and - 2*k == v+r_bibd-1 and - 4*l == -2*v + 6*k -v_bibd -k_bibd and - hadamard_matrix(r_bibd+1, existence=True) is True and - balanced_incomplete_block_design(v_bibd, k_bibd, existence = True) is True): + if (v == v_bibd*(r_bibd + 1) and + 2*k == v + r_bibd - 1 and + 4*l == -2*v + 6*k - v_bibd - k_bibd and + hadamard_matrix(r_bibd + 1, existence=True) is True and + balanced_incomplete_block_design(v_bibd, k_bibd, existence=True) is True): from sage.graphs.generators.families import GoethalsSeidelGraph return [GoethalsSeidelGraph, k_bibd, r_bibd] From f2323c01dd8ff975546f648d4e1058b995d08ac2 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 9 Aug 2022 14:29:21 +0200 Subject: [PATCH 185/742] trac #34313: extra care --- src/sage/graphs/strongly_regular_db.pyx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 53864cb24ee..a4eff7ecff8 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1204,7 +1204,8 @@ def SRG_from_RSHCD(v, k, l, mu, existence=False, check=True): ValueError: I do not know how to build a (784, 0, 14, 38)-SRG from a RSHCD """ from sage.combinat.matrices.hadamard_matrix import regular_symmetric_hadamard_matrix_with_constant_diagonal - sgn = lambda x: 1 if x >= 0 else -1 + def sgn(x): + return 1 if x >= 0 else -1 n = v a = (n-4*mu)//2 e = 2*k - n + 1 + a @@ -1649,7 +1650,7 @@ def is_switch_OA_srg(int v, int k, int l, int mu): cdef int n_2_p_1 = v cdef int n = floor(sqrt(n_2_p_1 - 1)) - if n*n != n_2_p_1-1: # is it a square? + if n*n != n_2_p_1 - 1: # is it a square? return None cdef int c = k//n From a0814891a6d55359c1a4de5bb6b6124bac429208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 9 Aug 2022 18:16:26 +0200 Subject: [PATCH 186/742] fix E251 in schemes --- src/sage/schemes/berkovich/berkovich_space.py | 4 +-- src/sage/schemes/curves/affine_curve.py | 10 +++--- src/sage/schemes/curves/projective_curve.py | 6 ++-- .../elliptic_curves/descent_two_isogeny.pyx | 13 ++++---- .../elliptic_curves/ell_rational_field.py | 14 ++++---- src/sage/schemes/elliptic_curves/heegner.py | 10 ++---- src/sage/schemes/elliptic_curves/height.py | 2 +- .../schemes/elliptic_curves/isogeny_class.py | 13 ++++---- .../schemes/elliptic_curves/mod_sym_num.pyx | 19 +++++------ .../schemes/elliptic_curves/padic_lseries.py | 8 ++--- src/sage/schemes/elliptic_curves/padics.py | 12 ++++--- .../schemes/elliptic_curves/period_lattice.py | 9 +++--- .../schemes/elliptic_curves/saturation.py | 10 +++--- src/sage/schemes/generic/scheme.py | 4 +-- .../hyperelliptic_curves/constructor.py | 7 ++-- .../hyperelliptic_generic.py | 4 +-- .../hyperelliptic_padic_field.py | 4 +-- src/sage/schemes/plane_conics/con_field.py | 32 +++++++++---------- src/sage/schemes/product_projective/space.py | 8 ++--- .../schemes/product_projective/subscheme.py | 2 +- .../projective/projective_subscheme.py | 11 ++++--- 21 files changed, 100 insertions(+), 102 deletions(-) diff --git a/src/sage/schemes/berkovich/berkovich_space.py b/src/sage/schemes/berkovich/berkovich_space.py index c19b8bca9f8..73369fda8d4 100644 --- a/src/sage/schemes/berkovich/berkovich_space.py +++ b/src/sage/schemes/berkovich/berkovich_space.py @@ -647,11 +647,11 @@ def __init__(self, base, ideal=None): ideal = None self._base_type = 'padic field' if base.dimension_relative() != 1: - raise ValueError("base of projective Berkovich space must be " + \ + raise ValueError("base of projective Berkovich space must be " "projective space of dimension 1 over Qp or a number field") self._p = prime self._ideal = ideal - Parent.__init__(self, base = base, category=TopologicalSpaces()) + Parent.__init__(self, base=base, category=TopologicalSpaces()) def base_ring(self): r""" diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index f09cde624eb..4c33b81ac35 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -395,7 +395,7 @@ def local_coordinates(self, pt, n): y0 = F(pt[1]) astr = ["a"+str(i) for i in range(1,2*n)] x,y = R.gens() - R0 = PolynomialRing(F,2*n+2,names = [str(x),str(y),"t"]+astr) + R0 = PolynomialRing(F, 2 * n + 2, names=[str(x), str(y), "t"] + astr) vars0 = R0.gens() t = vars0[2] yt = y0*t**0+add([vars0[i]*t**(i-2) for i in range(3,2*n+2)]) @@ -1930,15 +1930,13 @@ def rational_points(self, algorithm="enum"): return sorted(set(pnts)) elif algorithm == "all": - - S_enum = self.rational_points(algorithm = "enum") - S_bn = self.rational_points(algorithm = "bn") + S_enum = self.rational_points(algorithm="enum") + S_bn = self.rational_points(algorithm="bn") if S_enum != S_bn: raise RuntimeError("Bug in rational_points -- different algorithms give different answers for curve %s!" % self) return S_enum - else: - raise ValueError("No algorithm '%s' known"%algorithm) + raise ValueError("No algorithm '%s' known" % algorithm) class IntegralAffineCurve(AffineCurve_field): diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 529721d8958..84a4117749a 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -704,7 +704,7 @@ def local_coordinates(self, pt, n): y0 = F(pt[1]) astr = ["a"+str(i) for i in range(1,2*n)] x,y = R.gens() - R0 = PolynomialRing(F,2*n+2,names = [str(x),str(y),"t"]+astr) + R0 = PolynomialRing(F, 2 * n + 2, names=[str(x), str(y), "t"] + astr) vars0 = R0.gens() t = vars0[2] yt = y0*t**0 + add([vars0[i]*t**(i-2) for i in range(3,2*n+2)]) @@ -2148,8 +2148,8 @@ def rational_points(self, algorithm="enum", sort=True): if algorithm == "bn": return self._points_via_singular(sort=sort) elif algorithm == "all": - S_enum = self.rational_points(algorithm = "enum") - S_bn = self.rational_points(algorithm = "bn") + S_enum = self.rational_points(algorithm="enum") + S_bn = self.rational_points(algorithm="bn") if S_enum != S_bn: raise RuntimeError("Bug in rational_points -- different\ algorithms give different answers for\ diff --git a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx index af82dd3d91c..0c3a7a72385 100644 --- a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx +++ b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx @@ -1045,10 +1045,10 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len return 0 def two_descent_by_two_isogeny(E, - int global_limit_small = 10, - int global_limit_large = 10000, - int verbosity = 0, - bint selmer_only = 0, bint proof = 1): + int global_limit_small=10, + int global_limit_large=10000, + int verbosity=0, + bint selmer_only=0, bint proof=1): """ Given an elliptic curve E with a two-isogeny phi : E --> E' and dual isogeny phi', runs a two-isogeny descent on E, returning n1, n2, n1' and n2'. Here @@ -1148,9 +1148,10 @@ def two_descent_by_two_isogeny(E, return two_descent_by_two_isogeny_work(c, d, global_limit_small, global_limit_large, verbosity, selmer_only, proof) + def two_descent_by_two_isogeny_work(Integer c, Integer d, - int global_limit_small = 10, int global_limit_large = 10000, - int verbosity = 0, bint selmer_only = 0, bint proof = 1): + int global_limit_small=10, int global_limit_large=10000, + int verbosity=0, bint selmer_only=0, bint proof=1): """ Do all the work in doing a two-isogeny descent. diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 38088228122..fc54013b7ba 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -1095,7 +1095,7 @@ def _modular_symbol_normalize(self, sign, normalize, implementation, nap): raise ValueError("Implementation should be one of 'sage', 'num' or 'eclib'") return (sign, normalize, implementation, nap) - @cached_method(key = _modular_symbol_normalize) + @cached_method(key=_modular_symbol_normalize) def modular_symbol(self, sign=+1, normalize=None, implementation='eclib', nap=0): r""" Return the modular symbol map associated to this elliptic curve @@ -1964,7 +1964,7 @@ def three_selmer_rank(self, algorithm='UseSUnits'): """ from sage.interfaces.magma import magma E = magma(self) - return Integer(E.ThreeSelmerGroup(MethodForFinalStep = magma('"%s"'%algorithm)).Ngens()) + return Integer(E.ThreeSelmerGroup(MethodForFinalStep=magma('"%s"' % algorithm)).Ngens()) def rank(self, use_database=True, verbose=False, only_use_mwrank=True, @@ -2301,8 +2301,8 @@ def _compute_gens(self, proof, if not only_use_mwrank: try: verbose_verbose("Trying to compute rank.") - r = self.rank(only_use_mwrank = False) - verbose_verbose("Got r = %s."%r) + r = self.rank(only_use_mwrank=False) + verbose_verbose("Got r = %s." % r) if r == 0: verbose_verbose("Rank = 0, so done.") return [], True @@ -2438,7 +2438,7 @@ def ngens(self, proof=None): Generator 1 is [29604565304828237474403861024284371796799791624792913256602210:-256256267988926809388776834045513089648669153204356603464786949:490078023219787588959802933995928925096061616470779979261000]; height 95.98037... Regulator = 95.980... """ - return len(self.gens(proof = proof)) + return len(self.gens(proof=proof)) def regulator(self, proof=None, precision=53, **kwds): r""" @@ -2646,7 +2646,7 @@ def saturation(self, points, verbose=False, max_prime=-1, min_prime=2): from sage.libs.eclib.all import mwrank_MordellWeil mw = mwrank_MordellWeil(c, verbose) mw.process(v) # by default, this does no saturation yet - ok, index, unsat = mw.saturate(max_prime=max_prime, min_prime = min_prime) + ok, index, unsat = mw.saturate(max_prime=max_prime, min_prime=min_prime) if not ok: print("Failed to saturate failed at the primes {}".format(unsat)) sat = [Emin(P) for P in mw.points()] @@ -6630,7 +6630,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): M = U.transpose()*M*U # NB "lambda" is a reserved word in Python! - lamda = min(M.charpoly(algorithm="hessenberg").roots(multiplicities = False)) + lamda = min(M.charpoly(algorithm="hessenberg").roots(multiplicities=False)) max_S = max(S) len_S += 1 #Counting infinity (always "included" in S) if verbose: diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index 4701c66f5de..2b699fd6cf8 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -3520,7 +3520,7 @@ def point_exact(self, prec=53, algorithm='lll', var='a', optimize=False): M = K.extension(gg, names='b') y = M.gen()/dd x = M(x) - L = M.absolute_field(names = var) + L = M.absolute_field(names=var) phi = L.structure()[1] x = phi(x) y = phi(y) @@ -4364,13 +4364,9 @@ def mod(self, p, prec=53): # do actual calculation if self.conductor() == 1: - - P = self._trace_exact_conductor_1(prec = prec) + P = self._trace_exact_conductor_1(prec=prec) return E.change_ring(GF(p))(P) - - else: - - raise NotImplementedError + raise NotImplementedError ## def congruent_rational_point(self, n, prec=53): ## r""" diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py index e948474c8b9..06d83bc7759 100644 --- a/src/sage/schemes/elliptic_curves/height.py +++ b/src/sage/schemes/elliptic_curves/height.py @@ -1216,7 +1216,7 @@ def S(self, xi1, xi2, v): ([0.0781194447253472, 0.0823423732016403] U [0.917657626798360, 0.921880555274653]) """ L = self.E.period_lattice(v) - w1, w2 = L.basis(prec = v.codomain().prec()) + w1, w2 = L.basis(prec=v.codomain().prec()) beta = L.elliptic_exponential(w1/2)[0] if xi2 < beta: return UnionOfIntervals([]) diff --git a/src/sage/schemes/elliptic_curves/isogeny_class.py b/src/sage/schemes/elliptic_curves/isogeny_class.py index a5eb209bc69..bb5ae25a56e 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_class.py +++ b/src/sage/schemes/elliptic_curves/isogeny_class.py @@ -403,7 +403,7 @@ def graph(self): from sage.graphs.graph import Graph if not self.E.base_field() is QQ: - M = self.matrix(fill = False) + M = self.matrix(fill=False) n = len(self) G = Graph(M, format='weighted_adjacency_matrix') D = dict([(v,self.curves[v]) for v in G.vertices(sort=False)]) @@ -416,11 +416,10 @@ def graph(self): G.relabel(list(range(1, n + 1))) return G - - M = self.matrix(fill = False) + M = self.matrix(fill=False) n = M.nrows() # = M.ncols() G = Graph(M, format='weighted_adjacency_matrix') - N = self.matrix(fill = True) + N = self.matrix(fill=True) D = dict([(v,self.curves[v]) for v in G.vertices(sort=False)]) # The maximum degree classifies the shape of the isogeny # graph, though the number of vertices is often enough. @@ -535,7 +534,8 @@ def reorder(self, order): return self if isinstance(order, str): if order == "lmfdb": - reordered_curves = sorted(self.curves, key = lambda E: E.a_invariants()) + reordered_curves = sorted(self.curves, + key=lambda E: E.a_invariants()) else: reordered_curves = list(self.E.isogeny_class(algorithm=order)) elif isinstance(order, (list, tuple, IsogenyClass_EC)): @@ -1068,7 +1068,8 @@ def _compute(self): raise RuntimeError("unable to find %s in the database" % self.E) # All curves will have the same conductor and isogeny class, # and there are most 8 of them, so lexicographic sorting is okay. - self.curves = tuple(sorted(curves, key = lambda E: E.cremona_label())) + self.curves = tuple(sorted(curves, + key=lambda E: E.cremona_label())) self._mat = None elif algorithm == "sage": curves = [self.E.minimal_model()] diff --git a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx index dd452869e2e..8f50eff1e27 100644 --- a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx +++ b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx @@ -970,7 +970,7 @@ cdef class ModularSymbolNumerical: ans = self._evaluate_approx(ra, eps) if prec > self._om1.parent().prec(): - L = self._E.period_lattice().basis(prec = prec) + L = self._E.period_lattice().basis(prec=prec) self._om1 = L[0] self._om2 = L[1].imag() cinf = self._E.real_components() @@ -2156,10 +2156,8 @@ cdef class ModularSymbolNumerical: ans = su return CC(ans) - - def _from_r_to_rr_approx(self, Rational r, Rational rr, double eps, - method = None, int use_partials=2): + method=None, int use_partials=2): r""" Given a cusp `r` this computes the integral `\lambda(r\to r')` from `r` to `r'` to the given precision ``eps``. @@ -2313,7 +2311,7 @@ cdef class ModularSymbolNumerical: if method == "indirect" or method == "both": verbose(" using the indirect integration from %s to %s " - "with %s terms to sum"%(r, rr, T1+T2), level =2) + "with %s terms to sum"%(r, rr, T1+T2), level=2) #self.nc_indirect += 1 ans2 = ( self._from_ioo_to_r_approx(r, eps/2, use_partials=use_partials) @@ -2474,7 +2472,7 @@ cdef class ModularSymbolNumerical: # (key=lambda r,sign,use_partials:(r,sign)) lead to a compiler crash @cached_method - def _value_ioo_to_r(self, Rational r, int sign = 0, + def _value_ioo_to_r(self, Rational r, int sign=0, int use_partials=2): r""" Return `[r]^+` or `[r]^-` for a rational `r`. @@ -2532,7 +2530,7 @@ cdef class ModularSymbolNumerical: return self._round(lap, sign, True) @cached_method - def _value_r_to_rr(self, Rational r, Rational rr, int sign = 0, + def _value_r_to_rr(self, Rational r, Rational rr, int sign=0, int use_partials=2): r""" Return the rational number `[r']^+ - [r]^+`. However the @@ -2603,7 +2601,7 @@ cdef class ModularSymbolNumerical: return self._round(lap, sign, True) @cached_method - def transportable_symbol(self, Rational r, Rational rr, int sign = 0): + def transportable_symbol(self, Rational r, Rational rr, int sign=0): r""" Return the symbol `[r']^+ - [r]^+` where `r'=\gamma(r)` for some `\gamma\in\Gamma_0(N)`. These symbols can be computed by transporting @@ -2860,8 +2858,7 @@ cdef class ModularSymbolNumerical: res -= self._value_ioo_to_r(rr,sign, use_partials=2) return res - - def manin_symbol(self, llong u, llong v, int sign = 0): + def manin_symbol(self, llong u, llong v, int sign=0): r""" Given a pair `(u,v)` presenting a point in `\mathbb{P}^1(\mathbb{Z}/N\mathbb{Z})` and hence a coset of @@ -3755,7 +3752,7 @@ def _test_against_table(range_of_conductors, other_implementation="sage", list_o Mr = M(r) M2r = M(r, sign=-1) if verb: - print("r={} : ({},{}),({}, {})".format(r,mr,m2r,Mr,M2r), end= " ", flush=True) + print("r={} : ({},{}),({}, {})".format(r,mr,m2r,Mr,M2r), end=" ", flush=True) if mr != Mr or m2r != M2r: print (("B u g : curve = {}, cusp = {}, sage's symbols" + "({},{}), our symbols ({}, {})").format(C.label(), r, diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index 3910da83476..f8e16b3407a 100644 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -143,7 +143,7 @@ class pAdicLseries(SageObject): sage: lp == loads(dumps(lp)) True """ - def __init__(self, E, p, implementation = 'eclib', normalize='L_ratio'): + def __init__(self, E, p, implementation='eclib', normalize='L_ratio'): r""" INPUT: @@ -337,7 +337,7 @@ def modular_symbol(self, r, sign=+1, quadratic_twist=+1): return -sum([kronecker_symbol(D, u) * m(r + ZZ(u) / D) for u in range(1, -D)]) - def measure(self, a, n, prec, quadratic_twist=+1, sign = +1): + def measure(self, a, n, prec, quadratic_twist=+1, sign=+1): r""" Return the measure on `\ZZ_p^{\times}` defined by @@ -1550,9 +1550,9 @@ def __phi_bpr(self, prec=0): print("Warning: Very large value for the precision.") if prec == 0: prec = floor((log(10000)/log(p))) - verbose("prec set to %s"%prec) + verbose("prec set to %s" % prec) eh = E.formal() - om = eh.differential(prec = p**prec+3) + om = eh.differential(prec=p**prec+3) verbose("differential computed") xt = eh.x(prec=p**prec + 3) et = xt*om diff --git a/src/sage/schemes/elliptic_curves/padics.py b/src/sage/schemes/elliptic_curves/padics.py index 509d94e9e33..d4b38156669 100644 --- a/src/sage/schemes/elliptic_curves/padics.py +++ b/src/sage/schemes/elliptic_curves/padics.py @@ -98,8 +98,10 @@ def _normalize_padic_lseries(self, p, normalize, implementation, precision): raise ValueError("Implementation should be one of 'sage', 'eclib', 'num' or 'pollackstevens'") return (p, normalize, implementation, precision) + @cached_method(key=_normalize_padic_lseries) -def padic_lseries(self, p, normalize = None, implementation = 'eclib', precision = None): +def padic_lseries(self, p, normalize=None, implementation='eclib', + precision=None): r""" Return the `p`-adic `L`-series of self at `p`, which is an object whose approx method computes @@ -209,16 +211,16 @@ def padic_lseries(self, p, normalize = None, implementation = 'eclib', precision if implementation in ['sage', 'eclib', 'num']: if self.ap(p) % p != 0: Lp = plseries.pAdicLseriesOrdinary(self, p, - normalize = normalize, implementation = implementation) + normalize=normalize, implementation=implementation) else: Lp = plseries.pAdicLseriesSupersingular(self, p, - normalize = normalize, implementation = implementation) + normalize=normalize, implementation=implementation) else: phi = self.pollack_stevens_modular_symbol(sign=0) if phi.parent().level() % p == 0: - Phi = phi.lift(p, precision, eigensymbol = True) + Phi = phi.lift(p, precision, eigensymbol=True) else: - Phi = phi.p_stabilize_and_lift(p, precision, eigensymbol = True) + Phi = phi.p_stabilize_and_lift(p, precision, eigensymbol=True) Lp = Phi.padic_lseries() #mm TODO should this pass precision on too ? Lp._cinf = self.real_components() return Lp diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 704fe7e4d0b..205c2ff12c1 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -802,7 +802,7 @@ def is_rectangular(self): return self.real_flag == +1 raise RuntimeError("Not defined for non-real lattices.") - def real_period(self, prec = None, algorithm='sage'): + def real_period(self, prec=None, algorithm='sage'): """ Return the real period of this period lattice. @@ -840,8 +840,9 @@ def real_period(self, prec = None, algorithm='sage'): return self.basis(prec,algorithm)[0] raise RuntimeError("Not defined for non-real lattices.") - def omega(self, prec = None, bsd_normalise = False): - r"""Return the real or complex volume of this period lattice. + def omega(self, prec=None, bsd_normalise=False): + r""" + Return the real or complex volume of this period lattice. INPUT: @@ -1014,7 +1015,7 @@ def complex_area(self, prec=None): w1,w2 = self.basis(prec) return (w1*w2.conjugate()).imag().abs() - def sigma(self, z, prec = None, flag=0): + def sigma(self, z, prec=None, flag=0): r""" Return the value of the Weierstrass sigma function for this elliptic curve period lattice. diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py index 07b4738c079..1d75c076e53 100644 --- a/src/sage/schemes/elliptic_curves/saturation.py +++ b/src/sage/schemes/elliptic_curves/saturation.py @@ -674,10 +674,10 @@ def p_projections(Eq, Plist, p, debug=False): if debug: print("Cyclic case, taking dlogs to base {} of order {}".format(g,pp)) # logs are well-defined mod pp, hence mod p - v = [dlog(pt, g, ord = pp, operation = '+') for pt in pts] + v = [dlog(pt, g, ord=pp, operation='+') for pt in pts] if debug: print("dlogs: {}".format(v)) - return [vector(Fp,v)] + return [vector(Fp, v)] # We make no assumption about which generator order divides the # other, since conventions differ! @@ -700,5 +700,7 @@ def p_projections(Eq, Plist, p, debug=False): # logs are well-defined mod p1, hence mod p - return [vector(Fp, [dlog(pt.weil_pairing(g1,p2), zeta, ord = p1, operation = '*') for pt in pts]), - vector(Fp, [dlog(pt.weil_pairing(g2,p2), zeta, ord = p1, operation = '*') for pt in pts])] + return [vector(Fp, [dlog(pt.weil_pairing(g1,p2), zeta, + ord=p1, operation='*') for pt in pts]), + vector(Fp, [dlog(pt.weil_pairing(g2,p2), zeta, + ord=p1, operation='*') for pt in pts])] diff --git a/src/sage/schemes/generic/scheme.py b/src/sage/schemes/generic/scheme.py index 2793babda4a..10305c2ee99 100644 --- a/src/sage/schemes/generic/scheme.py +++ b/src/sage/schemes/generic/scheme.py @@ -126,9 +126,9 @@ def __init__(self, X=None, category=None): category = default_category else: assert category.is_subcategory(default_category), \ - "%s is not a subcategory of %s"%(category, default_category) + "%s is not a subcategory of %s" % (category, default_category) - Parent.__init__(self, self.base_ring(), category = category) + Parent.__init__(self, self.base_ring(), category=category) def union(self, X): """ diff --git a/src/sage/schemes/hyperelliptic_curves/constructor.py b/src/sage/schemes/hyperelliptic_curves/constructor.py index f5478623bdf..5aa3ad0abd4 100644 --- a/src/sage/schemes/hyperelliptic_curves/constructor.py +++ b/src/sage/schemes/hyperelliptic_curves/constructor.py @@ -260,14 +260,15 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): if g in genus_classes: superclass.append(genus_classes[g]) - cls_name.append("g%s"%g) + cls_name.append("g%s" % g) - for name,test,cls in fields: + for name, test, cls in fields: if test(R): superclass.append(cls) cls_name.append(name) break class_name = "_".join(cls_name) - cls = dynamic_class(class_name, tuple(superclass), HyperellipticCurve_generic, doccls = HyperellipticCurve) + cls = dynamic_class(class_name, tuple(superclass), + HyperellipticCurve_generic, doccls=HyperellipticCurve) return cls(PP, f, h, names=names, genus=g) diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py index b9d32c897b0..ad3b7d59a53 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py @@ -514,7 +514,7 @@ def local_coordinates_at_weierstrass(self, P, prec=20, name='t'): c -= (pol(c) - t2)/pol_prime(c) return (c, t.add_bigoh(prec)) - def local_coordinates_at_infinity(self, prec = 20, name = 't'): + def local_coordinates_at_infinity(self, prec=20, name='t'): """ For the genus `g` hyperelliptic curve `y^2 = f(x)`, return `(x(t), y(t))` such that `(y(t))^2 = f(x(t))`, where `t = x^g/y` is @@ -569,7 +569,7 @@ def local_coordinates_at_infinity(self, prec = 20, name = 't'): y = x**g/t return x+O(t**(prec+2)) , y+O(t**(prec+2)) - def local_coord(self, P, prec = 20, name = 't'): + def local_coord(self, P, prec=20, name='t'): """ Calls the appropriate local_coordinates function diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py index f69234cdc04..373394b20af 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py @@ -702,9 +702,9 @@ def coleman_integrals_on_basis(self, P, Q, algorithm=None): # MW = monsky_washnitzer.MonskyWashnitzerDifferentialRing(S) # return MW.invariant_differential() - def coleman_integral(self, w, P, Q, algorithm = 'None'): + def coleman_integral(self, w, P, Q, algorithm='None'): r""" - Returns the Coleman integral `\int_P^Q w` + Return the Coleman integral `\int_P^Q w`. INPUT: diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index 3ed2b06e960..9587573c882 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -357,7 +357,7 @@ def diagonalization(self, names=None): names = self.defining_polynomial().parent().variable_names() from .constructor import Conic D, T = self.diagonal_matrix() - con = Conic(D, names = names) + con = Conic(D, names=names) return con, con.hom(T, self), self.hom(T.inverse(), con) def gens(self): @@ -386,8 +386,8 @@ def gens(self): """ return self.coordinate_ring().gens() - def has_rational_point(self, point = False, - algorithm = 'default', read_cache = True): + def has_rational_point(self, point=False, + algorithm='default', read_cache=True): r""" Returns True if and only if the conic ``self`` has a point over its base field `B`. @@ -523,21 +523,21 @@ def has_rational_point(self, point = False, if d == 0: return True, self.point([0,1,0]) return True, self.point([0, ((e**2-4*d*f).sqrt()-e)/(2*d), 1], - check = False) + check=False) return True if isinstance(B, sage.rings.abc.RealField): D, T = self.diagonal_matrix() [a, b, c] = [D[0,0], D[1,1], D[2,2]] if a == 0: - ret = True, self.point(T*vector([1,0,0]), check = False) + ret = True, self.point(T*vector([1,0,0]), check=False) elif a*c <= 0: ret = True, self.point(T*vector([(-c/a).sqrt(),0,1]), - check = False) + check=False) elif b == 0: - ret = True, self.point(T*vector([0,1,0]), check = False) + ret = True, self.point(T*vector([0,1,0]), check=False) elif b*c <= 0: ret = True, self.point(T*vector([0,(-c/b).sqrt(),0,1]), - check = False) + check=False) else: ret = False, None if point: @@ -546,7 +546,7 @@ def has_rational_point(self, point = False, raise NotImplementedError("has_rational_point not implemented for " \ "conics over base field %s" % B) - def has_singular_point(self, point = False): + def has_singular_point(self, point=False): r""" Return True if and only if the conic ``self`` has a rational singular point. @@ -701,7 +701,7 @@ def hom(self, x, Y=None): "map from self (= %s) to Y (= %s)" % \ (x, self, Y)) x = Sequence(x*vector(self.ambient_space().gens())) - return self.Hom(Y)(x, check = False) + return self.Hom(Y)(x, check=False) return ProjectivePlaneCurve.hom(self, x, Y) def is_diagonal(self): @@ -938,7 +938,7 @@ def parametrization(self, point=None, morphism=True): if not morphism: return par P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y') - return P1.hom(par[0],self), self.Hom(P1)(par[1], check = False) + return P1.hom(par[0],self), self.Hom(P1)(par[1], check=False) def point(self, v, check=True): r""" @@ -968,7 +968,6 @@ def point(self, v, check=True): self._rational_point = p return p - def random_rational_point(self, *args1, **args2): r""" Return a random rational point of the conic ``self``. @@ -1017,8 +1016,7 @@ def random_rational_point(self, *args1, **args2): y = B.random_element(*args1, **args2) return par[0]([x,y]) - - def rational_point(self, algorithm = 'default', read_cache = True): + def rational_point(self, algorithm='default', read_cache=True): r""" Return a point on ``self`` defined over the base field. @@ -1132,8 +1130,8 @@ def rational_point(self, algorithm = 'default', read_cache = True): ... ValueError: Conic Projective Conic Curve over Real Field with 53 bits of precision defined by x^2 + y^2 + z^2 has no rational points over Real Field with 53 bits of precision! """ - bl,pt = self.has_rational_point(point = True, algorithm = algorithm, - read_cache = read_cache) + bl,pt = self.has_rational_point(point=True, algorithm=algorithm, + read_cache=read_cache) if bl: return pt raise ValueError("Conic %s has no rational points over %s!" % \ @@ -1160,7 +1158,7 @@ def singular_point(self): ... ValueError: The conic self (= Projective Conic Curve over Rational Field defined by x^2 + x*y + y^2 + x*z + y*z + z^2) has no rational singular point """ - b = self.has_singular_point(point = True) + b = self.has_singular_point(point=True) if not b[0]: raise ValueError("The conic self (= %s) has no rational " \ "singular point" % self) diff --git a/src/sage/schemes/product_projective/space.py b/src/sage/schemes/product_projective/space.py index a7eb86ce43f..a727bb5e285 100644 --- a/src/sage/schemes/product_projective/space.py +++ b/src/sage/schemes/product_projective/space.py @@ -190,7 +190,7 @@ class ProductProjectiveSpaces_ring(AmbientSpace): sage: f(Q) (4 : 1 , 1 : 2 : 1) """ - def __init__(self, N, R = QQ, names = None): + def __init__(self, N, R=QQ, names=None): r""" The Python constructor. @@ -292,9 +292,9 @@ def _latex_(self): {\mathbf P}_{\Bold{Z}}^1 \times {\mathbf P}_{\Bold{Z}}^2 \times {\mathbf P}_{\Bold{Z}}^3 """ - return '%s' % " \\times ".join(PS._latex_() for PS in self) + return " \\times ".join(PS._latex_() for PS in self) - def _latex_generic_point(self, v = None): + def _latex_generic_point(self, v=None): """ Return a LaTeX representation of the generic point on this product space. @@ -893,7 +893,7 @@ def change_ring(self, R): new_components = [P.change_ring(R) for P in self._components] return ProductProjectiveSpaces(new_components) - def affine_patch(self, I, return_embedding = False): + def affine_patch(self, I, return_embedding=False): r""" Return the `I^{th}` affine patch of this projective space product where ``I`` is a multi-index. diff --git a/src/sage/schemes/product_projective/subscheme.py b/src/sage/schemes/product_projective/subscheme.py index 1ac8018f8ab..963feea3d09 100644 --- a/src/sage/schemes/product_projective/subscheme.py +++ b/src/sage/schemes/product_projective/subscheme.py @@ -282,7 +282,7 @@ def is_smooth(self, point=None): """ raise NotImplementedError("Not Implemented") - def affine_patch(self, I, return_embedding = False): + def affine_patch(self, I, return_embedding=False): r""" Return the `I^{th}` affine patch of this projective scheme where 'I' is a multi-index. diff --git a/src/sage/schemes/projective/projective_subscheme.py b/src/sage/schemes/projective/projective_subscheme.py index fec6ea3558c..3c0faa498a6 100644 --- a/src/sage/schemes/projective/projective_subscheme.py +++ b/src/sage/schemes/projective/projective_subscheme.py @@ -201,9 +201,10 @@ def dimension(self): self.__dimension = self.defining_ideal().dimension() - 1 return self.__dimension - def affine_patch(self, i, AA = None): + def affine_patch(self, i, AA=None): r""" Return the `i^{th}` affine patch of this projective scheme. + This is the intersection with this `i^{th}` affine patch of its ambient space. @@ -598,7 +599,7 @@ def nth_iterate(self, f, n): raise TypeError("must be a forward orbit") return self.orbit(f,[n,n+1])[0] - def _forward_image(self, f, check = True): + def _forward_image(self, f, check=True): r""" Compute the forward image of this subscheme by the morphism ``f``. @@ -771,11 +772,11 @@ def _forward_image(self, f, check = True): m = CR_codom.ngens() #can't call eliminate if the base ring is polynomial so we do it ourselves #with a lex ordering - R = PolynomialRing(f.base_ring(), n+m, 'tempvar', order = 'lex') + R = PolynomialRing(f.base_ring(), n + m, 'tempvar', order='lex') Rvars = R.gens()[0 : n] - phi = CR_dom.hom(Rvars,R) + phi = CR_dom.hom(Rvars, R) zero = n*[0] - psi = R.hom(zero + list(CR_codom.gens()),CR_codom) + psi = R.hom(zero + list(CR_codom.gens()), CR_codom) #set up ideal L = R.ideal([phi(t) for t in self.defining_polynomials()] + [R.gen(n+i) - phi(f[i]) for i in range(m)]) G = L.groebner_basis() # eliminate From 9567e09a4ac8092f58d65b67076931ac4f4b434f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 9 Aug 2022 18:59:41 +0200 Subject: [PATCH 187/742] fix E251 in groups --- .../additive_abelian_group.py | 3 ++- .../additive_abelian_wrapper.py | 2 +- src/sage/groups/cubic_braid.py | 17 ++++++++-------- src/sage/groups/finitely_presented.py | 2 +- src/sage/groups/old.pyx | 2 +- src/sage/groups/perm_gps/cubegroup.py | 2 +- .../perm_gps/partn_ref/refinement_graphs.pyx | 10 +++++++--- .../perm_gps/partn_ref/refinement_sets.pyx | 4 +++- .../partn_ref2/refinement_generic.pyx | 2 +- src/sage/groups/perm_gps/permgroup.py | 20 +++++++++---------- .../groups/perm_gps/permgroup_element.pyx | 4 ++-- 11 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/sage/groups/additive_abelian/additive_abelian_group.py b/src/sage/groups/additive_abelian/additive_abelian_group.py index 0a326d42c60..3efc1d7621c 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_group.py +++ b/src/sage/groups/additive_abelian/additive_abelian_group.py @@ -11,7 +11,8 @@ from sage.modules.fg_pid.fgp_element import FGP_Element from sage.rings.integer_ring import ZZ -def AdditiveAbelianGroup(invs, remember_generators = True): + +def AdditiveAbelianGroup(invs, remember_generators=True): r""" Construct a finitely-generated additive abelian group. diff --git a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py index 87bbfcb938e..7c0aec05ff8 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py +++ b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py @@ -465,7 +465,7 @@ def _element_constructor_(self, x, check=False): (6, 2) """ if parent(x) is self.universe(): - return self.element_class(self, self.discrete_log(x), element = x) + return self.element_class(self, self.discrete_log(x), element=x) return addgp.AdditiveAbelianGroup_fixed_gens._element_constructor_(self, x, check) diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index 295d43aa1d2..77f95ef3758 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -194,7 +194,8 @@ def AssionGroupS(n=None, names='s'): sage: S3 == S3x True """ - return CubicBraidGroup(n = n, names = names, cbg_type=CubicBraidGroup.type.AssionS) + return CubicBraidGroup(n=n, names=names, + cbg_type=CubicBraidGroup.type.AssionS) def AssionGroupU(n=None, names='u'): @@ -222,9 +223,9 @@ def AssionGroupU(n=None, names='u'): Assion group on 3 strands of type U sage: U3 == U3x True - """ - return CubicBraidGroup(n = n, names = names, cbg_type=CubicBraidGroup.type.AssionU) + return CubicBraidGroup(n=n, names=names, + cbg_type=CubicBraidGroup.type.AssionU) @@ -367,9 +368,9 @@ class :class:`Braid`. braid_group = self.parent().braid_group() return braid_group(self) - @cached_method - def burau_matrix(self, root_bur = None, domain = None, characteristic = None, var='t', reduced=False): + def burau_matrix(self, root_bur=None, domain=None, characteristic=None, + var='t', reduced=False): r""" Return the Burau matrix of the cubic braid coset. @@ -2022,10 +2023,10 @@ def is_finite(self): from sage.rings.infinity import infinity return not self.order() is infinity - # ---------------------------------------------------------------------------------- + # ------------------------------------------------------------------ # creating a CubicBraidGroup as subgroup of self on less strands - # ---------------------------------------------------------------------------------- - def cubic_braid_subgroup(self, nstrands = None): + # ------------------------------------------------------------------ + def cubic_braid_subgroup(self, nstrands=None): r""" Creates a cubic braid group as subgroup of ``self`` on the first ``nstrands`` strands. diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 2a61bbf91dc..d953022d3da 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1486,7 +1486,7 @@ def epimorphisms(self, H): res.append(fhom) return res - def alexander_matrix(self, im_gens = None): + def alexander_matrix(self, im_gens=None): """ Return the Alexander matrix of the group. diff --git a/src/sage/groups/old.pyx b/src/sage/groups/old.pyx index 8d6740a454a..c17082f59cb 100644 --- a/src/sage/groups/old.pyx +++ b/src/sage/groups/old.pyx @@ -31,7 +31,7 @@ cdef class Group(sage.structure.parent.Parent): """ Generic group class """ - def __init__(self, category = None): + def __init__(self, category=None): """ TESTS:: diff --git a/src/sage/groups/perm_gps/cubegroup.py b/src/sage/groups/perm_gps/cubegroup.py index 3c704b0dc9b..921c6201c43 100644 --- a/src/sage/groups/perm_gps/cubegroup.py +++ b/src/sage/groups/perm_gps/cubegroup.py @@ -944,7 +944,7 @@ def repr2d(self, mv): line13 = " +--------------+\n" return line1+line2+line3+line4+line5+line6+line7+line8+line9+line10+line11+line12+line13 - def plot_cube(self, mv, title=True, colors = [lpurple, yellow, red, green, orange, blue]): + def plot_cube(self, mv, title=True, colors=[lpurple, yellow, red, green, orange, blue]): r""" Input the move mv, as a string in the Singmaster notation, and output the 2D plot of the cube in that state. diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx index 34d453cba77..4ab08bd6ba7 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx @@ -1257,8 +1257,9 @@ cdef void free_dg_edge_gen(iterator *dg_edge_gen): sig_free(dg_edge_gen) -def generate_dense_graphs_edge_addition(int n, bint loops, G = None, depth = None, bint construct = False, - bint indicate_mem_err = True): +def generate_dense_graphs_edge_addition(int n, bint loops, G=None, depth=None, + bint construct=False, + bint indicate_mem_err=True): r""" EXAMPLES:: @@ -1534,7 +1535,10 @@ cdef void free_cgd_2(void *data): cdef canonical_generator_data *cgd = data deallocate_cgd(cgd) -def generate_dense_graphs_vert_addition(int n, base_G = None, bint construct = False, bint indicate_mem_err = True): + +def generate_dense_graphs_vert_addition(int n, base_G=None, + bint construct=False, + bint indicate_mem_err=True): r""" EXAMPLES:: diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx index 1ae52e88426..6e80294db3c 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx @@ -685,7 +685,9 @@ cdef iterator *setup_set_gen(iterator *subset_gen, int degree, int max_size): bitset_clear(&empty_set.bits) return subset_iterator -def sets_modulo_perm_group(list generators, int max_size, bint indicate_mem_err = 1): + +def sets_modulo_perm_group(list generators, int max_size, + bint indicate_mem_err=1): r""" Given generators of a permutation group, list subsets up to permutations in the group. diff --git a/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pyx b/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pyx index 2fcb0363a8b..b423ef036b0 100644 --- a/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pyx +++ b/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pyx @@ -639,7 +639,7 @@ cdef class PartitionRefinement_generic: self._backtrack(True) self._finish_latex() - cdef void _backtrack(self, bint first_step = False): + cdef void _backtrack(self, bint first_step=False): r""" Backtracking with pruning. diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 49089346995..9d3dae84cb0 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -2781,7 +2781,7 @@ def semidirect_product(self, N, mapping, check=True): from sage.categories.finite_permutation_groups import FinitePermutationGroups if N not in FinitePermutationGroups(): raise TypeError("{0} is not a permutation group".format(N)) - if not PermutationGroup(gens = mapping[0]) == self: + if not PermutationGroup(gens=mapping[0]) == self: msg = 'the generator list must generate the calling group, {0} does not generate {1}' raise ValueError(msg.format(mapping[0], self._repr_())) if len(mapping[0]) != len(mapping[1]): @@ -3159,7 +3159,7 @@ def commutator(self, other=None): return PermutationGroup(gap_group=gap_group) @hap_decorator - def cohomology(self, n, p = 0): + def cohomology(self, n, p=0): r""" Computes the group cohomology `H^n(G, F)`, where `F = \ZZ` if `p=0` and `F = \ZZ / p \ZZ` if `p > 0` is a prime. @@ -3208,7 +3208,7 @@ def cohomology(self, n, p = 0): return AbelianGroup(len(L), L) @hap_decorator - def cohomology_part(self, n, p = 0): + def cohomology_part(self, n, p=0): r""" Compute the p-part of the group cohomology `H^n(G, F)`, where `F = \ZZ` if `p=0` and `F = \ZZ / p \ZZ` if @@ -3244,7 +3244,7 @@ def cohomology_part(self, n, p = 0): return AbelianGroup(len(L), L) @hap_decorator - def homology(self, n, p = 0): + def homology(self, n, p=0): r""" Computes the group homology `H_n(G, F)`, where `F = \ZZ` if `p=0` and `F = \ZZ / p \ZZ` if @@ -3292,7 +3292,7 @@ def homology(self, n, p = 0): return AbelianGroup(len(L), L) @hap_decorator - def homology_part(self, n, p = 0): + def homology_part(self, n, p=0): r""" Computes the `p`-part of the group homology `H_n(G, F)`, where `F = \ZZ` if `p=0` and @@ -3616,7 +3616,7 @@ def _regular_subgroup_gap(self): return C @cached_method - def has_regular_subgroup(self, return_group = False): + def has_regular_subgroup(self, return_group=False): r""" Return whether the group contains a regular subgroup. @@ -3656,12 +3656,10 @@ def has_regular_subgroup(self, return_group = False): b = (C is not None) if b and return_group: G = self.subgroup(gap_group=C.Representative()) - if return_group: - return G - else: - return b - def blocks_all(self, representatives = True): + return G if return_group else b + + def blocks_all(self, representatives=True): r""" Return the list of block systems of imprimitivity. diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index 037884f55da..df553df6ed8 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -1849,14 +1849,14 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): [2, 1, 1] """ cycle_type = [len(c) for c in self.cycle_tuples(singletons)] - cycle_type.sort(reverse = True) + cycle_type.sort(reverse=True) if as_list: return cycle_type else: from sage.combinat.partition import _Partitions return _Partitions(cycle_type) - def has_descent(self, i, side = "right", positive = False): + def has_descent(self, i, side="right", positive=False): """ INPUT: From d93b793c7bb627e82ce22fb4f4a4c5a278fc7dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 9 Aug 2022 21:19:24 +0200 Subject: [PATCH 188/742] details in saturation --- src/sage/schemes/elliptic_curves/saturation.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py index 1d75c076e53..9f5b59ac404 100644 --- a/src/sage/schemes/elliptic_curves/saturation.py +++ b/src/sage/schemes/elliptic_curves/saturation.py @@ -693,14 +693,14 @@ def p_projections(Eq, Plist, p, debug=False): # roots of unity with p1|p2, together with discrete log in the # multiplicative group. - zeta = g1.weil_pairing(g2,p2) # a primitive p1'th root of unity + zeta = g1.weil_pairing(g2, p2) # a primitive p1'th root of unity if debug: print("wp of gens = {} with order {}".format(zeta, zeta.multiplicative_order())) - assert zeta.multiplicative_order() == p1, "Weil pairing error during saturation: p={}, G={}, Plist={}".format(p,G,Plist) + assert zeta.multiplicative_order() == p1, "Weil pairing error during saturation: p={}, G={}, Plist={}".format(p, G, Plist) # logs are well-defined mod p1, hence mod p - return [vector(Fp, [dlog(pt.weil_pairing(g1,p2), zeta, + return [vector(Fp, [dlog(pt.weil_pairing(g1, p2), zeta, ord=p1, operation='*') for pt in pts]), - vector(Fp, [dlog(pt.weil_pairing(g2,p2), zeta, - ord=p1, operation='*') for pt in pts])] + vector(Fp, [dlog(pt.weil_pairing(g2, p2), zeta, + ord=p1, operation='*') for pt in pts])] From 499f5ce57ac696ab74f560d9494a948270f91285 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 12:46:12 -0700 Subject: [PATCH 189/742] build/pkgs/gcc/spkg-configure.m4: Reject gcc < 8 --- build/pkgs/gcc/spkg-configure.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/gcc/spkg-configure.m4 b/build/pkgs/gcc/spkg-configure.m4 index 959e499b68a..63335eb7357 100644 --- a/build/pkgs/gcc/spkg-configure.m4 +++ b/build/pkgs/gcc/spkg-configure.m4 @@ -161,8 +161,8 @@ SAGE_SPKG_CONFIGURE_BASE([gcc], [ # Add the .0 because Debian/Ubuntu gives version numbers like # 4.6 instead of 4.6.4 (Trac #18885) AS_CASE(["$GXX_VERSION.0"], - [[[0-5]].*|6.[[0-2]].*], [ - # Install our own GCC if the system-provided one is older than gcc-6.3 + [[[0-7]].*], [ + # Install our own GCC if the system-provided one is older than gcc 8 SAGE_SHOULD_INSTALL_GCC([you have $CXX version $GXX_VERSION, which is quite old]) ], [1[[3-9]].*], [ From 810ecd144d1b770901be51b09c5b9071f98393ce Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 12:48:30 -0700 Subject: [PATCH 190/742] README.md, src/doc/en/installation/source.rst: Update version lower bound for gcc --- README.md | 2 +- src/doc/en/installation/source.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fd467aa85f8..abe5d2a42fe 100644 --- a/README.md +++ b/README.md @@ -243,7 +243,7 @@ in the Installation Guide. 3. [Linux, Cygwin] Install the required minimal build prerequisites. - - Compilers: `gcc`, `gfortran`, `g++` (GCC 6.3 to 12.x and recent + - Compilers: `gcc`, `gfortran`, `g++` (GCC 8.x to 12.x and recent versions of Clang (LLVM) are supported). See the Installation Manual for a discussion of suitable compilers. diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index f670cd925b9..78b5ec62810 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -59,7 +59,7 @@ and the :wikipedia:`bash ` shell, the following standard command-line development tools must be installed on your computer: -- A **C/C++ compiler**: GCC versions 6.3 to 12.x are supported. +- A **C/C++ compiler**: GCC versions 8.x to 12.x are supported. Clang (LLVM) is also supported. See also `Using alternative compilers`_. - **make**: GNU make, version 3.80 or later. Version 3.82 or later is recommended. From 4e8ec602ed0653b6dbc0b19f45e48f943555e7c4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 13:01:37 -0700 Subject: [PATCH 191/742] .github/workflows/docker.yml: Remove debian-stretch, fedora-{26,27,27} --- .github/workflows/docker.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 79fd279963c..534a0e0e273 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -22,7 +22,6 @@ on: "ubuntu-focal", "ubuntu-jammy", "ubuntu-kinetic", - "debian-stretch", "debian-buster", "debian-bullseye", "debian-bookworm", @@ -33,9 +32,6 @@ on: "linuxmint-20.2", "linuxmint-20.3", "linuxmint-21", - "fedora-26", - "fedora-27", - "fedora-28", "fedora-29", "fedora-30", "fedora-31", From a9f4b154cfe44116bd0aa0dc6c86d9993aaaeab7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 13:07:47 -0700 Subject: [PATCH 192/742] tox.ini (gcc_8), build/pkgs/_gcc8: New --- build/pkgs/_gcc8/distros/debian.txt | 3 +++ build/pkgs/_gcc8/distros/opensuse.txt | 3 +++ build/pkgs/_gcc8/type | 1 + tox.ini | 2 ++ 4 files changed, 9 insertions(+) create mode 100644 build/pkgs/_gcc8/distros/debian.txt create mode 100644 build/pkgs/_gcc8/distros/opensuse.txt create mode 100644 build/pkgs/_gcc8/type diff --git a/build/pkgs/_gcc8/distros/debian.txt b/build/pkgs/_gcc8/distros/debian.txt new file mode 100644 index 00000000000..3c56d438a9e --- /dev/null +++ b/build/pkgs/_gcc8/distros/debian.txt @@ -0,0 +1,3 @@ +gcc-8 +g++-8 +gfortran-8 diff --git a/build/pkgs/_gcc8/distros/opensuse.txt b/build/pkgs/_gcc8/distros/opensuse.txt new file mode 100644 index 00000000000..7a7764d2d5a --- /dev/null +++ b/build/pkgs/_gcc8/distros/opensuse.txt @@ -0,0 +1,3 @@ +gcc8 +gcc8-c++ +gcc8-fortran diff --git a/build/pkgs/_gcc8/type b/build/pkgs/_gcc8/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/_gcc8/type @@ -0,0 +1 @@ +optional diff --git a/tox.ini b/tox.ini index ad135de10cb..a2520b51bdd 100644 --- a/tox.ini +++ b/tox.ini @@ -523,6 +523,8 @@ setenv = # - toolchain # gcc_spkg: CONFIG_CONFIGURE_ARGS_2=--without-system-gcc + gcc_8: CONFIG_CONFIGURE_ARGS_2=--with-system-gcc=force CC=gcc-8 CXX=g++-8 FC=gfortran-8 + gcc_8: EXTRA_SAGE_PACKAGES_2=_gcc8 gcc_9: CONFIG_CONFIGURE_ARGS_2=--with-system-gcc=force CC=gcc-9 CXX=g++-9 FC=gfortran-9 gcc_9: EXTRA_SAGE_PACKAGES_2=_gcc9 gcc_10: CONFIG_CONFIGURE_ARGS_2=--with-system-gcc=force CC=gcc-10 CXX=g++-10 FC=gfortran-10 From 120ab057065a70a24c515e1a8788c96141f9db5f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 13:08:10 -0700 Subject: [PATCH 193/742] tox.ini (envlist): Replace docker-ubuntu-trusty-minimal with docker-ubuntu-trusty-toolchain-gcc_9-minimal --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index a2520b51bdd..0106e693891 100644 --- a/tox.ini +++ b/tox.ini @@ -55,7 +55,7 @@ envlist = ### - standard # Install all known system packages equivalent to standard packages that have spkg-configure.m4 ### - maximal # Install all known system packages equivalent to standard/optional packages that have spkg-configure.m4 - docker-ubuntu-trusty-minimal, + docker-ubuntu-trusty-toolchain-gcc_9-minimal, docker-debian-bullseye-standard, docker-fedora-34-standard, docker-archlinux-latest-maximal, From 9b38bad852a3d10712f7cbcad6dfbca158f623d1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 13:11:14 -0700 Subject: [PATCH 194/742] build/pkgs/_gcc{9,10,11}/distros/opensuse.txt: New --- build/pkgs/_gcc10/distros/opensuse.txt | 3 +++ build/pkgs/_gcc11/distros/opensuse.txt | 3 +++ build/pkgs/_gcc9/distros/opensuse.txt | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 build/pkgs/_gcc10/distros/opensuse.txt create mode 100644 build/pkgs/_gcc11/distros/opensuse.txt create mode 100644 build/pkgs/_gcc9/distros/opensuse.txt diff --git a/build/pkgs/_gcc10/distros/opensuse.txt b/build/pkgs/_gcc10/distros/opensuse.txt new file mode 100644 index 00000000000..372f607e2ab --- /dev/null +++ b/build/pkgs/_gcc10/distros/opensuse.txt @@ -0,0 +1,3 @@ +gcc10 +gcc10-c++ +gcc10-fortran diff --git a/build/pkgs/_gcc11/distros/opensuse.txt b/build/pkgs/_gcc11/distros/opensuse.txt new file mode 100644 index 00000000000..467f354c123 --- /dev/null +++ b/build/pkgs/_gcc11/distros/opensuse.txt @@ -0,0 +1,3 @@ +gcc11 +gcc11-c++ +gcc11-fortran diff --git a/build/pkgs/_gcc9/distros/opensuse.txt b/build/pkgs/_gcc9/distros/opensuse.txt new file mode 100644 index 00000000000..ea8e8a6bcaa --- /dev/null +++ b/build/pkgs/_gcc9/distros/opensuse.txt @@ -0,0 +1,3 @@ +gcc9 +gcc9-c++ +gcc9-fortran From ccce5b1e5fb7b8ac15512b079aa3ee98d7753dab Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 13:40:23 -0700 Subject: [PATCH 195/742] .github/workflows/docker.yml: Use gcc_8 with ubuntu-bionic, linuxmint-19.x --- .github/workflows/docker.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 534a0e0e273..950f36f44e7 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -18,7 +18,7 @@ on: default: >- ["ubuntu-trusty-toolchain-gcc_9", "ubuntu-xenial-toolchain-gcc_9", - "ubuntu-bionic", + "ubuntu-bionic-gcc_8", "ubuntu-focal", "ubuntu-jammy", "ubuntu-kinetic", @@ -26,8 +26,8 @@ on: "debian-bullseye", "debian-bookworm", "debian-sid", - "linuxmint-19", - "linuxmint-19.3", + "linuxmint-19-gcc_8", + "linuxmint-19.3-gcc_8", "linuxmint-20.1", "linuxmint-20.2", "linuxmint-20.3", From 27a0882bc43a231ebecb439f80026a3cf9c526fc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 13:40:42 -0700 Subject: [PATCH 196/742] .github/workflows/docker.yml: Use gcc_11 with opensuse-15.{3,4} --- .github/workflows/docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 950f36f44e7..8eff13405f8 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -47,8 +47,8 @@ on: "gentoo-python3.9", "gentoo-python3.10", "archlinux-latest", - "opensuse-15.3", - "opensuse-15.4", + "opensuse-15.3-gcc_11", + "opensuse-15.4-gcc_11", "opensuse-tumbleweed", "conda-forge", "ubuntu-bionic-i386", From 8729071a8e49e53e0aed08997e391bcfb1b8a43a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Tue, 9 Aug 2022 23:38:27 +0200 Subject: [PATCH 197/742] 33002: updating doctest to fix deprecation warning --- src/sage/misc/latex_standalone.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/latex_standalone.py b/src/sage/misc/latex_standalone.py index 8f698ffc2e6..8d9e928c012 100644 --- a/src/sage/misc/latex_standalone.py +++ b/src/sage/misc/latex_standalone.py @@ -158,7 +158,7 @@ sage: from sage.misc.latex_standalone import TikzPicture sage: V = [[1,0,1],[1,0,0],[1,1,0],[0,0,-1],[0,1,0],[-1,0,0],[0,1,1],[0,0,1],[0,-1,0]] sage: P = Polyhedron(vertices=V).polar() - sage: s = P.projection().tikz([674,108,-731],112) + sage: s = P.projection().tikz([674,108,-731],112, output_type='LatexExpr') sage: t = TikzPicture(s) Open the image in a viewer (the returned value is a string giving the From d086479da51147e7a539ea55f5d3225dd704561a Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Wed, 10 Aug 2022 22:48:43 +0800 Subject: [PATCH 198/742] 34212: clean version --- src/sage/rings/number_field/number_field.py | 67 +++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 66dddb5597e..8e0c876b933 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -153,6 +153,10 @@ from collections import Counter from builtins import zip +from sage.categories.homset import Hom +from sage.categories.sets_cat import Sets +from sage.modules.free_module import VectorSpace +from sage.modules.free_module_element import vector _NumberFields = NumberFields() @@ -9297,6 +9301,69 @@ def minkowski_embedding(self, B=None, prec=None): return sage.matrix.all.matrix(d) + def logarithmic_embedding(self, prec=53): + """ + Return the morphism of ``self`` under the logarithmic embedding + in the category Set. + + The logarithmic embedding is defined as a map from the number field ``self`` to `\RR^n`. + + It is defined under Definition 4.9.6 in [Cohen1993]_. + + INPUT: + + - ``prec`` -- desired floating point precision. + + OUTPUT: + + - a tuple of real numbers. + + EXAMPLES:: + + sage: CF. = CyclotomicField(97) + sage: f = CF.logarithmic_embedding() + sage: f(0) + (-1) + sage: f(7) + (1.94591014905531) + + :: + + sage: K. = NumberField(x^3 + 5) + sage: f = K.logarithmic_embedding() + sage: f(0) + (-1) + sage: f(7) + (1.94591014905531) + """ + def closure_map(x, prec=53): + """ + The function closure of the logarithmic embedding. + """ + K = self.base_ring() + K_embeddings = K.places(prec) + r1, r2 = K.signature() + r = r1 + r2 - 1 + + from sage.rings.all import RealField + Reals = RealField(prec) + + if x == 0: + return vector([-1 for _ in range(r + 1)]) + + x_logs = [] + for i in range(r1): + sigma = K_embeddings[i] + x_logs.append(Reals(abs(sigma(x))).log()) + for i in range(r1, r + 1): + tau = K_embeddings[i] + x_logs.append(2 * Reals(abs(tau(x))).log()) + + return vector(x_logs) + + log_map = closure_map(self(0), prec) + return Hom(self, VectorSpace(QQ, len(log_map)), Sets()) + def places(self, all_complex=False, prec=None): r""" Return the collection of all infinite places of self. From 2e9c42adcf9cf8a491a0954b18318289c0ae1b74 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Thu, 11 Aug 2022 14:00:41 +0800 Subject: [PATCH 199/742] 34212: fix doc --- src/sage/rings/number_field/number_field.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 8e0c876b933..2b7687ad9fa 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -157,6 +157,7 @@ from sage.categories.sets_cat import Sets from sage.modules.free_module import VectorSpace from sage.modules.free_module_element import vector +from sage.rings.real_mpfr import RR _NumberFields = NumberFields() @@ -9302,7 +9303,7 @@ def minkowski_embedding(self, B=None, prec=None): return sage.matrix.all.matrix(d) def logarithmic_embedding(self, prec=53): - """ + r""" Return the morphism of ``self`` under the logarithmic embedding in the category Set. @@ -9362,7 +9363,8 @@ def closure_map(x, prec=53): return vector(x_logs) log_map = closure_map(self(0), prec) - return Hom(self, VectorSpace(QQ, len(log_map)), Sets()) + hom = Hom(self, VectorSpace(RR, len(log_map)), Sets()) + return hom(log_map) def places(self, all_complex=False, prec=None): r""" From ba8c658fb0abc2244d935923e3939b16d8f54435 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Thu, 11 Aug 2022 16:43:53 +0800 Subject: [PATCH 200/742] 34212: fix doc and code --- src/sage/rings/number_field/number_field.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 2b7687ad9fa..594d103b6aa 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -9317,31 +9317,31 @@ def logarithmic_embedding(self, prec=53): OUTPUT: - - a tuple of real numbers. + - the morphism of ``self`` under the logarithmic embedding in the category Set. EXAMPLES:: - sage: CF. = CyclotomicField(97) + sage: CF. = CyclotomicField(5) sage: f = CF.logarithmic_embedding() sage: f(0) - (-1) + (-1, -1) sage: f(7) - (1.94591014905531) + (3.89182029811063, 3.89182029811063) :: sage: K. = NumberField(x^3 + 5) sage: f = K.logarithmic_embedding() sage: f(0) - (-1) + (-1, -1) sage: f(7) - (1.94591014905531) + (1.94591014905531, 3.89182029811063) """ def closure_map(x, prec=53): """ The function closure of the logarithmic embedding. """ - K = self.base_ring() + K = self K_embeddings = K.places(prec) r1, r2 = K.signature() r = r1 + r2 - 1 @@ -9362,9 +9362,8 @@ def closure_map(x, prec=53): return vector(x_logs) - log_map = closure_map(self(0), prec) - hom = Hom(self, VectorSpace(RR, len(log_map)), Sets()) - return hom(log_map) + hom = Hom(self, VectorSpace(RR, len(closure_map(self(0), prec))), Sets()) + return hom(closure_map) def places(self, all_complex=False, prec=None): r""" From 69d1ea8445763c5190ff0edc584306d6bf346c80 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Thu, 11 Aug 2022 16:15:08 -0700 Subject: [PATCH 201/742] Add horizontal cells --- src/sage/combinat/partition.py | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 6b8b2f669e4..787f76b2591 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -4752,6 +4752,60 @@ def add_horizontal_border_strip(self, k): res.append(_Partitions(tmp)) return res + def horizontal_border_strip_cells(self, k): + """ + Return a list of all the horizontal border strips of length ``k`` + which can be added to ``self``, where each horizontal border strip is + represented as a list of cells. + + EXAMPLES:: + + sage: Partition([]).horizontal_border_strip_cells(0) + [] + sage: Partition([3,2,1]).horizontal_border_strip_cells(0) + [] + sage: Partition([]).horizontal_border_strip_cells(2) + [[(0, 0), (0, 1)]] + sage: Partition([2,2]).horizontal_border_strip_cells(2) + [[(0, 2), (0, 3)], [(0, 2), (2, 0)], [(2, 0), (2, 1)]] + sage: Partition([3,2,2]).horizontal_border_strip_cells(2) + [[(0, 3), (0, 4)], + [(0, 3), (1, 2)], + [(0, 3), (3, 0)], + [(1, 2), (3, 0)], + [(3, 0), (3, 1)]] + """ + if k == 0: + return list() + + L = self._list + res = [] + shelf = [k] # the number of boxes which will fit in a row + mapping = [0] # a record of the rows + for i in range(len(L)-1): + val = L[i] - L[i+1] + if not val: + continue + mapping.append(i+1) + shelf.append(val) + + # add the last shelf + if L: + mapping.append(len(L)) + shelf.append(L[-1]) + + L.append(0) # add room on the bottom + # list all of the positions for cells + # filling each self from the top to bottom + for iv in IntegerListsBackend_invlex(k, length=len(shelf), ceiling=shelf, check=False)._iter(): + tmp = [] + # mapping[i] is the row index, val is the number of cells added to the row. + for i, val in enumerate(iv): + tmp.extend((mapping[i], L[mapping[i]] + j) for j in range(val)) + res.append(tmp) + return res + + def remove_horizontal_border_strip(self, k): """ Return the partitions obtained from ``self`` by removing an From 3d7a37bb6971fbd8b8cdcfafc92d05e4f5ec81d1 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Thu, 11 Aug 2022 17:21:32 -0700 Subject: [PATCH 202/742] Add vertical strips --- src/sage/combinat/partition.py | 57 ++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 787f76b2591..af39531c26c 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -4805,6 +4805,63 @@ def horizontal_border_strip_cells(self, k): res.append(tmp) return res + def vertical_border_strip_cells(self, k): + """ + Return a list of all the vertical border strips of length ``k`` + which can be added to ``self``, where each horizontal border strip is + represented as a list of cells. + + EXAMPLES:: + + sage: Partition([]).vertical_border_strip_cells(0) + [] + sage: Partition([3,2,1]).vertical_border_strip_cells(0) + [] + sage: Partition([]).vertical_border_strip_cells(2) + [[(0, 0), (1, 0)]] + sage: Partition([2,2]).vertical_border_strip_cells(2) + [[(0, 2), (1, 2)], + [(0, 2), (2, 0)], + [(2, 0), (3, 0)]] + sage: Partition([3,2,2]).vertical_border_strip_cells(2) + [[(0, 3), (1, 2)], + [(0, 3), (3, 0)], + [(1, 2), (2, 2)], + [(1, 2), (3, 0)], + [(3, 0), (4, 0)]] + """ + if k == 0: + return [] + + shelf = [] + res = [] + i = 0 + ell = len(self._list) + while i < ell: + tmp = 1 + while i+1 < ell and self._list[i] == self._list[i+1]: + tmp += 1 + i += 1 + if i == ell-1 and i > 0 and self._list[i] != self._list[i-1]: + tmp = 1 + shelf.append(tmp) + i += 1 + + # added the last shelf on the right side of + # the first line + shelf.append(k) + # list all of the positions for cells + for iv in IntegerListsBackend_invlex(k, length=len(shelf), ceiling=shelf, check=False)._iter(): + tmp = self._list + [0]*k + j = 0 + current_strip = [] + for t in range(len(iv)): + for _ in range(iv[t]): + current_strip.append((j, tmp[j])) + j += 1 + j = sum(shelf[:t+1]) + res.append(current_strip) + return res def remove_horizontal_border_strip(self, k): """ From bae3378fd6cb6a3b772680827c872af820d290c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 11 Aug 2022 17:37:17 +0200 Subject: [PATCH 203/742] fix various suggestions of lgtm.com --- build/pkgs/matplotlib/make-setup-config.py | 5 +- .../algebras/quatalg/quaternion_algebra.py | 19 +-- src/sage/functions/log.py | 7 +- .../groups/abelian_gps/dual_abelian_group.py | 21 ++- src/sage/interfaces/ecm.py | 10 +- src/sage/modules/quotient_module.py | 8 +- src/sage/symbolic/expression_conversions.py | 156 ++++++++++-------- src/sage/typeset/character_art.py | 2 - 8 files changed, 119 insertions(+), 109 deletions(-) diff --git a/build/pkgs/matplotlib/make-setup-config.py b/build/pkgs/matplotlib/make-setup-config.py index 98450dec2fd..4f9acf1f04c 100644 --- a/build/pkgs/matplotlib/make-setup-config.py +++ b/build/pkgs/matplotlib/make-setup-config.py @@ -1,5 +1,4 @@ from configparser import ConfigParser -import pkgconfig import os config = ConfigParser() @@ -23,7 +22,7 @@ print("NOTE: Set SAGE_MATPLOTLIB_GUI to anything but 'no' to try to build the Matplotlib GUI.") -graphical_backend='False' +graphical_backend = 'False' if os.environ.get('SAGE_MATPLOTLIB_GUI', 'no').lower() != 'no': graphical_backend = 'auto' @@ -35,7 +34,7 @@ config.add_section('gui_support') for backend in ('gtk', 'gtkagg', 'tkagg', 'wxagg', 'macosx', 'windowing'): - config.set('gui_support', backend, graphical_backend) + config.set('gui_support', backend, graphical_backend) with open('src/mplsetup.cfg', 'w') as configfile: config.write(configfile) diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py index 3bde7b21536..1ad378eea65 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra.py +++ b/src/sage/algebras/quatalg/quaternion_algebra.py @@ -2690,15 +2690,13 @@ def multiply_by_conjugate(self, J): R = self.quaternion_algebra() return R.ideal(basis, check=False) - def is_equivalent(I, J, B=10): + def is_equivalent(self, J, B=10) -> bool: """ - Return ``True`` if ``I`` and ``J`` are equivalent as right ideals. + Return ``True`` if ``self`` and ``J`` are equivalent as right ideals. INPUT: - - ``I`` -- a fractional quaternion ideal (self) - - - ``J`` -- a fractional quaternion ideal with same order as ``I`` + - ``J`` -- a fractional quaternion ideal with same order as ``self`` - ``B`` -- a bound to compute and compare theta series before doing the full equivalence test @@ -2718,15 +2716,16 @@ def is_equivalent(I, J, B=10): sage: R[0].is_equivalent(S) True """ - if not isinstance(I, QuaternionFractionalIdeal_rational): + # shorthand: let I be self + if not isinstance(self, QuaternionFractionalIdeal_rational): return False - if I.right_order() != J.right_order(): - raise ValueError("I and J must be right ideals") + if self.right_order() != J.right_order(): + raise ValueError("self and J must be right ideals") # Just test theta series first. If the theta series are # different, the ideals are definitely not equivalent. - if B > 0 and I.theta_series_vector(B) != J.theta_series_vector(B): + if B > 0 and self.theta_series_vector(B) != J.theta_series_vector(B): return False # The theta series are the same, so perhaps the ideals are @@ -2734,7 +2733,7 @@ def is_equivalent(I, J, B=10): # 1. Compute I * Jbar # see Prop. 1.17 in Pizer. Note that we use IJbar instead of # JbarI since we work with right ideals - IJbar = I.multiply_by_conjugate(J) + IJbar = self.multiply_by_conjugate(J) # 2. Determine if there is alpha in K such # that N(alpha) = N(I)*N(J) as explained by Pizer. diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index d322305b223..46cc279a287 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -1243,6 +1243,7 @@ def _print_latex_(self, z, m): harmonic_number = Function_harmonic_number_generalized() + class _Function_swap_harmonic(BuiltinFunction): r""" Harmonic number function with swapped arguments. For internal use only. @@ -1262,14 +1263,18 @@ class _Function_swap_harmonic(BuiltinFunction): """ def __init__(self): BuiltinFunction.__init__(self, "_swap_harmonic", nargs=2) + def _eval_(self, a, b, **kwds): - return harmonic_number(b,a,**kwds) + return harmonic_number(b, a, **kwds) + _swap_harmonic = _Function_swap_harmonic() + register_symbol(_swap_harmonic, {'maxima': 'gen_harmonic_number'}) register_symbol(_swap_harmonic, {'maple': 'harmonic'}) + class Function_harmonic_number(BuiltinFunction): r""" Harmonic number function, defined by: diff --git a/src/sage/groups/abelian_gps/dual_abelian_group.py b/src/sage/groups/abelian_gps/dual_abelian_group.py index df2b51e0d57..521267cccae 100644 --- a/src/sage/groups/abelian_gps/dual_abelian_group.py +++ b/src/sage/groups/abelian_gps/dual_abelian_group.py @@ -63,11 +63,10 @@ # http://www.gnu.org/licenses/ ########################################################################### -from sage.rings.infinity import infinity from sage.structure.category_object import normalize_names from sage.structure.unique_representation import UniqueRepresentation from sage.groups.abelian_gps.dual_abelian_group_element import ( - DualAbelianGroupElement, is_DualAbelianGroupElement ) + DualAbelianGroupElement, is_DualAbelianGroupElement) from sage.misc.mrange import mrange from sage.misc.cachefunc import cached_method from sage.groups.group import AbelianGroup as AbelianGroupBase @@ -126,7 +125,7 @@ def __init__(self, G, names, base_ring): self._group = G names = normalize_names(G.ngens(), names) self._assign_names(names) - AbelianGroupBase.__init__(self) # TODO: category=CommutativeGroups() + AbelianGroupBase.__init__(self) # TODO: category=CommutativeGroups() def group(self): """ @@ -165,7 +164,7 @@ def __str__(self): sage: print(Fd) DualAbelianGroup( AbelianGroup ( 3, (5, 64, 729) ) ) """ - s = "DualAbelianGroup( AbelianGroup ( %s, %s ) )"%(self.ngens(), self.gens_orders()) + s = "DualAbelianGroup( AbelianGroup ( %s, %s ) )" % (self.ngens(), self.gens_orders()) return s def _repr_(self): @@ -188,9 +187,9 @@ def _repr_(self): eldv = G.gens_orders() gp = "" for x in eldv: - if x!=0: - gp = gp + "Z/%sZ x "%x - if x==0: + if x != 0: + gp = gp + "Z/%sZ x " % x + if x == 0: gp = gp + "Z x " gp = gp[:-2].strip() s = 'Dual of Abelian Group isomorphic to ' + gp + ' over ' + str(self.base_ring()) @@ -235,7 +234,7 @@ def random_element(self): result = self.one() for g in self.gens(): order = g.order() - result *= g**(randint(0,order)) + result *= g**(randint(0, order)) return result def gen(self, i=0): @@ -255,8 +254,8 @@ def gen(self, i=0): """ n = self.group().ngens() if i < 0 or i >= n: - raise IndexError("Argument i (= %s) must be between 0 and %s."%(i, n-1)) - x = [0]*n + raise IndexError("Argument i (= %s) must be between 0 and %s." % (i, n - 1)) + x = [0] * n if self.gens_orders()[i] != 1: x[i] = 1 return self.element_class(self, x) @@ -324,7 +323,7 @@ def invariants(self): # TODO: deprecate return self.group().gens_orders() - def __contains__(self,X): + def __contains__(self, X): """ Implements "in". diff --git a/src/sage/interfaces/ecm.py b/src/sage/interfaces/ecm.py index 171040c77a3..81ca002056f 100644 --- a/src/sage/interfaces/ecm.py +++ b/src/sage/interfaces/ecm.py @@ -46,11 +46,11 @@ # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 3 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ############################################################################### import re -import subprocess +from subprocess import Popen, PIPE, call from sage.structure.sage_object import SageObject from sage.rings.integer_ring import ZZ @@ -216,8 +216,6 @@ def _run_ecm(self, cmd, n): sage: ecm._run_ecm(['cat'], 1234) '1234' """ - from subprocess import Popen, PIPE - # Under normal usage this program only returns ASCII; anything # else mixed is garbage and an error # So just accept latin-1 without encoding errors, and let the @@ -261,7 +259,7 @@ def interact(self): """ print("Enter numbers to run ECM on them.") print("Press control-D to exit.") - subprocess.call(self._cmd) + call(self._cmd) # Recommended settings from # http://www.mersennewiki.org/index.php/Elliptic_Curve_Method @@ -661,7 +659,7 @@ def factor(self, n, factor_digits=None, B1=2000, proof=False, **kwds): # Step 3: Call find_factor until a factorization is found n_factorization = [n] while len(n_factorization) == 1: - n_factorization = self.find_factor(n,B1=B1) + n_factorization = self.find_factor(n, B1=B1) factors.extend(n_factorization) return sorted(probable_prime_factors) diff --git a/src/sage/modules/quotient_module.py b/src/sage/modules/quotient_module.py index f7aa99210a1..10db2189997 100644 --- a/src/sage/modules/quotient_module.py +++ b/src/sage/modules/quotient_module.py @@ -19,12 +19,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.richcmp import rich_to_bool, richcmp - from .free_module import (Module_free_ambient, FreeModule_ambient, FreeModule_ambient_field) + ############################################################################### # # Quotients of ambient free modules over a domain @@ -80,7 +79,7 @@ def __init__(self, module, sub): v = [C(self._free_cover, x.list(), coerce=False, copy=False) for x in sub.gens()] w = [C(self._free_cover, x.list(), coerce=False, copy=False) for x in module.free_relations().gens()] self._relations = self._free_cover.submodule(v + w, check=False) - else: # Otherwise module should be a free module + else: # Otherwise module should be a free module self._free_cover = module self._relations = sub @@ -448,7 +447,7 @@ def _repr_(self): sage: Q._repr_() 'Vector space quotient V/W of dimension 1 over Finite Field in a of size 3^2 where\nV: Vector space of degree 3 and dimension 2 over Finite Field in a of size 3^2\nUser basis matrix:\n[1 0 a]\n[a a 1]\nW: Vector space of degree 3 and dimension 1 over Finite Field in a of size 3^2\nBasis matrix:\n[ 1 1 a + 2]' """ - return "%s space quotient V/W of dimension %s over %s where\nV: %s\nW: %s"%( + return "%s space quotient V/W of dimension %s over %s where\nV: %s\nW: %s" % ( "Sparse vector" if self.is_sparse() else "Vector", self.dimension(), self.base_ring(), self.V(), self.W()) @@ -675,4 +674,3 @@ def relations(self): return self._sub W = relations - diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index c5a8240cda0..430b102ba4a 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -15,7 +15,9 @@ # https://www.gnu.org/licenses/ ############################################################################### -import operator as _operator +from operator import eq, ne, gt, lt, ge, le, mul, pow, neg, add, truediv +from functools import reduce + from sage.rings.rational_field import QQ from sage.symbolic.ring import SR from sage.structure.element import Expression @@ -23,7 +25,6 @@ from sage.symbolic.operators import arithmetic_operators, relation_operators, FDerivativeOperator, add_vararg, mul_vararg from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_gaussian from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField -from functools import reduce class FakeExpression(): @@ -59,7 +60,7 @@ def __repr__(self): sage: FakeExpression([x, y], operator.truediv) FakeExpression([x, y], ) """ - return "FakeExpression(%r, %r)"%(self._operands, self._operator) + return "FakeExpression(%r, %r)" % (self._operands, self._operator) def pyobject(self): """ @@ -200,7 +201,7 @@ def __call__(self, ex=None): return self.symbol(ex) if operator in arithmetic_operators: - if getattr(self, 'use_fake_div', False) and (operator is _operator.mul or operator is mul_vararg): + if getattr(self, 'use_fake_div', False) and (operator is mul or operator is mul_vararg): div = self.get_fake_div(ex) return self.arithmetic(div, div.operator()) return self.arithmetic(ex, operator) @@ -238,7 +239,7 @@ def get_fake_div(self, ex): for arg in ex.operands(): ops = arg.operands() try: - if arg.operator() is _operator.pow and repr(ops[1]) == '-1': + if arg.operator() is pow and repr(ops[1]) == '-1': d.append(ops[0]) else: n.append(arg) @@ -250,22 +251,22 @@ def get_fake_div(self, ex): repr_n = [repr(_) for _ in n] if len(n) == 2 and "-1" in repr_n: a = n[0] if repr_n[1] == "-1" else n[1] - return FakeExpression([a], _operator.neg) + return FakeExpression([a], neg) else: return ex elif len_d == 1: d = d[0] else: - d = FakeExpression(d, _operator.mul) + d = FakeExpression(d, mul) if len(n) == 0: - return FakeExpression([SR.one(), d], _operator.truediv) + return FakeExpression([SR.one(), d], truediv) elif len(n) == 1: n = n[0] else: - n = FakeExpression(n, _operator.mul) + n = FakeExpression(n, mul) - return FakeExpression([n,d], _operator.truediv) + return FakeExpression([n, d], truediv) def pyobject(self, ex, obj): """ @@ -379,6 +380,7 @@ def composition(self, ex, operator): """ raise NotImplementedError("composition") + class InterfaceInit(Converter): def __init__(self, interface): """ @@ -395,7 +397,7 @@ def __init__(self, interface): '(%pi)+(exp((_SAGE_VAR_x)^(2)))+(2)' """ - self.name_init = "_%s_init_"%interface.name() + self.name_init = "_%s_init_" % interface.name() self.interface = interface self.relation_symbols = interface._relation_symbols() @@ -417,12 +419,11 @@ def symbol(self, ex): sage: g.symbol(x) 'sageVARx' """ - if self.interface.name()=='maxima': - return '_SAGE_VAR_'+repr(SR(ex)) - elif self.interface.name() == 'giac': + if self.interface.name() == 'maxima': + return '_SAGE_VAR_' + repr(SR(ex)) + if self.interface.name() == 'giac': return 'sageVAR' + repr(SR(ex)) - else: - return repr(SR(ex)) + return repr(SR(ex)) def pyobject(self, ex, obj): """ @@ -440,7 +441,7 @@ def pyobject(self, ex, obj): sage: ii.pyobject(pi, pi.pyobject()) 'Pi' """ - if (self.interface.name() in ['pari','gp'] and + if (self.interface.name() in ['pari', 'gp'] and isinstance(obj, NumberFieldElement_gaussian)): return repr(obj) try: @@ -460,8 +461,8 @@ def relation(self, ex, operator): sage: m.relation(x==3, operator.lt) '_SAGE_VAR_x < 3' """ - return "%s %s %s"%(self(ex.lhs()), self.relation_symbols[operator], - self(ex.rhs())) + return "%s %s %s" % (self(ex.lhs()), self.relation_symbols[operator], + self(ex.rhs())) def tuple(self, ex): """ @@ -575,8 +576,8 @@ def derivative(self, ex, operator): sage: (gamma_inc(x,x+1).diff(x)).simplify() -(x + 1)^(x - 1)*e^(-x - 1) + D[0](gamma)(x, x + 1) """ - #This code should probably be moved into the interface - #object in a nice way. + # This code should probably be moved into the interface + # object in a nice way. from sage.symbolic.ring import is_SymbolicVariable if self.name_init != "_maxima_init_": raise NotImplementedError @@ -591,20 +592,22 @@ def derivative(self, ex, operator): # trac #12796. Note that we cannot use SR.temp_var here # since two conversions of the same expression have to be # equal. - temp_args = [SR.symbol("_symbol%s"%i) for i in range(len(args))] + temp_args = [SR.symbol("_symbol%s" % i) for i in range(len(args))] f = operator.function()(*temp_args) params = operator.parameter_set() - params = ["%s, %s"%(temp_args[i]._maxima_init_(), params.count(i)) for i in set(params)] - subs = ["%s = %s"%(t._maxima_init_(),a._maxima_init_()) for t,a in zip(temp_args,args)] - outstr = "at(diff(%s, %s), [%s])"%(f._maxima_init_(), - ", ".join(params), - ", ".join(subs)) + params = ["%s, %s" % (temp_args[i]._maxima_init_(), params.count(i)) for i in set(params)] + subs = ["%s = %s" % (t._maxima_init_(), a._maxima_init_()) + for t, a in zip(temp_args, args)] + outstr = "at(diff(%s, %s), [%s])" % (f._maxima_init_(), + ", ".join(params), + ", ".join(subs)) else: f = operator.function()(*args) params = operator.parameter_set() - params = ["%s, %s"%(args[i]._maxima_init_(), params.count(i)) for i in set(params)] - outstr = "diff(%s, %s)"%(f._maxima_init_(), - ", ".join(params)) + params = ["%s, %s" % (args[i]._maxima_init_(), params.count(i)) + for i in set(params)] + outstr = "diff(%s, %s)" % (f._maxima_init_(), + ", ".join(params)) return outstr def arithmetic(self, ex, operator): @@ -617,7 +620,7 @@ def arithmetic(self, ex, operator): sage: m.arithmetic(x+2, sage.symbolic.operators.add_vararg) '(_SAGE_VAR_x)+(2)' """ - args = ["(%s)"%self(op) for op in ex.operands()] + args = ["(%s)" % self(op) for op in ex.operands()] return arithmetic_operators[operator].join(args) def composition(self, ex, operator): @@ -636,7 +639,7 @@ def composition(self, ex, operator): 'Sin[x]' """ ops = ex.operands() - #FIXME: consider stripping pyobjects() in ops + # FIXME: consider stripping pyobjects() in ops if hasattr(operator, self.name_init + "evaled_"): return getattr(operator, self.name_init + "evaled_")(*ops) else: @@ -646,7 +649,8 @@ def composition(self, ex, operator): except (TypeError, AttributeError): op = repr(operator) - return self.interface._function_call_string(op,ops,[]) + return self.interface._function_call_string(op, ops, []) + ######### # Sympy # @@ -780,9 +784,8 @@ def relation(self, ex, op): sage: s.relation(x > 0, operator.gt) x > 0 """ - from operator import eq, ne, gt, lt, ge, le from sympy import Eq, Ne, Gt, Lt, Ge, Le - ops = {eq : Eq, ne : Ne, gt : Gt, lt : Lt, ge : Ge, le : Le} + ops = {eq: Eq, ne: Ne, gt: Gt, lt: Lt, ge: Ge, le: Le} return ops.get(op)(self(ex.lhs()), self(ex.rhs()), evaluate=False) def composition(self, ex, operator): @@ -940,6 +943,7 @@ def derivative(self, ex, operator): sympy_converter = SympyConverter() + ########## # FriCAS # ########## @@ -1096,7 +1100,7 @@ def derivative(self, ex, operator): """ from sage.symbolic.ring import is_SymbolicVariable - args = ex.operands() # the arguments the derivative is evaluated at + args = ex.operands() # the arguments the derivative is evaluated at params = operator.parameter_set() params_set = set(params) mult = ",".join(str(params.count(i)) for i in params_set) @@ -1123,8 +1127,10 @@ def derivative(self, ex, operator): return outstr + fricas_converter = FriCASConverter() + ############# # Algebraic # ############# @@ -1199,7 +1205,7 @@ def arithmetic(self, ex, operator): # can change the value of a radical expression (by changing which # root is selected). try: - if operator is _operator.pow: + if operator is pow: from sage.rings.all import Rational base, expt = ex.operands() base = self.field(base) @@ -1207,20 +1213,20 @@ def arithmetic(self, ex, operator): return self.field(base**expt) else: if operator is add_vararg: - operator = _operator.add + operator = add elif operator is mul_vararg: - operator = _operator.mul + operator = mul return reduce(operator, map(self, ex.operands())) except TypeError: pass - if operator is _operator.pow: + if operator is pow: from sage.symbolic.constants import e, pi, I base, expt = ex.operands() - if base == e and expt / (pi*I) in QQ: + if base == e and expt / (pi * I) in QQ: return exp(expt)._algebraic_(self.field) - raise TypeError("unable to convert %r to %s"%(ex, self.field)) + raise TypeError("unable to convert %r to %s" % (ex, self.field)) def composition(self, ex, operator): """ @@ -1291,17 +1297,17 @@ def composition(self, ex, operator): if func_name == 'exp': if operand.is_trivial_zero(): return self.field.one() - if not (SR(-1).sqrt()*operand).is_real(): + if not (SR(-1).sqrt() * operand).is_real(): raise ValueError("unable to represent as an algebraic number") # Coerce (not convert, see #22571) arg to a rational arg = operand.imag()/(2*ex.parent().pi()) try: rat_arg = QQ.coerce(arg.pyobject()) except TypeError: - raise TypeError("unable to convert %r to %s"%(ex, self.field)) + raise TypeError("unable to convert %r to %s" % (ex, self.field)) res = zeta(rat_arg.denom())**rat_arg.numer() elif func_name in ['sin', 'cos', 'tan']: - exp_ia = exp(SR(-1).sqrt()*operand, hold=hold)._algebraic_(QQbar) + exp_ia = exp(SR(-1).sqrt() * operand, hold=hold)._algebraic_(QQbar) if func_name == 'sin': res = (exp_ia - ~exp_ia) / (2 * zeta(4)) elif func_name == 'cos': @@ -1322,13 +1328,14 @@ def composition(self, ex, operator): res = ~self.reciprocal_trig_functions[func_name](operand)._algebraic_(QQbar) else: res = func(operand._algebraic_(self.field)) - #We have to handle the case where we get the same symbolic - #expression back. For example, QQbar(zeta(7)). See - #ticket #12665. + # We have to handle the case where we get the same symbolic + # expression back. For example, QQbar(zeta(7)). See + # ticket #12665. if (res - ex).is_trivial_zero(): - raise TypeError("unable to convert %r to %s"%(ex, self.field)) + raise TypeError("unable to convert %r to %s" % (ex, self.field)) return self.field(res) + def algebraic(ex, field): """ Returns the symbolic expression *ex* as a element of the algebraic @@ -1372,6 +1379,7 @@ def algebraic(ex, field): """ return AlgebraicConverter(field)(ex) + ############## # Polynomial # ############## @@ -1424,7 +1432,7 @@ def __init__(self, ex, base_ring=None, ring=None): self.varnames = ring.variable_names_recursive() for v in ex.variables(): if repr(v) not in self.varnames and v not in base_ring: - raise TypeError("%s is not a variable of %s" %(v, ring)) + raise TypeError("%s is not a variable of %s" % (v, ring)) self.ring = ring self.base_ring = base_ring elif base_ring is not None: @@ -1456,10 +1464,10 @@ def symbol(self, ex): y """ try: - #The symbol is one of the polynomial generators + # The symbol is one of the polynomial generators return self.ring(repr(ex)) except TypeError: - #The symbol should go into the base ring + # The symbol should go into the base ring return self.base_ring(repr(ex)) def pyobject(self, ex, obj): @@ -1541,17 +1549,18 @@ def arithmetic(self, ex, operator): """ if not any(repr(v) in self.varnames for v in ex.variables()): return self.base_ring(ex) - elif operator == _operator.pow: + elif operator == pow: from sage.rings.integer import Integer base, exp = ex.operands() return self(base)**Integer(exp) if operator == add_vararg: - operator = _operator.add + operator = add elif operator == mul_vararg: - operator = _operator.mul + operator = mul ops = [self(a) for a in ex.operands()] return reduce(operator, ops) + def polynomial(ex, base_ring=None, ring=None): """ Return a polynomial from the symbolic expression ``ex``. @@ -1739,7 +1748,7 @@ def relation(self, ex, operator): ... NotImplementedError """ - if operator is not _operator.eq: + if operator is not eq: raise NotImplementedError return self(ex.lhs() - ex.rhs()) @@ -1777,23 +1786,23 @@ def arithmetic(self, ex, operator): # exponent before the exponent gets (potentially) converted # to another type. operands = ex.operands() - if operator is _operator.pow: + if operator is pow: exponent = operands[1] if exponent == -1: - return self.etb.call(_operator.truediv, 1, operands[0]) + return self.etb.call(truediv, 1, operands[0]) elif exponent == 0.5: from sage.misc.functional import sqrt return self.etb.call(sqrt, operands[0]) elif exponent == -0.5: from sage.misc.functional import sqrt - return self.etb.call(_operator.truediv, 1, self.etb.call(sqrt, operands[0])) - elif operator is _operator.neg: + return self.etb.call(truediv, 1, self.etb.call(sqrt, operands[0])) + elif operator is neg: return self.etb.call(operator, operands[0]) if operator == add_vararg: - operator = _operator.add + operator = add elif operator == mul_vararg: - operator = _operator.mul - return reduce(lambda x,y: self.etb.call(operator, x,y), operands) + operator = mul + return reduce(lambda x, y: self.etb.call(operator, x, y), operands) def symbol(self, ex): r""" @@ -1846,6 +1855,7 @@ def tuple(self, ex): """ return ex.operands() + def fast_callable(ex, etb): """ Given an ExpressionTreeBuilder *etb*, return an Expression representing @@ -1867,6 +1877,7 @@ def fast_callable(ex, etb): """ return FastCallableConverter(ex, etb)() + class RingConverter(Converter): def __init__(self, R, subs_dict=None): """ @@ -1940,15 +1951,15 @@ def arithmetic(self, ex, operator): sage: R(a) 2*z^2 + z + 3 """ - if operator not in [_operator.pow, add_vararg, mul_vararg]: + if operator not in [pow, add_vararg, mul_vararg]: raise TypeError operands = ex.operands() - if operator is _operator.pow: + if operator is pow: from sage.all import Integer, Rational base, expt = operands - if expt == Rational(((1,2))): + if expt == Rational(((1, 2))): from sage.misc.functional import sqrt return sqrt(self(base)) try: @@ -1960,9 +1971,9 @@ def arithmetic(self, ex, operator): return base ** expt if operator == add_vararg: - operator = _operator.add + operator = add elif operator == mul_vararg: - operator = _operator.mul + operator = mul return reduce(operator, map(self, operands)) def composition(self, ex, operator): @@ -1974,7 +1985,7 @@ def composition(self, ex, operator): sage: R(cos(2)) -0.4161468365471424? """ - res = operator(*[self(_) for _ in ex.operands()]) + res = operator(*[self(op) for op in ex.operands()]) if res.parent() is not self.ring: raise TypeError else: @@ -2094,6 +2105,7 @@ def tuple(self, ex): """ return ex.operands() + class SubstituteFunction(ExpressionTreeWalker): def __init__(self, ex, *args): """ @@ -2178,6 +2190,7 @@ def derivative(self, ex, operator): else: return operator(*[self(_) for _ in ex.operands()]) + class Exponentialize(ExpressionTreeWalker): # Implementation note: this code is executed once at first # reference in the code using it, therefore avoiding rebuilding @@ -2216,7 +2229,7 @@ def __init__(self, ex): expressions. EXAMPLES:: - + sage: from sage.symbolic.expression_conversions import Exponentialize sage: d = Exponentialize(sin(x)) sage: d(sin(x)) @@ -2268,7 +2281,7 @@ def __init__(self, ex, force=False): """ self.ex = ex self.force = force - + def composition(self, ex, op): """ Return the composition of ``self`` with ``ex`` by ``op``. @@ -2306,6 +2319,7 @@ def composition(self, ex, op): return cosh(arg) + sinh(arg) return exp(arg) + class HoldRemover(ExpressionTreeWalker): def __init__(self, ex, exclude=None): """ diff --git a/src/sage/typeset/character_art.py b/src/sage/typeset/character_art.py index 7ec212f0631..9681f0b8c53 100644 --- a/src/sage/typeset/character_art.py +++ b/src/sage/typeset/character_art.py @@ -24,8 +24,6 @@ # # https://www.gnu.org/licenses/ # ****************************************************************************** - -import os import sys from sage.structure.sage_object import SageObject From dcbbba20f48249d488b0eab5107adfeafee972fd Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 13 Aug 2022 19:34:15 +0200 Subject: [PATCH 204/742] trac #34358: clean src/sage/graphs/generic_graph.py - part 4 --- src/sage/graphs/generic_graph.py | 80 +++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index b8a2a920dab..3e212cb5123 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -17605,7 +17605,7 @@ def wiener_index(self, by_weight=False, algorithm=None, G = networkx.Graph(list(self.edges(labels=False, sort=False))) G.add_nodes_from(self) total = sum(sum(networkx.single_source_dijkstra_path_length(G, u).values()) - for u in G) + for u in G) WI = total if self.is_directed() else (total / 2) else: @@ -17687,14 +17687,14 @@ def average_distance(self, by_weight=False, algorithm=None, """ if self.order() < 2: raise ValueError("average distance is not defined for empty or one-element graph") - WI = self.wiener_index(by_weight=by_weight, algorithm=algorithm, - weight_function=weight_function, check_weight=check_weight) + WI = self.wiener_index(by_weight=by_weight, algorithm=algorithm, + weight_function=weight_function, check_weight=check_weight) f = 1 if self.is_directed() else 2 if WI in ZZ: return QQ((f * WI, self.order() * (self.order() - 1))) return f * WI / (self.order() * (self.order() - 1)) - ### Searches + # Searches def breadth_first_search(self, start, ignore_direction=False, distance=None, neighbors=None, @@ -18038,7 +18038,7 @@ def depth_first_search(self, start, ignore_direction=False, if x not in seen: queue.append((w, x, d + 1)) - ### Constructors + # Constructors def add_clique(self, vertices, loops=False): """ @@ -18543,7 +18543,9 @@ def cartesian_product(self, other): sage: H = Graph([('a', 'b')]) sage: C1 = G.cartesian_product(H) sage: C1.edges(sort=True, labels=None) - [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'b'), (1, 'b')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] + [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'b'), (1, 'b')), + ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), ((1, 'b'), (2, 'b')), + ((2, 'a'), (2, 'b'))] sage: C2 = H.cartesian_product(G) sage: C1.is_isomorphic(C2) True @@ -18562,7 +18564,16 @@ def cartesian_product(self, other): sage: B = digraphs.DeBruijn(['a', 'b'], 2) sage: Q = P.cartesian_product(B) sage: Q.edges(sort=True, labels=None) - [((0, 'aa'), (0, 'aa')), ((0, 'aa'), (0, 'ab')), ((0, 'aa'), (1, 'aa')), ((0, 'ab'), (0, 'ba')), ((0, 'ab'), (0, 'bb')), ((0, 'ab'), (1, 'ab')), ((0, 'ba'), (0, 'aa')), ((0, 'ba'), (0, 'ab')), ((0, 'ba'), (1, 'ba')), ((0, 'bb'), (0, 'ba')), ((0, 'bb'), (0, 'bb')), ((0, 'bb'), (1, 'bb')), ((1, 'aa'), (1, 'aa')), ((1, 'aa'), (1, 'ab')), ((1, 'ab'), (1, 'ba')), ((1, 'ab'), (1, 'bb')), ((1, 'ba'), (1, 'aa')), ((1, 'ba'), (1, 'ab')), ((1, 'bb'), (1, 'ba')), ((1, 'bb'), (1, 'bb'))] + [((0, 'aa'), (0, 'aa')), ((0, 'aa'), (0, 'ab')), + ((0, 'aa'), (1, 'aa')), ((0, 'ab'), (0, 'ba')), + ((0, 'ab'), (0, 'bb')), ((0, 'ab'), (1, 'ab')), + ((0, 'ba'), (0, 'aa')), ((0, 'ba'), (0, 'ab')), + ((0, 'ba'), (1, 'ba')), ((0, 'bb'), (0, 'ba')), + ((0, 'bb'), (0, 'bb')), ((0, 'bb'), (1, 'bb')), + ((1, 'aa'), (1, 'aa')), ((1, 'aa'), (1, 'ab')), + ((1, 'ab'), (1, 'ba')), ((1, 'ab'), (1, 'bb')), + ((1, 'ba'), (1, 'aa')), ((1, 'ba'), (1, 'ab')), + ((1, 'bb'), (1, 'ba')), ((1, 'bb'), (1, 'bb'))] sage: Q.strongly_connected_components_digraph().num_verts() 2 sage: V = Q.strongly_connected_component_containing_vertex((0, 'aa')) @@ -18709,7 +18720,10 @@ def lexicographic_product(self, other): sage: H = Graph([('a', 'b')]) sage: T = G.lexicographic_product(H) sage: T.edges(sort=True, labels=None) - [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] + [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), + ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), ((1, 'a'), (1, 'b')), + ((1, 'a'), (2, 'a')), ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), + ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] sage: T.is_isomorphic(H.lexicographic_product(G)) False @@ -18719,7 +18733,10 @@ def lexicographic_product(self, other): sage: J = DiGraph([('a', 'b')]) sage: T = I.lexicographic_product(J) sage: T.edges(sort=True, labels=None) - [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] + [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), + ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), ((1, 'a'), (1, 'b')), + ((1, 'a'), (2, 'a')), ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), + ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] sage: T.is_isomorphic(J.lexicographic_product(I)) False """ @@ -18861,7 +18878,11 @@ def disjunctive_product(self, other): sage: H = Graph([('a', 'b')]) sage: T = G.disjunctive_product(H) sage: T.edges(sort=True, labels=None) - [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), ((0, 'a'), (2, 'b')), ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), ((0, 'b'), (2, 'a')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] + [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), + ((0, 'a'), (2, 'b')), ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), + ((0, 'b'), (2, 'a')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), + ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), ((1, 'b'), (2, 'b')), + ((2, 'a'), (2, 'b'))] sage: T.is_isomorphic(H.disjunctive_product(G)) True @@ -18871,7 +18892,11 @@ def disjunctive_product(self, other): sage: J = DiGraph([('a', 'b')]) sage: T = I.disjunctive_product(J) sage: T.edges(sort=True, labels=None) - [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), ((0, 'a'), (2, 'b')), ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), ((1, 'a'), (0, 'b')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), ((1, 'b'), (2, 'b')), ((2, 'a'), (0, 'b')), ((2, 'a'), (1, 'b')), ((2, 'a'), (2, 'b'))] + [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), + ((0, 'a'), (2, 'b')), ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), + ((1, 'a'), (0, 'b')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), + ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), ((1, 'b'), (2, 'b')), + ((2, 'a'), (0, 'b')), ((2, 'a'), (1, 'b')), ((2, 'a'), (2, 'b'))] sage: T.is_isomorphic(J.disjunctive_product(I)) True """ @@ -19047,8 +19072,7 @@ def is_transitively_reduced(self): return self.is_forest() - - ### Visualization + # Visualization def _color_by_label(self, format='hex', as_function=False, default_color="black"): """ @@ -19149,7 +19173,8 @@ def _color_by_label(self, format='hex', as_function=False, default_color="black" color_of_label = dict(zip(labels, colors)) color_of_label = color_of_label.__getitem__ elif isinstance(format, dict): - color_of_label = lambda label: format.get(label, default_color) + def color_of_label(label): + return format.get(label, default_color) else: # This assumes that ``format`` is already a function color_of_label = format @@ -19218,7 +19243,6 @@ def set_latex_options(self, **kwds): opts = self.latex_options() opts.set_options(**kwds) - def layout(self, layout=None, pos=None, dim=2, save_pos=False, **options): """ Return a layout for the vertices of this graph. @@ -19341,10 +19365,10 @@ def layout(self, layout=None, pos=None, dim=2, save_pos=False, **options): if pos is None: layout = 'default' - if hasattr(self, "layout_%s"%layout): - pos = getattr(self, "layout_%s"%layout)(dim=dim, **options) + if hasattr(self, "layout_%s" % layout): + pos = getattr(self, "layout_%s" % layout)(dim=dim, **options) elif layout is not None: - raise ValueError("unknown layout algorithm: %s"%layout) + raise ValueError("unknown layout algorithm: %s" % layout) if len(pos) < self.order(): pos = self.layout_extend_randomly(pos, dim=dim) @@ -19353,7 +19377,6 @@ def layout(self, layout=None, pos=None, dim=2, save_pos=False, **options): self.set_pos(pos, dim=dim) return pos - def layout_spring(self, by_component=True, **options): """ Return a spring layout for this graph. @@ -19490,11 +19513,11 @@ def layout_extend_randomly(self, pos, dim=2): sage: (xmin, ymin) == (0, 0) and (xmax, ymax) == (1, 1) True """ - assert dim == 2 # 3d not yet implemented + assert dim == 2 # 3d not yet implemented from sage.misc.randstate import current_randstate random = current_randstate().python_random().random - xmin, xmax,ymin, ymax = self._layout_bounding_box(pos) + xmin, xmax, ymin, ymax = self._layout_bounding_box(pos) dx = xmax - xmin dy = ymax - ymin @@ -19505,7 +19528,6 @@ def layout_extend_randomly(self, pos, dim=2): pos[v] = [xmin + dx * random(), ymin + dy * random()] return pos - def layout_circular(self, dim=2, center=(0, 0), radius=1, shift=0, angle=0, **options): r""" Return a circular layout for this graph @@ -19947,9 +19969,9 @@ def _layout_bounding_box(self, pos): ys = [pos[v][1] for v in pos] if not xs: xmin = -1 - xmax = 1 + xmax = 1 ymin = -1 - ymax = 1 + ymax = 1 else: xmin = min(xs) xmax = max(xs) @@ -20047,7 +20069,7 @@ def _circle_embedding(self, vertices, center=(0, 0), radius=1, shift=0, angle=0, pos = self._pos = {} from math import sin, cos, pi - for i,v in enumerate(vertices): + for i, v in enumerate(vertices): i += shift # We round cos and sin to avoid results like 1.2246467991473532e-16 # when asking for sin(pi) @@ -20365,7 +20387,11 @@ def plot(self, **options): :: - sage: D = DiGraph( { 0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], 17: [18], 18: [19], 19: []} , sparse=True) + sage: D = DiGraph({0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], + ....: 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], + ....: 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], + ....: 12: [16, 13], 13: [14], 14: [15], 15: [16], + ....: 16: [17], 17: [18], 18: [19]}, sparse=True) sage: for u,v,l in D.edges(sort=False): ....: D.set_edge_label(u, v, '(' + str(u) + ',' + str(v) + ')') sage: D.plot(edge_labels=True, layout='circular').show() @@ -20559,7 +20585,7 @@ def show(self, method="matplotlib", **kwds): return from sage.misc.viewer import browser import os - os.system('%s %s 2>/dev/null 1>/dev/null &'% (browser(), filename)) + os.system('%s %s 2>/dev/null 1>/dev/null &' % (browser(), filename)) return from .graph_plot import graphplot_options From c69daa70a888bd42b9a46bec4782077005fce70b Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 13 Aug 2022 19:37:33 +0200 Subject: [PATCH 205/742] trac #34358: a few more --- src/sage/graphs/generic_graph.py | 34 +++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 3e212cb5123..bb2af596b7a 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -17116,17 +17116,33 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: G.plot(edge_labels=True).show() # long time sage: dist, pred = G.shortest_path_all_pairs(by_weight = True) sage: dist - {0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 2}, 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}, 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 3}, 3: {0: 3, 1: 2, 2: 1, 3: 0, 4: 2}, 4: {0: 2, 1: 3, 2: 3, 3: 2, 4: 0}} + {0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 2}, + 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}, + 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 3}, + 3: {0: 3, 1: 2, 2: 1, 3: 0, 4: 2}, + 4: {0: 2, 1: 3, 2: 3, 3: 2, 4: 0}} sage: pred - {0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0}, 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0}, 2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3}, 3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3}, 4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}} + {0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0}, + 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0}, + 2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3}, + 3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3}, + 4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}} sage: pred[0] {0: None, 1: 0, 2: 1, 3: 2, 4: 0} sage: G = Graph( { 0: {1: {'weight':1}}, 1: {2: {'weight':1}}, 2: {3: {'weight':1}}, 3: {4: {'weight':2}}, 4: {0: {'weight':2}} }, sparse=True) sage: dist, pred = G.shortest_path_all_pairs(weight_function = lambda e:e[2]['weight']) sage: dist - {0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 2}, 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}, 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 3}, 3: {0: 3, 1: 2, 2: 1, 3: 0, 4: 2}, 4: {0: 2, 1: 3, 2: 3, 3: 2, 4: 0}} + {0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 2}, + 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}, + 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 3}, + 3: {0: 3, 1: 2, 2: 1, 3: 0, 4: 2}, + 4: {0: 2, 1: 3, 2: 3, 3: 2, 4: 0}} sage: pred - {0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0}, 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0}, 2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3}, 3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3}, 4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}} + {0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0}, + 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0}, + 2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3}, + 3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3}, + 4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}} So for example the shortest weighted path from `0` to `3` is obtained as follows. The predecessor of `3` is ``pred[0][3] == 2``, the predecessor @@ -17347,8 +17363,8 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, dist = {int_to_vertex[i]: {int_to_vertex[j]: dd[i, j] for j in range(n) if dd[i, j] != +Infinity} for i in range(n)} pred = {int_to_vertex[i]: {int_to_vertex[j]: (int_to_vertex[pp[i, j]] if i != j else None) - for j in range(n) if (i == j or pp[i, j] != -9999)} - for i in range(n)} + for j in range(n) if (i == j or pp[i, j] != -9999)} + for i in range(n)} return dist, pred elif algorithm == "Johnson_Boost": @@ -17367,9 +17383,9 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, dist = dict() pred = dict() for u in self: - paths=self.shortest_paths(u, by_weight=by_weight, - algorithm=algorithm, - weight_function=weight_function) + paths = self.shortest_paths(u, by_weight=by_weight, + algorithm=algorithm, + weight_function=weight_function) dist[u] = {v: self._path_length(p, by_weight=by_weight, weight_function=weight_function) for v, p in paths.items()} From a90608f7ac6cd3a63ada3ae939ec4b316a902639 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 14 Aug 2022 13:40:32 -0700 Subject: [PATCH 206/742] build/bin/write-dockerfile.sh: Invoke sage-package directly, do not go through ./sage --- build/bin/write-dockerfile.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/bin/write-dockerfile.sh b/build/bin/write-dockerfile.sh index e9ec84dc925..27b7d38b7f8 100755 --- a/build/bin/write-dockerfile.sh +++ b/build/bin/write-dockerfile.sh @@ -15,7 +15,7 @@ SAGE_ROOT=. export PATH="$SAGE_ROOT"/build/bin:$PATH SYSTEM_PACKAGES=$EXTRA_SYSTEM_PACKAGES CONFIGURE_ARGS="--enable-option-checking " -for PKG_BASE in $($SAGE_ROOT/sage -package list --has-file=distros/$SYSTEM.txt $SAGE_PACKAGE_LIST_ARGS) $EXTRA_SAGE_PACKAGES; do +for PKG_BASE in $(sage-package list --has-file=distros/$SYSTEM.txt $SAGE_PACKAGE_LIST_ARGS) $EXTRA_SAGE_PACKAGES; do PKG_SCRIPTS="$SAGE_ROOT"/build/pkgs/$PKG_BASE if [ -d $PKG_SCRIPTS ]; then SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/distros/$SYSTEM.txt From 89fc91c0308c35f43ce4d5d79542b8f1d8547945 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 17 Aug 2022 17:13:22 +0900 Subject: [PATCH 207/742] Adding hooks for (graded) free resolutions and handling cases when given a free module. --- src/sage/homology/free_resolution.py | 89 +++++++++++++++-- src/sage/homology/graded_resolution.py | 95 +++++++++++++++++-- src/sage/modules/free_module.py | 47 +++++++++ src/sage/rings/ideal.py | 42 +++++++- src/sage/rings/polynomial/ideal.py | 1 + .../polynomial/multi_polynomial_ideal.py | 56 ++++++++++- 6 files changed, 311 insertions(+), 19 deletions(-) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 4468585c4f6..e3a8eab1344 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -69,10 +69,12 @@ from sage.libs.singular.singular import si2sa_resolution from sage.libs.singular.function import singular_function from sage.misc.lazy_attribute import lazy_attribute -from sage.matrix.matrix_mpolynomial_dense import Matrix_mpolynomial_dense +from sage.structure.element import Matrix +from sage.categories.principal_ideal_domains import PrincipalIdealDomains +from sage.categories.integral_domains import IntegralDomains from sage.modules.free_module_element import vector from sage.modules.free_module import FreeModule -from sage.modules.free_module import Module_free_ambient +from sage.modules.free_module import Module_free_ambient, FreeModule_generic from sage.rings.ideal import Ideal_generic from sage.structure.sage_object import SageObject @@ -513,15 +515,60 @@ def __init__(self, module, name='S', algorithm='heuristic'): sage: M = m.image() sage: r = FreeResolution(M, name='S') sage: TestSuite(r).run(skip=['_test_pickling']) + + sage: R. = QQ[] + sage: I = R.ideal([x^2, y^3]) + sage: Q = R.quo(I) + sage: Q.is_integral_domain() + False + sage: xb, yb = Q.gens() + sage: FreeResolution(Q.ideal([xb])) # has torsion + Traceback (most recent call last): + ... + NotImplementedError: the ring must be a polynomial ring that can be constructed in Singular + + An overdetermined system over a PID:: + + sage: M = matrix([[x^2, 2], + ....: [3*x^2, 5], + ....: [5*x^2, 4]]) + sage: res = FreeResolution(M) + sage: res + S^2 <-- S^2 <-- 0 + sage: res._m() + [ x^2 3*x^2 5*x^2] + [ 2 5 4] + sage: res._maps + [ + [x^2 0] + [ 0 1] + ] """ + # The module might still be free even if _is_free_module is False. + # This is just to handle the cases when we trivially know it is. + self._is_free_module = False if isinstance(module, Ideal_generic): S = module.ring() + if len(module.gens()) == 1 and S in IntegralDomains(): + self._is_free_module = True elif isinstance(module, Module_free_ambient): S = module.base_ring() - elif isinstance(module, Matrix_mpolynomial_dense): + self._is_free_module = (S in PrincipalIdealDomains() + or isinstance(module, FreeModule_generic)) + elif isinstance(module, Matrix): S = module.base_ring() + if S in PrincipalIdealDomains(): + self._is_free_module = True + module = module.echelon_form() + if module.nrows() > module.rank(): + module = module.submatrix(nrows=module.rank()) else: - raise TypeError('no ideal, module, or matrix') + raise TypeError('no module, matrix, or ideal') + + if not self._is_free_module: + from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if not isinstance(S, MPolynomialRing_libsingular): + raise NotImplementedError("the ring must be a polynomial ring that can be constructed in Singular") self._module = module self._algorithm = algorithm @@ -554,7 +601,7 @@ def _m(self): return self._module if isinstance(self._module, Module_free_ambient): return self._module.matrix().transpose() - if isinstance(self._module, Matrix_mpolynomial_dense): + if isinstance(self._module, Matrix): return self._module.transpose() @lazy_attribute @@ -574,7 +621,37 @@ def _maps(self): [ z -y] [z^2 - y*w y*z - x*w y^2 - x*z], [-w z] ] + + sage: R. = QQ[] + sage: M = R^3 + sage: v = M([x^2, 2*x^2, 3*x^2]) + sage: w = M([0, x, 2*x]) + sage: S = M.submodule([v, w]) + sage: S + Free module of degree 3 and rank 2 over Univariate Polynomial Ring in x over Rational Field + Echelon basis matrix: + [ x^2 2*x^2 3*x^2] + [ 0 x 2*x] + sage: res = S.free_resolution() + sage: res + S^3 <-- S^2 <-- 0 + sage: ascii_art(res.chain_complex()) + [ x^2 0] + [2*x^2 x] + [3*x^2 2*x] + 0 <-- C_0 <-------------- C_1 <-- 0 + sage: res._maps + [ + [ x^2 0] + [2*x^2 x] + [3*x^2 2*x] + ] """ + if self._is_free_module: + if isinstance(self._module, Ideal_generic): + return matrix([[self._module.gen()]]) + return [self._m()] + # This ensures the first component of the Singular resolution to be a # module, like the later components. This is important when the # components are converted to Sage modules. @@ -632,7 +709,7 @@ def _initial_differential(self): S = ideal.base_ring() M = ideal.ambient_module() N = ideal - elif isinstance(ideal, Matrix_mpolynomial_dense): + elif isinstance(ideal, Matrix): S = ideal.base_ring() N = ideal.row_space() M = N.ambient_module() diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index a73aa7f5c9f..cb5f0b82421 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -76,7 +76,7 @@ from sage.libs.singular.singular import si2sa_resolution_graded from sage.libs.singular.function import singular_function from sage.misc.lazy_attribute import lazy_attribute -from sage.matrix.matrix_mpolynomial_dense import Matrix_mpolynomial_dense +from sage.structure.element import Matrix from sage.modules.free_module_element import vector from sage.modules.free_module import Module_free_ambient from sage.rings.integer_ring import ZZ @@ -86,7 +86,7 @@ from sage.homology.free_resolution import FreeResolution class GradedFreeResolution(FreeResolution): - """ + r""" Graded free resolutions of ideals of multivariate polynomial rings. INPUT: @@ -166,23 +166,29 @@ def __init__(self, module, degrees=None, shifts=None, name='S', algorithm='heuri sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = GradedFreeResolution(I) sage: TestSuite(r).run(skip=['_test_pickling']) + + An overdetermined system over a PID:: + + sage: M = matrix([[x^2, 2], + ....: [3*x^2, 5], + ....: [5*x^2, 4]]) + sage: res = GradedFreeResolution(M) + sage: res + S(0)⊕S(0) <-- S(-2)⊕S(0) <-- 0 + sage: res._res_shifts + [[2, 0]] """ super().__init__(module, name=name, algorithm=algorithm) nvars = self._base_ring.ngens() - if isinstance(self._module, Ideal_generic): - rank = 1 - elif isinstance(self._module, Module_free_ambient): - rank = self._m().nrows() - elif isinstance(self._module, Matrix_mpolynomial_dense): - rank = self._module.ncols() - if degrees is None: degrees = nvars * (1,) # standard grading if len(degrees) != nvars: raise ValueError('the length of degrees does not match the number of generators') + if self._is_free_module and len(degrees) > 1 and any(d != 1 for d in degrees): + raise NotImplementedError("only the natural grading supported when more than one generator") if degrees[0] in ZZ: zero_deg = 0 @@ -193,6 +199,13 @@ def __init__(self, module, degrees=None, shifts=None, name='S', algorithm='heuri multigrade = True if shifts is None: + if isinstance(self._module, Ideal_generic): + rank = 1 + elif isinstance(self._module, Module_free_ambient): + rank = self._m().nrows() + elif isinstance(self._module, Matrix): + rank = self._module.ncols() + shifts = rank * [zero_deg] self._shifts = shifts @@ -221,7 +234,71 @@ def _maps(self): ] sage: r._res_shifts [[2, 2, 2], [3, 3]] + + sage: R. = QQ[] + sage: M = matrix([[x^3, 3*x^3, 5*x^3], + ....: [0, x, 2*x]]) + sage: res = GradedFreeResolution(M) + sage: res + S(0)⊕S(0)⊕S(0) <-- S(-3)⊕S(-1) <-- 0 + sage: res._maps + [ + [ x^3 0] + [3*x^3 x] + [5*x^3 2*x] + ] + sage: res._res_shifts + [[3, 1]] + + sage: M = matrix([[x^2, 2], + ....: [3*x^2, 5], + ....: [5*x^2, 4]]) + sage: res = GradedFreeResolution(M) + sage: res + S(0)⊕S(0) <-- S(-2)⊕S(0) <-- 0 + sage: res._res_shifts + [[2, 0]] + + sage: I = R.ideal([x^4]) + sage: res = I.graded_free_resolution(shifts=[1], degrees=[2]) + sage: res + S(-1) <-- S(-9) <-- 0 + sage: res._maps + [[x^4]] + sage: res._res_shifts + [[9]] """ + if self._is_free_module: + + def compute_degree(base, i): + """ + Compute the degree by ``base * deg + shift``, + where ``*`` is entry-wise multiplication, ``deg`` and + ``shift`` are the ``i``-th index. + """ + deg = self._degrees[0] + shift = self._shifts[i] + if self._multigrade: + return vector([val * d + s for val, d, s in zip(base, deg, shift)]) + return base * deg + shift + + if isinstance(self._module, Ideal_generic): + from sage.matrix.constructor import matrix + val = self._module.gen(0) + self._res_shifts = [[compute_degree(val.degree(), 0)]] + return [matrix([[val]])] + + M = self._m() + def find_deg(i): + for j in range(M.nrows()): + ret = M[j,i].degree() + if ret != -1: + return ret + raise NotImplementedError("a generator maps to 0") + self._res_shifts = [[compute_degree(find_deg(i), i) + for i in range(M.ncols())]] + return [M] + #cdef int i, j, k, ncols, nrows #cdef list res_shifts, prev_shifts, new_shifts diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 9946a588c85..b3bd30bb78f 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -1759,6 +1759,53 @@ def __truediv__(self, sub): """ return self.quotient(sub, check=True) + def free_resolution(self, *args, **kwds): + r""" + Return a free resolution of ``self``. + + For input options, see + :class:`~sage.homology.free_resolution.FreeResolution`. + + EXAMPLES:: + + sage: S. = PolynomialRing(QQ) + sage: M = S**2 + sage: N = M.submodule([vector([x - y, z]), vector([y * z, x * z])]) + sage: res = N.free_resolution() + sage: res + S^2 <-- S^2 <-- 0 + sage: ascii_art(res.chain_complex()) + [x - y y*z] + [ z x*z] + 0 <-- C_0 <-------------- C_1 <-- 0 + """ + from sage.homology.free_resolution import FreeResolution + return FreeResolution(self, *args, **kwds) + + def graded_free_resolution(self, *args, **kwds): + r""" + Return a graded free resolution of ``self``. + + For input options, see + :class:`~sage.homology.graded_resolution.GradedFreeResolution`. + + EXAMPLES:: + + sage: S. = PolynomialRing(QQ) + sage: M = S**2 + sage: N = M.submodule([vector([x - y, z]), vector([y * z, x * z])]) + sage: N.graded_free_resolution(shifts=[1, -1]) + S(-1)⊕S(--1) <-- S(-2)⊕S(-3) <-- 0 + sage: N.graded_free_resolution(shifts=[2, 3]) + S(-2)⊕S(-3) <-- S(-3)⊕S(-4) <-- 0 + + sage: N = M.submodule([vector([x^3 - y^6, z^2]), vector([y * z, x])]) + sage: N.graded_free_resolution(degrees=[2, 1, 3], shifts=[2, 3]) + S(-2)⊕S(-3) <-- S(-6)⊕S(-8) <-- 0 + """ + from sage.homology.graded_resolution import GradedFreeResolution + return GradedFreeResolution(self, *args, **kwds) + class FreeModule_generic(Module_free_ambient): """ diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 8bb1de564f3..85203abed43 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -1203,6 +1203,38 @@ def _macaulay2_init_(self, macaulay2=None): gens = ['0'] return macaulay2.ideal(gens) + def free_resolution(self, *args, **kwds): + r""" + Return a free resolution of ``self``. + + For input options, see + :class:`~sage.homology.free_resolution.FreeResolution`. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQ) + sage: I = R.ideal([x^4 + 3*x^2 + 2]) + sage: I.free_resolution() + """ + from sage.homology.free_resolution import FreeResolution + return FreeResolution(self, *args, **kwds) + + def graded_free_resolution(self, *args, **kwds): + r""" + Return a graded free resolution of ``self``. + + For input options, see + :class:`~sage.homology.graded_resolution.GradedFreeResolution`. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQ) + sage: I = R.ideal([x^3]) + sage: I.graded_free_resolution() + """ + from sage.homology.graded_resolution import GradedFreeResolution + return GradedFreeResolution(self, *args, **kwds) + class Ideal_principal(Ideal_generic): """ @@ -1257,10 +1289,11 @@ def is_principal(self): """ return True - def gen(self): + def gen(self, i=0): r""" - Returns the generator of the principal ideal. The generators are - elements of the ring containing the ideal. + Return the generator of the principal ideal. + + The generator is an element of the ring containing the ideal. EXAMPLES: @@ -1288,6 +1321,8 @@ def gen(self): sage: b.base_ring() Rational Field """ + if i: + raise ValueError(f"i (={i}) must be 0") return self.gens()[0] def __contains__(self, x): @@ -1816,3 +1851,4 @@ def FieldIdeal(R): raise TypeError("Cannot construct field ideal for R.base_ring().order()==infinity") return R.ideal([x**q - x for x in R.gens() ]) + diff --git a/src/sage/rings/polynomial/ideal.py b/src/sage/rings/polynomial/ideal.py index 857718c9a10..b768ed1a96b 100644 --- a/src/sage/rings/polynomial/ideal.py +++ b/src/sage/rings/polynomial/ideal.py @@ -84,3 +84,4 @@ 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) + diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 10c0db501af..46feca52b20 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -1775,6 +1775,60 @@ def syzygy_module(self): S = syz(self) return matrix(self.ring(), S) + @require_field + def free_resolution(self, *args, **kwds): + r""" + Return a free resolution of ``self``. + + For input options, see + :class:`~sage.homology.free_resolution.FreeResolution`. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQ) + sage: f = 2*x^2 + y + sage: g = y + sage: h = 2*f + g + sage: I = R.ideal([f,g,h]) + sage: res = I.free_resolution() + sage: res + S^1 <-- S^2 <-- S^1 <-- 0 + sage: ascii_art(res.chain_complex()) + [-x^2] + [ y x^2] [ y] + 0 <-- C_0 <---------- C_1 <------- C_2 <-- 0 + """ + from sage.homology.free_resolution import FreeResolution + return FreeResolution(self, *args, **kwds) + + @require_field + def graded_free_resolution(self, *args, **kwds): + r""" + Return a graded free resolution of ``self``. + + For input options, see + :class:`~sage.homology.graded_resolution.GradedFreeResolution`. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQ) + sage: f = 2*x^2 + y^2 + sage: g = y^2 + sage: h = 2*f + g + sage: I = R.ideal([f,g,h]) + sage: I.graded_free_resolution(shifts=[1]) + S(-1) <-- S(-3)⊕S(-3) <-- S(-5) <-- 0 + + sage: f = 2*x^2 + y + sage: g = y + sage: h = 2*f + g + sage: I = R.ideal([f,g,h]) + sage: I.graded_free_resolution(degrees=[1,2]) + S(0) <-- S(-2)⊕S(-2) <-- S(-4) <-- 0 + """ + from sage.homology.graded_resolution import GradedFreeResolution + return GradedFreeResolution(self, *args, **kwds) + @handle_AA_and_QQbar @singular_gb_standard_options @libsingular_gb_standard_options @@ -5224,7 +5278,6 @@ class MPolynomialIdeal_quotient(MPolynomialIdeal): Ideal (w^2 + x + z - 1) of Quotient of Multivariate Polynomial Ring in x, y, z, w over Rational Field by the ideal (x*y - z^2, y^2 - w^2) """ - def reduce(self, f): r""" Reduce an element modulo a Gröbner basis for this ideal. @@ -5330,3 +5383,4 @@ def __richcmp__(self, other, op): return not (contained and contains) else: # remaining case < return contained and not contains + From dfb33843f5cbfb63a73d20e2b8b9197d3a273726 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 17 Aug 2022 17:21:30 +0900 Subject: [PATCH 208/742] Rewriting the _repr_module() of graded resolutions to negate the grading. --- src/sage/homology/graded_resolution.py | 34 ++++++++++++-------------- src/sage/modules/free_module.py | 2 +- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index cb5f0b82421..4a38a347e5d 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -53,7 +53,7 @@ sage: C = P3.subscheme(I) # twisted cubic curve sage: r = GradedFreeResolution(I, degrees=[(1,0), (1,1), (1,2), (1,3)]) sage: r - S(0) <-- S(-(2, 4))⊕S(-(2, 3))⊕S(-(2, 2)) <-- S(-(3, 5))⊕S(-(3, 4)) <-- 0 + S((0, 0)) <-- S((-2, -4))⊕S((-2, -3))⊕S((-2, -2)) <-- S((-3, -5))⊕S((-3, -4)) <-- 0 sage: r.K_polynomial(names='s,t') s^3*t^5 + s^3*t^4 - s^2*t^4 - s^2*t^3 - s^2*t^2 + 1 @@ -368,28 +368,24 @@ def _repr_module(self, i): 'S(-3)⊕S(-3)' sage: r._repr_module(3) '0' + + sage: r = GradedFreeResolution(I, shifts=[-1]) + sage: r._repr_module(0) + 'S(1)' """ self._maps # to set _res_shifts if i > len(self): - m = '0' + return '0' + + if i == 0: + shifts = self._shifts else: - if i == 0: - shifts = self._shifts - else: - shifts = self._res_shifts[i - 1] - - if len(shifts) > 0: - for j in range(len(shifts)): - shift = shifts[j] - if j == 0: - m = f'{self._name}' + \ - (f'(-{shift})' if shift != self._zero_deg else '(0)') - else: - m += f'\u2295{self._name}' + \ - (f'(-{shift})' if shift != self._zero_deg else '(0)') - else: - m = '0' - return m + shifts = self._res_shifts[i - 1] + if not shifts: + return '0' + + return '\u2295'.join(f'{self._name}' + '({})'.format(-sh) + for sh in shifts) def shifts(self, i): """ diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index b3bd30bb78f..1acf13bbb9e 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -1795,7 +1795,7 @@ def graded_free_resolution(self, *args, **kwds): sage: M = S**2 sage: N = M.submodule([vector([x - y, z]), vector([y * z, x * z])]) sage: N.graded_free_resolution(shifts=[1, -1]) - S(-1)⊕S(--1) <-- S(-2)⊕S(-3) <-- 0 + S(-1)⊕S(1) <-- S(-2)⊕S(-3) <-- 0 sage: N.graded_free_resolution(shifts=[2, 3]) S(-2)⊕S(-3) <-- S(-3)⊕S(-4) <-- 0 From d02630a545d3b0ff037289f1d938cf302563ce3c Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Thu, 18 Aug 2022 13:35:29 +0100 Subject: [PATCH 209/742] Fixed formatting errors. --- .../schemes/riemann_surfaces/riemann_surface.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index edbb2aeb720..0e6620d11fc 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -17,8 +17,8 @@ period lattice numerically, by determining integer (near) solutions to the relevant approximate linear equations. -One can also calculate the Abel-Jacobi map on the Riemann surface, and there -is basic functionality to interface with divisors of curves to facilitate this. +One can also calculate the Abel-Jacobi map on the Riemann surface, and there +is basic functionality to interface with divisors of curves to facilitate this. AUTHORS: @@ -138,6 +138,7 @@ from sage.schemes.curves.constructor import Curve import sage.libs.mpmath.all as mpall + def voronoi_ghost(cpoints, n=6, CC=CDF): r""" Convert a set of complex points to a list of real tuples `(x,y)`, and @@ -1837,8 +1838,9 @@ def _bounding_data(self, differentials, exact=False): A tuple ``(Rzg, [(g, dgdz, F, a0_info), ...])`` where each element of the list corresponds to an element of ``differentials``. Introducing the - notation ``RBzg = PolynomialRing(self._R, ['z','g'])`` and + notation ``RBzg = PolynomialRing(self._R, ['z','g'])`` and ``CCzg = PolynomialRing(self._CC, ['z','g'])``, we have that: + - ``Rzg`` is either ``RBzg`` or ``CCzg`` depending on the value of ``exact``, - ``g`` is the full rational function in ``self._R.fraction_field()`` @@ -2834,6 +2836,7 @@ def _integrate_differentials_iteratively(self, upstairs_edge, cutoff_individuall mp_list = [CCzg(mp) for mp in mp_list] J = 1/z_end endscale = -z_end**(-2) + def initialise(z, i): DF = ComplexField(2*self._prec) DFw = PolynomialRing(DF,'wbar') @@ -2851,6 +2854,7 @@ def initialise(z, i): CCzg = mp_list[0].parent() J = z_end-z_start endscale = 1 + def initialise(z, i): newg = self.cohomology_basis()[i](z_start, w_start)/self._dfdw(z_start, w_start) err = mp_list[i](z, newg).abs() @@ -2892,11 +2896,13 @@ def initialise(z, i): cutoff_individually = bool(not all(ai<=0 for ai in aes) and cutoff_individually) if raise_errors: - n_steps = self._prec-1 + n_steps = self._prec-1 + def error_handle(out): raise ConvergenceError("Newton iteration fails to converge") else: n_steps = 15 + def error_handle(out): return out @@ -3583,6 +3589,7 @@ def divisor_to_divisor_list(self, divisor): raise ValueError("Numerical instability, list of wrong degree") return dl + def integer_matrix_relations(M1, M2, b=None, r=None): r""" Determine integer relations between complex matrices. From b1db4f146caea0add146573237468ee6a88bb7d5 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 20 Aug 2022 11:16:49 +0200 Subject: [PATCH 210/742] trac #34358: extra care --- src/sage/graphs/generic_graph.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index d97b154d37c..0ec81a48b9b 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -17360,8 +17360,9 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, return_predecessors=True, unweighted=not by_weight) # and format the result - dist = {int_to_vertex[i]: {int_to_vertex[j]: dd[i, j] for j in range(n) if dd[i, j] != +Infinity} - for i in range(n)} + dist = {int_to_vertex[i]: {int_to_vertex[j]: dd[i, j] + for j in range(n) if dd[i, j] != +Infinity} + for i in range(n)} pred = {int_to_vertex[i]: {int_to_vertex[j]: (int_to_vertex[pp[i, j]] if i != j else None) for j in range(n) if (i == j or pp[i, j] != -9999)} for i in range(n)} From 773d5a1771854bbe9e57ffcd954bb9459f1a4a52 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 20 Aug 2022 12:05:06 +0200 Subject: [PATCH 211/742] trac #34392: clean src/sage/graphs/generic_graph.py - part 5 --- src/sage/graphs/generic_graph.py | 181 +++++++++++++++++++++---------- 1 file changed, 125 insertions(+), 56 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 0ec81a48b9b..076de6c1a7e 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -12000,7 +12000,11 @@ def set_edge_label(self, u, v, l): EXAMPLES:: - sage: SD = DiGraph({1:[18,2], 2:[5,3], 3:[4,6], 4:[7,2], 5:[4], 6:[13,12], 7:[18,8,10], 8:[6,9,10], 9:[6], 10:[11,13], 11:[12], 12:[13], 13:[17,14], 14:[16,15], 15:[2], 16:[13], 17:[15,13], 18:[13]}, sparse=True) + sage: d = {1: [18, 2], 2: [5, 3], 3: [4, 6], 4: [7, 2], 5: [4], + ....: 6: [13, 12], 7: [18, 8, 10], 8: [6, 9, 10], 9: [6], + ....: 10: [11, 13], 11: [12], 12: [13], 13: [17, 14], + ....: 14: [16, 15], 15: [2], 16: [13], 17: [15, 13], 18: [13]} + sage: SD = DiGraph(d, sparse=True) sage: SD.set_edge_label(1, 18, 'discrete') sage: SD.set_edge_label(4, 7, 'discrete') sage: SD.set_edge_label(2, 5, 'h = 0') @@ -12013,7 +12017,11 @@ def set_edge_label(self, u, v, l): sage: SD.set_edge_label(13, 14, 'k = h') sage: SD.set_edge_label(17, 15, 'v_k finite') sage: SD.set_edge_label(14, 15, 'v_k m.c.r.') - sage: posn = {1:[ 3,-3], 2:[0,2], 3:[0, 13], 4:[3,9], 5:[3,3], 6:[16, 13], 7:[6,1], 8:[6,6], 9:[6,11], 10:[9,1], 11:[10,6], 12:[13,6], 13:[16,2], 14:[10,-6], 15:[0,-10], 16:[14,-6], 17:[16,-10], 18:[6,-4]} + sage: posn = {1: [3, -3], 2: [0, 2], 3: [0, 13], 4: [3, 9], + ....: 5: [3, 3], 6: [16, 13], 7: [6, 1], 8: [6, 6], + ....: 9: [6, 11], 10: [9, 1], 11: [10, 6], 12: [13, 6], + ....: 13: [16, 2], 14: [10, -6], 15: [0, -10], 16: [14, -6], + ....: 17: [16, -10], 18: [6, -4]} sage: SD.plot(pos=posn, vertex_size=400, vertex_colors={'#FFFFFF':list(range(1,19))}, edge_labels=True).show() # long time :: @@ -12066,7 +12074,8 @@ def set_edge_label(self, u, v, l): """ if self.allows_multiple_edges(): if len(self.edge_label(u, v)) > 1: - raise RuntimeError("cannot set edge label, since there are multiple edges from %s to %s"%(u,v)) + raise RuntimeError("cannot set edge label, since there are " + "multiple edges from %s to %s" % (u,v)) self._backend.set_edge_label(u, v, l, self._directed) def has_edge(self, u, v=None, label=None): @@ -12102,7 +12111,8 @@ def has_edge(self, u, v=None, label=None): label = None return self._backend.has_edge(u, v, label) - def edges(self, vertices=None, labels=True, sort=None, key=None, ignore_direction=False, sort_vertices=True): + def edges(self, vertices=None, labels=True, sort=None, key=None, + ignore_direction=False, sort_vertices=True): r""" Return a :class:`~EdgesView` of edges. @@ -12162,20 +12172,53 @@ def edges(self, vertices=None, labels=True, sort=None, key=None, ignore_directio EXAMPLES:: sage: graphs.DodecahedralGraph().edges(sort=True) - [(0, 1, None), (0, 10, None), (0, 19, None), (1, 2, None), (1, 8, None), (2, 3, None), (2, 6, None), (3, 4, None), (3, 19, None), (4, 5, None), (4, 17, None), (5, 6, None), (5, 15, None), (6, 7, None), (7, 8, None), (7, 14, None), (8, 9, None), (9, 10, None), (9, 13, None), (10, 11, None), (11, 12, None), (11, 18, None), (12, 13, None), (12, 16, None), (13, 14, None), (14, 15, None), (15, 16, None), (16, 17, None), (17, 18, None), (18, 19, None)] + [(0, 1, None), (0, 10, None), (0, 19, None), (1, 2, None), + (1, 8, None), (2, 3, None), (2, 6, None), (3, 4, None), + (3, 19, None), (4, 5, None), (4, 17, None), (5, 6, None), + (5, 15, None), (6, 7, None), (7, 8, None), (7, 14, None), + (8, 9, None), (9, 10, None), (9, 13, None), (10, 11, None), + (11, 12, None), (11, 18, None), (12, 13, None), (12, 16, None), + (13, 14, None), (14, 15, None), (15, 16, None), (16, 17, None), + (17, 18, None), (18, 19, None)] :: sage: graphs.DodecahedralGraph().edges(sort=True, labels=False) - [(0, 1), (0, 10), (0, 19), (1, 2), (1, 8), (2, 3), (2, 6), (3, 4), (3, 19), (4, 5), (4, 17), (5, 6), (5, 15), (6, 7), (7, 8), (7, 14), (8, 9), (9, 10), (9, 13), (10, 11), (11, 12), (11, 18), (12, 13), (12, 16), (13, 14), (14, 15), (15, 16), (16, 17), (17, 18), (18, 19)] + [(0, 1), (0, 10), (0, 19), (1, 2), (1, 8), (2, 3), (2, 6), (3, 4), + (3, 19), (4, 5), (4, 17), (5, 6), (5, 15), (6, 7), (7, 8), (7, 14), + (8, 9), (9, 10), (9, 13), (10, 11), (11, 12), (11, 18), (12, 13), + (12, 16), (13, 14), (14, 15), (15, 16), (16, 17), (17, 18), + (18, 19)] :: sage: D = graphs.DodecahedralGraph().to_directed() sage: D.edges(sort=True) - [(0, 1, None), (0, 10, None), (0, 19, None), (1, 0, None), (1, 2, None), (1, 8, None), (2, 1, None), (2, 3, None), (2, 6, None), (3, 2, None), (3, 4, None), (3, 19, None), (4, 3, None), (4, 5, None), (4, 17, None), (5, 4, None), (5, 6, None), (5, 15, None), (6, 2, None), (6, 5, None), (6, 7, None), (7, 6, None), (7, 8, None), (7, 14, None), (8, 1, None), (8, 7, None), (8, 9, None), (9, 8, None), (9, 10, None), (9, 13, None), (10, 0, None), (10, 9, None), (10, 11, None), (11, 10, None), (11, 12, None), (11, 18, None), (12, 11, None), (12, 13, None), (12, 16, None), (13, 9, None), (13, 12, None), (13, 14, None), (14, 7, None), (14, 13, None), (14, 15, None), (15, 5, None), (15, 14, None), (15, 16, None), (16, 12, None), (16, 15, None), (16, 17, None), (17, 4, None), (17, 16, None), (17, 18, None), (18, 11, None), (18, 17, None), (18, 19, None), (19, 0, None), (19, 3, None), (19, 18, None)] + [(0, 1, None), (0, 10, None), (0, 19, None), (1, 0, None), + (1, 2, None), (1, 8, None), (2, 1, None), (2, 3, None), + (2, 6, None), (3, 2, None), (3, 4, None), (3, 19, None), + (4, 3, None), (4, 5, None), (4, 17, None), (5, 4, None), + (5, 6, None), (5, 15, None), (6, 2, None), (6, 5, None), + (6, 7, None), (7, 6, None), (7, 8, None), (7, 14, None), + (8, 1, None), (8, 7, None), (8, 9, None), (9, 8, None), + (9, 10, None), (9, 13, None), (10, 0, None), (10, 9, None), + (10, 11, None), (11, 10, None), (11, 12, None), (11, 18, None), + (12, 11, None), (12, 13, None), (12, 16, None), (13, 9, None), + (13, 12, None), (13, 14, None), (14, 7, None), (14, 13, None), + (14, 15, None), (15, 5, None), (15, 14, None), (15, 16, None), + (16, 12, None), (16, 15, None), (16, 17, None), (17, 4, None), + (17, 16, None), (17, 18, None), (18, 11, None), (18, 17, None), + (18, 19, None), (19, 0, None), (19, 3, None), (19, 18, None)] sage: D.edges(sort=True, labels=False) - [(0, 1), (0, 10), (0, 19), (1, 0), (1, 2), (1, 8), (2, 1), (2, 3), (2, 6), (3, 2), (3, 4), (3, 19), (4, 3), (4, 5), (4, 17), (5, 4), (5, 6), (5, 15), (6, 2), (6, 5), (6, 7), (7, 6), (7, 8), (7, 14), (8, 1), (8, 7), (8, 9), (9, 8), (9, 10), (9, 13), (10, 0), (10, 9), (10, 11), (11, 10), (11, 12), (11, 18), (12, 11), (12, 13), (12, 16), (13, 9), (13, 12), (13, 14), (14, 7), (14, 13), (14, 15), (15, 5), (15, 14), (15, 16), (16, 12), (16, 15), (16, 17), (17, 4), (17, 16), (17, 18), (18, 11), (18, 17), (18, 19), (19, 0), (19, 3), (19, 18)] + [(0, 1), (0, 10), (0, 19), (1, 0), (1, 2), (1, 8), (2, 1), (2, 3), + (2, 6), (3, 2), (3, 4), (3, 19), (4, 3), (4, 5), (4, 17), (5, 4), + (5, 6), (5, 15), (6, 2), (6, 5), (6, 7), (7, 6), (7, 8), (7, 14), + (8, 1), (8, 7), (8, 9), (9, 8), (9, 10), (9, 13), (10, 0), (10, 9), + (10, 11), (11, 10), (11, 12), (11, 18), (12, 11), (12, 13), + (12, 16), (13, 9), (13, 12), (13, 14), (14, 7), (14, 13), (14, 15), + (15, 5), (15, 14), (15, 16), (16, 12), (16, 15), (16, 17), (17, 4), + (17, 16), (17, 18), (18, 11), (18, 17), (18, 19), (19, 0), (19, 3), + (19, 18)] The default is to sort the returned list in the default fashion, as in the above examples. This can be overridden by specifying a key @@ -12263,7 +12306,7 @@ def edges(self, vertices=None, labels=True, sort=None, key=None, ignore_directio vertices = [vertices] return EdgesView(self, vertices=vertices, labels=labels, sort=sort, key=key, - ignore_direction=ignore_direction, sort_vertices=sort_vertices) + ignore_direction=ignore_direction, sort_vertices=sort_vertices) def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): r""" @@ -12322,19 +12365,19 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): if vertices2 is not None: vertices2 = set(v for v in vertices2 if v in self) output = [e for e in self.outgoing_edge_iterator(vertices1, labels=labels) - if e[1] in vertices2] + if e[1] in vertices2] else: output = [e for e in self.outgoing_edge_iterator(vertices1, labels=labels) - if e[1] not in vertices1] + if e[1] not in vertices1] else: if vertices2 is not None: vertices2 = set(v for v in vertices2 if v in self) output = [e for e in self.edges(vertices=vertices1, labels=labels, sort=False) - if (e[0] in vertices1 and e[1] in vertices2) or - (e[1] in vertices1 and e[0] in vertices2)] + if (e[0] in vertices1 and e[1] in vertices2) or + (e[1] in vertices1 and e[0] in vertices2)] else: output = [e for e in self.edges(vertices=vertices1, labels=labels, sort=False) - if e[1] not in vertices1 or e[0] not in vertices1] + if e[1] not in vertices1 or e[0] not in vertices1] if sort: output.sort() return output @@ -12509,7 +12552,7 @@ def edge_label(self, u, v): sage: g.edge_label(2, 3) is None True """ - return self._backend.get_edge_label(u,v) + return self._backend.get_edge_label(u, v) def edge_labels(self): """ @@ -12611,7 +12654,7 @@ def remove_loops(self, vertices=None): if self.has_edge(v, v): self.delete_multiedge(v, v) - ### Modifications + # Modifications def clear(self): """ @@ -12646,7 +12689,7 @@ def clear(self): self.name('') self.delete_vertices(self.vertex_iterator()) - ### Degree functions + # Degree functions def degree(self, vertices=None, labels=False): """ @@ -12944,11 +12987,11 @@ def is_regular(self, k=None): return True - ### Substructures + # Substructures def subgraph(self, vertices=None, edges=None, inplace=False, - vertex_property=None, edge_property=None, algorithm=None, - immutable=None): + vertex_property=None, edge_property=None, algorithm=None, + immutable=None): r""" Return the subgraph containing the given vertices and edges. @@ -13227,7 +13270,7 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm """ G = self.__class__(weighted=self._weighted, loops=self.allows_loops(), multiedges=self.allows_multiple_edges()) - G.name("Subgraph of (%s)"%self.name()) + G.name("Subgraph of (%s)" % self.name()) if edges is None and edge_property is None: self._backend.subgraph_given_vertices(G._backend, vertices) else: @@ -13254,7 +13297,7 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm else: s_vertices = set(vertices) edges_to_keep = [e for e in self.edges(vertices=vertices, sort=False, sort_vertices=False) - if e[0] in s_vertices and e[1] in s_vertices] + if e[0] in s_vertices and e[1] in s_vertices] if edge_property is not None: edges_to_keep = [e for e in edges_to_keep if edge_property(e)] @@ -13409,7 +13452,7 @@ def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, if vertices is not None: vertices = set(vertices) G.delete_vertices([v for v in G if v not in vertices]) - G.name("Subgraph of (%s)"%self.name()) + G.name("Subgraph of (%s)" % self.name()) else: G = self._subgraph_by_adding(vertices) @@ -13849,7 +13892,7 @@ def subgraph_search_iterator(self, G, induced=False, return_graphs=True): G._scream_if_not_simple() if self.is_directed() and not G.is_directed(): raise ValueError("cannot search for a graph in a digraph") - if not self.is_directed() and G.is_directed(): + if not self.is_directed() and G.is_directed(): raise ValueError("cannot search for a digraph in a graph") DoG = self.__class__ if not G.order(): @@ -14056,7 +14099,7 @@ def is_chordal(self, certificate=False, algorithm="B"): if algorithm == "A": - peo,t_peo = self.lex_BFS(tree=True) + peo, t_peo = self.lex_BFS(tree=True) peo.reverse() # Iteratively removing vertices and checking everything is fine. @@ -14100,7 +14143,7 @@ def is_chordal(self, certificate=False, algorithm="B"): elif algorithm == "B": - peo,t_peo = self.lex_BFS(reverse=True, tree=True) + peo, t_peo = self.lex_BFS(reverse=True, tree=True) # Remembering the (closed) neighborhoods of each vertex neighbors_subsets = {v: frozenset(self.neighbors(v) + [v]) for v in g} @@ -14145,7 +14188,6 @@ def is_chordal(self, certificate=False, algorithm="B"): else: return False - # Returning values # ---------------- @@ -14161,7 +14203,6 @@ def is_chordal(self, certificate=False, algorithm="B"): return (False, hole) - # 2- The graph is chordal if certificate: return True, peo @@ -14253,9 +14294,9 @@ def is_circulant(self, certificate=False): # The automorphism group, the translation between the vertices of self # and 1..n, and the orbits. ag, orbits = self.automorphism_group([list(self)], - order=False, - return_group=True, - orbits=True) + order=False, + return_group=True, + orbits=True) # Not transitive ? Not a circulant graph ! if len(orbits) != 1: @@ -14268,8 +14309,7 @@ def is_circulant(self, certificate=False): # If the automorphism is not the identity and has exactly one # cycle that contains all vertices. - if ((not cycles) or - len(cycles[0]) != self.order()): + if not cycles or len(cycles[0]) != self.order(): continue # From now on the graph is a circulant graph ! @@ -14370,7 +14410,10 @@ def is_interval(self, certificate=False): Test certificate on a larger graph by re-doing isomorphic graph:: - sage: g = Graph(':S__@_@A_@AB_@AC_@ACD_@ACDE_ACDEF_ACDEFG_ACDEGH_ACDEGHI_ACDEGHIJ_ACDEGIJK_ACDEGIJKL_ACDEGIJKLMaCEGIJKNaCEGIJKNaCGIJKNPaCIP', loops=False, multiedges=False) + sage: s6 = ':S__@_@A_@AB_@AC_@ACD_@ACDE_ACDEF_ACDEFG_ACDEGH_ACDEGHI' + ....: '_ACDEGHIJ_ACDEGIJK_ACDEGIJKL_ACDEGIJKLMaCEGIJKNaCEGIJKN' + ....: 'aCGIJKNPaCIP' + sage: g = Graph(s6, loops=False, multiedges=False) sage: d = g.is_interval(certificate=True)[1] sage: g2 = graphs.IntervalGraph(d.values()) sage: g2.is_isomorphic(g) @@ -14633,13 +14676,15 @@ def is_clique(self, vertices=None, directed_clique=False, induced=True, loops=Fa # We check that we have edges between all pairs of vertices v_to_int = {v: i for i, v in enumerate(self)} if G.is_directed() and not directed_clique: - R = lambda u,v: (u, v) if u <= v else (v, u) + def R(u, v): + return (u, v) if u <= v else (v, u) else: - R = lambda u,v:(u,v) + def R(u, v): + return (u, v) if loops: - edges = set(R(v_to_int[u], v_to_int[v]) for u,v in G.edge_iterator(labels=False)) + edges = set(R(v_to_int[u], v_to_int[v]) for u, v in G.edge_iterator(labels=False)) else: - edges = set(R(v_to_int[u], v_to_int[v]) for u,v in G.edge_iterator(labels=False) if u != v) + edges = set(R(v_to_int[u], v_to_int[v]) for u, v in G.edge_iterator(labels=False) if u != v) # If induced == True, we already know that G.size() == M, so # we only need to check that we have the right set of edges. @@ -14872,7 +14917,7 @@ def is_subgraph(self, other, induced=True, up_to_isomorphism=False): else: return self._backend.is_subgraph(other._backend, self) - ### Cluster + # Cluster def cluster_triangles(self, nbunch=None, implementation=None): r""" @@ -14938,7 +14983,7 @@ def cluster_triangles(self, nbunch=None, implementation=None): elif implementation == 'sparse_copy': from sage.graphs.base.static_sparse_graph import triangles_count - elif implementation =="dense_copy": + elif implementation == "dense_copy": from sage.graphs.base.static_dense_graph import triangles_count else: @@ -15131,8 +15176,7 @@ def clustering_coeff(self, raise ValueError("the implementation can only be 'networkx', " "'boost', 'sparse_copy', 'dense_copy' or None") - if ((self.is_directed() or weight) and - implementation != 'networkx'): + if (self.is_directed() or weight) and implementation != 'networkx': raise ValueError("this value of 'implementation' is invalid for directed/weighted graphs") if (implementation in ['sparse_copy', 'dense_copy'] and nodes is not None): @@ -15157,7 +15201,7 @@ def coeff_from_triangle_count(v, count): from sage.graphs.base.static_sparse_graph import triangles_count return {v: coeff_from_triangle_count(v, count) for v, count in triangles_count(self).items()} - elif implementation =="dense_copy": + elif implementation == "dense_copy": from sage.graphs.base.static_dense_graph import triangles_count return {v: coeff_from_triangle_count(v, count) for v, count in triangles_count(self).items()} @@ -15180,7 +15224,7 @@ def cluster_transitivity(self): import networkx return networkx.transitivity(self.networkx_graph()) - ### Distance + # Distance def distance(self, u, v, by_weight=False, weight_function=None, check_weight=True): """ @@ -15301,7 +15345,16 @@ def distance_all_pairs(self, by_weight=False, algorithm=None, sage: g = graphs.PetersenGraph() sage: print(g.distance_all_pairs()) - {0: {0: 0, 1: 1, 2: 2, 3: 2, 4: 1, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2}, 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 2, 5: 2, 6: 1, 7: 2, 8: 2, 9: 2}, 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 2, 5: 2, 6: 2, 7: 1, 8: 2, 9: 2}, 3: {0: 2, 1: 2, 2: 1, 3: 0, 4: 1, 5: 2, 6: 2, 7: 2, 8: 1, 9: 2}, 4: {0: 1, 1: 2, 2: 2, 3: 1, 4: 0, 5: 2, 6: 2, 7: 2, 8: 2, 9: 1}, 5: {0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 0, 6: 2, 7: 1, 8: 1, 9: 2}, 6: {0: 2, 1: 1, 2: 2, 3: 2, 4: 2, 5: 2, 6: 0, 7: 2, 8: 1, 9: 1}, 7: {0: 2, 1: 2, 2: 1, 3: 2, 4: 2, 5: 1, 6: 2, 7: 0, 8: 2, 9: 1}, 8: {0: 2, 1: 2, 2: 2, 3: 1, 4: 2, 5: 1, 6: 1, 7: 2, 8: 0, 9: 2}, 9: {0: 2, 1: 2, 2: 2, 3: 2, 4: 1, 5: 2, 6: 1, 7: 1, 8: 2, 9: 0}} + {0: {0: 0, 1: 1, 2: 2, 3: 2, 4: 1, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2}, + 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 2, 5: 2, 6: 1, 7: 2, 8: 2, 9: 2}, + 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 2, 5: 2, 6: 2, 7: 1, 8: 2, 9: 2}, + 3: {0: 2, 1: 2, 2: 1, 3: 0, 4: 1, 5: 2, 6: 2, 7: 2, 8: 1, 9: 2}, + 4: {0: 1, 1: 2, 2: 2, 3: 1, 4: 0, 5: 2, 6: 2, 7: 2, 8: 2, 9: 1}, + 5: {0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 0, 6: 2, 7: 1, 8: 1, 9: 2}, + 6: {0: 2, 1: 1, 2: 2, 3: 2, 4: 2, 5: 2, 6: 0, 7: 2, 8: 1, 9: 1}, + 7: {0: 2, 1: 2, 2: 1, 3: 2, 4: 2, 5: 1, 6: 2, 7: 0, 8: 2, 9: 1}, + 8: {0: 2, 1: 2, 2: 2, 3: 1, 4: 2, 5: 1, 6: 1, 7: 2, 8: 0, 9: 2}, + 9: {0: 2, 1: 2, 2: 2, 3: 2, 4: 1, 5: 2, 6: 1, 7: 1, 8: 2, 9: 0}} Testing on Random Graphs:: @@ -15634,7 +15687,7 @@ def _girth_bfs(self, odd=False, certificate=False): else: return best - ### Centrality + # Centrality def centrality_betweenness(self, k=None, normalized=True, weight=None, endpoints=False, seed=None, exact=False, @@ -15719,10 +15772,10 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, if algorithm == "NetworkX" and exact: raise ValueError("'exact' is not available with the NetworkX implementation") if (algorithm is None and - seed is None and - weight is None and - endpoints is False and - k is None): + seed is None and + weight is None and + endpoints is False and + k is None): algorithm = "Sage" elif algorithm is None: algorithm = "NetworkX" @@ -15741,7 +15794,6 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, else: raise ValueError("'algorithm' can be \"NetworkX\", \"Sage\" or None") - def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" @@ -15832,7 +15884,12 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, Standard examples:: sage: (graphs.ChvatalGraph()).centrality_closeness() - {0: 0.61111111111111..., 1: 0.61111111111111..., 2: 0.61111111111111..., 3: 0.61111111111111..., 4: 0.61111111111111..., 5: 0.61111111111111..., 6: 0.61111111111111..., 7: 0.61111111111111..., 8: 0.61111111111111..., 9: 0.61111111111111..., 10: 0.61111111111111..., 11: 0.61111111111111...} + {0: 0.61111111111111..., 1: 0.61111111111111..., + 2: 0.61111111111111..., 3: 0.61111111111111..., + 4: 0.61111111111111..., 5: 0.61111111111111..., + 6: 0.61111111111111..., 7: 0.61111111111111..., + 8: 0.61111111111111..., 9: 0.61111111111111..., + 10: 0.61111111111111..., 11: 0.61111111111111...} sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]}) sage: D.show(figsize=[2,2]) sage: D.centrality_closeness(vert=[0,1]) @@ -16276,7 +16333,12 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, [] [] [] - """ # TODO- multiple edges?? + + .. TODO:: + + Add options to return a path as a list of edges with or without edge + labels. This can be useful in (di)graphs with multiple edges. + """ if not self.has_vertex(u): raise ValueError("vertex '{}' is not in the (di)graph".format(u)) if not self.has_vertex(v): @@ -16693,7 +16755,12 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, sage: D = graphs.DodecahedralGraph() sage: D.shortest_paths(0) - {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 4: [0, 19, 3, 4], 5: [0, 1, 2, 6, 5], 6: [0, 1, 2, 6], 7: [0, 1, 8, 7], 8: [0, 1, 8], 9: [0, 10, 9], 10: [0, 10], 11: [0, 10, 11], 12: [0, 10, 11, 12], 13: [0, 10, 9, 13], 14: [0, 1, 8, 7, 14], 15: [0, 19, 18, 17, 16, 15], 16: [0, 19, 18, 17, 16], 17: [0, 19, 18, 17], 18: [0, 19, 18], 19: [0, 19]} + {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 4: [0, 19, 3, 4], + 5: [0, 1, 2, 6, 5], 6: [0, 1, 2, 6], 7: [0, 1, 8, 7], 8: [0, 1, 8], + 9: [0, 10, 9], 10: [0, 10], 11: [0, 10, 11], 12: [0, 10, 11, 12], + 13: [0, 10, 9, 13], 14: [0, 1, 8, 7, 14], + 15: [0, 19, 18, 17, 16, 15], 16: [0, 19, 18, 17, 16], + 17: [0, 19, 18, 17], 18: [0, 19, 18], 19: [0, 19]} All these paths are obviously induced graphs:: @@ -16703,7 +16770,9 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, :: sage: D.shortest_paths(0, cutoff=2) - {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 8: [0, 1, 8], 9: [0, 10, 9], 10: [0, 10], 11: [0, 10, 11], 18: [0, 19, 18], 19: [0, 19]} + {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 8: [0, 1, 8], + 9: [0, 10, 9], 10: [0, 10], 11: [0, 10, 11], 18: [0, 19, 18], + 19: [0, 19]} sage: G = Graph( { 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} }, sparse=True) sage: G.plot(edge_labels=True).show() # long time sage: G.shortest_paths(0, by_weight=True) @@ -16894,7 +16963,7 @@ def _path_length(self, path, by_weight=False, weight_function=None): weight_function=weight_function, check_weight=False) return sum(weight_function((u, v, self.edge_label(u, v))) - for u, v in zip(path[:-1], path[1:])) + for u, v in zip(path[:-1], path[1:])) else: return len(path) - 1 From 42516880b873d5a613b7ff88d76682e7cdcad915 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 20 Aug 2022 13:30:28 +0200 Subject: [PATCH 212/742] trac #34392: fix identation error --- src/sage/graphs/generic_graph.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 076de6c1a7e..1ec85e7d955 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -14411,8 +14411,8 @@ def is_interval(self, certificate=False): Test certificate on a larger graph by re-doing isomorphic graph:: sage: s6 = ':S__@_@A_@AB_@AC_@ACD_@ACDE_ACDEF_ACDEFG_ACDEGH_ACDEGHI' - ....: '_ACDEGHIJ_ACDEGIJK_ACDEGIJKL_ACDEGIJKLMaCEGIJKNaCEGIJKN' - ....: 'aCGIJKNPaCIP' + sage: s6 += '_ACDEGHIJ_ACDEGIJK_ACDEGIJKL_ACDEGIJKLMaCEGIJKNaCEGIJK' + sage: s6 += 'NaCGIJKNPaCIP' sage: g = Graph(s6, loops=False, multiedges=False) sage: d = g.is_interval(certificate=True)[1] sage: g2 = graphs.IntervalGraph(d.values()) From 176e3914b277ef1ff3ae678bbbca67e3ff8a5026 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 20 Aug 2022 13:54:11 +0200 Subject: [PATCH 213/742] trac #34392: and a missing space --- src/sage/graphs/generic_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 1ec85e7d955..23e66648fb2 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -12075,7 +12075,7 @@ def set_edge_label(self, u, v, l): if self.allows_multiple_edges(): if len(self.edge_label(u, v)) > 1: raise RuntimeError("cannot set edge label, since there are " - "multiple edges from %s to %s" % (u,v)) + "multiple edges from %s to %s" % (u, v)) self._backend.set_edge_label(u, v, l, self._directed) def has_edge(self, u, v=None, label=None): From 9e6ca2a67102d4c133173cedaa5ca505c2082ddf Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 21 Aug 2022 20:05:20 +0900 Subject: [PATCH 214/742] Replace pdflatex to latex --- src/sage/features/latex.py | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py index cf65aea6afc..c3e28a6da9c 100644 --- a/src/sage/features/latex.py +++ b/src/sage/features/latex.py @@ -37,7 +37,7 @@ def __init__(self, name): sage: isinstance(latex(), latex) True """ - Executable.__init__(self, name, executable=name, spkg=latex_spkg, url=latex_url) + super().__init__(name, executable=name, spkg=latex_spkg, url=latex_url) def is_functional(self): r""" @@ -97,7 +97,7 @@ def __init__(self): sage: isinstance(latex(), latex) True """ - LaTeX.__init__(self, "latex") + super().__init__("latex") class pdflatex(LaTeX): @@ -118,7 +118,7 @@ def __init__(self): sage: isinstance(pdflatex(), pdflatex) True """ - LaTeX.__init__(self, "pdflatex") + super().__init__("pdflatex") class xelatex(LaTeX): @@ -139,7 +139,7 @@ def __init__(self): sage: isinstance(xelatex(), xelatex) True """ - LaTeX.__init__(self, "xelatex") + super().__init__("xelatex") class lualatex(LaTeX): @@ -160,7 +160,7 @@ def __init__(self): sage: isinstance(lualatex(), lualatex) True """ - LaTeX.__init__(self, "lualatex") + super().__init__("lualatex") class TeXFile(StaticFile, JoinFeature): @@ -170,20 +170,20 @@ class TeXFile(StaticFile, JoinFeature): EXAMPLES:: sage: from sage.features.latex import TeXFile - sage: TeXFile('x', 'x.tex').is_present() # optional: pdflatex + sage: TeXFile('x', 'x.tex').is_present() # optional - latex FeatureTestResult('x', True) - sage: TeXFile('nonexisting', 'xxxxxx-nonexisting-file.tex').is_present() # optional - pdflatex + sage: TeXFile('nonexisting', 'xxxxxx-nonexisting-file.tex').is_present() # optional - latex FeatureTestResult('nonexisting', False) """ def __init__(self, name, filename, **kwds): r""" EXAMPLES:: - sage: from sage.features.latex import LaTeXPackage, pdflatex + sage: from sage.features.latex import LaTeXPackage sage: LaTeXPackage("tkz-graph")._features - [Feature('pdflatex')] + [Feature('latex')] """ - JoinFeature.__init__(self, name, [pdflatex()], + JoinFeature.__init__(self, name, [latex()], spkg=latex_spkg, url=latex_url) # see :trac:`34282` StaticFile.__init__(self, name, filename, search_path=[], **kwds) @@ -195,7 +195,7 @@ def absolute_filename(self) -> str: sage: from sage.features.latex import TeXFile sage: feature = TeXFile('latex_class_article', 'article.cls') - sage: feature.absolute_filename() # optional - pdflatex + sage: feature.absolute_filename() # optional - latex '.../latex/base/article.cls' """ from subprocess import run, CalledProcessError, PIPE @@ -214,16 +214,13 @@ def _is_present(self): EXAMPLES:: - sage: from sage.features.latex import LaTeXPackage, pdflatex + sage: from sage.features.latex import LaTeXPackage, latex sage: f = LaTeXPackage("tkz-graph") - sage: g = pdflatex() - sage: bool(f.is_present()) == bool(g.is_present()) # indirect doctest + sage: g = latex() + sage: not f.is_present() or bool(g.is_present()) # indirect doctest True """ - test = JoinFeature._is_present(self) - if not test: - return test - return super(TeXFile, self)._is_present() + return JoinFeature._is_present(self) and StaticFile._is_present(self) class LaTeXPackage(TeXFile): @@ -234,7 +231,7 @@ class LaTeXPackage(TeXFile): EXAMPLES:: sage: from sage.features.latex import LaTeXPackage - sage: LaTeXPackage('graphics').is_present() # optional - pdflatex + sage: LaTeXPackage('graphics').is_present() # optional - latex FeatureTestResult('latex_package_graphics', True) """ @staticmethod From 553f6ffc7473fabcff8e630b995bd7e3dc671207 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 21 Aug 2022 20:43:16 +0900 Subject: [PATCH 215/742] Do not use JoinFeature --- src/sage/features/latex.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py index c3e28a6da9c..a3c8f3b4ab1 100644 --- a/src/sage/features/latex.py +++ b/src/sage/features/latex.py @@ -163,7 +163,7 @@ def __init__(self): super().__init__("lualatex") -class TeXFile(StaticFile, JoinFeature): +class TeXFile(StaticFile): r""" A :class:`sage.features.Feature` describing the presence of a TeX file @@ -172,19 +172,16 @@ class TeXFile(StaticFile, JoinFeature): sage: from sage.features.latex import TeXFile sage: TeXFile('x', 'x.tex').is_present() # optional - latex FeatureTestResult('x', True) - sage: TeXFile('nonexisting', 'xxxxxx-nonexisting-file.tex').is_present() # optional - latex - FeatureTestResult('nonexisting', False) """ def __init__(self, name, filename, **kwds): r""" - EXAMPLES:: + Initialize. - sage: from sage.features.latex import LaTeXPackage - sage: LaTeXPackage("tkz-graph")._features - [Feature('latex')] + TESTS:: + + sage: TeXFile('nonexisting', 'xxxxxx-nonexisting-file.tex').is_present() # optional - latex + FeatureTestResult('nonexisting', False) """ - JoinFeature.__init__(self, name, [latex()], - spkg=latex_spkg, url=latex_url) # see :trac:`34282` StaticFile.__init__(self, name, filename, search_path=[], **kwds) def absolute_filename(self) -> str: @@ -205,8 +202,8 @@ def absolute_filename(self) -> str: universal_newlines=True, check=True) return proc.stdout.strip() except CalledProcessError: - raise FeatureNotPresentError(self, - reason="{filename!r} not found by kpsewhich".format(filename=self.filename)) + reason = "{filename!r} not found by kpsewhich".format(filename=self.filename) + raise FeatureNotPresentError(self, reason) def _is_present(self): r""" @@ -220,7 +217,7 @@ def _is_present(self): sage: not f.is_present() or bool(g.is_present()) # indirect doctest True """ - return JoinFeature._is_present(self) and StaticFile._is_present(self) + return latex().is_present() and super()._is_present() class LaTeXPackage(TeXFile): From a31205abd7189dfb0f888fe78fd3bfcd4bd09eee Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 21 Aug 2022 21:38:19 +0900 Subject: [PATCH 216/742] A tiny edit --- src/sage/features/latex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py index a3c8f3b4ab1..501c82c0539 100644 --- a/src/sage/features/latex.py +++ b/src/sage/features/latex.py @@ -207,7 +207,7 @@ def absolute_filename(self) -> str: def _is_present(self): r""" - Test for the presence of the TeX-file. + Test for the presence of the TeX file. EXAMPLES:: From d4c8b90fddd0e9aaabe99d3062b182b191700eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 20 Aug 2022 12:03:57 +0200 Subject: [PATCH 217/742] add tensor_factors method to tensor products --- src/sage/categories/modules.py | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index d37b4812209..1410f650a4d 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -551,6 +551,42 @@ def extra_super_categories(self): """ return [self.base_category()] + class ParentMethods: + """ + Implement operations on tensor products of modules. + """ + def construction(self): + """ + Return the construction of ``self``. + + EXAMPLES:: + + sage: A = algebras.Free(QQ,2) + sage: T = A.tensor(A) + sage: T.construction() + [The tensor functorial construction, + (Free Algebra on 2 generators (None0, None1) over Rational Field, + Free Algebra on 2 generators (None0, None1) over Rational Field)] + """ + return [tensor, self._sets] + + def tensor_factors(self): + """ + Return the tensor factors of this tensor product. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(ZZ, [1,2]) + sage: F.__custom_name = "F" + sage: G = CombinatorialFreeModule(ZZ, [3,4]) + sage: G.__custom_name = "G" + sage: T = tensor([F, G]); T + F # G + sage: T.tensor_factors() + (F, G) + """ + return self._sets + class FinitelyPresented(CategoryWithAxiom_over_base_ring): def extra_super_categories(self): From d0972e6183fbe3396f41dc7fba641e579bd3a30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 22 Aug 2022 08:35:24 +0200 Subject: [PATCH 218/742] trying to use the suggestions about tensor construction --- src/sage/categories/modules.py | 8 +++++--- src/sage/combinat/free_module.py | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 1410f650a4d..4f48ee0e840 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -12,6 +12,7 @@ # ***************************************************************************** from sage.misc.cachefunc import cached_method +from sage.misc.abstract_method import abstract_method from sage.misc.lazy_import import LazyImport from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.morphism import SetMorphism @@ -19,7 +20,7 @@ from sage.categories.homset import Hom from .category import Category from .category_types import Category_module -from sage.categories.tensor import TensorProductsCategory, tensor +from sage.categories.tensor import TensorProductsCategory, TensorProductFunctor, tensor from .dual import DualObjectsCategory from sage.categories.cartesian_product import CartesianProductsCategory from sage.categories.sets_cat import Sets @@ -568,8 +569,10 @@ def construction(self): (Free Algebra on 2 generators (None0, None1) over Rational Field, Free Algebra on 2 generators (None0, None1) over Rational Field)] """ - return [tensor, self._sets] + return (TensorProductFunctor(self.category()), + self.tensor_factors()) + @abstract_method def tensor_factors(self): """ Return the tensor factors of this tensor product. @@ -585,7 +588,6 @@ def tensor_factors(self): sage: T.tensor_factors() (F, G) """ - return self._sets class FinitelyPresented(CategoryWithAxiom_over_base_ring): diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index a2f789a4202..e1cfa54ffdb 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1306,6 +1306,23 @@ def _repr_(self): return symb.join("%s" % module for module in self._sets) # TODO: make this overridable by setting _name + def tensor_factors(self): + """ + Return the tensor factors of this tensor product. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(ZZ, [1,2]) + sage: F.__custom_name = "F" + sage: G = CombinatorialFreeModule(ZZ, [3,4]) + sage: G.__custom_name = "G" + sage: T = tensor([F, G]); T + F # G + sage: T.tensor_factors() + (F, G) + """ + return self._sets + def _ascii_art_(self, term): """ TESTS:: From f7eff260b32155d69d1eae416ab443d9a8bc592e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 22 Aug 2022 16:32:19 +0900 Subject: [PATCH 219/742] Fixing last details. --- src/sage/homology/free_resolution.py | 9 ++++++++- src/sage/homology/graded_resolution.py | 1 + src/sage/rings/ideal.py | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index e3a8eab1344..2f9ad448baa 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -646,10 +646,17 @@ def _maps(self): [2*x^2 x] [3*x^2 2*x] ] + + sage: R. = PolynomialRing(QQ) + sage: I = R.ideal([x^4 + 3*x^2 + 2]) + sage: res = I.free_resolution() + sage: res._maps + [[x^4 + 3*x^2 + 2]] """ if self._is_free_module: if isinstance(self._module, Ideal_generic): - return matrix([[self._module.gen()]]) + from sage.matrix.constructor import matrix + return [matrix([[self._module.gen()]])] return [self._m()] # This ensures the first component of the Singular resolution to be a diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index 4a38a347e5d..bc30e61ef6e 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -289,6 +289,7 @@ def compute_degree(base, i): return [matrix([[val]])] M = self._m() + def find_deg(i): for j in range(M.nrows()): ret = M[j,i].degree() diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 85203abed43..4ca750e6909 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -1215,6 +1215,7 @@ def free_resolution(self, *args, **kwds): sage: R. = PolynomialRing(QQ) sage: I = R.ideal([x^4 + 3*x^2 + 2]) sage: I.free_resolution() + S^1 <-- S^1 <-- 0 """ from sage.homology.free_resolution import FreeResolution return FreeResolution(self, *args, **kwds) @@ -1231,6 +1232,7 @@ def graded_free_resolution(self, *args, **kwds): sage: R. = PolynomialRing(QQ) sage: I = R.ideal([x^3]) sage: I.graded_free_resolution() + S(0) <-- S(-3) <-- 0 """ from sage.homology.graded_resolution import GradedFreeResolution return GradedFreeResolution(self, *args, **kwds) From eba9d161893a80d65aff472ee5e26a307872482a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 22 Aug 2022 13:51:17 +0200 Subject: [PATCH 220/742] detail fix --- src/sage/categories/modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 4f48ee0e840..ca38625682d 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -569,7 +569,7 @@ def construction(self): (Free Algebra on 2 generators (None0, None1) over Rational Field, Free Algebra on 2 generators (None0, None1) over Rational Field)] """ - return (TensorProductFunctor(self.category()), + return (TensorProductFunctor(), self.tensor_factors()) @abstract_method From c862151e4b82674751fd3a3cbdfa02ffbf752b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 22 Aug 2022 18:52:58 +0200 Subject: [PATCH 221/742] rather use rename --- src/sage/categories/modules.py | 4 ++-- src/sage/combinat/free_module.py | 41 ++++++++++++++++---------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index ca38625682d..780ab68a44d 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -580,9 +580,9 @@ def tensor_factors(self): EXAMPLES:: sage: F = CombinatorialFreeModule(ZZ, [1,2]) - sage: F.__custom_name = "F" + sage: F.rename("F") sage: G = CombinatorialFreeModule(ZZ, [3,4]) - sage: G.__custom_name = "G" + sage: G.rename("G") sage: T = tensor([F, G]); T F # G sage: T.tensor_factors() diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index e1cfa54ffdb..ec59d021416 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1159,8 +1159,8 @@ class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): We construct two free modules, assign them short names, and construct their tensor product:: - sage: F = CombinatorialFreeModule(ZZ, [1,2]); F.__custom_name = "F" - sage: G = CombinatorialFreeModule(ZZ, [3,4]); G.__custom_name = "G" + sage: F = CombinatorialFreeModule(ZZ, [1,2]); F.rename("F") + sage: G = CombinatorialFreeModule(ZZ, [3,4]); G.rename("G") sage: T = tensor([F, G]); T F # G @@ -1313,9 +1313,9 @@ def tensor_factors(self): EXAMPLES:: sage: F = CombinatorialFreeModule(ZZ, [1,2]) - sage: F.__custom_name = "F" + sage: F.rename("F") sage: G = CombinatorialFreeModule(ZZ, [3,4]) - sage: G.__custom_name = "G" + sage: G.rename("G") sage: T = tensor([F, G]); T F # G sage: T.tensor_factors() @@ -1447,8 +1447,8 @@ def tensor_constructor(self, modules): EXAMPLES:: - sage: F = CombinatorialFreeModule(ZZ, [1,2]); F.__custom_name = "F" - sage: G = CombinatorialFreeModule(ZZ, [3,4]); G.__custom_name = "G" + sage: F = CombinatorialFreeModule(ZZ, [1,2]); F.rename("F") + sage: G = CombinatorialFreeModule(ZZ, [3,4]); G.rename("G") sage: H = CombinatorialFreeModule(ZZ, [5,6]); H.rename("H") sage: f = F.monomial(1) + 2 * F.monomial(2) @@ -1487,8 +1487,8 @@ def _tensor_of_elements(self, elements): EXAMPLES:: - sage: F = CombinatorialFreeModule(ZZ, [1,2]); F.__custom_name = "F" - sage: G = CombinatorialFreeModule(ZZ, [3,4]); G.__custom_name = "G" + sage: F = CombinatorialFreeModule(ZZ, [1,2]); F.rename("F") + sage: G = CombinatorialFreeModule(ZZ, [3,4]); G.rename("G") sage: H = CombinatorialFreeModule(ZZ, [5,6]); H.rename("H") sage: f = F.monomial(1) + 2 * F.monomial(2) @@ -1622,9 +1622,9 @@ class CombinatorialFreeModule_CartesianProduct(CombinatorialFreeModule): We construct two free modules, assign them short names, and construct their Cartesian product:: - sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.__custom_name = "F" - sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.__custom_name = "G" - sage: H = CombinatorialFreeModule(ZZ, [4,7]); H.__custom_name = "H" + sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename("F") + sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename("G") + sage: H = CombinatorialFreeModule(ZZ, [4,7]); H.rename("H") sage: S = cartesian_product([F, G]) sage: S F (+) G @@ -1696,7 +1696,7 @@ def _repr_(self): sage: F = CombinatorialFreeModule(ZZ, [2,4,5]) sage: CP = cartesian_product([F, F]); CP # indirect doctest Free module generated by {2, 4, 5} over Integer Ring (+) Free module generated by {2, 4, 5} over Integer Ring - sage: F.__custom_name = "F"; CP + sage: F.rename("F"); CP F (+) F """ from sage.categories.cartesian_product import cartesian_product @@ -1716,8 +1716,8 @@ def cartesian_embedding(self, i): EXAMPLES:: - sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.__custom_name = "F" - sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.__custom_name = "G" + sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename("F") + sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename("G") sage: S = cartesian_product([F, G]) sage: phi = S.cartesian_embedding(0) sage: phi(F.monomial(4) + 2 * F.monomial(5)) @@ -1750,8 +1750,8 @@ def cartesian_projection(self, i): EXAMPLES:: - sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.__custom_name = "F" - sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.__custom_name = "G" + sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename("F") + sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename("G") sage: S = cartesian_product([F, G]) sage: x = S.monomial((0,4)) + 2 * S.monomial((0,5)) + 3 * S.monomial((1,6)) sage: S.cartesian_projection(0)(x) @@ -1780,8 +1780,8 @@ def _cartesian_product_of_elements(self, elements): EXAMPLES:: - sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.__custom_name = "F" - sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.__custom_name = "G" + sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename("F") + sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename("G") sage: S = cartesian_product([F, G]) sage: f = F.monomial(4) + 2 * F.monomial(5) sage: g = 2*G.monomial(4) + G.monomial(6) @@ -1819,12 +1819,11 @@ def cartesian_factors(self): EXAMPLES:: - sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.__custom_name = "F" - sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.__custom_name = "G" + sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename("F") + sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename("G") sage: S = cartesian_product([F, G]) sage: S.cartesian_factors() (F, G) - """ return self._sets From d5b86a820b8ff27c2832ad27eb4f1f8ecb6f54cb Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 22 Aug 2022 19:45:34 +0200 Subject: [PATCH 222/742] implement revert, improve plethysm --- src/sage/combinat/sf/sfa.py | 23 ++-- src/sage/data_structures/stream.py | 168 +++++++++++++++++++++++------ src/sage/rings/lazy_series.py | 83 +++++++++++++- src/sage/rings/lazy_series_ring.py | 12 +-- 4 files changed, 232 insertions(+), 54 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index d1fd77e8c69..63579adca06 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -3076,19 +3076,20 @@ def plethysm(self, x, include=None, exclude=None): # Handle degree one elements if include is not None and exclude is not None: raise RuntimeError("include and exclude cannot both be specified") + R = p.base_ring() - try: - degree_one = [R(g) for g in R.variable_names_recursive()] - except AttributeError: - try: - degree_one = R.gens() - except NotImplementedError: - degree_one = [] - - if include: + if include is not None: degree_one = [R(g) for g in include] - if exclude: - degree_one = [g for g in degree_one if g not in exclude] + else: + try: + degree_one = [R(g) for g in R.variable_names_recursive()] + except AttributeError: + try: + degree_one = R.gens() + except NotImplementedError: + degree_one = [] + if exclude is not None: + degree_one = [g for g in degree_one if g not in exclude] degree_one = [g for g in degree_one if g != R.one()] diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index e54a90b8b88..380b27fb751 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -80,7 +80,6 @@ - Kwankyu Lee (2019-02-24): initial version - Tejasvi Chebrolu, Martin Rubey, Travis Scrimshaw (2021-08): refactored and expanded functionality - """ # **************************************************************************** @@ -168,6 +167,15 @@ class Stream_inexact(Stream): - ``sparse`` -- boolean; whether the implementation of the stream is sparse - ``approximate_order`` -- integer; a lower bound for the order of the stream + + .. TODO:: + + The ``approximate_order`` is currently only updated when + invoking :meth:`order`. It might make sense to update it + whenever the coefficient one larger than the current + ``approximate_order`` is computed, since in some methods this + will allow shortcuts. + """ def __init__(self, is_sparse, approximate_order): """ @@ -1659,30 +1667,73 @@ class Stream_plethysm(Stream_binary): - ``f`` -- a :class:`Stream` - ``g`` -- a :class:`Stream` with positive order - ``p`` -- the powersum symmetric functions + - ``ring`` (optional, default ``None``) -- the ring the result + should be in, by default ``p`` + - ``include`` -- a list of variables to be treated as degree one + elements instead of the default degree one elements + - ``exclude`` -- a list of variables to be excluded from the + default degree one elements EXAMPLES:: - sage: from sage.data_structures.stream import Stream_function, Stream_plethysm + sage: from sage.data_structures.stream import Stream_function, Stream_plethysm sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() sage: f = Stream_function(lambda n: s[n], s, True, 1) sage: g = Stream_function(lambda n: s[[1]*n], s, True, 1) - sage: h = Stream_plethysm(f, g, p) - sage: [s(h[i]) for i in range(5)] + sage: h = Stream_plethysm(f, g, p, s) + sage: [h[i] for i in range(5)] [0, s[1], s[1, 1] + s[2], 2*s[1, 1, 1] + s[2, 1] + s[3], 3*s[1, 1, 1, 1] + 2*s[2, 1, 1] + s[2, 2] + s[3, 1] + s[4]] - sage: u = Stream_plethysm(g, f, p) - sage: [s(u[i]) for i in range(5)] + sage: u = Stream_plethysm(g, f, p, s) + sage: [u[i] for i in range(5)] [0, s[1], s[1, 1] + s[2], s[1, 1, 1] + s[2, 1] + 2*s[3], s[1, 1, 1, 1] + s[2, 1, 1] + 3*s[3, 1] + 2*s[4]] + + TESTS: + + Check corner cases:: + + sage: from sage.data_structures.stream import Stream_exact + sage: p = SymmetricFunctions(QQ).p() + sage: f0 = Stream_exact([p([])], True) + sage: f1 = Stream_exact([p[1]], True, order=1) + sage: f2 = Stream_exact([p[2]], True, order=2 ) + sage: f11 = Stream_exact([p[1,1]], True, order=2 ) + sage: r = Stream_plethysm(f0, f1, p); [r[n] for n in range(3)] + [p[], 0, 0] + sage: r = Stream_plethysm(f0, f2, p); [r[n] for n in range(3)] + [p[], 0, 0] + sage: r = Stream_plethysm(f0, f11, p); [r[n] for n in range(3)] + [p[], 0, 0] + + Check that degree one elements are treated in the correct way:: + + sage: R. = QQ[]; p = SymmetricFunctions(R).p() + sage: f_s = a1*p[1] + a2*p[2] + a11*p[1,1] + sage: g_s = b1*p[1] + b21*p[2,1] + b111*p[1,1,1] + sage: r_s = f_s(g_s) + sage: f = Stream_exact([f_s.restrict_degree(k) for k in range(f_s.degree()+1)], True) + sage: g = Stream_exact([g_s.restrict_degree(k) for k in range(g_s.degree()+1)], True) + sage: r = Stream_plethysm(f, g, p) + sage: r_s == sum(r[n] for n in range(2*(r_s.degree()+1))) + True + + sage: r_s - f_s(g_s, include=[]) + (a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2] + + sage: r2 = Stream_plethysm(f, g, p, include=[]) + sage: r_s - sum(r2[n] for n in range(2*(r_s.degree()+1))) + (a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2] + """ - def __init__(self, f, g, p): + def __init__(self, f, g, p, ring=None, include=None, exclude=None): r""" Initialize ``self``. @@ -1695,12 +1746,38 @@ def __init__(self, f, g, p): sage: g = Stream_function(lambda n: s[n-1,1], s, True, 2) sage: h = Stream_plethysm(f, g, p) """ - #assert g._approximate_order > 0 - self._fv = f._approximate_order - self._gv = g._approximate_order + # handle degree one elements + if include is not None and exclude is not None: + raise RuntimeError("include and exclude cannot both be specified") + R = p.base_ring() + + if include is not None: + degree_one = [R(g) for g in include] + else: + try: + degree_one = [R(g) for g in R.variable_names_recursive()] + except AttributeError: + try: + degree_one = R.gens() + except NotImplementedError: + degree_one = [] + if exclude is not None: + degree_one = [g for g in degree_one if g not in exclude] + + self._degree_one = [g for g in degree_one if g != R.one()] + + # assert g._approximate_order > 0 + val = f._approximate_order * g._approximate_order + p_f = Stream_map_coefficients(f, lambda x: x, p) + p_g = Stream_map_coefficients(g, lambda x: x, p) + self._powers = [p_g] # a cache for the powers of p_g + if ring is None: + self._basis = p + else: + self._basis = ring self._p = p - val = self._fv * self._gv - super().__init__(f, g, f._is_sparse, val) + + super().__init__(p_f, p_g, f._is_sparse, val) def get_coefficient(self, n): r""" @@ -1731,18 +1808,12 @@ def get_coefficient(self, n): if not n: # special case of 0 return self._left[0] - # We assume n > 0 - p = self._p - ret = p.zero() - for k in range(n+1): - temp = p(self._left[k]) - for la, c in temp: - inner = self._compute_product(n, la, c) - if inner is not None: - ret += inner - return ret + return sum((c * self._compute_product(n, la) + for k in range(self._left._approximate_order, n+1) + for la, c in self._left[k]), + self._basis.zero()) - def _compute_product(self, n, la, c): + def _compute_product(self, n, la): """ Compute the product ``c * p[la](self._right)`` in degree ``n``. @@ -1754,25 +1825,53 @@ def _compute_product(self, n, la, c): sage: f = Stream_function(lambda n: s[n], s, True, 1) sage: g = Stream_exact([s[2], s[3]], False, 0, 4, 2) sage: h = Stream_plethysm(f, g, p) - sage: ret = h._compute_product(7, [2, 1], 1); ret + sage: ret = h._compute_product(7, Partition([2, 1])); ret 1/12*p[2, 2, 1, 1, 1] + 1/4*p[2, 2, 2, 1] + 1/6*p[3, 2, 2] + 1/12*p[4, 1, 1, 1] + 1/4*p[4, 2, 1] + 1/6*p[4, 3] sage: ret == p[2,1](s[2] + s[3]).homogeneous_component(7) True """ - p = self._p - ret = p.zero() - for mu in wt_int_vec_iter(n, la): - temp = c - for i, j in zip(la, mu): - gs = self._right[j] - if not gs: - temp = p.zero() - break - temp *= p[i](gs) + ret = self._basis.zero() + la_exp = la.to_exp() + wgt = [i for i, m in enumerate(la_exp, 1) if m] + exp = [m for m in la_exp if m] + for k in wt_int_vec_iter(n, wgt): + # TODO: it may make a big difference here if the + # approximate order would be updated + if any(d < self._right._approximate_order * m + for m, d in zip(exp, k)): + continue + temp = self._basis.one() + for i, m, d in zip(wgt, exp, k): + temp *= self._stretched_power_restrict_degree(i, m, d) ret += temp return ret + def _scale_part(self, mu, i): + return mu.__class__(mu.parent(), [j * i for j in mu]) + + def _raise_c(self, c, i): + return c.subs(**{str(g): g ** i + for g in self._degree_one}) + + def _stretched_power_restrict_degree(self, i, m, d): + """ + Return the degree ``d*i`` part of ``p([i]*m)(g)``. + """ + while len(self._powers) < m: + self._powers.append(Stream_cauchy_mul(self._powers[-1], self._powers[0])) + power = self._powers[m-1] + + # we have to check power[d] for zero because it might be an + # integer and not a symmetric function + if power[d]: + terms = [(self._scale_part(m, i), self._raise_c(c, i)) for m, c in power[d]] + else: + terms = [] + + return self._p.sum_of_terms(terms, distinct = True) + + ##################################################################### # Unary operations @@ -2324,4 +2423,3 @@ def is_nonzero(self): True """ return self._series.is_nonzero() - diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 50a8577504e..0e694e0e30b 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -965,7 +965,10 @@ def change_ring(self, ring): Lazy Taylor Series Ring in z over Rational Field """ P = self.parent() - Q = type(P)(ring, names=P.variable_names(), sparse=P._sparse) + if P._names is not None: + Q = type(P)(ring, names=P.variable_names(), sparse=P._sparse) + else: + Q = type(P)(ring, sparse=P._sparse) return Q.element_class(Q, self._coeff_stream) # === module structure === @@ -3076,6 +3079,8 @@ def revert(self): raise ValueError("compositional inverse does not exist") raise ValueError("cannot determine whether the compositional inverse exists") + compositional_inverse = revert + def approximate_series(self, prec, name=None): r""" Return the Laurent series with absolute precision ``prec`` approximated @@ -3643,6 +3648,10 @@ def __call__(self, *args, check=True): - ``args`` -- other (lazy) symmetric functions + .. TODO:: + + allow specification of degree one elements + EXAMPLES:: sage: P. = QQ[] @@ -3752,6 +3761,78 @@ def __call__(self, *args, check=True): plethysm = __call__ + def revert(self): + r""" + Return the compositional inverse of ``self`` if possible. + + (Specifically, if ``self`` is of the form `0 + p_{1} + \cdots`.) + + The compositional inverse is the inverse with respect to + plethystic substitution. This is the operation on cycle index + series which corresponds to substitution, a.k.a. partitional + composition, on the level of species. See Section 2.2 of + [BLL]_ for a definition of this operation. + + EXAMPLES:: + + sage: h = SymmetricFunctions(QQ).h() + sage: p = SymmetricFunctions(QQ).p() + sage: L = LazySymmetricFunctions(p) + sage: Eplus = L(lambda n: h[n]) - 1 + sage: Eplus(Eplus.revert()) + p[1] + O^8 + + TESTS:: + + sage: Eplus = L(lambda n: h[n]) - 1 - h[1] + sage: Eplus.compositional_inverse() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + ALGORITHM: + + Let `F` be a species satisfying `F = 0 + X + F_2 + F_3 + \cdots` for + `X` the species of singletons. (Equivalently, `\lvert F[\varnothing] + \rvert = 0` and `\lvert F[\{1\}] \rvert = 1`.) Then there exists a + (virtual) species `G` satisfying `F \circ G = G \circ F = X`. + + It follows that `(F - X) \circ G = F \circ G - X \circ G = X - G`. + Rearranging, we obtain the recursive equation `G = X - (F - X) \circ G`, + which can be solved using iterative methods. + + .. WARNING:: + + This algorithm is functional but can be very slow. + Use with caution! + + .. SEEALSO:: + + The compositional inverse `\Omega` of the species `E_{+}` + of nonempty sets can be handled much more efficiently + using specialized methods. See + :func:`~sage.combinat.species.generating_series.LogarithmCycleIndexSeries` + + AUTHORS: + + - Andrew Gainer-Dewar + """ + P = self.parent() + if P._arity != 1: + raise ValueError("arity must be equal to 1") + if self.valuation() == 1: + from sage.combinat.sf.sf import SymmetricFunctions + p = SymmetricFunctions(P.base()).p() + X = P(p[1]) + f1 = self - X + g = P(None, valuation=1) + g.define(X - f1(g)) + return g + raise ValueError("compositional inverse does not exist") + + plethystic_inverse = revert + compositional_inverse = revert + def _format_series(self, formatter, format_strings=False): r""" Return nonzero ``self`` formatted by ``formatter``. diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 2626384097c..44c461ccbce 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -804,11 +804,11 @@ class LazyLaurentSeriesRing(LazySeriesRing): sage: s 1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + O(z^7) - If we do not explcitly know the exact value of every coefficient, - then equality checking will depend on the computed coefficients. - If at a certain point we cannot prove two series are different - (which involves the coefficients we have computed), then we will - raise an error:: + If we do not explicitly know the exact value of every + coefficient, then equality checking will depend on the computed + coefficients. If at a certain point we cannot prove two series + are different (which involves the coefficients we have computed), + then we will raise an error:: sage: f = 1 / (z + z^2); f z^-1 - 1 + z - z^2 + z^3 - z^4 + z^5 + O(z^6) @@ -1476,7 +1476,6 @@ def _an_element_(self): coeff_stream = Stream_exact([R.one()], self._sparse, order=1, constant=c) return self.element_class(self, coeff_stream) - ###################################################################### class LazySymmetricFunctions(LazySeriesRing): @@ -1999,4 +1998,3 @@ def _monomial(self, c, n): return L(c) * L(n) ** -L(self.variable_name()) except (ValueError, TypeError): return '({})/{}^{}'.format(self.base_ring()(c), n, self.variable_name()) - From 44d42db483c61cea2e5497982ad08c12b57f8d96 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 19:53:14 -0700 Subject: [PATCH 223/742] src/sage/categories/modules.py: Deprecate classes without tensor_factors --- src/sage/categories/modules.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 780ab68a44d..58b83b8a785 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -569,10 +569,16 @@ def construction(self): (Free Algebra on 2 generators (None0, None1) over Rational Field, Free Algebra on 2 generators (None0, None1) over Rational Field)] """ + try: + factors = self.tensor_factors() + except (TypeError, NotImplementedError): + from sage.misc.superseded import deprecation + deprecation(34393, "implementations of Modules().TensorProducts() now must define the method tensor_factors") + return None return (TensorProductFunctor(), - self.tensor_factors()) + factors) - @abstract_method + @abstract_method(optional=True) def tensor_factors(self): """ Return the tensor factors of this tensor product. @@ -587,6 +593,15 @@ def tensor_factors(self): F # G sage: T.tensor_factors() (F, G) + + TESTS:: + + sage: M = CombinatorialFreeModule(ZZ, ((1, 1), (1, 2), (2, 1), (2, 2)), + ....: category=ModulesWithBasis(ZZ).FiniteDimensional().TensorProducts()) + sage: M.construction() + doctest:warning... + DeprecationWarning: implementations of Modules().TensorProducts() now must define the method tensor_factors + See https://trac.sagemath.org/34393 for details. """ class FinitelyPresented(CategoryWithAxiom_over_base_ring): From d7f05ce7d49d5cc1e4e7faceb94ead163d32039b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 23 Aug 2022 13:24:43 +0900 Subject: [PATCH 224/742] Initial implementation of q-commuting polynomials. --- src/doc/en/reference/algebras/index.rst | 1 + src/sage/algebras/catalog.py | 7 +- src/sage/algebras/q_commuting_polynomials.py | 276 +++++++++++++++++++ 3 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 src/sage/algebras/q_commuting_polynomials.py diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 898d8ace33e..b6a455a370a 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -98,6 +98,7 @@ Various associative algebras sage/algebras/associated_graded sage/algebras/cellular_basis sage/algebras/q_system + sage/algebras/q_commuting_polynomials sage/algebras/splitting_algebra Non-associative algebras diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index 4a6ee3b6985..68b35506a66 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -58,6 +58,8 @@ - :class:`algebras.QSym ` - :class:`algebras.Partition ` - :class:`algebras.PlanarPartition ` +- :class:`algebras.qCommutingPolynomials + ` - :class:`algebras.QuantumGroup ` - :func:`algebras.Quaternion @@ -69,11 +71,11 @@ - :class:`algebras.Steenrod ` - :class:`algebras.TemperleyLieb ` +- :class:`algebras.Tensor ` - :class:`algebras.WQSym ` - :class:`algebras.Yangian ` - :class:`algebras.YokonumaHecke ` -- :class:`algebras.Tensor ` """ from sage.algebras.free_algebra import FreeAlgebra as Free @@ -121,9 +123,12 @@ lazy_import('sage.algebras.quantum_matrix_coordinate_algebra', 'QuantumMatrixCoordinateAlgebra', 'QuantumMatrixCoordinate') lazy_import('sage.algebras.quantum_matrix_coordinate_algebra', 'QuantumGL') +lazy_import('sage.algebras.q_commuting_polynomials', 'qCommutingPolynomials') lazy_import('sage.algebras.tensor_algebra', 'TensorAlgebra', 'Tensor') lazy_import('sage.algebras.quantum_groups.quantum_group_gap', 'QuantumGroup') lazy_import('sage.algebras.quantum_groups.ace_quantum_onsager', 'ACEQuantumOnsagerAlgebra', 'AlternatingCentralExtensionQuantumOnsager') lazy_import('sage.algebras.yangian', 'Yangian') + del lazy_import # We remove the object from here so it doesn't appear under tab completion + diff --git a/src/sage/algebras/q_commuting_polynomials.py b/src/sage/algebras/q_commuting_polynomials.py new file mode 100644 index 00000000000..c948d4e8b20 --- /dev/null +++ b/src/sage/algebras/q_commuting_polynomials.py @@ -0,0 +1,276 @@ +r""" +`q`-Commuting Polynomials + +AUTHORS: + +- Travis Scrimshaw (2022-08-23): Initial version +""" + +# **************************************************************************** +# Copyright (C) 2022 Travis Scrimshaw +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.sets.family import Family +from sage.rings.infinity import infinity +from sage.categories.algebras import Algebras +from sage.combinat.free_module import CombinatorialFreeModule +from sage.monoids.free_abelian_monoid import FreeAbelianMonoid, FreeAbelianMonoid_class + +class qCommutingPolynomials(CombinatorialFreeModule): + r""" + The algebra of `q`-commuting polynomials. + + Let `R` be a commutative ring, and fix an element `q \in R`. We say two + distinct variables `x` and `y` `q`-*commute* if they satisfy the relation + + .. MATH:: + + x y = q \cdot y x. + + These form a graded `R`-algebra with a natural basis given by monomials + written in increasing order. These then satisfy a `q`-analog of the + classical binomial coefficient theorem: + + .. MATH:: + + (x + y)^n = \sum_{k=0}^n \binom{n}{k}_q x^k y^{n-k}. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q) + + We verify the `q`-binomial theorem:: + + sage: f = (x + y)^10 + sage: all(f[b] == q_binomial(10, b.list()[0]) for b in f.support()) + True + """ + @staticmethod + def __classcall_private__(cls, q, n=None, base_ring=None, names=None): + r""" + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R1. = algebras.qCommutingPolynomials(q) + sage: R2 = algebras.qCommutingPolynomials(q, base_ring=q.parent(), names='x,y,z') + sage: R3 = algebras.qCommutingPolynomials(q, names=['x', 'y', 'z']) + sage: R1 is R2 is R3 + True + """ + if base_ring is not None: + q = base_ring(q) + + if isinstance(n, FreeAbelianMonoid_class): + indices = n + else: + indices = FreeAbelianMonoid(n, names) + return super().__classcall__(cls, q, indices) + + def __init__(self, q, indices): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q) + sage: TestSuite(R).run() + """ + self._q = q + base_ring = q.parent() + category = Algebras(base_ring).WithBasis().Graded() + CombinatorialFreeModule.__init__(self, base_ring, indices, + bracket=False, prefix='', + sorting_key=qCommutingPolynomials._term_key, + names=indices.variable_names(), category=category) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q) + sage: R + q-commuting polynomial ring in x, y, z over Fraction Field of + Univariate Polynomial Ring in q over Integer Ring + """ + names = ", ".join(self.variable_names()) + return "{}-commuting polynomial ring in {} over {}".format(self._q, names, self.base_ring()) + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q) + sage: latex(R) + \mathrm{Frac}(\Bold{Z}[q])[x, y, z]_{q} + """ + from sage.misc.latex import latex + names = ", ".join(self.variable_names()) + return "{}[{}]_{{{}}}".format(latex(self.base_ring()), names, self._q) + + @staticmethod + def _term_key(x): + r""" + Compute a key for ``x`` for comparisons. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q) + sage: elt = (x*y^3*z^2).leading_support() + sage: R._term_key(elt) + (6, [2, 3, 1]) + """ + L = x.list() + L.reverse() + return (sum(L), L) + + def gen(self, i): + """ + Return the ``i``-generator of ``self``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q) + sage: R.gen(0) + x + sage: R.gen(2) + z + """ + return self.monomial(self._indices.gen(i)) + + @cached_method + def gens(self): + r""" + Return the generators of ``self``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q) + sage: R.gens() + (x, y, z) + """ + return tuple([self.monomial(g) for g in self._indices.gens()]) + + @cached_method + def algebra_generators(self): + r""" + Return the algebra generators of ``self``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q) + sage: R.algebra_generators() + Finite family {'x': x, 'y': y, 'z': z} + """ + d = {v: self.gen(i) for i,v in enumerate(self.variable_names())} + return Family(self.variable_names(), d.__getitem__, name="generator") + + @cached_method + def one_basis(self): + r""" + Return the basis index of the element `1`. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q) + sage: R.one_basis() + 1 + """ + return self._indices.one() + + def degree_on_basis(self, m): + r""" + Return the degree of the monomial index by ``m``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q) + sage: R.degree_on_basis(R.one_basis()) + 0 + sage: f = (x + y)^3 + z^3 + sage: f.degree() + 3 + """ + return sum(m.list()) + + def dimension(self): + r""" + Return the dimension of ``self``, which is `\infty`. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q) + sage: R.dimension() + +Infinity + """ + return infinity + + @cached_method + def product_on_basis(self, x, y): + r""" + Return the product of two monomials given by ``x`` and ``y``. + + EXAMPLES:: + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q) + sage: R.product_on_basis(x.leading_support(), y.leading_support()) + x*y + sage: R.product_on_basis(y.leading_support(), x.leading_support()) + q*x*y + + sage: x * y + x*y + sage: y * x + q*x*y + sage: y^2 * x + q^2*x*y^2 + sage: y * x^2 + q^2*x^2*y + sage: x * y * x + q*x^2*y + sage: y^2 * x^2 + q^4*x^2*y^2 + sage: (x + y)^2 + x^2 + (q+1)*x*y + y^2 + sage: (x + y)^3 + x^3 + (q^2+q+1)*x^2*y + (q^2+q+1)*x*y^2 + y^3 + sage: (x + y)^4 + x^4 + (q^3+q^2+q+1)*x^3*y + (q^4+q^3+2*q^2+q+1)*x^2*y^2 + (q^3+q^2+q+1)*x*y^3 + y^4 + """ + # Special case for multiplying by 1 + if x == self.one_basis(): + return self.monomial(y) + if y == self.one_basis(): + return self.monomial(x) + + Lx = x.list() + Ly = y.list() + + # This could be made more efficient + qpow = sum(exp * sum(Ly[:i]) for i,exp in enumerate(Lx)) + return self.term(x * y, self._q ** qpow) + From 1e55368b8e961c568b41ec439ecc6919e55bb267 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 23 Aug 2022 16:55:55 +0900 Subject: [PATCH 225/742] Almost done with refactoring code to separate free module cases. --- src/sage/homology/free_resolution.py | 651 +++++++++++------- src/sage/homology/graded_resolution.py | 532 ++++++++------ src/sage/modules/free_module.py | 8 +- src/sage/rings/ideal.py | 8 +- .../polynomial/multi_polynomial_ideal.py | 8 +- 5 files changed, 721 insertions(+), 486 deletions(-) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 2f9ad448baa..efa327d051c 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -22,16 +22,15 @@ S^1 <-- S^3 <-- S^2 <-- 0 sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = FreeResolution(I) + sage: r = I.free_resolution() sage: r S^1 <-- S^3 <-- S^2 <-- 0 :: - sage: from sage.homology.graded_resolution import GradedFreeResolution sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) + sage: r = I.graded_free_resolution() sage: r S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 @@ -39,7 +38,7 @@ sage: R. = QQ[] sage: I = R.ideal([y*z - x*w, y^3 - x^2*z, x*z^2 - y^2*w, z^3 - y*w^2]) - sage: r = FreeResolution(I) + sage: r = I.free_resolution() sage: r S^1 <-- S^4 <-- S^4 <-- S^1 <-- 0 sage: len(r) @@ -69,6 +68,9 @@ from sage.libs.singular.singular import si2sa_resolution from sage.libs.singular.function import singular_function from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.abstract_method import abstract_method +from sage.structure.sage_object import SageObject +from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.structure.element import Matrix from sage.categories.principal_ideal_domains import PrincipalIdealDomains from sage.categories.integral_domains import IntegralDomains @@ -77,15 +79,12 @@ from sage.modules.free_module import Module_free_ambient, FreeModule_generic from sage.rings.ideal import Ideal_generic -from sage.structure.sage_object import SageObject - +from copy import copy -class FreeResolution_generic(SageObject): - r""" - Generic base class of finite free resolutions. - A subclass must provide a ``_maps`` attribute that contains a list of the - maps defining the resolution. +class FreeResolution(SageObject, metaclass=ClasscallMetaclass): + """ + Abstract base class for free resolutions. The matrix at index `i` in the list defines the differential map from `(i + 1)`-th free module to the `i`-th free module over the base ring by @@ -95,35 +94,96 @@ class FreeResolution_generic(SageObject): Note that the first matrix in the list defines the differential map at homological index `1`. + """ + @staticmethod + def __classcall_private__(cls, module, degrees=None, shifts=None, name='S', **kwds): + """ + Dispatch to the correct constructor. - A subclass can define ``_initial_differential`` attribute that - contains the `0`-th differential map whose codomain is the target - of the free resolution. + TESTS:: - EXAMPLES:: + sage: from sage.homology.free_resolution import FreeResolution + sage: S. = PolynomialRing(QQ) + sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() + sage: r = FreeResolution(m, name='S') + sage: type(r) + - sage: from sage.homology.free_resolution import FreeResolution - sage: S. = PolynomialRing(QQ) - sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = FreeResolution(I) - sage: r.differential(0) - Coercion map: - From: Ambient free module of rank 1 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field - To: Quotient module by Submodule of Ambient free module of rank 1 - over the integral domain Multivariate Polynomial Ring in x, y, z, w over Rational Field - Generated by the rows of the matrix: - [-z^2 + y*w] - [ y*z - x*w] - [-y^2 + x*z] - """ - def __init__(self, base_ring, name='F'): + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: type(r) + + + sage: R. = QQ[] + sage: M = R^3 + sage: v = M([x^2, 2*x^2, 3*x^2]) + sage: w = M([0, x, 2*x]) + sage: S = M.submodule([v, w]) + sage: r = FreeResolution(S) + sage: type(r) + + + sage: I = R.ideal([x^4 + 3*x^2 + 2]) + sage: r = FreeResolution(I) + sage: type(r) + + """ + # The module might still be free even if is_free_module is False. + # This is just to handle the cases when we trivially know it is. + is_free_module = False + if isinstance(module, Ideal_generic): + S = module.ring() + if len(module.gens()) == 1 and S in IntegralDomains(): + is_free_module = True + elif isinstance(module, Module_free_ambient): + S = module.base_ring() + if (S in PrincipalIdealDomains() + or isinstance(module, FreeModule_generic)): + is_free_module = True + elif isinstance(module, Matrix): + S = module.base_ring() + if S in PrincipalIdealDomains(): + module = module.echelon_form() + if module.nrows() > module.rank(): + module = module.submatrix(nrows=module.rank()) + module.set_immutable() + is_free_module = True + if not module.is_immutable(): + # We need to make an immutable copy of the matrix + module = copy(module) + module.set_immutable() + else: + raise TypeError('no module, matrix, or ideal') + + if not is_free_module: + from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if not isinstance(S, MPolynomialRing_libsingular): + raise NotImplementedError("the ring must be a free module or a polynomial ring that can be constructed in Singular") + + if degrees is not None or shifts is not None: + # We are computing a graded resolution + from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular + return GradedFiniteFreeResolution_singular(module, degrees=degrees, shifts=shifts, name=name, **kwds) + + return FiniteFreeResolution_singular(module, name=name, **kwds) + + # Otherwise we know it is a free module + + if degrees is not None or shifts is not None: + # We are computing a graded resolution + from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + return GradedFiniteFreeResolution_free_module(module, degrees=degrees, shifts=shifts, name=name, **kwds) + + return FiniteFreeResolution_free_module(module, name=name, **kwds) + + def __init__(self, module, name='S', **kwds): """ Initialize. INPUT: - ``base_ring`` -- a ring + - ``name`` -- (default: ``'S'``) the name of the ring for printing TESTS:: @@ -133,47 +193,32 @@ def __init__(self, base_ring, name='F'): sage: r = FreeResolution(m1, name='S') sage: TestSuite(r).run(skip=['_test_pickling']) """ - self._base_ring = base_ring + if isinstance(module, Ideal_generic): + S = module.ring() + else: #if isinstance(module, (Module_free_ambient, Matrix)): + S = module.base_ring() + + self._base_ring = S self._name = name + self._module = module - @lazy_attribute - def _length(self): - """ - The length of ``self``. + def _repr_(self): + r""" + Return a string representation of ``self``. TESTS:: sage: from sage.homology.free_resolution import FreeResolution sage: S. = PolynomialRing(QQ) - sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = FreeResolution(I) - sage: r._length - 2 - """ - return len(self._maps) - - def _repr_(self): - """ - Return the string form of this resolution. - - INPUT: - - - ``i`` -- a positive integer - - EXAMPLES:: - - sage: from sage.homology.graded_resolution import GradedFreeResolution - sage: S. = PolynomialRing(QQ) - sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) - sage: r - S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) + sage: r = FreeResolution(m1, name='S') + sage: print(FreeResolution._repr_(r)) + Free resolution with initial map: + [z^2 - y*w, y*z - x*w, y^2 - x*z] """ - s = self._repr_module(0) - for i in range(1, self._length + 1): - s += ' <-- ' + self._repr_module(i) - s += ' <-- 0' - return s + if isinstance(self._module, Matrix): + return f"Free resolution with inital map:\n{self._module}" + return f"Free resolution of {self._module}" def _repr_module(self, i): r""" @@ -208,6 +253,145 @@ def _repr_module(self, i): s = '0' return s + def _m(self): + r""" + The defining matrix or ideal of the module defining ``self``. + + TESTS:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r._m() + Ideal (-z^2 + y*w, y*z - x*w, -y^2 + x*z) of Multivariate Polynomial Ring in x, y, z, w over Rational Field + + sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() + sage: r = FreeResolution(m, name='S') + sage: r._m() + [z^2 - y*w y*z - x*w y^2 - x*z] + + sage: M = m.image() + sage: r = FreeResolution(M, name='S') + sage: r._m() + [z^2 - y*w y*z - x*w y^2 - x*z] + """ + if isinstance(self._module, Ideal_generic): + return self._module + if isinstance(self._module, Module_free_ambient): + return self._module.matrix().transpose() + if isinstance(self._module, Matrix): + return self._module.transpose() + raise ValueError("unable to create a matrix/ideal to build the resolution") + + @abstract_method + def differential(self, i): + r""" + Return the ``i``-th differential map. + + INPUT: + + - ``i`` -- a positive integer + + TESTS:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: S. = PolynomialRing(QQ) + sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) + sage: r = FreeResolution(m1, name='S') + sage: FreeResolution.differiental(r, 1) + Traceback (most recent call last): + ... + AttributeError: type object 'FreeResolution' has no attribute 'differiental' + """ + + def target(self): + r""" + Return the codomain of the ``0``-th differential map. + + EXAMPLES:: + + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = I.graded_free_resolution() + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: r.target() + Quotient module by Submodule of Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + return self.differential(0).codomain() + +class FiniteFreeResolution(FreeResolution): + r""" + Finite free resolutions. + + A subclass must provide a ``_maps`` attribute that contains a list of the + maps defining the resolution. + + A subclass can define ``_initial_differential`` attribute that + contains the `0`-th differential map whose codomain is the target + of the free resolution. + + EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r.differential(0) + Coercion map: + From: Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + To: Quotient module by Submodule of Ambient free module of rank 1 + over the integral domain Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + @lazy_attribute + def _length(self): + """ + The length of ``self``. + + TESTS:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r._length + 2 + """ + return len(self._maps) + + def _repr_(self): + """ + Return the string form of this resolution. + + INPUT: + + - ``i`` -- a positive integer + + EXAMPLES:: + + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = I.graded_free_resolution() + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + """ + s = self._repr_module(0) + for i in range(1, self._length + 1): + s += ' <-- ' + self._repr_module(i) + s += ' <-- 0' + return s + def __len__(self): r""" Return the length of this resolution. @@ -216,10 +400,9 @@ def __len__(self): EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFreeResolution sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) + sage: r = I.graded_free_resolution() sage: r S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 sage: len(r) @@ -237,10 +420,9 @@ def __getitem__(self, i): EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFreeResolution sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) + sage: r = I.graded_free_resolution() sage: r S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 sage: r.target() @@ -250,7 +432,7 @@ def __getitem__(self, i): [-z^2 + y*w] [ y*z - x*w] [-y^2 + x*z] - """ + """ if i < 0: raise IndexError('invalid index') elif i > self._length: @@ -263,7 +445,7 @@ def __getitem__(self, i): def differential(self, i): r""" - Return the matrix representing the ``i``-th differential map. + Return the ``i``-th differential map. INPUT: @@ -271,10 +453,9 @@ def differential(self, i): EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFreeResolution sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) + sage: r = I.graded_free_resolution() sage: r S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 sage: r.differential(3) @@ -332,28 +513,6 @@ def differential(self, i): m = s.hom(self._maps[i - 1], t, side='right') return m - def target(self): - r""" - Return the codomain of the ``0``-th differential map. - - EXAMPLES:: - - sage: from sage.homology.graded_resolution import GradedFreeResolution - sage: S. = PolynomialRing(QQ) - sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) - sage: r - S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 - sage: r.target() - Quotient module by Submodule of Ambient free module of rank 1 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field - Generated by the rows of the matrix: - [-z^2 + y*w] - [ y*z - x*w] - [-y^2 + x*z] - """ - return self.differential(0).codomain() - def matrix(self, i): r""" Return the matrix representing the ``i``-th differential map. @@ -364,10 +523,9 @@ def matrix(self, i): EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFreeResolution sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) + sage: r = I.graded_free_resolution() sage: r S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 sage: r.matrix(3) @@ -394,10 +552,9 @@ def chain_complex(self): EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFreeResolution sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) + sage: r = I.graded_free_resolution() sage: unicode_art(r.chain_complex()) ⎛-y x⎞ ⎜ z -y⎟ @@ -410,20 +567,149 @@ def chain_complex(self): mats[i] = self.matrix(i) return ChainComplex(mats, degree_of_differential=-1) + @lazy_attribute + def _initial_differential(self): + r""" + Define the `0`-th differential map of this resolution. + + EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r._initial_differential + Coercion map: + From: Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + To: Quotient module by Submodule of Ambient free module of rank 1 + over the integral domain Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + ideal = self._module + if isinstance(ideal, Ideal_generic): + S = ideal.ring() + M = FreeModule(S, 1) + N = M.submodule([vector([g]) for g in ideal.gens()]) + elif isinstance(ideal, Module_free_ambient): + S = ideal.base_ring() + M = ideal.ambient_module() + N = ideal + elif isinstance(ideal, Matrix): + S = ideal.base_ring() + N = ideal.row_space() + M = N.ambient_module() + Q = M.quotient(N) + return Q.coerce_map_from(M) -class FreeResolution(FreeResolution_generic): +class FiniteFreeResolution_free_module(FiniteFreeResolution): + r""" + Free resolutions of a free module. + + INPUT: + + - ``module`` -- a free module or ideal over a PID + - ``name`` -- the name of the base ring + + EXAMPLES:: + + sage: R. = QQ[] + sage: M = R^3 + sage: v = M([x^2, 2*x^2, 3*x^2]) + sage: w = M([0, x, 2*x]) + sage: S = M.submodule([v, w]) + sage: S + Free module of degree 3 and rank 2 over Univariate Polynomial Ring in x over Rational Field + Echelon basis matrix: + [ x^2 2*x^2 3*x^2] + [ 0 x 2*x] + sage: res = S.free_resolution() + sage: res + S^3 <-- S^2 <-- 0 + sage: ascii_art(res.chain_complex()) + [ x^2 0] + [2*x^2 x] + [3*x^2 2*x] + 0 <-- C_0 <-------------- C_1 <-- 0 + + sage: R. = PolynomialRing(QQ) + sage: I = R.ideal([x^4 + 3*x^2 + 2]) + sage: res = I.free_resolution() + sage: res + S^1 <-- S^1 <-- 0 + """ + @lazy_attribute + def _maps(self): + r""" + Return the maps that define ``self``. + + EXAMPLES:: + + sage: R. = QQ[] + sage: M = R^3 + sage: v = M([x^2, 2*x^2, 3*x^2]) + sage: w = M([0, x, 2*x]) + sage: S = M.submodule([v, w]) + sage: res = S.free_resolution() + sage: res + S^3 <-- S^2 <-- 0 + sage: ascii_art(res.chain_complex()) + [ x^2 0] + [2*x^2 x] + [3*x^2 2*x] + 0 <-- C_0 <-------------- C_1 <-- 0 + sage: res._maps + [ + [ x^2 0] + [2*x^2 x] + [3*x^2 2*x] + ] + + sage: R. = PolynomialRing(QQ) + sage: I = R.ideal([x^4 + 3*x^2 + 2]) + sage: res = I.free_resolution() + sage: res._maps + [[x^4 + 3*x^2 + 2]] + + An overdetermined system over a PID:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: R. = QQ[] + sage: M = matrix([[x^2, 2], + ....: [3*x^2, 5], + ....: [5*x^2, 4]]) + sage: res = FreeResolution(M) + sage: res + S^2 <-- S^2 <-- 0 + sage: res._m() + [ x^2 3*x^2 5*x^2] + [ 2 5 4] + sage: res._maps + [ + [x^2 0] + [ 0 1] + ] + """ + if isinstance(self._module, Ideal_generic): + from sage.matrix.constructor import matrix + return [matrix([[self._module.gen()]])] + return [self._m()] + +class FiniteFreeResolution_singular(FiniteFreeResolution): r""" Minimal free resolutions of ideals or submodules of free modules - of multivariate polynomial rings. + of multivariate polynomial rings implemented in Singular. INPUT: - ``module`` -- a submodule of a free module `M` of rank `n` over `S` or an ideal of a multi-variate polynomial ring - - - ``name`` -- a string; name of the base ring - - - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` + - ``name`` -- string (optional); name of the base ring + - ``algorithm`` -- (default: ``'heuristic'``) Singular algorithm + to compute a resolution of ``ideal`` OUTPUT: a minimal free resolution of the ideal @@ -496,8 +782,8 @@ class FreeResolution(FreeResolution_generic): [-y*z + x*w] [ z^2 - y*w] """ - def __init__(self, module, name='S', algorithm='heuristic'): - """ + def __init__(self, module, name='S', algorithm='heuristic', **kwds): + r""" Initialize. TESTS:: @@ -525,84 +811,10 @@ def __init__(self, module, name='S', algorithm='heuristic'): sage: FreeResolution(Q.ideal([xb])) # has torsion Traceback (most recent call last): ... - NotImplementedError: the ring must be a polynomial ring that can be constructed in Singular - - An overdetermined system over a PID:: - - sage: M = matrix([[x^2, 2], - ....: [3*x^2, 5], - ....: [5*x^2, 4]]) - sage: res = FreeResolution(M) - sage: res - S^2 <-- S^2 <-- 0 - sage: res._m() - [ x^2 3*x^2 5*x^2] - [ 2 5 4] - sage: res._maps - [ - [x^2 0] - [ 0 1] - ] + NotImplementedError: the ring must be a free module or a polynomial ring that can be constructed in Singular """ - # The module might still be free even if _is_free_module is False. - # This is just to handle the cases when we trivially know it is. - self._is_free_module = False - if isinstance(module, Ideal_generic): - S = module.ring() - if len(module.gens()) == 1 and S in IntegralDomains(): - self._is_free_module = True - elif isinstance(module, Module_free_ambient): - S = module.base_ring() - self._is_free_module = (S in PrincipalIdealDomains() - or isinstance(module, FreeModule_generic)) - elif isinstance(module, Matrix): - S = module.base_ring() - if S in PrincipalIdealDomains(): - self._is_free_module = True - module = module.echelon_form() - if module.nrows() > module.rank(): - module = module.submatrix(nrows=module.rank()) - else: - raise TypeError('no module, matrix, or ideal') - - if not self._is_free_module: - from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular - if not isinstance(S, MPolynomialRing_libsingular): - raise NotImplementedError("the ring must be a polynomial ring that can be constructed in Singular") - - self._module = module self._algorithm = algorithm - super().__init__(S, name=name) - - def _m(self): - r""" - The defining module of ``self``. - - TESTS:: - - sage: from sage.homology.free_resolution import FreeResolution - sage: S. = PolynomialRing(QQ) - sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = FreeResolution(I) - sage: r._m() - Ideal (-z^2 + y*w, y*z - x*w, -y^2 + x*z) of Multivariate Polynomial Ring in x, y, z, w over Rational Field - - sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() - sage: r = FreeResolution(m, name='S') - sage: r._m() - [z^2 - y*w y*z - x*w y^2 - x*z] - - sage: M = m.image() - sage: r = FreeResolution(M, name='S') - sage: r._m() - [z^2 - y*w y*z - x*w y^2 - x*z] - """ - if isinstance(self._module, Ideal_generic): - return self._module - if isinstance(self._module, Module_free_ambient): - return self._module.matrix().transpose() - if isinstance(self._module, Matrix): - return self._module.transpose() + super().__init__(module, name=name, **kwds) @lazy_attribute def _maps(self): @@ -621,44 +833,7 @@ def _maps(self): [ z -y] [z^2 - y*w y*z - x*w y^2 - x*z], [-w z] ] - - sage: R. = QQ[] - sage: M = R^3 - sage: v = M([x^2, 2*x^2, 3*x^2]) - sage: w = M([0, x, 2*x]) - sage: S = M.submodule([v, w]) - sage: S - Free module of degree 3 and rank 2 over Univariate Polynomial Ring in x over Rational Field - Echelon basis matrix: - [ x^2 2*x^2 3*x^2] - [ 0 x 2*x] - sage: res = S.free_resolution() - sage: res - S^3 <-- S^2 <-- 0 - sage: ascii_art(res.chain_complex()) - [ x^2 0] - [2*x^2 x] - [3*x^2 2*x] - 0 <-- C_0 <-------------- C_1 <-- 0 - sage: res._maps - [ - [ x^2 0] - [2*x^2 x] - [3*x^2 2*x] - ] - - sage: R. = PolynomialRing(QQ) - sage: I = R.ideal([x^4 + 3*x^2 + 2]) - sage: res = I.free_resolution() - sage: res._maps - [[x^4 + 3*x^2 + 2]] """ - if self._is_free_module: - if isinstance(self._module, Ideal_generic): - from sage.matrix.constructor import matrix - return [matrix([[self._module.gen()]])] - return [self._m()] - # This ensures the first component of the Singular resolution to be a # module, like the later components. This is important when the # components are converted to Sage modules. @@ -685,41 +860,3 @@ def _maps(self): return si2sa_resolution(r) - @lazy_attribute - def _initial_differential(self): - r""" - Define the `0`-th differential map of this resolution. - - EXAMPLES:: - - sage: from sage.homology.free_resolution import FreeResolution - sage: S. = PolynomialRing(QQ) - sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = FreeResolution(I) - sage: r._initial_differential - Coercion map: - From: Ambient free module of rank 1 over the integral domain - Multivariate Polynomial Ring in x, y, z, w over Rational Field - To: Quotient module by Submodule of Ambient free module of rank 1 - over the integral domain Multivariate Polynomial Ring in x, y, z, w over Rational Field - Generated by the rows of the matrix: - [-z^2 + y*w] - [ y*z - x*w] - [-y^2 + x*z] - """ - ideal = self._module - if isinstance(ideal, Ideal_generic): - S = ideal.ring() - M = FreeModule(S, 1) - N = M.submodule([vector([g]) for g in ideal.gens()]) - elif isinstance(ideal, Module_free_ambient): - S = ideal.base_ring() - M = ideal.ambient_module() - N = ideal - elif isinstance(ideal, Matrix): - S = ideal.base_ring() - N = ideal.row_space() - M = N.ambient_module() - Q = M.quotient(N) - return Q.coerce_map_from(M) - diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index bc30e61ef6e..d9d64062a63 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -7,17 +7,17 @@ EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I, algorithm='minimal') + sage: r = GradedFiniteFreeResolution_singular(I, algorithm='minimal') sage: r S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 - sage: GradedFreeResolution(I, algorithm='shreyer') + sage: GradedFiniteFreeResolution_singular(I, algorithm='shreyer') S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 - sage: GradedFreeResolution(I, algorithm='standard') + sage: GradedFiniteFreeResolution_singular(I, algorithm='standard') S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 - sage: GradedFreeResolution(I, algorithm='heuristic') + sage: GradedFiniteFreeResolution_singular(I, algorithm='heuristic') S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 :: @@ -39,7 +39,7 @@ [ y -z w] [ x -y z] sage: m = d.image() - sage: GradedFreeResolution(m, shifts=(2,2,2)) + sage: GradedFiniteFreeResolution_singular(m, shifts=(2,2,2)) S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 An example of multigraded resolution from Example 9.1 of [MilStu2005]_:: @@ -51,7 +51,7 @@ Ideal (c^2 - b*d, b*c - a*d, b^2 - a*c) of Multivariate Polynomial Ring in a, b, c, d over Rational Field sage: P3 = ProjectiveSpace(S) sage: C = P3.subscheme(I) # twisted cubic curve - sage: r = GradedFreeResolution(I, degrees=[(1,0), (1,1), (1,2), (1,3)]) + sage: r = GradedFiniteFreeResolution_singular(I, degrees=[(1,0), (1,1), (1,2), (1,3)]) sage: r S((0, 0)) <-- S((-2, -4))⊕S((-2, -3))⊕S((-2, -2)) <-- S((-3, -5))⊕S((-3, -4)) <-- 0 sage: r.K_polynomial(names='s,t') @@ -83,102 +83,54 @@ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.ideal import Ideal_generic -from sage.homology.free_resolution import FreeResolution +from sage.homology.free_resolution import (FiniteFreeResolution, + FiniteFreeResolution_free_module, + FiniteFreeResolution_singular) -class GradedFreeResolution(FreeResolution): +class GradedFiniteFreeResolution(FiniteFreeResolution): r""" - Graded free resolutions of ideals of multivariate polynomial rings. + Graded finite free resolutions. INPUT: - ``module`` -- a homogeneous submodule of a free module `M` of rank `n` over `S` or a homogeneous ideal of a multivariate polynomial ring `S` - - ``degrees`` -- (default: a list with all entries `1`) a list of integers or integer vectors giving degrees of variables of `S` - - ``shifts`` -- a list of integers or integer vectors giving shifts of degrees of `n` summands of the free module `M`; this is a list of zero degrees of length `n` by default - - ``name`` -- a string; name of the base ring - - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` - - If ``module`` is an ideal of `S`, it is considered as a submodule of a - free module of rank `1` over `S`. - - The degrees given to the variables of `S` are integers or integer vectors of - the same length. In the latter case, `S` is said to be multigraded, and the - resolution is a multigraded free resolution. The standard grading where all - variables have degree `1` is used if the degrees are not specified. - - A summand of the graded free module `M` is a shifted (or twisted) module of - rank one over `S`, denoted `S(-d)` with shift `d`. - - The computation of the resolution is done by using ``libSingular``. - Different Singular algorithms can be chosen for best performance. - - OUTPUT: a graded minimal free resolution of ``ideal`` - - The available algorithms and the corresponding Singular commands are shown - below: - - ============= ============================ - algorithm Singular commands - ============= ============================ - ``minimal`` ``mres(ideal)`` - ``shreyer`` ``minres(sres(std(ideal)))`` - ``standard`` ``minres(nres(std(ideal)))`` - ``heuristic`` ``minres(res(std(ideal)))`` - ============= ============================ - .. WARNING:: This does not check that the module is homogeneous. - - EXAMPLES:: - - sage: from sage.homology.graded_resolution import GradedFreeResolution - sage: S. = PolynomialRing(QQ) - sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) - sage: r - S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 - sage: len(r) - 2 - - sage: I = S.ideal([z^2 - y*w, y*z - x*w, y - x]) - sage: I.is_homogeneous() - True - sage: R = GradedFreeResolution(I) - sage: R - S(0) <-- S(-1)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3)⊕S(-4) <-- S(-5) <-- 0 """ - def __init__(self, module, degrees=None, shifts=None, name='S', algorithm='heuristic'): + def __init__(self, module, degrees=None, shifts=None, name='S', **kwds): """ Initialize. TESTS:: - sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) + sage: r = GradedFiniteFreeResolution_singular(I) sage: TestSuite(r).run(skip=['_test_pickling']) An overdetermined system over a PID:: + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module sage: M = matrix([[x^2, 2], ....: [3*x^2, 5], ....: [5*x^2, 4]]) - sage: res = GradedFreeResolution(M) + sage: res = GradedFiniteFreeResolution_free_module(M) sage: res S(0)⊕S(0) <-- S(-2)⊕S(0) <-- 0 sage: res._res_shifts [[2, 0]] """ - super().__init__(module, name=name, algorithm=algorithm) + super().__init__(module, name=name, **kwds) nvars = self._base_ring.ngens() @@ -187,8 +139,6 @@ def __init__(self, module, degrees=None, shifts=None, name='S', algorithm='heuri if len(degrees) != nvars: raise ValueError('the length of degrees does not match the number of generators') - if self._is_free_module and len(degrees) > 1 and any(d != 1 for d in degrees): - raise NotImplementedError("only the natural grading supported when more than one generator") if degrees[0] in ZZ: zero_deg = 0 @@ -213,154 +163,14 @@ def __init__(self, module, degrees=None, shifts=None, name='S', algorithm='heuri self._multigrade = multigrade self._zero_deg = zero_deg - @lazy_attribute - def _maps(self): - """ - The maps that define ``self``. - - This also sets the attribute ``_res_shifts``. - - TESTS:: - - sage: from sage.homology.graded_resolution import GradedFreeResolution - sage: S. = PolynomialRing(QQ) - sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) - sage: r._maps - [ - [-y x] - [ z -y] - [z^2 - y*w y*z - x*w y^2 - x*z], [-w z] - ] - sage: r._res_shifts - [[2, 2, 2], [3, 3]] - - sage: R. = QQ[] - sage: M = matrix([[x^3, 3*x^3, 5*x^3], - ....: [0, x, 2*x]]) - sage: res = GradedFreeResolution(M) - sage: res - S(0)⊕S(0)⊕S(0) <-- S(-3)⊕S(-1) <-- 0 - sage: res._maps - [ - [ x^3 0] - [3*x^3 x] - [5*x^3 2*x] - ] - sage: res._res_shifts - [[3, 1]] - - sage: M = matrix([[x^2, 2], - ....: [3*x^2, 5], - ....: [5*x^2, 4]]) - sage: res = GradedFreeResolution(M) - sage: res - S(0)⊕S(0) <-- S(-2)⊕S(0) <-- 0 - sage: res._res_shifts - [[2, 0]] - - sage: I = R.ideal([x^4]) - sage: res = I.graded_free_resolution(shifts=[1], degrees=[2]) - sage: res - S(-1) <-- S(-9) <-- 0 - sage: res._maps - [[x^4]] - sage: res._res_shifts - [[9]] - """ - if self._is_free_module: - - def compute_degree(base, i): - """ - Compute the degree by ``base * deg + shift``, - where ``*`` is entry-wise multiplication, ``deg`` and - ``shift`` are the ``i``-th index. - """ - deg = self._degrees[0] - shift = self._shifts[i] - if self._multigrade: - return vector([val * d + s for val, d, s in zip(base, deg, shift)]) - return base * deg + shift - - if isinstance(self._module, Ideal_generic): - from sage.matrix.constructor import matrix - val = self._module.gen(0) - self._res_shifts = [[compute_degree(val.degree(), 0)]] - return [matrix([[val]])] - - M = self._m() - - def find_deg(i): - for j in range(M.nrows()): - ret = M[j,i].degree() - if ret != -1: - return ret - raise NotImplementedError("a generator maps to 0") - self._res_shifts = [[compute_degree(find_deg(i), i) - for i in range(M.ncols())]] - return [M] - - #cdef int i, j, k, ncols, nrows - #cdef list res_shifts, prev_shifts, new_shifts - - # This ensures the first component of the Singular resolution to be a - # module, like the later components. This is important when the - # components are converted to Sage modules. - module = singular_function("module") - mod = module(self._m()) - - if self._algorithm == 'minimal': - mres = singular_function('mres') # syzygy method - r = mres(mod, 0) - elif self._algorithm == 'shreyer': - std = singular_function('std') - sres = singular_function('sres') # Shreyer method - minres = singular_function('minres') - r = minres(sres(std(mod), 0)) - elif self._algorithm == 'standard': - nres = singular_function('nres') # standard basis method - minres = singular_function('minres') - r = minres(nres(mod, 0)) - elif self._algorithm == 'heuristic': - std = singular_function('std') - res = singular_function('res') # heuristic method - minres = singular_function('minres') - r = minres(res(std(mod), 0)) - - res_mats, res_degs = si2sa_resolution_graded(r, self._degrees) - - # compute shifts of free modules in the resolution - res_shifts = [] - prev_shifts = list(self._shifts) - for k in range(len(res_degs)): - new_shifts = [] - degs = res_degs[k] - ncols = len(degs) - for j in range(ncols): - col = degs[j] - nrows = len(col) - # should be enough to compute the new shifts - # from any one entry of the column vector - for i in range(nrows): - d = col[i] - if d is not None: - e = prev_shifts[i] - new_shifts.append(d + e) - break - res_shifts.append(new_shifts) - prev_shifts = new_shifts - - self._res_shifts = res_shifts - return res_mats - def _repr_module(self, i): """ EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) + sage: r = GradedFiniteFreeResolution_singular(I) sage: r._repr_module(0) 'S(0)' sage: r._repr_module(1) @@ -370,7 +180,7 @@ def _repr_module(self, i): sage: r._repr_module(3) '0' - sage: r = GradedFreeResolution(I, shifts=[-1]) + sage: r = GradedFiniteFreeResolution_singular(I, shifts=[-1]) sage: r._repr_module(0) 'S(1)' """ @@ -394,10 +204,10 @@ def shifts(self, i): EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) + sage: r = GradedFiniteFreeResolution_singular(I) sage: r.shifts(0) [0] sage: r.shifts(1) @@ -431,10 +241,10 @@ def betti(self, i, a=None): EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) + sage: r = GradedFiniteFreeResolution_singular(I) sage: r.betti(0) {0: 1} sage: r.betti(1) @@ -475,10 +285,10 @@ def K_polynomial(self, names=None): EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFreeResolution(I) + sage: r = GradedFiniteFreeResolution_singular(I) sage: r.K_polynomial() 2*t^3 - 3*t^2 + 1 """ @@ -505,3 +315,291 @@ def K_polynomial(self, names=None): return kpoly +class GradedFiniteFreeResolution_free_module(GradedFiniteFreeResolution, FiniteFreeResolution_free_module): + r""" + Graded free resolution of free modules. + + .. WARNING:: + + This does not check that the module is homogeneous. + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + sage: R. = QQ[] + sage: M = matrix([[x^3, 3*x^3, 5*x^3], + ....: [0, x, 2*x]]) + sage: res = GradedFiniteFreeResolution_free_module(M) + sage: res + S(0)⊕S(0)⊕S(0) <-- S(-3)⊕S(-1) <-- 0 + + sage: M = matrix([[x^2, 2], + ....: [3*x^2, 5], + ....: [5*x^2, 4]]) + sage: res = GradedFiniteFreeResolution_free_module(M) + sage: res + S(0)⊕S(0) <-- S(-2)⊕S(0) <-- 0 + """ + def __init__(self, module, degrees=None, *args, **kwds): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + sage: R. = QQ[] + sage: M = matrix([[x^3, 3*x^3, 5*x^3], + ....: [0, x, 2*x]]) + sage: res = GradedFiniteFreeResolution_free_module(M) + sage: TestSuite(res).run(skip="_test_pickling") + """ + super().__init__(module, degrees=degrees, *args, **kwds) + + if len(self._degrees) > 1 and any(d != 1 for d in self._degrees): + raise NotImplementedError("only the natural grading supported when more than one generator") + + @lazy_attribute + def _maps(self): + r""" + The maps that define ``self``. + + This also sets the attribute ``_res_shifts``. + + TESTS:: + + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + sage: R. = QQ[] + sage: M = matrix([[x^3, 3*x^3, 5*x^3], + ....: [0, x, 2*x]]) + sage: res = GradedFiniteFreeResolution_free_module(M) + sage: res + S(0)⊕S(0)⊕S(0) <-- S(-3)⊕S(-1) <-- 0 + sage: res._maps + [ + [ x^3 0] + [3*x^3 x] + [5*x^3 2*x] + ] + sage: res._res_shifts + [[3, 1]] + + sage: M = matrix([[x^2, 2], + ....: [3*x^2, 5], + ....: [5*x^2, 4]]) + sage: res = GradedFiniteFreeResolution_free_module(M) + sage: res._maps + sage: res._res_shifts + [[2, 0]] + + sage: I = R.ideal([x^4]) + sage: res = I.graded_free_resolution(shifts=[1], degrees=[2]) + sage: res + S(-1) <-- S(-9) <-- 0 + sage: res._maps + [[x^4]] + sage: res._res_shifts + [[9]] + """ + def compute_degree(base, i): + """ + Compute the degree by ``base * deg + shift``, + where ``*`` is entry-wise multiplication, ``deg`` and + ``shift`` are the ``i``-th index. + """ + deg = self._degrees[0] + shift = self._shifts[i] + if self._multigrade: + return vector([val * d + s for val, d, s in zip(base, deg, shift)]) + return base * deg + shift + + if isinstance(self._module, Ideal_generic): + from sage.matrix.constructor import matrix + val = self._module.gen(0) + self._res_shifts = [[compute_degree(val.degree(), 0)]] + return [matrix([[val]])] + + M = self._m() + + def find_deg(i): + for j in range(M.nrows()): + ret = M[j,i].degree() + if ret != -1: + return ret + raise NotImplementedError("a generator maps to 0") + self._res_shifts = [[compute_degree(find_deg(i), i) + for i in range(M.ncols())]] + return [M] + + +class GradedFiniteFreeResolution_singular(GradedFiniteFreeResolution, FiniteFreeResolution_singular): + r""" + Graded free resolutions of submodules and ideals of multivariate + polynomial rings implemented using Singular. + + INPUT: + + - ``module`` -- a homogeneous submodule of a free module `M` of rank `n` + over `S` or a homogeneous ideal of a multivariate polynomial ring `S` + + - ``degrees`` -- (default: a list with all entries `1`) a list of integers + or integer vectors giving degrees of variables of `S` + + - ``shifts`` -- a list of integers or integer vectors giving shifts of + degrees of `n` summands of the free module `M`; this is a list of zero + degrees of length `n` by default + + - ``name`` -- a string; name of the base ring + + - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` + + If ``module`` is an ideal of `S`, it is considered as a submodule of a + free module of rank `1` over `S`. + + The degrees given to the variables of `S` are integers or integer vectors of + the same length. In the latter case, `S` is said to be multigraded, and the + resolution is a multigraded free resolution. The standard grading where all + variables have degree `1` is used if the degrees are not specified. + + A summand of the graded free module `M` is a shifted (or twisted) module of + rank one over `S`, denoted `S(-d)` with shift `d`. + + The computation of the resolution is done by using ``libSingular``. + Different Singular algorithms can be chosen for best performance. + + OUTPUT: a graded minimal free resolution of ``ideal`` + + The available algorithms and the corresponding Singular commands are shown + below: + + ============= ============================ + algorithm Singular commands + ============= ============================ + ``minimal`` ``mres(ideal)`` + ``shreyer`` ``minres(sres(std(ideal)))`` + ``standard`` ``minres(nres(std(ideal)))`` + ``heuristic`` ``minres(res(std(ideal)))`` + ============= ============================ + + .. WARNING:: + + This does not check that the module is homogeneous. + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFiniteFreeResolution_singular(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: len(r) + 2 + + sage: I = S.ideal([z^2 - y*w, y*z - x*w, y - x]) + sage: I.is_homogeneous() + True + sage: R = GradedFiniteFreeResolution_singular(I) + sage: R + S(0) <-- S(-1)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3)⊕S(-4) <-- S(-5) <-- 0 + """ + def __init__(self, module, degrees=None, shifts=None, name='S', algorithm='heuristic', **kwds): + """ + Initialize. + + TESTS:: + + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFiniteFreeResolution_singular(I) + sage: TestSuite(r).run(skip=['_test_pickling']) + + An overdetermined system over a PID:: + + sage: M = matrix([[x^2, 2], + ....: [3*x^2, 5], + ....: [5*x^2, 4]]) + sage: res = GradedFiniteFreeResolution_singular(M) + sage: res + S(0)⊕S(0) <-- S(-2)⊕S(0) <-- 0 + sage: res._res_shifts + [[2, 0]] + """ + super().__init__(module, degrees=degrees, shifts=shifts, name=name, **kwds) + self._algorithm = algorithm + + @lazy_attribute + def _maps(self): + """ + The maps that define ``self``. + + This also sets the attribute ``_res_shifts``. + + TESTS:: + + sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFiniteFreeResolution_singular(I) + sage: r._maps + [ + [-y x] + [ z -y] + [z^2 - y*w y*z - x*w y^2 - x*z], [-w z] + ] + sage: r._res_shifts + [[2, 2, 2], [3, 3]] + """ + #cdef int i, j, k, ncols, nrows + #cdef list res_shifts, prev_shifts, new_shifts + + # This ensures the first component of the Singular resolution to be a + # module, like the later components. This is important when the + # components are converted to Sage modules. + module = singular_function("module") + mod = module(self._m()) + + if self._algorithm == 'minimal': + mres = singular_function('mres') # syzygy method + r = mres(mod, 0) + elif self._algorithm == 'shreyer': + std = singular_function('std') + sres = singular_function('sres') # Shreyer method + minres = singular_function('minres') + r = minres(sres(std(mod), 0)) + elif self._algorithm == 'standard': + nres = singular_function('nres') # standard basis method + minres = singular_function('minres') + r = minres(nres(mod, 0)) + elif self._algorithm == 'heuristic': + std = singular_function('std') + res = singular_function('res') # heuristic method + minres = singular_function('minres') + r = minres(res(std(mod), 0)) + + res_mats, res_degs = si2sa_resolution_graded(r, self._degrees) + + # compute shifts of free modules in the resolution + res_shifts = [] + prev_shifts = list(self._shifts) + for k in range(len(res_degs)): + new_shifts = [] + degs = res_degs[k] + ncols = len(degs) + for j in range(ncols): + col = degs[j] + nrows = len(col) + # should be enough to compute the new shifts + # from any one entry of the column vector + for i in range(nrows): + d = col[i] + if d is not None: + e = prev_shifts[i] + new_shifts.append(d + e) + break + res_shifts.append(new_shifts) + prev_shifts = new_shifts + + self._res_shifts = res_shifts + return res_mats + diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 1acf13bbb9e..b818e36ee48 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -1779,8 +1779,8 @@ def free_resolution(self, *args, **kwds): [ z x*z] 0 <-- C_0 <-------------- C_1 <-- 0 """ - from sage.homology.free_resolution import FreeResolution - return FreeResolution(self, *args, **kwds) + from sage.homology.free_resolution import FiniteFreeResolution_free_module + return FiniteFreeResolution_free_module(self, *args, **kwds) def graded_free_resolution(self, *args, **kwds): r""" @@ -1803,8 +1803,8 @@ def graded_free_resolution(self, *args, **kwds): sage: N.graded_free_resolution(degrees=[2, 1, 3], shifts=[2, 3]) S(-2)⊕S(-3) <-- S(-6)⊕S(-8) <-- 0 """ - from sage.homology.graded_resolution import GradedFreeResolution - return GradedFreeResolution(self, *args, **kwds) + from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + return GradedFiniteFreeResolution_free_module(self, *args, **kwds) class FreeModule_generic(Module_free_ambient): diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 4ca750e6909..e1bce143122 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -1217,8 +1217,8 @@ def free_resolution(self, *args, **kwds): sage: I.free_resolution() S^1 <-- S^1 <-- 0 """ - from sage.homology.free_resolution import FreeResolution - return FreeResolution(self, *args, **kwds) + from sage.homology.free_resolution import FiniteFreeResolution_free_module + return FiniteFreeResolution_free_module(self, *args, **kwds) def graded_free_resolution(self, *args, **kwds): r""" @@ -1234,8 +1234,8 @@ def graded_free_resolution(self, *args, **kwds): sage: I.graded_free_resolution() S(0) <-- S(-3) <-- 0 """ - from sage.homology.graded_resolution import GradedFreeResolution - return GradedFreeResolution(self, *args, **kwds) + from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + return GradedFiniteFreeResolution_free_module(self, *args, **kwds) class Ideal_principal(Ideal_generic): diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 46feca52b20..139b942555c 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -1798,8 +1798,8 @@ def free_resolution(self, *args, **kwds): [ y x^2] [ y] 0 <-- C_0 <---------- C_1 <------- C_2 <-- 0 """ - from sage.homology.free_resolution import FreeResolution - return FreeResolution(self, *args, **kwds) + from sage.homology.free_resolution import FiniteFreeResolution_singular + return FiniteFreeResolution_singular(self, *args, **kwds) @require_field def graded_free_resolution(self, *args, **kwds): @@ -1826,8 +1826,8 @@ def graded_free_resolution(self, *args, **kwds): sage: I.graded_free_resolution(degrees=[1,2]) S(0) <-- S(-2)⊕S(-2) <-- S(-4) <-- 0 """ - from sage.homology.graded_resolution import GradedFreeResolution - return GradedFreeResolution(self, *args, **kwds) + from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular + return GradedFiniteFreeResolution_singular(self, *args, **kwds) @handle_AA_and_QQbar @singular_gb_standard_options From 6eebb35c5f30a0a68d0d5f0152929c60b2cdebc6 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 23 Aug 2022 10:54:23 +0200 Subject: [PATCH 226/742] do not assume that the approximate valuation will not change over time --- src/sage/data_structures/stream.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 380b27fb751..3c185918dba 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -1611,18 +1611,16 @@ def __init__(self, f, g): sage: h = Stream_cauchy_compose(f, g) """ #assert g._approximate_order > 0 - self._fv = f._approximate_order - self._gv = g._approximate_order - if self._fv < 0: + if f._approximate_order < 0: ginv = Stream_cauchy_invert(g) # The constant part makes no contribution to the negative. # We need this for the case so self._neg_powers[0][n] => 0. self._neg_powers = [Stream_zero(f._is_sparse), ginv] - for i in range(1, -self._fv): + for i in range(1, -f._approximate_order): self._neg_powers.append(Stream_cauchy_mul(self._neg_powers[-1], ginv)) # Placeholder None to make this 1-based. self._pos_powers = [None, g] - val = self._fv * self._gv + val = f._approximate_order * g._approximate_order super().__init__(f, g, f._is_sparse, val) def get_coefficient(self, n): @@ -1644,15 +1642,18 @@ def get_coefficient(self, n): sage: [h.get_coefficient(i) for i in range(10)] [0, 1, 6, 28, 124, 527, 2172, 8755, 34704, 135772] """ + fv = self._left._approximate_order + gv = self._right._approximate_order if n < 0: - return sum(self._left[i] * self._neg_powers[-i][n] for i in range(self._fv, n // self._gv + 1)) + return sum(self._left[i] * self._neg_powers[-i][n] + for i in range(fv, n // gv + 1)) # n > 0 - while len(self._pos_powers) <= n // self._gv: + while len(self._pos_powers) <= n // gv: self._pos_powers.append(Stream_cauchy_mul(self._pos_powers[-1], self._right)) - ret = sum(self._left[i] * self._neg_powers[-i][n] for i in range(self._fv, 0)) + ret = sum(self._left[i] * self._neg_powers[-i][n] for i in range(fv, 0)) if n == 0: ret += self._left[0] - return ret + sum(self._left[i] * self._pos_powers[i][n] for i in range(1, n // self._gv+1)) + return ret + sum(self._left[i] * self._pos_powers[i][n] for i in range(1, n // gv+1)) class Stream_plethysm(Stream_binary): From de30ad3820c183c6f42cb4ad59a66ad21cf86d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 23 Aug 2022 11:10:19 +0200 Subject: [PATCH 227/742] moving the code --- src/sage/categories/modules.py | 104 ++++++++++++++++----------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 58b83b8a785..afe402ec818 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -552,58 +552,6 @@ def extra_super_categories(self): """ return [self.base_category()] - class ParentMethods: - """ - Implement operations on tensor products of modules. - """ - def construction(self): - """ - Return the construction of ``self``. - - EXAMPLES:: - - sage: A = algebras.Free(QQ,2) - sage: T = A.tensor(A) - sage: T.construction() - [The tensor functorial construction, - (Free Algebra on 2 generators (None0, None1) over Rational Field, - Free Algebra on 2 generators (None0, None1) over Rational Field)] - """ - try: - factors = self.tensor_factors() - except (TypeError, NotImplementedError): - from sage.misc.superseded import deprecation - deprecation(34393, "implementations of Modules().TensorProducts() now must define the method tensor_factors") - return None - return (TensorProductFunctor(), - factors) - - @abstract_method(optional=True) - def tensor_factors(self): - """ - Return the tensor factors of this tensor product. - - EXAMPLES:: - - sage: F = CombinatorialFreeModule(ZZ, [1,2]) - sage: F.rename("F") - sage: G = CombinatorialFreeModule(ZZ, [3,4]) - sage: G.rename("G") - sage: T = tensor([F, G]); T - F # G - sage: T.tensor_factors() - (F, G) - - TESTS:: - - sage: M = CombinatorialFreeModule(ZZ, ((1, 1), (1, 2), (2, 1), (2, 2)), - ....: category=ModulesWithBasis(ZZ).FiniteDimensional().TensorProducts()) - sage: M.construction() - doctest:warning... - DeprecationWarning: implementations of Modules().TensorProducts() now must define the method tensor_factors - See https://trac.sagemath.org/34393 for details. - """ - class FinitelyPresented(CategoryWithAxiom_over_base_ring): def extra_super_categories(self): @@ -944,3 +892,55 @@ def extra_super_categories(self): [Category of modules over Integer Ring] """ return [self.base_category()] + + class ParentMethods: + """ + Implement operations on tensor products of modules. + """ + def construction(self): + """ + Return the construction of ``self``. + + EXAMPLES:: + + sage: A = algebras.Free(QQ,2) + sage: T = A.tensor(A) + sage: T.construction() + [The tensor functorial construction, + (Free Algebra on 2 generators (None0, None1) over Rational Field, + Free Algebra on 2 generators (None0, None1) over Rational Field)] + """ + try: + factors = self.tensor_factors() + except (TypeError, NotImplementedError): + from sage.misc.superseded import deprecation + deprecation(34393, "implementations of Modules().TensorProducts() now must define the method tensor_factors") + return None + return (TensorProductFunctor(), + factors) + + @abstract_method(optional=True) + def tensor_factors(self): + """ + Return the tensor factors of this tensor product. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(ZZ, [1,2]) + sage: F.rename("F") + sage: G = CombinatorialFreeModule(ZZ, [3,4]) + sage: G.rename("G") + sage: T = tensor([F, G]); T + F # G + sage: T.tensor_factors() + (F, G) + + TESTS:: + + sage: M = CombinatorialFreeModule(ZZ, ((1, 1), (1, 2), (2, 1), (2, 2)), + ....: category=ModulesWithBasis(ZZ).FiniteDimensional().TensorProducts()) + sage: M.construction() + doctest:warning... + DeprecationWarning: implementations of Modules().TensorProducts() now must define the method tensor_factors + See https://trac.sagemath.org/34393 for details. + """ From bc6828fd5f265e2921aeaf4739f3fd86611a6190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 23 Aug 2022 15:49:47 +0200 Subject: [PATCH 228/742] fix the doctest --- src/sage/categories/modules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index afe402ec818..21ee46b24f1 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -906,9 +906,9 @@ def construction(self): sage: A = algebras.Free(QQ,2) sage: T = A.tensor(A) sage: T.construction() - [The tensor functorial construction, + (The tensor functorial construction, (Free Algebra on 2 generators (None0, None1) over Rational Field, - Free Algebra on 2 generators (None0, None1) over Rational Field)] + Free Algebra on 2 generators (None0, None1) over Rational Field)) """ try: factors = self.tensor_factors() From 4098dbf0ed1b84d50d4f26a6020f394f55c1ce2e Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 23 Aug 2022 16:00:57 +0200 Subject: [PATCH 229/742] add derivative for LazyLaurentSeries --- src/sage/data_structures/stream.py | 113 ++++++++++++++++++++++++++++- src/sage/rings/lazy_series.py | 52 ++++++++++++- 2 files changed, 160 insertions(+), 5 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 3c185918dba..1004136ca9d 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -97,6 +97,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.arith.misc import divisors +from sage.misc.misc_c import prod from sage.combinat.integer_vector_weighted import iterator_fast as wt_int_vec_iter class Stream(): @@ -2347,7 +2348,7 @@ def __init__(self, series, shift): sage: from sage.data_structures.stream import Stream_exact sage: h = Stream_exact([1], False, constant=3) sage: M = Stream_shift(h, 2) - sage: TestSuite(M).run() + sage: TestSuite(M).run(skip="_test_pickling") """ self._series = series self._shift = shift @@ -2424,3 +2425,113 @@ def is_nonzero(self): True """ return self._series.is_nonzero() + +class Stream_derivative(Stream_inexact): + """ + Operator for taking derivatives of a stream. + + INPUT: + + - ``series`` -- a :class:`Stream` + - ``shift`` -- a positive integer + """ + def __init__(self, series, shift): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_exact, Stream_derivative + sage: f = Stream_exact([1,2,3], False) + sage: f2 = Stream_derivative(f, 2) + sage: TestSuite(f2).run() + """ + self._series = series + self._shift = shift + if 0 <= series._approximate_order <= shift: + aorder = 0 + else: + aorder = series._approximate_order - shift + super().__init__(series._is_sparse, aorder) + + def __getitem__(self, n): + """ + Return the ``n``-th coefficient of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_derivative + sage: f = Stream_function(lambda n: 1/n if n else 0, QQ, True, -2) + sage: [f[i] for i in range(-5, 3)] + [0, 0, 0, -1/2, -1, 0, 1, 1/2] + sage: f2 = Stream_derivative(f, 2) + sage: [f2[i] for i in range(-5, 3)] + [0, -3, -2, 0, 0, 1, 2, 3] + + sage: f = Stream_function(lambda n: 1/n, QQ, True, 2) + sage: [f[i] for i in range(-1, 4)] + [0, 0, 0, 1/2, 1/3] + sage: f2 = Stream_derivative(f, 3) + sage: [f2[i] for i in range(-1, 4)] + [0, 2, 6, 12, 20] + """ + return (prod(n+k for k in range(1, self._shift + 1)) + * self._series[n + self._shift]) + + def __hash__(self): + """ + Return the hash of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function + sage: from sage.data_structures.stream import Stream_derivative + sage: a = Stream_function(lambda n: 2*n, ZZ, False, 1) + sage: f = Stream_derivative(a, 1) + sage: g = Stream_derivative(a, 2) + sage: hash(f) == hash(f) + True + sage: hash(f) == hash(g) + False + + """ + return hash((type(self), self._series, self._shift)) + + def __eq__(self, other): + """ + Test equality. + + INPUT: + + - ``other`` -- a stream of coefficients + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function + sage: from sage.data_structures.stream import Stream_derivative + sage: a = Stream_function(lambda n: 2*n, ZZ, False, 1) + sage: f = Stream_derivative(a, 1) + sage: g = Stream_derivative(a, 2) + sage: f == g + False + sage: f == Stream_derivative(a, 1) + True + """ + return (isinstance(other, type(self)) and self._shift == other._shift + and self._series == other._series) + + def is_nonzero(self): + r""" + Return ``True`` if and only if this stream is known + to be nonzero. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_exact, Stream_derivative + sage: f = Stream_exact([1,2], False) + sage: Stream_derivative(f, 1).is_nonzero() + True + sage: Stream_derivative(f, 2).is_nonzero() # it might be nice if this gave False + True + """ + return self._series.is_nonzero() diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 0e694e0e30b..2ef13fe6e18 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -118,6 +118,7 @@ from sage.structure.richcmp import op_EQ, op_NE from sage.functions.other import factorial from sage.arith.power import generic_power +from sage.misc.misc_c import prod from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing @@ -137,6 +138,7 @@ Stream_uninitialized, Stream_shift, Stream_function, + Stream_derivative, Stream_dirichlet_convolve, Stream_dirichlet_invert, Stream_plethysm @@ -323,10 +325,10 @@ def map_coefficients(self, func, ring=None): if not any(initial_coefficients) and not c: return P.zero() coeff_stream = Stream_exact(initial_coefficients, - self._coeff_stream._is_sparse, - order=coeff_stream._approximate_order, - degree=coeff_stream._degree, - constant=BR(c)) + self._coeff_stream._is_sparse, + order=coeff_stream._approximate_order, + degree=coeff_stream._degree, + constant=BR(c)) return P.element_class(P, coeff_stream) R = P._internal_poly_ring.base_ring() coeff_stream = Stream_map_coefficients(self._coeff_stream, func, R) @@ -3081,6 +3083,48 @@ def revert(self): compositional_inverse = revert + def derivative(self, order=1): + """ + Return the derivative of the Laurent series. + + INPUT: + + - ``order`` -- optional integer (default 1) + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: z.derivative() + 1 + sage: (1+z+z^2).derivative(3) + 0 + sage: (1/z).derivative() + -z^-2 + sage: (1/(1-z)).derivative() + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + + """ + P = self.parent() + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, Stream_zero): + return self + BR = P.base_ring() + if (isinstance(coeff_stream, Stream_exact) + and not coeff_stream._constant): + if coeff_stream._approximate_order >= 0 and coeff_stream._degree <= order: + return P.zero() + initial_coefficients = [prod(i-k for k in range(order)) * c + for i, c in enumerate(coeff_stream._initial_coefficients, + coeff_stream._approximate_order)] + coeff_stream = Stream_exact(initial_coefficients, + self._coeff_stream._is_sparse, + order=coeff_stream._approximate_order - order, + constant=coeff_stream._constant) + return P.element_class(P, coeff_stream) + + coeff_stream = Stream_derivative(self._coeff_stream, order) + return P.element_class(P, coeff_stream) + def approximate_series(self, prec, name=None): r""" Return the Laurent series with absolute precision ``prec`` approximated From 55761b891778b6ccc520dcdd8539d5c828c60e82 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 23 Aug 2022 17:34:06 +0200 Subject: [PATCH 230/742] better derivative for LazyLaurentSeries --- src/sage/rings/lazy_series.py | 55 +++++++++++++++++++++++++----- src/sage/rings/lazy_series_ring.py | 3 +- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 2ef13fe6e18..ef32320b35e 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -119,6 +119,7 @@ from sage.functions.other import factorial from sage.arith.power import generic_power from sage.misc.misc_c import prod +from sage.misc.derivative import derivative_parse from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing @@ -3083,14 +3084,12 @@ def revert(self): compositional_inverse = revert - def derivative(self, order=1): + def derivative(self, *args): """ Return the derivative of the Laurent series. INPUT: - - ``order`` -- optional integer (default 1) - EXAMPLES:: sage: L. = LazyLaurentSeriesRing(ZZ) @@ -3100,11 +3099,40 @@ def derivative(self, order=1): 0 sage: (1/z).derivative() -z^-2 - sage: (1/(1-z)).derivative() + sage: (1/(1-z)).derivative(z) 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + TESTS:: + + sage: R. = QQ[] + sage: L. = LazyLaurentSeriesRing(R) + sage: (z*q).derivative() + q + + sage: (z*q).derivative(q) + z + + sage: (z*q).derivative(q, z) + 1 + + sage: f = 1/(1-q*z+z^2) + sage: f + 1 + q*z + (q^2 - 1)*z^2 + (q^3 - 2*q)*z^3 + (q^4 - 3*q^2 + 1)*z^4 + (q^5 - 4*q^3 + 3*q)*z^5 + (q^6 - 5*q^4 + 6*q^2 - 1)*z^6 + O(z^7) + sage: f.derivative(q)[3] + 3*q^2 - 2 + """ P = self.parent() + R = P._laurent_poly_ring + v = R.gen() + order = 0 + vars = [] + for x in derivative_parse(args): + if x is None or x == v: + order += 1 + else: + vars.append(x) + coeff_stream = self._coeff_stream if isinstance(coeff_stream, Stream_zero): return self @@ -3113,16 +3141,25 @@ def derivative(self, order=1): and not coeff_stream._constant): if coeff_stream._approximate_order >= 0 and coeff_stream._degree <= order: return P.zero() - initial_coefficients = [prod(i-k for k in range(order)) * c - for i, c in enumerate(coeff_stream._initial_coefficients, - coeff_stream._approximate_order)] - coeff_stream = Stream_exact(initial_coefficients, + if vars: + coeffs = [prod(i-k for k in range(order)) * c.derivative(vars) + for i, c in enumerate(coeff_stream._initial_coefficients, + coeff_stream._approximate_order)] + else: + coeffs = [prod(i-k for k in range(order)) * c + for i, c in enumerate(coeff_stream._initial_coefficients, + coeff_stream._approximate_order)] + coeff_stream = Stream_exact(coeffs, self._coeff_stream._is_sparse, order=coeff_stream._approximate_order - order, constant=coeff_stream._constant) return P.element_class(P, coeff_stream) coeff_stream = Stream_derivative(self._coeff_stream, order) + if vars: + coeff_stream = Stream_map_coefficients(coeff_stream, + lambda c: c.derivative(vars), + R) return P.element_class(P, coeff_stream) def approximate_series(self, prec, name=None): @@ -3441,7 +3478,7 @@ def __call__(self, *g, check=True): TypeError: no common canonical parent for objects with parents: ... """ - if len(g) != len(self.parent().variable_names()): + if len(g) != self.parent()._arity: raise ValueError("arity of must be equal to the number of arguments provided") # Find a good parent for the result diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 44c461ccbce..77d80a3e41e 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1147,7 +1147,8 @@ def __init__(self, base_ring, names, sparse=True, category=None): names = normalize_names(-1, names) self._sparse = sparse self._laurent_poly_ring = PolynomialRing(base_ring, names) - if len(names) == 1: + self._arity = len(names) + if self._arity == 1: self._internal_poly_ring = self._laurent_poly_ring else: coeff_ring = PolynomialRing(base_ring, names) From 50ce4508add8c080f9af5afe916fe9f5fe903d9d Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 23 Aug 2022 22:19:56 +0200 Subject: [PATCH 231/742] derivative for LazyTaylorSeries --- src/sage/rings/lazy_series.py | 80 ++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index ef32320b35e..af511dc8e58 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3136,7 +3136,6 @@ def derivative(self, *args): coeff_stream = self._coeff_stream if isinstance(coeff_stream, Stream_zero): return self - BR = P.base_ring() if (isinstance(coeff_stream, Stream_exact) and not coeff_stream._constant): if coeff_stream._approximate_order >= 0 and coeff_stream._degree <= order: @@ -3567,6 +3566,85 @@ def coefficient(n): compose = __call__ + def derivative(self, *args): + """ + Return the derivative of the Taylor series. + + INPUT: + + EXAMPLES:: + + sage: T. = LazyTaylorSeriesRing(ZZ) + sage: z.derivative() + 1 + sage: (1+z+z^2).derivative(3) + 0 + sage: (1/(1-z)).derivative() + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + + sage: R. = QQ[] + sage: L. = LazyTaylorSeriesRing(R) + sage: f = 1/(1-q*x+y); f + 1 + (q*x-y) + (q^2*x^2+(-2*q)*x*y+y^2) + (q^3*x^3+(-3*q^2)*x^2*y+3*q*x*y^2-y^3) + (q^4*x^4+(-4*q^3)*x^3*y+6*q^2*x^2*y^2+(-4*q)*x*y^3+y^4) + (q^5*x^5+(-5*q^4)*x^4*y+10*q^3*x^3*y^2+(-10*q^2)*x^2*y^3+5*q*x*y^4-y^5) + (q^6*x^6+(-6*q^5)*x^5*y+15*q^4*x^4*y^2+(-20*q^3)*x^3*y^3+15*q^2*x^2*y^4+(-6*q)*x*y^5+y^6) + O(x,y)^7 + sage: f.derivative(q) + x + (2*q*x^2+(-2)*x*y) + (3*q^2*x^3+(-6*q)*x^2*y+3*x*y^2) + (4*q^3*x^4+(-12*q^2)*x^3*y+12*q*x^2*y^2+(-4)*x*y^3) + (5*q^4*x^5+(-20*q^3)*x^4*y+30*q^2*x^3*y^2+(-20*q)*x^2*y^3+5*x*y^4) + (6*q^5*x^6+(-30*q^4)*x^5*y+60*q^3*x^4*y^2+(-60*q^2)*x^3*y^3+30*q*x^2*y^4+(-6)*x*y^5) + O(x,y)^7 + + """ + P = self.parent() + R = P._laurent_poly_ring + V = R.gens() + order = 0 + vars = [] + gen_vars = [] + for x in derivative_parse(args): + if x is None: + order += 1 + elif x in V: + gen_vars.append(x) + else: + vars.append(x) + + if P._arity > 1 and order: + raise ValueError("for multivariate series you have to specify the variable with respect to which the derivative should be taken") + else: + order += len(gen_vars) + + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, Stream_zero): + return self + + if P._arity > 1: + coeff_stream = Stream_shift(Stream_map_coefficients(coeff_stream, + lambda c: c.derivative(gen_vars + vars), + P._laurent_poly_ring), + -len(gen_vars)) + return P.element_class(P, coeff_stream) + + if (isinstance(coeff_stream, Stream_exact) + and not coeff_stream._constant): + if coeff_stream._degree <= order: + return P.zero() + if vars: + coeffs = [prod(i-k for k in range(order)) * c.derivative(vars) + for i, c in enumerate(coeff_stream._initial_coefficients, + coeff_stream._approximate_order)] + else: + coeffs = [prod(i-k for k in range(order)) * c + for i, c in enumerate(coeff_stream._initial_coefficients, + coeff_stream._approximate_order)] + coeff_stream = Stream_exact(coeffs, + self._coeff_stream._is_sparse, + order=coeff_stream._approximate_order - order, + constant=coeff_stream._constant) + return P.element_class(P, coeff_stream) + + coeff_stream = Stream_derivative(self._coeff_stream, order) + if vars: + coeff_stream = Stream_map_coefficients(coeff_stream, + lambda c: c.derivative(vars), + R) + return P.element_class(P, coeff_stream) + def _format_series(self, formatter, format_strings=False): """ Return nonzero ``self`` formatted by ``formatter``. From 10cfc11a7393ccf2d92cd45b9a3ee127056c7363 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 23 Aug 2022 23:25:10 +0200 Subject: [PATCH 232/742] derivative for LazySymmetricFunctions --- src/sage/rings/lazy_series.py | 60 +++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index af511dc8e58..e82321b9f18 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3992,6 +3992,66 @@ def revert(self): plethystic_inverse = revert compositional_inverse = revert + def derivative_with_respect_to_p1(self, n=1): + r""" + Return the symmetric function obtained by taking the + derivative of ``self`` with respect to the power-sum + symmetric function `p_1` when the expansion of ``self`` in + the power-sum basis is considered as a polynomial in `p_k`'s + (with `k \geq 1`). + + This is the same as skewing ``self`` by the first power-sum + symmetric function `p_1`. + + INPUT: + + - ``n`` -- (default: 1) nonnegative integer which determines + which power of the derivative is taken + + + EXAMPLES: + + The species `E` of sets satisfies the relationship `E' = E`:: + + sage: h = SymmetricFunctions(QQ).h() + sage: T = LazySymmetricFunctions(h) + sage: E = T(lambda n: h[n]) + sage: E - E.derivative_with_respect_to_p1() + O^6 + + The species `C` of cyclic orderings and the species `L` of linear + orderings satisfy the relationship `C' = L`:: + + sage: p = SymmetricFunctions(QQ).p() + sage: C = T(lambda n: (sum(euler_phi(k)*p([k])**(n//k) for k in divisors(n))/n if n > 0 else 0)) + sage: L = T(lambda n: p([1]*n)) + sage: L - C.derivative_with_respect_to_p1() + O^6 + + TESTS:: + + sage: T = LazySymmetricFunctions(p) + sage: a = T(p([1,1,1])) + sage: a.derivative_with_respect_to_p1() + (3*p[1,1]) + O^9 + sage: a.derivative_with_respect_to_p1(1) + (3*p[1,1]) + O^9 + sage: a.derivative_with_respect_to_p1(2) + 6*p[1] + O^8 + sage: a.derivative_with_respect_to_p1(3) + 6*p[] + O^7 + """ + P = self.parent() + if P._arity != 1: + raise ValueError("arity must be equal to 1") + + coeff_stream = Stream_shift(Stream_map_coefficients(self._coeff_stream, + lambda c: c.derivative_with_respect_to_p1(n), + P._laurent_poly_ring), + -n) + return P.element_class(P, coeff_stream) + + def _format_series(self, formatter, format_strings=False): r""" Return nonzero ``self`` formatted by ``formatter``. From f1becfd9d4031a102287b7682189f2d64e958e1b Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Tue, 23 Aug 2022 14:44:59 -0700 Subject: [PATCH 233/742] raise NotImplementedError, auto-convert function-field divisors, cache curve --- src/sage/schemes/curves/affine_curve.py | 4 +- .../riemann_surfaces/riemann_surface.py | 500 ++++++++++-------- 2 files changed, 268 insertions(+), 236 deletions(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index f09cde624eb..c9eb561a7d6 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -1785,7 +1785,9 @@ def riemann_surface(self, **kwargs): Riemann surface defined by polynomial f = x^3 + 3*y^3 + 5 = 0, with 53 bits of precision """ from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface - return RiemannSurface(self.defining_polynomial(),**kwargs) + S = RiemannSurface(self.defining_polynomial(),**kwargs) + S._curve = self + return S class AffinePlaneCurve_finite_field(AffinePlaneCurve_field): diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 0e6620d11fc..fcef9536bf8 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -58,9 +58,9 @@ sage: all(len(a.minpoly().roots(K)) == a.minpoly().degree() for a in A) True -We can look at an extended example of the Abel-Jacobi functionality. We will -demonstrate a particular half-canonical divisor on Klein's Curve, known in -the literature.:: +We can look at an extended example of the Abel-Jacobi functionality. We will +demonstrate a particular half-canonical divisor on Klein's Curve, known in +the literature.:: sage: f = x^3*y + y^3 + x sage: S = RiemannSurface(f, integration_method='rigorous') @@ -90,7 +90,7 @@ We can also check this using our Abel-Jacobi functions:: sage: avoid = C.places_at_infinity() - sage: Zeq, _ = S.strong_approximation(Z, avoid) + sage: Zeq, _ = S.strong_approximation(Z, avoid) sage: Zlist = S.divisor_to_divisor_list(Zeq) sage: AJ = S.abel_jacobi(Zlist) # long time (1 second) sage: S.reduce_over_period_lattice(AJ).norm() < 1e-10 # long time @@ -129,6 +129,7 @@ from sage.numerical.gauss_legendre import integrate_vector, integrate_vector_N from sage.rings.complex_mpfr import ComplexField, CDF from sage.rings.function_field.constructor import FunctionField +from sage.rings.function_field.divisor import FunctionFieldDivisor from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -373,10 +374,10 @@ def differential_basis_baker(f): def find_closest_element(item, List): r""" Return the index of the closest element of a list. - + Given ``List`` and ``item``, return the index of the element ``l`` of ``List`` - which minimises ``(item-l).abs()``. If there are multiple such elements, the - first is returned. + which minimises ``(item-l).abs()``. If there are multiple such elements, the + first is returned. INPUT: @@ -401,35 +402,35 @@ def find_closest_element(item, List): def reparameterise_differential_minpoly(minpoly, z0): r""" - Rewrites a minimal polynomial to write is around `z_0`. - + Rewrites a minimal polynomial to write is around `z_0`. + Given a minimal polynomial `m(z,g)`, where `g` corresponds to a differential - on the surface (that is, it is represented as a rational function, and - implicitly carries a factor `dz`), we rewrite the minpoly in terms of - variables `\bar{z}, \bar{g}` s.t now `\bar{z}=0 \Leftrightarrow z=z_0`. - + on the surface (that is, it is represented as a rational function, and + implicitly carries a factor `dz`), we rewrite the minpoly in terms of + variables `\bar{z}, \bar{g}` s.t now `\bar{z}=0 \Leftrightarrow z=z_0`. + INPUT: - - - ``minpoly`` -- a polynomial in two variables, where the first variables + + - ``minpoly`` -- a polynomial in two variables, where the first variables corresponds to the base coordinate on the Riemann surface. - - - ``z0`` -- complex number of infinity. The point about which to + + - ``z0`` -- complex number of infinity. The point about which to reparameterise. - + OUTPUT: - - A polynomial in two variables giving the reparameterise minimal polynomial. - + + A polynomial in two variables giving the reparameterise minimal polynomial. + EXAMPLES: - - On the curve given by `w^2-z^3+1=0`, we have differential + + On the curve given by `w^2-z^3+1=0`, we have differential `\frac{dz}{2w} = \frac{dz}{2\sqrt{z^3-1}}` - with minimal polynomial `g^2(z^3-1)-1/4=0`. We can make the substitution - `\bar{z}=z^{-1}` to parameterise the differential about `z=\Infty` as + with minimal polynomial `g^2(z^3-1)-1/4=0`. We can make the substitution + `\bar{z}=z^{-1}` to parameterise the differential about `z=\Infty` as `\frac{-\bar{z}^{-2} d\bar{z}}{2\sqrt{\bar{z}^{-3}-1}} = \frac{-d\bar{z}}{2\sqrt{\bar{z}(1-\bar{z}^3)}}`. - Hence the transformed differential should have minimal polynomial + Hence the transformed differential should have minimal polynomial `\bar{g}^2\bar{z}(1-\bar{z}^3)-1/4=0`, and we can check this:: - + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface, reparameterise_differential_minpoly sage: R. = QQ[] sage: S = RiemannSurface(w^2-z^3+1) @@ -438,7 +439,7 @@ def reparameterise_differential_minpoly(minpoly, z0): sage: reparameterise_differential_minpoly(minpoly, z0) -zbar^4*gbar^2 + zbar*gbar^2 - 1/4 - We can further check that reparameterising about `0` is the identity + We can further check that reparameterising about `0` is the identity operation:: sage: reparameterise_differential_minpoly(minpoly, 0)(*minpoly.parent().gens())==minpoly @@ -446,19 +447,19 @@ def reparameterise_differential_minpoly(minpoly, z0): .. NOTE:: - As part of the routine, when reparameterising about infinity, a + As part of the routine, when reparameterising about infinity, a rational function is reduced and then the numerator is taken. Over an inexact ring this is numerically unstable, and so it is advisable - to only reparameterise about infinity over an exact ring. + to only reparameterise about infinity over an exact ring. """ P = minpoly.parent() F = PolynomialRing(P.base_ring(), [str(v)+"bar" for v in P.gens()]) - + try: Inf = bool(z0==z0.parent()(Infinity)) except TypeError: Inf = False - + if Inf: F = F.fraction_field() mt = F(minpoly(F.gen(0)**(-1),-F.gen(0)**(+2)*F.gen(1))) @@ -574,8 +575,8 @@ class RiemannSurface(object): 1.2429363969691192 Note that for the above curve, the branch points are evenly distributed, and - hence the implicit assumptions in the heuristic method are more sensible, - meaning that a higher precision is required to see the heuristic method + hence the implicit assumptions in the heuristic method are more sensible, + meaning that a higher precision is required to see the heuristic method being significantly slower than the rigorous method. For a worse conditioned curve, this effect is more pronounced:: @@ -645,6 +646,7 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati self._CCz = PolynomialRing(self._CC, [self._R.gen(0)]) self._CCw = PolynomialRing(self._CC, [self._R.gen(1)]) self._RRz = PolynomialRing(self._RR, [self._R.gen(0)]) + self._curve = None self.f = f if differentials is not None: self._differentials = [self._R(a) for a in differentials] @@ -679,7 +681,7 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati exact=True) RBzg, bounding_data_list = self._cohomology_basis_bounding_data minpoly_list = [bd[2] for bd in bounding_data_list] - # We now want to calculate the additional branchpoints associated to + # We now want to calculate the additional branchpoints associated to # the differentials. discriminants = [RBzg(self._discriminant(*RBzg.gens()))] for minpoly in minpoly_list: @@ -694,9 +696,9 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati 0)).roots(multiplicities=False) # We add these branchpoints to the existing. #self.branch_locus = self.branch_locus+self._differentials_branch_locus - # We now want to also check whether Infinity is a branch point of any + # We now want to also check whether Infinity is a branch point of any # of the differentials. - # This will be useful when calculating the Abel-Jacobi map. + # This will be useful when calculating the Abel-Jacobi map. minpoly_list = [reparameterise_differential_minpoly(mp, Infinity) for mp in minpoly_list] discriminants = [] @@ -715,7 +717,7 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati for x0, y0 in self.voronoi_diagram.vertices] self._wvalues = [self.w_values(z0) for z0 in self._vertices] # We arbitrarily, but sensibly, set the basepoint to be the rightmost vertex - self._basepoint = (self._vertices.index(sorted(self._vertices, + self._basepoint = (self._vertices.index(sorted(self._vertices, key=lambda z:z.real())[-1]), 0) self._Sn = SymmetricGroup(range(self.degree)) self._L = {} @@ -723,7 +725,7 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati self._fastcall_f = fast_callable(f, domain=self._CC) self._fastcall_dfdw = fast_callable(self._dfdw, domain=self._CC) self._fastcall_dfdz = fast_callable(self._dfdz, domain=self._CC) - self._fastcall_cohomology_basis = [fast_callable(h, domain = self._CC) + self._fastcall_cohomology_basis = [fast_callable(h, domain = self._CC) for h in self.cohomology_basis()] def __repr__(self): @@ -830,7 +832,7 @@ def downstairs_graph(self): Return the Voronoi decomposition as a planar graph. The result of this routine can be useful to interpret the labelling of - the vertices. See also :meth:`upstairs_graph`. + the vertices. See also :meth:`upstairs_graph`. OUTPUT: @@ -853,17 +855,17 @@ def downstairs_graph(self): def upstairs_graph(self): r""" Return the graph of the upstairs edges. - + This method can be useful for generating paths in the surface between points labelled - by upstairs vertices, and verifying that a homology basis is likely computed correctly. + by upstairs vertices, and verifying that a homology basis is likely computed correctly. See also :meth:`downstairs_graph`. OUTPUT: - The homotopy-continued Voronoi decomposition as a graph, with appropriate 3D embedding. - + The homotopy-continued Voronoi decomposition as a graph, with appropriate 3D embedding. + EXAMPLES:: - + sage: R. = QQ[] sage: S = Curve(w^2-z^4+1).riemann_surface() sage: G = S.upstairs_graph(); G @@ -874,8 +876,8 @@ def upstairs_graph(self): True """ G = Graph(self.upstairs_edges()) - G.set_pos({(i,j): [self._vertices[i].real(), self._vertices[i].imag(), - self.w_values(self._vertices[i])[j].imag()] + G.set_pos({(i,j): [self._vertices[i].real(), self._vertices[i].imag(), + self.w_values(self._vertices[i])[j].imag()] for i in range(len(self._vertices)) for j in range(self.degree)}, dim=3) return G @@ -963,16 +965,16 @@ def homotopy_continuation(self, edge): INPUT: - ``edge`` -- a tuple ``(z_start, z_end)`` indicating the straight line - over which to perform the homotopy continutation. + over which to perform the homotopy continutation. OUTPUT: - A list containing the initialised continuation data. Each entry in the - list contains: the `t` values that entry corresponds to, a list of - complex numbers corresponding to the points which are reached when - continued along the edge when traversing along the direction of the + A list containing the initialised continuation data. Each entry in the + list contains: the `t` values that entry corresponds to, a list of + complex numbers corresponding to the points which are reached when + continued along the edge when traversing along the direction of the edge, and a value ``epsilon`` giving the minimumdistance between the - fibre values divided by 3. The ordering of these points indicates how + fibre values divided by 3. The ordering of these points indicates how they have been permuted due to the weaving of the curve. EXAMPLES: @@ -1094,7 +1096,7 @@ def _determine_new_w(self, z0, oldw, epsilon): .. NOTE:: Algorithmically, this method is nearly identical to :meth:`_newton_iteration`, - but this method takes a list of `w` values. + but this method takes a list of `w` values. """ # Tools of Newton iteration. F = self._fastcall_f @@ -1239,7 +1241,7 @@ def upstairs_edges(self): i0, i1 = e d_edge = (self._vertices[i0], self._vertices[i1]) # Epsilon for checking w-value later. - epsilon = min([abs(self._wvalues[i1][i] - self._wvalues[i1][n-j-1]) + epsilon = min([abs(self._wvalues[i1][i] - self._wvalues[i1][n-j-1]) for i in range(n) for j in range(n-i-1)])/3 # Homotopy continuation along e. self._L[e] = self.homotopy_continuation(d_edge) @@ -1608,10 +1610,10 @@ def make_zw_interpolator(self, upstairs_edge, initial_continuation=None): INPUT: - ``upstairs_edge`` -- tuple. ``((z_start, sb), (z_end,))`` giving the - start and end values of the base coordinate along the straight-line - path and the starting branch. + start and end values of the base coordinate along the straight-line + path and the starting branch. - - ``initial_continuation`` -- list (default: None). Output of + - ``initial_continuation`` -- list (default: None). Output of ``homotopy_continuation`` initialising the continuation data. OUTPUT: @@ -1630,7 +1632,7 @@ def make_zw_interpolator(self, upstairs_edge, initial_continuation=None): sage: u_edge = [(0, 0), (1, 0)] sage: d_edge = tuple(u[0] for u in u_edge) sage: u_edge = [(S._vertices[i], j) for i, j in u_edge] - sage: initial_continuation = S._L[d_edge] + sage: initial_continuation = S._L[d_edge] sage: g, d = S.make_zw_interpolator(u_edge, initial_continuation) sage: all(f(*g(i*0.1)).abs() < 1e-13 for i in range(10)) True @@ -1639,10 +1641,10 @@ def make_zw_interpolator(self, upstairs_edge, initial_continuation=None): .. NOTE:: - The interpolator returned by this method can effectively hang if + The interpolator returned by this method can effectively hang if either ``z_start`` or ``z_end`` are branchpoints. In these situations it is better to take a different approach rather than continue to use - the interpolator. + the interpolator. """ downstairs_edge = tuple(u[0] for u in upstairs_edge) z_start, z_end = downstairs_edge @@ -1699,7 +1701,7 @@ def simple_vector_line_integral(self, upstairs_edge, differentials): - ``upstairs_edge`` -- tuple. Either a pair of integer tuples corresponding to an edge of the upstairs graph, or a tuple - ``((z_start, sb), (z_end, ))`` as in the input of + ``((z_start, sb), (z_end, ))`` as in the input of ``make_zw_interpolator``. - ``differentials`` -- a list of polynomials; a polynomial `g` @@ -1730,12 +1732,12 @@ def simple_vector_line_integral(self, upstairs_edge, differentials): Uses data that :meth:`homology_basis` initializes, and may give incorrect values if :meth:`homology_basis` has not initialized them. In practice - it is more efficient to set ``differentials`` to a fast-callable version - of differentials to speed up execution. + it is more efficient to set ``differentials`` to a fast-callable version + of differentials to speed up execution. """ d_edge = tuple(u[0] for u in upstairs_edge) # Using a try-catch here allows us to retain a certain amount of back compatibility - # for users. + # for users. try: initial_continuation = self._L[d_edge] upstairs_edge = ((self._vertices[d_edge[0]], upstairs_edge[0][1]), @@ -1827,33 +1829,33 @@ def _bounding_data(self, differentials, exact=False): INPUT: - ``differentials`` -- list. A list of polynomials in ``self._R`` giving - the numerators of the differentials, as per the output of + the numerators of the differentials, as per the output of :meth:`cohomology_basis`. - ``exact`` -- logical (default: False). Whether to return the minimal - polynomials over the exact base ring, or whether to return them over - ``self._CC``. + polynomials over the exact base ring, or whether to return them over + ``self._CC``. OUTPUT: - A tuple ``(Rzg, [(g, dgdz, F, a0_info), ...])`` where each element of + A tuple ``(Rzg, [(g, dgdz, F, a0_info), ...])`` where each element of the list corresponds to an element of ``differentials``. Introducing the - notation ``RBzg = PolynomialRing(self._R, ['z','g'])`` and + notation ``RBzg = PolynomialRing(self._R, ['z','g'])`` and ``CCzg = PolynomialRing(self._CC, ['z','g'])``, we have that: - - ``Rzg`` is either ``RBzg`` or ``CCzg`` depending on the value of + - ``Rzg`` is either ``RBzg`` or ``CCzg`` depending on the value of ``exact``, - - ``g`` is the full rational function in ``self._R.fraction_field()`` + - ``g`` is the full rational function in ``self._R.fraction_field()`` giving the differential, - ``dgdz`` is the derivative of ``g`` with respect to ``self._R.gen(0)``, - written in terms of ``self._R.gen(0)`` and ``g``, hence laying in + written in terms of ``self._R.gen(0)`` and ``g``, hence laying in ``RBzg``, - - ``F`` is the minimal polynomial of ``g`` over ``self._R.gen(0)``, + - ``F`` is the minimal polynomial of ``g`` over ``self._R.gen(0)``, laying in the polynomial ring ``Rzg``, - - ``a0_info`` is a tuple ``(lc, roots)`` where ``lc`` and ``roots`` are + - ``a0_info`` is a tuple ``(lc, roots)`` where ``lc`` and ``roots`` are the leading coefficient and roots of the polynomial in ``CCzg.gen(0)`` - that is the coefficient of the term of ``F`` of highest degree in - ``CCzg.gen(1)``. + that is the coefficient of the term of ``F`` of highest degree in + ``CCzg.gen(1)``. EXAMPLES:: @@ -1898,8 +1900,8 @@ def _bounding_data(self, differentials, exact=False): L = k.extension(fZW, 'Wb') dfdw_L = self._dfdw(P.gen(0), L.gen(0)) integrand_list = [h/self._dfdw for h in differentials] - # minpoly_univ gives the minimal polynomial for h, in variable x, with - # coefficients given by polynomials with coefficients in P (i.e. + # minpoly_univ gives the minimal polynomial for h, in variable x, with + # coefficients given by polynomials with coefficients in P (i.e. # rational polynomials in Z). minpoly_univ = [(h(P.gen(0), L.gen(0))/dfdw_L).minpoly().numerator() for h in differentials] @@ -1945,7 +1947,7 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): - ``upstairs_edge`` -- tuple. Either a pair of integer tuples corresponding to an edge of the upstairs graph, or a tuple - ``((z_start, sb), (z_end, ))`` as in the input of + ``((z_start, sb), (z_end, ))`` as in the input of ``make_zw_interpolator``. - ``differentials`` -- a list of polynomials; a polynomial `g` @@ -1980,7 +1982,7 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): .. NOTE:: Uses data that ``homology_basis`` initializes, and may give incorrect - values if :meth:`homology_basis` has not initialized them. + values if :meth:`homology_basis` has not initialized them. Note also that the data of the differentials is contained within ``bounding_data``. It is, however, still advantageous to have this @@ -2013,26 +2015,26 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): # Note that this, in its current formalism, makes no check that bounding # data at all corresponds to the differentials given. The onus is then # on the design of other functions which use it. - + # CCzg is required to be known as we need to know the ring which the minpolys - # lie in. + # lie in. CCzg, bounding_data_list = bounding_data d_edge = tuple(u[0] for u in upstairs_edge) - # Using a try-catch here allows us to retain a certain amount of back - # compatibility for users. + # Using a try-catch here allows us to retain a certain amount of back + # compatibility for users. try: initial_continuation = self._L[d_edge] upstairs_edge = ((self._vertices[d_edge[0]], upstairs_edge[0][1]), (self._vertices[d_edge[1]], )) except KeyError: initial_continuation = self.homotopy_continuation(d_edge) - - zwt, z1_minus_z0 = self.make_zw_interpolator(upstairs_edge, + + zwt, z1_minus_z0 = self.make_zw_interpolator(upstairs_edge, initial_continuation) z0 = zwt(0)[0] z1 = zwt(1)[0] - + # list of (centre, radius) pairs that still need to be processed ball_stack = [(self._RR(1/2), self._RR(1/2), 0)] alpha = self._RR(912/1000) @@ -2169,7 +2171,7 @@ def matrix_of_integral_values(self, differentials, integration_method="heuristic .. NOTE:: - If ``differentials is self.cohomology_basis()``, the calculations + If ``differentials is self.cohomology_basis()``, the calculations of the integrals along the edges are written to `self._integral_dict``. This is as this data will be required when computing the Abel-Jacobi map, and so it is helpful to have is stored rather than recomputing. @@ -2370,7 +2372,7 @@ def path(t): P += line3d([path(t[0])+(t[1][i].imag_part(),) for t in T],color=color,thickness=thickness) for z,ws in zip(self._vertices,self._wvalues): for w in ws: - P += point3d([z.real_part(), z.imag_part(), w.imag_part()], + P += point3d([z.real_part(), z.imag_part(), w.imag_part()], color="purple", size=20) return P @@ -2750,49 +2752,49 @@ def __add__(self, other): def _integrate_differentials_iteratively(self, upstairs_edge, cutoff_individually=False, raise_errors=True, prec=None): r""" - Integrate the cohomology basis along a straight line edge. - + Integrate the cohomology basis along a straight line edge. + The cohomology basis is integrated along a straight line using a version - of the double exponential quadrature. This method of integrating the - cohomology basis is especially useful when integrating out to infinity, - or near roots of `self._dfdw`. In order to aid with convergence of the - method, two main modification to a standard integrator are made, most - importantly of which is the truncation of the integral near branch points, - where the first term in the Puiseux series of the integrands are used to - approximately bound the integral. The ``cutoff_individually`` parameter - allows the user to set whether that truncation is uniform over all the - integrands, which improves the complexity of the algorithm, but loses + of the double exponential quadrature. This method of integrating the + cohomology basis is especially useful when integrating out to infinity, + or near roots of `self._dfdw`. In order to aid with convergence of the + method, two main modification to a standard integrator are made, most + importantly of which is the truncation of the integral near branch points, + where the first term in the Puiseux series of the integrands are used to + approximately bound the integral. The ``cutoff_individually`` parameter + allows the user to set whether that truncation is uniform over all the + integrands, which improves the complexity of the algorithm, but loses the ability to gain benefits where integrands vanish to a high order at - the branchpoint. - + the branchpoint. + INPUT: - + - ``upstairs_edge`` -- tuple. A tuple of complex numbers of the form - ``((z_start, w_start), z_end)`` specifying the path to integrate + ``((z_start, w_start), z_end)`` specifying the path to integrate along, where ``z_start`` may be infinite, in which case ``w_start`` - must be an integer specifying the branch. - + must be an integer specifying the branch. + - ``cutoff_individually`` -- boolean (default: False). Whether to truncate - the integrand uniformly or not. If ``None``, then no truncation is - applied. + the integrand uniformly or not. If ``None``, then no truncation is + applied. - ``raise_errors`` -- boolean (default: True). By default the code uses - convergence errors to ensure any answers returned are accurate. This + convergence errors to ensure any answers returned are accurate. This can be turned off to return answers faster that are not necessarily - correct. + correct. + + - ``prec`` -- integer (default: ``self._prec``). The precision to try + and achieve, defined as `2^{-\text{prec}+3}`. - - ``prec`` -- integer (default: ``self._prec``). The precision to try - and achieve, defined as `2^{-\text{prec}+3}`. - OUTPUT: - - Tuple ``(I, gs)`` where ``I`` is the vector of integrals, and ``gs`` are - the values of the differentials at ``z_end``. - + + Tuple ``(I, gs)`` where ``I`` is the vector of integrals, and ``gs`` are + the values of the differentials at ``z_end``. + EXAMPLES: - + We know that for the surface given by `w^2-z^4-1` a cohomology basis is - given by `\frac{dz}{2w}`. One can verify analytically that + given by `\frac{dz}{2w}`. One can verify analytically that `\int_0^1 frac{dt}{\sqrt{1-t^4}}=\frac{\sqrt{\pi}\Gamma(5/4)}{\Gamma(3/4)}`, and we check this with the integrator, being careful with signs:: @@ -2813,24 +2815,24 @@ def _integrate_differentials_iteratively(self, upstairs_edge, cutoff_individuall .. NOTE:: The cutoff methodology is calculating the first term in the Puiseux - series of the differentials about z_start. In future it may be + series of the differentials about z_start. In future it may be desirable to extend this further and use the truncated Puiseux series - entirely to integrate the differentials. + entirely to integrate the differentials. """ (z_start, w_start), z_end = upstairs_edge z_start = self._CC(z_start) z_end = self._CC(z_end) - + if z_end==self._CC(Infinity): raise NotImplementedError - + _, bounding_data_list = self._cohomology_basis_bounding_data mp_list = [bd[2] for bd in bounding_data_list] - + # Parameterise so zbar=0 corresponds to z=z_start mp_list = [reparameterise_differential_minpoly(mp, z_start) for mp in mp_list] - + if z_start==self._CC(Infinity): CCzg = PolynomialRing(self._CC, ['zbar','gbar']) mp_list = [CCzg(mp) for mp in mp_list] @@ -2849,7 +2851,7 @@ def initialise(z, i): rs = mp_list[i](z, DFw.gen(0)).roots(multiplicities=False) sb = find_closest_element(newg, rs) newg = rs[sb] - return newg + return newg else: CCzg = mp_list[0].parent() J = z_end-z_start @@ -2865,12 +2867,12 @@ def initialise(z, i): return newg fc_mp_list = [fast_callable(mp, domain=self._CC) for mp in mp_list] - fc_dmp_list = [fast_callable(mp.derivative(CCzg.gen(1)), domain=self._CC) + fc_dmp_list = [fast_callable(mp.derivative(CCzg.gen(1)), domain=self._CC) for mp in mp_list] if prec is None: prec = self._prec - # tau here is playing the role of the desired error. + # tau here is playing the role of the desired error. tau = self._RR(2)**(-prec+3) ONE = self._RR(1) LAMBDA = self._RR.pi()/2 @@ -2884,7 +2886,7 @@ def initialise(z, i): aes = [] for mp in mp_list: d = mp.dict() - mp = sum([d[k]*CCzg.gen(0)**k[0]*CCzg.gen(1)**k[1] + mp = sum([d[k]*CCzg.gen(0)**k[0]*CCzg.gen(1)**k[1] for k in d.keys() if d[k].abs()>tau]) cst = min([iz for (iz, ig) in d.keys() if ig==0]) a = QQ(max([(cst-iz)/ig for (iz,ig) in d.keys() if ig>0])) @@ -2894,10 +2896,10 @@ def initialise(z, i): cutoffs.append(((a+1)*tau/G)**(1/self._CC(a+1))/J.abs()) aes.append(a) cutoff_individually = bool(not all(ai<=0 for ai in aes) and cutoff_individually) - + if raise_errors: n_steps = self._prec-1 - + def error_handle(out): raise ConvergenceError("Newton iteration fails to converge") else: @@ -2913,7 +2915,7 @@ def error_handle(out): if cutoff_individually: z_fc_list = list(zip(fc_mp_list, fc_dmp_list)) - + def fv(hj, previous_estimate_and_validity): u2 = LAMBDA*hj.sinh() t = 1/(2*u2.exp()*u2.cosh()) @@ -2952,14 +2954,14 @@ def fv(hj, previous_estimate_and_validity): u1 = LAMBDA*hj.cosh() w = u1/(2*u2.cosh()**2) return (fj, valid), w*fj - + f0, v0 = fv(h0, (self.genus*[0], self.genus*[False])) else: cutoffs.append(1) cutoff = min(cutoffs) cutoff_z = J*cutoff J -= cutoff_z - + def fv(hj, previous_estimate): u2 = LAMBDA*hj.sinh() t = 1/(2*u2.exp()*u2.cosh()) @@ -2984,9 +2986,9 @@ def fv(hj, previous_estimate): outg.append(error_handle(newg)) fj = V(outg) u1 = LAMBDA*hj.cosh() - w = u1/(2*u2.cosh()**2) + w = u1/(2*u2.cosh()**2) return fj, w*fj - + u1, u2 = (LAMBDA*h0.cosh(),LAMBDA*h0.sinh()) y, w = (1/(2*u2.exp()*u2.cosh()), u1/(2*u2.cosh()**2)) z0 = cutoff_z+J*y @@ -2997,13 +2999,13 @@ def fv(hj, previous_estimate): D3_over_tau = v0.norm(Infinity) D4 = D3_over_tau results = [] - + for k in range(n_steps): hj = h0 val = v0 fj = f0 for j in range(2*Nh): - hj -= h + hj -= h try: fj, v = fv(hj, fj) except ConvergenceError: @@ -3020,7 +3022,7 @@ def fv(hj, previous_estimate): D1 = (results[-1]-results[-2]).norm(Infinity) D2 = (results[-1]-results[-3]).norm(Infinity) D = min(ONE,max(D1**(D1.log()/D2.log()),D2**2,tau*D3_over_tau,D4,tau)) - + if D <= tau: if cutoff_individually: fj = fj[0] @@ -3028,34 +3030,34 @@ def fv(hj, previous_estimate): h /= 2 Nh *= 2 return error_handle((J*results[-1], endscale*fj)) - + def _aj_based(self, P): r""" Return the Abel-Jacobi map to ``P`` from ``self._basepoint``. - + Computes a representative of the Abel-Jacobi map from ``self._basepoint`` to ``P`` via a well-chosen vertex ``V``. The representative given will be dependent on the path chosen. - + INPUT: - + - ``P`` -- tuple. A pair giving the endpoint of the integral, either in the form ``(z, w)`` or ``(Infinity, branch)``, where in the latter case we are using the convention that the `w` value over `\infty` is given by - the limit as ``z`` tends to `\infty` of ``self.w_values(z)[branch]``. - + the limit as ``z`` tends to `\infty` of ``self.w_values(z)[branch]``. + OUTPUT: - + A vector of length ``self.genus``. - + EXAMPLES: - + As the output of ``_aj_based`` is difficult to interpret due to its path - dependency, we look at the output of :meth:`abel_jacobi`. We check for - two hyperelliptic curves that the Abel-Jacobi map between two branch + dependency, we look at the output of :meth:`abel_jacobi`. We check for + two hyperelliptic curves that the Abel-Jacobi map between two branch points is a 2-torsion point over the lattice. Note we must remember to reduce over the period lattice, as results are path dependent:: - + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface sage: R. = QQ[] sage: p = 100 @@ -3073,11 +3075,11 @@ def _aj_based(self, P): sage: AJx2 = [2*z for z in AJ] sage: bool(S.reduce_over_period_lattice(AJx2).norm() < 1e-10) True - + """ ##### fcd = self._fastcall_cohomology_basis - + if self._integration_method=="heuristic": line_int = lambda edge: self.simple_vector_line_integral(edge, fcd) else: @@ -3086,19 +3088,19 @@ def _aj_based(self, P): ##### B = self._basepoint zP, wP = P - + try: Inf = bool(zP==zP.parent()(Infinity)) except TypeError: Inf = False - + if Inf: zV = self._vertices[B[0]] if zV==0: zV += 1 upstairs_edge = (P, zV) ci = bool(self._CC(Infinity) in self._differentials_branch_locus) - AJ, endgs = self._integrate_differentials_iteratively(upstairs_edge, + AJ, endgs = self._integrate_differentials_iteratively(upstairs_edge, cutoff_individually=ci) AJ = -AJ g0e = endgs[0] @@ -3106,7 +3108,7 @@ def _aj_based(self, P): g0s = [self.cohomology_basis()[0](zV, wi)/self._dfdw(zV, wi) for wi in ws] W_index = find_closest_element(g0e, g0s) if (g0e - self.cohomology_basis()[0](zV, ws[W_index])/self._dfdw(zV, ws[W_index])).abs()>1e-10: - raise ConvergenceError("Integrand continuation failed to get representative values, higher precision required.") + raise ConvergenceError("Integrand continuation failed to get representative values, higher precision required.") V_index = B[0] else: zP = self._CC(zP) @@ -3115,17 +3117,17 @@ def _aj_based(self, P): if zP==self._vertices[V_index]: W_index = find_closest_element(wP, self._wvalues[V_index]) - AJ = 0 + AJ = 0 else: b_index = find_closest_element(zP, self.branch_locus) b = self.branch_locus[b_index] #bl = self.branch_locus+self._differentials_branch_locus #b_index = find_closest_element(zP, bl) #b = bl[b_index] - + scale = max(b.abs() for b in self.branch_locus) d1 = self._CC(1e-2)*scale - + # We choose the first vertex we want to go to. # If the closest vertex is closer than the nearest branch point, just take that vertex # otherwise we need something smarter. @@ -3133,7 +3135,7 @@ def _aj_based(self, P): if not ((zP-self._vertices[V_index]).abs() < (zP-b).abs() or (zP-b).abs()<=delta): region = self.voronoi_diagram.regions[self.voronoi_diagram.point_region[b_index]] args = [(self._vertices[i]-zP).argument() - (b-zP).argument() for i in region] - suitable_vertex_indices = [region[i] + suitable_vertex_indices = [region[i] for i in range(len(region)) if args[i].abs()-self._RR.pi()/2>=-self._RR(1e-15)] suitable_vertices = [self._vertices[i] for i in suitable_vertex_indices] if suitable_vertices==[]: @@ -3148,7 +3150,7 @@ def _aj_based(self, P): u_edge = ((zP, wP_index), (zV, )) initial_continuation = self.homotopy_continuation(d_edge) AJ = -line_int(u_edge) - + w_end = initial_continuation[-1][1][wP_index] W_index = find_closest_element(w_end, self._wvalues[V_index]) else: @@ -3159,14 +3161,14 @@ def _aj_based(self, P): # Here we need a block of code to change the vertex if the path # from zP to zV would go through a ramification point of the integrands fl = [c for c in self._differentials_branch_locus if not c==self._CC(Infinity)] - ts = [((c-zP)*(zV-zP).conjugate()).real()/(zP-zV).norm()**2 + ts = [((c-zP)*(zV-zP).conjugate()).real()/(zP-zV).norm()**2 for c in fl] ds = [(fl[i]-zP-ts[i]*(zV-zP)).abs() for i in range(len(ts)) if (ts[i]>=0 and ts[i]<=1)] while (len(ds)>=1 and min(ds)=0 and ts[i]<=1)] @@ -3178,11 +3180,11 @@ def _aj_based(self, P): wP_index = find_closest_element(ws, ws_list) ws = ws_list[wP_index] upstairs_edge = ((zs, ws), zV) - AJ, endgs = self._integrate_differentials_iteratively(upstairs_edge, + AJ, endgs = self._integrate_differentials_iteratively(upstairs_edge, cutoff_individually=False) AJ = -AJ g0e = endgs[0] - + ws = self.w_values(zV) g0s = [self.cohomology_basis()[0](zV, wi)/self._dfdw(zV, wi) for wi in ws] W_index = find_closest_element(g0e, g0s) @@ -3206,33 +3208,33 @@ def _aj_based(self, P): except KeyError: Ie = line_int(e) self._integral_dict[e] = Ie - AJ += s*Ie + AJ += s*Ie return AJ def abel_jacobi(self, divisor, verbose=False): r""" - Return the Abel-Jacobi map of ``divisor``. - + Return the Abel-Jacobi map of ``divisor``. + Return a representative of the Abel-Jacobi map of a divisor with basepoint ``self._basepoint``. - + INPUT: - + - ``divisor`` -- list. A list with each entry a tuple of the form ``(v, P)``, - where ``v`` is the valuation of the divisor at point ``P``, ``P`` as per + where ``v`` is the valuation of the divisor at point ``P``, ``P`` as per the input to :meth:`_aj_based`. - ``verbose`` -- logical (default: False). Whether to report the progress of the computation, in terms of how many elements of the list ``divisor`` - have been completed. - + have been completed. + OUTPUT: - + A vector of length ``self.genus``. EXAMPLES: - We can test that the Abel-Jacobi map between two branchpoints of a + We can test that the Abel-Jacobi map between two branchpoints of a superelliptic curve of degree `p` is a `p`-torsion point in the Jacobian:: sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface @@ -3241,10 +3243,12 @@ def abel_jacobi(self, divisor, verbose=False): sage: S = RiemannSurface(y^p-x^4+1, prec=100) sage: divisor = [(-1, (-1, 0)), (1, (1, 0))] sage: AJ = S.abel_jacobi(divisor) # long time (15 seconds) - sage: AJxp = [p*z for z in AJ] # long time + sage: AJxp = [p*z for z in AJ] # long time sage: bool(S.reduce_over_period_lattice(AJxp).norm()<1e-7) # long time True """ + if isinstance(divisor, FunctionFieldDivisor): + divisor = self.divisor_to_divisor_list(divisor) ans = 0 n = len(divisor) for i in range(n): @@ -3258,24 +3262,24 @@ def abel_jacobi(self, divisor, verbose=False): def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None, normalised=False): r""" - Reduce a vector over the period lattice. - - Given a vector of length ``self.genus``, this method returns a vector - in the same orbit of the period lattice that is short. There are two - possible methods, ``'svp'`` which returns a certified shortest vector, + Reduce a vector over the period lattice. + + Given a vector of length ``self.genus``, this method returns a vector + in the same orbit of the period lattice that is short. There are two + possible methods, ``'svp'`` which returns a certified shortest vector, but can be much slower for higher genus curves, and ``'ip'``, which is faster but not guaranteed to return the shortest vector. In general the - latter will perform well when the lattice basis vectors are of similar - size. - + latter will perform well when the lattice basis vectors are of similar + size. + INPUT: - - - ``vector`` -- vector. A vector of length ``self.genus`` to reduce over + + - ``vector`` -- vector. A vector of length ``self.genus`` to reduce over the lattice. - + - ``method`` -- string (default: ``'ip'``). String specifying the method to use to reduce the vector. THe options are ``'ip'`` and ``'svp'``. - + - ``b`` -- integer (default provided): as for :meth:`homomorphism_basis`, and used in its invocation if (re)calculating said basis. @@ -3284,20 +3288,20 @@ def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None, normal :meth:`homomorphism_basis`, and used in its invocation if (re)calculating said basis. - - ``normalised`` -- logical (default: ``False``). Whether to use the + - ``normalised`` -- logical (default: ``False``). Whether to use the period matrix with the differentials normalised s.t. the `A`-matrix - is the identity. - + is the identity. + OUTPUT: - - Complex vector of length ``self.genus`` in the same orbit as ``vector`` + + Complex vector of length ``self.genus`` in the same orbit as ``vector`` in the lattice. - + EXAMPLES: - + We can check that the lattice basis vectors themselves are reduced to zero:: - + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface sage: R. = QQ[] sage: S = RiemannSurface(y^2-x^5+1) @@ -3309,7 +3313,7 @@ def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None, normal True True - We can also check that the method ``'svp'`` always gives a smaller norm + We can also check that the method ``'svp'`` always gives a smaller norm than ``'ip'``:: sage: for vector in S.period_matrix().columns(): @@ -3323,7 +3327,7 @@ def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None, normal """ if not len(vector)==self.genus: raise ValueError("Input vector needs to be of length {}".format(self.genus)) - + VR = VectorSpace(self._RR, 2*self.genus) VC = VectorSpace(self._CC, self.genus) I = self._CC(0, 1) @@ -3333,9 +3337,9 @@ def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None, normal AM = PM[:, 0:self.genus] AInv = numerical_inverse(AM) PM = AInv*PM - + if method=="svp": - H = max(max(z.real_part().abs() for z in vector), + H = max(max(z.real_part().abs() for z in vector), max(z.imag_part().abs() for z in vector)) if b is None: b = self._prec-5-H.log2().floor() @@ -3344,24 +3348,24 @@ def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None, normal S = 2**b if H*S > 2**(self._prec-4): raise ValueError("insufficient precision for b=%s" % b) - + def C2Z(v): vR = [(S*z.real_part()).round() for z in v] vR += [(S*z.imag_part()).round() for z in v] return vR - + M = Matrix(ZZ, 2*self.genus, 2*self.genus, [C2Z(c) for c in PM.columns()]) u = C2Z(vector) L = IntegerLattice(M) u = VR(u)-VR(L.closest_vector(u)) reduced = VC([self._CC(u[i]+I*u[i+self.genus])/S for i in range(self.genus)]) - + elif method=="ip": - + def C2R(v): return VR([z.real_part() for z in v]+[z.imag_part() for z in v]) - + u = C2R(vector) basis_vecs = [C2R(c) for c in PM.columns()] M = Matrix([[ei.dot_product(ej) for ei in basis_vecs] for ej in basis_vecs]) @@ -3371,23 +3375,47 @@ def C2R(v): reduced = VC([self._CC(u[i]+I*u[i+self.genus]) for i in range(self.genus)]) else: raise ValueError("Must give a valid method.") - + return reduced + def curve(self): + r""" + Return the curve from which this Riemann surface is obtained + + Riemann surfaces explicitly obtained from a curve return that same object. + For others, the curve is constructed and cached, so that an identical curve is + returned upon subsequent calls. + + OUTPUT: + + Curve from which Riemann surface is obtained. + + EXAMPLE: + + sage: R. = QQ[] + sage: C = Curve( y^3+x^3-1) + sage: S = C.riemann_surface() + sage: S.curve() is C + True + """ + if self._curve is None: + self._curve = Curve(self.f) + return self._curve + def places_at_branch_locus(self): r""" - Return the places above the branch locus. + Return the places above the branch locus. - Return a list of the of places above the branch locus. This must be - done over the base ring, and so the places are given in terms of the - factors of the discriminant. Currently, this method only works when - ``self._R.base_ring()==QQ`` as for other rings, the function field - for ``Curve(self.f)`` is not implemented. To go from these divisors to - a divisor list, see :meth:`divisor_to_divisor_list`. + Return a list of the of places above the branch locus. This must be + done over the base ring, and so the places are given in terms of the + factors of the discriminant. Currently, this method only works when + ``self._R.base_ring()==QQ`` as for other rings, the function field + for ``Curve(self.f)`` is not implemented. To go from these divisors to + a divisor list, see :meth:`divisor_to_divisor_list`. OUTPUT: - List of places of the functions field ``Curve(self.f).function_field()``. + List of places of the functions field ``Curve(self.f).function_field()``. EXAMPLES:: @@ -3406,7 +3434,7 @@ def places_at_branch_locus(self): K = self._R.base_ring() if not K==QQ: raise NotImplementedError - C = Curve(self.f) + C = self.curve() KC = C.function_field() g0, g1 = self._R.gens() Kb = FunctionField(K, str(g0)) @@ -3420,10 +3448,10 @@ def places_at_branch_locus(self): def strong_approximation(self, divisor, S): r""" - Apply the method of strong approximation to a divisor. + Apply the method of strong approximation to a divisor. As described in [Neu2018]_, apply the method of strong approximation to - ``divisor`` with list of places to avoid ``S``. Currently, this method + ``divisor`` with list of places to avoid ``S``. Currently, this method only works when ``self._R.base_ring()==QQ`` as for other rings, the function field for ``Curve(self.f)`` is not implemented. @@ -3431,11 +3459,11 @@ def strong_approximation(self, divisor, S): - ``divisor`` -- an element of ``Curve(self.f).function_field().divisor_group()`` - - ``S`` -- list. A list of places to avoid. + - ``S`` -- list. A list of places to avoid. OUTPUT: - A tuple ``(D, B)``, where ``D`` is a new divisor, linearly equivalent + A tuple ``(D, B)``, where ``D`` is a new divisor, linearly equivalent to ``divisor``, but not intersecting ``S``, and ``B`` is a list of tuples ``(v, b)`` where ``b`` are the functions giving the linear equivalence, added with multiplicity ``v``. @@ -3453,17 +3481,17 @@ def strong_approximation(self, divisor, S): + Place (x^2 + x + 1, y), [(1, (1/(x - 2))*y)]) """ - # One would standardly expect to run this with + # One would standardly expect to run this with # S = Curve(self.f).places_at_infinity() # or # S = Curve(self.f).places_at_infinity()+self.places_at_branch_locus() # # To avoid current implementation issues with going between divisors - # and divisor lists, we implement a method that handles only divisors + # and divisor lists, we implement a method that handles only divisors K = self._R.base_ring() if not K==QQ: raise NotImplementedError - C = Curve(self.f) + C = self.curve() KC = C.function_field() g0, g1 = self._R.gens() Kb = FunctionField(K, str(g0)) @@ -3476,7 +3504,7 @@ def strong_approximation(self, divisor, S): Fac = g0-K(rr) p0 = MO.ideal(Fac).place() q0 = KC.places_above(p0)[0] - + new_divisor = divisor B = [] for p in divisor.support(): @@ -3522,7 +3550,7 @@ def divisor_to_divisor_list(self, divisor): OUTPUT: - A list with elements of the form ``(v, (z, w))`` representing the finite places. + A list with elements of the form ``(v, (z, w))`` representing the finite places. EXAMPLES:: @@ -3538,11 +3566,11 @@ def divisor_to_divisor_list(self, divisor): .. TODO:: Currently this method can only handle places above finite points in - the base. It would be useful to extend this to allow for places at - infinity. + the base. It would be useful to extend this to allow for places at + infinity. """ - # If this error bound is too restrictive, this method might fail and - # not return. One might want to change the way this error is handled. + # If this error bound is too restrictive, this method might fail and + # not return. One might want to change the way this error is handled. eps = self._RR(2)**(-self._prec+3) dl = [] @@ -3550,20 +3578,22 @@ def divisor_to_divisor_list(self, divisor): RF = PolynomialRing(PZ, 'w') for d in divisor.support(): + if d.is_infinite_place(): + raise NotImplementedError("Conversion of infinite places not implemented yet.") v = divisor.valuation(d) gs = d._prime.gens() - + g0 = self._R(gs[0]) - gis = [sum([PZ(gi.list()[i])*RF.gen()**i + gis = [sum([PZ(gi.list()[i])*RF.gen()**i for i in range(len(gi.list()))]) for gi in gs[1:]] - + rs = self._CCz(g0).roots() rys = [] for r, m in rs: ys = [] for gi in gis: - # This test is a bit clunky, it surely can be made more efficient. + # This test is a bit clunky, it surely can be made more efficient. if len(ys): ers = min([gi(y, r).abs() for y in ys]) else: @@ -3577,7 +3607,7 @@ def divisor_to_divisor_list(self, divisor): nys = poly.roots() ys += [ny[0] for ny in nys] rys += [(v*m*n, (r, y)) for y, n in nys] - + if rys: dl.extend(rys) else: From f0727d647d18e699c709bfb7d589055877c3a227 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 1 Aug 2020 11:09:33 -0700 Subject: [PATCH 234/742] TensorFreeSubmodule_comp, TensorFreeSubmoduleBasis_comp: New --- src/sage/tensor/modules/tensor_free_module.py | 9 ++ .../tensor/modules/tensor_free_submodule.py | 93 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 src/sage/tensor/modules/tensor_free_submodule.py diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index dbeb1f2be25..611f54b3f02 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -686,3 +686,12 @@ def tensor_type(self): """ return self._tensor_type + + def basis(self, symbol, latex_symbol=None, from_family=None, + indices=None, latex_indices=None, symbol_dual=None, + latex_symbol_dual=None): + from sage.tensor.modules.free_module_comp_basis import FreeModuleCompTensorBasis + return FreeModuleCompTensorBasis(self, symbol, latex_symbol=latex_symbol, + indices=indices, latex_indices=latex_indices, + symbol_dual=symbol_dual, + latex_symbol_dual=latex_symbol_dual) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py new file mode 100644 index 00000000000..49020027b3c --- /dev/null +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -0,0 +1,93 @@ +r""" +Free submodules of tensor products of free modules +""" + +#****************************************************************************** +# Copyright (C) 2020 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.cachefunc import cached_method +from .tensor_free_module import TensorFreeModule +from .finite_rank_free_module import FiniteRankFreeModule +from .tensor_free_submodule_basis import TensorFreeSubmoduleBasis_comp + +class TensorFreeSubmodule_comp(TensorFreeModule): + r""" + Class for free submodules of tensor products of free modules + that are defined by the symmetries of a + :class:`~sage.tensor.modules.comp.Components` object. + + EXAMPLES:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M + Free module of type-(2,0) tensors + with Fully symmetric 2-indices components w.r.t. [0, 1, 2] + on the Rank-3 free module M over the Integer Ring + """ + def __init__(self, fmodule, tensor_type, name=None, latex_name=None, + sym=None, antisym=None): + self._fmodule = fmodule + self._tensor_type = tuple(tensor_type) + # Create a tensor only because we need a Components object + tensor = fmodule.tensor(tensor_type, + name=name, latex_name=latex_name, + sym=sym, antisym=antisym) + frame = list(fmodule.irange()) + self._comp = tensor._new_comp(frame) + rank = len(list(self._comp.non_redundant_index_generator())) + # Skip TensorFreeModule.__init__ + FiniteRankFreeModule.__init__(self, fmodule._ring, rank, name=name, + latex_name=latex_name, + start_index=fmodule._sindex, + output_formatter=fmodule._output_formatter) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(QQ, 2, name='M') + sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M + Free module of type-(2,0) tensors + with Fully symmetric 2-indices components w.r.t. [0, 1, 2] + on the Rank-3 free module M over the Integer Ring + + """ + return "Free module of type-({},{}) tensors with {} on the {}".format( + self._tensor_type[0], self._tensor_type[1], self._comp, self._fmodule) + + def is_submodule(self, other): + r""" + Return ``True`` if ``self`` is a submodule of ``other``. + + """ + raise NotImplementedError + + @cached_method + def basis(self, symbol): + r""" + + EXAMPLES:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)) + sage: e_Sym2M = Sym2M.basis('e'); e_Sym2M + + sage: for a in e_Sym2M: a.display() + e_0*e_0 + e_0*e_1 + e_0*e_2 + e_1*e_1 + e_1*e_2 + e_2*e_2 + """ + return TensorFreeSubmoduleBasis_comp(self, symbol) From 46500a50644e04d76529fa379a7870baadce181f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 1 Aug 2020 11:38:42 -0700 Subject: [PATCH 235/742] Move basis method to TensorFreeModule --- src/sage/tensor/modules/tensor_free_module.py | 39 +++++++++++++++++++ .../tensor/modules/tensor_free_submodule.py | 22 ----------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 611f54b3f02..5c7f5b1a659 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -66,6 +66,7 @@ from sage.tensor.modules.free_module_morphism import \ FiniteRankFreeModuleMorphism from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism +from .tensor_free_submodule_basis import TensorFreeSubmoduleBasis_comp class TensorFreeModule(FiniteRankFreeModule): r""" @@ -695,3 +696,41 @@ def basis(self, symbol, latex_symbol=None, from_family=None, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) + + + @cached_method + def basis(self, symbol, latex_symbol=None, from_family=None, + indices=None, latex_indices=None, symbol_dual=None, + latex_symbol_dual=None): + r""" + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: T = M.tensor_module(1,1) + sage: e_T = T.basis('e'); e_T + + sage: for a in e_T: a.display() + e_0*e^0 + e_0*e^1 + e_0*e^2 + e_1*e^0 + e_1*e^1 + e_1*e^2 + e_2*e^0 + e_2*e^1 + e_2*e^2 + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)) + sage: e_Sym2M = Sym2M.basis('e'); e_Sym2M + + sage: for a in e_Sym2M: a.display() + e_0*e_0 + e_0*e_1 + e_0*e_2 + e_1*e_1 + e_1*e_2 + e_2*e_2 + """ + return TensorFreeSubmoduleBasis_comp(self, symbol) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 49020027b3c..dcdc7d4fd82 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -14,7 +14,6 @@ from sage.misc.cachefunc import cached_method from .tensor_free_module import TensorFreeModule from .finite_rank_free_module import FiniteRankFreeModule -from .tensor_free_submodule_basis import TensorFreeSubmoduleBasis_comp class TensorFreeSubmodule_comp(TensorFreeModule): r""" @@ -70,24 +69,3 @@ def is_submodule(self, other): """ raise NotImplementedError - - @cached_method - def basis(self, symbol): - r""" - - EXAMPLES:: - - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp - sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)) - sage: e_Sym2M = Sym2M.basis('e'); e_Sym2M - - sage: for a in e_Sym2M: a.display() - e_0*e_0 - e_0*e_1 - e_0*e_2 - e_1*e_1 - e_1*e_2 - e_2*e_2 - """ - return TensorFreeSubmoduleBasis_comp(self, symbol) From bbeaced4758750f0857478b0966033d5dcdb0aa8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 1 Aug 2020 13:12:27 -0700 Subject: [PATCH 236/742] Add missing file --- .../modules/tensor_free_submodule_basis.py | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/sage/tensor/modules/tensor_free_submodule_basis.py diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py new file mode 100644 index 00000000000..31f6b1bbbb2 --- /dev/null +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -0,0 +1,71 @@ +r""" +Free module bases indexed by component indices +""" + +#****************************************************************************** +# Copyright (C) 2020 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.tensor.modules.free_module_basis import Basis_abstract +from sage.tensor.modules.comp import Components + +class TensorFreeSubmoduleBasis_comp(Basis_abstract): + r""" + Standard basis of a tensor module with prescribed symmetries. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: T11 = M.tensor_module(1,1) + sage: e11 = T11.basis('e') + sage: for a in e11: a.display() + e_0*e^0 + e_0*e^1 + e_0*e^2 + e_1*e^0 + e_1*e^1 + e_1*e^2 + e_2*e^0 + e_2*e^1 + e_2*e^2 + + """ + + def __init__(self, tensor_module, symbol, latex_symbol=None, indices=None, + latex_indices=None, symbol_dual=None, latex_symbol_dual=None): + base_module = tensor_module.base_module() + base_module_basis = base_module.basis(symbol, latex_symbol, indices, + latex_indices, symbol_dual, latex_symbol_dual) + super().__init__(tensor_module, symbol, latex_symbol, indices, latex_indices) + self._base_module_basis = base_module_basis + try: + # TensorFreeSubmodule_comp + self._comp = tensor_module._comp + except AttributeError: + # TensorFreeModule + tensor = tensor_module() + frame = list(base_module.irange()) + self._comp = tensor._new_comp(frame) + + def __iter__(self): + r""" + Generate the basis elements of ``self``. + """ + tensor_module = self._fmodule + base_module = tensor_module.base_module() + base_module_basis = self._base_module_basis + for ind in self._comp.non_redundant_index_generator(): + element = tensor_module.element_class(base_module, tensor_module._tensor_type) + element.set_comp(base_module_basis)[ind] = 1 + yield element + +# Todo: Make it a Family +# symmetrize/antisymmetrize it +# dual basis +# add test for dual +# lift/reduce/retract From 28d3c2073b403defd00e4520e886958f0cbd0af8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 2 Aug 2020 21:20:29 -0700 Subject: [PATCH 237/742] FiniteRankFreeModule: Add methods is_submodule, ambient_module --- .../tensor/modules/finite_rank_free_module.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 091dc252ad5..ecc2e914d35 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -2824,3 +2824,30 @@ def identity_map(self, name='Id', latex_name=None): latex_name = name self._identity_map.set_name(name=name, latex_name=latex_name) return self._identity_map + + def ambient_module(self): + """ + Return the ambient module associated to this module. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: M.ambient_module() is M + True + """ + return self + + def is_submodule(self, other): + """ + Return ``True`` if ``self`` is a submodule of ``other``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: N = FiniteRankFreeModule(ZZ, 4, name='M') + sage: M.is_submodule(M) + True + sage: M.is_submodule(N) + False + """ + return self == other From 72ffe906975d5fdce4f59504e0d3b237e88610e6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 2 Aug 2020 21:21:00 -0700 Subject: [PATCH 238/742] TensorFreeModule: Remove duplicate method 'basis' --- src/sage/tensor/modules/tensor_free_module.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 5c7f5b1a659..3959b88368a 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -688,16 +688,6 @@ def tensor_type(self): """ return self._tensor_type - def basis(self, symbol, latex_symbol=None, from_family=None, - indices=None, latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): - from sage.tensor.modules.free_module_comp_basis import FreeModuleCompTensorBasis - return FreeModuleCompTensorBasis(self, symbol, latex_symbol=latex_symbol, - indices=indices, latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) - - @cached_method def basis(self, symbol, latex_symbol=None, from_family=None, indices=None, latex_indices=None, symbol_dual=None, From 8d2ef6e7634223db406ec85a2ef9c3d1bc9c1983 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 2 Aug 2020 21:21:20 -0700 Subject: [PATCH 239/742] TensorFreeSubmodule_comp.is_submodule: New --- .../tensor/modules/tensor_free_submodule.py | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index dcdc7d4fd82..449acc81b77 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -12,6 +12,7 @@ #****************************************************************************** from sage.misc.cachefunc import cached_method +from sage.sets.disjoint_set import DisjointSet from .tensor_free_module import TensorFreeModule from .finite_rank_free_module import FiniteRankFreeModule @@ -67,5 +68,61 @@ def is_submodule(self, other): r""" Return ``True`` if ``self`` is a submodule of ``other``. + EXAMPLES:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: T60M = M.tensor_module(6, 0) + sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) + sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) + sage: Sym012345M.is_submodule(Sym012345M) + True + sage: Sym012345M.is_submodule(Sym0123x45M) + True + sage: Sym0123x45M.is_submodule(Sym012345M) + False + sage: Sym012x345M.is_submodule(Sym0123x45M) + False + sage: all(S.is_submodule(T60M) for S in (Sym0123x45M, Sym012x345M, Sym012345M)) + True + """ - raise NotImplementedError + if self == other: + return True + self_base_module = self.base_module() + self_tensor_type = self.tensor_type() + try: + other_base_module = other.base_module() + other_tensor_type = other.tensor_type() + except AttributeError: + return False + if self_base_module != other_base_module: + return False + if self_tensor_type != other_tensor_type: + return False + # Use the union-find data structure + def is_coarsening_of(self_sym_list, other_sym_list): + S = DisjointSet(self_tensor_type[0] + self_tensor_type[1]) + for index_set in self_sym_list: + i = index_set[0] + for j in index_set[1:]: + S.union(i, j) + for index_set in other_sym_list: + i = S.find(index_set[0]) + for j in index_set[1:]: + if S.find(j) != i: + return False + return True + # Similar code is in Component.contract, should refactor. + try: + other_sym = other._comp._sym + other_antisym = other._comp._antisym + except AttributeError: + # other is full tensor module (no symmetry) + return True + if not is_coarsening_of(self._comp._sym, other_sym): + return False + if not is_coarsening_of(self._comp._antisym, other._comp._antisym): + return False + return True From b132b842b137c05351820224ec78edeea6eab758 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 2 Aug 2020 21:27:49 -0700 Subject: [PATCH 240/742] TensorFreeSubmodule_comp.ambient_module: New --- src/sage/tensor/modules/tensor_free_submodule.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 449acc81b77..bfa46091960 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -64,6 +64,21 @@ def _repr_(self): return "Free module of type-({},{}) tensors with {} on the {}".format( self._tensor_type[0], self._tensor_type[1], self._comp, self._fmodule) + def ambient_module(self): + """ + Return the ambient module associated to this module. + + EXAMPLES:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: T60M = M.tensor_module(6, 0) + sage: Sym0123x45M.ambient_module() is T60M + True + """ + return self.base_module().tensor_module(*self.tensor_type()) + def is_submodule(self, other): r""" Return ``True`` if ``self`` is a submodule of ``other``. From 677c5aecb9d6f0b3e8c521c196913d62e39204a6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 2 Aug 2020 21:27:57 -0700 Subject: [PATCH 241/742] Fix doctests --- src/sage/tensor/modules/tensor_free_module.py | 2 +- src/sage/tensor/modules/tensor_free_submodule.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 3959b88368a..a07d96ce11d 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -699,7 +699,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: T = M.tensor_module(1,1) sage: e_T = T.basis('e'); e_T - + sage: for a in e_T: a.display() e_0*e^0 e_0*e^1 diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index bfa46091960..bcb083135ec 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -54,7 +54,8 @@ def _repr_(self): EXAMPLES:: - sage: M = FiniteRankFreeModule(QQ, 2, name='M') + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M Free module of type-(2,0) tensors with Fully symmetric 2-indices components w.r.t. [0, 1, 2] From 87d21c6c4e1655f8dd1ae650c66cdb97d55efee4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 2 Aug 2020 21:39:43 -0700 Subject: [PATCH 242/742] TensorFreeSubmodule_comp: Add alias ambient = ambient_module --- src/sage/tensor/modules/tensor_free_submodule.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index bcb083135ec..3f2ce525d5e 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -65,7 +65,7 @@ def _repr_(self): return "Free module of type-({},{}) tensors with {} on the {}".format( self._tensor_type[0], self._tensor_type[1], self._comp, self._fmodule) - def ambient_module(self): + def ambient_module(self): # compatible with sage.modules.free_module.FreeModule_generic """ Return the ambient module associated to this module. @@ -80,6 +80,8 @@ def ambient_module(self): """ return self.base_module().tensor_module(*self.tensor_type()) + ambient = ambient_module # compatible with sage.modules.with_basis.subquotient.SubmoduleWithBasis + def is_submodule(self, other): r""" Return ``True`` if ``self`` is a submodule of ``other``. From a6c6427437f4659533a72b31c212e33d7e32f84a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 3 Aug 2020 13:22:05 -0700 Subject: [PATCH 243/742] TensorFreeSubmodule_comp: Add tests --- .../tensor/modules/tensor_free_submodule.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 3f2ce525d5e..5763d9567e6 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -30,6 +30,25 @@ class TensorFreeSubmodule_comp(TensorFreeModule): Free module of type-(2,0) tensors with Fully symmetric 2-indices components w.r.t. [0, 1, 2] on the Rank-3 free module M over the Integer Ring + + Canonical injections from submodules are coercions:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: T60M = M.tensor_module(6, 0) + sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) + sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) + sage: Sym0123x45M.has_coerce_map_from(Sym012345M) + True + sage: T60M.has_coerce_map_from(Sym0123x45M) + True + + TESTS:: + + sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: TestSuite(Sym0123x45M).run() + """ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, sym=None, antisym=None): From 4dc5f18857dabe6a1951d132e5b0b96b175d1361 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 3 Aug 2020 17:34:51 -0700 Subject: [PATCH 244/742] FiniteRankFreeModule: Accept init arg 'ambient' --- .../tensor/modules/finite_rank_free_module.py | 24 +++++++++++++++---- .../tensor/modules/tensor_free_submodule.py | 22 ++++------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index ecc2e914d35..cb0500b02bb 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -757,7 +757,7 @@ class :class:`~sage.modules.module.Module`. @staticmethod def __classcall_private__(cls, ring, rank, name=None, latex_name=None, start_index=0, - output_formatter=None, category=None): + output_formatter=None, category=None, ambient=None): r""" Normalize init arguments for ``UniqueRepresentation`` @@ -791,6 +791,7 @@ def __init__( start_index: int = 0, output_formatter=None, category=None, + ambient=None, ): r""" See :class:`FiniteRankFreeModule` for documentation and examples. @@ -810,8 +811,12 @@ def __init__( if ring not in Rings().Commutative(): raise TypeError("the module base ring must be commutative") category = Modules(ring).FiniteDimensional().or_subcategory(category) - Parent.__init__(self, base=ring, category=category) + Parent.__init__(self, base=ring, category=category, facade=ambient) self._ring = ring # same as self._base + if ambient is None: + self._ambient_module = self + else: + self._ambient_module = ambient self._rank = rank self._name = name # This duplicates the normalization done in __classcall_private__, @@ -2825,7 +2830,7 @@ def identity_map(self, name='Id', latex_name=None): self._identity_map.set_name(name=name, latex_name=latex_name) return self._identity_map - def ambient_module(self): + def ambient_module(self): # compatible with sage.modules.free_module.FreeModule_generic """ Return the ambient module associated to this module. @@ -2834,8 +2839,17 @@ def ambient_module(self): sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: M.ambient_module() is M True + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: T60M = M.tensor_module(6, 0) + sage: Sym0123x45M.ambient_module() is T60M + True """ - return self + return self._ambient_module + + ambient = ambient_module # compatible with sage.modules.with_basis.subquotient.SubmoduleWithBasis def is_submodule(self, other): """ @@ -2850,4 +2864,4 @@ def is_submodule(self, other): sage: M.is_submodule(N) False """ - return self == other + return self == other or self == self.ambient_module() diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 5763d9567e6..2463e062b62 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -51,7 +51,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): """ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, - sym=None, antisym=None): + sym=None, antisym=None, *, ambient=None, category=None): self._fmodule = fmodule self._tensor_type = tuple(tensor_type) # Create a tensor only because we need a Components object @@ -61,11 +61,13 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, frame = list(fmodule.irange()) self._comp = tensor._new_comp(frame) rank = len(list(self._comp.non_redundant_index_generator())) + category = fmodule.category().TensorProducts().FiniteDimensional().Subobjects().or_subcategory(category) # Skip TensorFreeModule.__init__ FiniteRankFreeModule.__init__(self, fmodule._ring, rank, name=name, latex_name=latex_name, start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + output_formatter=fmodule._output_formatter, + ambient=ambient, category=category) def _repr_(self): r""" @@ -84,22 +86,6 @@ def _repr_(self): return "Free module of type-({},{}) tensors with {} on the {}".format( self._tensor_type[0], self._tensor_type[1], self._comp, self._fmodule) - def ambient_module(self): # compatible with sage.modules.free_module.FreeModule_generic - """ - Return the ambient module associated to this module. - - EXAMPLES:: - - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp - sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) - sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M.ambient_module() is T60M - True - """ - return self.base_module().tensor_module(*self.tensor_type()) - - ambient = ambient_module # compatible with sage.modules.with_basis.subquotient.SubmoduleWithBasis def is_submodule(self, other): r""" From 07291564d5dd3d19b6a8b115981523e6b7b84c74 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 3 Aug 2020 17:36:51 -0700 Subject: [PATCH 245/742] TensorFreeSubmodule_comp: Factor out _is_symmetry_coarsening_of, add _element_constructor_ --- .../tensor/modules/tensor_free_submodule.py | 99 ++++++++++++++----- 1 file changed, 77 insertions(+), 22 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 2463e062b62..daa7e3a62ae 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -35,6 +35,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0) sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) @@ -43,6 +44,11 @@ class TensorFreeSubmodule_comp(TensorFreeModule): True sage: T60M.has_coerce_map_from(Sym0123x45M) True + sage: t = e[0]^6 + sage: t.parent() + FIXME + sage: Sym012345M(t) is t + FIXME TESTS:: @@ -86,6 +92,73 @@ def _repr_(self): return "Free module of type-({},{}) tensors with {} on the {}".format( self._tensor_type[0], self._tensor_type[1], self._comp, self._fmodule) + def _is_symmetry_coarsening_of(self, coarser_comp, finer_comp): + self_tensor_type = self.tensor_type() + + def sym_antisym(comp): + if isinstance(comp, tuple): + sym, antisym = tuple + if sym is None: + sym = [] + if antisym is None: + antisym = [] + return sym, antisym + # Similar code is in Component.contract, should refactor. + try: + return comp._sym, comp._antisym + except AttributeError: + return [], [] + + def is_coarsening_of(self_sym_list, other_sym_list): + # Use the union-find data structure + S = DisjointSet(self_tensor_type[0] + self_tensor_type[1]) + for index_set in self_sym_list: + i = index_set[0] + for j in index_set[1:]: + S.union(i, j) + for index_set in other_sym_list: + i = S.find(index_set[0]) + for j in index_set[1:]: + if S.find(j) != i: + return False + return True + + finer_sym, finer_antisym = sym_antisym(finer_comp) + if not finer_sym and not finer_antisym: + return True + coarser_sym, coarser_antisym = sym_antisym(coarser_comp) + if not is_coarsening_of(self._comp._sym, other_sym): + return False + if not is_coarsening_of(self._comp._antisym, other_antisym): + return False + return True + + def _element_constructor_(self, comp=[], basis=None, name=None, + latex_name=None, sym=None, antisym=None): + if sym is not None or antisym is not None: + # Refuse to create a tensor with finer symmetries + # than those defining the subspace + if not self._is_symmetry_coarsening_of((sym, antisym), self._comp): + raise ValueError("cannot create a tensor with symmetries {} as an element of {}". + format((sym, antisym), self)) + try: + comp_parent = comp.parent() + except AttributeError: + comp_parent = None + if comp_parent == self.ambient_module(): + resu = comp + # comp is already a tensor. If its declared symmetries are coarser + # than the symmetries defining self, we can use it directly. + if self._is_symmetry_coarsening_of(resu, self._comp): + return resu + if sym is None: + sym = self._comp._sym + if antisym is None: + sym = self._comp._antisym + resu = super()._element_constructor_(comp=comp, basis=basis, name=name, + latex_name=latex_name, + sym=sym, antisym=antisym) + return resu def is_submodule(self, other): r""" @@ -111,7 +184,7 @@ def is_submodule(self, other): True """ - if self == other: + if super().is_submodule(other): return True self_base_module = self.base_module() self_tensor_type = self.tensor_type() @@ -124,28 +197,10 @@ def is_submodule(self, other): return False if self_tensor_type != other_tensor_type: return False - # Use the union-find data structure - def is_coarsening_of(self_sym_list, other_sym_list): - S = DisjointSet(self_tensor_type[0] + self_tensor_type[1]) - for index_set in self_sym_list: - i = index_set[0] - for j in index_set[1:]: - S.union(i, j) - for index_set in other_sym_list: - i = S.find(index_set[0]) - for j in index_set[1:]: - if S.find(j) != i: - return False - return True - # Similar code is in Component.contract, should refactor. + try: - other_sym = other._comp._sym - other_antisym = other._comp._antisym + other_comp = other._comp except AttributeError: # other is full tensor module (no symmetry) return True - if not is_coarsening_of(self._comp._sym, other_sym): - return False - if not is_coarsening_of(self._comp._antisym, other._comp._antisym): - return False - return True + return self._is_symmetry_coarsening_of(self._comp, other_comp) From a07fe6d3ecea7266eefc8d5d7318a8a186ff0aef Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 3 Aug 2020 18:18:46 -0700 Subject: [PATCH 246/742] Fixup --- src/sage/tensor/modules/finite_rank_free_module.py | 2 +- src/sage/tensor/modules/tensor_free_submodule.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index cb0500b02bb..108a845c596 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -2864,4 +2864,4 @@ def is_submodule(self, other): sage: M.is_submodule(N) False """ - return self == other or self == self.ambient_module() + return self == other or self.ambient_module() == other diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index daa7e3a62ae..1e2f0f4ae51 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -127,9 +127,9 @@ def is_coarsening_of(self_sym_list, other_sym_list): if not finer_sym and not finer_antisym: return True coarser_sym, coarser_antisym = sym_antisym(coarser_comp) - if not is_coarsening_of(self._comp._sym, other_sym): + if not is_coarsening_of(coarser_sym, finer_sym): return False - if not is_coarsening_of(self._comp._antisym, other_antisym): + if not is_coarsening_of(coarser_antisym, finer_antisym): return False return True From cff18191ec726801ed70d255abfee783df6e6366 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 3 Aug 2020 19:06:18 -0700 Subject: [PATCH 247/742] TensorFreeModule._element_constructor_: Accept FreeModuleTensor of same tensor type and base module as input --- src/sage/tensor/modules/tensor_free_module.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index a07d96ce11d..07e99366b5a 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -484,6 +484,17 @@ def _element_constructor_(self, comp=[], basis=None, name=None, latex_name=autom._latex_name) for basis, comp in autom._components.items(): resu._components[basis] = comp.copy() + elif isinstance(comp, FreeModuleTensor): + tensor = comp + if self._tensor_type != tensor._tensor_type or \ + self._fmodule != tensor.base_module(): + raise TypeError("cannot coerce the {}".format(tensor) + + " to an element of {}".format(self)) + resu = self.element_class(self._fmodule, self._tensor_type, + name=name, latex_name=latex_name, + sym=sym, antisym=antisym) + for basis, comp in tensor._components.items(): + resu._components[basis] = comp.copy() else: # Standard construction: resu = self.element_class(self._fmodule, self._tensor_type, From a6f81a614c4e945bf495008bf5bc3169659fa6db Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 3 Aug 2020 19:06:55 -0700 Subject: [PATCH 248/742] TensorFreeSubmodule_comp: Set ambient correctly --- src/sage/tensor/modules/tensor_free_submodule.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 1e2f0f4ae51..e42df1cbd89 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -41,14 +41,14 @@ class TensorFreeSubmodule_comp(TensorFreeModule): sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) sage: Sym0123x45M.has_coerce_map_from(Sym012345M) - True + False sage: T60M.has_coerce_map_from(Sym0123x45M) - True - sage: t = e[0]^6 + False + sage: t = e[0] * e[0] * e[0] * e[0] * e[0] * e[0] sage: t.parent() - FIXME + Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring sage: Sym012345M(t) is t - FIXME + False TESTS:: @@ -69,6 +69,8 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, rank = len(list(self._comp.non_redundant_index_generator())) category = fmodule.category().TensorProducts().FiniteDimensional().Subobjects().or_subcategory(category) # Skip TensorFreeModule.__init__ + if ambient is None: + ambient = fmodule.tensor_module(*tensor_type) FiniteRankFreeModule.__init__(self, fmodule._ring, rank, name=name, latex_name=latex_name, start_index=fmodule._sindex, @@ -155,7 +157,8 @@ def _element_constructor_(self, comp=[], basis=None, name=None, sym = self._comp._sym if antisym is None: sym = self._comp._antisym - resu = super()._element_constructor_(comp=comp, basis=basis, name=name, + resu = super()._element_constructor_(comp=comp, + basis=basis, name=name, latex_name=latex_name, sym=sym, antisym=antisym) return resu From 22e9e1cb230de30ad3a80f5f1ee2753555c10eb6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 3 Aug 2020 22:34:30 -0700 Subject: [PATCH 249/742] TensorFreeModule._coerce_map_from_: Add coercion from submodules --- src/sage/tensor/modules/tensor_free_module.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 07e99366b5a..fd5b092d41c 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -609,6 +609,13 @@ def _coerce_map_from_(self, other): sage: M.tensor_module(0,2)._coerce_map_from_(N.dual_exterior_power(2)) False + Coercion from submodules:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: Sym01M = TensorFreeSubmodule_comp(M, (2, 0), sym=((0, 1))) + sage: M.tensor_module(2,0)._coerce_map_from_(Sym01M) + True + """ from .free_module_homset import FreeModuleHomset from .ext_pow_free_module import (ExtPowerFreeModule, @@ -634,6 +641,11 @@ def _coerce_map_from_(self, other): # Coercion of an automorphism to a type-(1,1) tensor: return self._tensor_type == (1,1) and \ self._fmodule is other.base_module() + try: + if other.is_submodule(self): + return True + except AttributeError: + pass return False #### End of parent methods From 02927b83fb8d002153bb118b506d82395b99099c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 3 Aug 2020 22:36:02 -0700 Subject: [PATCH 250/742] TensorFreeSubmodule_comp: Fix coerce map tests --- src/sage/tensor/modules/tensor_free_submodule.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index e42df1cbd89..19cfbae44e0 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -41,9 +41,9 @@ class TensorFreeSubmodule_comp(TensorFreeModule): sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) sage: Sym0123x45M.has_coerce_map_from(Sym012345M) - False + True sage: T60M.has_coerce_map_from(Sym0123x45M) - False + True sage: t = e[0] * e[0] * e[0] * e[0] * e[0] * e[0] sage: t.parent() Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring From 4995258b766262d152b8a160c316f19c733b1849 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 3 Aug 2020 22:51:17 -0700 Subject: [PATCH 251/742] TensorFreeSubmodule_comp.lift: New --- .../tensor/modules/tensor_free_submodule.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 19cfbae44e0..8d9090ef816 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -12,6 +12,7 @@ #****************************************************************************** from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute from sage.sets.disjoint_set import DisjointSet from .tensor_free_module import TensorFreeModule from .finite_rank_free_module import FiniteRankFreeModule @@ -207,3 +208,25 @@ def is_submodule(self, other): # other is full tensor module (no symmetry) return True return self._is_symmetry_coarsening_of(self._comp, other_comp) + + @lazy_attribute + def lift(self): + r""" + The lift (embedding) map from ``self`` to the ambient space. + + EXAMPLES:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M.lift + Generic morphism: + From: Free module of type-(6,0) tensors + with 6-indices components w.r.t. [0, 1, 2], + with symmetry on the index positions (0, 1, 2, 3), + with symmetry on the index positions (4, 5) + on the Rank-3 free module M over the Integer Ring + To: Free module of type-(6,0) tensors + on the Rank-3 free module M over the Integer Ring + """ + return self.module_morphism(function=lambda x: x, codomain=self.ambient()) From eca7a57b3ca6ecf1eab49df4b4b60f278f8de42f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 4 Aug 2020 12:28:58 -0700 Subject: [PATCH 252/742] FiniteRankFreeModule: Add _test_basis method --- src/sage/tensor/modules/finite_rank_free_module.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 108a845c596..77fcc807446 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1396,6 +1396,18 @@ def basis(self, symbol, latex_symbol=None, from_family=None, "linearly independent") return resu + def _test_basis(self, **options): + r""" + Test that the ``basis`` method works correctly. + """ + tester = self._tester(**options) + b = self.basis('test') + # Test uniqueness + b_again = self.basis('test') + tester.assertTrue(b is b_again) + # Test rank + tester.assertEqual(len(b), self.rank()) + def tensor(self, tensor_type, name=None, latex_name=None, sym=None, antisym=None): r""" From f633af8fb9f9d2005c1f780a9cab714385e29fc9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 4 Aug 2020 19:54:10 -0700 Subject: [PATCH 253/742] FiniteRankFreeModule._test_basis: Test indices and containment --- src/sage/tensor/modules/finite_rank_free_module.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 77fcc807446..bc4b6ca5ddc 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1407,6 +1407,12 @@ def _test_basis(self, **options): tester.assertTrue(b is b_again) # Test rank tester.assertEqual(len(b), self.rank()) + indices = list(self.irange()) + tester.assertEqual(len(b), len(indices)) + # Test basis indexing + for index, element in zip(indices, b): + tester.assertTrue(element is b[index]) + tester.assertTrue(element in self) def tensor(self, tensor_type, name=None, latex_name=None, sym=None, antisym=None): From ef3e7b76f0f43729351582e016089879fce14644 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 4 Aug 2020 19:58:08 -0700 Subject: [PATCH 254/742] TensorFreeSubmoduleBasis_comp: Add keys, __getitem__; compute symmetrized elements --- .../modules/tensor_free_submodule_basis.py | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index 31f6b1bbbb2..33b0787e796 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -52,20 +52,52 @@ def __init__(self, tensor_module, symbol, latex_symbol=None, indices=None, frame = list(base_module.irange()) self._comp = tensor._new_comp(frame) + def keys(self): + yield from self._comp.non_redundant_index_generator() + def __iter__(self): r""" Generate the basis elements of ``self``. + """ + for ind in self.keys(): + yield self[ind] + + def __getitem__(self, index): + r""" + Return the basis element corresponding to a given index. + + INPUT: + + - ``index`` -- the index of the basis element + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: T11 = M.tensor_module(1,1) + sage: e11 = T11.basis('e') + sage: e11[1, 2].display() + e_1*e^2 + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M + Free module of type-(2,0) tensors + with Fully symmetric 2-indices components w.r.t. [0, 1, 2] + on the Rank-3 free module M over the Integer Ring + sage: eSym2M = Sym2M.basis('e') + sage: eSym2M[1, 1].display() + e_1*e_1 + sage: eSym2M[1, 2].display() + e_1*e_2 + e_2*e_1 + """ tensor_module = self._fmodule base_module = tensor_module.base_module() base_module_basis = self._base_module_basis - for ind in self._comp.non_redundant_index_generator(): - element = tensor_module.element_class(base_module, tensor_module._tensor_type) - element.set_comp(base_module_basis)[ind] = 1 - yield element + element = tensor_module([]) + element.set_comp(base_module_basis)[index] = 1 + return element # Todo: Make it a Family -# symmetrize/antisymmetrize it # dual basis # add test for dual # lift/reduce/retract From 419bec6e6324b5d8232032e429859d4f132cc23c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 5 Aug 2020 11:08:11 -0700 Subject: [PATCH 255/742] FiniteRankFreeModule._test_basis: Run the test suite of the basis object --- .../tensor/modules/finite_rank_free_module.py | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index bc4b6ca5ddc..b1291525909 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1396,11 +1396,28 @@ def basis(self, symbol, latex_symbol=None, from_family=None, "linearly independent") return resu - def _test_basis(self, **options): + def _test_basis(self, tester=None, **options): r""" Test that the ``basis`` method works correctly. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: M._test_basis(verbose=True) + + Running the test suite of self.basis('test') + running ._test_category() . . . pass + running ._test_new() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_pickling() . . . pass + """ - tester = self._tester(**options) + from sage.misc.sage_unittest import TestSuite + # The intention is to raise an exception only if this is + # run as a sub-testsuite of a larger testsuite. + # (from _test_elements) + is_sub_testsuite = (tester is not None) + tester = self._tester(tester=tester, **options) b = self.basis('test') # Test uniqueness b_again = self.basis('test') @@ -1412,7 +1429,10 @@ def _test_basis(self, **options): # Test basis indexing for index, element in zip(indices, b): tester.assertTrue(element is b[index]) - tester.assertTrue(element in self) + # Run test suite of the basis object (similar to _test_elements) + tester.info("\n Running the test suite of self.basis('test')") + TestSuite(b).run(verbose=tester._verbose, prefix=tester._prefix + " ", + raise_on_failure=is_sub_testsuite) def tensor(self, tensor_type, name=None, latex_name=None, sym=None, antisym=None): From c7649e407e5812a8c00452908ae6f5586d770956 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 5 Aug 2020 12:26:44 -0700 Subject: [PATCH 256/742] FiniteRankFreeModule.isomorphism_with_fixed_basis: Make basis argument optional; add test method --- .../tensor/modules/finite_rank_free_module.py | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index b1291525909..53de21f863b 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -2620,7 +2620,7 @@ def hom(self, codomain, matrix_rep, bases=None, name=None, return homset(matrix_rep, bases=bases, name=name, latex_name=latex_name) - def isomorphism_with_fixed_basis(self, basis, codomain=None): + def isomorphism_with_fixed_basis(self, basis=None, codomain=None): r""" Construct the canonical isomorphism from the free module ``self`` to a free module in which ``basis`` of ``self`` is mapped to the @@ -2628,8 +2628,9 @@ def isomorphism_with_fixed_basis(self, basis, codomain=None): INPUT: - - ``basis`` -- the basis of ``self`` which should be mapped to the - distinguished basis on ``codomain`` + - ``basis`` -- (default: ``None``) the basis of ``self`` which + should be mapped to the distinguished basis on ``codomain``; + if ``None``, the default basis is assumed. - ``codomain`` -- (default: ``None``) the codomain of the isomorphism represented by a free module within the category :class:`~sage.categories.modules_with_basis.ModulesWithBasis` with @@ -2694,6 +2695,8 @@ def isomorphism_with_fixed_basis(self, basis, codomain=None): ValueError: domain and codomain must have the same base ring """ base_ring = self.base_ring() + if basis is None: + basis = self.default_basis() if codomain is None: from sage.combinat.free_module import CombinatorialFreeModule if isinstance(basis._symbol, str): @@ -2720,6 +2723,20 @@ def _isomorphism(x): return self.module_morphism(function=_isomorphism, codomain=codomain) + def _test_isomorphism_with_fixed_basis(self, **options): + r""" + Test that the method ``isomorphism_with_fixed_basis`` works correctly. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: M._test_isomorphism_with_fixed_basis() + """ + tester = self._tester(**options) + basis = self.basis('test') + morphism = self.isomorphism_with_fixed_basis(basis) + tester.assertEqual(morphism.codomain().rank(), self.rank()) + def endomorphism(self, matrix_rep, basis=None, name=None, latex_name=None): r""" Construct an endomorphism of the free module ``self``. From fbc4445c7f73cad787bffe57195d035b7d6891ae Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 5 Aug 2020 14:13:21 -0700 Subject: [PATCH 257/742] WIP: _comp and irange --- src/sage/tensor/modules/tensor_free_module.py | 13 +++++++++ .../tensor/modules/tensor_free_submodule.py | 27 ++++++++----------- .../modules/tensor_free_submodule_basis.py | 9 +------ 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index fd5b092d41c..dae92b0a605 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -747,3 +747,16 @@ def basis(self, symbol, latex_symbol=None, from_family=None, e_2*e_2 """ return TensorFreeSubmoduleBasis_comp(self, symbol) + + @cached_method + def _basis_comp(self): + # Data for TensorFreeSubmoduleBasis_comp + frame = tuple(self.base_module().irange()) + tensor = self.ambient()() + return tensor._new_comp(frame) + + def irange(self): + r""" + Index generator, labelling the elements of a basis of ``self``. + """ + yield from self._basis_comp().non_redundant_index_generator() diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 8d9090ef816..ecd374018ee 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -61,17 +61,16 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, sym=None, antisym=None, *, ambient=None, category=None): self._fmodule = fmodule self._tensor_type = tuple(tensor_type) + if ambient is None: + ambient = fmodule.tensor_module(*tensor_type) + self._ambient_module = ambient # Create a tensor only because we need a Components object tensor = fmodule.tensor(tensor_type, name=name, latex_name=latex_name, sym=sym, antisym=antisym) - frame = list(fmodule.irange()) - self._comp = tensor._new_comp(frame) - rank = len(list(self._comp.non_redundant_index_generator())) + rank = len(list(self.irange())) category = fmodule.category().TensorProducts().FiniteDimensional().Subobjects().or_subcategory(category) # Skip TensorFreeModule.__init__ - if ambient is None: - ambient = fmodule.tensor_module(*tensor_type) FiniteRankFreeModule.__init__(self, fmodule._ring, rank, name=name, latex_name=latex_name, start_index=fmodule._sindex, @@ -93,7 +92,7 @@ def _repr_(self): """ return "Free module of type-({},{}) tensors with {} on the {}".format( - self._tensor_type[0], self._tensor_type[1], self._comp, self._fmodule) + self._tensor_type[0], self._tensor_type[1], self._basis_comp(), self._fmodule) def _is_symmetry_coarsening_of(self, coarser_comp, finer_comp): self_tensor_type = self.tensor_type() @@ -141,7 +140,7 @@ def _element_constructor_(self, comp=[], basis=None, name=None, if sym is not None or antisym is not None: # Refuse to create a tensor with finer symmetries # than those defining the subspace - if not self._is_symmetry_coarsening_of((sym, antisym), self._comp): + if not self._is_symmetry_coarsening_of((sym, antisym), self._basis_comp()): raise ValueError("cannot create a tensor with symmetries {} as an element of {}". format((sym, antisym), self)) try: @@ -152,12 +151,12 @@ def _element_constructor_(self, comp=[], basis=None, name=None, resu = comp # comp is already a tensor. If its declared symmetries are coarser # than the symmetries defining self, we can use it directly. - if self._is_symmetry_coarsening_of(resu, self._comp): + if self._is_symmetry_coarsening_of(resu, self._basis_comp()): return resu if sym is None: - sym = self._comp._sym + sym = self._basis_comp()._sym if antisym is None: - sym = self._comp._antisym + antisym = self._basis_comp()._antisym resu = super()._element_constructor_(comp=comp, basis=basis, name=name, latex_name=latex_name, @@ -202,12 +201,8 @@ def is_submodule(self, other): if self_tensor_type != other_tensor_type: return False - try: - other_comp = other._comp - except AttributeError: - # other is full tensor module (no symmetry) - return True - return self._is_symmetry_coarsening_of(self._comp, other_comp) + other_comp = other._basis_comp() + return self._is_symmetry_coarsening_of(self._basis_comp(), other_comp) @lazy_attribute def lift(self): diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index 33b0787e796..64be46ffc02 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -43,14 +43,7 @@ def __init__(self, tensor_module, symbol, latex_symbol=None, indices=None, latex_indices, symbol_dual, latex_symbol_dual) super().__init__(tensor_module, symbol, latex_symbol, indices, latex_indices) self._base_module_basis = base_module_basis - try: - # TensorFreeSubmodule_comp - self._comp = tensor_module._comp - except AttributeError: - # TensorFreeModule - tensor = tensor_module() - frame = list(base_module.irange()) - self._comp = tensor._new_comp(frame) + self._comp = tensor_module._basis_comp() def keys(self): yield from self._comp.non_redundant_index_generator() From 7715f04c94acee3879fa553c7d91e1eea0bdd9c4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 16:16:48 -0700 Subject: [PATCH 258/742] Update doctest outputs --- .../tensor/modules/finite_rank_free_module.py | 1 + src/sage/tensor/modules/tensor_free_module.py | 30 +++++++++---------- .../tensor/modules/tensor_free_submodule.py | 6 ++-- .../modules/tensor_free_submodule_basis.py | 26 ++++++++-------- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 53de21f863b..0b23d770057 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1407,6 +1407,7 @@ def _test_basis(self, tester=None, **options): Running the test suite of self.basis('test') running ._test_category() . . . pass + running ._test_iter_len() . . . pass running ._test_new() . . . pass running ._test_not_implemented_methods() . . . pass running ._test_pickling() . . . pass diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index dae92b0a605..7a9e13499cb 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -724,27 +724,27 @@ def basis(self, symbol, latex_symbol=None, from_family=None, sage: e_T = T.basis('e'); e_T sage: for a in e_T: a.display() - e_0*e^0 - e_0*e^1 - e_0*e^2 - e_1*e^0 - e_1*e^1 - e_1*e^2 - e_2*e^0 - e_2*e^1 - e_2*e^2 + e_0⊗e^0 + e_0⊗e^1 + e_0⊗e^2 + e_1⊗e^0 + e_1⊗e^1 + e_1⊗e^2 + e_2⊗e^0 + e_2⊗e^1 + e_2⊗e^2 sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)) sage: e_Sym2M = Sym2M.basis('e'); e_Sym2M sage: for a in e_Sym2M: a.display() - e_0*e_0 - e_0*e_1 - e_0*e_2 - e_1*e_1 - e_1*e_2 - e_2*e_2 + e_0⊗e_0 + e_0⊗e_1 + e_0⊗e_2 + e_1⊗e_1 + e_1⊗e_2 + e_2⊗e_2 """ return TensorFreeSubmoduleBasis_comp(self, symbol) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index ecd374018ee..16a03e272cc 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -29,7 +29,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M Free module of type-(2,0) tensors - with Fully symmetric 2-indices components w.r.t. [0, 1, 2] + with Fully symmetric 2-indices components w.r.t. (0, 1, 2) on the Rank-3 free module M over the Integer Ring Canonical injections from submodules are coercions:: @@ -87,7 +87,7 @@ def _repr_(self): sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M Free module of type-(2,0) tensors - with Fully symmetric 2-indices components w.r.t. [0, 1, 2] + with Fully symmetric 2-indices components w.r.t. (0, 1, 2) on the Rank-3 free module M over the Integer Ring """ @@ -217,7 +217,7 @@ def lift(self): sage: Sym0123x45M.lift Generic morphism: From: Free module of type-(6,0) tensors - with 6-indices components w.r.t. [0, 1, 2], + with 6-indices components w.r.t. (0, 1, 2), with symmetry on the index positions (0, 1, 2, 3), with symmetry on the index positions (4, 5) on the Rank-3 free module M over the Integer Ring diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index 64be46ffc02..ed4cdacd9dd 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -24,15 +24,15 @@ class TensorFreeSubmoduleBasis_comp(Basis_abstract): sage: T11 = M.tensor_module(1,1) sage: e11 = T11.basis('e') sage: for a in e11: a.display() - e_0*e^0 - e_0*e^1 - e_0*e^2 - e_1*e^0 - e_1*e^1 - e_1*e^2 - e_2*e^0 - e_2*e^1 - e_2*e^2 + e_0⊗e^0 + e_0⊗e^1 + e_0⊗e^2 + e_1⊗e^0 + e_1⊗e^1 + e_1⊗e^2 + e_2⊗e^0 + e_2⊗e^1 + e_2⊗e^2 """ @@ -69,18 +69,18 @@ def __getitem__(self, index): sage: T11 = M.tensor_module(1,1) sage: e11 = T11.basis('e') sage: e11[1, 2].display() - e_1*e^2 + e_1⊗e^2 sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M Free module of type-(2,0) tensors - with Fully symmetric 2-indices components w.r.t. [0, 1, 2] + with Fully symmetric 2-indices components w.r.t. (0, 1, 2) on the Rank-3 free module M over the Integer Ring sage: eSym2M = Sym2M.basis('e') sage: eSym2M[1, 1].display() - e_1*e_1 + e_1⊗e_1 sage: eSym2M[1, 2].display() - e_1*e_2 + e_2*e_1 + e_1⊗e_2 + e_2⊗e_1 """ tensor_module = self._fmodule From 7caacef17846f4e5c679451ab0a46b6a1cc50e7c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 16:41:08 -0700 Subject: [PATCH 259/742] Update doctest outputs --- .../tensor/modules/finite_rank_free_module.py | 21 +++++++++++++++++++ src/sage/tensor/modules/tensor_free_module.py | 4 ++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 0b23d770057..b476047d6e6 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1406,11 +1406,32 @@ def _test_basis(self, tester=None, **options): sage: M._test_basis(verbose=True) Running the test suite of self.basis('test') + running ._test_an_element() . . . pass + running ._test_cardinality() . . . pass running ._test_category() . . . pass + running ._test_construction() . . . pass + running ._test_elements() . . . + Running the test suite of self.an_element() + running ._test_category() . . . pass + running ._test_eq() . . . pass + running ._test_new() . . . pass + running ._test_nonzero_equal() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_pickling() . . . pass + pass + running ._test_elements_eq_reflexive() . . . pass + running ._test_elements_eq_symmetric() . . . pass + running ._test_elements_eq_transitive() . . . pass + running ._test_elements_neq() . . . pass + running ._test_enumerated_set_contains() . . . pass + running ._test_enumerated_set_iter_cardinality() . . . pass + running ._test_enumerated_set_iter_list() . . . pass + running ._test_eq() . . . pass running ._test_iter_len() . . . pass running ._test_new() . . . pass running ._test_not_implemented_methods() . . . pass running ._test_pickling() . . . pass + running ._test_some_elements() . . . pass """ from sage.misc.sage_unittest import TestSuite diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 7a9e13499cb..d566d4ead7d 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -722,7 +722,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: T = M.tensor_module(1,1) sage: e_T = T.basis('e'); e_T - + sage: for a in e_T: a.display() e_0⊗e^0 e_0⊗e^1 @@ -737,7 +737,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)) sage: e_Sym2M = Sym2M.basis('e'); e_Sym2M - + sage: for a in e_Sym2M: a.display() e_0⊗e_0 e_0⊗e_1 From ce3ca35473f1790f7f1b88f5370578198fe7f888 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 17:02:44 -0700 Subject: [PATCH 260/742] TensorFreeSubmodule_comp: Store sym, antisym, use it in _basis_comp --- src/sage/tensor/modules/tensor_free_submodule.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 16a03e272cc..1039ee6ec26 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -64,10 +64,8 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, if ambient is None: ambient = fmodule.tensor_module(*tensor_type) self._ambient_module = ambient - # Create a tensor only because we need a Components object - tensor = fmodule.tensor(tensor_type, - name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + self._sym = sym + self._antisym = antisym rank = len(list(self.irange())) category = fmodule.category().TensorProducts().FiniteDimensional().Subobjects().or_subcategory(category) # Skip TensorFreeModule.__init__ @@ -77,6 +75,12 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, output_formatter=fmodule._output_formatter, ambient=ambient, category=category) + @cached_method + def _basis_comp(self): + frame = tuple(self.base_module().irange()) + tensor = self.ambient()(sym=self._sym, antisym=self._antisym) + return tensor._new_comp(frame) + def _repr_(self): r""" Return a string representation of ``self``. From e940d0ffa01c0ed51d73cd4c066ef6418aef18dd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 17:26:00 -0700 Subject: [PATCH 261/742] TensorFreeSubmodule_comp._basis_comp: Fix up --- src/sage/tensor/modules/tensor_free_submodule.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 1039ee6ec26..f7ee2487c67 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -78,7 +78,8 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, @cached_method def _basis_comp(self): frame = tuple(self.base_module().irange()) - tensor = self.ambient()(sym=self._sym, antisym=self._antisym) + # Need to call _element_constructor_ explicitly, or the passed arguments are dropped + tensor = self.ambient()._element_constructor_(sym=self._sym, antisym=self._antisym) return tensor._new_comp(frame) def _repr_(self): From a6ebabf1dc2683f1cf0e4dd54c57bcb3421b4669 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 17:27:27 -0700 Subject: [PATCH 262/742] src/sage/tensor/modules/tensor_free_module.py: Fix doctest output --- src/sage/tensor/modules/tensor_free_module.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index d566d4ead7d..7663c8448a9 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -740,10 +740,10 @@ def basis(self, symbol, latex_symbol=None, from_family=None, sage: for a in e_Sym2M: a.display() e_0⊗e_0 - e_0⊗e_1 - e_0⊗e_2 + e_0⊗e_1 + e_1⊗e_0 + e_0⊗e_2 + e_2⊗e_0 e_1⊗e_1 - e_1⊗e_2 + e_1⊗e_2 + e_2⊗e_1 e_2⊗e_2 """ return TensorFreeSubmoduleBasis_comp(self, symbol) From 8d7879577afe8a40324adfc6d6f00262d6da8273 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 18:03:20 -0700 Subject: [PATCH 263/742] TensorFreeSubmoduleBasis_comp.values: New --- src/sage/tensor/modules/tensor_free_submodule_basis.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index ed4cdacd9dd..96076a27bd3 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -48,6 +48,9 @@ def __init__(self, tensor_module, symbol, latex_symbol=None, indices=None, def keys(self): yield from self._comp.non_redundant_index_generator() + def values(self): + yield from self + def __iter__(self): r""" Generate the basis elements of ``self``. From fec6930606048747da6290ea92ec000ad26d894e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 18:55:47 -0700 Subject: [PATCH 264/742] Disable _test_basis on non-base modules --- src/sage/tensor/modules/ext_pow_free_module.py | 9 +++++++++ src/sage/tensor/modules/finite_rank_free_module.py | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/ext_pow_free_module.py b/src/sage/tensor/modules/ext_pow_free_module.py index c68033fdf51..588d72db42f 100644 --- a/src/sage/tensor/modules/ext_pow_free_module.py +++ b/src/sage/tensor/modules/ext_pow_free_module.py @@ -423,6 +423,10 @@ def degree(self): """ return self._degree + def basis(self, *args, **kwds): + # We override it so that _test_basis is disabled. + # See https://trac.sagemath.org/ticket/30229#comment:6 for a better solution + raise NotImplementedError #*********************************************************************** @@ -893,3 +897,8 @@ def degree(self): """ return self._degree + + def basis(self, *args, **kwds): + # We override it so that _test_basis is disabled. + # See https://trac.sagemath.org/ticket/30229#comment:6 for a better solution + raise NotImplementedError diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index b476047d6e6..33f8ef8267f 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1440,7 +1440,10 @@ def _test_basis(self, tester=None, **options): # (from _test_elements) is_sub_testsuite = (tester is not None) tester = self._tester(tester=tester, **options) - b = self.basis('test') + try: + b = self.basis('test') + except NotImplementedError: + return # Test uniqueness b_again = self.basis('test') tester.assertTrue(b is b_again) From 5403ee0677cc9388d76b825ee1cc9e35b8a90b96 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 24 Aug 2022 12:32:59 +0900 Subject: [PATCH 265/742] Finishing the migration to the methods for building free resolutions. --- src/sage/homology/free_resolution.py | 42 ++++++++----- src/sage/homology/graded_resolution.py | 84 +++++++++++--------------- src/sage/modules/free_module.py | 16 +++-- 3 files changed, 75 insertions(+), 67 deletions(-) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index efa327d051c..7b7c611ca24 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -52,11 +52,12 @@ AUTHORS: - Kwankyu Lee (2022-05-13): initial version - +- Travis Scrimshaw (2022-08-23): refactored for free module inputs """ # **************************************************************************** # Copyright (C) 2022 Kwankyu Lee +# (C) 2022 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -96,7 +97,7 @@ class FreeResolution(SageObject, metaclass=ClasscallMetaclass): homological index `1`. """ @staticmethod - def __classcall_private__(cls, module, degrees=None, shifts=None, name='S', **kwds): + def __classcall_private__(cls, module, degrees=None, shifts=None, name='S', graded=False, **kwds): """ Dispatch to the correct constructor. @@ -158,9 +159,9 @@ def __classcall_private__(cls, module, degrees=None, shifts=None, name='S', **kw if not is_free_module: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular if not isinstance(S, MPolynomialRing_libsingular): - raise NotImplementedError("the ring must be a free module or a polynomial ring that can be constructed in Singular") + raise NotImplementedError("the module must be a free module or have the base ring be a polynomial ring using Singular") - if degrees is not None or shifts is not None: + if graded or degrees is not None or shifts is not None: # We are computing a graded resolution from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular return GradedFiniteFreeResolution_singular(module, degrees=degrees, shifts=shifts, name=name, **kwds) @@ -169,7 +170,7 @@ def __classcall_private__(cls, module, degrees=None, shifts=None, name='S', **kw # Otherwise we know it is a free module - if degrees is not None or shifts is not None: + if graded or degrees is not None or shifts is not None: # We are computing a graded resolution from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module return GradedFiniteFreeResolution_free_module(module, degrees=degrees, shifts=shifts, name=name, **kwds) @@ -214,10 +215,10 @@ def _repr_(self): sage: r = FreeResolution(m1, name='S') sage: print(FreeResolution._repr_(r)) Free resolution with initial map: - [z^2 - y*w, y*z - x*w, y^2 - x*z] + [z^2 - y*w y*z - x*w y^2 - x*z] """ if isinstance(self._module, Matrix): - return f"Free resolution with inital map:\n{self._module}" + return f"Free resolution with initial map:\n{self._module}" return f"Free resolution of {self._module}" def _repr_module(self, i): @@ -674,23 +675,36 @@ def _maps(self): sage: res._maps [[x^4 + 3*x^2 + 2]] - An overdetermined system over a PID:: - sage: from sage.homology.free_resolution import FreeResolution - sage: R. = QQ[] sage: M = matrix([[x^2, 2], ....: [3*x^2, 5], ....: [5*x^2, 4]]) + sage: res = FreeResolution(M.transpose()) + sage: res + S^3 <-- S^2 <-- 0 + sage: res._m() + [ 1 0] + [ 5/2 -x^2] + [ 2 -6*x^2] + sage: res._maps + [ + [ 1 0] + [ 5/2 -x^2] + [ 2 -6*x^2] + ] + + An overdetermined system over a PID:: + sage: res = FreeResolution(M) sage: res S^2 <-- S^2 <-- 0 sage: res._m() - [ x^2 3*x^2 5*x^2] - [ 2 5 4] + [x^2 0] + [ 2 -1] sage: res._maps [ [x^2 0] - [ 0 1] + [ 2 -1] ] """ if isinstance(self._module, Ideal_generic): @@ -811,7 +825,7 @@ def __init__(self, module, name='S', algorithm='heuristic', **kwds): sage: FreeResolution(Q.ideal([xb])) # has torsion Traceback (most recent call last): ... - NotImplementedError: the ring must be a free module or a polynomial ring that can be constructed in Singular + NotImplementedError: the module must be a free module or have the base ring be a polynomial ring using Singular """ self._algorithm = algorithm super().__init__(module, name=name, **kwds) diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index d9d64062a63..6396c0ab65f 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -7,17 +7,16 @@ EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFiniteFreeResolution_singular(I, algorithm='minimal') + sage: r = I.graded_free_resolution(algorithm='minimal') sage: r S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 - sage: GradedFiniteFreeResolution_singular(I, algorithm='shreyer') + sage: I.graded_free_resolution(algorithm='shreyer') S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 - sage: GradedFiniteFreeResolution_singular(I, algorithm='standard') + sage: I.graded_free_resolution(algorithm='standard') S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 - sage: GradedFiniteFreeResolution_singular(I, algorithm='heuristic') + sage: I.graded_free_resolution(algorithm='heuristic') S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 :: @@ -39,7 +38,7 @@ [ y -z w] [ x -y z] sage: m = d.image() - sage: GradedFiniteFreeResolution_singular(m, shifts=(2,2,2)) + sage: m.graded_free_resolution(shifts=(2,2,2)) S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 An example of multigraded resolution from Example 9.1 of [MilStu2005]_:: @@ -51,7 +50,7 @@ Ideal (c^2 - b*d, b*c - a*d, b^2 - a*c) of Multivariate Polynomial Ring in a, b, c, d over Rational Field sage: P3 = ProjectiveSpace(S) sage: C = P3.subscheme(I) # twisted cubic curve - sage: r = GradedFiniteFreeResolution_singular(I, degrees=[(1,0), (1,1), (1,2), (1,3)]) + sage: r = I.graded_free_resolution(degrees=[(1,0), (1,1), (1,2), (1,3)]) sage: r S((0, 0)) <-- S((-2, -4))⊕S((-2, -3))⊕S((-2, -2)) <-- S((-3, -5))⊕S((-3, -4)) <-- 0 sage: r.K_polynomial(names='s,t') @@ -60,11 +59,12 @@ AUTHORS: - Kwankyu Lee (2022-05): initial version - +- Travis Scrimshaw (2022-08-23): refactored for free module inputs """ # **************************************************************************** # Copyright (C) 2022 Kwankyu Lee +# (C) 2022 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -112,19 +112,18 @@ def __init__(self, module, degrees=None, shifts=None, name='S', **kwds): TESTS:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFiniteFreeResolution_singular(I) + sage: r = I.graded_free_resolution() sage: TestSuite(r).run(skip=['_test_pickling']) An overdetermined system over a PID:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + sage: from sage.homology.free_resolution import FreeResolution sage: M = matrix([[x^2, 2], ....: [3*x^2, 5], ....: [5*x^2, 4]]) - sage: res = GradedFiniteFreeResolution_free_module(M) + sage: res = FreeResolution(M, graded=True) sage: res S(0)⊕S(0) <-- S(-2)⊕S(0) <-- 0 sage: res._res_shifts @@ -167,10 +166,9 @@ def _repr_module(self, i): """ EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFiniteFreeResolution_singular(I) + sage: r = I.graded_free_resolution() sage: r._repr_module(0) 'S(0)' sage: r._repr_module(1) @@ -180,7 +178,7 @@ def _repr_module(self, i): sage: r._repr_module(3) '0' - sage: r = GradedFiniteFreeResolution_singular(I, shifts=[-1]) + sage: r = I.graded_free_resolution(shifts=[-1]) sage: r._repr_module(0) 'S(1)' """ @@ -199,15 +197,14 @@ def _repr_module(self, i): for sh in shifts) def shifts(self, i): - """ + r""" Return the shifts of ``self``. EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFiniteFreeResolution_singular(I) + sage: r = I.graded_free_resolution() sage: r.shifts(0) [0] sage: r.shifts(1) @@ -241,10 +238,9 @@ def betti(self, i, a=None): EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFiniteFreeResolution_singular(I) + sage: r = I.graded_free_resolution() sage: r.betti(0) {0: 1} sage: r.betti(1) @@ -285,10 +281,9 @@ def K_polynomial(self, names=None): EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFiniteFreeResolution_singular(I) + sage: r = I.graded_free_resolution() sage: r.K_polynomial() 2*t^3 - 3*t^2 + 1 """ @@ -325,18 +320,18 @@ class GradedFiniteFreeResolution_free_module(GradedFiniteFreeResolution, FiniteF EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + sage: from sage.homology.free_resolution import FreeResolution sage: R. = QQ[] sage: M = matrix([[x^3, 3*x^3, 5*x^3], ....: [0, x, 2*x]]) - sage: res = GradedFiniteFreeResolution_free_module(M) + sage: res = FreeResolution(M, graded=True) sage: res S(0)⊕S(0)⊕S(0) <-- S(-3)⊕S(-1) <-- 0 sage: M = matrix([[x^2, 2], ....: [3*x^2, 5], ....: [5*x^2, 4]]) - sage: res = GradedFiniteFreeResolution_free_module(M) + sage: res = FreeResolution(M, graded=True) sage: res S(0)⊕S(0) <-- S(-2)⊕S(0) <-- 0 """ @@ -346,11 +341,11 @@ def __init__(self, module, degrees=None, *args, **kwds): EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + sage: from sage.homology.free_resolution import FreeResolution sage: R. = QQ[] sage: M = matrix([[x^3, 3*x^3, 5*x^3], ....: [0, x, 2*x]]) - sage: res = GradedFiniteFreeResolution_free_module(M) + sage: res = FreeResolution(M, graded=True) sage: TestSuite(res).run(skip="_test_pickling") """ super().__init__(module, degrees=degrees, *args, **kwds) @@ -367,11 +362,11 @@ def _maps(self): TESTS:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + sage: from sage.homology.free_resolution import FreeResolution sage: R. = QQ[] sage: M = matrix([[x^3, 3*x^3, 5*x^3], ....: [0, x, 2*x]]) - sage: res = GradedFiniteFreeResolution_free_module(M) + sage: res = FreeResolution(M, graded=True) sage: res S(0)⊕S(0)⊕S(0) <-- S(-3)⊕S(-1) <-- 0 sage: res._maps @@ -386,8 +381,12 @@ def _maps(self): sage: M = matrix([[x^2, 2], ....: [3*x^2, 5], ....: [5*x^2, 4]]) - sage: res = GradedFiniteFreeResolution_free_module(M) + sage: res = FreeResolution(M, graded=True) sage: res._maps + [ + [x^2 0] + [ 2 -1] + ] sage: res._res_shifts [[2, 0]] @@ -400,6 +399,7 @@ def _maps(self): sage: res._res_shifts [[9]] """ + def compute_degree(base, i): """ Compute the degree by ``base * deg + shift``, @@ -486,10 +486,9 @@ class GradedFiniteFreeResolution_singular(GradedFiniteFreeResolution, FiniteFree EXAMPLES:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFiniteFreeResolution_singular(I) + sage: r = I.graded_free_resolution() sage: r S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 sage: len(r) @@ -498,8 +497,8 @@ class GradedFiniteFreeResolution_singular(GradedFiniteFreeResolution, FiniteFree sage: I = S.ideal([z^2 - y*w, y*z - x*w, y - x]) sage: I.is_homogeneous() True - sage: R = GradedFiniteFreeResolution_singular(I) - sage: R + sage: r = I.graded_free_resolution() + sage: r S(0) <-- S(-1)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3)⊕S(-4) <-- S(-5) <-- 0 """ def __init__(self, module, degrees=None, shifts=None, name='S', algorithm='heuristic', **kwds): @@ -508,22 +507,10 @@ def __init__(self, module, degrees=None, shifts=None, name='S', algorithm='heuri TESTS:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFiniteFreeResolution_singular(I) + sage: r = I.graded_free_resolution() sage: TestSuite(r).run(skip=['_test_pickling']) - - An overdetermined system over a PID:: - - sage: M = matrix([[x^2, 2], - ....: [3*x^2, 5], - ....: [5*x^2, 4]]) - sage: res = GradedFiniteFreeResolution_singular(M) - sage: res - S(0)⊕S(0) <-- S(-2)⊕S(0) <-- 0 - sage: res._res_shifts - [[2, 0]] """ super().__init__(module, degrees=degrees, shifts=shifts, name=name, **kwds) self._algorithm = algorithm @@ -537,10 +524,9 @@ def _maps(self): TESTS:: - sage: from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular sage: S. = PolynomialRing(QQ) sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = GradedFiniteFreeResolution_singular(I) + sage: r = I.graded_free_resolution() sage: r._maps [ [-y x] diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index b818e36ee48..8f27451a4ea 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -1779,8 +1779,8 @@ def free_resolution(self, *args, **kwds): [ z x*z] 0 <-- C_0 <-------------- C_1 <-- 0 """ - from sage.homology.free_resolution import FiniteFreeResolution_free_module - return FiniteFreeResolution_free_module(self, *args, **kwds) + from sage.homology.free_resolution import FreeResolution + return FreeResolution(self, *args, **kwds) def graded_free_resolution(self, *args, **kwds): r""" @@ -1803,8 +1803,16 @@ def graded_free_resolution(self, *args, **kwds): sage: N.graded_free_resolution(degrees=[2, 1, 3], shifts=[2, 3]) S(-2)⊕S(-3) <-- S(-6)⊕S(-8) <-- 0 """ - from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module - return GradedFiniteFreeResolution_free_module(self, *args, **kwds) + 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 + return GradedFiniteFreeResolution_singular(self, *args, **kwds) + + if isinstance(self, FreeModule_generic): + 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 have the base ring be a polynomial ring using Singular") class FreeModule_generic(Module_free_ambient): From b524b39f8e7c904b50274ceeba51c14c431aa510 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 24 Aug 2022 12:44:06 +0900 Subject: [PATCH 266/742] Catching poly rings for ideals that are implemented via Singular. --- src/sage/modules/free_module.py | 2 +- src/sage/rings/ideal.py | 2 +- .../polynomial/multi_polynomial_ideal.py | 30 ++++++++++++++++--- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 8f27451a4ea..8e5c3da9e17 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -1787,7 +1787,7 @@ def graded_free_resolution(self, *args, **kwds): Return a graded free resolution of ``self``. For input options, see - :class:`~sage.homology.graded_resolution.GradedFreeResolution`. + :class:`~sage.homology.graded_resolution.GradedFiniteFreeResolution`. EXAMPLES:: diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index e1bce143122..b1537ee3651 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -1225,7 +1225,7 @@ def graded_free_resolution(self, *args, **kwds): Return a graded free resolution of ``self``. For input options, see - :class:`~sage.homology.graded_resolution.GradedFreeResolution`. + :class:`~sage.homology.graded_resolution.GradedFiniteFreeResolution`. EXAMPLES:: diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 139b942555c..18f52b0ad74 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -1797,9 +1797,20 @@ def free_resolution(self, *args, **kwds): [-x^2] [ y x^2] [ y] 0 <-- C_0 <---------- C_1 <------- C_2 <-- 0 + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = q.parent()[] + sage: I = R.ideal([x^2+y^2+z^2, x*y*z^4]) + sage: I.free_resolution() + Traceback (most recent call last): + ... + NotImplementedError: the ring must be a polynomial ring using Singular """ - from sage.homology.free_resolution import FiniteFreeResolution_singular - return FiniteFreeResolution_singular(self, *args, **kwds) + from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if isinstance(self.ring(), MPolynomialRing_libsingular): + from sage.homology.free_resolution import FiniteFreeResolution_singular + return FiniteFreeResolution_singular(self, *args, **kwds) + raise NotImplementedError("the ring must be a polynomial ring using Singular") @require_field def graded_free_resolution(self, *args, **kwds): @@ -1825,9 +1836,20 @@ def graded_free_resolution(self, *args, **kwds): sage: I = R.ideal([f,g,h]) sage: I.graded_free_resolution(degrees=[1,2]) S(0) <-- S(-2)⊕S(-2) <-- S(-4) <-- 0 + + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = q.parent()[] + sage: I = R.ideal([x^2+y^2+z^2, x*y*z^4]) + sage: I.graded_free_resolution() + Traceback (most recent call last): + ... + NotImplementedError: the ring must be a polynomial ring using Singular """ - from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular - return GradedFiniteFreeResolution_singular(self, *args, **kwds) + from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if isinstance(self.ring(), MPolynomialRing_libsingular): + from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular + return GradedFiniteFreeResolution_singular(self, *args, **kwds) + raise NotImplementedError("the ring must be a polynomial ring using Singular") @handle_AA_and_QQbar @singular_gb_standard_options From dc7aad2bc28cbf739aecb9c28136d6fddbedfaaf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 23:25:26 -0700 Subject: [PATCH 267/742] src/sage/tensor/modules/tensor_free_submodule_basis.py: Add doctests --- src/sage/tensor/modules/tensor_free_module.py | 1 + .../modules/tensor_free_submodule_basis.py | 30 +++++++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 7663c8448a9..c356953b110 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -716,6 +716,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" + Return the standard basis of ``self`` corresponding to a basis of the base module. EXAMPLES:: diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index 96076a27bd3..45704e81ac1 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -46,14 +46,34 @@ def __init__(self, tensor_module, symbol, latex_symbol=None, indices=None, self._comp = tensor_module._basis_comp() def keys(self): + """ + Return an iterator for the keys (indices) of the family. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: T11 = M.tensor_module(1,1) + sage: e11 = T11.basis('e') + sage: list(e11.keys()) + [(0, 0), (0, 1), (0, 2), + (1, 0), (1, 1), (1, 2), + (2, 0), (2, 1), (2, 2)] + """ yield from self._comp.non_redundant_index_generator() def values(self): - yield from self + """ + Return an iterator for the elements of the family. - def __iter__(self): - r""" - Generate the basis elements of ``self``. + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: T11 = M.tensor_module(1,1) + sage: e11 = T11.basis('e') + sage: [b.disp() for b in e11.values()] + [e_0⊗e^0, e_0⊗e^1, e_0⊗e^2, + e_1⊗e^0, e_1⊗e^1, e_1⊗e^2, + e_2⊗e^0, e_2⊗e^1, e_2⊗e^2] """ for ind in self.keys(): yield self[ind] @@ -93,7 +113,7 @@ def __getitem__(self, index): element.set_comp(base_module_basis)[index] = 1 return element -# Todo: Make it a Family +# Todo: # dual basis # add test for dual # lift/reduce/retract From 494794d767b6393eb9b8e59a14d13e8c3d9cbc30 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 24 Aug 2022 18:26:31 +0900 Subject: [PATCH 268/742] Refactor --- src/sage/homology/free_resolution.py | 254 ++++++++++++++------------- 1 file changed, 130 insertions(+), 124 deletions(-) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 7b7c611ca24..a6622d8cb8d 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -83,100 +83,92 @@ from copy import copy -class FreeResolution(SageObject, metaclass=ClasscallMetaclass): +def FreeResolution(module, degrees=None, shifts=None, name='S', graded=False, **kwds): """ - Abstract base class for free resolutions. + Constructor. - The matrix at index `i` in the list defines the differential map from - `(i + 1)`-th free module to the `i`-th free module over the base ring by - multiplication on the left. The number of matrices in the list is the - length of the resolution. The number of rows and columns of the matrices - define the ranks of the free modules in the resolution. + TESTS:: - Note that the first matrix in the list defines the differential map at - homological index `1`. - """ - @staticmethod - def __classcall_private__(cls, module, degrees=None, shifts=None, name='S', graded=False, **kwds): - """ - Dispatch to the correct constructor. - - TESTS:: - - sage: from sage.homology.free_resolution import FreeResolution - sage: S. = PolynomialRing(QQ) - sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() - sage: r = FreeResolution(m, name='S') - sage: type(r) - + sage: from sage.homology.free_resolution import FreeResolution + sage: S. = PolynomialRing(QQ) + sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() + sage: r = FreeResolution(m, name='S') + sage: type(r) + - sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = FreeResolution(I) - sage: type(r) - + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: type(r) + - sage: R. = QQ[] - sage: M = R^3 - sage: v = M([x^2, 2*x^2, 3*x^2]) - sage: w = M([0, x, 2*x]) - sage: S = M.submodule([v, w]) - sage: r = FreeResolution(S) - sage: type(r) - + sage: R. = QQ[] + sage: M = R^3 + sage: v = M([x^2, 2*x^2, 3*x^2]) + sage: w = M([0, x, 2*x]) + sage: S = M.submodule([v, w]) + sage: r = FreeResolution(S) + sage: type(r) + - sage: I = R.ideal([x^4 + 3*x^2 + 2]) - sage: r = FreeResolution(I) - sage: type(r) - - """ - # The module might still be free even if is_free_module is False. - # This is just to handle the cases when we trivially know it is. - is_free_module = False - if isinstance(module, Ideal_generic): - S = module.ring() - if len(module.gens()) == 1 and S in IntegralDomains(): - is_free_module = True - elif isinstance(module, Module_free_ambient): - S = module.base_ring() - if (S in PrincipalIdealDomains() - or isinstance(module, FreeModule_generic)): - is_free_module = True - elif isinstance(module, Matrix): - S = module.base_ring() - if S in PrincipalIdealDomains(): - module = module.echelon_form() - if module.nrows() > module.rank(): - module = module.submatrix(nrows=module.rank()) - module.set_immutable() - is_free_module = True - if not module.is_immutable(): - # We need to make an immutable copy of the matrix - module = copy(module) + sage: I = R.ideal([x^4 + 3*x^2 + 2]) + sage: r = FreeResolution(I) + sage: type(r) + + """ + # The module might still be free even if is_free_module is False. + # This is just to handle the cases when we trivially know it is. + is_free_module = False + if isinstance(module, Ideal_generic): + S = module.ring() + if len(module.gens()) == 1 and S in IntegralDomains(): + is_free_module = True + elif isinstance(module, Module_free_ambient): + S = module.base_ring() + if (S in PrincipalIdealDomains() + or isinstance(module, FreeModule_generic)): + is_free_module = True + elif isinstance(module, Matrix): + S = module.base_ring() + if S in PrincipalIdealDomains(): + module = module.echelon_form() + if module.nrows() > module.rank(): + module = module.submatrix(nrows=module.rank()) module.set_immutable() - else: - raise TypeError('no module, matrix, or ideal') + is_free_module = True + if not module.is_immutable(): + # We need to make an immutable copy of the matrix + module = copy(module) + module.set_immutable() + else: + raise TypeError('no module, matrix, or ideal') + + if not is_free_module: + from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if not isinstance(S, MPolynomialRing_libsingular): + raise NotImplementedError("the module must be a free module or " + "the base ring must be a polynomial ring using Singular") - if not is_free_module: - from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular - if not isinstance(S, MPolynomialRing_libsingular): - raise NotImplementedError("the module must be a free module or have the base ring be a polynomial ring using Singular") + if graded or degrees is not None or shifts is not None: + # We are computing a graded resolution + from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular + return GradedFiniteFreeResolution_singular(module, degrees=degrees, shifts=shifts, name=name, **kwds) - if graded or degrees is not None or shifts is not None: - # We are computing a graded resolution - from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular - return GradedFiniteFreeResolution_singular(module, degrees=degrees, shifts=shifts, name=name, **kwds) + return FiniteFreeResolution_singular(module, name=name, **kwds) - return FiniteFreeResolution_singular(module, name=name, **kwds) + # Otherwise we know it is a free module - # Otherwise we know it is a free module + if graded or degrees is not None or shifts is not None: + # We are computing a graded resolution + from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + return GradedFiniteFreeResolution_free_module(module, degrees=degrees, shifts=shifts, name=name, **kwds) - if graded or degrees is not None or shifts is not None: - # We are computing a graded resolution - from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module - return GradedFiniteFreeResolution_free_module(module, degrees=degrees, shifts=shifts, name=name, **kwds) + return FiniteFreeResolution_free_module(module, name=name, **kwds) - return FiniteFreeResolution_free_module(module, name=name, **kwds) +class FreeResolution_abs(SageObject): + """ + Abstract base class for free resolutions. + """ def __init__(self, module, name='S', **kwds): """ Initialize. @@ -196,7 +188,7 @@ def __init__(self, module, name='S', **kwds): """ if isinstance(module, Ideal_generic): S = module.ring() - else: #if isinstance(module, (Module_free_ambient, Matrix)): + else: # module or matrix S = module.base_ring() self._base_ring = S @@ -218,7 +210,7 @@ def _repr_(self): [z^2 - y*w y*z - x*w y^2 - x*z] """ if isinstance(self._module, Matrix): - return f"Free resolution with initial map:\n{self._module}" + return f"Free resolution of the :\n{self._module}" return f"Free resolution of {self._module}" def _repr_module(self, i): @@ -254,37 +246,6 @@ def _repr_module(self, i): s = '0' return s - def _m(self): - r""" - The defining matrix or ideal of the module defining ``self``. - - TESTS:: - - sage: from sage.homology.free_resolution import FreeResolution - sage: S. = PolynomialRing(QQ) - sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = FreeResolution(I) - sage: r._m() - Ideal (-z^2 + y*w, y*z - x*w, -y^2 + x*z) of Multivariate Polynomial Ring in x, y, z, w over Rational Field - - sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() - sage: r = FreeResolution(m, name='S') - sage: r._m() - [z^2 - y*w y*z - x*w y^2 - x*z] - - sage: M = m.image() - sage: r = FreeResolution(M, name='S') - sage: r._m() - [z^2 - y*w y*z - x*w y^2 - x*z] - """ - if isinstance(self._module, Ideal_generic): - return self._module - if isinstance(self._module, Module_free_ambient): - return self._module.matrix().transpose() - if isinstance(self._module, Matrix): - return self._module.transpose() - raise ValueError("unable to create a matrix/ideal to build the resolution") - @abstract_method def differential(self, i): r""" @@ -327,13 +288,23 @@ def target(self): """ return self.differential(0).codomain() -class FiniteFreeResolution(FreeResolution): + +class FiniteFreeResolution(FreeResolution_abs): r""" Finite free resolutions. A subclass must provide a ``_maps`` attribute that contains a list of the maps defining the resolution. + The matrix at index `i` in the list defines the differential map from + `(i + 1)`-th free module to the `i`-th free module over the base ring by + multiplication on the left. The number of matrices in the list is the + length of the resolution. The number of rows and columns of the matrices + define the ranks of the free modules in the resolution. + + Note that the first matrix in the list defines the differential map at + homological index `1`. + A subclass can define ``_initial_differential`` attribute that contains the `0`-th differential map whose codomain is the target of the free resolution. @@ -590,22 +561,56 @@ def _initial_differential(self): [ y*z - x*w] [-y^2 + x*z] """ - ideal = self._module - if isinstance(ideal, Ideal_generic): - S = ideal.ring() + module = self._module + if isinstance(module, Ideal_generic): + S = module.ring() M = FreeModule(S, 1) - N = M.submodule([vector([g]) for g in ideal.gens()]) + N = M.submodule([vector([g]) for g in module.gens()]) elif isinstance(ideal, Module_free_ambient): - S = ideal.base_ring() - M = ideal.ambient_module() - N = ideal - elif isinstance(ideal, Matrix): - S = ideal.base_ring() - N = ideal.row_space() + S = module.base_ring() + M = module.ambient_module() + N = module + elif isinstance(module, Matrix): + S = module.base_ring() + N = module.row_space() M = N.ambient_module() Q = M.quotient(N) return Q.coerce_map_from(M) + def _m(self): + r""" + Return the matrix whose column space is ``self._module``. + + If ``self._module`` is an ideal, then returns just the ideal. + + TESTS:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r._m() + Ideal (-z^2 + y*w, y*z - x*w, -y^2 + x*z) of Multivariate Polynomial Ring in x, y, z, w over Rational Field + + sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() + sage: r = FreeResolution(m, name='S') + sage: r._m() + [z^2 - y*w y*z - x*w y^2 - x*z] + + sage: M = m.image() + sage: r = FreeResolution(M, name='S') + sage: r._m() + [z^2 - y*w y*z - x*w y^2 - x*z] + """ + if isinstance(self._module, Ideal_generic): + return self._module + if isinstance(self._module, Module_free_ambient): + return self._module.matrix().transpose() + if isinstance(self._module, Matrix): + return self._module.transpose() + raise ValueError("unable to create a matrix/ideal to build the resolution") + + class FiniteFreeResolution_free_module(FiniteFreeResolution): r""" Free resolutions of a free module. @@ -712,6 +717,7 @@ def _maps(self): return [matrix([[self._module.gen()]])] return [self._m()] + class FiniteFreeResolution_singular(FiniteFreeResolution): r""" Minimal free resolutions of ideals or submodules of free modules From 7be0b868dac6612ffd822ee5af1e7c2f69eaedff Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 24 Aug 2022 15:33:51 +0200 Subject: [PATCH 269/742] functorial composition for LazySymmetricFunctions --- src/sage/rings/lazy_series.py | 112 ++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index e82321b9f18..0f91fe9d50d 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -118,6 +118,9 @@ from sage.structure.richcmp import op_EQ, op_NE from sage.functions.other import factorial from sage.arith.power import generic_power +from sage.arith.functions import lcm +from sage.arith.misc import divisors, moebius +from sage.combinat.partition import Partition, Partitions from sage.misc.misc_c import prod from sage.misc.derivative import derivative_parse from sage.rings.infinity import infinity @@ -3990,6 +3993,7 @@ def revert(self): raise ValueError("compositional inverse does not exist") plethystic_inverse = revert + compositional_inverse = revert def derivative_with_respect_to_p1(self, n=1): @@ -4045,10 +4049,110 @@ def derivative_with_respect_to_p1(self, n=1): if P._arity != 1: raise ValueError("arity must be equal to 1") - coeff_stream = Stream_shift(Stream_map_coefficients(self._coeff_stream, - lambda c: c.derivative_with_respect_to_p1(n), - P._laurent_poly_ring), - -n) + coeff_stream = Stream_map_coefficients(self._coeff_stream, + lambda c: c.derivative_with_respect_to_p1(n), + P._laurent_poly_ring) + coeff_stream = Stream_shift(coeff_stream, -n) + return P.element_class(P, coeff_stream) + + def functorial_composition(self, *args): + r"""Returns the functorial composition of ``self`` and ``g``. + + If `F` and `G` are species, their functorial composition is the species + `F \Box G` obtained by setting `(F \Box G) [A] = F[ G[A] ]`. + In other words, an `(F \Box G)`-structure on a set `A` of labels is an + `F`-structure whose labels are the set of all `G`-structures on `A`. + + It can be shown (as in section 2.2 of [BLL]_) that there is a + corresponding operation on cycle indices: + + .. MATH:: + + Z_{F} \Box Z_{G} = \sum_{n \geq 0} \frac{1}{n!} + \sum_{\sigma \in \mathfrak{S}_{n}} + \operatorname{fix} F[ (G[\sigma])_{1}, (G[\sigma])_{2}, \ldots ] + \, p_{1}^{\sigma_{1}} p_{2}^{\sigma_{2}} \cdots. + + This method implements that operation on cycle index series. + + EXAMPLES: + + The species `G` of simple graphs can be expressed in terms of a functorial + composition: `G = \mathfrak{p} \Box \mathfrak{p}_{2}`, where + `\mathfrak{p}` is the :class:`~sage.combinat.species.subset_species.SubsetSpecies`.:: + + sage: R. = QQ[] + sage: h = SymmetricFunctions(R).h() + sage: m = SymmetricFunctions(R).m() + sage: L = LazySymmetricFunctions(m) + sage: P = L(lambda n: sum(q^k*h[n-k]*h[k] for k in range(n+1))) + sage: P2 = L(lambda n: h[2]*h[n-2], valuation=2) + sage: P.functorial_composition(P2)[:4] + [m[], + m[1], + (q+1)*m[1, 1] + (q+1)*m[2], + (q^3+3*q^2+3*q+1)*m[1, 1, 1] + (q^3+2*q^2+2*q+1)*m[2, 1] + (q^3+q^2+q+1)*m[3]] + + For example, there are:: + + sage: P.functorial_composition(P2)[4].coefficient([4])[3] + 3 + + unlabelled graphs on 4 vertices and 3 edges, and:: + + sage: P.functorial_composition(P2)[4].coefficient([2,2])[3] + 8 + + labellings of their vertices with two 1's and two 2's. + """ + if len(args) != self.parent()._arity: + raise ValueError("arity must be equal to the number of arguments provided") + from sage.combinat.sf.sfa import is_SymmetricFunction + if not all(isinstance(g, LazySymmetricFunction) + or is_SymmetricFunction(g) + or not g for g in args): + raise ValueError("all arguments must be (possibly lazy) symmetric functions") + + if len(args) == 1: + g = args[0] + P = g.parent() + R = P._laurent_poly_ring + p = R.realization_of().p() + # TODO: does the following introduce a memory leak? + g = g.change_ring(p) + f = self.change_ring(p) + + def g_cycle_type(s): + if not s: + return Partition([g[0].coefficient([])]) + res = [] + # in the species case, k is at most + # factorial(n) * g[n].coefficient([1]*n) with n = sum(s) + for k in range(1, lcm(s) + 1): + e = 0 + for d in divisors(k): + m = moebius(d) + if m == 0: + continue + u = s.power(k/d) + e += m * u.aut() * g[u.size()].coefficient(u) + res.extend([k] * ZZ(e/k)) + res.reverse() + return Partition(res) + + def coefficient(n): + res = p(0) + for s in Partitions(n): + t = g_cycle_type(s) + q = t.aut() * f[t.size()].coefficient(t) / s.aut() + res += q * p(s) + return res + + coeff_stream = Stream_function(coefficient, R, P._sparse, 0) + + else: + raise NotImplementedError("only implemented for arity 1") + return P.element_class(P, coeff_stream) From c755d7182ad8b0dd1c4a0f298936fa61975fee54 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 24 Aug 2022 16:23:10 +0200 Subject: [PATCH 270/742] implement arithmetic product for LazySymmetricFunction --- src/sage/rings/lazy_series.py | 134 +++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 0f91fe9d50d..f566005425a 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -119,7 +119,7 @@ from sage.functions.other import factorial from sage.arith.power import generic_power from sage.arith.functions import lcm -from sage.arith.misc import divisors, moebius +from sage.arith.misc import divisors, moebius, gcd from sage.combinat.partition import Partition, Partitions from sage.misc.misc_c import prod from sage.misc.derivative import derivative_parse @@ -4155,6 +4155,138 @@ def coefficient(n): return P.element_class(P, coeff_stream) + def arithmetic_product(self, *args, check=True): + r""" + Return the arithmetic product of ``self`` with ``g``. + + For species `M` and `N` such that `M[\\varnothing] = + N[\\varnothing] = \\varnothing`, their arithmetic product is + the species `M \\boxdot N` of "`M`-assemblies of cloned + `N`-structures". This operation is defined and several + examples are given in [MM]_. + + The cycle index series for `M \\boxdot N` can be computed in + terms of the component series `Z_M` and `Z_N`, as implemented + in this method. + + INPUT: + + - ``g`` -- a cycle index series having the same parent as ``self``. + + - ``check`` -- (default: ``True``) a Boolean which, when set + to ``False``, will cause input checks to be skipped. + + OUTPUT: + + The arithmetic product of ``self`` with ``g``. This is a + cycle index series defined in terms of ``self`` and ``g`` + such that if ``self`` and ``g`` are the cycle index series of + two species `M` and `N`, their arithmetic product is the + cycle index series of the species `M \\boxdot N`. + + EXAMPLES: + + For `C` the species of (oriented) cycles and `L_{+}` the + species of nonempty linear orders, `C \\boxdot L_{+}` + corresponds to the species of "regular octopuses"; a `(C + \\boxdot L_{+})`-structure is a cycle of some length, each of + whose elements is an ordered list of a length which is + consistent for all the lists in the structure. :: + + sage: R. = QQ[] + sage: p = SymmetricFunctions(R).p() + sage: m = SymmetricFunctions(R).m() + sage: L = LazySymmetricFunctions(m) + + sage: C = species.CycleSpecies().cycle_index_series() + sage: c = L(lambda n: C[n]) + sage: Lplus = L(lambda n: p([1]*n), valuation=1) + sage: R = c.arithmetic_product(Lplus); R + m[1] + (3*m[1,1]+2*m[2]) + (8*m[1,1,1]+4*m[2,1]+2*m[3]) + (42*m[1,1,1,1]+21*m[2,1,1]+12*m[2,2]+7*m[3,1]+3*m[4]) + (144*m[1,1,1,1,1]+72*m[2,1,1,1]+36*m[2,2,1]+24*m[3,1,1]+12*m[3,2]+6*m[4,1]+2*m[5]) + (1440*m[1,1,1,1,1,1]+720*m[2,1,1,1,1]+360*m[2,2,1,1]+184*m[2,2,2]+240*m[3,1,1,1]+120*m[3,2,1]+42*m[3,3]+60*m[4,1,1]+32*m[4,2]+12*m[5,1]+4*m[6]) + O^7 + + In particular, the number of regular octopuses is:: + + sage: [R[n].coefficient([1]*n) for n in range(8)] + [0, 1, 3, 8, 42, 144, 1440, 5760] + + It is shown in [MM]_ that the exponential generating function + for regular octopuses satisfies `(C \\boxdot L_{+}) (x) = + \\sum_{n \geq 1} \\sigma (n) (n - 1)! \\frac{x^{n}}{n!}` + (where `\\sigma (n)` is the sum of the divisors of `n`). :: + + sage: [sum(divisors(i))*factorial(i-1) for i in range(1,8)] + [1, 3, 8, 42, 144, 1440, 5760] + + AUTHORS: + + - Andrew Gainer-Dewar (2013) + + REFERENCES: + + .. [MM] \M. Maia and M. Mendez. "On the arithmetic product of combinatorial species". + Discrete Mathematics, vol. 308, issue 23, 2008, pp. 5407-5427. + :arxiv:`math/0503436v2`. + + """ + from itertools import product, repeat, chain + if len(args) != self.parent()._arity: + raise ValueError("arity must be equal to the number of arguments provided") + from sage.combinat.sf.sfa import is_SymmetricFunction + if not all(isinstance(g, LazySymmetricFunction) + or is_SymmetricFunction(g) + or not g for g in args): + raise ValueError("all arguments must be (possibly lazy) symmetric functions") + + if len(args) == 1: + g = args[0] + P = g.parent() + R = P._laurent_poly_ring + p = R.realization_of().p() + # TODO: does the following introduce a memory leak? + g = g.change_ring(p) + f = self.change_ring(p) + + if check: + assert not f[0] + assert not g[0] + + # We first define an operation `\\boxtimes` on partitions as in Lemma 2.1 of [MM]_. + def arith_prod_of_partitions(l1, l2): + # Given two partitions `l_1` and `l_2`, we construct a new partition `l_1 \\boxtimes l_2` by + # the following procedure: each pair of parts `a \\in l_1` and `b \\in l_2` contributes + # `\\gcd (a, b)`` parts of size `\\lcm (a, b)` to `l_1 \\boxtimes l_2`. If `l_1` and `l_2` + # are partitions of integers `n` and `m`, respectively, then `l_1 \\boxtimes l_2` is a + # partition of `nm`. Finally, we return the corresponding powersum symmetric function. + term_iterable = chain.from_iterable(repeat(lcm(pair), gcd(pair)) + for pair in product(l1, l2)) + return p(Partition(sorted(term_iterable, reverse=True))) + + # We then extend this to an operation on symmetric functions as per eq. (52) of [MM]_. + # (Maia and Mendez, in [MM]_, are talking about polynomials instead of symmetric + # functions, but this boils down to the same: Their x_i corresponds to the i-th power + # sum symmetric function.) + def arith_prod_sf(x, y): + return p._apply_multi_module_morphism(x, y, arith_prod_of_partitions) + + # Sage stores cycle index series by degree. + # Thus, to compute the arithmetic product `Z_M \\boxdot Z_N` it is useful + # to compute all terms of a given degree `n` at once. + def coefficient(n): + if n == 0: + res = p.zero() + else: + index_set = ((d, n // d) for d in divisors(n)) + res = sum(arith_prod_sf(f[i], g[j]) for i, j in index_set) + + return res + + coeff_stream = Stream_function(coefficient, R, P._sparse, 0) + + else: + raise NotImplementedError("only implemented for arity 1") + + return P.element_class(P, coeff_stream) + def _format_series(self, formatter, format_strings=False): r""" From 18429ef0890975ccb09d5345823af3c7b97322cf Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 24 Aug 2022 23:00:31 +0200 Subject: [PATCH 271/742] do not use change_ring, because it is brittle, and take care of zero coefficients which are not symmetric functions --- src/sage/rings/lazy_series.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 0f91fe9d50d..99b5fd15e4b 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4119,12 +4119,14 @@ def functorial_composition(self, *args): R = P._laurent_poly_ring p = R.realization_of().p() # TODO: does the following introduce a memory leak? - g = g.change_ring(p) - f = self.change_ring(p) + g = Stream_map_coefficients(g._coeff_stream, lambda x: x, p) + f = Stream_map_coefficients(self._coeff_stream, lambda x: x, p) def g_cycle_type(s): if not s: - return Partition([g[0].coefficient([])]) + if g[0]: + return Partition([ZZ(g[0].coefficient([]))]) + return Partition([]) res = [] # in the species case, k is at most # factorial(n) * g[n].coefficient([1]*n) with n = sum(s) @@ -4132,10 +4134,12 @@ def g_cycle_type(s): e = 0 for d in divisors(k): m = moebius(d) - if m == 0: + if not m: continue u = s.power(k/d) - e += m * u.aut() * g[u.size()].coefficient(u) + g_u = g[u.size()] + if g_u: + e += m * u.aut() * g_u.coefficient(u) res.extend([k] * ZZ(e/k)) res.reverse() return Partition(res) From b469431783ad64c128a0a6a65164e4747ba3c2a4 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 24 Aug 2022 23:07:22 +0200 Subject: [PATCH 272/742] do not use change_ring, because it is brittle --- src/sage/rings/lazy_series.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 2babb83192e..a83d6cb12c7 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4247,8 +4247,8 @@ def arithmetic_product(self, *args, check=True): R = P._laurent_poly_ring p = R.realization_of().p() # TODO: does the following introduce a memory leak? - g = g.change_ring(p) - f = self.change_ring(p) + g = Stream_map_coefficients(g._coeff_stream, lambda x: x, p) + f = Stream_map_coefficients(self._coeff_stream, lambda x: x, p) if check: assert not f[0] From 5db5d4e56243c609f44afc1f21c112b026f9e1fe Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Mon, 11 Jul 2022 21:24:01 +0100 Subject: [PATCH 273/742] Update doctests for SymPy 1.11 Doctests related to SymPy's rsolve function are updated in: src/sage/calculus/test_sympy.py src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py The form of the output from SymPy has changed since https://github.com/sympy/sympy/pull/23567 --- src/sage/calculus/test_sympy.py | 4 ++-- .../recequadiff_doctest.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/calculus/test_sympy.py b/src/sage/calculus/test_sympy.py index 7cf7f3f6bfd..927e6ee4fb6 100644 --- a/src/sage/calculus/test_sympy.py +++ b/src/sage/calculus/test_sympy.py @@ -193,7 +193,7 @@ sage: u = Function('u') sage: n = Symbol('n', integer=True) sage: f = u(n+2) - u(n+1) + u(n)/4 - sage: 2**n * rsolve(f,u(n)) - C1*n + C0 + sage: expand(2**n * rsolve(f,u(n))) + 2*C1*n + C0 """ diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py index 1062f4f7e8c..f53f813d793 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py @@ -382,7 +382,7 @@ sage: from sympy import rsolve_hyper sage: from sympy.abc import n sage: rsolve_hyper([-2,1],2**(n+2),n) - 2**n*C0 + 2**(n + 2)*(C0 + n/2) + 2**n*C0 + 2**(n + 1)*n """ From 16fdc52e7dee6414a36cf3e6546b4a7c9089b21d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 24 Aug 2022 21:36:24 -0700 Subject: [PATCH 274/742] build/pkgs/sympy: Update to 1.11 --- build/pkgs/sympy/checksums.ini | 6 +++--- build/pkgs/sympy/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sympy/checksums.ini b/build/pkgs/sympy/checksums.ini index f2b891c8a65..d92eeec4219 100644 --- a/build/pkgs/sympy/checksums.ini +++ b/build/pkgs/sympy/checksums.ini @@ -1,5 +1,5 @@ tarball=sympy-VERSION.tar.gz -sha1=95b5323b284a3f64414dab3b9da909eeeb1c09ea -md5=8c7a956d74a47dc439c2935fec64ac46 -cksum=1092663182 +sha1=bb3ecaa4b223097831b5f0627d6579d8bd906840 +md5=973f746dd0b0d07b01f6b2b15603cbf8 +cksum=3499849170 upstream_url=https://github.com/sympy/sympy/releases/download/sympy-VERSION/sympy-VERSION.tar.gz diff --git a/build/pkgs/sympy/package-version.txt b/build/pkgs/sympy/package-version.txt index 4dae2985b58..09601587019 100644 --- a/build/pkgs/sympy/package-version.txt +++ b/build/pkgs/sympy/package-version.txt @@ -1 +1 @@ -1.10.1 +1.11 From 7e7593841298c488e2d9424740179da210459f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 25 Aug 2022 08:54:06 +0200 Subject: [PATCH 275/742] fix SchurTensormodule with construction None --- src/sage/algebras/schur_algebra.py | 47 +++++++++++++++++++----------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index ba606ded999..b716db0ce94 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -454,6 +454,19 @@ def _repr_(self): msg += " over {}" return msg.format(self._r, self._n, self.base_ring()) + def construction(self): + """ + Return ``None``. + + There is no functorial construction for ``self``. + + EXAMPLES:: + + sage: T = SchurTensorModule(QQ, 2, 3) + sage: T.construction() + """ + return None + def _monomial_product(self, xi, v): """ Result of acting by the basis element ``xi`` of the corresponding @@ -581,11 +594,11 @@ def GL_irreducible_character(n, mu, KK): A = M._schur SGA = M._sga - #make ST the superstandard tableau of shape mu + # make ST the superstandard tableau of shape mu from sage.combinat.tableau import from_shape_and_word ST = from_shape_and_word(mu, list(range(1, r + 1)), convention='English') - #make ell the reading word of the highest weight tableau of shape mu + # make ell the reading word of the highest weight tableau of shape mu ell = [i + 1 for i, l in enumerate(mu) for dummy in range(l)] e = M.basis()[tuple(ell)] # the element e_l @@ -607,17 +620,17 @@ def GL_irreducible_character(n, mu, KK): y = A.basis()[schur_rep] * e # M.action_by_Schur_alg(A.basis()[schur_rep], e) carter_lusztig.append(y.to_vector()) - #Therefore, we now have carter_lusztig as a list giving the basis - #of `V_\mu` + # Therefore, we now have carter_lusztig as a list giving the basis + # of `V_\mu` - #We want to think of expressing this character as a sum of monomial - #symmetric functions. + # We want to think of expressing this character as a sum of monomial + # symmetric functions. - #We will determine a basis element for each m_\lambda in the - #character, and we want to keep track of them by \lambda. + # We will determine a basis element for each m_\lambda in the + # character, and we want to keep track of them by \lambda. - #That means that we only want to pick out the basis elements above for - #those semistandard words whose content is a partition. + # That means that we only want to pick out the basis elements above for + # those semistandard words whose content is a partition. contents = Partitions(r, max_length=n).list() # all partitions of r, length at most n @@ -648,15 +661,15 @@ def GL_irreducible_character(n, mu, KK): except ValueError: pass - #There is an inner product on the Carter-Lusztig module V_\mu; its - #maximal submodule is exactly the kernel of the inner product. + # There is an inner product on the Carter-Lusztig module V_\mu; its + # maximal submodule is exactly the kernel of the inner product. - #Now, for each possible partition content, we look at the graded piece of - #that degree, and we record how these elements pair with each of the - #elements of carter_lusztig. + # Now, for each possible partition content, we look at the graded piece of + # that degree, and we record how these elements pair with each of the + # elements of carter_lusztig. - #The kernel of this pairing is the part of this graded piece which is - #not in the irreducible module for \mu. + # The kernel of this pairing is the part of this graded piece which is + # not in the irreducible module for \mu. length = len(carter_lusztig) From fc33cd4fa19f650b1e6c44b753f2db9b23ef86b0 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 25 Aug 2022 12:47:12 +0200 Subject: [PATCH 276/742] add test for degree one elements --- src/sage/combinat/sf/sfa.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 63579adca06..1743beafd61 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -3060,6 +3060,17 @@ def plethysm(self, x, include=None, exclude=None): sage: (1+p[2]).plethysm(p[2]) p[] + p[4] + + Check that degree one elements are treated in the correct way:: + + sage: R. = QQ[] + sage: p = SymmetricFunctions(R).p() + sage: f = a1*p[1] + a2*p[2] + a11*p[1,1] + sage: g = b1*p[1] + b21*p[2,1] + b111*p[1,1,1] + sage: r = f(g); r + a1*b1*p[1] + a11*b1^2*p[1, 1] + a1*b111*p[1, 1, 1] + 2*a11*b1*b111*p[1, 1, 1, 1] + a11*b111^2*p[1, 1, 1, 1, 1, 1] + a2*b1^2*p[2] + a1*b21*p[2, 1] + 2*a11*b1*b21*p[2, 1, 1] + 2*a11*b21*b111*p[2, 1, 1, 1, 1] + a11*b21^2*p[2, 2, 1, 1] + a2*b111^2*p[2, 2, 2] + a2*b21^2*p[4, 2] + sage: r - f(g, include=[]) + (a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2] """ parent = self.parent() R = parent.base_ring() From 39587572789aecc68ba649585d7ad41c7c027c16 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 25 Aug 2022 12:48:02 +0200 Subject: [PATCH 277/742] microoptimizations in stretched_power_restrict_degree --- src/sage/data_structures/stream.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 3c185918dba..06ab061e495 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -1861,16 +1861,15 @@ def _stretched_power_restrict_degree(self, i, m, d): """ while len(self._powers) < m: self._powers.append(Stream_cauchy_mul(self._powers[-1], self._powers[0])) - power = self._powers[m-1] - - # we have to check power[d] for zero because it might be an + power_d = self._powers[m-1][d] + # we have to check power_d for zero because it might be an # integer and not a symmetric function - if power[d]: - terms = [(self._scale_part(m, i), self._raise_c(c, i)) for m, c in power[d]] - else: - terms = [] + if power_d: + terms = {self._scale_part(m, i): raised_c for m, c in power_d + if (raised_c := self._raise_c(c, i))} + return self._p.element_class(self._p, terms) - return self._p.sum_of_terms(terms, distinct = True) + return self._p.zero() ##################################################################### From eabb0cb6f6f93e39c657e38131b299af53b48256 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 25 Aug 2022 16:54:52 +0200 Subject: [PATCH 278/742] add some (currently failing) doctests --- src/sage/data_structures/stream.py | 3 +- src/sage/rings/lazy_series.py | 48 ++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 06ab061e495..b60ef186118 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -541,7 +541,8 @@ def __init__(self, initial_coefficients, is_sparse, constant=None, degree=None, # We do not insist that the last entry of # initial_coefficients is different from constant in case - # comparisons can be expensive such as in the symbolic ring + # comparisons can be expensive such as in the symbolic ring, + # but we remove zeros for i, v in enumerate(initial_coefficients): if v: order += i diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 0e694e0e30b..cfb73ddd544 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -323,10 +323,10 @@ def map_coefficients(self, func, ring=None): if not any(initial_coefficients) and not c: return P.zero() coeff_stream = Stream_exact(initial_coefficients, - self._coeff_stream._is_sparse, - order=coeff_stream._approximate_order, - degree=coeff_stream._degree, - constant=BR(c)) + self._coeff_stream._is_sparse, + order=coeff_stream._approximate_order, + degree=coeff_stream._degree, + constant=BR(c)) return P.element_class(P, coeff_stream) R = P._internal_poly_ring.base_ring() coeff_stream = Stream_map_coefficients(self._coeff_stream, func, R) @@ -2163,6 +2163,11 @@ def _mul_(self, other): sage: t1 = t.approximate_series(44) sage: s1 * t1 - (s * t).approximate_series(42) O(z^42) + + Check products with exact series:: + + sage: L([1], constant=3)^2 + 1 + 6*z + 15*z^2 + 24*z^3 + 33*z^4 + 42*z^5 + 51*z^6 + O(z^7) """ P = self.parent() left = self._coeff_stream @@ -2998,27 +3003,35 @@ def revert(self): - `val(f) = 1`, or - - `f = a + b z` with `a b \neq 0`, or + - `f = a + b z` with `a, b \neq 0`, or - `f = a/z` with `a \neq 0` EXAMPLES:: - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: z.revert() - z + O(z^8) - sage: (1/z).revert() - z^-1 + sage: L. = LazyLaurentSeriesRing(QQ) + sage: (2*z).revert() + 1/2*z + sage: (2/z).revert() + 2*z^-1 sage: (z-z^2).revert() z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) + sage: s = L(degree=1, constant=-1) + sage: s.revert() + -z - z^2 - z^3 + O(z^4) + + sage: s = L(degree=1, constant=1) + sage: s.revert() + z - z^2 + z^3 - z^4 + z^5 - z^6 + z^7 + O(z^8) + TESTS:: sage: L. = LazyLaurentSeriesRing(QQ) - sage: s = L(lambda n: 1 if n == 1 else 0, valuation=1); s - z + O(z^8) + sage: s = L(lambda n: 2 if n == 1 else 0, valuation=1); s + 2*z + O(z^8) sage: s.revert() - z + O(z^8) + 1/2*z + O(z^8) sage: (2+3*z).revert() -2/3 + 1/3*z @@ -3030,6 +3043,15 @@ def revert(self): ... ValueError: cannot determine whether the compositional inverse exists + sage: R. = QQ[] + sage: L. = LazyLaurentSeriesRing(R.fraction_field()) + sage: s = L([q], valuation=0, constant=t); s + q + t*z + t*z^2 + t*z^3 + O(z^4) + sage: s.revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + We look at some cases where the compositional inverse does not exist: `f = 0`:: From 302bf7577d028ee97a194930f2c4f16072f9c964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Thu, 25 Aug 2022 18:31:22 +0200 Subject: [PATCH 279/742] 34432: Upgrade: jupyter-packaging 0.12.3 --- build/pkgs/jupyter_packaging/checksums.ini | 6 +++--- build/pkgs/jupyter_packaging/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/jupyter_packaging/checksums.ini b/build/pkgs/jupyter_packaging/checksums.ini index eb449d9da6f..65b3bd148f6 100644 --- a/build/pkgs/jupyter_packaging/checksums.ini +++ b/build/pkgs/jupyter_packaging/checksums.ini @@ -1,5 +1,5 @@ tarball=jupyter_packaging-VERSION.tar.gz -sha1=c9b7dd75a70ad6a7c621588db410f07fba7e0fad -md5=d30e6fb387d46398a3ab26765b8fa74f -cksum=669146472 +sha1=092d249360aa56838a188decc4bcd09647fda4d9 +md5=9c6834023bd699bda5365ab7ed18bde2 +cksum=3308833189 upstream_url=https://pypi.io/packages/source/j/jupyter_packaging/jupyter_packaging-VERSION.tar.gz diff --git a/build/pkgs/jupyter_packaging/package-version.txt b/build/pkgs/jupyter_packaging/package-version.txt index 26acbf080be..aa22d3ce39b 100644 --- a/build/pkgs/jupyter_packaging/package-version.txt +++ b/build/pkgs/jupyter_packaging/package-version.txt @@ -1 +1 @@ -0.12.2 +0.12.3 From 84547caf6707feaca274b85c0db166bbc557f8a6 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 25 Aug 2022 21:51:55 +0200 Subject: [PATCH 280/742] more doctests --- src/sage/rings/lazy_series.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index cfb73ddd544..9cc6f98c66c 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3065,7 +3065,7 @@ def revert(self): ... ValueError: compositional inverse does not exist - `val(f) ! = 1` and `f(0) * f(1) = 0`:: + `val(f) != 1` and `f(0) * f(1) = 0`:: sage: (z^2).revert() Traceback (most recent call last): @@ -3076,6 +3076,29 @@ def revert(self): Traceback (most recent call last): ... ValueError: compositional inverse does not exist + + Reversion of exact series:: + + sage: f = L([2], valuation=-1, constant=2) + sage: f.revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + sage: f = L([1, 2], valuation=0, constant=1) + sage: f.revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + sage: f = L([-1, -1], valuation=1, constant=-1) + sage: f.revert() + -z - z^2 - z^3 + O(z^4) + + sage: f = L([-1, 0, -1], valuation=1, constant=-1) + sage: f.revert() + -z + z^3 - z^4 - 2*z^5 + 6*z^6 + z^7 + O(z^8) + """ P = self.parent() if self.valuation() == 1: From 634edfaef274d214a69e9ffdf34d3b9b8bedab00 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 25 Aug 2022 23:09:43 +0200 Subject: [PATCH 281/742] fix bug in LazyCauchyProductSeries._mul_, be more exact in LazyLaurentSeries.revert --- src/sage/rings/lazy_series.py | 93 +++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 21 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 9cc6f98c66c..11c5b888a96 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -2176,9 +2176,15 @@ def _mul_(self, other): # Check some trivial products if isinstance(left, Stream_zero) or isinstance(right, Stream_zero): return P.zero() - if isinstance(left, Stream_exact) and left._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and left.order() == 0: + if (isinstance(left, Stream_exact) + and left._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) + and left.order() == 0 + and not left._constant): return other # self == 1 - if isinstance(right, Stream_exact) and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and right.order() == 0: + if (isinstance(right, Stream_exact) + and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) + and right.order() == 0 + and not right._constant): return self # right == 1 # The product is exact if and only if both factors are exact @@ -3043,6 +3049,13 @@ def revert(self): ... ValueError: cannot determine whether the compositional inverse exists + sage: s = L(lambda n: 1, valuation=-2); s + z^-2 + z^-1 + 1 + z + z^2 + z^3 + z^4 + O(z^5) + sage: s.revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + sage: R. = QQ[] sage: L. = LazyLaurentSeriesRing(R.fraction_field()) sage: s = L([q], valuation=0, constant=t); s @@ -3093,36 +3106,74 @@ def revert(self): sage: f = L([-1, -1], valuation=1, constant=-1) sage: f.revert() - -z - z^2 - z^3 + O(z^4) + -z - z^2 - z^3 - z^4 - z^5 + O(z^6) sage: f = L([-1, 0, -1], valuation=1, constant=-1) sage: f.revert() -z + z^3 - z^4 - 2*z^5 + 6*z^6 + z^7 + O(z^8) + sage: f = L([-1], valuation=1, degree=3, constant=-1) + sage: f.revert() + -z + z^3 - z^4 - 2*z^5 + 6*z^6 + z^7 + O(z^8) """ P = self.parent() - if self.valuation() == 1: + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, Stream_zero): + raise ValueError("compositional inverse does not exist") + if isinstance(coeff_stream, Stream_exact): + if coeff_stream._constant: + if coeff_stream.order() == 1: + R = P.base_ring() + # we cannot assume that the last initial coefficient + # and the constant differ, see stream.Stream_exact + if (coeff_stream._degree == 1 + len(coeff_stream._initial_coefficients) + and coeff_stream._constant == -R.one() + and all(c == -R.one() for c in coeff_stream._initial_coefficients)): + # self = -z/(1-z); self.revert() = -z/(1-z) + return self + else: + raise ValueError("compositional inverse does not exist") + else: + if (coeff_stream.order() == -1 + and coeff_stream._degree == 0): + # self = a/z; self.revert() = a/z + return self + + if (coeff_stream.order() >= 0 + and coeff_stream._degree == 2): + # self = a + b*z; self.revert() = -a/b + 1/b * z + a = coeff_stream[0] + b = coeff_stream[1] + coeff_stream = Stream_exact((-a/b, 1/b), + coeff_stream._is_sparse, + order=0) + return P.element_class(P, coeff_stream) + + if coeff_stream.order() != 1: + raise ValueError("compositional inverse does not exist") + + if any(coeff_stream[i] for i in range(coeff_stream._approximate_order, -1)): + raise ValueError("compositional inverse does not exist") + + if coeff_stream[-1]: + if coeff_stream[0] or coeff_stream[1]: + raise ValueError("compositional inverse does not exist") + else: + raise ValueError("cannot determine whether the compositional inverse exists") + + if coeff_stream[0]: + if coeff_stream[1]: + raise ValueError("cannot determine whether the compositional inverse exists") + else: + raise ValueError("compositional inverse does not exist") + + if coeff_stream[1]: z = P.gen() g = P(None, valuation=1) g.define(z/((self/z)(g))) return g - if self.valuation() not in [-1, 0]: - raise ValueError("compositional inverse does not exist") - coeff_stream = self._coeff_stream - if isinstance(coeff_stream, Stream_exact): - if (coeff_stream.order() == 0 - and coeff_stream._degree == 2): - a = coeff_stream[0] - b = coeff_stream[1] - coeff_stream = Stream_exact((-a/b, 1/b), - coeff_stream._is_sparse, - order=0) - return P.element_class(P, coeff_stream) - if (coeff_stream.order() == -1 - and coeff_stream._degree == 0): - return self - raise ValueError("compositional inverse does not exist") - raise ValueError("cannot determine whether the compositional inverse exists") + + raise ValueError("compositional inverse does not exist") compositional_inverse = revert From 74841c0b88efdea40a48b96aa310d17284d0417d Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 25 Aug 2022 23:55:56 +0200 Subject: [PATCH 282/742] improve revert of LazySymmetricFunction --- src/sage/rings/lazy_series.py | 39 ++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 11c5b888a96..29d1c2a7d75 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -118,6 +118,7 @@ from sage.structure.richcmp import op_EQ, op_NE from sage.functions.other import factorial from sage.arith.power import generic_power +from sage.combinat.partition import Partition from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing @@ -3876,7 +3877,7 @@ def revert(self): sage: L = LazySymmetricFunctions(p) sage: Eplus = L(lambda n: h[n]) - 1 sage: Eplus(Eplus.revert()) - p[1] + O^8 + p[1] + O^7 TESTS:: @@ -3886,6 +3887,21 @@ def revert(self): ... ValueError: compositional inverse does not exist + sage: R. = QQ[] + sage: p = SymmetricFunctions(R.fraction_field()).p() + sage: L = LazySymmetricFunctions(p) + sage: f = L(a + b*p[1]) + sage: f.revert() + ((-a)/b)*p[] + 1/b*p[1] + + sage: f = L(2*p[1]) + sage: f.revert() + 1/2*p[1] + O^8 + + sage: f = L(2*p[1] + p[2] + p[1,1]) + sage: f.revert() + 1/2*p[1] + (-1/4*p[1,1]-1/2*p[2]) + (1/4*p[1,1,1]+1/2*p[2,1]) + (-5/16*p[1,1,1,1]-3/4*p[2,1,1]+1/2*p[4]) + (7/16*p[1,1,1,1,1]+5/4*p[2,1,1,1]+1/2*p[2,2,1]-1/2*p[4,1]) + (-21/32*p[1,1,1,1,1,1]-35/16*p[2,1,1,1,1]-3/2*p[2,2,1,1]-1/4*p[2,2,2]+3/4*p[4,1,1]) + (33/32*p[1,1,1,1,1,1,1]+63/16*p[2,1,1,1,1,1]+15/4*p[2,2,1,1,1]+3/4*p[2,2,2,1]-5/4*p[4,1,1,1]-p[4,2,1]) + O^8 + ALGORITHM: Let `F` be a species satisfying `F = 0 + X + F_2 + F_3 + \cdots` for @@ -3916,15 +3932,18 @@ def revert(self): P = self.parent() if P._arity != 1: raise ValueError("arity must be equal to 1") - if self.valuation() == 1: - from sage.combinat.sf.sf import SymmetricFunctions - p = SymmetricFunctions(P.base()).p() - X = P(p[1]) - f1 = self - X - g = P(None, valuation=1) - g.define(X - f1(g)) - return g - raise ValueError("compositional inverse does not exist") + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, Stream_zero): + raise ValueError("compositional inverse does not exist") + if coeff_stream[0] or not coeff_stream[1]: + raise ValueError("compositional inverse does not exist") + + ps = P._laurent_poly_ring.realization_of().p() + X = P(ps[1]) + f1 = coeff_stream[1][Partition([1])] + g = P(None, valuation=1) + g.define(~f1*X - (self - f1*X)(g)) + return g plethystic_inverse = revert compositional_inverse = revert From 9e6b7b2e4ec266702154fc75b81331a43a369411 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Sep 2021 12:57:04 -0700 Subject: [PATCH 283/742] Polyhedra_base._repr_base_ring: Factor out from ._repr_ambient_module, do not fail if AA cannot be imported --- src/sage/geometry/polyhedron/parent.py | 41 +++++++++++++++++++------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 881c614238a..b4601a08444 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -495,6 +495,35 @@ def Hrepresentation_space(self): from sage.modules.free_module import FreeModule return FreeModule(self.base_ring(), self.ambient_dim()+1) + def _repr_base_ring(self): + """ + Return an abbreviated string representation of the base ring. + + EXAMPLES:: + + sage: from sage.geometry.polyhedron.parent import Polyhedra + sage: Polyhedra(QQ, 3)._repr_base_ring() + 'QQ' + sage: K. = NumberField(x^2 - 3, embedding=AA(3).sqrt()) + sage: Polyhedra(K, 4)._repr_base_ring() + '(Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)' + """ + + if self.base_ring() is ZZ: + return 'ZZ' + if self.base_ring() is QQ: + return 'QQ' + if self.base_ring() is RDF: + return 'RDF' + try: + from sage.rings.qqbar import AA + except ImportError: + pass + else: + if self.base_ring() is AA: + return 'AA' + return '({0})'.format(self.base_ring()) + def _repr_ambient_module(self): """ Return an abbreviated string representation of the ambient @@ -513,17 +542,7 @@ def _repr_ambient_module(self): sage: Polyhedra(K, 4)._repr_ambient_module() '(Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)^4' """ - from sage.rings.qqbar import AA - if self.base_ring() is ZZ: - s = 'ZZ' - elif self.base_ring() is QQ: - s = 'QQ' - elif self.base_ring() is RDF: - s = 'RDF' - elif self.base_ring() is AA: - s = 'AA' - else: - s = '({0})'.format(self.base_ring()) + s = self._repr_base_ring() s += '^' + repr(self.ambient_dim()) return s From 22e4b7cfafdf471847e2921df6580fad1162f5dc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 21:48:38 -0700 Subject: [PATCH 284/742] src/sage/geometry/polyhedron/parent.py: Mark doctests # optional - sage.rings.number_field --- src/sage/geometry/polyhedron/parent.py | 41 +++++++++++++------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index b4601a08444..de492eb6301 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -65,7 +65,7 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * EXAMPLES:: sage: from sage.geometry.polyhedron.parent import Polyhedra - sage: Polyhedra(AA, 3) + sage: Polyhedra(AA, 3) # optional - sage.rings.number_field Polyhedra in AA^3 sage: Polyhedra(ZZ, 3) Polyhedra in ZZ^3 @@ -105,11 +105,11 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * Traceback (most recent call last): ... ValueError: no default backend for computations with Real Field with 53 bits of precision - sage: Polyhedra(QQ[I], 2) + sage: Polyhedra(QQ[I], 2) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: invalid base ring: Number Field in I with defining polynomial x^2 + 1 with I = 1*I cannot be coerced to a real field - sage: Polyhedra(AA, 3, backend='polymake') # optional - polymake + sage: Polyhedra(AA, 3, backend='polymake') # optional - polymake # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: the 'polymake' backend for polyhedron cannot be used with Algebraic Real Field @@ -264,13 +264,13 @@ def list(self): sage: P.cardinality() +Infinity - sage: P = Polyhedra(AA, 0) - sage: P.category() + sage: P = Polyhedra(AA, 0) # optional - sage.rings.number_field + sage: P.category() # optional - sage.rings.number_field Category of finite enumerated polyhedral sets over Algebraic Real Field - sage: P.list() + sage: P.list() # optional - sage.rings.number_field [The empty polyhedron in AA^0, A 0-dimensional polyhedron in AA^0 defined as the convex hull of 1 vertex] - sage: P.cardinality() + sage: P.cardinality() # optional - sage.rings.number_field 2 """ if self.ambient_dim(): @@ -504,8 +504,8 @@ def _repr_base_ring(self): sage: from sage.geometry.polyhedron.parent import Polyhedra sage: Polyhedra(QQ, 3)._repr_base_ring() 'QQ' - sage: K. = NumberField(x^2 - 3, embedding=AA(3).sqrt()) - sage: Polyhedra(K, 4)._repr_base_ring() + sage: K. = NumberField(x^2 - 3, embedding=AA(3).sqrt()) # optional - sage.rings.number_field + sage: Polyhedra(K, 4)._repr_base_ring() # optional - sage.rings.number_field '(Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)' """ @@ -538,8 +538,8 @@ def _repr_ambient_module(self): sage: from sage.geometry.polyhedron.parent import Polyhedra sage: Polyhedra(QQ, 3)._repr_ambient_module() 'QQ^3' - sage: K. = NumberField(x^2 - 3, embedding=AA(3).sqrt()) - sage: Polyhedra(K, 4)._repr_ambient_module() + sage: K. = NumberField(x^2 - 3, embedding=AA(3).sqrt()) # optional - sage.rings.number_field + sage: Polyhedra(K, 4)._repr_ambient_module() # optional - sage.rings.number_field '(Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)^4' """ s = self._repr_base_ring() @@ -621,11 +621,11 @@ def _element_constructor_(self, *args, **kwds): When the parent of the object is not ``self``, the default is not to copy:: - sage: Q = P.base_extend(AA) - sage: q = Q._element_constructor_(p) - sage: q is p + sage: Q = P.base_extend(AA) # optional - sage.rings.number_field + sage: q = Q._element_constructor_(p) # optional - sage.rings.number_field + sage: q is p # optional - sage.rings.number_field False - sage: q = Q._element_constructor_(p, copy=False) + sage: q = Q._element_constructor_(p, copy=False) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: you need to make a copy when changing the parent @@ -712,9 +712,10 @@ def _element_constructor_polyhedron(self, polyhedron, **kwds): sage: P(p) A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices - sage: P = Polyhedra(AA, 3, backend='field') - sage: p = Polyhedron(vertices=[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]) - sage: P(p) + sage: P = Polyhedra(AA, 3, backend='field') # optional - sage.rings.number_field + sage: vertices = [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)] + sage: p = Polyhedron(vertices=vertices) # optional - sage.rings.number_field + sage: P(p) # optional - sage.rings.number_field A 3-dimensional polyhedron in AA^3 defined as the convex hull of 4 vertices """ Vrep = None @@ -1253,9 +1254,9 @@ def does_backend_handle_base_ring(base_ring, backend): sage: from sage.geometry.polyhedron.parent import does_backend_handle_base_ring sage: does_backend_handle_base_ring(QQ, 'ppl') True - sage: does_backend_handle_base_ring(QQ[sqrt(5)], 'ppl') + sage: does_backend_handle_base_ring(QQ[sqrt(5)], 'ppl') # optional - sage.rings.number_field False - sage: does_backend_handle_base_ring(QQ[sqrt(5)], 'field') + sage: does_backend_handle_base_ring(QQ[sqrt(5)], 'field') # optional - sage.rings.number_field True """ try: From 2a0c39a8eda7cd9ae63258d54eb00c19610f0524 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Jul 2022 21:36:45 -0700 Subject: [PATCH 285/742] sage.geometry: Remove module-level imports of AA, RR, PolynomialRing --- src/sage/geometry/convex_set.py | 12 ++++--- .../geometry/polyhedron/backend_normaliz.py | 9 ++--- src/sage/geometry/polyhedron/base.py | 1 + src/sage/geometry/polyhedron/base0.py | 12 ++----- src/sage/geometry/polyhedron/base6.py | 34 +++++++++++-------- src/sage/geometry/polyhedron/base7.py | 3 +- src/sage/geometry/voronoi_diagram.py | 3 +- 7 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/sage/geometry/convex_set.py b/src/sage/geometry/convex_set.py index 604df756af0..82c3f3bfbe1 100644 --- a/src/sage/geometry/convex_set.py +++ b/src/sage/geometry/convex_set.py @@ -855,10 +855,14 @@ def _test_contains(self, tester=None, **options): tester.assertEqual(contains_space_point, self.contains(ambient_point)) tester.assertEqual(contains_space_point, self.contains(space_coords)) if space.base_ring().is_exact(): - from sage.rings.qqbar import AA - ext_space = self.ambient_vector_space(AA) - ext_space_point = ext_space(space_point) - tester.assertEqual(contains_space_point, self.contains(ext_space_point)) + try: + from sage.rings.qqbar import AA + except ImportError: + pass + else: + ext_space = self.ambient_vector_space(AA) + ext_space_point = ext_space(space_point) + tester.assertEqual(contains_space_point, self.contains(ext_space_point)) try: from sage.symbolic.ring import SR symbolic_space = self.ambient_vector_space(SR) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 86b89632a51..4b5902da342 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -30,8 +30,8 @@ lazy_import('PyNormaliz', ['NmzResult', 'NmzCompute', 'NmzCone', 'NmzConeCopy'], feature=sage.features.normaliz.PyNormaliz()) -from sage.rings.all import ZZ, QQ, QQbar -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.arith.functions import LCM_list from sage.misc.functional import denominator from sage.matrix.constructor import vector @@ -1082,10 +1082,11 @@ def _number_field_triple(normaliz_field): sage: Pn._number_field_triple(QuadraticField(5)) # optional - sage.rings.number_field ['a^2 - 5', 'a', '[2.236067977499789 +/- 8.06e-16]'] """ - from sage.rings.real_arb import RealBallField R = normaliz_field if R is QQ: return None + from sage.rings.real_arb import RealBallField + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing emb = RealBallField(53)(R.gen(0)) gen = 'a' R_a = PolynomialRing(QQ, gen) @@ -2336,7 +2337,7 @@ class functions. ((t^4 + 3*t^3 + 8*t^2 + 3*t + 1)/(t + 1), (3*t^3 + 2*t^2 + 3*t)/(t + 1)) """ from sage.groups.conjugacy_classes import ConjugacyClassGAP - from sage.rings.all import CyclotomicField + from sage.rings.all import CyclotomicField, QQbar from sage.matrix.all import MatrixSpace from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.matrix.special import identity_matrix diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 576e073a825..5582bd190d1 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -51,6 +51,7 @@ from sage.misc.cachefunc import cached_method +import sage.rings.abc from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.matrix.constructor import matrix diff --git a/src/sage/geometry/polyhedron/base0.py b/src/sage/geometry/polyhedron/base0.py index 2e0f6a716cf..1d844d2a073 100644 --- a/src/sage/geometry/polyhedron/base0.py +++ b/src/sage/geometry/polyhedron/base0.py @@ -1366,13 +1366,9 @@ def cdd_Hrepresentation(self): try: cdd_type = self._cdd_type except AttributeError: - from sage.rings.integer_ring import ZZ - from sage.rings.rational_field import QQ - from sage.rings.real_double import RDF - if self.base_ring() is ZZ or self.base_ring() is QQ: cdd_type = 'rational' - elif self.base_ring() is RDF: + elif isinstance(self.base_ring(), sage.rings.abc.RealDoubleField): cdd_type = 'real' else: raise TypeError('the base ring must be ZZ, QQ, or RDF') @@ -1431,13 +1427,9 @@ def cdd_Vrepresentation(self): try: cdd_type = self._cdd_type except AttributeError: - from sage.rings.integer_ring import ZZ - from sage.rings.rational_field import QQ - from sage.rings.real_double import RDF - if self.base_ring() is ZZ or self.base_ring() is QQ: cdd_type = 'rational' - elif self.base_ring() is RDF: + elif isinstance(self.base_ring(), sage.rings.abc.RealDoubleField): cdd_type = 'real' else: raise TypeError('the base ring must be ZZ, QQ, or RDF') diff --git a/src/sage/geometry/polyhedron/base6.py b/src/sage/geometry/polyhedron/base6.py index b569f40613d..9044f3db4d9 100644 --- a/src/sage/geometry/polyhedron/base6.py +++ b/src/sage/geometry/polyhedron/base6.py @@ -36,7 +36,6 @@ from sage.modules.vector_space_morphism import linear_transformation from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector -from sage.rings.qqbar import AA from sage.geometry.convex_set import AffineHullProjectionData from .base5 import Polyhedron_base5 @@ -967,6 +966,7 @@ def _affine_hull_projection(self, *, except TypeError: if not extend: raise ValueError('the base ring needs to be extended; try with "extend=True"') + from sage.rings.qqbar import AA M = matrix(AA, M) A = M.gram_schmidt(orthonormal=orthonormal)[0] if minimal: @@ -1445,21 +1445,25 @@ def _test_affine_hull_projection(self, tester=None, verbose=False, **options): # Avoid very long doctests. return - data_sets = [None]*4 - data_sets[0] = self.affine_hull_projection(return_all_data=True) + try: + from sage.rings.qqbar import AA + except ImportError: + AA = None + + data_sets = [] + data_sets.append(self.affine_hull_projection(return_all_data=True)) if self.is_compact(): - data_sets[1] = self.affine_hull_projection(return_all_data=True, - orthogonal=True, - extend=True) - data_sets[2] = self.affine_hull_projection(return_all_data=True, - orthonormal=True, - extend=True) - data_sets[3] = self.affine_hull_projection(return_all_data=True, - orthonormal=True, - extend=True, - minimal=True) - else: - data_sets = data_sets[:1] + data_sets.append(self.affine_hull_projection(return_all_data=True, + orthogonal=True, + extend=True)) + if AA is not None: + data_sets.append(self.affine_hull_projection(return_all_data=True, + orthonormal=True, + extend=True)) + data_sets.append(self.affine_hull_projection(return_all_data=True, + orthonormal=True, + extend=True, + minimal=True)) for i, data in enumerate(data_sets): if verbose: diff --git a/src/sage/geometry/polyhedron/base7.py b/src/sage/geometry/polyhedron/base7.py index 93138e3dc4f..137acd2f61c 100644 --- a/src/sage/geometry/polyhedron/base7.py +++ b/src/sage/geometry/polyhedron/base7.py @@ -37,7 +37,6 @@ from sage.modules.free_module_element import vector from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.qqbar import AA from .base6 import Polyhedron_base6 class Polyhedron_base7(Polyhedron_base6): @@ -714,6 +713,7 @@ def volume(self, measure='ambient', engine='auto', **kwds): if Adet.is_square(): sqrt_Adet = Adet.sqrt() else: + from sage.rings.qqbar import AA sqrt_Adet = AA(Adet).sqrt() scaled_volume = AA(scaled_volume) return scaled_volume / sqrt_Adet @@ -910,6 +910,7 @@ def integrate(self, function, measure='ambient', **kwds): A = affine_hull_data.projection_linear_map.matrix() Adet = (A.transpose() * A).det() try: + from sage.rings.qqbar import AA Adet = AA.coerce(Adet) except TypeError: pass diff --git a/src/sage/geometry/voronoi_diagram.py b/src/sage/geometry/voronoi_diagram.py index e280a41143a..1e9629aa646 100644 --- a/src/sage/geometry/voronoi_diagram.py +++ b/src/sage/geometry/voronoi_diagram.py @@ -15,7 +15,6 @@ from sage.structure.sage_object import SageObject from sage.geometry.polyhedron.constructor import Polyhedron -from sage.rings.qqbar import AA from sage.rings.rational_field import QQ import sage.rings.abc from sage.geometry.triangulation.point_configuration import PointConfiguration @@ -103,7 +102,7 @@ def __init__(self, points): self._n = self._points.n_points() if not self._n or self._points.base_ring().is_subring(QQ): self._base_ring = QQ - elif isinstance(self._points.base_ring(), sage.rings.abc.RealDoubleField) or self._points.base_ring() == AA: + elif isinstance(self._points.base_ring(), (sage.rings.abc.RealDoubleField, sage.rings.abc.AlgebraicRealField)): self._base_ring = self._points.base_ring() elif isinstance(self._points.base_ring(), sage.rings.abc.RealField): from sage.rings.real_double import RDF From 278b93f390a1caf8e511409e2ee0e39697aed8c3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Jul 2022 21:37:15 -0700 Subject: [PATCH 286/742] sage.geometry: More # optional - sage.rings.number_field --- src/sage/geometry/polyhedron/base3.py | 4 ++-- src/sage/geometry/polyhedron/base6.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/geometry/polyhedron/base3.py b/src/sage/geometry/polyhedron/base3.py index 0b85c4f944c..ff144d04e39 100644 --- a/src/sage/geometry/polyhedron/base3.py +++ b/src/sage/geometry/polyhedron/base3.py @@ -136,8 +136,8 @@ def slack_matrix(self): [1 0 1 0 0 1] [1 0 0 0 1 1] - sage: P = polytopes.dodecahedron().faces(2)[0].as_polyhedron() - sage: P.slack_matrix() + sage: P = polytopes.dodecahedron().faces(2)[0].as_polyhedron() # optional - sage.rings.number_field + sage: P.slack_matrix() # optional - sage.rings.number_field [1/2*sqrt5 - 1/2 0 0 1 1/2*sqrt5 - 1/2 0] [ 0 0 1/2*sqrt5 - 1/2 1/2*sqrt5 - 1/2 1 0] [ 0 1/2*sqrt5 - 1/2 1 0 1/2*sqrt5 - 1/2 0] diff --git a/src/sage/geometry/polyhedron/base6.py b/src/sage/geometry/polyhedron/base6.py index 9044f3db4d9..c6ed839ba77 100644 --- a/src/sage/geometry/polyhedron/base6.py +++ b/src/sage/geometry/polyhedron/base6.py @@ -1176,9 +1176,9 @@ def affine_hull_projection(self, A vertex at (2, 0, 0), A vertex at (1, 3/2, 0), A vertex at (1, 1/2, 4/3)) - sage: A = S.affine_hull_projection(orthonormal=True, extend=True); A + sage: A = S.affine_hull_projection(orthonormal=True, extend=True); A # optional - sage.rings.number_field A 3-dimensional polyhedron in AA^3 defined as the convex hull of 4 vertices - sage: A.vertices() + sage: A.vertices() # optional - sage.rings.number_field (A vertex at (0.7071067811865475?, 0.4082482904638630?, 1.154700538379252?), A vertex at (0.7071067811865475?, 1.224744871391589?, 0.?e-18), A vertex at (1.414213562373095?, 0.?e-18, 0.?e-18), @@ -1187,11 +1187,11 @@ def affine_hull_projection(self, With the parameter ``minimal`` one can get a minimal base ring:: sage: s = polytopes.simplex(3) - sage: s_AA = s.affine_hull_projection(orthonormal=True, extend=True) - sage: s_AA.base_ring() + sage: s_AA = s.affine_hull_projection(orthonormal=True, extend=True) # optional - sage.rings.number_field + sage: s_AA.base_ring() # optional - sage.rings.number_field Algebraic Real Field - sage: s_full = s.affine_hull_projection(orthonormal=True, extend=True, minimal=True) - sage: s_full.base_ring() + sage: s_full = s.affine_hull_projection(orthonormal=True, extend=True, minimal=True) # optional - sage.rings.number_field + sage: s_full.base_ring() # optional - sage.rings.number_field Number Field in a with defining polynomial y^4 - 4*y^2 + 1 with a = 0.5176380902050415? More examples with the ``orthonormal`` parameter:: From fdb77649f1d64dada4cd22ac68808067314b4846 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Jun 2022 10:02:04 -0700 Subject: [PATCH 287/742] build/pkgs/numpy: Update to 1.23.0 --- build/pkgs/numpy/checksums.ini | 6 +++--- build/pkgs/numpy/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/numpy/checksums.ini b/build/pkgs/numpy/checksums.ini index c15b3d8db64..7d17cc9b58f 100644 --- a/build/pkgs/numpy/checksums.ini +++ b/build/pkgs/numpy/checksums.ini @@ -1,5 +1,5 @@ tarball=numpy-VERSION.zip -sha1=3ac08064b2ec8db8fe4870c2545c9d154f46bb30 -md5=b44849506fbb54cdef9dbb435b2b1987 -cksum=735479084 +sha1=16754e7f2688644744c099adfddcb6b18ae630f8 +md5=513e4241d06b8fae5732cd049cdf3b57 +cksum=2058823291 upstream_url=https://pypi.io/packages/source/n/numpy/numpy-VERSION.zip diff --git a/build/pkgs/numpy/package-version.txt b/build/pkgs/numpy/package-version.txt index 2a0ba77cc5e..a6c2798a482 100644 --- a/build/pkgs/numpy/package-version.txt +++ b/build/pkgs/numpy/package-version.txt @@ -1 +1 @@ -1.22.4 +1.23.0 From 09066c826bdf513374979a13c0a2518c874d8401 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Jun 2022 10:55:04 -0700 Subject: [PATCH 288/742] build/pkgs/numpy: Switch to using .tar.gz --- build/pkgs/numpy/checksums.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/numpy/checksums.ini b/build/pkgs/numpy/checksums.ini index 7d17cc9b58f..5cce3e2c75a 100644 --- a/build/pkgs/numpy/checksums.ini +++ b/build/pkgs/numpy/checksums.ini @@ -1,5 +1,5 @@ -tarball=numpy-VERSION.zip +tarball=numpy-VERSION.tar.gz sha1=16754e7f2688644744c099adfddcb6b18ae630f8 md5=513e4241d06b8fae5732cd049cdf3b57 cksum=2058823291 -upstream_url=https://pypi.io/packages/source/n/numpy/numpy-VERSION.zip +upstream_url=https://pypi.io/packages/source/n/numpy/numpy-VERSION.tar.gz From 5b0f2446a0eb2c5ae1d01890cfcada424e2cfb49 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 8 Jul 2022 19:23:58 -0700 Subject: [PATCH 289/742] build/pkgs/numpy: Update to 1.23.1 --- build/pkgs/numpy/checksums.ini | 6 +++--- build/pkgs/numpy/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/numpy/checksums.ini b/build/pkgs/numpy/checksums.ini index 5cce3e2c75a..e30ec7617ca 100644 --- a/build/pkgs/numpy/checksums.ini +++ b/build/pkgs/numpy/checksums.ini @@ -1,5 +1,5 @@ tarball=numpy-VERSION.tar.gz -sha1=16754e7f2688644744c099adfddcb6b18ae630f8 -md5=513e4241d06b8fae5732cd049cdf3b57 -cksum=2058823291 +sha1=5c3d78e955a302dcdb001012e565f52efb15d082 +md5=4f8636a9c1a77ca0fb923ba55378891f +cksum=2402400948 upstream_url=https://pypi.io/packages/source/n/numpy/numpy-VERSION.tar.gz diff --git a/build/pkgs/numpy/package-version.txt b/build/pkgs/numpy/package-version.txt index a6c2798a482..49e0a31d496 100644 --- a/build/pkgs/numpy/package-version.txt +++ b/build/pkgs/numpy/package-version.txt @@ -1 +1 @@ -1.23.0 +1.23.1 From d4ff77dce90d0a6df2f86f8e38fa099aaf7e1ff9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 25 Aug 2022 17:45:00 -0700 Subject: [PATCH 290/742] build/pkgs/numpy: Update to 1.23.2 --- build/pkgs/numpy/checksums.ini | 6 +++--- build/pkgs/numpy/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/numpy/checksums.ini b/build/pkgs/numpy/checksums.ini index e30ec7617ca..9c688839a58 100644 --- a/build/pkgs/numpy/checksums.ini +++ b/build/pkgs/numpy/checksums.ini @@ -1,5 +1,5 @@ tarball=numpy-VERSION.tar.gz -sha1=5c3d78e955a302dcdb001012e565f52efb15d082 -md5=4f8636a9c1a77ca0fb923ba55378891f -cksum=2402400948 +sha1=1cbc6c34a5c4522322951d502982060e0e48811e +md5=9bf2a361509797de14ceee607387fe0f +cksum=1967048071 upstream_url=https://pypi.io/packages/source/n/numpy/numpy-VERSION.tar.gz diff --git a/build/pkgs/numpy/package-version.txt b/build/pkgs/numpy/package-version.txt index 49e0a31d496..14bee92c9e7 100644 --- a/build/pkgs/numpy/package-version.txt +++ b/build/pkgs/numpy/package-version.txt @@ -1 +1 @@ -1.23.1 +1.23.2 From a8e663aede8d6c9d609cd57226f370e87edfa8ff Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 26 Aug 2022 09:02:33 +0200 Subject: [PATCH 291/742] final fixes for LazySymmetricFunction.revert --- src/sage/rings/lazy_series.py | 79 ++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 29d1c2a7d75..f3718bec000 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3860,29 +3860,31 @@ def __call__(self, *args, check=True): def revert(self): r""" - Return the compositional inverse of ``self`` if possible. + Return the compositional inverse of ``self``. + + Given a symmetric function `f`, the compositional inverse is + a symmetric function `g` over the same base ring, such that + `f \circ g = p_1`. Thus, it is the inverse with respect to + plethystic substitution. - (Specifically, if ``self`` is of the form `0 + p_{1} + \cdots`.) + The compositional inverse exists if and only if: + + - `val(f) = 1`, or - The compositional inverse is the inverse with respect to - plethystic substitution. This is the operation on cycle index - series which corresponds to substitution, a.k.a. partitional - composition, on the level of species. See Section 2.2 of - [BLL]_ for a definition of this operation. + - `f = a + b p_1` with `a, b \neq 0`. EXAMPLES:: sage: h = SymmetricFunctions(QQ).h() - sage: p = SymmetricFunctions(QQ).p() - sage: L = LazySymmetricFunctions(p) - sage: Eplus = L(lambda n: h[n]) - 1 - sage: Eplus(Eplus.revert()) - p[1] + O^7 + sage: L = LazySymmetricFunctions(h) + sage: f = L(lambda n: h[n]) - 1 + sage: f(f.revert()) + h[1] + O^7 TESTS:: - sage: Eplus = L(lambda n: h[n]) - 1 - h[1] - sage: Eplus.compositional_inverse() + sage: f = L(lambda n: h[n]) - 1 - h[1] + sage: f.compositional_inverse() Traceback (most recent call last): ... ValueError: compositional inverse does not exist @@ -3892,11 +3894,11 @@ def revert(self): sage: L = LazySymmetricFunctions(p) sage: f = L(a + b*p[1]) sage: f.revert() - ((-a)/b)*p[] + 1/b*p[1] + (((-a)/b)*p[]) + 1/b*p[1] sage: f = L(2*p[1]) sage: f.revert() - 1/2*p[1] + O^8 + 1/2*p[1] sage: f = L(2*p[1] + p[2] + p[1,1]) sage: f.revert() @@ -3904,45 +3906,56 @@ def revert(self): ALGORITHM: - Let `F` be a species satisfying `F = 0 + X + F_2 + F_3 + \cdots` for - `X` the species of singletons. (Equivalently, `\lvert F[\varnothing] - \rvert = 0` and `\lvert F[\{1\}] \rvert = 1`.) Then there exists a - (virtual) species `G` satisfying `F \circ G = G \circ F = X`. + Let `F` be a symmetric function with valuation `1`, i.e., + whose constant term vanishes and whose degree one term equals + `b p_1`. Then - It follows that `(F - X) \circ G = F \circ G - X \circ G = X - G`. - Rearranging, we obtain the recursive equation `G = X - (F - X) \circ G`, - which can be solved using iterative methods. + .. MATH:: - .. WARNING:: + (F - b p_1) \circ G = F \circ G - b p_1 \circ G = p_1 - b G`, - This algorithm is functional but can be very slow. - Use with caution! + and therefore `G = 1/b (p_1 - (F - b p_1) \circ G)`, which + allows recursive computation of `G`. .. SEEALSO:: - The compositional inverse `\Omega` of the species `E_{+}` - of nonempty sets can be handled much more efficiently - using specialized methods. See + The compositional inverse `\Omega` of the symmetric + function `h_1 + h_2 + \dots` can be handled much more + efficiently using specialized methods. See :func:`~sage.combinat.species.generating_series.LogarithmCycleIndexSeries` AUTHORS: - Andrew Gainer-Dewar + - Martin Rubey + """ P = self.parent() + R = P._laurent_poly_ring if P._arity != 1: raise ValueError("arity must be equal to 1") coeff_stream = self._coeff_stream if isinstance(coeff_stream, Stream_zero): raise ValueError("compositional inverse does not exist") + if (isinstance(coeff_stream, Stream_exact) + and coeff_stream.order() >= 0 + and coeff_stream._degree == 2): + # self = a + b * p_1; self.revert() = -a/b + 1/b * p_1 + a = coeff_stream[0] + b = coeff_stream[1][Partition([1])] + X = R(Partition([1])) + coeff_stream = Stream_exact((-a/b, 1/b * X), + coeff_stream._is_sparse, + order=0) + return P.element_class(P, coeff_stream) + if coeff_stream[0] or not coeff_stream[1]: raise ValueError("compositional inverse does not exist") - ps = P._laurent_poly_ring.realization_of().p() - X = P(ps[1]) - f1 = coeff_stream[1][Partition([1])] + X = R(Partition([1])) + b = coeff_stream[1][Partition([1])] g = P(None, valuation=1) - g.define(~f1*X - (self - f1*X)(g)) + g.define(~b * X - (self - b * X)(g)) return g plethystic_inverse = revert From 5436995676cf798189202f582ba283c3d95402f5 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 26 Aug 2022 09:11:07 +0200 Subject: [PATCH 292/742] final fixes for LazySymmetricFunction.revert, part 2 --- src/sage/rings/lazy_series.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index f3718bec000..6fd45d14c0e 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3162,19 +3162,16 @@ def revert(self): else: raise ValueError("cannot determine whether the compositional inverse exists") + if not coeff_stream[1]: + raise ValueError("compositional inverse does not exist") + if coeff_stream[0]: - if coeff_stream[1]: raise ValueError("cannot determine whether the compositional inverse exists") - else: - raise ValueError("compositional inverse does not exist") - - if coeff_stream[1]: - z = P.gen() - g = P(None, valuation=1) - g.define(z/((self/z)(g))) - return g - raise ValueError("compositional inverse does not exist") + z = P.gen() + g = P(None, valuation=1) + g.define(z / ((self / z)(g))) + return g compositional_inverse = revert @@ -3949,9 +3946,12 @@ def revert(self): order=0) return P.element_class(P, coeff_stream) - if coeff_stream[0] or not coeff_stream[1]: + if not coeff_stream[1]: raise ValueError("compositional inverse does not exist") + if coeff_stream[0]: + raise ValueError("cannot determine whether the compositional inverse exists") + X = R(Partition([1])) b = coeff_stream[1][Partition([1])] g = P(None, valuation=1) From af347b2de7608315242ca53b1b8b03a4d6ccfbb7 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 26 Aug 2022 12:27:19 +0200 Subject: [PATCH 293/742] refactor and doctest --- src/sage/combinat/partition.py | 14 +++ src/sage/combinat/sf/powersum.py | 4 +- src/sage/combinat/sf/sfa.py | 132 +++++++++++++++++++++-------- src/sage/data_structures/stream.py | 47 ++++------ 4 files changed, 131 insertions(+), 66 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 811679ede16..d24f6add1f6 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -1057,6 +1057,20 @@ def __truediv__(self, p): return SkewPartition([self[:], p]) + def stretch(self, k): + """ + Return the partition obtained by multiplying each part with the + given number. + + EXAMPLES:: + + sage: p = Partition([4,2,2,1,1]) + sage: p.stretch(3) + [12,6,6,3,3] + + """ + return _Partitions([k * p for p in self]) + def power(self, k): r""" Return the cycle type of the `k`-th power of any permutation diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index f7542d7929e..f7019407840 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -476,8 +476,8 @@ def frobenius(self, n): :meth:`~sage.combinat.sf.sfa.SymmetricFunctionAlgebra_generic_Element.plethysm` """ - dct = {Partition([n * i for i in lam]): coeff - for (lam, coeff) in self.monomial_coefficients().items()} + dct = {lam.stretch(n): coeff + for lam, coeff in self.monomial_coefficients().items()} return self.parent()._from_dict(dct) adams_operation = frobenius diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 1743beafd61..d6f7773ef84 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -3071,6 +3071,13 @@ def plethysm(self, x, include=None, exclude=None): a1*b1*p[1] + a11*b1^2*p[1, 1] + a1*b111*p[1, 1, 1] + 2*a11*b1*b111*p[1, 1, 1, 1] + a11*b111^2*p[1, 1, 1, 1, 1, 1] + a2*b1^2*p[2] + a1*b21*p[2, 1] + 2*a11*b1*b21*p[2, 1, 1] + 2*a11*b21*b111*p[2, 1, 1, 1, 1] + a11*b21^2*p[2, 2, 1, 1] + a2*b111^2*p[2, 2, 2] + a2*b21^2*p[4, 2] sage: r - f(g, include=[]) (a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2] + + .. TODO:: + + The implementation of plethysm in + :class:`sage.data_structures.stream.Stream_plethysm` seems + to be faster. This should be investigated. + """ parent = self.parent() R = parent.base_ring() @@ -3084,54 +3091,33 @@ def plethysm(self, x, include=None, exclude=None): if self == parent.zero(): return self - # Handle degree one elements - if include is not None and exclude is not None: - raise RuntimeError("include and exclude cannot both be specified") - R = p.base_ring() - - if include is not None: - degree_one = [R(g) for g in include] - else: - try: - degree_one = [R(g) for g in R.variable_names_recursive()] - except AttributeError: - try: - degree_one = R.gens() - except NotImplementedError: - degree_one = [] - if exclude is not None: - degree_one = [g for g in degree_one if g not in exclude] - - degree_one = [g for g in degree_one if g != R.one()] + degree_one = _variables_recursive(R, include=include, exclude=exclude) def raise_c(n): return lambda c: c.subs(**{str(g): g ** n for g in degree_one}) if tensorflag: tparents = x.parent()._sets - return tensor([parent]*len(tparents))(sum(d*prod(sum(raise_c(r)(c) - * tensor([p[r].plethysm(base(la)) - for (base,la) in zip(tparents,trm)]) - for (trm,c) in x) - for r in mu) - for (mu, d) in p(self))) - - # Takes in n, and returns a function which takes in a partition and - # scales all of the parts of that partition by n - def scale_part(n): - return lambda m: m.__class__(m.parent(), [i * n for i in m]) + + s = sum(d * prod(sum(_raise_variables(c, r, degree_one) + * tensor([p[r].plethysm(base(la)) + for base, la in zip(tparents, trm)]) + for trm, c in x) + for r in mu) + for mu, d in p(self)) + return tensor([parent]*len(tparents))(s) # Takes n an symmetric function f, and an n and returns the # symmetric function with all of its basis partitions scaled # by n def pn_pleth(f, n): - return f.map_support(scale_part(n)) + return f.map_support(lambda mu: mu.stretch(n)) # Takes in a partition and applies p_x = p(x) def f(part): - return p.prod(pn_pleth(p_x.map_coefficients(raise_c(i)), i) + return p.prod(pn_pleth(p_x.map_coefficients(lambda c: _raise_variables(c, i, degree_one)), i) for i in part) return parent(p._apply_module_morphism(p(self), f, codomain=p)) @@ -4910,8 +4896,7 @@ def frobenius(self, n): parent = self.parent() m = parent.realization_of().monomial() from sage.combinat.partition import Partition - dct = {Partition([n * i for i in lam]): coeff - for (lam, coeff) in m(self)} + dct = {lam.stretch(n): coeff for lam, coeff in m(self)} result_in_m_basis = m._from_dict(dct) return parent(result_in_m_basis) @@ -6116,3 +6101,82 @@ def _nonnegative_coefficients(x): return all(c >= 0 for c in x.coefficients(sparse=False)) else: return x >= 0 + +def _variables_recursive(R, include=None, exclude=None): + """ + Return all variables appearing in the ring ``R``. + + INPUT: + + - ``R`` -- a :class:`Ring` + - ``include``, ``exclude`` (optional, default ``None``) -- + iterables of variables in ``R`` + + OUTPUT: + + - If ``include`` is specified, only these variables are returned + as elements of ``R``. Otherwise, all variables in ``R`` + (recursively) with the exception of those in ``exclude`` are + returned. + + EXAMPLES:: + + sage: from sage.combinat.sf.sfa import _variables_recursive + sage: R. = QQ[] + sage: S. = R[] + sage: _variables_recursive(S) + [a, b, t] + + sage: _variables_recursive(S, exclude=[b]) + [a, t] + + sage: _variables_recursive(S, include=[b]) + [b] + + TESTS:: + + sage: _variables_recursive(R.fraction_field(), exclude=[b]) + [a] + + sage: _variables_recursive(S.fraction_field(), exclude=[b]) # known bug + [a, t] + """ + if include is not None and exclude is not None: + raise RuntimeError("include and exclude cannot both be specified") + + if include is not None: + degree_one = [R(g) for g in include] + else: + try: + degree_one = [R(g) for g in R.variable_names_recursive()] + except AttributeError: + try: + degree_one = R.gens() + except NotImplementedError: + degree_one = [] + if exclude is not None: + degree_one = [g for g in degree_one if g not in exclude] + + return [g for g in degree_one if g != R.one()] + +def _raise_variables(c, n, variables): + """ + Replace the given variables in the ring element ``c`` with their + ``n``-th power. + + INPUT: + + - ``c`` -- an element of a ring + - ``n`` -- the power to raise the given variables to + - ``variables`` -- the variables to raise + + EXAMPLES:: + + sage: from sage.combinat.sf.sfa import _raise_variables + sage: R. = QQ[] + sage: S. = R[] + sage: _raise_variables(2*a + 3*b*t, 2, [a, t]) + 3*b*t^2 + 2*a^2 + + """ + return c.subs(**{str(g): g ** n for g in variables}) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index b60ef186118..62391b8ec2c 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -98,6 +98,7 @@ from sage.rings.infinity import infinity from sage.arith.misc import divisors from sage.combinat.integer_vector_weighted import iterator_fast as wt_int_vec_iter +from sage.combinat.sf.sfa import _variables_recursive, _raise_variables class Stream(): """ @@ -1748,26 +1749,6 @@ def __init__(self, f, g, p, ring=None, include=None, exclude=None): sage: g = Stream_function(lambda n: s[n-1,1], s, True, 2) sage: h = Stream_plethysm(f, g, p) """ - # handle degree one elements - if include is not None and exclude is not None: - raise RuntimeError("include and exclude cannot both be specified") - R = p.base_ring() - - if include is not None: - degree_one = [R(g) for g in include] - else: - try: - degree_one = [R(g) for g in R.variable_names_recursive()] - except AttributeError: - try: - degree_one = R.gens() - except NotImplementedError: - degree_one = [] - if exclude is not None: - degree_one = [g for g in degree_one if g not in exclude] - - self._degree_one = [g for g in degree_one if g != R.one()] - # assert g._approximate_order > 0 val = f._approximate_order * g._approximate_order p_f = Stream_map_coefficients(f, lambda x: x, p) @@ -1778,7 +1759,8 @@ def __init__(self, f, g, p, ring=None, include=None, exclude=None): else: self._basis = ring self._p = p - + self._degree_one = _variables_recursive(self._basis.base_ring(), + include=include, exclude=exclude) super().__init__(p_f, p_g, f._is_sparse, val) def get_coefficient(self, n): @@ -1849,16 +1831,21 @@ def _compute_product(self, n, la): ret += temp return ret - def _scale_part(self, mu, i): - return mu.__class__(mu.parent(), [j * i for j in mu]) - - def _raise_c(self, c, i): - return c.subs(**{str(g): g ** i - for g in self._degree_one}) - def _stretched_power_restrict_degree(self, i, m, d): """ Return the degree ``d*i`` part of ``p([i]*m)(g)``. + + TESTS:: + + sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function + sage: s = SymmetricFunctions(QQ).s() + sage: p = SymmetricFunctions(QQ).p() + sage: f = Stream_function(lambda n: s[n], s, True, 1) + sage: g = Stream_exact([s[2], s[3]], False, 0, 4, 2) + sage: h = Stream_plethysm(f, g, p) + sage: ret = h._stretched_power_restrict_degree(2, 3, 6) + sage: ret == p[2,2,2](s[2] + s[3]).homogeneous_component(12) + True """ while len(self._powers) < m: self._powers.append(Stream_cauchy_mul(self._powers[-1], self._powers[0])) @@ -1866,8 +1853,8 @@ def _stretched_power_restrict_degree(self, i, m, d): # we have to check power_d for zero because it might be an # integer and not a symmetric function if power_d: - terms = {self._scale_part(m, i): raised_c for m, c in power_d - if (raised_c := self._raise_c(c, i))} + terms = {m.stretch(i): raised_c for m, c in power_d + if (raised_c := _raise_variables(c, i, self._degree_one))} return self._p.element_class(self._p, terms) return self._p.zero() From 0d9f02f91f7ed204c1ce3dfde5b1df42a9e5e787 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 26 Aug 2022 14:10:19 +0200 Subject: [PATCH 294/742] leftover --- src/sage/combinat/sf/sfa.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index d6f7773ef84..ab49198fbaa 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -3093,9 +3093,6 @@ def plethysm(self, x, include=None, exclude=None): degree_one = _variables_recursive(R, include=include, exclude=exclude) - def raise_c(n): - return lambda c: c.subs(**{str(g): g ** n for g in degree_one}) - if tensorflag: tparents = x.parent()._sets @@ -3107,7 +3104,7 @@ def raise_c(n): for mu, d in p(self)) return tensor([parent]*len(tparents))(s) - # Takes n an symmetric function f, and an n and returns the + # Takes a symmetric function f, and an n and returns the # symmetric function with all of its basis partitions scaled # by n def pn_pleth(f, n): From ae991754875bedbac56b99424daef033ba05dd4d Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 26 Aug 2022 19:58:42 +0200 Subject: [PATCH 295/742] plethysm with tensor products, part 1 --- src/sage/combinat/sf/sfa.py | 1 - src/sage/data_structures/stream.py | 56 +++++++++++++++++++++++------- src/sage/rings/lazy_series.py | 17 +++++++-- 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index ab49198fbaa..82125d275fe 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -3095,7 +3095,6 @@ def plethysm(self, x, include=None, exclude=None): if tensorflag: tparents = x.parent()._sets - s = sum(d * prod(sum(_raise_variables(c, r, degree_one) * tensor([p[r].plethysm(base(la)) for base, la in zip(tparents, trm)]) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 62391b8ec2c..aeebe90e6d9 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -99,6 +99,7 @@ from sage.arith.misc import divisors from sage.combinat.integer_vector_weighted import iterator_fast as wt_int_vec_iter from sage.combinat.sf.sfa import _variables_recursive, _raise_variables +from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis class Stream(): """ @@ -1759,8 +1760,12 @@ def __init__(self, f, g, p, ring=None, include=None, exclude=None): else: self._basis = ring self._p = p - self._degree_one = _variables_recursive(self._basis.base_ring(), - include=include, exclude=exclude) + R = self._basis.base_ring() + if HopfAlgebrasWithBasis(R).TensorProducts() in p.categories(): + self._tensor_power = len(p._sets) + else: + self._tensor_power = None + self._degree_one = _variables_recursive(R, include=include, exclude=exclude) super().__init__(p_f, p_g, f._is_sparse, val) def get_coefficient(self, n): @@ -1801,18 +1806,28 @@ def _compute_product(self, n, la): """ Compute the product ``c * p[la](self._right)`` in degree ``n``. - EXAMPLES:: + TESTS:: - sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function + sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function, Stream_zero sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() - sage: f = Stream_function(lambda n: s[n], s, True, 1) + sage: f = Stream_zero(True) # irrelevant for this test sage: g = Stream_exact([s[2], s[3]], False, 0, 4, 2) sage: h = Stream_plethysm(f, g, p) - sage: ret = h._compute_product(7, Partition([2, 1])); ret + sage: A = h._compute_product(7, Partition([2, 1])); A 1/12*p[2, 2, 1, 1, 1] + 1/4*p[2, 2, 2, 1] + 1/6*p[3, 2, 2] + 1/12*p[4, 1, 1, 1] + 1/4*p[4, 2, 1] + 1/6*p[4, 3] - sage: ret == p[2,1](s[2] + s[3]).homogeneous_component(7) + sage: A == p[2,1](s[2] + s[3]).homogeneous_component(7) + True + + sage: p2 = tensor([p, p]) + sage: f = Stream_zero(True) # irrelevant for this test + sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), p2, True, 1) + sage: h = Stream_plethysm(f, g, p2) + sage: A = h._compute_product(7, Partition([2, 1])) + sage: B = p[2,1](sum(g[n] for n in range(7))) + sage: B = p2.element_class(p2, {m: c for m, c in B if sum(mu.size() for mu in m) == 7}) + sage: A == B True """ ret = self._basis.zero() @@ -1837,14 +1852,24 @@ def _stretched_power_restrict_degree(self, i, m, d): TESTS:: - sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function + sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function, Stream_zero sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() - sage: f = Stream_function(lambda n: s[n], s, True, 1) + sage: f = Stream_zero(False) # irrelevant for this test sage: g = Stream_exact([s[2], s[3]], False, 0, 4, 2) sage: h = Stream_plethysm(f, g, p) - sage: ret = h._stretched_power_restrict_degree(2, 3, 6) - sage: ret == p[2,2,2](s[2] + s[3]).homogeneous_component(12) + sage: A = h._stretched_power_restrict_degree(2, 3, 6) + sage: A == p[2,2,2](s[2] + s[3]).homogeneous_component(12) + True + + sage: p2 = tensor([p, p]) + sage: f = Stream_zero(True) # irrelevant for this test + sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), p2, True, 1) + sage: h = Stream_plethysm(f, g, p2) + sage: A = h._stretched_power_restrict_degree(2, 3, 6) + sage: B = p[2,2,2](sum(g[n] for n in range(7))) + sage: B = p2.element_class(p2, {m: c for m, c in B if sum(mu.size() for mu in m) == 12}) + sage: A == B True """ while len(self._powers) < m: @@ -1853,8 +1878,13 @@ def _stretched_power_restrict_degree(self, i, m, d): # we have to check power_d for zero because it might be an # integer and not a symmetric function if power_d: - terms = {m.stretch(i): raised_c for m, c in power_d - if (raised_c := _raise_variables(c, i, self._degree_one))} + if self._tensor_power is None: + terms = {m.stretch(i): raised_c for m, c in power_d + if (raised_c := _raise_variables(c, i, self._degree_one))} + else: + terms = {tuple((mu.stretch(i) for mu in m)): raised_c + for m, c in power_d + if (raised_c := _raise_variables(c, i, self._degree_one))} return self._p.element_class(self._p, terms) return self._p.zero() diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 6fd45d14c0e..01059a15e9d 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3780,6 +3780,17 @@ def __call__(self, *args, check=True): sage: [s(x) for x in P[:5]] [s[], s[1], 2*s[2], s[2, 1] + 3*s[3], 2*s[2, 2] + 2*s[3, 1] + 5*s[4]] + The plethysm with a tensor product is also implemented:: + + sage: s = SymmetricFunctions(QQ).s() + sage: X = tensor([s[1],s[[]]]) + sage: Y = tensor([s[[]],s[1]]) + sage: S = LazySymmetricFunctions(s) + sage: S2 = LazySymmetricFunctions(tensor([s, s])) + sage: A = S(s[1,1,1]) + sage: B = S2(X+Y) + sage: A(B) + TESTS:: sage: s = SymmetricFunctions(QQ).s() @@ -3822,12 +3833,14 @@ def __call__(self, *args, check=True): if not isinstance(g, LazySymmetricFunction) and not g: return P(self[0].leading_coefficient()) - if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: + if (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): f = self.symmetric_function() if is_SymmetricFunction(g): return f(g) # g must be a LazySymmetricFunction - if isinstance(g._coeff_stream, Stream_exact) and not g._coeff_stream._constant: + if (isinstance(g._coeff_stream, Stream_exact) + and not g._coeff_stream._constant): gs = g.symmetric_function() return P(f(gs)) From 0f12ac293022f5c43c8d2497b44ea8d69a34685e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 14:18:08 -0700 Subject: [PATCH 296/742] src/sage/geometry/polyhedron/base0.py: Restore lost imports --- src/sage/geometry/polyhedron/base0.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/geometry/polyhedron/base0.py b/src/sage/geometry/polyhedron/base0.py index 1d844d2a073..2cef77fd47e 100644 --- a/src/sage/geometry/polyhedron/base0.py +++ b/src/sage/geometry/polyhedron/base0.py @@ -1366,6 +1366,8 @@ def cdd_Hrepresentation(self): try: cdd_type = self._cdd_type except AttributeError: + from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ if self.base_ring() is ZZ or self.base_ring() is QQ: cdd_type = 'rational' elif isinstance(self.base_ring(), sage.rings.abc.RealDoubleField): @@ -1427,6 +1429,8 @@ def cdd_Vrepresentation(self): try: cdd_type = self._cdd_type except AttributeError: + from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ if self.base_ring() is ZZ or self.base_ring() is QQ: cdd_type = 'rational' elif isinstance(self.base_ring(), sage.rings.abc.RealDoubleField): From 74bc04b8493ec925a4cfcd33dbc73cf078d08d06 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 14:22:28 -0700 Subject: [PATCH 297/742] src/sage/geometry/polyhedron/base{3,6}.py: Muffle pyflakes warnings about unused imports --- src/sage/geometry/polyhedron/base3.py | 1 + src/sage/geometry/polyhedron/base6.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/sage/geometry/polyhedron/base3.py b/src/sage/geometry/polyhedron/base3.py index ff144d04e39..49204ed6304 100644 --- a/src/sage/geometry/polyhedron/base3.py +++ b/src/sage/geometry/polyhedron/base3.py @@ -1863,6 +1863,7 @@ def _test_combinatorial_face_as_combinatorial_polyhedron(self, tester=None, **op D2._test_bitsets(tester, **options) try: import sage.graphs.graph + assert sage.graphs.graph # to muffle pyflakes except ImportError: pass else: diff --git a/src/sage/geometry/polyhedron/base6.py b/src/sage/geometry/polyhedron/base6.py index c6ed839ba77..21045562e78 100644 --- a/src/sage/geometry/polyhedron/base6.py +++ b/src/sage/geometry/polyhedron/base6.py @@ -699,6 +699,7 @@ def _test_gale_transform(self, tester=None, **options): try: import sage.graphs.graph + assert sage.graphs.graph # to muffle pyflakes except ImportError: pass else: From 7db47e13d73818b34da78c7f6ee05005b5206bc7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 14:23:22 -0700 Subject: [PATCH 298/742] src/sage/geometry/polyhedron/parent.py: Muffle pyflakes warning --- src/sage/geometry/polyhedron/parent.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index de492eb6301..c6a2b315c73 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -176,6 +176,7 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * try: from sage.interfaces.polymake import polymake polymake_base_field = polymake(base_field) + assert polymake_base_field # to muffle pyflakes except TypeError: raise ValueError(f"the 'polymake' backend for polyhedron cannot be used with {base_field}") return Polyhedra_polymake(base_field, ambient_dim, backend) From 6dd4f075e8a81a28292d5badbbeab2024b0c4e26 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 14:24:23 -0700 Subject: [PATCH 299/742] src/sage/geometry/polyhedron/base.py: Remove unused import --- src/sage/geometry/polyhedron/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 5582bd190d1..576e073a825 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -51,7 +51,6 @@ from sage.misc.cachefunc import cached_method -import sage.rings.abc from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.matrix.constructor import matrix From 1ede2147fc76bfb2ce9cba350f5cc579d352922a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 14:28:53 -0700 Subject: [PATCH 300/742] src/sage/geometry/polyhedron/backend_normaliz.py: Add missing imports --- src/sage/geometry/polyhedron/backend_normaliz.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 4b5902da342..f38498aa597 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -2337,8 +2337,9 @@ class functions. ((t^4 + 3*t^3 + 8*t^2 + 3*t + 1)/(t + 1), (3*t^3 + 2*t^2 + 3*t)/(t + 1)) """ from sage.groups.conjugacy_classes import ConjugacyClassGAP - from sage.rings.all import CyclotomicField, QQbar - from sage.matrix.all import MatrixSpace + from sage.rings.number_field.number_field import CyclotomicField + from sage.rings.qqbar import QQbar + from sage.matrix.matrix_space import MatrixSpace from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.matrix.special import identity_matrix # Setting the group @@ -2476,6 +2477,8 @@ def _Hstar_as_rat_fct(self, initial_Hstar): [ 1 1 -1 -1 1] [ 2 0 0 0 -2] """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + from sage.rings.qqbar import QQbar chi_vars = ','.join('chi_{}'.format(i) for i in range(len(initial_Hstar))) Chi_ring = PolynomialRing(QQbar, chi_vars) virtual_ring = PolynomialRing(Chi_ring, initial_Hstar.base_ring().gens()) From 341475cb0bf03648c3de3d55173ba09f33cedd59 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 14:31:30 -0700 Subject: [PATCH 301/742] src/sage/geometry/polyhedron/base_ZZ.py: Replace .all import --- src/sage/geometry/polyhedron/base_ZZ.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 07c7bbd6a4c..4255f0232df 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -17,7 +17,7 @@ from sage.misc.cachefunc import cached_method from sage.modules.free_module_element import vector from .base_QQ import Polyhedron_QQ -from sage.arith.all import gcd +from sage.arith.misc import gcd ######################################################################### From fb1ce4270e9d9aa1511192d6097aaa7692ab8883 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 14:59:46 -0700 Subject: [PATCH 302/742] src/sage/tensor/modules/ext_pow_free_module.py: No need to override basis() any more --- src/sage/tensor/modules/ext_pow_free_module.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/sage/tensor/modules/ext_pow_free_module.py b/src/sage/tensor/modules/ext_pow_free_module.py index 4fe480049df..82c64faea8d 100644 --- a/src/sage/tensor/modules/ext_pow_free_module.py +++ b/src/sage/tensor/modules/ext_pow_free_module.py @@ -421,11 +421,6 @@ def degree(self): """ return self._degree - def basis(self, *args, **kwds): - # We override it so that _test_basis is disabled. - # See https://trac.sagemath.org/ticket/30229#comment:6 for a better solution - raise NotImplementedError - #*********************************************************************** @@ -893,8 +888,3 @@ def degree(self): """ return self._degree - - def basis(self, *args, **kwds): - # We override it so that _test_basis is disabled. - # See https://trac.sagemath.org/ticket/30229#comment:6 for a better solution - raise NotImplementedError From 30d4eec4cdd67c9ecd037b3edc0f9c5bcbad18d6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 15:22:56 -0700 Subject: [PATCH 303/742] TensorFreeModule.basis: Pass all args --- src/sage/tensor/modules/tensor_free_module.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index ac874919901..e27f4fa6f64 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -744,7 +744,9 @@ def basis(self, symbol, latex_symbol=None, from_family=None, e_1⊗e_2 + e_2⊗e_1 e_2⊗e_2 """ - return TensorFreeSubmoduleBasis_comp(self, symbol) + return TensorFreeSubmoduleBasis_comp(self, symbol=symbol, latex_symbol=latex_symbol, + indices=indices, latex_indices=latex_indices, + symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) @cached_method def _basis_comp(self): From d1376fda20910920f7333303f1466969a0d165dd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 16:01:05 -0700 Subject: [PATCH 304/742] TensorFreeModule.basis: Add documentation --- src/sage/tensor/modules/tensor_free_module.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index e27f4fa6f64..21af77745d1 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -715,6 +715,17 @@ def basis(self, symbol, latex_symbol=None, from_family=None, r""" Return the standard basis of ``self`` corresponding to a basis of the base module. + INPUT: + + - ``symbol``, ``indices`` -- passed to he base module's method + :meth:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule.basis` + to select a basis of the :meth:`base_module` of ``self``, + or to create it. + + - other parameters -- passed to + :meth:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule.basis`; when + the basis does not exist yet, it will be created using these parameters. + EXAMPLES:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') From 2bcfc2103e48f153ef156147a613d2074e5fbf53 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 16:52:11 -0700 Subject: [PATCH 305/742] src/sage/tensor/modules: Use keyword order: category, ambient --- src/sage/tensor/modules/tensor_free_submodule.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index f7ee2487c67..3a297eabae2 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -58,7 +58,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): """ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, - sym=None, antisym=None, *, ambient=None, category=None): + sym=None, antisym=None, *, category=None, ambient=None): self._fmodule = fmodule self._tensor_type = tuple(tensor_type) if ambient is None: @@ -73,7 +73,7 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, latex_name=latex_name, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter, - ambient=ambient, category=category) + category=category, ambient=ambient) @cached_method def _basis_comp(self): From 6e9bec511d2b00fa1a550dd460831ae90dea9d57 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 16:58:37 -0700 Subject: [PATCH 306/742] src/sage/tensor/modules/finite_rank_free_module.py: Move ambient_module, is_submodule to FiniteRankFreeModule_abstract --- .../tensor/modules/finite_rank_free_module.py | 72 +++++++++---------- .../tensor/modules/tensor_free_submodule.py | 10 ++- 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index c04251e0ed2..4390e687377 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -693,6 +693,42 @@ def zero(self): resu.set_immutable() return resu + def ambient_module(self): # compatible with sage.modules.free_module.FreeModule_generic + """ + Return the ambient module associated to this module. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: M.ambient_module() is M + True + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: T60M = M.tensor_module(6, 0) + sage: Sym0123x45M.ambient_module() is T60M + True + """ + return self._ambient_module + + ambient = ambient_module # compatible with sage.modules.with_basis.subquotient.SubmoduleWithBasis + + def is_submodule(self, other): + """ + Return ``True`` if ``self`` is a submodule of ``other``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: N = FiniteRankFreeModule(ZZ, 4, name='M') + sage: M.is_submodule(M) + True + sage: M.is_submodule(N) + False + """ + return self == other or self.ambient_module() == other + class FiniteRankFreeModule(FiniteRankFreeModule_abstract): r""" @@ -2941,39 +2977,3 @@ def identity_map(self, name='Id', latex_name=None): latex_name = name self._identity_map.set_name(name=name, latex_name=latex_name) return self._identity_map - - def ambient_module(self): # compatible with sage.modules.free_module.FreeModule_generic - """ - Return the ambient module associated to this module. - - EXAMPLES:: - - sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: M.ambient_module() is M - True - - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp - sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) - sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M.ambient_module() is T60M - True - """ - return self._ambient_module - - ambient = ambient_module # compatible with sage.modules.with_basis.subquotient.SubmoduleWithBasis - - def is_submodule(self, other): - """ - Return ``True`` if ``self`` is a submodule of ``other``. - - EXAMPLES:: - - sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: N = FiniteRankFreeModule(ZZ, 4, name='M') - sage: M.is_submodule(M) - True - sage: M.is_submodule(N) - False - """ - return self == other or self.ambient_module() == other diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 3a297eabae2..814284a41de 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -15,7 +15,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.sets.disjoint_set import DisjointSet from .tensor_free_module import TensorFreeModule -from .finite_rank_free_module import FiniteRankFreeModule +from .finite_rank_free_module import FiniteRankFreeModule_abstract class TensorFreeSubmodule_comp(TensorFreeModule): r""" @@ -69,11 +69,9 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, rank = len(list(self.irange())) category = fmodule.category().TensorProducts().FiniteDimensional().Subobjects().or_subcategory(category) # Skip TensorFreeModule.__init__ - FiniteRankFreeModule.__init__(self, fmodule._ring, rank, name=name, - latex_name=latex_name, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter, - category=category, ambient=ambient) + FiniteRankFreeModule_abstract.__init__(self, fmodule._ring, rank, name=name, + latex_name=latex_name, + category=category, ambient=ambient) @cached_method def _basis_comp(self): From fd5ba8cf1dbcd80fd3d364f042bb1eb44aa674fe Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 17:07:21 -0700 Subject: [PATCH 307/742] src/sage/tensor/modules/tensor_free_module.py: No more need for TensorFreeModule.irange --- src/sage/tensor/modules/tensor_free_module.py | 6 ------ src/sage/tensor/modules/tensor_free_submodule.py | 3 ++- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 21af77745d1..11147a685ec 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -765,9 +765,3 @@ def _basis_comp(self): frame = tuple(self.base_module().irange()) tensor = self.ambient()() return tensor._new_comp(frame) - - def irange(self): - r""" - Index generator, labelling the elements of a basis of ``self``. - """ - yield from self._basis_comp().non_redundant_index_generator() diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 814284a41de..5c778c6ac0a 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -66,7 +66,8 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, self._ambient_module = ambient self._sym = sym self._antisym = antisym - rank = len(list(self.irange())) + rank = len(list(self._basis_comp().non_redundant_index_generator())) + # TODO: Good defaults for name, latex_name category = fmodule.category().TensorProducts().FiniteDimensional().Subobjects().or_subcategory(category) # Skip TensorFreeModule.__init__ FiniteRankFreeModule_abstract.__init__(self, fmodule._ring, rank, name=name, From a4d65bc519d8c5172a8af73387ba1307a7a10b26 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 17:34:33 -0700 Subject: [PATCH 308/742] FiniteRankFreeModule_abstract.isomorphism_with_fixed_basis: Move here from FiniteRankFreeModule, rewrite using Family --- .../tensor/modules/finite_rank_free_module.py | 241 +++++++++--------- 1 file changed, 124 insertions(+), 117 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 4390e687377..c2e90307e3d 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -538,6 +538,7 @@ class :class:`~sage.modules.free_module.FreeModule_generic` from sage.categories.rings import Rings from sage.misc.cachefunc import cached_method from sage.rings.integer import Integer +from sage.sets.family import Family, TrivialFamily from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement @@ -729,6 +730,129 @@ def is_submodule(self, other): """ return self == other or self.ambient_module() == other + def isomorphism_with_fixed_basis(self, basis=None, codomain=None): + r""" + Construct the canonical isomorphism from the free module ``self`` + to a free module in which ``basis`` of ``self`` is mapped to the + distinguished basis of ``codomain``. + + INPUT: + + - ``basis`` -- (default: ``None``) the basis of ``self`` which + should be mapped to the distinguished basis on ``codomain``; + if ``None``, the default basis is assumed. + - ``codomain`` -- (default: ``None``) the codomain of the + isomorphism represented by a free module within the category + :class:`~sage.categories.modules_with_basis.ModulesWithBasis` with + the same rank and base ring as ``self``; if ``None`` a free module + represented by + :class:`~sage.combinat.free_module.CombinatorialFreeModule` is + constructed + + OUTPUT: + + - a module morphism represented by + :class:`~sage.modules.with_basis.morphism.ModuleMorphismFromFunction` + + EXAMPLES:: + + sage: V = FiniteRankFreeModule(QQ, 3, start_index=1); V + 3-dimensional vector space over the Rational Field + sage: basis = e = V.basis("e"); basis + Basis (e_1,e_2,e_3) on the 3-dimensional vector space over the + Rational Field + sage: phi_e = V.isomorphism_with_fixed_basis(basis); phi_e + Generic morphism: + From: 3-dimensional vector space over the Rational Field + To: Free module generated by {1, 2, 3} over Rational Field + sage: phi_e.codomain().category() + Category of finite dimensional vector spaces with basis over + Rational Field + sage: phi_e(e[1] + 2 * e[2]) + e[1] + 2*e[2] + + sage: abc = V.basis(['a', 'b', 'c'], symbol_dual=['d', 'e', 'f']); abc + Basis (a,b,c) on the 3-dimensional vector space over the Rational Field + sage: phi_abc = V.isomorphism_with_fixed_basis(abc); phi_abc + Generic morphism: + From: 3-dimensional vector space over the Rational Field + To: Free module generated by {1, 2, 3} over Rational Field + sage: phi_abc(abc[1] + 2 * abc[2]) + B[1] + 2*B[2] + + Providing a codomain:: + + sage: W = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) + sage: phi_eW = V.isomorphism_with_fixed_basis(basis, codomain=W); phi_eW + Generic morphism: + From: 3-dimensional vector space over the Rational Field + To: Free module generated by {'a', 'b', 'c'} over Rational Field + sage: phi_eW(e[1] + 2 * e[2]) + B['a'] + 2*B['b'] + + TESTS:: + + sage: V = FiniteRankFreeModule(QQ, 3); V + 3-dimensional vector space over the Rational Field + sage: e = V.basis("e") + sage: V.isomorphism_with_fixed_basis(e, codomain=QQ^42) + Traceback (most recent call last): + ... + ValueError: domain and codomain must have the same rank + sage: V.isomorphism_with_fixed_basis(e, codomain=RR^3) + Traceback (most recent call last): + ... + ValueError: domain and codomain must have the same base ring + """ + base_ring = self.base_ring() + if basis is None: + basis = self.default_basis() + if codomain is None: + from sage.combinat.free_module import CombinatorialFreeModule + if isinstance(basis._symbol, str): + prefix = basis._symbol + else: + prefix = None + codomain = CombinatorialFreeModule(base_ring, basis.keys(), + prefix=prefix) + else: + if codomain.rank() != self.rank(): + raise ValueError("domain and codomain must have the same rank") + if codomain.base_ring() != base_ring: + raise ValueError("domain and codomain must have the same " + "base ring") + + codomain_basis = Family(codomain.basis()) + if isinstance(codomain_basis, TrivialFamily): + # assume that codomain basis keys are to be ignored + key_pairs = enumerate(basis_keys()) + else: + # assume that the keys of the codomain should be used + key_pairs = zip(codomain_basis.keys(), basis.keys()) + + def _isomorphism(x): + r""" + Concrete isomorphism from ``self`` to ``codomain``. + """ + return codomain.sum(x[basis, domain_key] * codomain_basis[codomain_key] + for codomain_key, domain_key in key_pairs) + + return self.module_morphism(function=_isomorphism, codomain=codomain) + + def _test_isomorphism_with_fixed_basis(self, **options): + r""" + Test that the method ``isomorphism_with_fixed_basis`` works correctly. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: M._test_isomorphism_with_fixed_basis() + """ + tester = self._tester(**options) + basis = self.basis('test') + morphism = self.isomorphism_with_fixed_basis(basis) + tester.assertEqual(morphism.codomain().rank(), self.rank()) + class FiniteRankFreeModule(FiniteRankFreeModule_abstract): r""" @@ -2713,123 +2837,6 @@ def hom(self, codomain, matrix_rep, bases=None, name=None, return homset(matrix_rep, bases=bases, name=name, latex_name=latex_name) - def isomorphism_with_fixed_basis(self, basis=None, codomain=None): - r""" - Construct the canonical isomorphism from the free module ``self`` - to a free module in which ``basis`` of ``self`` is mapped to the - distinguished basis of ``codomain``. - - INPUT: - - - ``basis`` -- (default: ``None``) the basis of ``self`` which - should be mapped to the distinguished basis on ``codomain``; - if ``None``, the default basis is assumed. - - ``codomain`` -- (default: ``None``) the codomain of the - isomorphism represented by a free module within the category - :class:`~sage.categories.modules_with_basis.ModulesWithBasis` with - the same rank and base ring as ``self``; if ``None`` a free module - represented by - :class:`~sage.combinat.free_module.CombinatorialFreeModule` is - constructed - - OUTPUT: - - - a module morphism represented by - :class:`~sage.modules.with_basis.morphism.ModuleMorphismFromFunction` - - EXAMPLES:: - - sage: V = FiniteRankFreeModule(QQ, 3, start_index=1); V - 3-dimensional vector space over the Rational Field - sage: basis = e = V.basis("e"); basis - Basis (e_1,e_2,e_3) on the 3-dimensional vector space over the - Rational Field - sage: phi_e = V.isomorphism_with_fixed_basis(basis); phi_e - Generic morphism: - From: 3-dimensional vector space over the Rational Field - To: Free module generated by {1, 2, 3} over Rational Field - sage: phi_e.codomain().category() - Category of finite dimensional vector spaces with basis over - Rational Field - sage: phi_e(e[1] + 2 * e[2]) - e[1] + 2*e[2] - - sage: abc = V.basis(['a', 'b', 'c'], symbol_dual=['d', 'e', 'f']); abc - Basis (a,b,c) on the 3-dimensional vector space over the Rational Field - sage: phi_abc = V.isomorphism_with_fixed_basis(abc); phi_abc - Generic morphism: - From: 3-dimensional vector space over the Rational Field - To: Free module generated by {1, 2, 3} over Rational Field - sage: phi_abc(abc[1] + 2 * abc[2]) - B[1] + 2*B[2] - - Providing a codomain:: - - sage: W = CombinatorialFreeModule(QQ, ['a', 'b', 'c']) - sage: phi_eW = V.isomorphism_with_fixed_basis(basis, codomain=W); phi_eW - Generic morphism: - From: 3-dimensional vector space over the Rational Field - To: Free module generated by {'a', 'b', 'c'} over Rational Field - sage: phi_eW(e[1] + 2 * e[2]) - B['a'] + 2*B['b'] - - TESTS:: - - sage: V = FiniteRankFreeModule(QQ, 3); V - 3-dimensional vector space over the Rational Field - sage: e = V.basis("e") - sage: V.isomorphism_with_fixed_basis(e, codomain=QQ^42) - Traceback (most recent call last): - ... - ValueError: domain and codomain must have the same rank - sage: V.isomorphism_with_fixed_basis(e, codomain=RR^3) - Traceback (most recent call last): - ... - ValueError: domain and codomain must have the same base ring - """ - base_ring = self.base_ring() - if basis is None: - basis = self.default_basis() - if codomain is None: - from sage.combinat.free_module import CombinatorialFreeModule - if isinstance(basis._symbol, str): - prefix = basis._symbol - else: - prefix = None - codomain = CombinatorialFreeModule(base_ring, list(self.irange()), - prefix=prefix) - else: - if codomain.rank() != self.rank(): - raise ValueError("domain and codomain must have the same rank") - if codomain.base_ring() != base_ring: - raise ValueError("domain and codomain must have the same " - "base ring") - - codomain_basis = list(codomain.basis()) - - def _isomorphism(x): - r""" - Concrete isomorphism from ``self`` to ``codomain``. - """ - return codomain.sum(x[basis, i] * codomain_basis[i - self._sindex] - for i in self.irange()) - - return self.module_morphism(function=_isomorphism, codomain=codomain) - - def _test_isomorphism_with_fixed_basis(self, **options): - r""" - Test that the method ``isomorphism_with_fixed_basis`` works correctly. - - EXAMPLES:: - - sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: M._test_isomorphism_with_fixed_basis() - """ - tester = self._tester(**options) - basis = self.basis('test') - morphism = self.isomorphism_with_fixed_basis(basis) - tester.assertEqual(morphism.codomain().rank(), self.rank()) - def endomorphism(self, matrix_rep, basis=None, name=None, latex_name=None): r""" Construct an endomorphism of the free module ``self``. From 280424ec1a8d625bdbe1b827d8c0382a1f794456 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 17:40:22 -0700 Subject: [PATCH 309/742] FiniteRankFreeModule_abstract.isomorphism_with_fixed_basis: Add example with codomain from sage.modules --- src/sage/tensor/modules/finite_rank_free_module.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index c2e90307e3d..f31d38117df 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -790,6 +790,16 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): sage: phi_eW(e[1] + 2 * e[2]) B['a'] + 2*B['b'] + Providing a :class:`~sage.modules.free_module.Module_free_ambient` as the codomain:: + + sage: W = QQ^3 + sage: phi_eW = V.isomorphism_with_fixed_basis(basis, codomain=W); phi_eW + Generic morphism: + From: 3-dimensional vector space over the Rational Field + To: Vector space of dimension 3 over Rational Field + sage: phi_eW(e[1] + 2 * e[2]) + (1, 2, 0) + TESTS:: sage: V = FiniteRankFreeModule(QQ, 3); V @@ -825,7 +835,7 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): codomain_basis = Family(codomain.basis()) if isinstance(codomain_basis, TrivialFamily): # assume that codomain basis keys are to be ignored - key_pairs = enumerate(basis_keys()) + key_pairs = enumerate(basis.keys()) else: # assume that the keys of the codomain should be used key_pairs = zip(codomain_basis.keys(), basis.keys()) From e452316628bf0982b63e1f6613f00bae313bbc52 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 18:24:45 -0700 Subject: [PATCH 310/742] FreeModuleTensor: Handle TensorFreeSubmoduleBasis_comp --- src/sage/tensor/modules/free_module_tensor.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index bbcc1ecb2e0..845c9185a26 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -1101,6 +1101,12 @@ class :class:`~sage.tensor.modules.comp.Components` fmodule = self._fmodule if basis is None: basis = fmodule._def_basis + try: + # Standard bases of tensor modules are keyed to the base module's basis, + # not to the TensorFreeSubmoduleBasis_comp instance. + basis = basis._base_module_basis + except AttributeError: + pass if basis not in self._components: # The components must be computed from # those in the basis from_basis From b0b8d19851c634da9051cf91f3d05386dab71a67 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 18:25:16 -0700 Subject: [PATCH 311/742] FiniteRankFreeModule_abstract.isomorphism_with_fixed_basis: Handle codomain=MatrixSpace --- .../tensor/modules/finite_rank_free_module.py | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index f31d38117df..69b8b2c0874 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -800,6 +800,24 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): sage: phi_eW(e[1] + 2 * e[2]) (1, 2, 0) + Sending (1,1)-tensors to matrices:: + + sage: T11 = V.tensor_module(1, 1); T11 + Free module of type-(1,1) tensors on the 3-dimensional vector space over the Rational Field + sage: e_T11 = T11.basis("e"); e_T11 + + sage: W = MatrixSpace(QQ, 3) + sage: phi_e_T11 = T11.isomorphism_with_fixed_basis(e_T11, codomain=W); phi_e_T11 + Generic morphism: + From: Free module of type-(1,1) tensors on the 3-dimensional vector space over the Rational Field + To: Full MatrixSpace of 3 by 3 dense matrices over Rational Field + sage: t = T11.an_element(); t.display() + 1/2 e_1⊗e^1 + sage: phi_e_T11(t) + [1/2 0 0] + [ 0 0 0] + [ 0 0 0] + TESTS:: sage: V = FiniteRankFreeModule(QQ, 3); V @@ -826,7 +844,12 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): codomain = CombinatorialFreeModule(base_ring, basis.keys(), prefix=prefix) else: - if codomain.rank() != self.rank(): + try: + codomain_rank = codomain.rank() + except AttributeError: + # https://trac.sagemath.org/ticket/34445: MatrixSpace does not have rank + codomain_rank = codomain.dimension() + if codomain_rank != self.rank(): raise ValueError("domain and codomain must have the same rank") if codomain.base_ring() != base_ring: raise ValueError("domain and codomain must have the same " From 18aa856005ef29aa3508b3ec816c0958fbaa03db Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 18:33:45 -0700 Subject: [PATCH 312/742] FiniteRankFreeModule_abstract.isomorphism_with_fixed_basis: Add example with symmetric binary forms --- .../tensor/modules/finite_rank_free_module.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 69b8b2c0874..f7e606c5255 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -818,6 +818,24 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): [ 0 0 0] [ 0 0 0] + Sending symmetric bilinear forms to matrices:: + + sage: T02 = V.tensor_module(0, 2); T02 + Free module of type-(0,2) tensors on the 3-dimensional vector space over the Rational Field + sage: e_T02 = T02.basis("e"); e_T02 + + sage: W = MatrixSpace(QQ, 3) + sage: phi_e_T02 = T02.isomorphism_with_fixed_basis(e_T02, codomain=W); phi_e_T02 + Generic morphism: + From: Free module of type-(0,2) tensors on the 3-dimensional vector space over the Rational Field + To: Full MatrixSpace of 3 by 3 dense matrices over Rational Field + sage: t = T02.an_element(); t.display() + 1/2 e^1⊗e^1 + sage: phi_e_T02(t) + [1/2 0 0] + [ 0 0 0] + [ 0 0 0] + TESTS:: sage: V = FiniteRankFreeModule(QQ, 3); V From dafd47d72cd15666e3b325a5b93f39f2d903d53f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 18:47:18 -0700 Subject: [PATCH 313/742] FiniteRankFreeModule_abstract.isomorphism_with_fixed_basis: Better example with symmetric binary forms --- .../tensor/modules/finite_rank_free_module.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index f7e606c5255..32ad6f2aaa1 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -818,7 +818,8 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): [ 0 0 0] [ 0 0 0] - Sending symmetric bilinear forms to matrices:: + Sending symmetric bilinear forms to matrices (note that they are currently elements + of `T^{(0,2)}(M)`, not the symmetric power of `M`):: sage: T02 = V.tensor_module(0, 2); T02 Free module of type-(0,2) tensors on the 3-dimensional vector space over the Rational Field @@ -829,12 +830,17 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): Generic morphism: From: Free module of type-(0,2) tensors on the 3-dimensional vector space over the Rational Field To: Full MatrixSpace of 3 by 3 dense matrices over Rational Field - sage: t = T02.an_element(); t.display() - 1/2 e^1⊗e^1 - sage: phi_e_T02(t) - [1/2 0 0] - [ 0 0 0] - [ 0 0 0] + + sage: a = V.sym_bilinear_form() + sage: a[1,1], a[1,2], a[1,3] = 1, 2, 3 + sage: a[2,2], a[2,3] = 4, 5 + sage: a[3,3] = 6 + sage: a.display() + e^1⊗e^1 + 2 e^1⊗e^2 + 3 e^1⊗e^3 + 2 e^2⊗e^1 + 4 e^2⊗e^2 + 5 e^2⊗e^3 + 3 e^3⊗e^1 + 5 e^3⊗e^2 + 6 e^3⊗e^3 + sage: phi_e_T02(a) + [1 2 3] + [2 4 5] + [3 5 6] TESTS:: From c3547702c8ff842c0059879a35cca2de3c78704a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 19:03:10 -0700 Subject: [PATCH 314/742] FiniteRankFreeModule_abstract.isomorphism_with_fixed_basis: Add example with codomain= tensor square of a CombinatorialFreeModule --- .../tensor/modules/finite_rank_free_module.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 32ad6f2aaa1..d11c07fa405 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -842,6 +842,23 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): [2 4 5] [3 5 6] + Sending tensors to elements of the tensor square of :class:`CombinatorialFreeModule`:: + + sage: T20 = V.tensor_module(2, 0); T20 + Free module of type-(2,0) tensors on the 3-dimensional vector space over the Rational Field + sage: e_T20 = T02.basis("e"); e_T20 + + sage: W = CombinatorialFreeModule(QQ, [1, 2, 3]).tensor_square(); W + Free module generated by {1, 2, 3} over Rational Field # Free module generated by {1, 2, 3} over Rational Field + sage: phi_e_T20 = T20.isomorphism_with_fixed_basis(e_T20, codomain=W); phi_e_T20 + Generic morphism: + From: Free module of type-(2,0) tensors on the 3-dimensional vector space over the Rational Field + To: Free module generated by {1, 2, 3} over Rational Field # Free module generated by {1, 2, 3} over Rational Field + sage: t = T20.an_element(); t.display() + 1/2 e_1⊗e_1 + sage: phi_e_T20(t) + 1/2*B[1] # B[1] + TESTS:: sage: V = FiniteRankFreeModule(QQ, 3); V From 49129ea518c875cc0b793c50c84cf5dd280221e9 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 27 Aug 2022 11:28:46 +0900 Subject: [PATCH 315/742] Allowing an arbitrary skew-symmetric matrix as input to determine the multiplication. --- src/sage/algebras/q_commuting_polynomials.py | 111 ++++++++++++++++--- 1 file changed, 93 insertions(+), 18 deletions(-) diff --git a/src/sage/algebras/q_commuting_polynomials.py b/src/sage/algebras/q_commuting_polynomials.py index c948d4e8b20..b772f04a57e 100644 --- a/src/sage/algebras/q_commuting_polynomials.py +++ b/src/sage/algebras/q_commuting_polynomials.py @@ -19,24 +19,31 @@ from sage.misc.cachefunc import cached_method from sage.sets.family import Family from sage.rings.infinity import infinity +from sage.rings.integer_ring import ZZ from sage.categories.algebras import Algebras from sage.combinat.free_module import CombinatorialFreeModule -from sage.monoids.free_abelian_monoid import FreeAbelianMonoid, FreeAbelianMonoid_class +from sage.monoids.free_abelian_monoid import FreeAbelianMonoid +from sage.matrix.constructor import matrix +from sage.structure.element import Matrix class qCommutingPolynomials(CombinatorialFreeModule): r""" The algebra of `q`-commuting polynomials. - Let `R` be a commutative ring, and fix an element `q \in R`. We say two - distinct variables `x` and `y` `q`-*commute* if they satisfy the relation + Let `R` be a commutative ring, and fix an element `q \in R`. Let + B = (B_{xy})_{x,y \in I}` be a skew-symmetric bilinear form with + index set `I`. Let `R[I]_{q,B}` denote the polynomial ring in the variables + `I` such that we have the `q`-*commuting* relation for `x, y \in I`: .. MATH:: - x y = q \cdot y x. + y x = q^{B_{xy}} \cdot x y. - These form a graded `R`-algebra with a natural basis given by monomials - written in increasing order. These then satisfy a `q`-analog of the - classical binomial coefficient theorem: + This is a graded `R`-algebra with a natural basis given by monomials + written in increasing order with respect to some total order on `I`. + + When `B_{xy} = 1` and `B_{yx} = -1` for all `x < y`, then we have + a `q`-analog of the classical binomial coefficient theorem: .. MATH:: @@ -47,14 +54,38 @@ class qCommutingPolynomials(CombinatorialFreeModule): sage: q = ZZ['q'].fraction_field().gen() sage: R. = algebras.qCommutingPolynomials(q) - We verify the `q`-binomial theorem:: + We verify a case of the `q`-binomial theorem:: sage: f = (x + y)^10 sage: all(f[b] == q_binomial(10, b.list()[0]) for b in f.support()) True + + We now do a computation with a non-standard `B` matrix:: + + sage: B = matrix([[0,1,2],[-1,0,3],[-2,-3,0]]) + sage: B + [ 0 1 2] + [-1 0 3] + [-2 -3 0] + sage: q = ZZ['q'].gen() + sage: R. = algebras.qCommutingPolynomials(q, B) + sage: y * x + q*x*y + sage: z * x + q^2*x*z + sage: z * y + q^3*y*z + + sage: f = (x + z)^10 + sage: all(f[b] == q_binomial(10, b.list()[0], q^2) for b in f.support()) + True + + sage: f = (y + z)^10 + sage: all(f[b] == q_binomial(10, b.list()[1], q^3) for b in f.support()) + True """ @staticmethod - def __classcall_private__(cls, q, n=None, base_ring=None, names=None): + def __classcall_private__(cls, q, n=None, B=None, base_ring=None, names=None): r""" Normalize input to ensure a unique representation. @@ -70,13 +101,34 @@ def __classcall_private__(cls, q, n=None, base_ring=None, names=None): if base_ring is not None: q = base_ring(q) - if isinstance(n, FreeAbelianMonoid_class): - indices = n + if B is None and isinstance(n, Matrix): + n, B = B, n + + if names is None: + raise ValueError("the names of the variables must be given") + from sage.structure.category_object import normalize_names + if n is None: + if isinstance(names, str): + n = names.count(',') + 1 + else: + n = len(names) + names = normalize_names(n, names) + n = len(names) + if B is None: + B = matrix.zero(ZZ, n) + for i in range(n): + for j in range(i+1, n): + B[i,j] = 1 + B[j,i] = -1 + B.set_immutable() else: - indices = FreeAbelianMonoid(n, names) - return super().__classcall__(cls, q, indices) + if not B.is_skew_symmetric(): + raise ValueError("the matrix must be skew symmetric") + B = B.change_ring(ZZ) + B.set_immutable() + return super().__classcall__(cls, q=q, B=B, names=names) - def __init__(self, q, indices): + def __init__(self, q, B, names): r""" Initialize ``self``. @@ -87,7 +139,9 @@ def __init__(self, q, indices): sage: TestSuite(R).run() """ self._q = q + self._B = B base_ring = q.parent() + indices = FreeAbelianMonoid(len(names), names) category = Algebras(base_ring).WithBasis().Graded() CombinatorialFreeModule.__init__(self, base_ring, indices, bracket=False, prefix='', @@ -104,10 +158,13 @@ def _repr_(self): sage: R. = algebras.qCommutingPolynomials(q) sage: R q-commuting polynomial ring in x, y, z over Fraction Field of - Univariate Polynomial Ring in q over Integer Ring + Univariate Polynomial Ring in q over Integer Ring with matrix: + [ 0 1 1] + [-1 0 1] + [-1 -1 0] """ names = ", ".join(self.variable_names()) - return "{}-commuting polynomial ring in {} over {}".format(self._q, names, self.base_ring()) + return "{}-commuting polynomial ring in {} over {} with matrix:\n{}".format(self._q, names, self.base_ring(), self._B) def _latex_(self): r""" @@ -142,7 +199,7 @@ def _term_key(x): return (sum(L), L) def gen(self, i): - """ + r""" Return the ``i``-generator of ``self``. EXAMPLES:: @@ -260,6 +317,24 @@ def product_on_basis(self, x, y): x^3 + (q^2+q+1)*x^2*y + (q^2+q+1)*x*y^2 + y^3 sage: (x + y)^4 x^4 + (q^3+q^2+q+1)*x^3*y + (q^4+q^3+2*q^2+q+1)*x^2*y^2 + (q^3+q^2+q+1)*x*y^3 + y^4 + + With a non-standard `B` matrix:: + + sage: B = matrix([[0,1,2],[-1,0,3],[-2,-3,0]]) + sage: q = ZZ['q'].fraction_field().gen() + sage: R. = algebras.qCommutingPolynomials(q, B=B) + sage: x * y + x*y + sage: y * x^2 + q^2*x^2*y + sage: z^2 * x + q^4*x*z^2 + sage: z^2 * x^3 + q^12*x^3*z^2 + sage: z^2 * y + q^6*y*z^2 + sage: z^2 * y^3 + q^18*y^3*z^2 """ # Special case for multiplying by 1 if x == self.one_basis(): @@ -271,6 +346,6 @@ def product_on_basis(self, x, y): Ly = y.list() # This could be made more efficient - qpow = sum(exp * sum(Ly[:i]) for i,exp in enumerate(Lx)) + qpow = sum(exp * sum(self._B[j,i] * val for j, val in enumerate(Ly[:i])) for i,exp in enumerate(Lx)) return self.term(x * y, self._q ** qpow) From 694e665430527083480ee4fa58c8b6857fc5acfe Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 20:30:13 -0700 Subject: [PATCH 316/742] TensorFreeSubmoduleBasis_comp._repr_: New --- .../modules/tensor_free_submodule_basis.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index 45704e81ac1..856d58554fb 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -45,6 +45,23 @@ def __init__(self, tensor_module, symbol, latex_symbol=None, indices=None, self._base_module_basis = base_module_basis self._comp = tensor_module._basis_comp() + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: T11 = M.tensor_module(1,1) + sage: e_T11 = T11.basis('e') + sage: e_T11 + Standard basis on the + Free module of type-(1,1) tensors on the Rank-3 free module M over the Integer Ring + induced by Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring + """ + return f"Standard basis on the {self._fmodule} induced by {self._base_module_basis}" + def keys(self): """ Return an iterator for the keys (indices) of the family. From 454f0b08a338a0e4dde93cc731654bff6f40269b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 20:34:12 -0700 Subject: [PATCH 317/742] src/sage/tensor/modules/finite_rank_free_module.py: Update doctest output --- src/sage/tensor/modules/finite_rank_free_module.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index d11c07fa405..d4519298210 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -805,7 +805,9 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): sage: T11 = V.tensor_module(1, 1); T11 Free module of type-(1,1) tensors on the 3-dimensional vector space over the Rational Field sage: e_T11 = T11.basis("e"); e_T11 - + Standard basis on the + Free module of type-(1,1) tensors on the 3-dimensional vector space over the Rational Field + induced by Basis (e_1,e_2,e_3) on the 3-dimensional vector space over the Rational Field sage: W = MatrixSpace(QQ, 3) sage: phi_e_T11 = T11.isomorphism_with_fixed_basis(e_T11, codomain=W); phi_e_T11 Generic morphism: @@ -824,7 +826,9 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): sage: T02 = V.tensor_module(0, 2); T02 Free module of type-(0,2) tensors on the 3-dimensional vector space over the Rational Field sage: e_T02 = T02.basis("e"); e_T02 - + Standard basis on the + Free module of type-(0,2) tensors on the 3-dimensional vector space over the Rational Field + induced by Basis (e_1,e_2,e_3) on the 3-dimensional vector space over the Rational Field sage: W = MatrixSpace(QQ, 3) sage: phi_e_T02 = T02.isomorphism_with_fixed_basis(e_T02, codomain=W); phi_e_T02 Generic morphism: @@ -847,7 +851,9 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): sage: T20 = V.tensor_module(2, 0); T20 Free module of type-(2,0) tensors on the 3-dimensional vector space over the Rational Field sage: e_T20 = T02.basis("e"); e_T20 - + Standard basis on the + Free module of type-(0,2) tensors on the 3-dimensional vector space over the Rational Field + induced by Basis (e_1,e_2,e_3) on the 3-dimensional vector space over the Rational Field sage: W = CombinatorialFreeModule(QQ, [1, 2, 3]).tensor_square(); W Free module generated by {1, 2, 3} over Rational Field # Free module generated by {1, 2, 3} over Rational Field sage: phi_e_T20 = T20.isomorphism_with_fixed_basis(e_T20, codomain=W); phi_e_T20 From 50f3eeb101cf6c04d26c781fba8330352e052102 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Tue, 17 May 2022 16:29:08 +0800 Subject: [PATCH 318/742] rename .rational_reconstruct() to .rational_reconstruction() for consistency --- .../rings/polynomial/polynomial_element.pyx | 40 ++++++++++--------- .../polynomial/polynomial_zmod_flint.pxd | 2 +- .../polynomial/polynomial_zmod_flint.pyx | 8 +++- src/sage/rings/power_series_poly.pyx | 4 +- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 59f0b21fe8d..e3a00051f8c 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -126,7 +126,7 @@ from sage.misc.cachefunc import cached_function from sage.categories.map cimport Map from sage.categories.morphism cimport Morphism -from sage.misc.superseded import deprecation_cython as deprecation +from sage.misc.superseded import deprecation_cython as deprecation, deprecated_function_alias from sage.misc.cachefunc import cached_method from sage.rings.number_field.order import is_NumberFieldOrder @@ -8915,7 +8915,7 @@ cdef class Polynomial(CommutativeAlgebraElement): else: raise NotImplementedError("%s does not provide an xgcd implementation for univariate polynomials"%self.base_ring()) - def rational_reconstruct(self, m, n_deg=None, d_deg=None): + def rational_reconstruction(self, m, n_deg=None, d_deg=None): r""" Return a tuple of two polynomials ``(n, d)`` where ``self * d`` is congruent to ``n`` modulo ``m`` and @@ -8940,7 +8940,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: z = PolynomialRing(QQ, 'z').gen() sage: p = -z**16 - z**15 - z**14 + z**13 + z**12 + z**11 - z**5 - z**4 - z**3 + z**2 + z + 1 sage: m = z**21 - sage: n, d = p.rational_reconstruct(m) + sage: n, d = p.rational_reconstruction(m) sage: print((n ,d)) (z^4 + 2*z^3 + 3*z^2 + 2*z + 1, z^10 + z^9 + z^8 + z^7 + z^6 + z^5 + z^4 + z^3 + z^2 + z + 1) sage: print(((p*d - n) % m ).is_zero()) @@ -8951,7 +8951,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: z = PolynomialRing(ZZ, 'z').gen() sage: p = -z**16 - z**15 - z**14 + z**13 + z**12 + z**11 - z**5 - z**4 - z**3 + z**2 + z + 1 sage: m = z**21 - sage: n, d = p.rational_reconstruct(m) + sage: n, d = p.rational_reconstruction(m) sage: print((n ,d)) (z^4 + 2*z^3 + 3*z^2 + 2*z + 1, z^10 + z^9 + z^8 + z^7 + z^6 + z^5 + z^4 + z^3 + z^2 + z + 1) sage: print(((p*d - n) % m ).is_zero()) @@ -8963,12 +8963,12 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: x = P.gen() sage: p = 7*x^5 - 10*x^4 + 16*x^3 - 32*x^2 + 128*x + 256 sage: m = x^5 - sage: n, d = p.rational_reconstruct(m, 3, 2) + sage: n, d = p.rational_reconstruction(m, 3, 2) sage: print((n ,d)) (-32*x^3 + 384*x^2 + 2304*x + 2048, 5*x + 8) sage: print(((p*d - n) % m ).is_zero()) True - sage: n, d = p.rational_reconstruct(m, 4, 0) + sage: n, d = p.rational_reconstruction(m, 4, 0) sage: print((n ,d)) (-10*x^4 + 16*x^3 - 32*x^2 + 128*x + 256, 1) sage: print(((p*d - n) % m ).is_zero()) @@ -8983,7 +8983,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: # p = (1 + t^2*z + z^4) / (1 - t*z) sage: p = (1 + t^2*z + z^4)*(1 - t*z).inverse_mod(z^9) sage: m = z^9 - sage: n, d = p.rational_reconstruct(m) + sage: n, d = p.rational_reconstruction(m) sage: print((n ,d)) (-1/t*z^4 - t*z - 1/t, z - 1/t) sage: print(((p*d - n) % m ).is_zero()) @@ -8992,7 +8992,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: n = -10*t^2*z^4 + (-t^2 + t - 1)*z^3 + (-t - 8)*z^2 + z + 2*t^2 - t sage: d = z^4 + (2*t + 4)*z^3 + (-t + 5)*z^2 + (t^2 + 2)*z + t^2 + 2*t + 1 sage: prec = 9 - sage: nc, dc = Pz((n.subs(z = w)/d.subs(z = w) + O(w^prec)).list()).rational_reconstruct(z^prec) + sage: nc, dc = Pz((n.subs(z = w)/d.subs(z = w) + O(w^prec)).list()).rational_reconstruction(z^prec) sage: print( (nc, dc) == (n, d) ) True @@ -9004,7 +9004,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: # p = (1 + t^2*z + z^4) / (1 - t*z) mod z^9 sage: p = (1 + t^2*z + z^4) * sum((t*z)**i for i in range(9)) sage: m = z^9 - sage: n, d = p.rational_reconstruct(m,) + sage: n, d = p.rational_reconstruction(m,) sage: print((n ,d)) (-z^4 - t^2*z - 1, t*z - 1) sage: print(((p*d - n) % m ).is_zero()) @@ -9015,7 +9015,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: x = PolynomialRing(Qp(5),'x').gen() sage: p = 4*x^5 + 3*x^4 + 2*x^3 + 2*x^2 + 4*x + 2 sage: m = x^6 - sage: n, d = p.rational_reconstruct(m, 3, 2) + sage: n, d = p.rational_reconstruction(m, 3, 2) sage: print(((p*d - n) % m ).is_zero()) True @@ -9026,34 +9026,34 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: x = P.gen() sage: p = P(exp(z).list()) sage: m = x^5 - sage: n, d = p.rational_reconstruct(m, 4, 0) + sage: n, d = p.rational_reconstruction(m, 4, 0) sage: print((n ,d)) (1/24*x^4 + 1/6*x^3 + 1/2*x^2 + x + 1, 1) sage: print(((p*d - n) % m ).is_zero()) True sage: m = x^3 - sage: n, d = p.rational_reconstruct(m, 1, 1) + sage: n, d = p.rational_reconstruction(m, 1, 1) sage: print((n ,d)) (-x - 2, x - 2) sage: print(((p*d - n) % m ).is_zero()) True sage: p = P(log(1-z).list()) sage: m = x^9 - sage: n, d = p.rational_reconstruct(m, 4, 4) + sage: n, d = p.rational_reconstruction(m, 4, 4) sage: print((n ,d)) (25/6*x^4 - 130/3*x^3 + 105*x^2 - 70*x, x^4 - 20*x^3 + 90*x^2 - 140*x + 70) sage: print(((p*d - n) % m ).is_zero()) True sage: p = P(sqrt(1+z).list()) sage: m = x^6 - sage: n, d = p.rational_reconstruct(m, 3, 2) + sage: n, d = p.rational_reconstruction(m, 3, 2) sage: print((n ,d)) (1/6*x^3 + 3*x^2 + 8*x + 16/3, x^2 + 16/3*x + 16/3) sage: print(((p*d - n) % m ).is_zero()) True sage: p = P(exp(2*z).list()) sage: m = x^7 - sage: n, d = p.rational_reconstruct(m, 3, 3) + sage: n, d = p.rational_reconstruction(m, 3, 3) sage: print((n ,d)) (-x^3 - 6*x^2 - 15*x - 15, x^3 - 6*x^2 + 15*x - 15) sage: print(((p*d - n) % m ).is_zero()) @@ -9066,26 +9066,26 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: x = P.gen() sage: p = P(exp(2*z).list()) sage: m = x^7 - sage: n, d = p.rational_reconstruct( m, 3, 3) + sage: n, d = p.rational_reconstruction(m, 3, 3) sage: print((n ,d)) # absolute tolerance 1e-10 (-x^3 - 6.0*x^2 - 15.0*x - 15.0, x^3 - 6.0*x^2 + 15.0*x - 15.0) .. SEEALSO:: * :mod:`sage.matrix.berlekamp_massey`, - * :meth:`sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint.rational_reconstruct` + * :meth:`sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint.rational_reconstruction` """ P = self.parent() if not P.base_ring().is_field(): if not P.base_ring().is_integral_domain(): - raise NotImplementedError("rational_reconstruct() " + raise NotImplementedError("rational_reconstruction() " "is only implemented when the base ring is a field " "or a integral domain, " "a workaround is to do a multimodular approach") Pf = P.base_extend(P.base_ring().fraction_field()) sF = Pf(self) mF = Pf(m) - n, d = sF.rational_reconstruct( mF, n_deg, d_deg) + n, d = sF.rational_reconstruction(mF, n_deg, d_deg) l = lcm([n.denominator(), d.denominator()]) n *= l d *= l @@ -9125,6 +9125,8 @@ cdef class Polynomial(CommutativeAlgebraElement): t1 = t1 / c return t1, t0 + rational_reconstruct = deprecated_function_alias(12696, rational_reconstruction) + def variables(self): """ Return the tuple of variables occurring in this polynomial. diff --git a/src/sage/rings/polynomial/polynomial_zmod_flint.pxd b/src/sage/rings/polynomial/polynomial_zmod_flint.pxd index d8cef40282f..c6a92f3df6c 100644 --- a/src/sage/rings/polynomial/polynomial_zmod_flint.pxd +++ b/src/sage/rings/polynomial/polynomial_zmod_flint.pxd @@ -14,4 +14,4 @@ cdef class Polynomial_zmod_flint(Polynomial_template): cdef int _set_list(self, x) except -1 cdef int _set_fmpz_poly(self, fmpz_poly_t) except -1 cpdef Polynomial _mul_trunc_opposite(self, Polynomial_zmod_flint other, length) - cpdef rational_reconstruct(self, m, n_deg=?, d_deg=?) + cpdef rational_reconstruction(self, m, n_deg=?, d_deg=?) diff --git a/src/sage/rings/polynomial/polynomial_zmod_flint.pyx b/src/sage/rings/polynomial/polynomial_zmod_flint.pyx index 748d8ce37c7..f974916fac8 100644 --- a/src/sage/rings/polynomial/polynomial_zmod_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_zmod_flint.pyx @@ -45,6 +45,8 @@ from sage.structure.element cimport parent from sage.structure.element import coerce_binop from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint +from sage.misc.superseded import deprecated_function_alias + # We need to define this stuff before including the templating stuff # to make sure the function get_cparent is found since it is used in # 'polynomial_template.pxi'. @@ -585,7 +587,7 @@ cdef class Polynomial_zmod_flint(Polynomial_template): nmod_poly_pow_trunc(&ans.x, &self.x, n, prec) return ans - cpdef rational_reconstruct(self, m, n_deg=0, d_deg=0): + cpdef rational_reconstruction(self, m, n_deg=0, d_deg=0): """ Construct a rational function n/d such that `p*d` is equivalent to `n` modulo `m` where `p` is this polynomial. @@ -594,7 +596,7 @@ cdef class Polynomial_zmod_flint(Polynomial_template): sage: P. = GF(5)[] sage: p = 4*x^5 + 3*x^4 + 2*x^3 + 2*x^2 + 4*x + 2 - sage: n, d = p.rational_reconstruct(x^9, 4, 4); n, d + sage: n, d = p.rational_reconstruction(x^9, 4, 4); n, d (3*x^4 + 2*x^3 + x^2 + 2*x, x^4 + 3*x^3 + x^2 + x) sage: (p*d % x^9) == n True @@ -638,6 +640,8 @@ cdef class Polynomial_zmod_flint(Polynomial_template): return t1, t0 + rational_reconstruct = deprecated_function_alias(12696, rational_reconstruction) + @cached_method def is_irreducible(self): """ diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index 198c8e99438..58d509e8454 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -1120,7 +1120,7 @@ cdef class PowerSeries_poly(PowerSeries): .. SEEALSO:: * :mod:`sage.matrix.berlekamp_massey`, - * :meth:`sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint.rational_reconstruct` + * :meth:`sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint.rational_reconstruction` EXAMPLES:: @@ -1173,7 +1173,7 @@ cdef class PowerSeries_poly(PowerSeries): polyring = self.parent()._poly_ring() z = polyring.gen() c = self.polynomial() - u, v = c.rational_reconstruct(z**(n + m + 1), m, n) + u, v = c.rational_reconstruction(z**(n + m + 1), m, n) return u / v def _symbolic_(self, ring): From b4f413ddbf7ea3e4beff767e05a88cb63d0df0a7 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 27 Aug 2022 14:56:50 +0900 Subject: [PATCH 319/742] Replacing the indedxing set of the Yangian with cartesian_product. --- src/sage/algebras/yangian.py | 172 ++++------------------------------- 1 file changed, 18 insertions(+), 154 deletions(-) diff --git a/src/sage/algebras/yangian.py b/src/sage/algebras/yangian.py index b63648bbb95..bfd69fbaf27 100644 --- a/src/sage/algebras/yangian.py +++ b/src/sage/algebras/yangian.py @@ -22,6 +22,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis +from sage.categories.cartesian_product import cartesian_product from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -34,155 +35,6 @@ import itertools -class GeneratorIndexingSet(UniqueRepresentation): - """ - Helper class for the indexing set of the generators. - """ - def __init__(self, index_set, level=None): - """ - Initialize ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: I = GeneratorIndexingSet((1,2)) - """ - self._index_set = index_set - self._level = level - - def __repr__(self): - """ - Return a string representation of ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: GeneratorIndexingSet((1,2)) - Cartesian product of Positive integers, (1, 2), (1, 2) - sage: GeneratorIndexingSet((1,2), 4) - Cartesian product of (1, 2, 3, 4), (1, 2), (1, 2) - """ - if self._level is None: - L = PositiveIntegers() - else: - L = tuple(range(1, self._level + 1)) - return "Cartesian product of {L}, {I}, {I}".format(L=L, I=self._index_set) - - def an_element(self): - """ - Initialize ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: I = GeneratorIndexingSet((1,2)) - sage: I.an_element() - (3, 1, 1) - sage: I = GeneratorIndexingSet((1,2), 5) - sage: I.an_element() - (3, 1, 1) - sage: I = GeneratorIndexingSet((1,2), 1) - sage: I.an_element() - (1, 1, 1) - """ - if self._level is not None and self._level < 3: - return (1, self._index_set[0], self._index_set[0]) - return (3, self._index_set[0], self._index_set[0]) - - def cardinality(self): - """ - Return the cardinality of ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: I = GeneratorIndexingSet((1,2)) - sage: I.cardinality() - +Infinity - sage: I = GeneratorIndexingSet((1,2), level=3) - sage: I.cardinality() == 3 * 2 * 2 - True - """ - if self._level is not None: - return self._level * len(self._index_set)**2 - return infinity - - __len__ = cardinality - - def __call__(self, x): - """ - Call ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: I = GeneratorIndexingSet((1,2)) - sage: I([1, 2]) - (1, 2) - """ - return tuple(x) - - def __contains__(self, x): - """ - Check containment of ``x`` in ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: I = GeneratorIndexingSet((1,2)) - sage: (4, 1, 2) in I - True - sage: [4, 2, 1] in I - True - sage: (-1, 1, 1) in I - False - sage: (1, 3, 1) in I - False - - :: - - sage: I3 = GeneratorIndexingSet((1,2), 3) - sage: (1, 1, 2) in I3 - True - sage: (3, 1, 1) in I3 - True - sage: (4, 1, 1) in I3 - False - """ - return (isinstance(x, (tuple, list)) and len(x) == 3 - and x[0] in ZZ and x[0] > 0 - and (self._level is None or x[0] <= self._level) - and x[1] in self._index_set - and x[2] in self._index_set) - - def __iter__(self): - """ - Iterate over ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: I = GeneratorIndexingSet((1,2)) - sage: it = iter(I) - sage: [next(it) for dummy in range(5)] - [(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), (2, 1, 1)] - - sage: I = GeneratorIndexingSet((1,2), 3) - sage: list(I) - [(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), - (2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2), - (3, 1, 1), (3, 1, 2), (3, 2, 1), (3, 2, 2)] - """ - I = self._index_set - if self._level is not None: - for x in itertools.product(range(1, self._level + 1), I, I): - yield x - return - for i in PositiveIntegers(): - for x in itertools.product(I, I): - yield (i, x[0], x[1]) - - class Yangian(CombinatorialFreeModule): r""" The Yangian `Y(\mathfrak{gl}_n)`. @@ -392,7 +244,7 @@ def __init__(self, base_ring, n, variable_name, filtration): category = category.Connected() self._index_set = tuple(range(1, n + 1)) # The keys for the basis are tuples (l, i, j) - indices = GeneratorIndexingSet(self._index_set) + indices = cartesian_product([PositiveIntegers(), self._index_set, self._index_set]) # We note that the generators are non-commutative, but we always sort # them, so they are, in effect, indexed by the free abelian monoid basis_keys = IndexedFreeAbelianMonoid(indices, bracket=False, @@ -501,7 +353,7 @@ def _element_constructor_(self, x): True sage: Y6 = Yangian(QQ, 4, level=6, filtration='natural') sage: Y(Y6.an_element()) - t(1)[1,1]*t(1)[1,2]^2*t(1)[1,3]^3*t(3)[1,1] + t(1)[1,1]^2*t(1)[1,2]^2*t(1)[1,3]^3 + 2*t(1)[1,1] + 3*t(1)[1,2] + 1 """ if isinstance(x, CombinatorialFreeModule.Element): if isinstance(x.parent(), Yangian) and x.parent()._n <= self._n: @@ -543,8 +395,8 @@ def algebra_generators(self): sage: Y = Yangian(QQ, 4) sage: Y.algebra_generators() - Lazy family (generator(i))_{i in Cartesian product of - Positive integers, (1, 2, 3, 4), (1, 2, 3, 4)} + Lazy family (generator(i))_{i in The Cartesian product of + (Positive integers, {1, 2, 3, 4}, {1, 2, 3, 4})} """ return Family(self._indices._indices, self.gen, name="generator") @@ -816,7 +668,8 @@ def __init__(self, base_ring, n, level, variable_name, filtration): category = HopfAlgebrasWithBasis(base_ring).Filtered() self._index_set = tuple(range(1,n+1)) # The keys for the basis are tuples (l, i, j) - indices = GeneratorIndexingSet(self._index_set, level) + L = range(1, self._level + 1) + indices = cartesian_product([L, self._index_set, self._index_set]) # We note that the generators are non-commutative, but we always sort # them, so they are, in effect, indexed by the free abelian monoid basis_keys = IndexedFreeAbelianMonoid(indices, bracket=False, prefix=variable_name) @@ -1170,6 +1023,17 @@ def antipode_on_basis(self, m): -tbar(2)[1,1] sage: x = grY.an_element(); x + tbar(1)[1,1]*tbar(1)[1,2]^2*tbar(1)[1,3]^3*tbar(42)[1,1] + sage: grY.antipode_on_basis(x.leading_support()) + -tbar(1)[1,1]*tbar(1)[1,2]^2*tbar(1)[1,3]^3*tbar(42)[1,1] + - 2*tbar(1)[1,1]*tbar(1)[1,2]*tbar(1)[1,3]^3*tbar(42)[1,2] + - 3*tbar(1)[1,1]*tbar(1)[1,2]^2*tbar(1)[1,3]^2*tbar(42)[1,3] + + 5*tbar(1)[1,2]^2*tbar(1)[1,3]^3*tbar(42)[1,1] + + 10*tbar(1)[1,2]*tbar(1)[1,3]^3*tbar(42)[1,2] + + 15*tbar(1)[1,2]^2*tbar(1)[1,3]^2*tbar(42)[1,3] + + sage: g = grY.indices().gens() + sage: x = grY(g[1,1,1] * g[1,1,2]^2 * g[1,1,3]^3 * g[3,1,1]); x tbar(1)[1,1]*tbar(1)[1,2]^2*tbar(1)[1,3]^3*tbar(3)[1,1] sage: grY.antipode_on_basis(x.leading_support()) -tbar(1)[1,1]*tbar(1)[1,2]^2*tbar(1)[1,3]^3*tbar(3)[1,1] From a346bff43695d3e23e21cce07b823fafdb792269 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 27 Aug 2022 15:05:35 +0900 Subject: [PATCH 320/742] Fixing pyflakes for yangian.py. --- src/sage/algebras/yangian.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/algebras/yangian.py b/src/sage/algebras/yangian.py index bfd69fbaf27..185d62ae09e 100644 --- a/src/sage/algebras/yangian.py +++ b/src/sage/algebras/yangian.py @@ -19,11 +19,9 @@ from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod -from sage.structure.unique_representation import UniqueRepresentation from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis from sage.categories.cartesian_product import cartesian_product -from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.sets.family import Family @@ -32,8 +30,6 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.algebras.associated_graded import AssociatedGradedAlgebra -import itertools - class Yangian(CombinatorialFreeModule): r""" From a1de06499bf16d26b13fb8c0c09116700465d917 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 23:06:49 -0700 Subject: [PATCH 321/742] TensorFreeSubmodule_comp: Default name, latex_name for the case Sym^n(M) --- src/sage/tensor/modules/tensor_free_submodule.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 5c778c6ac0a..086010de013 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -16,6 +16,7 @@ from sage.sets.disjoint_set import DisjointSet from .tensor_free_module import TensorFreeModule from .finite_rank_free_module import FiniteRankFreeModule_abstract +from sage.tensor.modules.comp import CompFullySym, CompWithSym class TensorFreeSubmodule_comp(TensorFreeModule): r""" @@ -31,6 +32,8 @@ class TensorFreeSubmodule_comp(TensorFreeModule): Free module of type-(2,0) tensors with Fully symmetric 2-indices components w.r.t. (0, 1, 2) on the Rank-3 free module M over the Integer Ring + sage: latex(Sym2M) + \mathrm{Sym}^{2}\left(M\right) Canonical injections from submodules are coercions:: @@ -63,11 +66,18 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, self._tensor_type = tuple(tensor_type) if ambient is None: ambient = fmodule.tensor_module(*tensor_type) + ambient_type = ambient.tensor_type() self._ambient_module = ambient self._sym = sym self._antisym = antisym - rank = len(list(self._basis_comp().non_redundant_index_generator())) - # TODO: Good defaults for name, latex_name + basis_comp = self._basis_comp() + rank = len(list(basis_comp.non_redundant_index_generator())) + # TODO: Good defaults for name, latex_name for more cases + if name is None and fmodule._name is not None: + if isinstance(basis_comp, CompFullySym) and not ambient_type[1]: + name = 'Sym^' + str(ambient_type[0]) + '(' + fmodule._name + ')' + latex_name = r'\mathrm{Sym}^{' + str(ambient_type[0]) + r'}\left(' + \ + fmodule._latex_name + r'\right)' category = fmodule.category().TensorProducts().FiniteDimensional().Subobjects().or_subcategory(category) # Skip TensorFreeModule.__init__ FiniteRankFreeModule_abstract.__init__(self, fmodule._ring, rank, name=name, From baff2153edf95ad14180bd9ca29155b9b6648422 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 27 Aug 2022 11:08:47 +0200 Subject: [PATCH 322/742] plethysm with tensor products, part 2 of 2 --- src/sage/data_structures/stream.py | 10 ++++++---- src/sage/rings/lazy_series.py | 14 +++++++++++++- src/sage/rings/lazy_series_ring.py | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index aeebe90e6d9..fc77581446f 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -1752,19 +1752,21 @@ def __init__(self, f, g, p, ring=None, include=None, exclude=None): """ # assert g._approximate_order > 0 val = f._approximate_order * g._approximate_order - p_f = Stream_map_coefficients(f, lambda x: x, p) - p_g = Stream_map_coefficients(g, lambda x: x, p) - self._powers = [p_g] # a cache for the powers of p_g if ring is None: self._basis = p else: self._basis = ring self._p = p + p_g = Stream_map_coefficients(g, lambda x: x, p) + self._powers = [p_g] # a cache for the powers of p_g R = self._basis.base_ring() if HopfAlgebrasWithBasis(R).TensorProducts() in p.categories(): self._tensor_power = len(p._sets) + p_f = Stream_map_coefficients(f, lambda x: x, p._sets[0]) else: self._tensor_power = None + p_f = Stream_map_coefficients(f, lambda x: x, p) + self._degree_one = _variables_recursive(R, include=include, exclude=exclude) super().__init__(p_f, p_g, f._is_sparse, val) @@ -1795,7 +1797,7 @@ def get_coefficient(self, n): 4*s[1, 1, 1, 1, 1] + 4*s[2, 1, 1, 1] + 2*s[2, 2, 1] + 2*s[3, 1, 1] + s[3, 2] + s[4, 1] + s[5]] """ if not n: # special case of 0 - return self._left[0] + return self._left[0].coefficient([]) return sum((c * self._compute_product(n, la) for k in range(self._left._approximate_order, n+1) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 01059a15e9d..1cb9844d294 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -123,6 +123,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.categories.tensor import tensor from sage.data_structures.stream import ( Stream_add, Stream_cauchy_mul, @@ -3790,6 +3791,14 @@ def __call__(self, *args, check=True): sage: A = S(s[1,1,1]) sage: B = S2(X+Y) sage: A(B) + (s[]#s[1,1,1]+s[1]#s[1,1]+s[1,1]#s[1]+s[1,1,1]#s[]) + + sage: H = S(lambda n: s[n]) + sage: H(S2(X*Y)) + (s[]#s[]) + (s[1]#s[1]) + (s[1,1]#s[1,1]+s[2]#s[2]) + (s[1,1,1]#s[1,1,1]+s[2,1]#s[2,1]+s[3]#s[3]) + O^7 + sage: H(S2(X+Y)) + (s[]#s[]) + (s[1]#s[1]) + (s[1,1]#s[1,1]+s[2]#s[2]) + (s[1,1,1]#s[1,1,1]+s[2,1]#s[2,1]+s[3]#s[3]) + O^7 +(s[]#s[]) + (s[]#s[1]+s[1]#s[]) + (s[]#s[2]+s[1]#s[1]+s[2]#s[]) + (s[]#s[3]+s[1]#s[2]+s[2]#s[1]+s[3]#s[]) + (s[]#s[4]+s[1]#s[3]+s[2]#s[2]+s[3]#s[1]+s[4]#s[]) + (s[]#s[5]+s[1]#s[4]+s[2]#s[3]+s[3]#s[2]+s[4]#s[1]+s[5]#s[]) + (s[]#s[6]+s[1]#s[5]+s[2]#s[4]+s[3]#s[3]+s[4]#s[2]+s[5]#s[1]+s[6]#s[]) + O^7 TESTS:: @@ -3859,7 +3868,10 @@ def __call__(self, *args, check=True): raise ValueError("can only compose with a positive valuation series") g._coeff_stream._approximate_order = 1 - ps = P._laurent_poly_ring.realization_of().p() + if P._arity == 1: + ps = P._laurent_poly_ring.realization_of().p() + else: + ps = tensor([P._laurent_poly_ring._sets[0].realization_of().p()]*P._arity) coeff_stream = Stream_plethysm(self._coeff_stream, g._coeff_stream, ps) else: raise NotImplementedError("only implemented for arity 1") diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 44c461ccbce..3be0396ca63 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1679,7 +1679,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) p_dict[d] = p_dict.get(d, 0) + f else: for f in x.terms(): - d = sum(p.size() for p in f.support()) + d = sum(sum(mu.size() for mu in p) for p in f.support()) p_dict[d] = p_dict.get(d, 0) + f v = min(p_dict.keys()) d = max(p_dict.keys()) From 08c7631cdf7356e2eb1e6cd0c04c2fb158a60145 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sat, 27 Aug 2022 13:49:54 +0800 Subject: [PATCH 323/742] add .rational_reconstruction() wrapper to PolynomialQuotientRingElement --- .../polynomial_quotient_ring_element.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index 846cd727986..c639214e5d6 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -714,3 +714,27 @@ def trace(self): 389 """ return self.matrix().trace() + + def rational_reconstruction(self, *args, **kwargs): + r""" + Compute a rational reconstruction of this polynomial quotient + ring element to its parent. + + This method is a thin convenience wrapper around + :meth:`Polynomial.rational_reconstruction`. + + EXAMPLES:: + + sage: R. = GF(65537)[] + sage: m = x^11 + 25345*x^10 + 10956*x^9 + 13873*x^8 + 23962*x^7 + 17496*x^6 + 30348*x^5 + 7440*x^4 + 65438*x^3 + 7676*x^2 + 54266*x + 47805 + sage: f = 20437*x^10 + 62630*x^9 + 63241*x^8 + 12820*x^7 + 42171*x^6 + 63091*x^5 + 15288*x^4 + 32516*x^3 + 2181*x^2 + 45236*x + 2447 + sage: f_mod_m = R.quotient(m)(f) + sage: f_mod_m.rational_reconstruction() + (51388*x^5 + 29141*x^4 + 59341*x^3 + 7034*x^2 + 14152*x + 23746, + x^5 + 15208*x^4 + 19504*x^3 + 20457*x^2 + 11180*x + 28352) + """ + m = self.parent().modulus() + R = m.parent() + f = R(self._polynomial) + return f.lift().rational_reconstruction(m, *args, **kwargs) + From 320d00b310cc27a923662b33769fa214987ff7bc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 27 Aug 2022 08:30:56 -0700 Subject: [PATCH 324/742] TensorFreeSubmodule_comp: Default name, latex_name for more cases --- .../tensor/modules/tensor_free_submodule.py | 106 ++++++++++++++---- 1 file changed, 86 insertions(+), 20 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 086010de013..1ced6855eb7 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -3,7 +3,7 @@ """ #****************************************************************************** -# Copyright (C) 2020 Matthias Koeppe +# Copyright (C) 2020-2022 Matthias Koeppe # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -11,12 +11,17 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +import itertools + from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.sets.disjoint_set import DisjointSet +from sage.typeset.unicode_characters import unicode_otimes + +from .comp import CompFullySym, CompFullyAntiSym, CompWithSym from .tensor_free_module import TensorFreeModule from .finite_rank_free_module import FiniteRankFreeModule_abstract -from sage.tensor.modules.comp import CompFullySym, CompWithSym + class TensorFreeSubmodule_comp(TensorFreeModule): r""" @@ -28,22 +33,42 @@ class TensorFreeSubmodule_comp(TensorFreeModule): sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M - Free module of type-(2,0) tensors - with Fully symmetric 2-indices components w.r.t. (0, 1, 2) - on the Rank-3 free module M over the Integer Ring - sage: latex(Sym2M) - \mathrm{Sym}^{2}\left(M\right) + sage: e = M.basis('e') + sage: T60M = M.tensor_module(6, 0); T60M + Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring + sage: T60M._name + 'T^(6, 0)(M)' + sage: latex(T60M) + T^{(6, 0)}\left(M\right) + sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))); Sym0123x45M + Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), + with symmetry on the index positions (0, 1, 2, 3), + with symmetry on the index positions (4, 5) + on the Rank-3 free module M over the Integer Ring + sage: Sym0123x45M._name + 'Sym^{0,1,2,3}(M)⊗Sym^{4,5}(M)' + sage: latex(Sym0123x45M) + \mathrm{Sym}^{\{0,1,2,3\}}\left(M\right) \otimes \mathrm{Sym}^{\{4,5\}}\left(M\right) + sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))); Sym012x345M + Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), + with symmetry on the index positions (0, 1, 2), + with symmetry on the index positions (3, 4, 5) + on the Rank-3 free module M over the Integer Ring + sage: Sym012x345M._name + 'Sym^{0,1,2}(M)⊗Sym^{3,4,5}(M)' + sage: latex(Sym012x345M) + \mathrm{Sym}^{\{0,1,2\}}\left(M\right) \otimes \mathrm{Sym}^{\{3,4,5\}}\left(M\right) + sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))); Sym012345M + Free module of type-(6,0) tensors + with Fully symmetric 6-indices components w.r.t. (0, 1, 2) + on the Rank-3 free module M over the Integer Ring + sage: Sym012345M._name + 'Sym^6(M)' + sage: latex(Sym012345M) + \mathrm{Sym}^6\left(M\right) Canonical injections from submodules are coercions:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp - sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: e = M.basis('e') - sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) - sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) - sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) sage: Sym0123x45M.has_coerce_map_from(Sym012345M) True sage: T60M.has_coerce_map_from(Sym0123x45M) @@ -58,6 +83,9 @@ class TensorFreeSubmodule_comp(TensorFreeModule): sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) sage: TestSuite(Sym0123x45M).run() + Traceback (most recent call last): + ... + The following tests failed: _test_not_implemented_methods, _test_zero """ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, @@ -66,7 +94,6 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, self._tensor_type = tuple(tensor_type) if ambient is None: ambient = fmodule.tensor_module(*tensor_type) - ambient_type = ambient.tensor_type() self._ambient_module = ambient self._sym = sym self._antisym = antisym @@ -74,10 +101,49 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, rank = len(list(basis_comp.non_redundant_index_generator())) # TODO: Good defaults for name, latex_name for more cases if name is None and fmodule._name is not None: - if isinstance(basis_comp, CompFullySym) and not ambient_type[1]: - name = 'Sym^' + str(ambient_type[0]) + '(' + fmodule._name + ')' - latex_name = r'\mathrm{Sym}^{' + str(ambient_type[0]) + r'}\left(' + \ - fmodule._latex_name + r'\right)' + if isinstance(basis_comp, CompFullySym): + sym = [tuple(range(tensor_type[0] + tensor_type[1]))] + antisym = [] + elif isinstance(basis_comp, CompFullyAntiSym): + sym = [] + antisym = [tuple(range(tensor_type[0] + tensor_type[1]))] + elif isinstance(basis_comp, CompWithSym): + sym = basis_comp._sym + antisym = basis_comp._antisym + else: + assert False, "full tensor module" + + def power_name(op, s, latex=False): + if s[0] < tensor_type[0]: + assert all(i < tensor_type[0] for i in s) + base = fmodule + full = tensor_type[0] + else: + base = fmodule.dual() + full = tensor_type[1] + if len(s) == full: + superscript = str(full) + else: + superscript = ','.join(str(i) for i in s) + if latex: + superscript = r'\{' + superscript + r'\}' + else: + superscript = '{' + superscript + '}' + if latex: + if len(superscript) != 1: + superscript = '{' + superscript + '}' + return r'\mathrm{' + op + '}^' + superscript + \ + r'\left(' + base._latex_name + r'\right)' + else: + return op + '^' + superscript + '(' + base._name + ')' + + name = unicode_otimes.join(itertools.chain( + (power_name('Sym', s, latex=False) for s in sym), + (power_name('ASym', s, latex=False) for s in antisym))) + latex_name = r' \otimes '.join(itertools.chain( + (power_name('Sym', s, latex=True) for s in sym), + (power_name('ASym', s, latex=True) for s in antisym))) + category = fmodule.category().TensorProducts().FiniteDimensional().Subobjects().or_subcategory(category) # Skip TensorFreeModule.__init__ FiniteRankFreeModule_abstract.__init__(self, fmodule._ring, rank, name=name, From e8ba50907ca202f62d086f3aff7aa7b6d20acee3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 27 Aug 2022 09:19:47 -0700 Subject: [PATCH 325/742] TensorFreeSubmodule_comp: Fix default name, latex_name for indices without symmetries --- .../tensor/modules/tensor_free_submodule.py | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 1ced6855eb7..ec566577985 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -40,6 +40,14 @@ class TensorFreeSubmodule_comp(TensorFreeModule): 'T^(6, 0)(M)' sage: latex(T60M) T^{(6, 0)}\left(M\right) + sage: T40Sym45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((4, 5))); T40Sym45M + Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), + with symmetry on the index positions (4, 5) + on the Rank-3 free module M over the Integer Ring + sage: T40Sym45M._name + 'T^{0,1,2,3}(M)⊗Sym^{4,5}(M)' + sage: latex(T40Sym45M) + T^{\{0,1,2,3\}}(M) \otimes \mathrm{Sym}^{\{4,5\}}(M) sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))); Sym0123x45M Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), with symmetry on the index positions (0, 1, 2, 3), @@ -48,7 +56,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): sage: Sym0123x45M._name 'Sym^{0,1,2,3}(M)⊗Sym^{4,5}(M)' sage: latex(Sym0123x45M) - \mathrm{Sym}^{\{0,1,2,3\}}\left(M\right) \otimes \mathrm{Sym}^{\{4,5\}}\left(M\right) + \mathrm{Sym}^{\{0,1,2,3\}}(M) \otimes \mathrm{Sym}^{\{4,5\}}(M) sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))); Sym012x345M Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), with symmetry on the index positions (0, 1, 2), @@ -57,7 +65,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): sage: Sym012x345M._name 'Sym^{0,1,2}(M)⊗Sym^{3,4,5}(M)' sage: latex(Sym012x345M) - \mathrm{Sym}^{\{0,1,2\}}\left(M\right) \otimes \mathrm{Sym}^{\{3,4,5\}}\left(M\right) + \mathrm{Sym}^{\{0,1,2\}}(M) \otimes \mathrm{Sym}^{\{3,4,5\}}(M) sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))); Sym012345M Free module of type-(6,0) tensors with Fully symmetric 6-indices components w.r.t. (0, 1, 2) @@ -65,7 +73,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): sage: Sym012345M._name 'Sym^6(M)' sage: latex(Sym012345M) - \mathrm{Sym}^6\left(M\right) + \mathrm{Sym}^6(M) Canonical injections from submodules are coercions:: @@ -99,19 +107,25 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, self._antisym = antisym basis_comp = self._basis_comp() rank = len(list(basis_comp.non_redundant_index_generator())) - # TODO: Good defaults for name, latex_name for more cases + if name is None and fmodule._name is not None: + all_indices = tuple(range(tensor_type[0] + tensor_type[1])) if isinstance(basis_comp, CompFullySym): - sym = [tuple(range(tensor_type[0] + tensor_type[1]))] + sym = [all_indices] antisym = [] elif isinstance(basis_comp, CompFullyAntiSym): sym = [] - antisym = [tuple(range(tensor_type[0] + tensor_type[1]))] + antisym = [all_indices] elif isinstance(basis_comp, CompWithSym): sym = basis_comp._sym antisym = basis_comp._antisym else: - assert False, "full tensor module" + sym = antisym = [] + nosym_0 = [i for i in range(tensor_type[0]) + if not any(i in s for s in sym) and not any(i in s for s in antisym)] + nosym_1 = [i for i in range(tensor_type[0], tensor_type[0] + tensor_type[1]) + if not any(i in s for s in sym) and not any(i in s for s in antisym)] + nosym = [s for s in [nosym_0, nosym_1] if s] def power_name(op, s, latex=False): if s[0] < tensor_type[0]: @@ -119,6 +133,7 @@ def power_name(op, s, latex=False): base = fmodule full = tensor_type[0] else: + assert all(i >= tensor_type[0] for i in s) base = fmodule.dual() full = tensor_type[1] if len(s) == full: @@ -132,17 +147,21 @@ def power_name(op, s, latex=False): if latex: if len(superscript) != 1: superscript = '{' + superscript + '}' - return r'\mathrm{' + op + '}^' + superscript + \ - r'\left(' + base._latex_name + r'\right)' + if len(base._latex_name) > 3: + return op + '^' + superscript + r'\left(' + base._latex_name + r'\right)' + else: + return op + '^' + superscript + '(' + base._name + ')' else: return op + '^' + superscript + '(' + base._name + ')' name = unicode_otimes.join(itertools.chain( + (power_name('T', s, latex=False) for s in nosym), (power_name('Sym', s, latex=False) for s in sym), (power_name('ASym', s, latex=False) for s in antisym))) latex_name = r' \otimes '.join(itertools.chain( - (power_name('Sym', s, latex=True) for s in sym), - (power_name('ASym', s, latex=True) for s in antisym))) + (power_name('T', s, latex=True) for s in nosym), + (power_name(r'\mathrm{Sym}', s, latex=True) for s in sym), + (power_name(r'\mathrm{ASym}', s, latex=True) for s in antisym))) category = fmodule.category().TensorProducts().FiniteDimensional().Subobjects().or_subcategory(category) # Skip TensorFreeModule.__init__ From 0277d80c8d35e467b8e4e0faaa2b0fcec3794916 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 27 Aug 2022 09:32:33 -0700 Subject: [PATCH 326/742] TensorFreeSubmodule_comp: Add example for module with sym and antisym --- .../tensor/modules/tensor_free_submodule.py | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index ec566577985..39b70ec332e 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -89,15 +89,31 @@ class TensorFreeSubmodule_comp(TensorFreeModule): TESTS:: - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) - sage: TestSuite(Sym0123x45M).run() - Traceback (most recent call last): - ... - The following tests failed: _test_not_implemented_methods, _test_zero + sage: T = TensorFreeSubmodule_comp(M, (4, 4), sym=((0, 1)), antisym=((4, 5))); T + Free module of type-(4,4) tensors with 8-indices components w.r.t. (0, 1, 2), + with symmetry on the index positions (0, 1), + with antisymmetry on the index positions (4, 5) + on the Rank-3 free module M over the Integer Ring + sage: T._name + 'T^{2,3}(M)⊗T^{6,7}(M*)⊗Sym^{0,1}(M)⊗ASym^{4,5}(M*)' + sage: latex(T) + T^{\{2,3\}}(M) \otimes T^{\{6,7\}}(M^*) \otimes \mathrm{Sym}^{\{0,1\}}(M) \otimes \mathrm{ASym}^{\{4,5\}}(M^*) """ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, sym=None, antisym=None, *, category=None, ambient=None): + r""" + TESTS:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: TestSuite(Sym0123x45M).run() + Traceback (most recent call last): + ... + The following tests failed: _test_not_implemented_methods, _test_zero + """ self._fmodule = fmodule self._tensor_type = tuple(tensor_type) if ambient is None: @@ -150,7 +166,7 @@ def power_name(op, s, latex=False): if len(base._latex_name) > 3: return op + '^' + superscript + r'\left(' + base._latex_name + r'\right)' else: - return op + '^' + superscript + '(' + base._name + ')' + return op + '^' + superscript + '(' + base._latex_name + ')' else: return op + '^' + superscript + '(' + base._name + ')' From 9f200b47270e2f7ad4cc492ad4f173760f5e3cf3 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 27 Aug 2022 18:51:43 +0200 Subject: [PATCH 327/742] fix oversights --- src/sage/data_structures/stream.py | 4 +++- src/sage/rings/lazy_series.py | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index fc77581446f..75a697d28c6 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -1797,7 +1797,9 @@ def get_coefficient(self, n): 4*s[1, 1, 1, 1, 1] + 4*s[2, 1, 1, 1] + 2*s[2, 2, 1] + 2*s[3, 1, 1] + s[3, 2] + s[4, 1] + s[5]] """ if not n: # special case of 0 - return self._left[0].coefficient([]) + if self._tensor_power is None: + return self._left[0] + return self._basis(self._left[0].coefficient([])) return sum((c * self._compute_product(n, la) for k in range(self._left._approximate_order, n+1) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index eb9cf55acc6..8aef2b92197 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3876,8 +3876,7 @@ def __call__(self, *args, check=True): sage: H(S2(X*Y)) (s[]#s[]) + (s[1]#s[1]) + (s[1,1]#s[1,1]+s[2]#s[2]) + (s[1,1,1]#s[1,1,1]+s[2,1]#s[2,1]+s[3]#s[3]) + O^7 sage: H(S2(X+Y)) - (s[]#s[]) + (s[1]#s[1]) + (s[1,1]#s[1,1]+s[2]#s[2]) + (s[1,1,1]#s[1,1,1]+s[2,1]#s[2,1]+s[3]#s[3]) + O^7 -(s[]#s[]) + (s[]#s[1]+s[1]#s[]) + (s[]#s[2]+s[1]#s[1]+s[2]#s[]) + (s[]#s[3]+s[1]#s[2]+s[2]#s[1]+s[3]#s[]) + (s[]#s[4]+s[1]#s[3]+s[2]#s[2]+s[3]#s[1]+s[4]#s[]) + (s[]#s[5]+s[1]#s[4]+s[2]#s[3]+s[3]#s[2]+s[4]#s[1]+s[5]#s[]) + (s[]#s[6]+s[1]#s[5]+s[2]#s[4]+s[3]#s[3]+s[4]#s[2]+s[5]#s[1]+s[6]#s[]) + O^7 + (s[]#s[]) + (s[]#s[1]+s[1]#s[]) + (s[]#s[2]+s[1]#s[1]+s[2]#s[]) + (s[]#s[3]+s[1]#s[2]+s[2]#s[1]+s[3]#s[]) + (s[]#s[4]+s[1]#s[3]+s[2]#s[2]+s[3]#s[1]+s[4]#s[]) + (s[]#s[5]+s[1]#s[4]+s[2]#s[3]+s[3]#s[2]+s[4]#s[1]+s[5]#s[]) + (s[]#s[6]+s[1]#s[5]+s[2]#s[4]+s[3]#s[3]+s[4]#s[2]+s[5]#s[1]+s[6]#s[]) + O^7 TESTS:: From 17137cf98bb41b2d1adeed0cf6d37f00117c890e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 27 Aug 2022 10:24:20 -0700 Subject: [PATCH 328/742] FiniteRankFreeModule.tensor_module: Add parameters sym, antisym; add methods symmetric_power, dual_symmetric_power --- .../tensor/modules/finite_rank_free_module.py | 118 +++++++++++++++++- 1 file changed, 112 insertions(+), 6 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 4390e687377..743cd8dae80 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1130,7 +1130,7 @@ def _Hom_(self, other, category=None): from .free_module_homset import FreeModuleHomset return FreeModuleHomset(self, other) - def tensor_module(self, k, l): + def tensor_module(self, k, l, *, sym=None, antisym=None): r""" Return the free module of all tensors of type `(k, l)` defined on ``self``. @@ -1141,6 +1141,18 @@ def tensor_module(self, k, l): type being `(k, l)` - ``l`` -- non-negative integer; the covariant rank, the tensor type being `(k, l)` + - ``sym`` -- (default: ``None``) a symmetry or a list of symmetries + among the tensor arguments: each symmetry is described by a tuple + containing the positions of the involved arguments, with the + convention ``position = 0`` for the first argument. For instance: + + * ``sym = (0,1)`` for a symmetry between the 1st and 2nd arguments + * ``sym = [(0,2), (1,3,4)]`` for a symmetry between the 1st and 3rd + arguments and a symmetry between the 2nd, 4th and 5th arguments. + + - ``antisym`` -- (default: ``None``) antisymmetry or list of + antisymmetries among the arguments, with the same convention + as for ``sym`` OUTPUT: @@ -1170,21 +1182,115 @@ def tensor_module(self, k, l): sage: M.tensor_module(1,0) is M True + By using the arguments ``sym`` and ``antisym``, submodules of a full tensor + module can be constructed:: + + sage: T = M.tensor_module(4, 4, sym=((0, 1)), antisym=((4, 5))); T + Free module of type-(4,4) tensors with 8-indices components w.r.t. (0, 1, 2), + with symmetry on the index positions (0, 1), + with antisymmetry on the index positions (4, 5) + on the Rank-3 free module M over the Integer Ring + sage: T._name + 'T^{2,3}(M)⊗T^{6,7}(M*)⊗Sym^{0,1}(M)⊗ASym^{4,5}(M*)' + sage: latex(T) + T^{\{2,3\}}(M) \otimes T^{\{6,7\}}(M^*) \otimes \mathrm{Sym}^{\{0,1\}}(M) \otimes \mathrm{ASym}^{\{4,5\}}(M^*) + See :class:`~sage.tensor.modules.tensor_free_module.TensorFreeModule` + and :class:`~sage.tensor.modules.tensor_free_module.TensorFreeSubmodule_comp` for more documentation. """ + if sym or antisym: + # TODO: Canonicalize sym, antisym, make hashable + key = (k, l, sym, antisym) + else: + key = (k, l) try: - return self._tensor_modules[(k,l)] + return self._tensor_modules[key] except KeyError: - if (k, l) == (1, 0): + if key == (1, 0): T = self + elif sym or antisym: + from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + T = TensorFreeSubmodule_comp(self, (k, l), sym=sym, antisym=antisym) else: from sage.tensor.modules.tensor_free_module import TensorFreeModule - T = TensorFreeModule(self, (k,l)) - self._tensor_modules[(k,l)] = T + T = TensorFreeModule(self, (k, l)) + self._tensor_modules[key] = T return T + def symmetric_power(self, p): + r""" + Return the `p`-th symmetric power of ``self``. + + EXAMPLES: + + Symmetric powers of a free `\ZZ`-module of rank 3:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: M.symmetric_power(0) + Free module of type-(0,0) tensors on the Rank-3 free module M over the Integer Ring + sage: M.symmetric_power(1) # return the module itself + Rank-3 free module M over the Integer Ring + sage: M.symmetric_power(1) is M + True + sage: M.symmetric_power(2) + Free module of type-(2,0) tensors + with Fully symmetric 2-indices components w.r.t. (0, 1, 2) + on the Rank-3 free module M over the Integer Ring + sage: M.symmetric_power(2).an_element() + Type-(2,0) tensor on the Rank-3 free module M over the Integer Ring + sage: M.symmetric_power(2).an_element().display() + e_0⊗e_0 + sage: M.symmetric_power(3) + Free module of type-(3,0) tensors + with Fully symmetric 3-indices components w.r.t. (0, 1, 2) + on the Rank-3 free module M over the Integer Ring + sage: M.symmetric_power(3).an_element() + Type-(3,0) tensor on the Rank-3 free module M over the Integer Ring + sage: M.symmetric_power(3).an_element().display() + e_0⊗e_0⊗e_0 + """ + if p <= 1: + return self.tensor_module(p, 0) + return self.tensor_module(p, 0, sym=(tuple(range(p)),)) + + def dual_symmetric_power(self, p): + r""" + Return the `p`-th symmetric power of the dual of ``self``. + + EXAMPLES: + + Symmetric powers of the dual of a free `\ZZ`-module of rank 3:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: M.dual_symmetric_power(0) + Free module of type-(0,0) tensors on the Rank-3 free module M over the Integer Ring + sage: M.dual_symmetric_power(1) # return the module itself + Free module of type-(0,1) tensors on the Rank-3 free module M over the Integer Ring + sage: M.dual_symmetric_power(2) + Free module of type-(0,2) tensors + with Fully symmetric 2-indices components w.r.t. (0, 1, 2) + on the Rank-3 free module M over the Integer Ring + sage: M.dual_symmetric_power(2).an_element() + Type-(0,2) tensor on the Rank-3 free module M over the Integer Ring + sage: M.dual_symmetric_power(2).an_element().display() + e^0⊗e^0 + sage: M.dual_symmetric_power(3) + Free module of type-(0,3) tensors + with Fully symmetric 3-indices components w.r.t. (0, 1, 2) + on the Rank-3 free module M over the Integer Ring + sage: M.dual_symmetric_power(3).an_element() + Type-(0,3) tensor on the Rank-3 free module M over the Integer Ring + sage: M.dual_symmetric_power(3).an_element().display() + e^0⊗e^0⊗e^0 + """ + if p <= 1: + return self.tensor_module(0, p) + return self.tensor_module(0, p, sym=(tuple(range(p)),)) + def exterior_power(self, p): r""" Return the `p`-th exterior power of ``self``. @@ -1216,7 +1322,7 @@ def exterior_power(self, p): EXAMPLES: - Exterior powers of the dual of a free `\ZZ`-module of rank 3:: + Exterior powers of a free `\ZZ`-module of rank 3:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') From c59c1f22768280d75383d258f73e860bf1b096f6 Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Sat, 27 Aug 2022 12:39:49 -0700 Subject: [PATCH 329/742] double colon --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index fcef9536bf8..4e679b453df 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3390,7 +3390,7 @@ def curve(self): Curve from which Riemann surface is obtained. - EXAMPLE: + EXAMPLE:: sage: R. = QQ[] sage: C = Curve( y^3+x^3-1) From e2d2ea8265cfb915e55a20e89ea731eed2f16b11 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 27 Aug 2022 10:59:51 -0700 Subject: [PATCH 330/742] src/sage/tensor/modules/finite_rank_free_module.py: isomorphism_with_fixed_basis with codomain=symmetric matrices --- .../tensor/modules/finite_rank_free_module.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 9da331cf3b3..2a84cee63a9 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -846,6 +846,36 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): [2 4 5] [3 5 6] + Same but explicitly in the subspace of symmetric bilinear forms:: + + sage: Sym2Vdual = V.dual_symmetric_power(2); Sym2Vdual + Free module of type-(0,2) tensors + with Fully symmetric 2-indices components w.r.t. (1, 2, 3) + on the 3-dimensional vector space over the Rational Field + sage: Sym2Vdual.is_submodule(T02) + True + sage: Sym2Vdual.rank() + 6 + sage: e_Sym2Vdual = Sym2Vdual.basis("e"); e_Sym2Vdual + Standard basis on the Free module of type-(0,2) tensors + with Fully symmetric 2-indices components w.r.t. (1, 2, 3) + on the 3-dimensional vector space over the Rational Field + induced by Basis (e_1,e_2,e_3) on the 3-dimensional vector space over the Rational Field + sage: W_basis = [phi_e_T02(b) for b in e_Sym2Vdual]; W_basis + [ + [1 0 0] [0 1 0] [0 0 1] [0 0 0] [0 0 0] [0 0 0] + [0 0 0] [1 0 0] [0 0 0] [0 1 0] [0 0 1] [0 0 0] + [0 0 0], [0 0 0], [1 0 0], [0 0 0], [0 1 0], [0 0 1] + ] + sage: W = MatrixSpace(QQ, 3).submodule(W_basis); W + Free module generated by {0, 1, 2, 3, 4, 5} over Rational Field + sage: phi_e_Sym2Vdual = Sym2Vdual.isomorphism_with_fixed_basis(e_Sym2Vdual, codomain=W); phi_e_Sym2Vdual + Generic morphism: + From: Free module of type-(0,2) tensors + with Fully symmetric 2-indices components w.r.t. (1, 2, 3) + on the 3-dimensional vector space over the Rational Field + To: Free module generated by {0, 1, 2, 3, 4, 5} over Rational Field + Sending tensors to elements of the tensor square of :class:`CombinatorialFreeModule`:: sage: T20 = V.tensor_module(2, 0); T20 @@ -909,6 +939,8 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): else: # assume that the keys of the codomain should be used key_pairs = zip(codomain_basis.keys(), basis.keys()) + # Need them several times, can't keep as generators + key_pairs = tuple(key_pairs) def _isomorphism(x): r""" From 993b3437f31c224e2e901a6d320480318b808baa Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 27 Aug 2022 14:34:42 -0700 Subject: [PATCH 331/742] TensorFreeModule._element_constructor_: Pass parent=self to element_class --- src/sage/tensor/modules/tensor_free_module.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 11147a685ec..474b4e9a498 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -428,7 +428,8 @@ def _element_constructor_(self, comp=[], basis=None, name=None, self._fmodule is endo.domain(): resu = self.element_class(self._fmodule, (1,1), name=endo._name, - latex_name=endo._latex_name) + latex_name=endo._latex_name, + parent=self) for basis, mat in endo._matrices.items(): resu.add_comp(basis[0])[:] = mat else: @@ -450,7 +451,8 @@ def _element_constructor_(self, comp=[], basis=None, name=None, resu = self.element_class(self._fmodule, (p,0), name=tensor._name, latex_name=tensor._latex_name, - antisym=asym) + antisym=asym, + parent=self) for basis, comp in tensor._components.items(): resu._components[basis] = comp.copy() elif isinstance(comp, FreeModuleAltForm): @@ -467,7 +469,8 @@ def _element_constructor_(self, comp=[], basis=None, name=None, asym = range(p) resu = self.element_class(self._fmodule, (0,p), name=form._name, latex_name=form._latex_name, - antisym=asym) + antisym=asym, + parent=self) for basis, comp in form._components.items(): resu._components[basis] = comp.copy() elif isinstance(comp, FreeModuleAutomorphism): @@ -478,7 +481,8 @@ def _element_constructor_(self, comp=[], basis=None, name=None, raise TypeError("cannot coerce the {}".format(autom) + " to an element of {}".format(self)) resu = self.element_class(self._fmodule, (1,1), name=autom._name, - latex_name=autom._latex_name) + latex_name=autom._latex_name, + parent=self) for basis, comp in autom._components.items(): resu._components[basis] = comp.copy() elif isinstance(comp, FreeModuleTensor): @@ -489,14 +493,15 @@ def _element_constructor_(self, comp=[], basis=None, name=None, " to an element of {}".format(self)) resu = self.element_class(self._fmodule, self._tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + sym=sym, antisym=antisym, + parent=self) for basis, comp in tensor._components.items(): resu._components[basis] = comp.copy() else: # Standard construction: resu = self.element_class(self._fmodule, self._tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + sym=sym, antisym=antisym, parent=self) if comp: resu.set_comp(basis)[:] = comp return resu From 5b8ccdef2e7a8b9deee937e05f03a87244ef8141 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 27 Aug 2022 14:38:08 -0700 Subject: [PATCH 332/742] src/sage/tensor/modules/tensor_free_module.py: Update doctest output --- src/sage/tensor/modules/tensor_free_module.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 474b4e9a498..25cfa23ca6f 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -736,7 +736,9 @@ def basis(self, symbol, latex_symbol=None, from_family=None, sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: T = M.tensor_module(1,1) sage: e_T = T.basis('e'); e_T - + Standard basis on the + Free module of type-(1,1) tensors on the Rank-3 free module M over the Integer Ring + induced by Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring sage: for a in e_T: a.display() e_0⊗e^0 e_0⊗e^1 @@ -751,7 +753,10 @@ def basis(self, symbol, latex_symbol=None, from_family=None, sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)) sage: e_Sym2M = Sym2M.basis('e'); e_Sym2M - + Standard basis on the + Free module of type-(2,0) tensors with Fully symmetric 2-indices components w.r.t. (0, 1, 2) + on the Rank-3 free module M over the Integer Ring + induced by Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring sage: for a in e_Sym2M: a.display() e_0⊗e_0 e_0⊗e_1 + e_1⊗e_0 From b0812b12bcc0ba670a6963fd88310101fcde6f65 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 27 Aug 2022 18:23:08 -0700 Subject: [PATCH 333/742] TensorFreeSubmoduleBasis_comp._element_constructor_: Full implementation --- .../tensor/modules/tensor_free_submodule.py | 59 ++++++++++++++----- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 39b70ec332e..54eb5a92b0d 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -252,30 +252,57 @@ def is_coarsening_of(self_sym_list, other_sym_list): def _element_constructor_(self, comp=[], basis=None, name=None, latex_name=None, sym=None, antisym=None): + r""" + TESTS:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: T60M = M.tensor_module(6, 0) + sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: t = Sym0123x45M(e[0]*e[0]*e[0]*e[0]*e[1]*e[2]); t.disp() + Traceback (most recent call last): + ... + ValueError: this tensor does not have the symmetries of + Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), + with symmetry on the index positions (0, 1, 2, 3), + with symmetry on the index positions (4, 5) + on the Rank-3 free module M over the Integer Ring + sage: t = Sym0123x45M(e[0]*e[0]*e[0]*e[0]*e[1]*e[2] + e[0]*e[0]*e[0]*e[0]*e[2]*e[1]); t.disp() + e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 + e_0⊗e_0⊗e_0⊗e_0⊗e_2⊗e_1 + sage: t.parent()._name + 'Sym^{0,1,2,3}(M)⊗Sym^{4,5}(M)' + """ if sym is not None or antisym is not None: # Refuse to create a tensor with finer symmetries # than those defining the subspace if not self._is_symmetry_coarsening_of((sym, antisym), self._basis_comp()): - raise ValueError("cannot create a tensor with symmetries {} as an element of {}". - format((sym, antisym), self)) - try: - comp_parent = comp.parent() - except AttributeError: - comp_parent = None - if comp_parent == self.ambient_module(): - resu = comp - # comp is already a tensor. If its declared symmetries are coarser - # than the symmetries defining self, we can use it directly. - if self._is_symmetry_coarsening_of(resu, self._basis_comp()): - return resu + raise ValueError(f"cannot create a tensor with symmetries {sym=}, {antisym=} " + f"as an element of {self}") + if sym is None: sym = self._basis_comp()._sym if antisym is None: antisym = self._basis_comp()._antisym - resu = super()._element_constructor_(comp=comp, - basis=basis, name=name, - latex_name=latex_name, - sym=sym, antisym=antisym) + + symmetrized = resu = super()._element_constructor_(comp=comp, + basis=basis, name=name, + latex_name=latex_name, + sym=sym, antisym=antisym) + # TODO: Implement a fast symmetry check, either as part of the symmetrize method, + # or as a separate method + try: + for s in sym: + symmetrized = symmetrized.symmetrize(*s) + for s in antisym: + symmetrized = symmetrized.antisymmetrize(*s) + except TypeError: + # Averaging over the orbits of a tensor that does not have the required + # symmetries can lead to "TypeError: no conversion of this rational to integer" + raise ValueError(f"this tensor does not have the symmetries of {self}") + if symmetrized != resu: + raise ValueError(f"this tensor does not have the symmetries of {self}") + return resu def is_submodule(self, other): From 8cd3cc4517ab7a633f4e522052f103a61ccda708 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 27 Aug 2022 19:01:08 -0700 Subject: [PATCH 334/742] TensorFreeSubmoduleBasis_comp._element_constructor_: Fix for zero; implement retract --- .../tensor/modules/tensor_free_submodule.py | 60 +++++++++++++++++-- .../modules/tensor_free_submodule_basis.py | 5 -- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 54eb5a92b0d..35333c9d92b 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -110,9 +110,6 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, sage: e = M.basis('e') sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) sage: TestSuite(Sym0123x45M).run() - Traceback (most recent call last): - ... - The following tests failed: _test_not_implemented_methods, _test_zero """ self._fmodule = fmodule self._tensor_type = tuple(tensor_type) @@ -260,7 +257,7 @@ def _element_constructor_(self, comp=[], basis=None, name=None, sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0) sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) - sage: t = Sym0123x45M(e[0]*e[0]*e[0]*e[0]*e[1]*e[2]); t.disp() + sage: Sym0123x45M(e[0]*e[0]*e[0]*e[0]*e[1]*e[2]) Traceback (most recent call last): ... ValueError: this tensor does not have the symmetries of @@ -289,6 +286,10 @@ def _element_constructor_(self, comp=[], basis=None, name=None, basis=basis, name=name, latex_name=latex_name, sym=sym, antisym=antisym) + if not symmetrized._components: + # zero tensor - methods symmetrize, antisymmetrize are broken + return resu + # TODO: Implement a fast symmetry check, either as part of the symmetrize method, # or as a separate method try: @@ -367,3 +368,54 @@ def lift(self): on the Rank-3 free module M over the Integer Ring """ return self.module_morphism(function=lambda x: x, codomain=self.ambient()) + + @lazy_attribute + def retract(self): + r""" + The retract map from the ambient space. + + This is a partial map, which gives an error for elements not in the subspace. + + Calling this map on elements of the ambient space is the same as calling the + element constructor of ``self``. + + EXAMPLES:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: X = M.tensor_module(6, 0) + sage: Y = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) + sage: e_Y = Y.basis('e') + sage: Y.retract + Generic morphism: + From: Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring + To: Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), + with symmetry on the index positions (0, 1, 2, 3), + with symmetry on the index positions (4, 5) + on the Rank-3 free module M over the Integer Ring + + sage: t = e[0]*e[0]*e[0]*e[0]*e[1]*e[2]; t.disp() + e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 = e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 + sage: Y.retract(t) + Traceback (most recent call last): + ... + ValueError: this tensor does not have the symmetries of + Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), + with symmetry on the index positions (0, 1, 2, 3), + with symmetry on the index positions (4, 5) + on the Rank-3 free module M over the Integer Ring + sage: t = e[0]*e[0]*e[0]*e[0]*e[1]*e[2] + e[0]*e[0]*e[0]*e[0]*e[2]*e[1] + sage: y = Y.retract(t); y + Type-(6,0) tensor on the Rank-3 free module M over the Integer Ring + sage: y.disp() + e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 + e_0⊗e_0⊗e_0⊗e_0⊗e_2⊗e_1 + sage: y.parent()._name + 'Sym^{0,1,2,3}(M)⊗Sym^{4,5}(M)' + + TESTS:: + + sage: all(Y.retract(u.lift()) == u for u in e_Y) + True + """ + return self.ambient().module_morphism(function=lambda x: self(x), codomain=self) diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index 856d58554fb..731242d2f50 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -129,8 +129,3 @@ def __getitem__(self, index): element = tensor_module([]) element.set_comp(base_module_basis)[index] = 1 return element - -# Todo: -# dual basis -# add test for dual -# lift/reduce/retract From ae2ff23068417561adc3c93b483b756fbc7d95c3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 27 Aug 2022 19:21:06 -0700 Subject: [PATCH 335/742] TensorFreeSubmoduleBasis_comp.reduce: New; use it in _element_constructor_ --- .../tensor/modules/tensor_free_submodule.py | 90 ++++++++++++++++--- 1 file changed, 76 insertions(+), 14 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 35333c9d92b..4609c68aec9 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -282,27 +282,21 @@ def _element_constructor_(self, comp=[], basis=None, name=None, if antisym is None: antisym = self._basis_comp()._antisym - symmetrized = resu = super()._element_constructor_(comp=comp, - basis=basis, name=name, - latex_name=latex_name, - sym=sym, antisym=antisym) - if not symmetrized._components: - # zero tensor - methods symmetrize, antisymmetrize are broken + resu = super()._element_constructor_(comp=comp, + basis=basis, name=name, + latex_name=latex_name, + sym=sym, antisym=antisym) + if not resu._components: + # fast path for zero tensor return resu - # TODO: Implement a fast symmetry check, either as part of the symmetrize method, - # or as a separate method try: - for s in sym: - symmetrized = symmetrized.symmetrize(*s) - for s in antisym: - symmetrized = symmetrized.antisymmetrize(*s) + if self.reduce(resu): + raise ValueError(f"this tensor does not have the symmetries of {self}") except TypeError: # Averaging over the orbits of a tensor that does not have the required # symmetries can lead to "TypeError: no conversion of this rational to integer" raise ValueError(f"this tensor does not have the symmetries of {self}") - if symmetrized != resu: - raise ValueError(f"this tensor does not have the symmetries of {self}") return resu @@ -369,6 +363,74 @@ def lift(self): """ return self.module_morphism(function=lambda x: x, codomain=self.ambient()) + @lazy_attribute + def reduce(self): + r""" + The reduce map. + + This map reduces elements of the ambient space modulo this + submodule. + + EXAMPLES:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(QQ, 3, name='M') + sage: e = M.basis('e') + sage: X = M.tensor_module(6, 0) + sage: Y = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) + sage: Y.reduce + Generic endomorphism of Free module of type-(6,0) tensors on the 3-dimensional vector space M over the Rational Field + sage: t = e[0]*e[0]*e[0]*e[0]*e[1]*e[2]; t.disp() + e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 = e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 + sage: r = Y.reduce(t); r + Type-(6,0) tensor on the 3-dimensional vector space M over the Rational Field + sage: r.disp() + 1/2 e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 - 1/2 e_0⊗e_0⊗e_0⊗e_0⊗e_2⊗e_1 + sage: r.parent()._name + 'T^(6, 0)(M)' + + If the base ring is not a field, this may fail:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: X = M.tensor_module(6, 0) + sage: Y = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) + sage: Y.reduce + Generic endomorphism of Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring + sage: t = e[0]*e[0]*e[0]*e[0]*e[1]*e[2]; t.disp() + e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 = e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 + sage: Y.reduce(t) + Traceback (most recent call last): + ... + TypeError: no conversion of this rational to integer + + TESTS:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: X = M.tensor_module(6, 0) + sage: Y = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) + sage: all(Y.reduce(u.lift()) == 0 for u in Y.basis('e')) + True + """ + sym = self._basis_comp()._sym + antisym = self._basis_comp()._antisym + + def _reduce_element(x): + if not x._components: + # zero tensor - methods symmetrize, antisymmetrize are broken + return x + # TODO: Implement a fast symmetry check, either as part of the symmetrize/antisymmetrize methods, + # or as a separate method + symmetrized = x + for s in sym: + symmetrized = symmetrized.symmetrize(*s) + for s in antisym: + symmetrized = symmetrized.antisymmetrize(*s) + return x - symmetrized + + return self.ambient().module_morphism(function=_reduce_element, codomain=self.ambient()) + @lazy_attribute def retract(self): r""" From 2e7e636881fae9a77eb394c74124cae3410f69af Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 28 Aug 2022 12:24:41 +0800 Subject: [PATCH 336/742] remove incorrect call to .lift() --- src/sage/rings/polynomial/polynomial_quotient_ring_element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index c639214e5d6..999665948d2 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -736,5 +736,5 @@ def rational_reconstruction(self, *args, **kwargs): m = self.parent().modulus() R = m.parent() f = R(self._polynomial) - return f.lift().rational_reconstruction(m, *args, **kwargs) + return f.rational_reconstruction(m, *args, **kwargs) From 888b4fa98d8ffac84d1db90da68712775a4b700f Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 28 Aug 2022 12:25:10 +0800 Subject: [PATCH 337/742] fix terminology in docstring --- src/sage/rings/polynomial/polynomial_quotient_ring_element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index 999665948d2..803e78f6e13 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -718,7 +718,7 @@ def trace(self): def rational_reconstruction(self, *args, **kwargs): r""" Compute a rational reconstruction of this polynomial quotient - ring element to its parent. + ring element to its cover ring. This method is a thin convenience wrapper around :meth:`Polynomial.rational_reconstruction`. From 43adfff83bea7dda1e09ba4f28b29c405dd64927 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 28 Aug 2022 10:41:15 +0200 Subject: [PATCH 338/742] fix bug in LazyTaylorSeries.polynomial, add revert --- src/sage/rings/lazy_series.py | 164 +++++++++++++++++++++++++++-- src/sage/rings/lazy_series_ring.py | 3 +- 2 files changed, 159 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 8aef2b92197..5755409009f 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3160,8 +3160,7 @@ def revert(self): if coeff_stream[-1]: if coeff_stream[0] or coeff_stream[1]: raise ValueError("compositional inverse does not exist") - else: - raise ValueError("cannot determine whether the compositional inverse exists") + raise ValueError("cannot determine whether the compositional inverse exists") if not coeff_stream[1]: raise ValueError("compositional inverse does not exist") @@ -3581,6 +3580,153 @@ def coefficient(n): compose = __call__ + def revert(self): + r""" + Return the compositional inverse of ``self``. + + Given a Taylor Series `f`. the compositional inverse is a + Laurent Series `g` over the same base ring, such that + `(f \circ g)(z) = f(g(z)) = z`. + + The compositional inverse exists if and only if: + + - `val(f) = 1`, or + + - `f = a + b z` with `a, b \neq 0`, or + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: (2*z).revert() + 1/2*z + sage: (z-z^2).revert() + z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) + + sage: s = L(degree=1, constant=-1) + sage: s.revert() + -z - z^2 - z^3 + O(z^4) + + sage: s = L(degree=1, constant=1) + sage: s.revert() + z - z^2 + z^3 - z^4 + z^5 - z^6 + z^7 + O(z^8) + + TESTS:: + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: s = L(lambda n: 2 if n == 1 else 0, valuation=1); s + 2*z + O(z^8) + sage: s.revert() + 1/2*z + O(z^8) + + sage: (2+3*z).revert() + -2/3 + 1/3*z + + sage: s = L(lambda n: 2 if n == 0 else 3 if n == 1 else 0, valuation=0); s + 2 + 3*z + O(z^7) + sage: s.revert() + Traceback (most recent call last): + ... + ValueError: cannot determine whether the compositional inverse exists + + sage: R. = QQ[] + sage: L. = LazyTaylorSeriesRing(R.fraction_field()) + sage: s = L([q], valuation=0, constant=t); s + q + t*z + t*z^2 + t*z^3 + O(z^4) + sage: s.revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + We look at some cases where the compositional inverse does not exist: + + `f = 0`:: + + sage: L(0).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + sage: (z - z).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + `val(f) != 1` and `f(0) * f(1) = 0`:: + + sage: (z^2).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + sage: L(1).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + Reversion of exact series:: + + sage: f = L([1, 2], valuation=0, constant=1) + sage: f.revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + sage: f = L([-1, -1], valuation=1, constant=-1) + sage: f.revert() + (-z) + (-z^2) + (-z^3) + (-z^4) + (-z^5) + O(z^6) + + sage: f = L([-1, 0, -1], valuation=1, constant=-1) + sage: f.revert() + (-z) + z^3 + (-z^4) + (-2*z^5) + 6*z^6 + z^7 + O(z^8) + + sage: f = L([-1], valuation=1, degree=3, constant=-1) + sage: f.revert() + (-z) + z^3 + (-z^4) + (-2*z^5) + 6*z^6 + z^7 + O(z^8) + """ + P = self.parent() + if P._arity != 1: + raise ValueError("arity must be equal to 1") + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, Stream_zero): + raise ValueError("compositional inverse does not exist") + if isinstance(coeff_stream, Stream_exact): + if coeff_stream._constant: + if coeff_stream.order() == 1: + R = P.base_ring() + # we cannot assume that the last initial coefficient + # and the constant differ, see stream.Stream_exact + if (coeff_stream._degree == 1 + len(coeff_stream._initial_coefficients) + and coeff_stream._constant == -R.one() + and all(c == -R.one() for c in coeff_stream._initial_coefficients)): + # self = -z/(1-z); self.revert() = -z/(1-z) + return self + else: + raise ValueError("compositional inverse does not exist") + else: + if coeff_stream._degree == 2: + # self = a + b*z; self.revert() = -a/b + 1/b * z + a = coeff_stream[0] + b = coeff_stream[1] + coeff_stream = Stream_exact((-a/b, 1/b), + coeff_stream._is_sparse, + order=0) + return P.element_class(P, coeff_stream) + + if coeff_stream.order() != 1: + raise ValueError("compositional inverse does not exist") + + if not coeff_stream[1]: + raise ValueError("compositional inverse does not exist") + + if coeff_stream[0]: + raise ValueError("cannot determine whether the compositional inverse exists") + + z = P.gen() + g = P(None, valuation=1) + g.define(z / ((self / z)(g))) + return g + + compositional_inverse = revert + def _format_series(self, formatter, format_strings=False): """ Return nonzero ``self`` formatted by ``formatter``. @@ -3691,6 +3837,11 @@ def polynomial(self, degree=None, names=None): True sage: g3.polynomial(0) 1 + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: f = z-z^2 + sage: f.polynomial() + -z^2 + z """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing S = self.parent() @@ -3709,10 +3860,9 @@ def polynomial(self, degree=None, names=None): else: m = degree + 1 - if names is None: - names = S.variable_names() - - return R.sum(self[:m]) + if S._arity == 1: + return R(self[0:m]) + return R.sum(self[0:m]) class LazyCompletionGradedAlgebraElement(LazyCauchyProductSeries): @@ -4031,12 +4181,12 @@ def revert(self): """ P = self.parent() - R = P._laurent_poly_ring if P._arity != 1: raise ValueError("arity must be equal to 1") coeff_stream = self._coeff_stream if isinstance(coeff_stream, Stream_zero): raise ValueError("compositional inverse does not exist") + R = P._laurent_poly_ring if (isinstance(coeff_stream, Stream_exact) and coeff_stream.order() >= 0 and coeff_stream._degree == 2): diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index fe1b81ba3dd..2f0f405a6b9 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1149,7 +1149,8 @@ def __init__(self, base_ring, names, sparse=True, category=None): names = normalize_names(-1, names) self._sparse = sparse self._laurent_poly_ring = PolynomialRing(base_ring, names) - if len(names) == 1: + self._arity = len(names) + if self._arity == 1: self._internal_poly_ring = self._laurent_poly_ring else: coeff_ring = PolynomialRing(base_ring, names) From b7631554fcf629dba6241621c7712cb0325f337a Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 28 Aug 2022 17:10:01 +0900 Subject: [PATCH 339/742] Refactor with ConstructorBaseclassMetaclass --- src/sage/homology/free_resolution.py | 12 +++++++---- .../misc/constructor_baseclass_metaclass.pyx | 21 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/sage/misc/constructor_baseclass_metaclass.pyx diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index a6622d8cb8d..fb1fbb5a397 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -70,8 +70,8 @@ from sage.libs.singular.function import singular_function from sage.misc.lazy_attribute import lazy_attribute from sage.misc.abstract_method import abstract_method +from sage.misc.constructor_baseclass_metaclass import ConstructorBaseclassMetaclass from sage.structure.sage_object import SageObject -from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.structure.element import Matrix from sage.categories.principal_ideal_domains import PrincipalIdealDomains from sage.categories.integral_domains import IntegralDomains @@ -83,7 +83,7 @@ from copy import copy -def FreeResolution(module, degrees=None, shifts=None, name='S', graded=False, **kwds): +def free_resolution_constructor(module, degrees=None, shifts=None, name='S', graded=False, **kwds): """ Constructor. @@ -95,6 +95,8 @@ def FreeResolution(module, degrees=None, shifts=None, name='S', graded=False, ** sage: r = FreeResolution(m, name='S') sage: type(r) + sage: isinstance(r, FreeResolution) + True sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = FreeResolution(I) @@ -165,10 +167,12 @@ def FreeResolution(module, degrees=None, shifts=None, name='S', graded=False, ** return FiniteFreeResolution_free_module(module, name=name, **kwds) -class FreeResolution_abs(SageObject): +class FreeResolution(SageObject, metaclass=ConstructorBaseclassMetaclass): """ Abstract base class for free resolutions. """ + __constructor__ = free_resolution_constructor + def __init__(self, module, name='S', **kwds): """ Initialize. @@ -289,7 +293,7 @@ def target(self): return self.differential(0).codomain() -class FiniteFreeResolution(FreeResolution_abs): +class FiniteFreeResolution(FreeResolution): r""" Finite free resolutions. diff --git a/src/sage/misc/constructor_baseclass_metaclass.pyx b/src/sage/misc/constructor_baseclass_metaclass.pyx new file mode 100644 index 00000000000..fc3ca66f641 --- /dev/null +++ b/src/sage/misc/constructor_baseclass_metaclass.pyx @@ -0,0 +1,21 @@ +from sage.misc.classcall_metaclass cimport ClasscallMetaclass + + +cdef class ConstructorBaseclassMetaclass(ClasscallMetaclass): + + def __cinit__(self, *args, **opts): + r""" + TESTS:: + """ + if '__constructor__' in self.__dict__: + def constructor(cls, *a, **o): + return self.__constructor__(*a, **o) + self.classcall = constructor + else: + self.classcall = None + + self.classcontains = getattr(self, "__classcontains__", None) + self.classget = getattr(self, "__classget__", None) + + + From fa6162ee88a19bfdfe4723651098c0e61919512e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 09:16:24 -0700 Subject: [PATCH 340/742] src/doc/en/reference/tensor_free_modules: Add tensor_free_submodule, tensor_free_submodule_basis --- src/doc/en/reference/tensor_free_modules/tensors.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/en/reference/tensor_free_modules/tensors.rst b/src/doc/en/reference/tensor_free_modules/tensors.rst index be87fc68ad1..434ea734191 100644 --- a/src/doc/en/reference/tensor_free_modules/tensors.rst +++ b/src/doc/en/reference/tensor_free_modules/tensors.rst @@ -6,6 +6,10 @@ Tensors sage/tensor/modules/tensor_free_module + sage/tensor/modules/tensor_free_submodule + sage/tensor/modules/free_module_tensor sage/tensor/modules/tensor_with_indices + + sage/tensor/modules/tensor_free_submodule_basis From 680e3f4edb33d69503add2fd81291b395a6e74e3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 09:41:16 -0700 Subject: [PATCH 341/742] src/sage/tensor/modules/comp.py (Components._repr_): Factor out _repr_symmetry --- src/sage/tensor/modules/comp.py | 87 +++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 04f14f782f0..38ee9c58601 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -525,15 +525,48 @@ def _repr_(self): sage: c._repr_() '2-indices components w.r.t. [1, 2, 3]' + sage: from sage.tensor.modules.comp import CompWithSym + sage: CompWithSym(ZZ, [1,2,3], 4, sym=(0,1)) + 4-indices components w.r.t. [1, 2, 3], + with symmetry on the index positions (0, 1) + sage: CompWithSym(ZZ, [1,2,3], 4, sym=(0,1), antisym=(2,3)) + 4-indices components w.r.t. [1, 2, 3], + with symmetry on the index positions (0, 1), + with antisymmetry on the index positions (2, 3) + + sage: from sage.tensor.modules.comp import CompFullySym + sage: CompFullySym(ZZ, (1,2,3), 4) + Fully symmetric 4-indices components w.r.t. (1, 2, 3) + + sage: from sage.tensor.modules.comp import CompFullyAntiSym + sage: CompFullyAntiSym(ZZ, (1,2,3), 4) + Fully antisymmetric 4-indices components w.r.t. (1, 2, 3) """ - description = str(self._nid) + prefix, suffix = self._repr_symmetry() + description = prefix + description += str(self._nid) if self._nid == 1: description += "-index" else: description += "-indices" description += " components w.r.t. " + str(self._frame) + description += suffix return description + def _repr_symmetry(self): + r""" + Return a prefix and a suffix string describing the symmetry of ``self``. + + EXAMPLES:: + + sage: from sage.tensor.modules.comp import Components + sage: c = Components(ZZ, [1,2,3], 2) + sage: c._repr_symmetry() + ('', '') + + """ + return "", "" + def _new_instance(self): r""" Creates a :class:`Components` instance of the same number of indices @@ -3037,35 +3070,29 @@ def __init__(self, ring, frame, nb_indices, start_index=0, raise IndexError("incompatible lists of symmetries: the same " + "index position appears more then once") - def _repr_(self): + def _repr_symmetry(self): r""" - Return a string representation of ``self``. + Return a prefix and a suffix string describing the symmetry of ``self``. EXAMPLES:: sage: from sage.tensor.modules.comp import CompWithSym - sage: CompWithSym(ZZ, [1,2,3], 4, sym=(0,1)) - 4-indices components w.r.t. [1, 2, 3], - with symmetry on the index positions (0, 1) - sage: CompWithSym(ZZ, [1,2,3], 4, sym=(0,1), antisym=(2,3)) - 4-indices components w.r.t. [1, 2, 3], - with symmetry on the index positions (0, 1), - with antisymmetry on the index positions (2, 3) - + sage: cp = CompWithSym(QQ, [1,2,3], 4, sym=(0,1)) + sage: cp._repr_symmetry() + ('', ', with symmetry on the index positions (0, 1)') + sage: cp = CompWithSym(QQ, [1,2,3], 4, sym=((0,1),), antisym=((2,3),)) + sage: cp._repr_symmetry() + ('', + ', with symmetry on the index positions (0, 1), with antisymmetry on the index positions (2, 3)') """ - description = str(self._nid) - if self._nid == 1: - description += "-index" - else: - description += "-indices" - description += " components w.r.t. " + str(self._frame) + description = "" for isym in self._sym: description += ", with symmetry on the index positions " + \ str(tuple(isym)) for isym in self._antisym: description += ", with antisymmetry on the index positions " + \ str(tuple(isym)) - return description + return "", description def _new_instance(self): r""" @@ -4731,19 +4758,19 @@ def __init__(self, ring, frame, nb_indices, start_index=0, CompWithSym.__init__(self, ring, frame, nb_indices, start_index, output_formatter, sym=range(nb_indices)) - def _repr_(self): + def _repr_symmetry(self): r""" - Return a string representation of ``self``. + Return a prefix and a suffix string describing the symmetry of ``self``. EXAMPLES:: sage: from sage.tensor.modules.comp import CompFullySym - sage: CompFullySym(ZZ, (1,2,3), 4) - Fully symmetric 4-indices components w.r.t. (1, 2, 3) + sage: c = CompFullySym(ZZ, (1,2,3), 4) + sage: c._repr_symmetry() + ('Fully symmetric ', '') """ - return "Fully symmetric " + str(self._nid) + "-indices" + \ - " components w.r.t. " + str(self._frame) + return "Fully symmetric ", "" def _new_instance(self): r""" @@ -5190,19 +5217,19 @@ def __init__(self, ring, frame, nb_indices, start_index=0, CompWithSym.__init__(self, ring, frame, nb_indices, start_index, output_formatter, antisym=range(nb_indices)) - def _repr_(self): + def _repr_symmetry(self): r""" - Return a string representation of ``self``. + Return a prefix and a suffix string describing the symmetry of ``self``. EXAMPLES:: sage: from sage.tensor.modules.comp import CompFullyAntiSym - sage: CompFullyAntiSym(ZZ, (1,2,3), 4) - Fully antisymmetric 4-indices components w.r.t. (1, 2, 3) + sage: c = CompFullyAntiSym(ZZ, (1,2,3), 4) + sage: c._repr_symmetry() + ('Fully antisymmetric ', '') """ - return "Fully antisymmetric " + str(self._nid) + "-indices" + \ - " components w.r.t. " + str(self._frame) + return "Fully antisymmetric ", "" def _new_instance(self): r""" From 548620d491ea0d51453af69d480edc9762cb56de Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 09:58:34 -0700 Subject: [PATCH 342/742] TensorFreeSubmodule_comp._repr_: Use Components._repr_symmetry, update doctest outputs --- .../tensor/modules/finite_rank_free_module.py | 15 ++--- .../tensor/modules/tensor_free_submodule.py | 55 ++++++++----------- 2 files changed, 28 insertions(+), 42 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 743cd8dae80..08b3873dfbc 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1186,10 +1186,9 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): module can be constructed:: sage: T = M.tensor_module(4, 4, sym=((0, 1)), antisym=((4, 5))); T - Free module of type-(4,4) tensors with 8-indices components w.r.t. (0, 1, 2), + Free module of type-(4,4) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1), with antisymmetry on the index positions (4, 5) - on the Rank-3 free module M over the Integer Ring sage: T._name 'T^{2,3}(M)⊗T^{6,7}(M*)⊗Sym^{0,1}(M)⊗ASym^{4,5}(M*)' sage: latex(T) @@ -1236,16 +1235,14 @@ def symmetric_power(self, p): sage: M.symmetric_power(1) is M True sage: M.symmetric_power(2) - Free module of type-(2,0) tensors - with Fully symmetric 2-indices components w.r.t. (0, 1, 2) + Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring sage: M.symmetric_power(2).an_element() Type-(2,0) tensor on the Rank-3 free module M over the Integer Ring sage: M.symmetric_power(2).an_element().display() e_0⊗e_0 sage: M.symmetric_power(3) - Free module of type-(3,0) tensors - with Fully symmetric 3-indices components w.r.t. (0, 1, 2) + Free module of fully symmetric type-(3,0) tensors on the Rank-3 free module M over the Integer Ring sage: M.symmetric_power(3).an_element() Type-(3,0) tensor on the Rank-3 free module M over the Integer Ring @@ -1271,16 +1268,14 @@ def dual_symmetric_power(self, p): sage: M.dual_symmetric_power(1) # return the module itself Free module of type-(0,1) tensors on the Rank-3 free module M over the Integer Ring sage: M.dual_symmetric_power(2) - Free module of type-(0,2) tensors - with Fully symmetric 2-indices components w.r.t. (0, 1, 2) + Free module of fully symmetric type-(0,2) tensors on the Rank-3 free module M over the Integer Ring sage: M.dual_symmetric_power(2).an_element() Type-(0,2) tensor on the Rank-3 free module M over the Integer Ring sage: M.dual_symmetric_power(2).an_element().display() e^0⊗e^0 sage: M.dual_symmetric_power(3) - Free module of type-(0,3) tensors - with Fully symmetric 3-indices components w.r.t. (0, 1, 2) + Free module of fully symmetric type-(0,3) tensors on the Rank-3 free module M over the Integer Ring sage: M.dual_symmetric_power(3).an_element() Type-(0,3) tensor on the Rank-3 free module M over the Integer Ring diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 4609c68aec9..df0cee25764 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -41,34 +41,30 @@ class TensorFreeSubmodule_comp(TensorFreeModule): sage: latex(T60M) T^{(6, 0)}\left(M\right) sage: T40Sym45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((4, 5))); T40Sym45M - Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), + Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (4, 5) - on the Rank-3 free module M over the Integer Ring sage: T40Sym45M._name 'T^{0,1,2,3}(M)⊗Sym^{4,5}(M)' sage: latex(T40Sym45M) T^{\{0,1,2,3\}}(M) \otimes \mathrm{Sym}^{\{4,5\}}(M) sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))); Sym0123x45M - Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), + Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2, 3), with symmetry on the index positions (4, 5) - on the Rank-3 free module M over the Integer Ring sage: Sym0123x45M._name 'Sym^{0,1,2,3}(M)⊗Sym^{4,5}(M)' sage: latex(Sym0123x45M) \mathrm{Sym}^{\{0,1,2,3\}}(M) \otimes \mathrm{Sym}^{\{4,5\}}(M) sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))); Sym012x345M - Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), + Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2), with symmetry on the index positions (3, 4, 5) - on the Rank-3 free module M over the Integer Ring sage: Sym012x345M._name 'Sym^{0,1,2}(M)⊗Sym^{3,4,5}(M)' sage: latex(Sym012x345M) \mathrm{Sym}^{\{0,1,2\}}(M) \otimes \mathrm{Sym}^{\{3,4,5\}}(M) sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))); Sym012345M - Free module of type-(6,0) tensors - with Fully symmetric 6-indices components w.r.t. (0, 1, 2) + Free module of fully symmetric type-(6,0) tensors on the Rank-3 free module M over the Integer Ring sage: Sym012345M._name 'Sym^6(M)' @@ -90,10 +86,9 @@ class TensorFreeSubmodule_comp(TensorFreeModule): TESTS:: sage: T = TensorFreeSubmodule_comp(M, (4, 4), sym=((0, 1)), antisym=((4, 5))); T - Free module of type-(4,4) tensors with 8-indices components w.r.t. (0, 1, 2), + Free module of type-(4,4) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1), with antisymmetry on the index positions (4, 5) - on the Rank-3 free module M over the Integer Ring sage: T._name 'T^{2,3}(M)⊗T^{6,7}(M*)⊗Sym^{0,1}(M)⊗ASym^{4,5}(M*)' sage: latex(T) @@ -198,13 +193,13 @@ def _repr_(self): sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M - Free module of type-(2,0) tensors - with Fully symmetric 2-indices components w.r.t. (0, 1, 2) - on the Rank-3 free module M over the Integer Ring + Free module of fully symmetric type-(2,0) tensors + on the Rank-3 free module M over the Integer Ring """ - return "Free module of type-({},{}) tensors with {} on the {}".format( - self._tensor_type[0], self._tensor_type[1], self._basis_comp(), self._fmodule) + prefix, suffix = self._basis_comp()._repr_symmetry() + return "Free module of {}type-({},{}) tensors on the {}{}".format( + prefix.lower(), self._tensor_type[0], self._tensor_type[1], self._fmodule, suffix) def _is_symmetry_coarsening_of(self, coarser_comp, finer_comp): self_tensor_type = self.tensor_type() @@ -261,10 +256,9 @@ def _element_constructor_(self, comp=[], basis=None, name=None, Traceback (most recent call last): ... ValueError: this tensor does not have the symmetries of - Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), + Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2, 3), with symmetry on the index positions (4, 5) - on the Rank-3 free module M over the Integer Ring sage: t = Sym0123x45M(e[0]*e[0]*e[0]*e[0]*e[1]*e[2] + e[0]*e[0]*e[0]*e[0]*e[2]*e[1]); t.disp() e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 + e_0⊗e_0⊗e_0⊗e_0⊗e_2⊗e_1 sage: t.parent()._name @@ -353,13 +347,10 @@ def lift(self): sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) sage: Sym0123x45M.lift Generic morphism: - From: Free module of type-(6,0) tensors - with 6-indices components w.r.t. (0, 1, 2), - with symmetry on the index positions (0, 1, 2, 3), - with symmetry on the index positions (4, 5) - on the Rank-3 free module M over the Integer Ring - To: Free module of type-(6,0) tensors - on the Rank-3 free module M over the Integer Ring + From: Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, + with symmetry on the index positions (0, 1, 2, 3), + with symmetry on the index positions (4, 5) + To: Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring """ return self.module_morphism(function=lambda x: x, codomain=self.ambient()) @@ -379,7 +370,8 @@ def reduce(self): sage: X = M.tensor_module(6, 0) sage: Y = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: Y.reduce - Generic endomorphism of Free module of type-(6,0) tensors on the 3-dimensional vector space M over the Rational Field + Generic endomorphism of + Free module of type-(6,0) tensors on the 3-dimensional vector space M over the Rational Field sage: t = e[0]*e[0]*e[0]*e[0]*e[1]*e[2]; t.disp() e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 = e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 sage: r = Y.reduce(t); r @@ -396,7 +388,8 @@ def reduce(self): sage: X = M.tensor_module(6, 0) sage: Y = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: Y.reduce - Generic endomorphism of Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring + Generic endomorphism of + Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring sage: t = e[0]*e[0]*e[0]*e[0]*e[1]*e[2]; t.disp() e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 = e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 sage: Y.reduce(t) @@ -452,10 +445,9 @@ def retract(self): sage: Y.retract Generic morphism: From: Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring - To: Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), - with symmetry on the index positions (0, 1, 2, 3), - with symmetry on the index positions (4, 5) - on the Rank-3 free module M over the Integer Ring + To: Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, + with symmetry on the index positions (0, 1, 2, 3), + with symmetry on the index positions (4, 5) sage: t = e[0]*e[0]*e[0]*e[0]*e[1]*e[2]; t.disp() e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 = e_0⊗e_0⊗e_0⊗e_0⊗e_1⊗e_2 @@ -463,10 +455,9 @@ def retract(self): Traceback (most recent call last): ... ValueError: this tensor does not have the symmetries of - Free module of type-(6,0) tensors with 6-indices components w.r.t. (0, 1, 2), + Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2, 3), with symmetry on the index positions (4, 5) - on the Rank-3 free module M over the Integer Ring sage: t = e[0]*e[0]*e[0]*e[0]*e[1]*e[2] + e[0]*e[0]*e[0]*e[0]*e[2]*e[1] sage: y = Y.retract(t); y Type-(6,0) tensor on the Rank-3 free module M over the Integer Ring From 2cc42fb294ebd8c7f24b3260d82c55f3338b7b1a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 10:00:49 -0700 Subject: [PATCH 343/742] src/sage/tensor/modules/tensor_free_submodule_basis.py: Update doctest output --- src/sage/tensor/modules/tensor_free_submodule_basis.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index 731242d2f50..1474bcbf3e2 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -113,9 +113,7 @@ def __getitem__(self, index): sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M - Free module of type-(2,0) tensors - with Fully symmetric 2-indices components w.r.t. (0, 1, 2) - on the Rank-3 free module M over the Integer Ring + Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring sage: eSym2M = Sym2M.basis('e') sage: eSym2M[1, 1].display() e_1⊗e_1 From 02cce265a8a17ed35a72e1bf556c19639c716c73 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 10:03:02 -0700 Subject: [PATCH 344/742] src/sage/tensor/modules/tensor_free_submodule_basis.py: Fix pyflakes unused warnings --- src/sage/tensor/modules/tensor_free_submodule_basis.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index 1474bcbf3e2..88875a4efa7 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -3,7 +3,7 @@ """ #****************************************************************************** -# Copyright (C) 2020 Matthias Koeppe +# Copyright (C) 2020-2022 Matthias Koeppe # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -12,7 +12,7 @@ #****************************************************************************** from sage.tensor.modules.free_module_basis import Basis_abstract -from sage.tensor.modules.comp import Components + class TensorFreeSubmoduleBasis_comp(Basis_abstract): r""" @@ -122,7 +122,6 @@ def __getitem__(self, index): """ tensor_module = self._fmodule - base_module = tensor_module.base_module() base_module_basis = self._base_module_basis element = tensor_module([]) element.set_comp(base_module_basis)[index] = 1 From bff49e5ba567a7c73cf6cc89885c3252ec20492d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 10:10:19 -0700 Subject: [PATCH 345/742] src/sage/tensor/modules/tensor_free_module.py: Update doctest output --- src/sage/tensor/modules/tensor_free_module.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 25cfa23ca6f..e3dae4c71b4 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -754,8 +754,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)) sage: e_Sym2M = Sym2M.basis('e'); e_Sym2M Standard basis on the - Free module of type-(2,0) tensors with Fully symmetric 2-indices components w.r.t. (0, 1, 2) - on the Rank-3 free module M over the Integer Ring + Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring induced by Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring sage: for a in e_Sym2M: a.display() e_0⊗e_0 From 89a5893fdaf7c8d26edcbd70815ecea53ef472ff Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 10:20:01 -0700 Subject: [PATCH 346/742] src/sage/tensor/modules/tensor_free_[sub]module.py (_basis_comp): Add docstrings --- src/sage/tensor/modules/tensor_free_module.py | 17 ++++++++++++++++- .../tensor/modules/tensor_free_submodule.py | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index e3dae4c71b4..e36bbe82071 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -770,7 +770,22 @@ def basis(self, symbol, latex_symbol=None, from_family=None, @cached_method def _basis_comp(self): - # Data for TensorFreeSubmoduleBasis_comp + r""" + Return an instance of :class:`~sage.tensor.modules.comp.Components`. + + This implementation returns an instance without symmetry. + + The subclass :class:`~sage.tensor.modules.tensor_free_submodule.TensorFreeSubmodule_comp` + overrides this method to encode the prescribed symmetry of the submodule. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: T = M.tensor_module(1,1) + sage: c = T._basis_comp(); c + 2-indices components w.r.t. (0, 1, 2) + + """ frame = tuple(self.base_module().irange()) tensor = self.ambient()() return tensor._new_comp(frame) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index df0cee25764..29e99dc6a94 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -179,6 +179,21 @@ def power_name(op, s, latex=False): @cached_method def _basis_comp(self): + r""" + Return an instance of :class:`~sage.tensor.modules.comp.Components`. + + It encodes the prescribed symmetry of ``self``. + + EXAMPLES:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M + Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring + sage: c = Sym2M._basis_comp(); c + Fully symmetric 2-indices components w.r.t. (0, 1, 2) + + """ frame = tuple(self.base_module().irange()) # Need to call _element_constructor_ explicitly, or the passed arguments are dropped tensor = self.ambient()._element_constructor_(sym=self._sym, antisym=self._antisym) From c8d987723dfca75236c0a45654c86e6fb40f92a6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 10:36:45 -0700 Subject: [PATCH 347/742] TensorFreeSubmodule_comp._is_symmetry_coarsening_of: Add docstring --- .../tensor/modules/tensor_free_submodule.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 29e99dc6a94..696af271272 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -217,6 +217,33 @@ def _repr_(self): prefix.lower(), self._tensor_type[0], self._tensor_type[1], self._fmodule, suffix) def _is_symmetry_coarsening_of(self, coarser_comp, finer_comp): + r""" + Return whether ``coarser_comp`` has coarser symmetry than ``finer_comp``. + + INPUT: + + - ``coarser_comp``, ``finer_comp``: :class:`~sage.tensor.modules.comp.Components` + + EXAMPLES:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: T60M = M.tensor_module(6, 0) + sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: com0123x45M = Sym0123x45M.an_element()._components[e]; com0123x45M + 6-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring + sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) + sage: com012x345M = Sym012x345M.an_element()._components[e]; com012x345M + 6-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring + sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) + sage: com012345M = Sym012345M.an_element()._components[e]; com012345M + 6-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring + sage: Sym0123x45M._is_symmetry_coarsening_of(com0123x45M, com012x345M) + True + sage: Sym0123x45M._is_symmetry_coarsening_of(com012345M, com012x345M) + True + """ self_tensor_type = self.tensor_type() def sym_antisym(comp): From e31bdacb80a880a557448fe712aaeba4232c3693 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 10:40:18 -0700 Subject: [PATCH 348/742] TensorFreeModule._an_element_: Pass parent to element class --- src/sage/tensor/modules/tensor_free_module.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index e36bbe82071..8984e01396e 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -552,8 +552,18 @@ def _an_element_(self): sage: M.tensor_module(2,3)._an_element_().display() 1/2 e_0⊗e_0⊗e^0⊗e^0⊗e^0 + TESTS:: + + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: T60M = M.tensor_module(6, 0) + sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: t = Sym0123x45M._an_element_() + sage: t.parent() is Sym0123x45M + True """ - resu = self.element_class(self._fmodule, self._tensor_type) + resu = self.element_class(self._fmodule, self._tensor_type, parent=self) # Make sure that the base module has a default basis self._fmodule.an_element() sindex = self._fmodule._sindex From e7d5e77161b2b9b8d8a15d10e702c559bc60c19b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 11:14:13 -0700 Subject: [PATCH 349/742] TensorFreeModule._an_element_: Use element constructor --- src/sage/tensor/modules/tensor_free_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 8984e01396e..d4f000d7be6 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -563,7 +563,7 @@ def _an_element_(self): sage: t.parent() is Sym0123x45M True """ - resu = self.element_class(self._fmodule, self._tensor_type, parent=self) + resu = self([]) # Make sure that the base module has a default basis self._fmodule.an_element() sindex = self._fmodule._sindex From 18d3dbee5d5d2703c2a335ea5627735fe2116a25 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 11:15:41 -0700 Subject: [PATCH 350/742] TensorFreeSubmodule_comp._is_symmetry_coarsening_of: Update example --- .../tensor/modules/tensor_free_submodule.py | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 696af271272..dc94ace3343 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -231,16 +231,29 @@ def _is_symmetry_coarsening_of(self, coarser_comp, finer_comp): sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0) sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) - sage: com0123x45M = Sym0123x45M.an_element()._components[e]; com0123x45M - 6-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring + sage: ten0123x45M = Sym0123x45M.an_element(); ten0123x45M + Type-(6,0) tensor on the Rank-3 free module M over the Integer Ring + sage: ten0123x45M.parent() + Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, + with symmetry on the index positions (0, 1, 2, 3), + with symmetry on the index positions (4, 5) + sage: com0123x45M = ten0123x45M._components[e]; com0123x45M + 6-indices components w.r.t. Basis (e_0,e_1,e_2) + on the Rank-3 free module M over the Integer Ring, + with symmetry on the index positions (0, 1, 2, 3), + with symmetry on the index positions (4, 5) sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) sage: com012x345M = Sym012x345M.an_element()._components[e]; com012x345M - 6-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring + 6-indices components w.r.t. Basis (e_0,e_1,e_2) + on the Rank-3 free module M over the Integer Ring, + with symmetry on the index positions (0, 1, 2), + with symmetry on the index positions (3, 4, 5) sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) sage: com012345M = Sym012345M.an_element()._components[e]; com012345M - 6-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring + Fully symmetric 6-indices components w.r.t. Basis (e_0,e_1,e_2) + on the Rank-3 free module M over the Integer Ring sage: Sym0123x45M._is_symmetry_coarsening_of(com0123x45M, com012x345M) - True + False sage: Sym0123x45M._is_symmetry_coarsening_of(com012345M, com012x345M) True """ From 3f1c33d718a59e7fd6b0c06e032ca43fff9ecdb2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 11:17:31 -0700 Subject: [PATCH 351/742] TensorFreeSubmoduleBasis_comp.__init__: Add doctest --- src/sage/tensor/modules/tensor_free_submodule_basis.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index 88875a4efa7..ae00f98971b 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -38,6 +38,15 @@ class TensorFreeSubmoduleBasis_comp(Basis_abstract): def __init__(self, tensor_module, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): + r""" + TESTS:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: T11 = M.tensor_module(1,1) + sage: e_T11 = T11.basis('e') + sage: TestSuite(e_T11).run() + """ base_module = tensor_module.base_module() base_module_basis = base_module.basis(symbol, latex_symbol, indices, latex_indices, symbol_dual, latex_symbol_dual) From 9378a78970b4202074d44e21f42550a9a597337f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 11:22:14 -0700 Subject: [PATCH 352/742] src/sage/tensor/modules/finite_rank_free_module.py: Update doctest output --- src/sage/tensor/modules/finite_rank_free_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 08b3873dfbc..b9a3e543eb1 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1271,7 +1271,7 @@ def dual_symmetric_power(self, p): Free module of fully symmetric type-(0,2) tensors on the Rank-3 free module M over the Integer Ring sage: M.dual_symmetric_power(2).an_element() - Type-(0,2) tensor on the Rank-3 free module M over the Integer Ring + Symmetric bilinear form on the Rank-3 free module M over the Integer Ring sage: M.dual_symmetric_power(2).an_element().display() e^0⊗e^0 sage: M.dual_symmetric_power(3) From f49622335a78c1ae3852d2662ae39145e786b426 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 12:18:24 -0700 Subject: [PATCH 353/742] FiniteRankFreeModule_abstract._test_isomorphism_with_fixed_basis: Do nothing if there is no basis method --- src/sage/tensor/modules/finite_rank_free_module.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index ad444876994..7d25a569e96 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -961,7 +961,10 @@ def _test_isomorphism_with_fixed_basis(self, **options): sage: M._test_isomorphism_with_fixed_basis() """ tester = self._tester(**options) - basis = self.basis('test') + try: + basis = self.basis('test') + except AttributeError: + return morphism = self.isomorphism_with_fixed_basis(basis) tester.assertEqual(morphism.codomain().rank(), self.rank()) From d341422efb34d3f5ad759897ad15362263b96f33 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 12:23:30 -0700 Subject: [PATCH 354/742] src/sage/tensor/modules/finite_rank_free_module.py: Update doctest output --- .../tensor/modules/finite_rank_free_module.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 7d25a569e96..d746f922309 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -849,17 +849,14 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): Same but explicitly in the subspace of symmetric bilinear forms:: sage: Sym2Vdual = V.dual_symmetric_power(2); Sym2Vdual - Free module of type-(0,2) tensors - with Fully symmetric 2-indices components w.r.t. (1, 2, 3) - on the 3-dimensional vector space over the Rational Field + Free module of fully symmetric type-(0,2) tensors on the 3-dimensional vector space over the Rational Field sage: Sym2Vdual.is_submodule(T02) True sage: Sym2Vdual.rank() 6 sage: e_Sym2Vdual = Sym2Vdual.basis("e"); e_Sym2Vdual - Standard basis on the Free module of type-(0,2) tensors - with Fully symmetric 2-indices components w.r.t. (1, 2, 3) - on the 3-dimensional vector space over the Rational Field + Standard basis on the + Free module of fully symmetric type-(0,2) tensors on the 3-dimensional vector space over the Rational Field induced by Basis (e_1,e_2,e_3) on the 3-dimensional vector space over the Rational Field sage: W_basis = [phi_e_T02(b) for b in e_Sym2Vdual]; W_basis [ @@ -871,10 +868,8 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): Free module generated by {0, 1, 2, 3, 4, 5} over Rational Field sage: phi_e_Sym2Vdual = Sym2Vdual.isomorphism_with_fixed_basis(e_Sym2Vdual, codomain=W); phi_e_Sym2Vdual Generic morphism: - From: Free module of type-(0,2) tensors - with Fully symmetric 2-indices components w.r.t. (1, 2, 3) - on the 3-dimensional vector space over the Rational Field - To: Free module generated by {0, 1, 2, 3, 4, 5} over Rational Field + From: Free module of fully symmetric type-(0,2) tensors on the 3-dimensional vector space over the Rational Field + To: Free module generated by {0, 1, 2, 3, 4, 5} over Rational Field Sending tensors to elements of the tensor square of :class:`CombinatorialFreeModule`:: From c42118a437ccfd7f7975869925ef5b56d503c1bf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 14:06:48 -0700 Subject: [PATCH 355/742] src/sage/manifolds/differentiable/tangent_space.py: Add example: isomorphism with inner product space --- .../manifolds/differentiable/tangent_space.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/sage/manifolds/differentiable/tangent_space.py b/src/sage/manifolds/differentiable/tangent_space.py index 0825f867e5e..f2a5afa73b0 100644 --- a/src/sage/manifolds/differentiable/tangent_space.py +++ b/src/sage/manifolds/differentiable/tangent_space.py @@ -162,6 +162,58 @@ class TangentSpace(FiniteRankFreeModule): sage: p2 == p True + An isomorphism of the tangent space with an inner product space with distinguished basis:: + + sage: g = M.metric('g') + sage: g[:] = ((1, 0), (0, 1)) + sage: Q_Tp_xy = g[c_xy.frame(),:](*p.coordinates(c_xy)); Q_Tp_xy + [1 0] + [0 1] + sage: W_Tp_xy = VectorSpace(SR, 2, inner_product_matrix=Q_Tp_xy) + sage: Tp.bases()[0] + Basis (∂/∂x,∂/∂y) on the Tangent space at Point p on the 2-dimensional differentiable manifold M + sage: phi_Tp_xy = Tp.isomorphism_with_fixed_basis(Tp.bases()[0], codomain=W_Tp_xy); phi_Tp_xy + Generic morphism: + From: Tangent space at Point p on the 2-dimensional differentiable manifold M + To: Ambient quadratic space of dimension 2 over Symbolic Ring + Inner product matrix: + [1 0] + [0 1] + + sage: Q_Tp_uv = g[c_uv.frame(),:](*p.coordinates(c_uv)); Q_Tp_uv + [1/2 0] + [ 0 1/2] + sage: W_Tp_uv = VectorSpace(SR, 2, inner_product_matrix=Q_Tp_uv) + sage: Tp.bases()[1] + Basis (∂/∂u,∂/∂v) on the Tangent space at Point p on the 2-dimensional differentiable manifold M + sage: phi_Tp_uv = Tp.isomorphism_with_fixed_basis(Tp.bases()[1], codomain=W_Tp_uv); phi_Tp_uv + Generic morphism: + From: Tangent space at Point p on the 2-dimensional differentiable manifold M + To: Ambient quadratic space of dimension 2 over Symbolic Ring + Inner product matrix: + [1/2 0] + [ 0 1/2] + + sage: t1, t2 = Tp.tensor((1,0)), Tp.tensor((1,0)) + sage: t1[:] = (8, 15) + sage: t2[:] = (47, 11) + sage: t1[Tp.bases()[0],:] + [8, 15] + sage: phi_Tp_xy(t1), phi_Tp_xy(t2) + ((8, 15), (47, 11)) + sage: phi_Tp_xy(t1).inner_product(phi_Tp_xy(t2)) + 541 + + sage: Tp_xy_to_uv = M.change_of_frame(c_xy.frame(), c_uv.frame()).at(p); Tp_xy_to_uv + Automorphism of the Tangent space at Point p on the 2-dimensional differentiable manifold M + sage: Tp.set_change_of_basis(Tp.bases()[0], Tp.bases()[1], Tp_xy_to_uv) + sage: t1[Tp.bases()[1],:] + [23, -7] + sage: phi_Tp_uv(t1), phi_Tp_uv(t2) + ((23, -7), (58, 36)) + sage: phi_Tp_uv(t1).inner_product(phi_Tp_uv(t2)) + 541 + .. SEEALSO:: :class:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule` From aaf46cc4c275e6fa6be216cf24525ea57d6d0367 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 16:18:10 -0700 Subject: [PATCH 356/742] DifferentiableManifold.tangent_space, TangentSpace: Accept keyword 'base_ring' --- src/sage/manifolds/differentiable/manifold.py | 6 ++++-- src/sage/manifolds/differentiable/tangent_space.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index d5e0ebc6200..7fa589be987 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -3403,7 +3403,7 @@ def is_manifestly_parallelizable(self): """ return bool(self._covering_frames) - def tangent_space(self, point): + def tangent_space(self, point, base_ring=None): r""" Tangent space to ``self`` at a given point. @@ -3412,6 +3412,8 @@ def tangent_space(self, point): - ``point`` -- :class:`~sage.manifolds.point.ManifoldPoint`; point `p` on the manifold + - ``base_ring`` -- (default: the symbolic ring) the base ring + OUTPUT: - :class:`~sage.manifolds.differentiable.tangent_space.TangentSpace` @@ -3445,7 +3447,7 @@ def tangent_space(self, point): raise TypeError("{} is not a manifold point".format(point)) if point not in self: raise ValueError("{} is not a point on the {}".format(point, self)) - return TangentSpace(point) + return TangentSpace(point, base_ring=base_ring) def curve(self, coord_expression, param, chart=None, name=None, latex_name=None): diff --git a/src/sage/manifolds/differentiable/tangent_space.py b/src/sage/manifolds/differentiable/tangent_space.py index f2a5afa73b0..a53dbd41788 100644 --- a/src/sage/manifolds/differentiable/tangent_space.py +++ b/src/sage/manifolds/differentiable/tangent_space.py @@ -222,7 +222,7 @@ class TangentSpace(FiniteRankFreeModule): """ Element = TangentVector - def __init__(self, point): + def __init__(self, point, base_ring=None): r""" Construct the tangent space at a given point. @@ -243,7 +243,9 @@ def __init__(self, point): latex_name = r"T_{%s}\,%s"%(point._latex_name, manif._latex_name) self._point = point self._manif = manif - FiniteRankFreeModule.__init__(self, SR, manif._dim, name=name, + if base_ring is None: + base_ring = SR + FiniteRankFreeModule.__init__(self, base_ring, manif._dim, name=name, latex_name=latex_name, start_index=manif._sindex) # Initialization of bases of the tangent space from existing vector From 6cd438c7e2f7f01118e8203a97c7d02f31b680e7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 16:18:52 -0700 Subject: [PATCH 357/742] StandardSymplecticSpace: Add example: isomorphism with inner product space --- .../examples/symplectic_space.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/manifolds/differentiable/examples/symplectic_space.py b/src/sage/manifolds/differentiable/examples/symplectic_space.py index 34c557cf830..623979ed7f3 100644 --- a/src/sage/manifolds/differentiable/examples/symplectic_space.py +++ b/src/sage/manifolds/differentiable/examples/symplectic_space.py @@ -91,6 +91,28 @@ def __init__( sage: omega = M.symplectic_form() sage: omega.display() omega = -dq∧dp + + An isomomorphism of its tangent space (at any point) with an indefinite inner product space + with distinguished basis:: + + sage: Q_M_qp = omega[:]; Q_M_qp + [ 0 -1] + [ 1 0] + sage: W_M_qp = VectorSpace(RR, 2, inner_product_matrix=Q_M_qp); W_M_qp + Ambient quadratic space of dimension 2 over Real Field with 53 bits of precision + Inner product matrix: + [0.000000000000000 -1.00000000000000] + [ 1.00000000000000 0.000000000000000] + sage: T = M.tangent_space(M.point(), base_ring=RR); T + Tangent space at Point on the Standard symplectic space R2 + sage: phi_M_qp = T.isomorphism_with_fixed_basis(T.default_basis(), codomain=W_M_qp); phi_M_qp + Generic morphism: + From: Tangent space at Point on the Standard symplectic space R2 + To: Ambient quadratic space of dimension 2 over Real Field with 53 bits of precision + Inner product matrix: + [0.000000000000000 -1.00000000000000] + [ 1.00000000000000 0.000000000000000] + """ # Check that manifold is even dimensional if dimension % 2 == 1: From cfec1e0f0ba419e838338bccd684bb511a0d843f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 29 Aug 2022 09:30:06 +0900 Subject: [PATCH 358/742] Making uninitialized series g have bool(g) == True. Better define() semantic with exact and non lazy series elements. --- src/sage/rings/lazy_series.py | 80 ++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 5755409009f..e9acf69c16a 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -569,6 +569,9 @@ def __bool__(self): """ Test whether ``self`` is not zero. + An unitialized series returns ``True`` as it is considered as a + formal variable, such as a generator of a polynomial ring. + TESTS:: sage: L. = LazyLaurentSeriesRing(GF(2)) @@ -603,11 +606,41 @@ def __bool__(self): 1 sage: bool(M) True + + Uninitialized series:: + + sage: g = L(None, valuation=0) + sage: bool(g) + True + sage: g.define(0) + sage: bool(g) + False + + sage: g = L(None, valuation=0) + sage: bool(g) + True + sage: g.define(1 + z) + sage: bool(g) + True + + sage: g = L(None, valuation=0) + sage: bool(g) + True + sage: g.define(1 + z*g) + sage: bool(g) + True """ if isinstance(self._coeff_stream, Stream_zero): return False if isinstance(self._coeff_stream, Stream_exact): return True + if isinstance(self._coeff_stream, Stream_uninitialized): + if self._coeff_stream._target is None: + return True + if isinstance(self._coeff_stream._target, Stream_zero): + return False + if isinstance(self._coeff_stream._target, Stream_exact): + return True if self.parent()._sparse: cache = self._coeff_stream._cache if any(cache[a] for a in cache): @@ -625,7 +658,7 @@ def define(self, s): INPUT: - - ``s`` -- a Laurent polynomial + - ``s`` -- a lazy series EXAMPLES: @@ -756,6 +789,16 @@ def define(self, s): ... ValueError: series already defined + sage: e = L(None, valuation=0) + sage: e.define(1) + sage: e + 1 + + sage: e = L(None, valuation=0) + sage: e.define((1 + z).polynomial()) + sage: e + 1 + z + sage: D = LazyDirichletSeriesRing(QQ, "s") sage: L. = LazyLaurentSeriesRing(QQ) sage: e = L(lambda n: 1/factorial(n), 0) @@ -767,6 +810,15 @@ def define(self, s): """ if not isinstance(self._coeff_stream, Stream_uninitialized) or self._coeff_stream._target is not None: raise ValueError("series already defined") + + if not isinstance(s, LazyModuleElement): + s = self.parent()(s) + + # Special case when it has a trivial definition + if isinstance(s._coeff_stream, (Stream_zero, Stream_exact)): + self._coeff_stream = s._coeff_stream + return + self._coeff_stream._target = s._coeff_stream # an alias for compatibility with padics @@ -2878,6 +2930,15 @@ def __call__(self, g, *, check=True): 3 sage: parent(three) Univariate Polynomial Ring in x over Rational Field + + Consistency check when `g` is an uninitialized series between a + polynomial `f` as both a polynomial and a lazy series:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: f = 1 + z + sage: g = L(None, valuation=0) + sage: f(g) == f.polynomial()(g) + True """ # f = self and compute f(g) from sage.structure.element import get_coercion_model @@ -3490,6 +3551,23 @@ def __call__(self, *g, check=True): ... TypeError: no common canonical parent for objects with parents: ... + Consistency check when `g` is an uninitialized series between a + polynomial `f` as both a polynomial and a lazy series:: + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: f = 1 - z + sage: g = L(None, valuation=1) + sage: f(g) == f.polynomial()(g) + True + + sage: g = L(None, valuation=1) + sage: g.define(z / (1 - g)) + sage: g + z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) + sage: gp = L(None, valuation=1) + sage: gp.define(z / f(gp)) + sage: gp + z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) """ if len(g) != len(self.parent().variable_names()): raise ValueError("arity of must be equal to the number of arguments provided") From 47c91eac9910b090ed5dcba24cfeaea89effb3f0 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 29 Aug 2022 10:13:59 +0800 Subject: [PATCH 359/742] fix book doctests --- .../polynomes_doctest.py | 6 +++--- .../sol/polynomes_doctest.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py index 452a116401d..951bfb2b5c6 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py @@ -267,7 +267,7 @@ sage: A = Integers(101); R. = A[] sage: f6 = sum( (i+1)^2 * x^i for i in (0..5) ); f6 36*x^5 + 25*x^4 + 16*x^3 + 9*x^2 + 4*x + 1 - sage: num, den = f6.rational_reconstruct(x^6, 1, 3); num/den + sage: num, den = f6.rational_reconstruction(x^6, 1, 3); num/den (100*x + 100)/(x^3 + 98*x^2 + 3*x + 100) Sage example in ./polynomes.tex, line 1611:: @@ -283,7 +283,7 @@ Sage example in ./polynomes.tex, line 1677:: - sage: num, den = ZpZx(s).rational_reconstruct(ZpZx(x)^10,4,5) + sage: num, den = ZpZx(s).rational_reconstruction(ZpZx(x)^10,4,5) sage: num/den (1073741779*x^3 + 105*x)/(x^4 + 1073741744*x^2 + 105) @@ -304,7 +304,7 @@ sage: def mypade(pol, n, k): ....: x = ZpZx.gen(); - ....: n,d = ZpZx(pol).rational_reconstruct(x^n, k-1, n-k) + ....: n,d = ZpZx(pol).rational_reconstruction(x^n, k-1, n-k) ....: return Qx(list(map(lift_sym, n)))/Qx(list(map(lift_sym, d))) Sage example in ./polynomes.tex, line 1813:: diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py index 15f60192153..2908f38254d 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py @@ -91,7 +91,7 @@ Sage example in ./sol/polynomes.tex, line 428:: - sage: s.rational_reconstruct(mul(x-i for i in range(4)), 1, 2) + sage: s.rational_reconstruction(mul(x-i for i in range(4)), 1, 2) (15*x + 2, x^2 + 11*x + 15) Sage example in ./sol/polynomes.tex, line 454:: From 9ce4fed2d9a4e0294e2aed31de08477ebfdb96f6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 19:25:19 -0700 Subject: [PATCH 360/742] FiniteRankFreeModule, VectorFieldModule, VectorFieldFreeModule: Method tensor has to double as the functorial construction --- .../manifolds/differentiable/vectorfield_module.py | 6 ++++-- src/sage/tensor/modules/finite_rank_free_module.py | 10 +++++++++- src/sage/tensor/modules/tensor_free_module.py | 5 +++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index cf3f1dc687d..b2a1d76ad73 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -713,7 +713,7 @@ def general_linear_group(self): self._general_linear_group = AutomorphismFieldGroup(self) return self._general_linear_group - def tensor(self, tensor_type, name=None, latex_name=None, sym=None, + def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, antisym=None, specific_type=None): r""" Construct a tensor on ``self``. @@ -820,6 +820,8 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, tensor_type, name=name, latex_name=latex_name, sym=sym, antisym=antisym) + tensor = FiniteRankFreeModule.tensor + def alternating_contravariant_tensor(self, degree, name=None, latex_name=None): r""" @@ -2024,7 +2026,7 @@ def basis(self, symbol=None, latex_symbol=None, from_frame=None, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) - def tensor(self, tensor_type, name=None, latex_name=None, sym=None, + def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, antisym=None, specific_type=None): r""" Construct a tensor on ``self``. diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index f208d80549a..121dcaa5723 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1802,7 +1802,7 @@ def _test_basis(self, tester=None, **options): TestSuite(b).run(verbose=tester._verbose, prefix=tester._prefix + " ", raise_on_failure=is_sub_testsuite) - def tensor(self, tensor_type, name=None, latex_name=None, sym=None, + def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, antisym=None): r""" Construct a tensor on the free module ``self``. @@ -1893,6 +1893,14 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, tensor_type, name=name, latex_name=latex_name, sym=sym, antisym=antisym) + def tensor(self, *args, **kwds): + # Until https://trac.sagemath.org/ticket/30373 is done, + # TensorProductFunctor._functor_name is "tensor", so this method + # also needs to double as the tensor product construction + if isinstance(args[0], Parent): + return self.tensor_product(*args, **kwds) + return self._tensor(*args, **kwds) + def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): r""" Construct a tensor on ``self`` from a set of components. diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index aabc06adee2..4863bc7dc35 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -811,3 +811,8 @@ def _basis_comp(self): frame = tuple(self.base_module().irange()) tensor = self.ambient()() return tensor._new_comp(frame) + + # Until https://trac.sagemath.org/ticket/30373 is done, + # TensorProductFunctor._functor_name is "tensor" + def tensor(self, *others): + return self.tensor_product(*others) From 87c93925a893d5d1bdbd3aa316f454a8ac0958c4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 19:27:29 -0700 Subject: [PATCH 361/742] TensorFreeModule: Use Modules().TensorProducts() except for type (0,1) --- src/sage/manifolds/differentiable/manifold.py | 6 ++-- .../differentiable/tensorfield_module.py | 4 +-- src/sage/tensor/modules/tensor_free_module.py | 36 ++++++++++++++----- .../tensor/modules/tensor_free_submodule.py | 6 ++++ 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index d5e0ebc6200..c16ca0bff0e 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -1438,9 +1438,9 @@ def tensor_field_module(self, tensor_type, dest_map=None): Free module T^(2,1)(U) of type-(2,1) tensors fields on the Open subset U of the 3-dimensional differentiable manifold M sage: TU.category() - Category of finite dimensional modules over Algebra of - differentiable scalar fields on the Open subset U of the - 3-dimensional differentiable manifold M + Category of tensor products of finite dimensional modules + over Algebra of differentiable scalar fields + on the Open subset U of the 3-dimensional differentiable manifold M sage: TU.base_ring() Algebra of differentiable scalar fields on the Open subset U of the 3-dimensional differentiable manifold M diff --git a/src/sage/manifolds/differentiable/tensorfield_module.py b/src/sage/manifolds/differentiable/tensorfield_module.py index d68264a472c..cbc73f9e520 100644 --- a/src/sage/manifolds/differentiable/tensorfield_module.py +++ b/src/sage/manifolds/differentiable/tensorfield_module.py @@ -652,8 +652,8 @@ class TensorFieldFreeModule(TensorFreeModule): `T^{(2,0)}(\RR^3)` is a module over the algebra `C^k(\RR^3)`:: sage: T20.category() - Category of finite dimensional modules over Algebra of differentiable - scalar fields on the 3-dimensional differentiable manifold R^3 + Category of tensor products of finite dimensional modules over + Algebra of differentiable scalar fields on the 3-dimensional differentiable manifold R^3 sage: T20.base_ring() is M.scalar_field_algebra() True diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 4863bc7dc35..792c1ee8a86 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -58,6 +58,7 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.categories.modules import Modules from sage.misc.cachefunc import cached_method from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule_abstract from sage.tensor.modules.free_module_tensor import FreeModuleTensor @@ -126,7 +127,7 @@ class TensorFreeModule(FiniteRankFreeModule_abstract): ``T`` is a module (actually a free module) over `\ZZ`:: sage: T.category() - Category of finite dimensional modules over Integer Ring + Category of tensor products of finite dimensional modules over Integer Ring sage: T in Modules(ZZ) True sage: T.rank() @@ -364,7 +365,7 @@ class TensorFreeModule(FiniteRankFreeModule_abstract): Element = FreeModuleTensor - def __init__(self, fmodule, tensor_type, name=None, latex_name=None): + def __init__(self, fmodule, tensor_type, name=None, latex_name=None, category=None): r""" TESTS:: @@ -375,33 +376,50 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None): """ self._fmodule = fmodule self._tensor_type = tuple(tensor_type) + ring = fmodule._ring rank = pow(fmodule._rank, tensor_type[0] + tensor_type[1]) if self._tensor_type == (0,1): # case of the dual + category = Modules(ring).FiniteDimensional().or_subcategory(category) if name is None and fmodule._name is not None: name = fmodule._name + '*' if latex_name is None and fmodule._latex_name is not None: latex_name = fmodule._latex_name + r'^*' else: + category = Modules(ring).FiniteDimensional().TensorProducts().or_subcategory(category) if name is None and fmodule._name is not None: name = 'T^' + str(self._tensor_type) + '(' + fmodule._name + \ ')' if latex_name is None and fmodule._latex_name is not None: latex_name = r'T^{' + str(self._tensor_type) + r'}\left(' + \ fmodule._latex_name + r'\right)' - super().__init__(fmodule._ring, rank, name=name, latex_name=latex_name) + super().__init__(fmodule._ring, rank, name=name, latex_name=latex_name, category=category) fmodule._all_modules.add(self) - def construction(self): + def tensor_factors(self): r""" - TESTS:: + Return the tensor factors of this tensor module. + + EXAMPLES:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: T = M.tensor_module(2, 3) - sage: T.construction() is None - True + sage: T.tensor_factors() + [Rank-3 free module M over the Integer Ring, + Rank-3 free module M over the Integer Ring, + Free module of type-(0,1) tensors on the Rank-3 free module M over the Integer Ring, + Free module of type-(0,1) tensors on the Rank-3 free module M over the Integer Ring, + Free module of type-(0,1) tensors on the Rank-3 free module M over the Integer Ring] """ - # No construction until https://trac.sagemath.org/ticket/31276 provides tensor_product methods - return None + if self._tensor_type == (0,1): # case of the dual + raise NotImplementedError + factors = [self._fmodule] * self._tensor_type[0] + # Until https://trac.sagemath.org/ticket/30241 is done, the dual is identified with + # ExtPowerDualFreeModule of degree 1. But that class does not have a tensor_product method, + # so we use instead the (0,1)-tensor module. + dmodule = self._fmodule.tensor_module(0, 1) + if self._tensor_type[1]: + factors += [dmodule] * self._tensor_type[1] + return factors #### Parent Methods diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index dc94ace3343..c8da4e86471 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -177,6 +177,12 @@ def power_name(op, s, latex=False): latex_name=latex_name, category=category, ambient=ambient) + def tensor_factors(self): + raise NotImplementedError + + def construction(self): + return None + @cached_method def _basis_comp(self): r""" From d92122d3517eb0025ec4b8ac970a358279eea0c9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 19:43:59 -0700 Subject: [PATCH 362/742] src/sage/tensor/modules/tensor_free_submodule.py: Add comment --- src/sage/tensor/modules/tensor_free_submodule.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index c8da4e86471..0cfdb046169 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -181,6 +181,9 @@ def tensor_factors(self): raise NotImplementedError def construction(self): + # TODO: Adapt from the code for the default name/latex_name in __init__. + # Define the symmetry group and its action (https://trac.sagemath.org/ticket/32029), + # use a construction functor for quotienting by the action return None @cached_method From b1cdacd0fe20d4da2bb296819983979a4c04accc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Jul 2022 17:14:57 -0700 Subject: [PATCH 363/742] build/pkgs/pyproject_metadata: New --- build/pkgs/pyproject_metadata/SPKG.rst | 18 ++++++++++++++++++ build/pkgs/pyproject_metadata/checksums.ini | 5 +++++ build/pkgs/pyproject_metadata/dependencies | 4 ++++ .../pyproject_metadata/install-requires.txt | 1 + .../pyproject_metadata/package-version.txt | 1 + build/pkgs/pyproject_metadata/spkg-install.in | 2 ++ build/pkgs/pyproject_metadata/type | 1 + 7 files changed, 32 insertions(+) create mode 100644 build/pkgs/pyproject_metadata/SPKG.rst create mode 100644 build/pkgs/pyproject_metadata/checksums.ini create mode 100644 build/pkgs/pyproject_metadata/dependencies create mode 100644 build/pkgs/pyproject_metadata/install-requires.txt create mode 100644 build/pkgs/pyproject_metadata/package-version.txt create mode 100644 build/pkgs/pyproject_metadata/spkg-install.in create mode 100644 build/pkgs/pyproject_metadata/type diff --git a/build/pkgs/pyproject_metadata/SPKG.rst b/build/pkgs/pyproject_metadata/SPKG.rst new file mode 100644 index 00000000000..6c0300e9a16 --- /dev/null +++ b/build/pkgs/pyproject_metadata/SPKG.rst @@ -0,0 +1,18 @@ +pyproject_metadata: PEP 621 metadata parsing +============================================ + +Description +----------- + +PEP 621 metadata parsing + +License +------- + +MIT + +Upstream Contact +---------------- + +https://pypi.org/project/pyproject-metadata/ + diff --git a/build/pkgs/pyproject_metadata/checksums.ini b/build/pkgs/pyproject_metadata/checksums.ini new file mode 100644 index 00000000000..da299c46588 --- /dev/null +++ b/build/pkgs/pyproject_metadata/checksums.ini @@ -0,0 +1,5 @@ +tarball=pyproject-metadata-VERSION.tar.gz +sha1=5421824aa29786bde43f510365c4d035a0614ba5 +md5=85fcbd5d777809ca2217a996e06fe2e0 +cksum=1327227039 +upstream_url=https://pypi.io/packages/source/p/pyproject_metadata/pyproject-metadata-VERSION.tar.gz diff --git a/build/pkgs/pyproject_metadata/dependencies b/build/pkgs/pyproject_metadata/dependencies new file mode 100644 index 00000000000..0738c2d7777 --- /dev/null +++ b/build/pkgs/pyproject_metadata/dependencies @@ -0,0 +1,4 @@ +$(PYTHON) | $(PYTHON_TOOLCHAIN) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/pyproject_metadata/install-requires.txt b/build/pkgs/pyproject_metadata/install-requires.txt new file mode 100644 index 00000000000..7ca7140f9d4 --- /dev/null +++ b/build/pkgs/pyproject_metadata/install-requires.txt @@ -0,0 +1 @@ +pyproject-metadata diff --git a/build/pkgs/pyproject_metadata/package-version.txt b/build/pkgs/pyproject_metadata/package-version.txt new file mode 100644 index 00000000000..8f0916f768f --- /dev/null +++ b/build/pkgs/pyproject_metadata/package-version.txt @@ -0,0 +1 @@ +0.5.0 diff --git a/build/pkgs/pyproject_metadata/spkg-install.in b/build/pkgs/pyproject_metadata/spkg-install.in new file mode 100644 index 00000000000..37ac1a53437 --- /dev/null +++ b/build/pkgs/pyproject_metadata/spkg-install.in @@ -0,0 +1,2 @@ +cd src +sdh_pip_install . diff --git a/build/pkgs/pyproject_metadata/type b/build/pkgs/pyproject_metadata/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/pyproject_metadata/type @@ -0,0 +1 @@ +standard From 345c019deffca04f8c1e91c30c094e9cf2cdfe15 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Jul 2022 17:24:55 -0700 Subject: [PATCH 364/742] build/pkgs/pyproject_metadata/dependencies: Update --- build/pkgs/pyproject_metadata/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/pyproject_metadata/dependencies b/build/pkgs/pyproject_metadata/dependencies index 0738c2d7777..6d5368db738 100644 --- a/build/pkgs/pyproject_metadata/dependencies +++ b/build/pkgs/pyproject_metadata/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) +$(PYTHON) packaging pyparsing | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. From bdc45376b64dfb472781caecf8fab6c30f1fc92c Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 29 Aug 2022 09:57:04 +0200 Subject: [PATCH 365/742] make the linter happier --- src/sage/data_structures/stream.py | 13 +++++++---- src/sage/rings/lazy_series.py | 36 ++++++++++++++++-------------- src/sage/rings/lazy_series_ring.py | 4 ++++ 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 75a697d28c6..61e140e006c 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -101,6 +101,7 @@ from sage.combinat.sf.sfa import _variables_recursive, _raise_variables from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis + class Stream(): """ Abstract base class for all streams. @@ -481,7 +482,7 @@ def __ne__(self, other): for i in self._cache: if i in other._cache and other._cache[i] != self._cache[i]: return True - else: # they are dense + else: # they are dense # Make ``self`` have the smaller approximate order. if self._approximate_order > other._approximate_order: self, other = other, self @@ -501,6 +502,7 @@ def __ne__(self, other): return False + class Stream_exact(Stream): r""" A stream of eventually constant coefficients. @@ -1460,7 +1462,7 @@ class Stream_dirichlet_convolve(Stream_binary): """ def __init__(self, left, right): """ - Initalize ``self``. + Initialize ``self``. sage: from sage.data_structures.stream import (Stream_dirichlet_convolve, Stream_function, Stream_exact) sage: f = Stream_function(lambda n: n, ZZ, True, 1) @@ -1758,7 +1760,7 @@ def __init__(self, f, g, p, ring=None, include=None, exclude=None): self._basis = ring self._p = p p_g = Stream_map_coefficients(g, lambda x: x, p) - self._powers = [p_g] # a cache for the powers of p_g + self._powers = [p_g] # a cache for the powers of p_g R = self._basis.base_ring() if HopfAlgebrasWithBasis(R).TensorProducts() in p.categories(): self._tensor_power = len(p._sets) @@ -1796,7 +1798,7 @@ def get_coefficient(self, n): 3*s[1, 1, 1, 1] + 2*s[2, 1, 1] + s[2, 2] + s[3, 1] + s[4], 4*s[1, 1, 1, 1, 1] + 4*s[2, 1, 1, 1] + 2*s[2, 2, 1] + 2*s[3, 1, 1] + s[3, 2] + s[4, 1] + s[5]] """ - if not n: # special case of 0 + if not n: # special case of 0 if self._tensor_power is None: return self._left[0] return self._basis(self._left[0].coefficient([])) @@ -2132,6 +2134,7 @@ def is_nonzero(self): """ return self._series.is_nonzero() + class Stream_cauchy_invert(Stream_unary): """ Operator for multiplicative inverse of the stream. @@ -2241,6 +2244,7 @@ def is_nonzero(self): """ return True + class Stream_map_coefficients(Stream_inexact): r""" The stream with ``function`` applied to each nonzero @@ -2349,6 +2353,7 @@ def __eq__(self, other): return (isinstance(other, type(self)) and self._series == other._series and self._ring == other._ring and self._function == other._function) + class Stream_shift(Stream_inexact): """ Operator for shifting the stream. diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index e9acf69c16a..19e413c837d 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -99,7 +99,6 @@ 1/4*z^-1 - 3/8 + 1/16*z - 17/32*z^2 + 5/64*z^3 - 29/128*z^4 + 165/256*z^5 + O(z^6) sage: hinv.valuation() -1 - """ # **************************************************************************** @@ -144,6 +143,7 @@ Stream_plethysm ) + class LazyModuleElement(Element): r""" A lazy sequence with a module structure given by term-wise @@ -569,8 +569,9 @@ def __bool__(self): """ Test whether ``self`` is not zero. - An unitialized series returns ``True`` as it is considered as a - formal variable, such as a generator of a polynomial ring. + An uninitialized series returns ``True`` as it is considered + as a formal variable, such as a generator of a polynomial + ring. TESTS:: @@ -1830,7 +1831,7 @@ def f(n): n = ZZ(n) if n % 2: h = 4 ** ((n + 1) // 2) - return bernoulli(n + 1) * h * (h -1) / factorial(n + 1) + return bernoulli(n + 1) * h * (h - 1) / factorial(n + 1) return ZZ.zero() return P(f, valuation=1)(self) @@ -2262,7 +2263,7 @@ def _mul_(self, other): # coefficients of q. if right._constant: d = right._degree - c = left._constant # this is zero + c = left._constant # this is zero # left._constant must be 0 and thus len(il) >= 1 for k in range(len(il)-1): c += il[k] * right._constant @@ -2270,14 +2271,14 @@ def _mul_(self, other): c += il[-1] * right._constant elif left._constant: d = left._degree - c = right._constant # this is zero + c = right._constant # this is zero # left._constant must be 0 and thus len(il) >= 1 for k in range(len(ir)-1): c += left._constant * ir[k] initial_coefficients[d - lv + k] += c c += left._constant * ir[-1] else: - c = left._constant # this is zero + c = left._constant # this is zero coeff_stream = Stream_exact(initial_coefficients, P._sparse, order=lv + rv, @@ -2436,7 +2437,7 @@ def __invert__(self): return P.element_class(P, coeff_stream) if (len(initial_coefficients) == 2 and not (initial_coefficients[0] + initial_coefficients[1]) - and not coeff_stream._constant): + and not coeff_stream._constant): v = -coeff_stream.order() c = ~initial_coefficients[0] coeff_stream = Stream_exact((), @@ -2940,7 +2941,7 @@ def __call__(self, g, *, check=True): sage: f(g) == f.polynomial()(g) True """ - # f = self and compute f(g) + # Find a good parent for the result from sage.structure.element import get_coercion_model cm = get_coercion_model() P = cm.common_parent(self.base_ring(), parent(g)) @@ -3227,7 +3228,7 @@ def revert(self): raise ValueError("compositional inverse does not exist") if coeff_stream[0]: - raise ValueError("cannot determine whether the compositional inverse exists") + raise ValueError("cannot determine whether the compositional inverse exists") z = P.gen() g = P(None, valuation=1) @@ -3406,6 +3407,7 @@ def _format_series(self, formatter, format_strings=False): return strformat("O({})".format(formatter(z**m))) return formatter(poly) + strformat(" + O({})".format(formatter(z**m))) + class LazyTaylorSeries(LazyCauchyProductSeries): r""" A Taylor series where the coefficients are computed lazily. @@ -3629,8 +3631,7 @@ def __call__(self, *g, check=True): raise ValueError("can only compose with a positive valuation series") h._coeff_stream._approximate_order = 2 - - # We now ahave that every element of g has a _coeff_stream + # We now have that every element of g has a _coeff_stream sorder = self._coeff_stream._approximate_order if len(g) == 1: g0 = g[0] @@ -3796,7 +3797,7 @@ def revert(self): raise ValueError("compositional inverse does not exist") if coeff_stream[0]: - raise ValueError("cannot determine whether the compositional inverse exists") + raise ValueError("cannot determine whether the compositional inverse exists") z = P.gen() g = P(None, valuation=1) @@ -3931,7 +3932,7 @@ def polynomial(self, degree=None, names=None): if degree is None: if (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant): + and not self._coeff_stream._constant): m = self._coeff_stream._degree else: raise ValueError("not a polynomial") @@ -4422,7 +4423,7 @@ def symmetric_function(self, degree=None): if degree is None: if (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant): + and not self._coeff_stream._constant): m = self._coeff_stream._degree else: raise ValueError("not a symmetric function") @@ -4431,6 +4432,7 @@ def symmetric_function(self, degree=None): return R.sum(self[:m]) + class LazyDirichletSeries(LazyModuleElement): r""" A Dirichlet series where the coefficients are computed lazily. @@ -4537,12 +4539,12 @@ def _mul_(self, other): and not left._constant and left._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and left.order() == 1): - return other # self == 1 + return other # self == 1 if (isinstance(right, Stream_exact) and not right._constant and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and right.order() == 1): - return self # other == 1 + return self # other == 1 coeff = Stream_dirichlet_convolve(left, right) # Performing exact arithmetic is slow because the series grow large # very quickly as we are multiplying the degree diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 2f0f405a6b9..9a12c626430 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -65,6 +65,7 @@ Stream_uninitialized ) + class LazySeriesRing(UniqueRepresentation, Parent): """ Abstract base class for lazy series. @@ -690,6 +691,7 @@ def is_exact(self): """ return self.base_ring().is_exact() + class LazyLaurentSeriesRing(LazySeriesRing): """ The ring of lazy Laurent series. @@ -1116,6 +1118,7 @@ def _monomial(self, c, n): ###################################################################### + class LazyTaylorSeriesRing(LazySeriesRing): """ The ring of (possibly multivariate) lazy Taylor series. @@ -1481,6 +1484,7 @@ def _an_element_(self): ###################################################################### + class LazyCompletionGradedAlgebra(LazySeriesRing): r""" The completion of a graded alebra consisting of formal series. From 07ca0294601f7cf25577e67e025818f8df5bc9e5 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 29 Aug 2022 09:57:55 +0200 Subject: [PATCH 366/742] add a consistency check --- src/sage/rings/lazy_series.py | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 19e413c837d..a87698f4071 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -99,6 +99,51 @@ 1/4*z^-1 - 3/8 + 1/16*z - 17/32*z^2 + 5/64*z^3 - 29/128*z^4 + 165/256*z^5 + O(z^6) sage: hinv.valuation() -1 + +TESTS:: + + sage: def check(L, z, verbose=False): + ....: # division + ....: lf = [0, L(0), 1, L(1), z, 1 + z, 2 + z + z^2] + ....: lg = [3, L(3), 1 + z, 2 + z + z^2] + ....: for f in lf: + ....: for g in lg: + ....: try: + ....: h = f / g + ....: if verbose: print("(%s) / (%s) = %s" % (f, g, h)) + ....: except Exception as e: + ....: print("%s in (%s) / (%s)" % (e, f, g)) + ....: # composition + ....: f = L(0) + ....: l = [(f, 0), (f, L(0)), (f, 2), (f, L(2)), (f, 2 + z + z^2), (f, 3/(1 - 2*z))] + ....: f = L(1) + ....: l.extend([(f, 0), (f, L(0)), (f, 2), (f, L(2)), (f, 2 + z + z^2), (f, 3/(1 - 2*z))]) + ....: f = 2 + z + z^2 + ....: l.extend([(f, 0), (f, L(0)), (f, 2), (f, L(2)), (f, 2 + z + z^2), (f, 3/(1 - 2*z))]) + ....: f = 3/(2 - 3*z) + ....: l.extend([(f, 0), (f, L(0)), (f, 3*z/(1 - 2*z))]) + ....: for f, g in l: + ....: try: + ....: h = f(g) + ....: if verbose: print("(%s)(%s) = %s" % (f, g, h)) + ....: except Exception as e: + ....: print("%s in (%s)(%s)" % (e, f, g)) + ....: # reversion + ....: l = [2 + 3*z, 3*z + 2*z^2, 3*z/(1 - 2*z - 3*z^2)] + ....: for f in l: + ....: try: + ....: h = f.revert() + ....: if verbose: print("(%s)^{(-1)} = %s" % (f, h)) + ....: except Exception as e: + ....: print("%s in (%s).revert()" % (e, f)) + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: check(L, z) + sage: L. = LazyTaylorSeriesRing(QQ) + sage: check(L, z) + sage: p = SymmetricFunctions(QQ).p() + sage: L = LazySymmetricFunctions(p) + sage: check(L, L(p[1])) """ # **************************************************************************** From 1d559cc8e2a9d2c79c29c0adbb0e6e19e4baead5 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 29 Aug 2022 16:00:24 +0200 Subject: [PATCH 367/742] improve composing Taylor series, start making plethysm more general --- src/sage/combinat/sf/sfa.py | 8 ++ src/sage/rings/lazy_series.py | 191 +++++++++++++++++++++++++--------- 2 files changed, 152 insertions(+), 47 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index b6975dba298..d440135e7e9 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -3093,6 +3093,14 @@ def plethysm(self, x, include=None, exclude=None): sage: r - f(g, include=[]) (a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2] + Check that we can compute the plethysm with a constant:: + + sage: p[2,2,1](2) + 8 + + sage: p[2,2,1](a1) + a1^5 + .. TODO:: The implementation of plethysm in diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index a87698f4071..1d116837a92 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -2706,7 +2706,7 @@ def __call__(self, g, *, check=True): r""" Return the composition of ``self`` with ``g``. - Given two Laurent Series `f` and `g` over the same base ring, the + Given two Laurent series `f` and `g` over the same base ring, the composition `(f \circ g)(z) = f(g(z))` is defined if and only if: - `g = 0` and `val(f) >= 0`, @@ -2907,7 +2907,7 @@ def __call__(self, g, *, check=True): ZeroDivisionError: the valuation of the series must be nonnegative `g \neq 0` and `val(g) \leq 0` and `f` has infinitely many - non-zero coefficients`:: + non-zero coefficients:: sage: g = z^-1 + z^-2 sage: g.valuation() <= 0 @@ -3110,8 +3110,8 @@ def revert(self): r""" Return the compositional inverse of ``self``. - Given a Laurent Series `f`. the compositional inverse is a - Laurent Series `g` over the same base ring, such that + Given a Laurent series `f`, the compositional inverse is a + Laurent series `g` over the same base ring, such that `(f \circ g)(z) = f(g(z)) = z`. The compositional inverse exists if and only if: @@ -3343,10 +3343,10 @@ def polynomial(self, degree=None, name=None): A Laurent polynomial if the valuation of the series is negative or a polynomial otherwise. - If ``degree`` is not ``None``, the terms of the series of degree - greater than ``degree`` are truncated first. If ``degree`` is ``None`` - and the series is not a polynomial or a Laurent polynomial, a - ``ValueError`` is raised. + If ``degree`` is not ``None``, the terms of the series of + degree greater than ``degree`` are first truncated. If + ``degree`` is ``None`` and the series is not a polynomial or + a Laurent polynomial, a ``ValueError`` is raised. EXAMPLES:: @@ -3387,6 +3387,7 @@ def polynomial(self, degree=None, name=None): sage: L.zero().polynomial() 0 + """ S = self.parent() @@ -3481,12 +3482,21 @@ def __call__(self, *g, check=True): The arity of ``self`` must be equal to the number of arguments provided. - Given two Taylor Series `f` and `g` over the same base ring, the - composition `(f \circ g)(z) = f(g(z))` is defined if and only if: + Given a Taylor series `f` of arity `n` and a tuple of Taylor + series `g = (g_1,\dots, g_n)` over the same base ring, the + composition `f \circ g` is defined if and only if for each + `1\leq k\leq n`: - - `g = 0` and `val(f) >= 0`, - - `g` is non-zero and `f` has only finitely many non-zero coefficients, - - `g` is non-zero and `val(g) > 0`. + - `g_i` is zero, or + - setting all variables except the `i`th in `f` to zero + yields a polynomial, or + - `val(g_i) > 0`. + + If `f` is a univariate 'exact' series, we can check whether + `f` is a actually a polynomial. However, if `f` is a + multivariate series, we have no way to test whether setting + all but one variable of `f` to zero yields a polynomial, + except if `f` itself is 'exact' and therefore a polynomial. INPUT: @@ -3615,8 +3625,33 @@ def __call__(self, *g, check=True): sage: gp.define(z / f(gp)) sage: gp z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) + + Check that composing the zero series with anything yields zero:: + + sage: T. = LazyTaylorSeriesRing(QQ) + sage: M. = LazyTaylorSeriesRing(QQ) + sage: T(0)(1/(1-a), a+b) + 0 + + Check that composing `f` with zero series yields the constant term of `f`:: + + sage: T(3/(1-x-2*y))(0, 0) + 3 + + Check that we can compose a polynomial with anything:: + + sage: T(1-x-2*y + x*y^2)(1, 3) + 3 + + sage: T(1-x-2*y + x*y^2)(1 + a, 3) + 3 + 8*a + + sage: T(1-x-2*y + x*y^2)(1/(1-a), 3) + 3 + 8*a + 8*a^2 + 8*a^3 + 8*a^4 + 8*a^5 + 8*a^6 + O(a,b)^7 + """ - if len(g) != len(self.parent().variable_names()): + fP = parent(self) + if len(g) != fP._arity: raise ValueError("arity of must be equal to the number of arguments provided") # Find a good parent for the result @@ -3624,8 +3659,20 @@ def __call__(self, *g, check=True): cm = get_coercion_model() P = cm.common_parent(self.base_ring(), *[parent(h) for h in g]) - # f has finite length - if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: + # f = 0 + if isinstance(self._coeff_stream, Stream_zero): + return P.zero() + + # g = (0, ..., 0) + if all((not isinstance(h, LazyModuleElement) and not h) + or (isinstance(h, LazyModuleElement) + and isinstance(h._coeff_stream, Stream_zero)) + for h in g): + return P(self[0]) + + # f has finite length and f != 0 + if (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): # constant polynomial poly = self.polynomial() if poly.is_constant(): @@ -3640,7 +3687,6 @@ def __call__(self, *g, check=True): from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing_univariate from sage.rings.lazy_series_ring import LazySeriesRing if not isinstance(P, LazySeriesRing): - fP = parent(self) if fP._laurent_poly_ring.has_coerce_map_from(P): S = fP._laurent_poly_ring P = fP @@ -3708,8 +3754,8 @@ def revert(self): r""" Return the compositional inverse of ``self``. - Given a Taylor Series `f`. the compositional inverse is a - Laurent Series `g` over the same base ring, such that + Given a Taylor series `f`, the compositional inverse is a + Laurent series `g` over the same base ring, such that `(f \circ g)(z) = f(g(z)) = z`. The compositional inverse exists if and only if: @@ -3932,9 +3978,10 @@ def polynomial(self, degree=None, names=None): OUTPUT: - If ``degree`` is not ``None``, the terms of the series of degree greater - than ``degree`` are truncated first. If ``degree`` is ``None`` and the - series is not a polynomial polynomial, a ``ValueError`` is raised. + If ``degree`` is not ``None``, the terms of the series of + degree greater than ``degree`` are first truncated. If + ``degree`` is ``None`` and the series is not a polynomial + polynomial, a ``ValueError`` is raised. EXAMPLES:: @@ -3966,6 +4013,7 @@ def polynomial(self, degree=None, names=None): sage: f = z-z^2 sage: f.polynomial() -z^2 + z + """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing S = self.parent() @@ -4077,24 +4125,35 @@ class LazySymmetricFunction(LazyCompletionGradedAlgebraElement): sage: s = SymmetricFunctions(ZZ).s() sage: L = LazySymmetricFunctions(s) """ - def __call__(self, *args, check=True): + def __call__(self, *g, check=True): r""" - Return the composition of ``self`` with ``args``. + Return the composition of ``self`` with ``g``. The arity of ``self`` must be equal to the number of arguments provided. - Given two lazy symmetric functions `f` and `g` over the same - base ring, the composition (or plethysm) `(f \circ g)` is - defined if and only if: - - - `g = 0`, - - `g` is non-zero and `f` has only finitely many non-zero coefficients, - - `g` is non-zero and `val(g) > 0`. + Given a lazy symmetric function `f` of arity `n` and a tuple + of lazy symmetric functions `g = (g_1,\dots, g_n)` over the + same base ring, the composition (or plethysm) `(f \circ g)` + is defined if and only if for each `1\leq k\leq n`: + + - `g_i = 0`, or + - setting all alphabets except the `i`th in `f` to zero + yields a symmetric function with only finitely many + non-zero coefficients, or + - `val(g) > 0`. + + If `f` is a univariate 'exact' lazy symmetric function, we + can check whether `f` has only finitely many non-zero + coefficients. However, if `f` has larger arity, we have no + way to test whether setting all but one alphabets of `f` to + zero yields a polynomial, except if `f` itself is 'exact' and + therefore a symmetric function with only finitely many + non-zero coefficients. INPUT: - - ``args`` -- other (lazy) symmetric functions + - ``g`` -- other (lazy) symmetric functions .. TODO:: @@ -4176,28 +4235,64 @@ def __call__(self, *args, check=True): Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series + + Check that composing the zero series with anything yields + zero in the correct parent:: + + sage: e = SymmetricFunctions(QQ).e() + sage: h = SymmetricFunctions(QQ).h() + sage: s = SymmetricFunctions(QQ).s() + sage: p = SymmetricFunctions(QQ).p() + sage: L = LazySymmetricFunctions(tensor([e, h])) + sage: r = (L(0)(s[1], p[1])); r + 0 + sage: r.parent() + Symmetric Functions over Rational Field in the Schur basis + + Check that composing `f` with zero series yields the constant term of `f`:: + + sage: f = 3*L(tensor([s[1], s[1]])) + sage: f(0, 0) + 0 + sage: (3+f)(0, 0) + 3 """ - if len(args) != self.parent()._arity: + fP = parent(self) + if len(g) != fP._arity: raise ValueError("arity must be equal to the number of arguments provided") + + # we actually do not need this from sage.combinat.sf.sfa import is_SymmetricFunction - if not all(isinstance(g, LazySymmetricFunction) or is_SymmetricFunction(g) or not g for g in args): - raise ValueError("all arguments must be (possibly lazy) symmetric functions") + # if not all(isinstance(h, LazySymmetricFunction) + # or is_SymmetricFunction(h) or not h for h in g): + # raise ValueError("all arguments must be (possibly lazy) symmetric functions") - if isinstance(self._coeff_stream, Stream_zero): - return self + # Find a good parent for the result + from sage.structure.element import get_coercion_model + cm = get_coercion_model() + P = cm.common_parent(self.base_ring(), *[parent(h) for h in g]) - if len(args) == 1: - g = args[0] - P = g.parent() + # f = 0 + if isinstance(self._coeff_stream, Stream_zero): + return P.zero() - # Handle other types of 0s - if not isinstance(g, LazySymmetricFunction) and not g: - return P(self[0].leading_coefficient()) + # g = (0, ..., 0) + if all((not isinstance(h, LazyModuleElement) and not h) + or (isinstance(h, LazyModuleElement) + and isinstance(h._coeff_stream, Stream_zero)) + for h in g): + f = self[0] + # FIXME: TypeError: unable to convert 0 to a rational + if f: + return P(f.leading_coefficient()) + return P.zero() + if len(g) == 1: + g = g[0] if (isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant): f = self.symmetric_function() - if is_SymmetricFunction(g): + if not isinstance(g, LazySymmetricFunction): return f(g) # g must be a LazySymmetricFunction if (isinstance(g._coeff_stream, Stream_exact) @@ -4422,9 +4517,10 @@ def symmetric_function(self, degree=None): OUTPUT: - If ``degree`` is not ``None``, the terms of the series of degree greater - than ``degree`` are truncated first. If ``degree`` is ``None`` and the - series is not a polynomial polynomial, a ``ValueError`` is raised. + If ``degree`` is not ``None``, the terms of the series of + degree greater than ``degree`` are first truncated. If + ``degree`` is ``None`` and the series is not a polynomial + polynomial, a ``ValueError`` is raised. EXAMPLES:: @@ -4459,6 +4555,7 @@ def symmetric_function(self, degree=None): 0 sage: f4.symmetric_function(0) s[] + """ S = self.parent() R = S._laurent_poly_ring From ab673bdf69be7698beacc7b8237b7e71ba576f40 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 29 Aug 2022 09:17:20 -0500 Subject: [PATCH 368/742] Add trim to integer vector --- src/sage/combinat/integer_vector.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index ee73284a59c..26016b8cc55 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -458,6 +458,29 @@ def check(self): raise ValueError("all entries must be non-negative") + def trim(self): + """ + Remove trailing zeros from the integer vector. + + EXAMPLES:: + + sage: IV = IntegerVectors() + sage: IV([5,3,5,1,0,0]).trim() + [5, 3, 5, 1] + sage: IV([5,0,5,1,0]).trim() + [5, 0, 5, 1] + sage: IV([4,3,3]).trim() + [4, 3, 3] + sage: IV([0,0,0]).trim() + [] + """ + v = list(self) + if all(i == 0 for i in v): + return self.parent()([]) + while not v[-1]: + v = v[:-1] + return self.parent()(v) + class IntegerVectors(Parent, metaclass=ClasscallMetaclass): """ The class of (non-negative) integer vectors. From 66366b3c1c3f7c80fb8b341af44c874a8ab57281 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 09:13:08 -0700 Subject: [PATCH 369/742] TensorFreeModule.basis: Fix typo in docstring --- src/sage/tensor/modules/tensor_free_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index d4f000d7be6..548b2f0a734 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -732,7 +732,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, INPUT: - - ``symbol``, ``indices`` -- passed to he base module's method + - ``symbol``, ``indices`` -- passed to the base module's method :meth:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule.basis` to select a basis of the :meth:`base_module` of ``self``, or to create it. From bb3bae0ad9042a70ea4428af30433e4b436d9400 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 09:20:59 -0700 Subject: [PATCH 370/742] TensorFreeSubmodule_sym, TensorFreeSubmoduleBasis_sym: Rename from ..._comp --- .../tensor/modules/finite_rank_free_module.py | 10 +-- src/sage/tensor/modules/tensor_free_module.py | 22 ++--- .../tensor/modules/tensor_free_submodule.py | 88 +++++++++---------- .../modules/tensor_free_submodule_basis.py | 8 +- 4 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index b9a3e543eb1..7264944bc59 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -703,9 +703,9 @@ def ambient_module(self): # compatible with sage.modules.free_module.FreeModule_ sage: M.ambient_module() is M True - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) sage: T60M = M.tensor_module(6, 0) sage: Sym0123x45M.ambient_module() is T60M True @@ -1195,7 +1195,7 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): T^{\{2,3\}}(M) \otimes T^{\{6,7\}}(M^*) \otimes \mathrm{Sym}^{\{0,1\}}(M) \otimes \mathrm{ASym}^{\{4,5\}}(M^*) See :class:`~sage.tensor.modules.tensor_free_module.TensorFreeModule` - and :class:`~sage.tensor.modules.tensor_free_module.TensorFreeSubmodule_comp` + and :class:`~sage.tensor.modules.tensor_free_module.TensorFreeSubmodule_sym` for more documentation. """ @@ -1210,8 +1210,8 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): if key == (1, 0): T = self elif sym or antisym: - from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp - T = TensorFreeSubmodule_comp(self, (k, l), sym=sym, antisym=antisym) + from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym + T = TensorFreeSubmodule_sym(self, (k, l), sym=sym, antisym=antisym) else: from sage.tensor.modules.tensor_free_module import TensorFreeModule T = TensorFreeModule(self, (k, l)) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 548b2f0a734..6d0b9e16af4 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -66,7 +66,7 @@ from sage.tensor.modules.free_module_morphism import \ FiniteRankFreeModuleMorphism from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism -from .tensor_free_submodule_basis import TensorFreeSubmoduleBasis_comp +from .tensor_free_submodule_basis import TensorFreeSubmoduleBasis_sym class TensorFreeModule(FiniteRankFreeModule_abstract): r""" @@ -554,11 +554,11 @@ def _an_element_(self): TESTS:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) sage: t = Sym0123x45M._an_element_() sage: t.parent() is Sym0123x45M True @@ -623,8 +623,8 @@ def _coerce_map_from_(self, other): Coercion from submodules:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp - sage: Sym01M = TensorFreeSubmodule_comp(M, (2, 0), sym=((0, 1))) + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym + sage: Sym01M = TensorFreeSubmodule_sym(M, (2, 0), sym=((0, 1))) sage: M.tensor_module(2,0)._coerce_map_from_(Sym01M) True @@ -760,8 +760,8 @@ def basis(self, symbol, latex_symbol=None, from_family=None, e_2⊗e^1 e_2⊗e^2 - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp - sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)) + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym + sage: Sym2M = TensorFreeSubmodule_sym(M, (2, 0), sym=range(2)) sage: e_Sym2M = Sym2M.basis('e'); e_Sym2M Standard basis on the Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring @@ -774,25 +774,25 @@ def basis(self, symbol, latex_symbol=None, from_family=None, e_1⊗e_2 + e_2⊗e_1 e_2⊗e_2 """ - return TensorFreeSubmoduleBasis_comp(self, symbol=symbol, latex_symbol=latex_symbol, + return TensorFreeSubmoduleBasis_sym(self, symbol=symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) @cached_method - def _basis_comp(self): + def _basis_sym(self): r""" Return an instance of :class:`~sage.tensor.modules.comp.Components`. This implementation returns an instance without symmetry. - The subclass :class:`~sage.tensor.modules.tensor_free_submodule.TensorFreeSubmodule_comp` + The subclass :class:`~sage.tensor.modules.tensor_free_submodule.TensorFreeSubmodule_sym` overrides this method to encode the prescribed symmetry of the submodule. EXAMPLES:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: T = M.tensor_module(1,1) - sage: c = T._basis_comp(); c + sage: c = T._basis_sym(); c 2-indices components w.r.t. (0, 1, 2) """ diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index dc94ace3343..03d5dda185e 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -23,7 +23,7 @@ from .finite_rank_free_module import FiniteRankFreeModule_abstract -class TensorFreeSubmodule_comp(TensorFreeModule): +class TensorFreeSubmodule_sym(TensorFreeModule): r""" Class for free submodules of tensor products of free modules that are defined by the symmetries of a @@ -31,7 +31,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0); T60M @@ -40,14 +40,14 @@ class TensorFreeSubmodule_comp(TensorFreeModule): 'T^(6, 0)(M)' sage: latex(T60M) T^{(6, 0)}\left(M\right) - sage: T40Sym45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((4, 5))); T40Sym45M + sage: T40Sym45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((4, 5))); T40Sym45M Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (4, 5) sage: T40Sym45M._name 'T^{0,1,2,3}(M)⊗Sym^{4,5}(M)' sage: latex(T40Sym45M) T^{\{0,1,2,3\}}(M) \otimes \mathrm{Sym}^{\{4,5\}}(M) - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))); Sym0123x45M + sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))); Sym0123x45M Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2, 3), with symmetry on the index positions (4, 5) @@ -55,7 +55,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): 'Sym^{0,1,2,3}(M)⊗Sym^{4,5}(M)' sage: latex(Sym0123x45M) \mathrm{Sym}^{\{0,1,2,3\}}(M) \otimes \mathrm{Sym}^{\{4,5\}}(M) - sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))); Sym012x345M + sage: Sym012x345M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))); Sym012x345M Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2), with symmetry on the index positions (3, 4, 5) @@ -63,7 +63,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): 'Sym^{0,1,2}(M)⊗Sym^{3,4,5}(M)' sage: latex(Sym012x345M) \mathrm{Sym}^{\{0,1,2\}}(M) \otimes \mathrm{Sym}^{\{3,4,5\}}(M) - sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))); Sym012345M + sage: Sym012345M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))); Sym012345M Free module of fully symmetric type-(6,0) tensors on the Rank-3 free module M over the Integer Ring sage: Sym012345M._name @@ -85,7 +85,7 @@ class TensorFreeSubmodule_comp(TensorFreeModule): TESTS:: - sage: T = TensorFreeSubmodule_comp(M, (4, 4), sym=((0, 1)), antisym=((4, 5))); T + sage: T = TensorFreeSubmodule_sym(M, (4, 4), sym=((0, 1)), antisym=((4, 5))); T Free module of type-(4,4) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1), with antisymmetry on the index positions (4, 5) @@ -100,10 +100,10 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, r""" TESTS:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) sage: TestSuite(Sym0123x45M).run() """ self._fmodule = fmodule @@ -113,20 +113,20 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, self._ambient_module = ambient self._sym = sym self._antisym = antisym - basis_comp = self._basis_comp() - rank = len(list(basis_comp.non_redundant_index_generator())) + basis_sym = self._basis_sym() + rank = len(list(basis_sym.non_redundant_index_generator())) if name is None and fmodule._name is not None: all_indices = tuple(range(tensor_type[0] + tensor_type[1])) - if isinstance(basis_comp, CompFullySym): + if isinstance(basis_sym, CompFullySym): sym = [all_indices] antisym = [] - elif isinstance(basis_comp, CompFullyAntiSym): + elif isinstance(basis_sym, CompFullyAntiSym): sym = [] antisym = [all_indices] - elif isinstance(basis_comp, CompWithSym): - sym = basis_comp._sym - antisym = basis_comp._antisym + elif isinstance(basis_sym, CompWithSym): + sym = basis_sym._sym + antisym = basis_sym._antisym else: sym = antisym = [] nosym_0 = [i for i in range(tensor_type[0]) @@ -178,7 +178,7 @@ def power_name(op, s, latex=False): category=category, ambient=ambient) @cached_method - def _basis_comp(self): + def _basis_sym(self): r""" Return an instance of :class:`~sage.tensor.modules.comp.Components`. @@ -186,11 +186,11 @@ def _basis_comp(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M + sage: Sym2M = TensorFreeSubmodule_sym(M, (2, 0), sym=range(2)); Sym2M Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring - sage: c = Sym2M._basis_comp(); c + sage: c = Sym2M._basis_sym(); c Fully symmetric 2-indices components w.r.t. (0, 1, 2) """ @@ -205,14 +205,14 @@ def _repr_(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M + sage: Sym2M = TensorFreeSubmodule_sym(M, (2, 0), sym=range(2)); Sym2M Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring """ - prefix, suffix = self._basis_comp()._repr_symmetry() + prefix, suffix = self._basis_sym()._repr_symmetry() return "Free module of {}type-({},{}) tensors on the {}{}".format( prefix.lower(), self._tensor_type[0], self._tensor_type[1], self._fmodule, suffix) @@ -226,11 +226,11 @@ def _is_symmetry_coarsening_of(self, coarser_comp, finer_comp): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) sage: ten0123x45M = Sym0123x45M.an_element(); ten0123x45M Type-(6,0) tensor on the Rank-3 free module M over the Integer Ring sage: ten0123x45M.parent() @@ -242,13 +242,13 @@ def _is_symmetry_coarsening_of(self, coarser_comp, finer_comp): on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2, 3), with symmetry on the index positions (4, 5) - sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) + sage: Sym012x345M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) sage: com012x345M = Sym012x345M.an_element()._components[e]; com012x345M 6-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2), with symmetry on the index positions (3, 4, 5) - sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) + sage: Sym012345M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) sage: com012345M = Sym012345M.an_element()._components[e]; com012345M Fully symmetric 6-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring @@ -302,11 +302,11 @@ def _element_constructor_(self, comp=[], basis=None, name=None, r""" TESTS:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) sage: Sym0123x45M(e[0]*e[0]*e[0]*e[0]*e[1]*e[2]) Traceback (most recent call last): ... @@ -322,14 +322,14 @@ def _element_constructor_(self, comp=[], basis=None, name=None, if sym is not None or antisym is not None: # Refuse to create a tensor with finer symmetries # than those defining the subspace - if not self._is_symmetry_coarsening_of((sym, antisym), self._basis_comp()): + if not self._is_symmetry_coarsening_of((sym, antisym), self._basis_sym()): raise ValueError(f"cannot create a tensor with symmetries {sym=}, {antisym=} " f"as an element of {self}") if sym is None: - sym = self._basis_comp()._sym + sym = self._basis_sym()._sym if antisym is None: - antisym = self._basis_comp()._antisym + antisym = self._basis_sym()._antisym resu = super()._element_constructor_(comp=comp, basis=basis, name=name, @@ -355,12 +355,12 @@ def is_submodule(self, other): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) - sage: Sym012x345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) - sage: Sym012345M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) + sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym012x345M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) + sage: Sym012345M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) sage: Sym012345M.is_submodule(Sym012345M) True sage: Sym012345M.is_submodule(Sym0123x45M) @@ -387,8 +387,8 @@ def is_submodule(self, other): if self_tensor_type != other_tensor_type: return False - other_comp = other._basis_comp() - return self._is_symmetry_coarsening_of(self._basis_comp(), other_comp) + other_comp = other._basis_sym() + return self._is_symmetry_coarsening_of(self._basis_sym(), other_comp) @lazy_attribute def lift(self): @@ -397,9 +397,9 @@ def lift(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym0123x45M = TensorFreeSubmodule_comp(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) sage: Sym0123x45M.lift Generic morphism: From: Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, @@ -419,7 +419,7 @@ def reduce(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(QQ, 3, name='M') sage: e = M.basis('e') sage: X = M.tensor_module(6, 0) @@ -461,8 +461,8 @@ def reduce(self): sage: all(Y.reduce(u.lift()) == 0 for u in Y.basis('e')) True """ - sym = self._basis_comp()._sym - antisym = self._basis_comp()._antisym + sym = self._basis_sym()._sym + antisym = self._basis_sym()._antisym def _reduce_element(x): if not x._components: @@ -491,7 +491,7 @@ def retract(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: X = M.tensor_module(6, 0) diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index ae00f98971b..0ee52bb5a95 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -14,7 +14,7 @@ from sage.tensor.modules.free_module_basis import Basis_abstract -class TensorFreeSubmoduleBasis_comp(Basis_abstract): +class TensorFreeSubmoduleBasis_sym(Basis_abstract): r""" Standard basis of a tensor module with prescribed symmetries. @@ -52,7 +52,7 @@ def __init__(self, tensor_module, symbol, latex_symbol=None, indices=None, latex_indices, symbol_dual, latex_symbol_dual) super().__init__(tensor_module, symbol, latex_symbol, indices, latex_indices) self._base_module_basis = base_module_basis - self._comp = tensor_module._basis_comp() + self._comp = tensor_module._basis_sym() def _repr_(self): r""" @@ -120,8 +120,8 @@ def __getitem__(self, index): sage: e11[1, 2].display() e_1⊗e^2 - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_comp - sage: Sym2M = TensorFreeSubmodule_comp(M, (2, 0), sym=range(2)); Sym2M + sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym + sage: Sym2M = TensorFreeSubmodule_sym(M, (2, 0), sym=range(2)); Sym2M Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring sage: eSym2M = Sym2M.basis('e') sage: eSym2M[1, 1].display() From a99f5c0207d4b84b329d38dde645e7fcf69e052b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 09:27:57 -0700 Subject: [PATCH 371/742] src/sage/tensor/modules/tensor_free_submodule[_basis].py: Deemphasize Components in the documentation --- src/sage/tensor/modules/tensor_free_submodule.py | 8 ++++---- src/sage/tensor/modules/tensor_free_submodule_basis.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 03d5dda185e..3d2ce06a01f 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -1,5 +1,5 @@ r""" -Free submodules of tensor products of free modules +Free submodules of tensor modules defined by monoterm symmetries """ #****************************************************************************** @@ -26,8 +26,7 @@ class TensorFreeSubmodule_sym(TensorFreeModule): r""" Class for free submodules of tensor products of free modules - that are defined by the symmetries of a - :class:`~sage.tensor.modules.comp.Components` object. + that are defined by some monoterm symmetries. EXAMPLES:: @@ -182,7 +181,8 @@ def _basis_sym(self): r""" Return an instance of :class:`~sage.tensor.modules.comp.Components`. - It encodes the prescribed symmetry of ``self``. + In the current implementation of :class:`~sage.tensor.modules.tensor_free_submodule.TensorFreeSubmodule_sym`, + it encodes the prescribed symmetry of ``self``. EXAMPLES:: diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index 0ee52bb5a95..d2b60298ee0 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -1,5 +1,5 @@ r""" -Free module bases indexed by component indices +Standard bases of free submodules of tensor modules defined by some monoterm symmetries """ #****************************************************************************** @@ -16,7 +16,7 @@ class TensorFreeSubmoduleBasis_sym(Basis_abstract): r""" - Standard basis of a tensor module with prescribed symmetries. + Standard basis of a free submodule of a tensor module with prescribed monoterm symmetries. EXAMPLES:: From 1e7430ab22f781ed9bc133b32f8153599e4539cc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 09:38:20 -0700 Subject: [PATCH 372/742] src/sage/tensor: In examples, use FiniteRankFreeModule.tensor_module(..., sym=...) instead of FiniteRankFreeModule_sym --- .../tensor/modules/finite_rank_free_module.py | 3 +- src/sage/tensor/modules/tensor_free_module.py | 9 ++-- .../tensor/modules/tensor_free_submodule.py | 42 +++++++------------ 3 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 7264944bc59..5f1faf48e58 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -703,9 +703,8 @@ def ambient_module(self): # compatible with sage.modules.free_module.FreeModule_ sage: M.ambient_module() is M True - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: T60M = M.tensor_module(6, 0) sage: Sym0123x45M.ambient_module() is T60M True diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 6d0b9e16af4..9ea88f3c5f0 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -554,11 +554,10 @@ def _an_element_(self): TESTS:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: t = Sym0123x45M._an_element_() sage: t.parent() is Sym0123x45M True @@ -623,8 +622,7 @@ def _coerce_map_from_(self, other): Coercion from submodules:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym - sage: Sym01M = TensorFreeSubmodule_sym(M, (2, 0), sym=((0, 1))) + sage: Sym01M = M.tensor_module(2, 0, sym=((0, 1))) sage: M.tensor_module(2,0)._coerce_map_from_(Sym01M) True @@ -760,8 +758,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, e_2⊗e^1 e_2⊗e^2 - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym - sage: Sym2M = TensorFreeSubmodule_sym(M, (2, 0), sym=range(2)) + sage: Sym2M = M.tensor_module(2, 0, sym=range(2)) sage: e_Sym2M = Sym2M.basis('e'); e_Sym2M Standard basis on the Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 3d2ce06a01f..cfe6b09dccf 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -30,7 +30,6 @@ class TensorFreeSubmodule_sym(TensorFreeModule): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0); T60M @@ -39,14 +38,14 @@ class TensorFreeSubmodule_sym(TensorFreeModule): 'T^(6, 0)(M)' sage: latex(T60M) T^{(6, 0)}\left(M\right) - sage: T40Sym45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((4, 5))); T40Sym45M + sage: T40Sym45M = M.tensor_module(6, 0, sym=((4, 5))); T40Sym45M Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (4, 5) sage: T40Sym45M._name 'T^{0,1,2,3}(M)⊗Sym^{4,5}(M)' sage: latex(T40Sym45M) T^{\{0,1,2,3\}}(M) \otimes \mathrm{Sym}^{\{4,5\}}(M) - sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))); Sym0123x45M + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))); Sym0123x45M Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2, 3), with symmetry on the index positions (4, 5) @@ -54,7 +53,7 @@ class TensorFreeSubmodule_sym(TensorFreeModule): 'Sym^{0,1,2,3}(M)⊗Sym^{4,5}(M)' sage: latex(Sym0123x45M) \mathrm{Sym}^{\{0,1,2,3\}}(M) \otimes \mathrm{Sym}^{\{4,5\}}(M) - sage: Sym012x345M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))); Sym012x345M + sage: Sym012x345M = M.tensor_module(6, 0, sym=((0, 1, 2), (3, 4, 5))); Sym012x345M Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2), with symmetry on the index positions (3, 4, 5) @@ -62,7 +61,7 @@ class TensorFreeSubmodule_sym(TensorFreeModule): 'Sym^{0,1,2}(M)⊗Sym^{3,4,5}(M)' sage: latex(Sym012x345M) \mathrm{Sym}^{\{0,1,2\}}(M) \otimes \mathrm{Sym}^{\{3,4,5\}}(M) - sage: Sym012345M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))); Sym012345M + sage: Sym012345M = M.tensor_module(6, 0, sym=((0, 1, 2, 3, 4, 5))); Sym012345M Free module of fully symmetric type-(6,0) tensors on the Rank-3 free module M over the Integer Ring sage: Sym012345M._name @@ -84,7 +83,7 @@ class TensorFreeSubmodule_sym(TensorFreeModule): TESTS:: - sage: T = TensorFreeSubmodule_sym(M, (4, 4), sym=((0, 1)), antisym=((4, 5))); T + sage: T = M.tensor_module(4, 4, sym=((0, 1)), antisym=((4, 5))); T Free module of type-(4,4) tensors on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1), with antisymmetry on the index positions (4, 5) @@ -99,10 +98,9 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, r""" TESTS:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') - sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: TestSuite(Sym0123x45M).run() """ self._fmodule = fmodule @@ -186,9 +184,8 @@ def _basis_sym(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym2M = TensorFreeSubmodule_sym(M, (2, 0), sym=range(2)); Sym2M + sage: Sym2M = M.tensor_module(2, 0, sym=range(2)); Sym2M Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring sage: c = Sym2M._basis_sym(); c Fully symmetric 2-indices components w.r.t. (0, 1, 2) @@ -205,9 +202,8 @@ def _repr_(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym2M = TensorFreeSubmodule_sym(M, (2, 0), sym=range(2)); Sym2M + sage: Sym2M = M.tensor_module(2, 0, sym=range(2)); Sym2M Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring @@ -226,11 +222,10 @@ def _is_symmetry_coarsening_of(self, coarser_comp, finer_comp): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: ten0123x45M = Sym0123x45M.an_element(); ten0123x45M Type-(6,0) tensor on the Rank-3 free module M over the Integer Ring sage: ten0123x45M.parent() @@ -242,13 +237,13 @@ def _is_symmetry_coarsening_of(self, coarser_comp, finer_comp): on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2, 3), with symmetry on the index positions (4, 5) - sage: Sym012x345M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) + sage: Sym012x345M = M.tensor_module(6, 0, sym=((0, 1, 2), (3, 4, 5))) sage: com012x345M = Sym012x345M.an_element()._components[e]; com012x345M 6-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring, with symmetry on the index positions (0, 1, 2), with symmetry on the index positions (3, 4, 5) - sage: Sym012345M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) + sage: Sym012345M = M.tensor_module(6, 0, sym=((0, 1, 2, 3, 4, 5))) sage: com012345M = Sym012345M.an_element()._components[e]; com012345M Fully symmetric 6-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring @@ -302,11 +297,10 @@ def _element_constructor_(self, comp=[], basis=None, name=None, r""" TESTS:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: Sym0123x45M(e[0]*e[0]*e[0]*e[0]*e[1]*e[2]) Traceback (most recent call last): ... @@ -355,12 +349,11 @@ def is_submodule(self, other): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: T60M = M.tensor_module(6, 0) - sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) - sage: Sym012x345M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2), (3, 4, 5))) - sage: Sym012345M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3, 4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) + sage: Sym012x345M = M.tensor_module(6, 0, sym=((0, 1, 2), (3, 4, 5))) + sage: Sym012345M = M.tensor_module(6, 0, sym=((0, 1, 2, 3, 4, 5))) sage: Sym012345M.is_submodule(Sym012345M) True sage: Sym012345M.is_submodule(Sym0123x45M) @@ -397,9 +390,8 @@ def lift(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: Sym0123x45M = TensorFreeSubmodule_sym(M, (6, 0), sym=((0, 1, 2, 3), (4, 5))) + sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5))) sage: Sym0123x45M.lift Generic morphism: From: Free module of type-(6,0) tensors on the Rank-3 free module M over the Integer Ring, @@ -419,7 +411,6 @@ def reduce(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(QQ, 3, name='M') sage: e = M.basis('e') sage: X = M.tensor_module(6, 0) @@ -491,7 +482,6 @@ def retract(self): EXAMPLES:: - sage: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: X = M.tensor_module(6, 0) From 046887c65442ba9c7320b82ef0a9182f4fb77eed Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 09:40:39 -0700 Subject: [PATCH 373/742] TensorFreeModule.basis: Add example from egourgoulhon --- src/sage/tensor/modules/tensor_free_module.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 9ea88f3c5f0..42a97d92b4b 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -770,6 +770,24 @@ def basis(self, symbol, latex_symbol=None, from_family=None, e_1⊗e_1 e_1⊗e_2 + e_2⊗e_1 e_2⊗e_2 + + sage: M = FiniteRankFreeModule(ZZ, 2) + sage: e = M.basis('e') + sage: f = M.basis('f', from_family=(-e[1], e[0])) + sage: for b in f: b.display() + f_0 = -e_1 + f_1 = e_0 + sage: S = M.tensor_module(2, 0, sym=(0,1)) + sage: fS = S.basis('f') + sage: for b in fS: b.display() + e_1⊗e_1 + -e_0⊗e_1 - e_1⊗e_0 + e_0⊗e_0 + sage: for b in fS: b.display(f) + f_0⊗f_0 + f_0⊗f_1 + f_1⊗f_0 + f_1⊗f_1 + """ return TensorFreeSubmoduleBasis_sym(self, symbol=symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, From 3a65d2d2c7f89d3d74109444b1501b3709bd6fce Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 09:56:39 -0700 Subject: [PATCH 374/742] CompWithSym._canonicalize_sym_antisym: Factor out from __init__ --- src/sage/tensor/modules/comp.py | 37 +++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 04f14f782f0..8de1f365212 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -2996,7 +2996,21 @@ def __init__(self, ring, frame, nb_indices, start_index=0, """ Components.__init__(self, ring, frame, nb_indices, start_index, output_formatter) - self._sym = [] + self._sym, self._antisym = self._canonicalize_sym_antisym( + nb_indices, sym, antisym) + + @staticmethod + def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): + r""" + Bring sym and antisym into their canonical form. + + EXAMPLES:: + + sage: from sage.tensor.modules.comp import CompWithSym + sage: CompWithSym._canonicalize_sym_antisym(6, [(2, 1)]) + ([(2, 1)], []) + """ + result_sym = [] if sym is not None and sym != []: if isinstance(sym[0], (int, Integer)): # a single symmetry is provided as a tuple or a range object; @@ -3007,11 +3021,11 @@ def __init__(self, ring, frame, nb_indices, start_index=0, raise IndexError("at least two index positions must be " + "provided to define a symmetry") for i in isym: - if i<0 or i>self._nid-1: + if i < 0 or i > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + - " not in [0," + str(self._nid-1) + "]") - self._sym.append(tuple(isym)) - self._antisym = [] + " not in [0," + str(nb_indices-1) + "]") + result_sym.append(tuple(isym)) + result_antisym = [] if antisym is not None and antisym != []: if isinstance(antisym[0], (int, Integer)): # a single antisymmetry is provided as a tuple or a range @@ -3022,20 +3036,21 @@ def __init__(self, ring, frame, nb_indices, start_index=0, raise IndexError("at least two index positions must be " + "provided to define an antisymmetry") for i in isym: - if i<0 or i>self._nid-1: + if i < 0 or i > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + - " not in [0," + str(self._nid-1) + "]") - self._antisym.append(tuple(isym)) + " not in [0," + str(nb_indices - 1) + "]") + result_antisym.append(tuple(isym)) # Final consistency check: index_list = [] - for isym in self._sym: + for isym in result_sym: index_list += isym - for isym in self._antisym: + for isym in result_antisym: index_list += isym if len(index_list) != len(set(index_list)): # There is a repeated index position: raise IndexError("incompatible lists of symmetries: the same " + - "index position appears more then once") + "index position appears more than once") + return result_sym, result_antisym def _repr_(self): r""" From 07ab9914adf5418070b9f326d99d282c18ddb35a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 10:52:35 -0700 Subject: [PATCH 375/742] src/sage/tensor: Allow _sym, _antisym attributes to be tuples --- .../manifolds/differentiable/tensorfield.py | 4 +-- src/sage/tensor/modules/comp.py | 26 +++++++++++++------ src/sage/tensor/modules/free_module_tensor.py | 4 +-- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index d5b63c9d81d..1370b104140 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -957,13 +957,13 @@ def symmetries(self): elif len(self._sym) == 1: s = "symmetry: {}; ".format(self._sym[0]) else: - s = "symmetries: {}; ".format(self._sym) + s = "symmetries: {}; ".format(list(self._sym)) if not self._antisym: a = "no antisymmetry" elif len(self._antisym) == 1: a = "antisymmetry: {}".format(self._antisym[0]) else: - a = "antisymmetries: {}".format(self._antisym) + a = "antisymmetries: {}".format(list(self._antisym)) print(s + a) #### End of simple accessors ##### diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 8de1f365212..d9c3dfdfe3e 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -1773,12 +1773,12 @@ def __mul__(self, other): "same starting index") if isinstance(other, CompWithSym): sym = [] - if other._sym != []: + if other._sym: for s in other._sym: ns = tuple(s[i]+self._nid for i in range(len(s))) sym.append(ns) antisym = [] - if other._antisym != []: + if other._antisym: for s in other._antisym: ns = tuple(s[i]+self._nid for i in range(len(s))) antisym.append(ns) @@ -3011,7 +3011,12 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): ([(2, 1)], []) """ result_sym = [] - if sym is not None and sym != []: + if sym is None: + sym = [] + else: + # Handle the case that sym is an iterator + sym = list(sym) + if sym: if isinstance(sym[0], (int, Integer)): # a single symmetry is provided as a tuple or a range object; # it is converted to a 1-item list: @@ -3026,7 +3031,12 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): " not in [0," + str(nb_indices-1) + "]") result_sym.append(tuple(isym)) result_antisym = [] - if antisym is not None and antisym != []: + if antisym is None: + antisym = [] + else: + # Handle the case that antisym is an iterator + antisym = list(antisym) + if antisym: if isinstance(antisym[0], (int, Integer)): # a single antisymmetry is provided as a tuple or a range # object; it is converted to a 1-item list: @@ -3535,7 +3545,7 @@ def paral_sum(a, b, local_list_ind): com = tuple(set(isym).intersection(set(osym))) if len(com) > 1: common_antisym.append(com) - if common_sym != [] or common_antisym != []: + if common_sym or common_antisym: result = CompWithSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter, common_sym, common_antisym) @@ -3643,11 +3653,11 @@ def __mul__(self, other): sym = list(self._sym) antisym = list(self._antisym) if isinstance(other, CompWithSym): - if other._sym != []: + if other._sym: for s in other._sym: ns = tuple(s[i]+self._nid for i in range(len(s))) sym.append(ns) - if other._antisym != []: + if other._antisym: for s in other._antisym: ns = tuple(s[i]+self._nid for i in range(len(s))) antisym.append(ns) @@ -3973,7 +3983,7 @@ def non_redundant_index_generator(self): si = self._sindex imax = self._dim - 1 + si ind = [si for k in range(self._nid)] - sym = self._sym.copy() # we may modify this in the following + sym = list(self._sym) # we may modify this in the following antisym = self._antisym for pos in range(self._nid): for isym in antisym: diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index bbcc1ecb2e0..1fa457475a0 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -563,13 +563,13 @@ def symmetries(self): elif len(self._sym) == 1: s = "symmetry: {}; ".format(self._sym[0]) else: - s = "symmetries: {}; ".format(self._sym) + s = "symmetries: {}; ".format(list(self._sym)) if len(self._antisym) == 0: a = "no antisymmetry" elif len(self._antisym) == 1: a = "antisymmetry: {}".format(self._antisym[0]) else: - a = "antisymmetries: {}".format(self._antisym) + a = "antisymmetries: {}".format(list(self._antisym)) print(s+a) #### End of simple accessors ##### From 3619b4c163234f71c4e68d4c0442e56c5f4898dc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 11:04:11 -0700 Subject: [PATCH 376/742] src/sage/tensor, src/sage/manifolds: Sort _sym, _antisym, store as tuples of tuples --- src/sage/manifolds/differentiable/metric.py | 8 ++-- .../manifolds/differentiable/tensorfield.py | 39 ++----------------- src/sage/tensor/modules/comp.py | 29 ++++++++------ src/sage/tensor/modules/free_module_tensor.py | 39 ++----------------- 4 files changed, 29 insertions(+), 86 deletions(-) diff --git a/src/sage/manifolds/differentiable/metric.py b/src/sage/manifolds/differentiable/metric.py index 686af0d3505..445862d6795 100644 --- a/src/sage/manifolds/differentiable/metric.py +++ b/src/sage/manifolds/differentiable/metric.py @@ -647,7 +647,7 @@ def set(self, symbiform): raise TypeError("the argument must be a tensor field") if symbiform._tensor_type != (0,2): raise TypeError("the argument must be of tensor type (0,2)") - if symbiform._sym != [(0,1)]: + if symbiform._sym != ((0,1),): raise TypeError("the argument must be symmetric") if not symbiform._domain.is_subset(self._domain): raise TypeError("the symmetric bilinear form is not defined " + @@ -2301,7 +2301,7 @@ def set(self, symbiform): "values on a parallelizable domain") if symbiform._tensor_type != (0,2): raise TypeError("the argument must be of tensor type (0,2)") - if symbiform._sym != [(0,1)]: + if symbiform._sym != ((0,1),): raise TypeError("the argument must be symmetric") if symbiform._vmodule is not self._vmodule: raise TypeError("the symmetric bilinear form and the metric are " + @@ -2781,7 +2781,7 @@ def set(self, symbiform): raise TypeError("the argument must be a tensor field") if symbiform._tensor_type != (0,2): raise TypeError("the argument must be of tensor type (0,2)") - if symbiform._sym != [(0,1)]: + if symbiform._sym != ((0,1),): raise TypeError("the argument must be symmetric") if not symbiform._domain.is_subset(self._domain): raise TypeError("the symmetric bilinear form is not defined " + @@ -3019,7 +3019,7 @@ def set(self, symbiform): "values on a parallelizable domain") if symbiform._tensor_type != (0,2): raise TypeError("the argument must be of tensor type (0,2)") - if symbiform._sym != [(0,1)]: + if symbiform._sym != ((0,1),): raise TypeError("the argument must be symmetric") if symbiform._vmodule is not self._vmodule: raise TypeError("the symmetric bilinear form and the metric are " + diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index 1370b104140..a2aad4d4937 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -58,6 +58,7 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.structure.element import ModuleElementWithMutability +from sage.tensor.modules.comp import CompWithSym from sage.tensor.modules.free_module_tensor import FreeModuleTensor from sage.tensor.modules.tensor_with_indices import TensorWithIndices @@ -495,40 +496,8 @@ def __init__( self._restrictions = {} # dict. of restrictions of self on subdomains # of self._domain, with the subdomains as keys # Treatment of symmetry declarations: - self._sym = [] - if sym is not None and sym != []: - if isinstance(sym[0], (int, Integer)): - # a single symmetry is provided as a tuple -> 1-item list: - sym = [tuple(sym)] - for isym in sym: - if len(isym) > 1: - for i in isym: - if i < 0 or i > self._tensor_rank - 1: - raise IndexError("invalid position: {}".format(i) + - " not in [0,{}]".format(self._tensor_rank-1)) - self._sym.append(tuple(isym)) - self._antisym = [] - if antisym is not None and antisym != []: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple -> 1-item list: - antisym = [tuple(antisym)] - for isym in antisym: - if len(isym) > 1: - for i in isym: - if i < 0 or i > self._tensor_rank - 1: - raise IndexError("invalid position: {}".format(i) + - " not in [0,{}]".format(self._tensor_rank-1)) - self._antisym.append(tuple(isym)) - # Final consistency check: - index_list = [] - for isym in self._sym: - index_list += isym - for isym in self._antisym: - index_list += isym - if len(index_list) != len(set(index_list)): - # There is a repeated index position: - raise IndexError("incompatible lists of symmetries: the same " + - "position appears more than once") + self._sym, self._antisym = CompWithSym._canonicalize_sym_antisym( + self._tensor_rank, sym, antisym) # Initialization of derived quantities: self._init_derived() @@ -591,7 +560,7 @@ def _repr_(self): """ # Special cases - if self._tensor_type == (0,2) and self._sym == [(0,1)]: + if self._tensor_type == (0,2) and self._sym == ((0,1),): description = "Field of symmetric bilinear forms " if self._name is not None: description += self._name + " " diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index d9c3dfdfe3e..3318c7b3ebf 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -3008,7 +3008,7 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): sage: from sage.tensor.modules.comp import CompWithSym sage: CompWithSym._canonicalize_sym_antisym(6, [(2, 1)]) - ([(2, 1)], []) + (((1, 2),), ()) """ result_sym = [] if sym is None: @@ -3023,8 +3023,8 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): sym = [tuple(sym)] for isym in sym: if len(isym) < 2: - raise IndexError("at least two index positions must be " + - "provided to define a symmetry") + # Drop trivial symmetry + continue for i in isym: if i < 0 or i > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + @@ -3043,8 +3043,8 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): antisym = [tuple(antisym)] for isym in antisym: if len(isym) < 2: - raise IndexError("at least two index positions must be " + - "provided to define an antisymmetry") + # Drop trivial antisymmetry + continue for i in isym: if i < 0 or i > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + @@ -3060,6 +3060,11 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): # There is a repeated index position: raise IndexError("incompatible lists of symmetries: the same " + "index position appears more than once") + # Canonicalize sort order, make tuples + result_sym = [tuple(sorted(s)) for s in result_sym] + result_antisym = [tuple(sorted(s)) for s in result_antisym] + result_sym = tuple(sorted(result_sym)) + result_antisym = tuple(sorted(result_antisym)) return result_sym, result_antisym def _repr_(self): @@ -3392,9 +3397,9 @@ def swap_adjacent_indices(self, pos1, pos2, pos3): [[0, 7, 8], [-7, 0, 9], [-8, -9, 0]]] sage: c1 = c.swap_adjacent_indices(0,1,3) sage: c._antisym # c is antisymmetric with respect to the last pair of indices... - [(1, 2)] + ((1, 2),) sage: c1._antisym #...while c1 is antisymmetric with respect to the first pair of indices - [(0, 1)] + ((0, 1),) sage: c[0,1,2] 3 sage: c1[1,2,0] @@ -3415,6 +3420,8 @@ def swap_adjacent_indices(self, pos1, pos2, pos3): for s in self._antisym: new_s = [new_lpos.index(pos) for pos in s] result._antisym.append(tuple(sorted(new_s))) + result._sym, result._antisym = self._canonicalize_sym_antisym( + self._nid, result._sym, result._antisym) # The values: for ind, val in self._comp.items(): new_ind = ind[:pos1] + ind[pos2:pos3] + ind[pos1:pos2] + ind[pos3:] @@ -4159,7 +4166,7 @@ def symmetrize(self, *pos): (0, 0, 1) ], with symmetry on the index positions (0, 1), with symmetry on the index positions (2, 3) sage: a1._sym # a1 has two distinct symmetries: - [(0, 1), (2, 3)] + ((0, 1), (2, 3)) sage: a[0,1,2,0] == a[0,0,2,1] # a is symmetric w.r.t. positions 1 and 3 True sage: a1[0,1,2,0] == a1[0,0,2,1] # a1 is not @@ -4437,10 +4444,10 @@ def antisymmetrize(self, *pos): (1, 0, 0), (0, 1, 0), (0, 0, 1) - ], with antisymmetry on the index positions (1, 3), - with antisymmetry on the index positions (0, 2) + ], with antisymmetry on the index positions (0, 2), + with antisymmetry on the index positions (1, 3) sage: s._antisym # the antisymmetry (0,1,2) has been reduced to (0,2), since 1 is involved in the new antisymmetry (1,3): - [(1, 3), (0, 2)] + ((0, 2), (1, 3)) Partial antisymmetrization of 4-indices components with a symmetry on the first two indices:: diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index 1fa457475a0..4d6d05c57b8 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -309,41 +309,8 @@ def __init__( # bases, with the bases as keys (initially empty) # Treatment of symmetry declarations: - self._sym = [] - if sym is not None and sym != []: - if isinstance(sym[0], (int, Integer)): - # a single symmetry is provided as a tuple -> 1-item list: - sym = [tuple(sym)] - for isym in sym: - if len(isym) > 1: - for i in isym: - if i<0 or i>self._tensor_rank-1: - raise IndexError("invalid position: " + str(i) + - " not in [0," + str(self._tensor_rank-1) + "]") - self._sym.append(tuple(isym)) - self._antisym = [] - if antisym is not None and antisym != []: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple -> 1-item list: - antisym = [tuple(antisym)] - for isym in antisym: - if len(isym) > 1: - for i in isym: - if i<0 or i>self._tensor_rank-1: - raise IndexError("invalid position: " + str(i) + - " not in [0," + str(self._tensor_rank-1) + "]") - self._antisym.append(tuple(isym)) - - # Final consistency check: - index_list = [] - for isym in self._sym: - index_list += isym - for isym in self._antisym: - index_list += isym - if len(index_list) != len(set(index_list)): - # There is a repeated index position: - raise IndexError("incompatible lists of symmetries: the same " + - "position appears more than once") + self._sym, self._antisym = CompWithSym._canonicalize_sym_antisym( + self._tensor_rank, sym, antisym) # Initialization of derived quantities: FreeModuleTensor._init_derived(self) @@ -405,7 +372,7 @@ def _repr_(self): """ # Special cases - if self._tensor_type == (0,2) and self._sym == [(0,1)]: + if self._tensor_type == (0,2) and self._sym == ((0,1),): description = "Symmetric bilinear form " else: # Generic case From 970c6c88e3b1e8efc54fccff8b68a67c83bdcf5b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 11:50:42 -0700 Subject: [PATCH 377/742] src/sage/tensor, src/sage/manifolds: Sort _sym, _antisym, store as tuples of tuples (fixup) --- .../manifolds/differentiable/pseudo_riemannian_submanifold.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py index 2eaef7510c8..3aef31eb703 100644 --- a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +++ b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py @@ -1173,7 +1173,7 @@ def ambient_second_fundamental_form(self): g.restrict(chart.domain()).contract(pf[j]) * self.scalar_field({chart: k.comp(chart.frame())[:][i, j]}) for i in range(self._dim) for j in range(self._dim)) - gam_rst._sym = [(0, 1)] + gam_rst._sym = ((0, 1),) self._ambient_second_fundamental_form.set_restriction(gam_rst) charts = iter(self.top_charts()) From 9f15e00a4396a993fe412b41993cd542d4f177a0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 11:50:57 -0700 Subject: [PATCH 378/742] src/sage/tensor: Allow _sym, _antisym attributes to be tuples (fixup) --- src/sage/manifolds/differentiable/vectorfield_module.py | 8 ++++---- src/sage/tensor/modules/finite_rank_free_module.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index cf3f1dc687d..393218bc7c0 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -787,7 +787,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, # a single antisymmetry is provided as a tuple or a # range object; it is converted to a 1-item list: antisym = [tuple(antisym)] - if isinstance(antisym, list): + if isinstance(antisym, (tuple, list)): antisym0 = antisym[0] else: antisym0 = antisym @@ -799,7 +799,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, # a single antisymmetry is provided as a tuple or a # range object; it is converted to a 1-item list: antisym = [tuple(antisym)] - if isinstance(antisym, list): + if isinstance(antisym, (tuple, list)): antisym0 = antisym[0] else: antisym0 = antisym @@ -2102,7 +2102,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, # a single antisymmetry is provided as a tuple or a # range object; it is converted to a 1-item list: antisym = [tuple(antisym)] - if isinstance(antisym, list): + if isinstance(antisym, (tuple, list)): antisym0 = antisym[0] else: antisym0 = antisym @@ -2114,7 +2114,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, # a single antisymmetry is provided as a tuple or a # range object; it is converted to a 1-item list: antisym = [tuple(antisym)] - if isinstance(antisym, list): + if isinstance(antisym, (tuple, list)): antisym0 = antisym[0] else: antisym0 = antisym diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 091dc252ad5..c0692104581 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1458,7 +1458,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, # a single antisymmetry is provided as a tuple or a range # object; it is converted to a 1-item list: antisym = [tuple(antisym)] - if isinstance(antisym, list): + if isinstance(antisym, (tuple, list)): antisym0 = antisym[0] else: antisym0 = antisym @@ -1470,7 +1470,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, # a single antisymmetry is provided as a tuple or a range # object; it is converted to a 1-item list: antisym = [tuple(antisym)] - if isinstance(antisym, list): + if isinstance(antisym, (tuple, list)): antisym0 = antisym[0] else: antisym0 = antisym From 04706dd4af5955e9fa38d5c9ab49d25605d344fd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 12:09:01 -0700 Subject: [PATCH 379/742] FiniteRankFreeModule.tensor_module: Canonicalize sym, antisym --- src/sage/tensor/modules/finite_rank_free_module.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index a0b4973f91b..8d3c41e4e26 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1197,9 +1197,16 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): and :class:`~sage.tensor.modules.tensor_free_module.TensorFreeSubmodule_sym` for more documentation. + TESTS:: + + sage: M = FiniteRankFreeModule(ZZ, 2) + sage: M.tensor_module(2, 0, sym=(0,1)) is M.symmetric_power(2) + True """ + from .comp import CompWithSym, CompFullyAntiSym + + sym, antisym = CompWithSym._canonicalize_sym_antisym(k + l, sym, antisym) if sym or antisym: - # TODO: Canonicalize sym, antisym, make hashable key = (k, l, sym, antisym) else: key = (k, l) From c47b060895cdf8c492d2dc78f222e0e2f8927e58 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 30 Aug 2022 09:44:22 +0900 Subject: [PATCH 380/742] Doing some changes to normal symmetric functions plethysm to support coefficients and lazy symmetric functions. --- src/sage/combinat/sf/sfa.py | 67 ++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index d440135e7e9..8abee9b6b3b 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -3073,6 +3073,31 @@ def plethysm(self, x, include=None, exclude=None): sage: sum(s[mu](X)*s[mu.conjugate()](Y) for mu in P5) == sum(m[mu](X)*e[mu](Y) for mu in P5) True + Sage can also do the plethysm with an element in the completion:: + + sage: L = LazySymmetricFunctions(s) + sage: f = s[2,1] + sage: g = L(s[1]) / (1 - L(s[1])); g + s[1] + (s[1,1]+s[2]) + (s[1,1,1]+2*s[2,1]+s[3]) + + (s[1,1,1,1]+3*s[2,1,1]+2*s[2,2]+3*s[3,1]+s[4]) + + (s[1,1,1,1,1]+4*s[2,1,1,1]+5*s[2,2,1]+6*s[3,1,1]+5*s[3,2]+4*s[4,1]+s[5]) + + ... + O^8 + sage: fog = f(g) + sage: fog[:8] + [s[2, 1], + s[1, 1, 1, 1] + 3*s[2, 1, 1] + 2*s[2, 2] + 3*s[3, 1] + s[4], + 2*s[1, 1, 1, 1, 1] + 8*s[2, 1, 1, 1] + 10*s[2, 2, 1] + + 12*s[3, 1, 1] + 10*s[3, 2] + 8*s[4, 1] + 2*s[5], + 3*s[1, 1, 1, 1, 1, 1] + 17*s[2, 1, 1, 1, 1] + 30*s[2, 2, 1, 1] + + 16*s[2, 2, 2] + 33*s[3, 1, 1, 1] + 54*s[3, 2, 1] + 16*s[3, 3] + + 33*s[4, 1, 1] + 30*s[4, 2] + 17*s[5, 1] + 3*s[6], + 5*s[1, 1, 1, 1, 1, 1, 1] + 30*s[2, 1, 1, 1, 1, 1] + 70*s[2, 2, 1, 1, 1] + + 70*s[2, 2, 2, 1] + 75*s[3, 1, 1, 1, 1] + 175*s[3, 2, 1, 1] + + 105*s[3, 2, 2] + 105*s[3, 3, 1] + 100*s[4, 1, 1, 1] + 175*s[4, 2, 1] + + 70*s[4, 3] + 75*s[5, 1, 1] + 70*s[5, 2] + 30*s[6, 1] + 5*s[7]] + sage: parent(fog) + Lazy completion of Symmetric Functions over Rational Field in the Schur basis + .. SEEALSO:: :meth:`frobenius` @@ -3089,41 +3114,59 @@ def plethysm(self, x, include=None, exclude=None): sage: f = a1*p[1] + a2*p[2] + a11*p[1,1] sage: g = b1*p[1] + b21*p[2,1] + b111*p[1,1,1] sage: r = f(g); r - a1*b1*p[1] + a11*b1^2*p[1, 1] + a1*b111*p[1, 1, 1] + 2*a11*b1*b111*p[1, 1, 1, 1] + a11*b111^2*p[1, 1, 1, 1, 1, 1] + a2*b1^2*p[2] + a1*b21*p[2, 1] + 2*a11*b1*b21*p[2, 1, 1] + 2*a11*b21*b111*p[2, 1, 1, 1, 1] + a11*b21^2*p[2, 2, 1, 1] + a2*b111^2*p[2, 2, 2] + a2*b21^2*p[4, 2] + a1*b1*p[1] + a11*b1^2*p[1, 1] + a1*b111*p[1, 1, 1] + + 2*a11*b1*b111*p[1, 1, 1, 1] + a11*b111^2*p[1, 1, 1, 1, 1, 1] + + a2*b1^2*p[2] + a1*b21*p[2, 1] + 2*a11*b1*b21*p[2, 1, 1] + + 2*a11*b21*b111*p[2, 1, 1, 1, 1] + a11*b21^2*p[2, 2, 1, 1] + + a2*b111^2*p[2, 2, 2] + a2*b21^2*p[4, 2] sage: r - f(g, include=[]) (a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2] Check that we can compute the plethysm with a constant:: sage: p[2,2,1](2) - 8 + 8*p[] sage: p[2,2,1](a1) - a1^5 + a1^5*p[] .. TODO:: The implementation of plethysm in :class:`sage.data_structures.stream.Stream_plethysm` seems to be faster. This should be investigated. - """ parent = self.parent() + if not self: + return self + R = parent.base_ring() tHA = HopfAlgebrasWithBasis(R).TensorProducts() - tensorflag = tHA in x.parent().categories() - if not (is_SymmetricFunction(x) or tensorflag): - raise TypeError("only know how to compute plethysms " - "between symmetric functions or tensors " - "of symmetric functions") + from sage.structure.element import parent as get_parent + Px = get_parent(x) + tensorflag = Px in tHA + if not tensorflag and Px is not R: + if not is_SymmetricFunction(x): + from sage.rings.lazy_series import LazySymmetricFunction + if isinstance(x, LazySymmetricFunction): + from sage.rings.lazy_series_ring import LazySymmetricFunctions + L = LazySymmetricFunctions(parent) + return L(self)(x) + + # Try to coerce into a symmetric function + phi = parent.coerce_map_from(Px) + if phi is None: + raise TypeError("only know how to compute plethysms " + "between symmetric functions or tensors " + "of symmetric functions") + x = phi(x) + p = parent.realization_of().power() - if self == parent.zero(): - return self degree_one = _variables_recursive(R, include=include, exclude=exclude) if tensorflag: - tparents = x.parent()._sets + tparents = Px._sets s = sum(d * prod(sum(_raise_variables(c, r, degree_one) * tensor([p[r].plethysm(base(la)) for base, la in zip(tparents, trm)]) From 5776c6172a683ef8f8f9d4fdb7c99eee994ccc52 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 30 Aug 2022 10:19:13 +0900 Subject: [PATCH 381/742] Adding the category of commutative rings to the category of tensor products of commutative algebras. --- src/sage/categories/commutative_algebras.py | 34 ++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/commutative_algebras.py b/src/sage/categories/commutative_algebras.py index ec4037f9a84..0f24e90c524 100644 --- a/src/sage/categories/commutative_algebras.py +++ b/src/sage/categories/commutative_algebras.py @@ -10,8 +10,11 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.algebras import Algebras +from sage.categories.commutative_rings import CommutativeRings +from sage.categories.tensor import TensorProductsCategory class CommutativeAlgebras(CategoryWithAxiom_over_base_ring): """ @@ -36,7 +39,7 @@ class CommutativeAlgebras(CategoryWithAxiom_over_base_ring): True sage: TestSuite(CommutativeAlgebras(ZZ)).run() - Todo: + .. TODO:: - product ( = Cartesian product) - coproduct ( = tensor product over base ring) @@ -58,3 +61,32 @@ def __contains__(self, A): """ return super().__contains__(A) or \ (A in Algebras(self.base_ring()) and hasattr(A, "is_commutative") and A.is_commutative()) + + class TensorProducts(TensorProductsCategory): + """ + The category of commutative algebras constructed by tensor product of commutative algebras. + """ + + @cached_method + def extra_super_categories(self): + """ + EXAMPLES:: + + sage: Algebras(QQ).Commutative().TensorProducts().extra_super_categories() + [Category of commutative rings] + sage: Algebras(QQ).Commutative().TensorProducts().super_categories() + [Category of tensor products of algebras over Rational Field, + Category of commutative algebras over Rational Field] + + TESTS:: + + sage: X = algebras.Shuffle(QQ, 'ab') + sage: Y = algebras.Shuffle(QQ, 'bc') + sage: X in Algebras(QQ).Commutative() + True + sage: T = tensor([X, Y]) + sage: T in CommutativeRings() + True + """ + return [CommutativeRings()] + From a2e9ed7c483e13980dd2849ca25c59e6995ca72c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 30 Aug 2022 10:24:22 +0900 Subject: [PATCH 382/742] Making the test for coercion of plethysms wrt tesnor products more robust. --- src/sage/combinat/sf/sfa.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 8abee9b6b3b..c573d2399c7 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -3127,9 +3127,19 @@ def plethysm(self, x, include=None, exclude=None): sage: p[2,2,1](2) 8*p[] + sage: p[2,2,1](int(2)) + 8*p[] + sage: p[2,2,1](a1) a1^5*p[] + sage: X = algebras.Shuffle(QQ, 'ab') + sage: Y = algebras.Shuffle(QQ, 'bc') + sage: T = tensor([X,Y]) + sage: s = SymmetricFunctions(T).s() + sage: s(2*T.one()) + (2*B[word:]#B[word:])*s[] + .. TODO:: The implementation of plethysm in @@ -3145,8 +3155,11 @@ def plethysm(self, x, include=None, exclude=None): from sage.structure.element import parent as get_parent Px = get_parent(x) tensorflag = Px in tHA - if not tensorflag and Px is not R: - if not is_SymmetricFunction(x): + if not is_SymmetricFunction(x): + if Px is R: # Handle stuff that is directly in the base ring + x = parent(x) + elif (not tensorflag or any(not isinstance(factor, SymmetricFunctionAlgebra_generic) + for factor in Px._sets)): from sage.rings.lazy_series import LazySymmetricFunction if isinstance(x, LazySymmetricFunction): from sage.rings.lazy_series_ring import LazySymmetricFunctions @@ -3155,11 +3168,12 @@ def plethysm(self, x, include=None, exclude=None): # Try to coerce into a symmetric function phi = parent.coerce_map_from(Px) - if phi is None: + if phi is not None: + x = phi(x) + elif not tensorflag: raise TypeError("only know how to compute plethysms " "between symmetric functions or tensors " "of symmetric functions") - x = phi(x) p = parent.realization_of().power() From b537651a077c050ef4fb507fa2686a1f692abebd Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 29 Aug 2022 22:26:19 -0500 Subject: [PATCH 383/742] Fix parent --- src/sage/combinat/integer_vector.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index 26016b8cc55..35819111495 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -473,13 +473,20 @@ def trim(self): [4, 3, 3] sage: IV([0,0,0]).trim() [] + + sage: IV = IntegerVectors(k=4) + sage: v = IV([4,3,2,0]).trim(); v + [4, 3, 2] + sage: v.parent() + Integer vectors """ + P = IntegerVectors() v = list(self) if all(i == 0 for i in v): - return self.parent()([]) + return P.element_class(P, [], check=False) while not v[-1]: v = v[:-1] - return self.parent()(v) + return P.element_class(P, v, check=False) class IntegerVectors(Parent, metaclass=ClasscallMetaclass): """ From 726e56229dd72791dc649265b73ec45bdab46c5f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 20:42:31 -0700 Subject: [PATCH 384/742] src/sage/tensor/modules/finite_rank_free_module.py: Remove unused import --- src/sage/tensor/modules/finite_rank_free_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 8d3c41e4e26..4a99be4c88f 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1203,7 +1203,7 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): sage: M.tensor_module(2, 0, sym=(0,1)) is M.symmetric_power(2) True """ - from .comp import CompWithSym, CompFullyAntiSym + from .comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym(k + l, sym, antisym) if sym or antisym: From 218b548a3920587c27b3cfd1b63d5b7f4dc431f9 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 29 Aug 2022 22:42:30 -0500 Subject: [PATCH 385/742] Make a generator, reorder, and move tmp variable --- src/sage/combinat/partition.py | 126 ++++++++++++++++----------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index af39531c26c..b6e606abf1f 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -4752,78 +4752,25 @@ def add_horizontal_border_strip(self, k): res.append(_Partitions(tmp)) return res - def horizontal_border_strip_cells(self, k): - """ - Return a list of all the horizontal border strips of length ``k`` - which can be added to ``self``, where each horizontal border strip is - represented as a list of cells. - - EXAMPLES:: - - sage: Partition([]).horizontal_border_strip_cells(0) - [] - sage: Partition([3,2,1]).horizontal_border_strip_cells(0) - [] - sage: Partition([]).horizontal_border_strip_cells(2) - [[(0, 0), (0, 1)]] - sage: Partition([2,2]).horizontal_border_strip_cells(2) - [[(0, 2), (0, 3)], [(0, 2), (2, 0)], [(2, 0), (2, 1)]] - sage: Partition([3,2,2]).horizontal_border_strip_cells(2) - [[(0, 3), (0, 4)], - [(0, 3), (1, 2)], - [(0, 3), (3, 0)], - [(1, 2), (3, 0)], - [(3, 0), (3, 1)]] - """ - if k == 0: - return list() - - L = self._list - res = [] - shelf = [k] # the number of boxes which will fit in a row - mapping = [0] # a record of the rows - for i in range(len(L)-1): - val = L[i] - L[i+1] - if not val: - continue - mapping.append(i+1) - shelf.append(val) - - # add the last shelf - if L: - mapping.append(len(L)) - shelf.append(L[-1]) - - L.append(0) # add room on the bottom - # list all of the positions for cells - # filling each self from the top to bottom - for iv in IntegerListsBackend_invlex(k, length=len(shelf), ceiling=shelf, check=False)._iter(): - tmp = [] - # mapping[i] is the row index, val is the number of cells added to the row. - for i, val in enumerate(iv): - tmp.extend((mapping[i], L[mapping[i]] + j) for j in range(val)) - res.append(tmp) - return res - def vertical_border_strip_cells(self, k): """ Return a list of all the vertical border strips of length ``k`` which can be added to ``self``, where each horizontal border strip is - represented as a list of cells. + a ``generator`` of cells. EXAMPLES:: - sage: Partition([]).vertical_border_strip_cells(0) + sage: list(Partition([]).vertical_border_strip_cells(0)) [] - sage: Partition([3,2,1]).vertical_border_strip_cells(0) + sage: list(Partition([3,2,1]).vertical_border_strip_cells(0)) [] - sage: Partition([]).vertical_border_strip_cells(2) + sage: list(Partition([]).vertical_border_strip_cells(2)) [[(0, 0), (1, 0)]] - sage: Partition([2,2]).vertical_border_strip_cells(2) + sage: list(Partition([2,2]).vertical_border_strip_cells(2)) [[(0, 2), (1, 2)], [(0, 2), (2, 0)], [(2, 0), (3, 0)]] - sage: Partition([3,2,2]).vertical_border_strip_cells(2) + sage: list(Partition([3,2,2]).vertical_border_strip_cells(2)) [[(0, 3), (1, 2)], [(0, 3), (3, 0)], [(1, 2), (2, 2)], @@ -4851,8 +4798,10 @@ def vertical_border_strip_cells(self, k): # the first line shelf.append(k) # list all of the positions for cells - for iv in IntegerListsBackend_invlex(k, length=len(shelf), ceiling=shelf, check=False)._iter(): - tmp = self._list + [0]*k + tmp = self._list + [0]*k + for iv in IntegerListsBackend_invlex(k, length=len(shelf), + ceiling=shelf, + check=False)._iter(): j = 0 current_strip = [] for t in range(len(iv)): @@ -4860,8 +4809,59 @@ def vertical_border_strip_cells(self, k): current_strip.append((j, tmp[j])) j += 1 j = sum(shelf[:t+1]) - res.append(current_strip) - return res + yield current_strip + + def horizontal_border_strip_cells(self, k): + """ + Return a list of all the horizontal border strips of length ``k`` + which can be added to ``self``, where each horizontal border strip is + a ``generator`` of cells. + + EXAMPLES:: + + sage: list(Partition([]).horizontal_border_strip_cells(0)) + [] + sage: list(Partition([3,2,1]).horizontal_border_strip_cells(0)) + [] + sage: list(Partition([]).horizontal_border_strip_cells(2)) + [[(0, 0), (0, 1)]] + sage: list(Partition([2,2]).horizontal_border_strip_cells(2)) + [[(0, 2), (0, 3)], [(0, 2), (2, 0)], [(2, 0), (2, 1)]] + sage: list(Partition([3,2,2]).horizontal_border_strip_cells(2)) + [[(0, 3), (0, 4)], + [(0, 3), (1, 2)], + [(0, 3), (3, 0)], + [(1, 2), (3, 0)], + [(3, 0), (3, 1)]] + """ + if k == 0: + return list() + + L = self._list + res = [] + shelf = [k] # the number of boxes which will fit in a row + mapping = [0] # a record of the rows + for i in range(len(L)-1): + val = L[i] - L[i+1] + if not val: + continue + mapping.append(i+1) + shelf.append(val) + + # add the last shelf + if L: + mapping.append(len(L)) + shelf.append(L[-1]) + + L.append(0) # add room on the bottom + # list all of the positions for cells + # filling each self from the top to bottom + for iv in IntegerListsBackend_invlex(k, length=len(shelf), ceiling=shelf, check=False)._iter(): + tmp = [] + # mapping[i] is the row index, val is the number of cells added to the row. + for i, val in enumerate(iv): + tmp.extend((mapping[i], L[mapping[i]] + j) for j in range(val)) + yield tmp def remove_horizontal_border_strip(self, k): """ From 4958211e8186b777705a27a31663967cdbd0e24e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 23:24:29 -0700 Subject: [PATCH 386/742] Components.items: New --- src/sage/tensor/modules/comp.py | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 04f14f782f0..695646d18db 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -1023,6 +1023,40 @@ def _set_value_list(self, ind, format_type, val): for i in range(si, nsi): self._set_value_list(ind + [i], format_type, val[i-si]) + def items(self): + r""" + Return an iterable of ``(indices, value)`` elements. + + This may (but is not guaranteed to) suppress zero values. + + EXAMPLES:: + + sage: from sage.tensor.modules.comp import Components, CompWithSym + + sage: c = Components(ZZ, (ZZ^2).basis(), 3) + sage: c[0,1,0], c[1,0,1], c[1,1,1] = -2, 5, 3 + sage: list(c.items()) + [((0, 1, 0), -2), ((1, 0, 1), 5), ((1, 1, 1), 3)] + + sage: c = CompWithSym(ZZ, (ZZ^2).basis(), 3, sym=((1, 2))) + sage: c[0,1,0], c[1,0,1], c[1,1,1] = -2, 5, 3 + sage: list(c.items()) + [((0, 0, 1), -2), + ((0, 1, 0), -2), + ((1, 0, 1), 5), + ((1, 1, 0), 5), + ((1, 1, 1), 3)] + + """ + for ind in self.index_generator(): + val = self[ind] + if hasattr(val, 'is_trivial_zero'): + zero_value = val.is_trivial_zero() + else: + zero_value = val == 0 + if not zero_value: + yield ind, val + def display(self, symbol, latex_symbol=None, index_positions=None, index_labels=None, index_latex_labels=None, format_spec=None, only_nonzero=True, only_nonredundant=False): From abf1edc239e4ce2db13455df39e812e2402cfe63 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 30 Aug 2022 15:56:09 +0900 Subject: [PATCH 387/742] Choosing smaller degree elements to run the test suite. --- src/sage/algebras/yangian.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/yangian.py b/src/sage/algebras/yangian.py index 185d62ae09e..55bb61fccf5 100644 --- a/src/sage/algebras/yangian.py +++ b/src/sage/algebras/yangian.py @@ -1001,7 +1001,10 @@ def __init__(self, Y): EXAMPLES:: sage: grY = Yangian(QQ, 4).graded_algebra() - sage: TestSuite(grY).run() # long time + sage: g = grY.indices().gens() + sage: x = grY(g[1,1,1] * g[1,1,2]^2 * g[1,1,3]^3 * g[3,1,1]) + sage: elts = [grY(g[1,1,1]), grY(g[2,1,1]), x] + sage: TestSuite(grY).run(elements=elts) # long time """ if Y._filtration != 'loop': raise ValueError("the Yangian must have the loop filtration") From 74d94934cad6eaa082f5beec41dd7440c7441a63 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 23:58:01 -0700 Subject: [PATCH 388/742] Matrix.items: New --- src/sage/matrix/matrix0.pyx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/matrix/matrix0.pyx b/src/sage/matrix/matrix0.pyx index 00037358faa..372ba91ec65 100644 --- a/src/sage/matrix/matrix0.pyx +++ b/src/sage/matrix/matrix0.pyx @@ -248,6 +248,22 @@ cdef class Matrix(sage.structure.element.Matrix): monomial_coefficients = dict + def items(self): + r""" + Return an iterable of ``((i,j), value)`` elements. + + This may (but is not guaranteed to) suppress zero values. + + EXAMPLES:: + + sage: a = matrix(QQ['x,y'], 2, range(6), sparse=True); a + [0 1 2] + [3 4 5] + sage: list(a.items()) + [((0, 1), 1), ((0, 2), 2), ((1, 0), 3), ((1, 1), 4), ((1, 2), 5)] + """ + return self._dict().items() + def _dict(self): """ Unsafe version of the dict method, mainly for internal use. From 94219d42cd8be4a910d09f9c2e2b3e89081cc64c Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 30 Aug 2022 10:37:42 +0200 Subject: [PATCH 389/742] fix plethysm with f having finite support --- src/sage/data_structures/stream.py | 47 ++++++++++++++++++++++-------- src/sage/rings/lazy_series.py | 19 +++++------- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 61e140e006c..3c60ef71473 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -1671,7 +1671,8 @@ class Stream_plethysm(Stream_binary): INPUT: - ``f`` -- a :class:`Stream` - - ``g`` -- a :class:`Stream` with positive order + - ``g`` -- a :class:`Stream` with positive order, unless ``f`` is + of :class:`Stream_exact`. - ``p`` -- the powersum symmetric functions - ``ring`` (optional, default ``None``) -- the ring the result should be in, by default ``p`` @@ -1702,12 +1703,20 @@ class Stream_plethysm(Stream_binary): s[1, 1, 1] + s[2, 1] + 2*s[3], s[1, 1, 1, 1] + s[2, 1, 1] + 3*s[3, 1] + 2*s[4]] + This class also handles the plethysm of an exact stream with a + stream of order `0`:: + + sage: from sage.data_structures.stream import Stream_exact + sage: f = Stream_exact([s[1]], True, order=1) + sage: g = Stream_function(lambda n: s[n], s, True, 0) + sage: r = Stream_plethysm(f, g, p, s) + sage: [r[n] for n in range(3)] + [s[], s[1], s[2]] + TESTS: Check corner cases:: - sage: from sage.data_structures.stream import Stream_exact - sage: p = SymmetricFunctions(QQ).p() sage: f0 = Stream_exact([p([])], True) sage: f1 = Stream_exact([p[1]], True, order=1) sage: f2 = Stream_exact([p[2]], True, order=2 ) @@ -1768,7 +1777,10 @@ def __init__(self, f, g, p, ring=None, include=None, exclude=None): else: self._tensor_power = None p_f = Stream_map_coefficients(f, lambda x: x, p) - + if isinstance(f, Stream_exact) and not f._constant: + self._degree_f = f._degree + else: + self._degree_f = None self._degree_one = _variables_recursive(R, include=include, exclude=exclude) super().__init__(p_f, p_g, f._is_sparse, val) @@ -1799,9 +1811,13 @@ def get_coefficient(self, n): 4*s[1, 1, 1, 1, 1] + 4*s[2, 1, 1, 1] + 2*s[2, 2, 1] + 2*s[3, 1, 1] + s[3, 2] + s[4, 1] + s[5]] """ if not n: # special case of 0 - if self._tensor_power is None: - return self._left[0] - return self._basis(self._left[0].coefficient([])) + if self._right[0]: + assert self._degree_f is not None, "the plethysm with a lazy symmetric function of valuation 0 is defined only for symmetric functions of finite support" + + return sum((c * self._compute_product(n, la) + for k in range(self._left._approximate_order, self._degree_f) + for la, c in self._left[k]), + self._basis.zero()) return sum((c * self._compute_product(n, la) for k in range(self._left._approximate_order, n+1) @@ -1823,7 +1839,7 @@ def _compute_product(self, n, la): sage: A = h._compute_product(7, Partition([2, 1])); A 1/12*p[2, 2, 1, 1, 1] + 1/4*p[2, 2, 2, 1] + 1/6*p[3, 2, 2] + 1/12*p[4, 1, 1, 1] + 1/4*p[4, 2, 1] + 1/6*p[4, 3] - sage: A == p[2,1](s[2] + s[3]).homogeneous_component(7) + sage: A == p[2, 1](s[2] + s[3]).homogeneous_component(7) True sage: p2 = tensor([p, p]) @@ -1831,10 +1847,17 @@ def _compute_product(self, n, la): sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), p2, True, 1) sage: h = Stream_plethysm(f, g, p2) sage: A = h._compute_product(7, Partition([2, 1])) - sage: B = p[2,1](sum(g[n] for n in range(7))) + sage: B = p[2, 1](sum(g[n] for n in range(7))) sage: B = p2.element_class(p2, {m: c for m, c in B if sum(mu.size() for mu in m) == 7}) sage: A == B True + + sage: f = Stream_zero(True) # irrelevant for this test + sage: g = Stream_function(lambda n: s[n], p, True, 0) + sage: h = Stream_plethysm(f, g, p) + sage: B = p[2, 2, 1](sum(s[i] for i in range(7))) + sage: all(h._compute_product(k, Partition([2, 2, 1])) == B.restrict_degree(k) for k in range(7)) + True """ ret = self._basis.zero() la_exp = la.to_exp() @@ -1846,10 +1869,10 @@ def _compute_product(self, n, la): if any(d < self._right._approximate_order * m for m, d in zip(exp, k)): continue - temp = self._basis.one() + prod = self._basis.one() for i, m, d in zip(wgt, exp, k): - temp *= self._stretched_power_restrict_degree(i, m, d) - ret += temp + prod *= self._stretched_power_restrict_degree(i, m, d) + ret += prod return ret def _stretched_power_restrict_degree(self, i, m, d): diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 1d116837a92..bd56ffa83cb 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4222,8 +4222,7 @@ def __call__(self, *g, check=True): True sage: f = 1 / (1 - S(s[2])) sage: g = S(s[1]) / (1 - S(s[1])) - sage: h = f(g) - sage: h + sage: f(g) s[] + s[2] + (s[1,1,1]+2*s[2,1]+s[3]) + (2*s[1,1,1,1]+4*s[2,1,1]+5*s[2,2]+5*s[3,1]+3*s[4]) + (2*s[1,1,1,1,1]+10*s[2,1,1,1]+14*s[2,2,1]+18*s[3,1,1]+16*s[3,2]+14*s[4,1]+4*s[5]) @@ -4261,12 +4260,6 @@ def __call__(self, *g, check=True): if len(g) != fP._arity: raise ValueError("arity must be equal to the number of arguments provided") - # we actually do not need this - from sage.combinat.sf.sfa import is_SymmetricFunction - # if not all(isinstance(h, LazySymmetricFunction) - # or is_SymmetricFunction(h) or not h for h in g): - # raise ValueError("all arguments must be (possibly lazy) symmetric functions") - # Find a good parent for the result from sage.structure.element import get_coercion_model cm = get_coercion_model() @@ -4291,12 +4284,14 @@ def __call__(self, *g, check=True): g = g[0] if (isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant): - f = self.symmetric_function() + if not isinstance(g, LazySymmetricFunction): + f = self.symmetric_function() return f(g) - # g must be a LazySymmetricFunction + if (isinstance(g._coeff_stream, Stream_exact) and not g._coeff_stream._constant): + f = self.symmetric_function() gs = g.symmetric_function() return P(f(gs)) @@ -4308,8 +4303,8 @@ def __call__(self, *g, check=True): P = LazySymmetricFunctions(R) g = P(g) - # self has (potentially) infinitely many terms - if check: + if check and not (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): if g._coeff_stream._approximate_order == 0: if g[0]: raise ValueError("can only compose with a positive valuation series") From 6745cf1ac7ea98faa4f1b3da63143f4e87b5e7e7 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 30 Aug 2022 18:31:37 +0900 Subject: [PATCH 390/742] Some last details and optimizations to Stream_plethysm. --- src/sage/data_structures/stream.py | 48 +++++++++++++++++------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 3c60ef71473..59f5cdc3d84 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -97,6 +97,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.arith.misc import divisors +from sage.misc.misc_c import prod from sage.combinat.integer_vector_weighted import iterator_fast as wt_int_vec_iter from sage.combinat.sf.sfa import _variables_recursive, _raise_variables from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis @@ -1814,21 +1815,21 @@ def get_coefficient(self, n): if self._right[0]: assert self._degree_f is not None, "the plethysm with a lazy symmetric function of valuation 0 is defined only for symmetric functions of finite support" - return sum((c * self._compute_product(n, la) + return sum((c * self.compute_product(n, la) for k in range(self._left._approximate_order, self._degree_f) for la, c in self._left[k]), self._basis.zero()) - return sum((c * self._compute_product(n, la) + return sum((c * self.compute_product(n, la) for k in range(self._left._approximate_order, n+1) for la, c in self._left[k]), self._basis.zero()) - def _compute_product(self, n, la): - """ + def compute_product(self, n, la): + r""" Compute the product ``c * p[la](self._right)`` in degree ``n``. - TESTS:: + EXAMPLES:: sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function, Stream_zero sage: s = SymmetricFunctions(QQ).s() @@ -1859,27 +1860,34 @@ def _compute_product(self, n, la): sage: all(h._compute_product(k, Partition([2, 2, 1])) == B.restrict_degree(k) for k in range(7)) True """ + # This is the approximate order of the result + rao = self._right._approximate_order + ret_approx_order = rao * sum(la) ret = self._basis.zero() + if n < ret_approx_order: + return ret + la_exp = la.to_exp() wgt = [i for i, m in enumerate(la_exp, 1) if m] exp = [m for m in la_exp if m] - for k in wt_int_vec_iter(n, wgt): + wgt.reverse() + exp.reverse() + for k in wt_int_vec_iter(n - ret_approx_order, wgt): # TODO: it may make a big difference here if the - # approximate order would be updated - if any(d < self._right._approximate_order * m - for m, d in zip(exp, k)): - continue - prod = self._basis.one() - for i, m, d in zip(wgt, exp, k): - prod *= self._stretched_power_restrict_degree(i, m, d) - ret += prod + # approximate order would be updated. + # The test below is based off not removing the flxed block + #if any(d < self._right._approximate_order * m + # for m, d in zip(exp, k)): + # continue + ret += prod(self.stretched_power_restrict_degree(i, m, rao * m + d) + for i, m, d in zip(wgt, exp, k)) return ret - def _stretched_power_restrict_degree(self, i, m, d): - """ + def stretched_power_restrict_degree(self, i, m, d): + r""" Return the degree ``d*i`` part of ``p([i]*m)(g)``. - TESTS:: + EXAMPLES:: sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function, Stream_zero sage: s = SymmetricFunctions(QQ).s() @@ -1908,11 +1916,11 @@ def _stretched_power_restrict_degree(self, i, m, d): # integer and not a symmetric function if power_d: if self._tensor_power is None: - terms = {m.stretch(i): raised_c for m, c in power_d + terms = {mon.stretch(i): raised_c for mon, c in power_d if (raised_c := _raise_variables(c, i, self._degree_one))} else: - terms = {tuple((mu.stretch(i) for mu in m)): raised_c - for m, c in power_d + terms = {tuple((mu.stretch(i) for mu in mon)): raised_c + for mon, c in power_d if (raised_c := _raise_variables(c, i, self._degree_one))} return self._p.element_class(self._p, terms) From 3d6d39f43ce16eb4a606f49671c236cddd25cdbf Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 30 Aug 2022 12:52:51 +0200 Subject: [PATCH 391/742] fix typo in comment --- src/sage/data_structures/stream.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 59f5cdc3d84..bba14d63a82 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -1870,12 +1870,14 @@ def compute_product(self, n, la): la_exp = la.to_exp() wgt = [i for i, m in enumerate(la_exp, 1) if m] exp = [m for m in la_exp if m] + # the docstring of wt_int_vec_iter, i.e., iterator_fast, + # states that the weights should be weakly decreasing wgt.reverse() exp.reverse() for k in wt_int_vec_iter(n - ret_approx_order, wgt): # TODO: it may make a big difference here if the # approximate order would be updated. - # The test below is based off not removing the flxed block + # The test below is based on not removing the fixed block #if any(d < self._right._approximate_order * m # for m, d in zip(exp, k)): # continue From e383a018a3d6e8958f0d95d9d461b308484fa6a5 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 30 Aug 2022 14:09:34 +0200 Subject: [PATCH 392/742] add (currently failing) sanity check for functorial composition --- src/sage/rings/lazy_series.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 43e6a3a5f4f..e01103af69e 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4656,7 +4656,7 @@ def derivative_with_respect_to_p1(self, n=1): return P.element_class(P, coeff_stream) def functorial_composition(self, *args): - r"""Returns the functorial composition of ``self`` and ``g``. + r"""Return the functorial composition of ``self`` and ``g``. If `F` and `G` are species, their functorial composition is the species `F \Box G` obtained by setting `(F \Box G) [A] = F[ G[A] ]`. @@ -4704,6 +4704,32 @@ def functorial_composition(self, *args): 8 labellings of their vertices with two 1's and two 2's. + + + The derivative of the symmetric function `\sum_n h_n`, times + `p_1` is the neutral element with respect to functorial + composition:: + + sage: p = SymmetricFunctions(QQ).p() + sage: h = SymmetricFunctions(QQ).h() + sage: L = LazySymmetricFunctions(h) + sage: E = L(lambda n: h[n]) + sage: Ep = p[1]*E.derivative_with_respect_to_p1(); Ep + h[1] + (h[1,1]) + (h[2,1]) + (h[3,1]) + (h[4,1]) + (h[5,1]) + O^7 + sage: f = L(lambda n: randint(3, 6)*h[n]) + sage: f - Ep.functorial_composition(f) + O^7 + + TESTS: + + Check a corner case:: + + sage: L = LazySymmetricFunctions(h) + sage: Ep = L(lambda n: h[n-1]*h[1], valuation=1); Ep + h[1] + (h[1,1]) + (h[2,1]) + (h[3,1]) + (h[4,1]) + (h[5,1]) + (h[6,1]) + O^8 + sage: Ep.functorial_composition(L([3*h[0]])) + 3*h[] + """ if len(args) != self.parent()._arity: raise ValueError("arity must be equal to the number of arguments provided") From 29c6545fc396f0d0fbd6ebfa519d084f78bfa95f Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 30 Aug 2022 16:43:23 +0200 Subject: [PATCH 393/742] return correct partition in g_cycle_type, add documentation --- src/sage/rings/lazy_series.py | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index e01103af69e..76a4f2b6609 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4656,12 +4656,14 @@ def derivative_with_respect_to_p1(self, n=1): return P.element_class(P, coeff_stream) def functorial_composition(self, *args): - r"""Return the functorial composition of ``self`` and ``g``. + r""" + Return the functorial composition of ``self`` and ``g``. - If `F` and `G` are species, their functorial composition is the species - `F \Box G` obtained by setting `(F \Box G) [A] = F[ G[A] ]`. - In other words, an `(F \Box G)`-structure on a set `A` of labels is an - `F`-structure whose labels are the set of all `G`-structures on `A`. + If `F` and `G` are species, their functorial composition is + the species `F \Box G` obtained by setting `(F \Box G) [A] = + F[ G[A] ]`. In other words, an `(F \Box G)`-structure on a + set `A` of labels is an `F`-structure whose labels are the + set of all `G`-structures on `A`. It can be shown (as in section 2.2 of [BLL]_) that there is a corresponding operation on cycle indices: @@ -4675,6 +4677,12 @@ def functorial_composition(self, *args): This method implements that operation on cycle index series. + .. WARNING:: + + The operation `f \Box g` only makes sense when `g` + corresponds to a permutation representation, i.e., a + group action. + EXAMPLES: The species `G` of simple graphs can be expressed in terms of a functorial @@ -4724,11 +4732,10 @@ def functorial_composition(self, *args): Check a corner case:: + sage: h = SymmetricFunctions(QQ).h() sage: L = LazySymmetricFunctions(h) - sage: Ep = L(lambda n: h[n-1]*h[1], valuation=1); Ep - h[1] + (h[1,1]) + (h[2,1]) + (h[3,1]) + (h[4,1]) + (h[5,1]) + (h[6,1]) + O^8 - sage: Ep.functorial_composition(L([3*h[0]])) - 3*h[] + sage: L(h[2,1]).functorial_composition(L([3*h[0]])) + 3*h[] + O^7 """ if len(args) != self.parent()._arity: @@ -4749,9 +4756,11 @@ def functorial_composition(self, *args): f = Stream_map_coefficients(self._coeff_stream, lambda x: x, p) def g_cycle_type(s): + # the cycle type of G[sigma] of any permutation sigma + # with cycle type s if not s: if g[0]: - return Partition([ZZ(g[0].coefficient([]))]) + return Partition([1]*ZZ(g[0].coefficient([]))) return Partition([]) res = [] # in the species case, k is at most @@ -4774,8 +4783,10 @@ def coefficient(n): res = p(0) for s in Partitions(n): t = g_cycle_type(s) - q = t.aut() * f[t.size()].coefficient(t) / s.aut() - res += q * p(s) + f_t = f[t.size()] + if f_t: + q = t.aut() * f_t.coefficient(t) / s.aut() + res += q * p(s) return res coeff_stream = Stream_function(coefficient, R, P._sparse, 0) From dafdcb4df69656b8f363d8825b06ccd7f524edfb Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 30 Aug 2022 16:51:45 +0200 Subject: [PATCH 394/742] fix doctests --- src/sage/combinat/partition.py | 3 +-- src/sage/data_structures/stream.py | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index d24f6add1f6..b1a78d1a5ce 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -1066,8 +1066,7 @@ def stretch(self, k): sage: p = Partition([4,2,2,1,1]) sage: p.stretch(3) - [12,6,6,3,3] - + [12, 6, 6, 3, 3] """ return _Partitions([k * p for p in self]) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index bba14d63a82..4a5c814cba3 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -1837,7 +1837,7 @@ def compute_product(self, n, la): sage: f = Stream_zero(True) # irrelevant for this test sage: g = Stream_exact([s[2], s[3]], False, 0, 4, 2) sage: h = Stream_plethysm(f, g, p) - sage: A = h._compute_product(7, Partition([2, 1])); A + sage: A = h.compute_product(7, Partition([2, 1])); A 1/12*p[2, 2, 1, 1, 1] + 1/4*p[2, 2, 2, 1] + 1/6*p[3, 2, 2] + 1/12*p[4, 1, 1, 1] + 1/4*p[4, 2, 1] + 1/6*p[4, 3] sage: A == p[2, 1](s[2] + s[3]).homogeneous_component(7) @@ -1847,7 +1847,7 @@ def compute_product(self, n, la): sage: f = Stream_zero(True) # irrelevant for this test sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), p2, True, 1) sage: h = Stream_plethysm(f, g, p2) - sage: A = h._compute_product(7, Partition([2, 1])) + sage: A = h.compute_product(7, Partition([2, 1])) sage: B = p[2, 1](sum(g[n] for n in range(7))) sage: B = p2.element_class(p2, {m: c for m, c in B if sum(mu.size() for mu in m) == 7}) sage: A == B @@ -1857,7 +1857,7 @@ def compute_product(self, n, la): sage: g = Stream_function(lambda n: s[n], p, True, 0) sage: h = Stream_plethysm(f, g, p) sage: B = p[2, 2, 1](sum(s[i] for i in range(7))) - sage: all(h._compute_product(k, Partition([2, 2, 1])) == B.restrict_degree(k) for k in range(7)) + sage: all(h.compute_product(k, Partition([2, 2, 1])) == B.restrict_degree(k) for k in range(7)) True """ # This is the approximate order of the result @@ -1897,7 +1897,7 @@ def stretched_power_restrict_degree(self, i, m, d): sage: f = Stream_zero(False) # irrelevant for this test sage: g = Stream_exact([s[2], s[3]], False, 0, 4, 2) sage: h = Stream_plethysm(f, g, p) - sage: A = h._stretched_power_restrict_degree(2, 3, 6) + sage: A = h.stretched_power_restrict_degree(2, 3, 6) sage: A == p[2,2,2](s[2] + s[3]).homogeneous_component(12) True @@ -1905,7 +1905,7 @@ def stretched_power_restrict_degree(self, i, m, d): sage: f = Stream_zero(True) # irrelevant for this test sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), p2, True, 1) sage: h = Stream_plethysm(f, g, p2) - sage: A = h._stretched_power_restrict_degree(2, 3, 6) + sage: A = h.stretched_power_restrict_degree(2, 3, 6) sage: B = p[2,2,2](sum(g[n] for n in range(7))) sage: B = p2.element_class(p2, {m: c for m, c in B if sum(mu.size() for mu in m) == 12}) sage: A == B From 90a34aef9e2aa099c63858d7de37e434ac7053b7 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 30 Aug 2022 17:11:31 +0200 Subject: [PATCH 395/742] move reference, polish docstring --- src/doc/en/reference/references/index.rst | 10 +++- src/sage/rings/lazy_series.py | 60 +++++++++++++---------- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index bb77d546810..dfa447532da 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -95,7 +95,7 @@ REFERENCES: graphs and isoperimetric inequalities*, The Annals of Probability 32 (2004), no. 3A, 1727-1745. -.. [ASV2020] Federico Ardila, Mariel Supina, and Andrés R. Vindas-Meléndez, +.. [ASV2020] Federico Ardila, Mariel Supina, and Andrés R. Vindas-Meléndez, *The Equivariant Ehrhart Theory of the Permutahedron*, Proc. Amer. Math. Soc. Volume 148, Number 12, 2020, pp. 5091--5107. @@ -4181,6 +4181,7 @@ REFERENCES: .. [MagmaHGM] *Hypergeometric motives* in Magma, http://magma.maths.usyd.edu.au/~watkins/papers/HGM-chapter.pdf + .. [Mar1980] Jacques Martinet, Petits discriminants des corps de nombres, Journ. Arithm. 1980, Cambridge Univ. Press, 1982, 151--193. @@ -4356,6 +4357,11 @@ REFERENCES: *Symmetric cyclotomic Hecke algebras* J. Algebra. **205** (1998) pp. 275-293. +.. [MM2008] Manel Maia and Miguel Méndez. + On the arithmetic product of combinatorial species. + Discrete Mathematics (2008), Volume 308, Issue 23, pp. 5407-5427, + :arxiv:`math/0503436v2`. + .. [MM2015] \J. Matherne and \G. Muller, *Computing upper cluster algebras*, Int. Math. Res. Not. IMRN, 2015, 3121-3149. @@ -5415,7 +5421,7 @@ REFERENCES: .. [St1986] Richard Stanley. *Two poset polytopes*, Discrete Comput. Geom. (1986), :doi:`10.1007/BF02187680` -.. [Stap2011] Alan Stapledon. *Equivariant Ehrhart Theory*. +.. [Stap2011] Alan Stapledon. *Equivariant Ehrhart Theory*. Advances in Mathematics 226 (2011), no. 4, 3622-3654 .. [Sta1973] \H. M. Stark, Class-Numbers of Complex Quadratic diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 77b493bbeae..60ec0beff3e 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4800,13 +4800,13 @@ def arithmetic_product(self, *args, check=True): r""" Return the arithmetic product of ``self`` with ``g``. - For species `M` and `N` such that `M[\\varnothing] = - N[\\varnothing] = \\varnothing`, their arithmetic product is - the species `M \\boxdot N` of "`M`-assemblies of cloned + For species `M` and `N` such that `M[\varnothing] = + N[\varnothing] = \varnothing`, their arithmetic product is + the species `M \boxdot N` of "`M`-assemblies of cloned `N`-structures". This operation is defined and several examples are given in [MM]_. - The cycle index series for `M \\boxdot N` can be computed in + The cycle index series for `M \boxdot N` can be computed in terms of the component series `Z_M` and `Z_N`, as implemented in this method. @@ -4823,14 +4823,14 @@ def arithmetic_product(self, *args, check=True): cycle index series defined in terms of ``self`` and ``g`` such that if ``self`` and ``g`` are the cycle index series of two species `M` and `N`, their arithmetic product is the - cycle index series of the species `M \\boxdot N`. + cycle index series of the species `M \boxdot N`. EXAMPLES: For `C` the species of (oriented) cycles and `L_{+}` the - species of nonempty linear orders, `C \\boxdot L_{+}` + species of nonempty linear orders, `C \boxdot L_{+}` corresponds to the species of "regular octopuses"; a `(C - \\boxdot L_{+})`-structure is a cycle of some length, each of + \boxdot L_{+})`-structure is a cycle of some length, each of whose elements is an ordered list of a length which is consistent for all the lists in the structure. :: @@ -4850,10 +4850,10 @@ def arithmetic_product(self, *args, check=True): sage: [R[n].coefficient([1]*n) for n in range(8)] [0, 1, 3, 8, 42, 144, 1440, 5760] - It is shown in [MM]_ that the exponential generating function - for regular octopuses satisfies `(C \\boxdot L_{+}) (x) = - \\sum_{n \geq 1} \\sigma (n) (n - 1)! \\frac{x^{n}}{n!}` - (where `\\sigma (n)` is the sum of the divisors of `n`). :: + It is shown in [MM2008]_ that the exponential generating function + for regular octopuses satisfies `(C \boxdot L_{+}) (x) = + \sum_{n \geq 1} \sigma (n) (n - 1)! \frac{x^{n}}{n!}` + (where `\sigma (n)` is the sum of the divisors of `n`). :: sage: [sum(divisors(i))*factorial(i-1) for i in range(1,8)] [1, 3, 8, 42, 144, 1440, 5760] @@ -4864,9 +4864,7 @@ def arithmetic_product(self, *args, check=True): REFERENCES: - .. [MM] \M. Maia and M. Mendez. "On the arithmetic product of combinatorial species". - Discrete Mathematics, vol. 308, issue 23, 2008, pp. 5407-5427. - :arxiv:`math/0503436v2`. + - [MM2008]_ """ from itertools import product, repeat, chain @@ -4891,27 +4889,35 @@ def arithmetic_product(self, *args, check=True): assert not f[0] assert not g[0] - # We first define an operation `\\boxtimes` on partitions as in Lemma 2.1 of [MM]_. + # We first define an operation `\boxtimes` on partitions + # as in Lemma 2.1 of [MM2008]_. def arith_prod_of_partitions(l1, l2): - # Given two partitions `l_1` and `l_2`, we construct a new partition `l_1 \\boxtimes l_2` by - # the following procedure: each pair of parts `a \\in l_1` and `b \\in l_2` contributes - # `\\gcd (a, b)`` parts of size `\\lcm (a, b)` to `l_1 \\boxtimes l_2`. If `l_1` and `l_2` - # are partitions of integers `n` and `m`, respectively, then `l_1 \\boxtimes l_2` is a - # partition of `nm`. Finally, we return the corresponding powersum symmetric function. + # Given two partitions `l_1` and `l_2`, we construct + # a new partition `l_1 \boxtimes l_2` by the + # following procedure: each pair of parts `a \in l_1` + # and `b \in l_2` contributes `\gcd (a, b)`` parts of + # size `\lcm (a, b)` to `l_1 \boxtimes l_2`. If `l_1` + # and `l_2` are partitions of integers `n` and `m`, + # respectively, then `l_1 \boxtimes l_2` is a + # partition of `nm`. Finally, we return the + # corresponding powersum symmetric function. term_iterable = chain.from_iterable(repeat(lcm(pair), gcd(pair)) for pair in product(l1, l2)) return p(Partition(sorted(term_iterable, reverse=True))) - # We then extend this to an operation on symmetric functions as per eq. (52) of [MM]_. - # (Maia and Mendez, in [MM]_, are talking about polynomials instead of symmetric - # functions, but this boils down to the same: Their x_i corresponds to the i-th power - # sum symmetric function.) + # We then extend this to an operation on symmetric + # functions as per eq. (52) of [MM]_. (Maia and Mendez, + # in [MM]_, are talking about polynomials instead of + # symmetric functions, but this boils down to the same: + # Their x_i corresponds to the i-th power sum symmetric + # function.) def arith_prod_sf(x, y): return p._apply_multi_module_morphism(x, y, arith_prod_of_partitions) - # Sage stores cycle index series by degree. - # Thus, to compute the arithmetic product `Z_M \\boxdot Z_N` it is useful - # to compute all terms of a given degree `n` at once. + # Sage stores cycle index series by degree. Thus, to + # compute the arithmetic product `Z_M \boxdot Z_N` it is + # useful to compute all terms of a given degree `n` at + # once. def coefficient(n): if n == 0: res = p.zero() From 90a26a118aef26b8892967dae7c42369784aedd0 Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Tue, 30 Aug 2022 11:28:12 -0700 Subject: [PATCH 396/742] S --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 4e679b453df..4bacb2545b6 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3390,7 +3390,7 @@ def curve(self): Curve from which Riemann surface is obtained. - EXAMPLE:: + EXAMPLES:: sage: R. = QQ[] sage: C = Curve( y^3+x^3-1) From 192c6ffeb65e1bcc061e90b87edb9bb07bf05a8f Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 30 Aug 2022 22:51:04 +0200 Subject: [PATCH 397/742] typo in reference --- src/sage/rings/lazy_series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 60ec0beff3e..80c3f9dd77d 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4804,7 +4804,7 @@ def arithmetic_product(self, *args, check=True): N[\varnothing] = \varnothing`, their arithmetic product is the species `M \boxdot N` of "`M`-assemblies of cloned `N`-structures". This operation is defined and several - examples are given in [MM]_. + examples are given in [MM2008]_. The cycle index series for `M \boxdot N` can be computed in terms of the component series `Z_M` and `Z_N`, as implemented From cd0b9482015e3927e468a7ec045c8d5bc077f709 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 31 Aug 2022 13:26:45 +0900 Subject: [PATCH 398/742] Revert to __classcall_private__ idiom --- src/sage/homology/free_resolution.py | 149 +++++++++++++-------------- src/sage/misc/constant_function.pyx | 128 ----------------------- 2 files changed, 72 insertions(+), 205 deletions(-) delete mode 100644 src/sage/misc/constant_function.pyx diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index fb1fbb5a397..bfe209b5fe0 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -83,95 +83,90 @@ from copy import copy -def free_resolution_constructor(module, degrees=None, shifts=None, name='S', graded=False, **kwds): +class FreeResolution(SageObject, metaclass=ClasscallMetaclass): """ - Constructor. + Abstract base class for free resolutions. + """ + @staticmethod + def __classcall_private__(cls, module, degrees=None, shifts=None, name='S', graded=False, **kwds): + """ + Dispatch to the correct constructor. - TESTS:: + TESTS:: - sage: from sage.homology.free_resolution import FreeResolution - sage: S. = PolynomialRing(QQ) - sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() - sage: r = FreeResolution(m, name='S') - sage: type(r) - - sage: isinstance(r, FreeResolution) - True + sage: from sage.homology.free_resolution import FreeResolution + sage: S. = PolynomialRing(QQ) + sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() + sage: r = FreeResolution(m, name='S') + sage: type(r) + - sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = FreeResolution(I) - sage: type(r) - + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: type(r) + - sage: R. = QQ[] - sage: M = R^3 - sage: v = M([x^2, 2*x^2, 3*x^2]) - sage: w = M([0, x, 2*x]) - sage: S = M.submodule([v, w]) - sage: r = FreeResolution(S) - sage: type(r) - + sage: R. = QQ[] + sage: M = R^3 + sage: v = M([x^2, 2*x^2, 3*x^2]) + sage: w = M([0, x, 2*x]) + sage: S = M.submodule([v, w]) + sage: r = FreeResolution(S) + sage: type(r) + - sage: I = R.ideal([x^4 + 3*x^2 + 2]) - sage: r = FreeResolution(I) - sage: type(r) - - """ - # The module might still be free even if is_free_module is False. - # This is just to handle the cases when we trivially know it is. - is_free_module = False - if isinstance(module, Ideal_generic): - S = module.ring() - if len(module.gens()) == 1 and S in IntegralDomains(): - is_free_module = True - elif isinstance(module, Module_free_ambient): - S = module.base_ring() - if (S in PrincipalIdealDomains() - or isinstance(module, FreeModule_generic)): - is_free_module = True - elif isinstance(module, Matrix): - S = module.base_ring() - if S in PrincipalIdealDomains(): - module = module.echelon_form() - if module.nrows() > module.rank(): - module = module.submatrix(nrows=module.rank()) + sage: I = R.ideal([x^4 + 3*x^2 + 2]) + sage: r = FreeResolution(I) + sage: type(r) + + """ + # The module might still be free even if is_free_module is False. + # This is just to handle the cases when we trivially know it is. + is_free_module = False + if isinstance(module, Ideal_generic): + S = module.ring() + if len(module.gens()) == 1 and S in IntegralDomains(): + is_free_module = True + elif isinstance(module, Module_free_ambient): + S = module.base_ring() + if (S in PrincipalIdealDomains() + or isinstance(module, FreeModule_generic)): + is_free_module = True + elif isinstance(module, Matrix): + S = module.base_ring() + if S in PrincipalIdealDomains(): + module = module.echelon_form() + if module.nrows() > module.rank(): + module = module.submatrix(nrows=module.rank()) + module.set_immutable() + is_free_module = True + if not module.is_immutable(): + # We need to make an immutable copy of the matrix + module = copy(module) module.set_immutable() - is_free_module = True - if not module.is_immutable(): - # We need to make an immutable copy of the matrix - module = copy(module) - module.set_immutable() - else: - raise TypeError('no module, matrix, or ideal') - - if not is_free_module: - from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular - if not isinstance(S, MPolynomialRing_libsingular): - raise NotImplementedError("the module must be a free module or " - "the base ring must be a polynomial ring using Singular") - - if graded or degrees is not None or shifts is not None: - # We are computing a graded resolution - from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular - return GradedFiniteFreeResolution_singular(module, degrees=degrees, shifts=shifts, name=name, **kwds) + else: + raise TypeError('no module, matrix, or ideal') - return FiniteFreeResolution_singular(module, name=name, **kwds) + if not is_free_module: + from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if not isinstance(S, MPolynomialRing_libsingular): + raise NotImplementedError("the module must be a free module or have the base ring be a polynomial ring using Singular") - # Otherwise we know it is a free module + if graded or degrees is not None or shifts is not None: + # We are computing a graded resolution + from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular + return GradedFiniteFreeResolution_singular(module, degrees=degrees, shifts=shifts, name=name, **kwds) - if graded or degrees is not None or shifts is not None: - # We are computing a graded resolution - from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module - return GradedFiniteFreeResolution_free_module(module, degrees=degrees, shifts=shifts, name=name, **kwds) + return FiniteFreeResolution_singular(module, name=name, **kwds) - return FiniteFreeResolution_free_module(module, name=name, **kwds) + # Otherwise we know it is a free module + if graded or degrees is not None or shifts is not None: + # We are computing a graded resolution + from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + return GradedFiniteFreeResolution_free_module(module, degrees=degrees, shifts=shifts, name=name, **kwds) -class FreeResolution(SageObject, metaclass=ConstructorBaseclassMetaclass): - """ - Abstract base class for free resolutions. - """ - __constructor__ = free_resolution_constructor + return FiniteFreeResolution_free_module(module, name=name, **kwds) def __init__(self, module, name='S', **kwds): """ @@ -585,7 +580,7 @@ def _m(self): r""" Return the matrix whose column space is ``self._module``. - If ``self._module`` is an ideal, then returns just the ideal. + If ``self._module`` is an ideal, then just the ideal is returned. TESTS:: diff --git a/src/sage/misc/constant_function.pyx b/src/sage/misc/constant_function.pyx deleted file mode 100644 index e94f36da403..00000000000 --- a/src/sage/misc/constant_function.pyx +++ /dev/null @@ -1,128 +0,0 @@ -r""" -Constant functions -""" - -#***************************************************************************** -# Copyright (C) 2009 Nicolas M. Thiery -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** - -from sage.structure.richcmp cimport richcmp -from sage.structure.sage_object cimport SageObject - - -cdef class ConstantFunction(SageObject): - """ - A class for function objects implementing constant functions. - - EXAMPLES:: - - sage: f = ConstantFunction(3) - sage: f - The constant function (...) -> 3 - sage: f() - 3 - sage: f(5) - 3 - - Such a function could be implemented as a lambda expression, but - this is not (currently) picklable:: - - sage: g = lambda x: 3 - sage: g == loads(dumps(g)) - Traceback (most recent call last): - ... - PicklingError: Can't pickle ...: attribute lookup ... failed - sage: f == loads(dumps(f)) - True - - Also, in the long run, the information that this function is - constant could be used by some algorithms. - - .. TODO:: - - - Should constant functions have unique representation? - - Should the number of arguments be specified in the input? - - Should this go into ``sage.categories.maps``? - Then what should be the parent (e.g. for ``lambda x: True``)? - - TESTS: - - These tests do fail if we try to use ``UniqueRepresentation``:: - - sage: f = ConstantFunction(True) - sage: g = ConstantFunction(1) - sage: f(), g() - (True, 1) - - That's because ``1`` and ``True`` cannot be distinguished as keys - in a dictionary (argl!):: - - sage: { 1: 'a', True: 'b' } - {1: 'b'} - """ - cdef object _value - - def __init__(self, value): - """ - EXAMPLES:: - - sage: ConstantFunction(1)() - 1 - """ - self._value = value - - def __reduce__(self): - """ - TESTS:: - - sage: loads(dumps(ConstantFunction(5))) == ConstantFunction(5) # indirect doctest - True - - """ - return ConstantFunction, (self._value,) - - def _repr_(self): - """ - EXAMPLES:: - - sage: ConstantFunction(1) - The constant function (...) -> 1 - """ - return "The constant function (...) -> %s"%self._value - - def __call__(self, *args): - """ - EXAMPLES:: - - sage: ConstantFunction(1)() - 1 - sage: ConstantFunction(1)(5,3) - 1 - sage: ConstantFunction(True)() - True - """ - return self._value - - def __richcmp__(self, other, op): - """ - EXAMPLES:: - - sage: ConstantFunction(1) == ConstantFunction(1) - True - sage: ConstantFunction(1) == ConstantFunction(3) - False - sage: ConstantFunction(1) == 1 - False - sage: ConstantFunction(True) == ConstantFunction(1) # argl! - True - """ - if not isinstance(other, ConstantFunction): - return NotImplemented - return richcmp((self)._value, - (other)._value, op) From be985d4bf3ce69adc01ed79c191c3455ded48b33 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 31 Aug 2022 13:51:08 +0900 Subject: [PATCH 399/742] uniformize the headline --- src/sage/rings/finite_rings/element_givaro.pyx | 2 +- src/sage/rings/finite_rings/element_ntl_gf2e.pyx | 2 +- src/sage/rings/finite_rings/finite_field_base.pyx | 2 +- src/sage/rings/finite_rings/finite_field_constructor.py | 2 +- src/sage/rings/finite_rings/finite_field_givaro.py | 2 +- src/sage/rings/finite_rings/finite_field_ntl_gf2e.py | 2 +- src/sage/rings/finite_rings/finite_field_prime_modn.py | 2 +- src/sage/rings/finite_rings/hom_finite_field_givaro.pyx | 2 +- src/sage/rings/finite_rings/homset.py | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index 025e9fe80ce..f17a32f558c 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -1,7 +1,7 @@ # distutils: libraries = givaro gmp m # distutils: language = c++ r""" -Givaro Field Elements +Givaro finite field flements Sage includes the Givaro finite field library, for highly optimized arithmetic in finite fields. diff --git a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx index beda02aea78..454f10c462d 100644 --- a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ r""" -Finite Fields of characteristic 2. +Finite fields of characteristic 2 elements This implementation uses NTL's GF2E class to perform the arithmetic and is the standard implementation for ``GF(2^n)`` for ``n >= 16``. diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index ffad0442389..caeadff7ae2 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -1,5 +1,5 @@ """ -Base Classes for Finite Fields +Base class for finite fields TESTS:: diff --git a/src/sage/rings/finite_rings/finite_field_constructor.py b/src/sage/rings/finite_rings/finite_field_constructor.py index 685c385cf2e..e42b2bed2dd 100644 --- a/src/sage/rings/finite_rings/finite_field_constructor.py +++ b/src/sage/rings/finite_rings/finite_field_constructor.py @@ -1,5 +1,5 @@ r""" -Finite Fields +Finite fields Sage supports arithmetic in finite prime and extension fields. Several implementation for prime fields are implemented natively in diff --git a/src/sage/rings/finite_rings/finite_field_givaro.py b/src/sage/rings/finite_rings/finite_field_givaro.py index 6b34b7e66be..a70cfc0c717 100644 --- a/src/sage/rings/finite_rings/finite_field_givaro.py +++ b/src/sage/rings/finite_rings/finite_field_givaro.py @@ -1,5 +1,5 @@ """ -Givaro Finite Field +Givaro finite fields Finite fields that are implemented using Zech logs and the cardinality must be less than `2^{16}`. By default, Conway polynomials are diff --git a/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py b/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py index ee47bba4d1c..d2dd7f49613 100644 --- a/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py +++ b/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py @@ -1,5 +1,5 @@ """ -Finite Fields of Characteristic 2 +Finite fields of characteristic 2 """ #***************************************************************************** diff --git a/src/sage/rings/finite_rings/finite_field_prime_modn.py b/src/sage/rings/finite_rings/finite_field_prime_modn.py index 9129ecb56aa..f2a91186cd9 100644 --- a/src/sage/rings/finite_rings/finite_field_prime_modn.py +++ b/src/sage/rings/finite_rings/finite_field_prime_modn.py @@ -1,5 +1,5 @@ """ -Finite Prime Fields +Finite prime fields AUTHORS: 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 d79ea68fc25..ad88a240355 100644 --- a/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx +++ b/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ """ -Finite field morphisms using Givaro +Givaro finite field morphisms Special implementation for givaro finite fields of: diff --git a/src/sage/rings/finite_rings/homset.py b/src/sage/rings/finite_rings/homset.py index ca4bd31571b..0a7578a092e 100644 --- a/src/sage/rings/finite_rings/homset.py +++ b/src/sage/rings/finite_rings/homset.py @@ -1,5 +1,5 @@ """ -Homset for Finite Fields +Homset for finite fields This is the set of all field homomorphisms between two finite fields. From d0e11a3d9816bb5ec9034272f904ff28e939f1d4 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 31 Aug 2022 13:49:05 +0900 Subject: [PATCH 400/742] Some edits --- src/sage/homology/free_resolution.py | 24 ++++++------ src/sage/homology/graded_resolution.py | 10 +++-- src/sage/libs/singular/singular.pyx | 37 +++++++++---------- .../misc/constructor_baseclass_metaclass.pyx | 21 ----------- src/sage/modules/free_module.py | 19 ++++++++-- .../polynomial/multi_polynomial_ideal.py | 4 +- 6 files changed, 54 insertions(+), 61 deletions(-) delete mode 100644 src/sage/misc/constructor_baseclass_metaclass.pyx diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index bfe209b5fe0..49fc3d7478f 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -119,6 +119,17 @@ def __classcall_private__(cls, module, degrees=None, shifts=None, name='S', grad sage: r = FreeResolution(I) sage: type(r) + + sage: R. = QQ[] + sage: I = R.ideal([x^2, y^3]) + sage: Q = R.quo(I) + sage: Q.is_integral_domain() + False + sage: xb, yb = Q.gens() + sage: FreeResolution(Q.ideal([xb])) # has torsion + Traceback (most recent call last): + ... + NotImplementedError: the module must be a free module or have the base ring be a polynomial ring using Singular """ # The module might still be free even if is_free_module is False. # This is just to handle the cases when we trivially know it is. @@ -726,7 +737,9 @@ class FiniteFreeResolution_singular(FiniteFreeResolution): - ``module`` -- a submodule of a free module `M` of rank `n` over `S` or an ideal of a multi-variate polynomial ring + - ``name`` -- string (optional); name of the base ring + - ``algorithm`` -- (default: ``'heuristic'``) Singular algorithm to compute a resolution of ``ideal`` @@ -820,17 +833,6 @@ def __init__(self, module, name='S', algorithm='heuristic', **kwds): sage: M = m.image() sage: r = FreeResolution(M, name='S') sage: TestSuite(r).run(skip=['_test_pickling']) - - sage: R. = QQ[] - sage: I = R.ideal([x^2, y^3]) - sage: Q = R.quo(I) - sage: Q.is_integral_domain() - False - sage: xb, yb = Q.gens() - sage: FreeResolution(Q.ideal([xb])) # has torsion - Traceback (most recent call last): - ... - NotImplementedError: the module must be a free module or have the base ring be a polynomial ring using Singular """ self._algorithm = algorithm super().__init__(module, name=name, **kwds) diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index 6396c0ab65f..88b6184fb03 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -87,6 +87,7 @@ FiniteFreeResolution_free_module, FiniteFreeResolution_singular) + class GradedFiniteFreeResolution(FiniteFreeResolution): r""" Graded finite free resolutions. @@ -190,6 +191,7 @@ def _repr_module(self, i): shifts = self._shifts else: shifts = self._res_shifts[i - 1] + if not shifts: return '0' @@ -310,6 +312,7 @@ def K_polynomial(self, names=None): return kpoly + class GradedFiniteFreeResolution_free_module(GradedFiniteFreeResolution, FiniteFreeResolution_free_module): r""" Graded free resolution of free modules. @@ -351,7 +354,8 @@ def __init__(self, module, degrees=None, *args, **kwds): super().__init__(module, degrees=degrees, *args, **kwds) if len(self._degrees) > 1 and any(d != 1 for d in self._degrees): - raise NotImplementedError("only the natural grading supported when more than one generator") + raise NotImplementedError("only the natural grading supported " + "when more than one generator") @lazy_attribute def _maps(self): @@ -399,7 +403,6 @@ def _maps(self): sage: res._res_shifts [[9]] """ - def compute_degree(base, i): """ Compute the degree by ``base * deg + shift``, @@ -422,10 +425,11 @@ def compute_degree(base, i): def find_deg(i): for j in range(M.nrows()): - ret = M[j,i].degree() + ret = M[j,i].degree() if ret != -1: return ret raise NotImplementedError("a generator maps to 0") + self._res_shifts = [[compute_degree(find_deg(i), i) for i in range(M.ncols())]] return [M] diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index 82d83e01212..bb729cf2db2 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -865,9 +865,9 @@ cdef number *sa2si_QQ(Rational r, ring *_ring): INPUT: - - ``r`` - a sage rational number + - ``r`` -- a sage rational number - - ``_ ring`` - a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live OUTPUT: @@ -895,9 +895,9 @@ cdef number *sa2si_GFqGivaro(int quo, ring *_ring): INPUT: - - ``quo`` - a sage integer + - ``quo`` -- a sage integer - - ``_ ring`` - a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live OUTPUT: @@ -963,9 +963,9 @@ cdef number *sa2si_GFqNTLGF2E(FFgf2eE elem, ring *_ring): INPUT: - - ``elem`` - a sage element of a ntl_gf2e finite field + - ``elem`` -- a sage element of a ntl_gf2e finite field - - ``_ ring`` - a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live OUTPUT: @@ -1028,9 +1028,9 @@ cdef number *sa2si_GFq_generic(object elem, ring *_ring): INPUT: - - ``elem`` - a sage element of a generic finite field + - ``elem`` -- a sage element of a generic finite field - - ``_ ring`` - a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live OUTPUT: @@ -1094,15 +1094,14 @@ cdef number *sa2si_transext_QQ(object elem, ring *_ring): INPUT: - - ``elem`` - a sage element of a FractionField of polynomials over the rationals + - ``elem`` -- a sage element of a FractionField of polynomials over the rationals - - ``_ ring`` - a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live OUTPUT: - A (pointer to) a singular number - TESTS:: sage: F = PolynomialRing(QQ,'a,b').fraction_field() @@ -1245,15 +1244,14 @@ cdef number *sa2si_transext_FF(object elem, ring *_ring): INPUT: - - ``elem`` - a sage element of a FractionField of polynomials over the rationals + - ``elem`` -- a sage element of a FractionField of polynomials over the rationals - - ``_ ring`` - a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live OUTPUT: - A (pointer to) a singular number - TESTS:: sage: F = PolynomialRing(FiniteField(7),'a,b').fraction_field() @@ -1346,9 +1344,9 @@ cdef number *sa2si_NF(object elem, ring *_ring): INPUT: - - ``elem`` - a sage element of a NumberField + - ``elem`` -- a sage element of a NumberField - - ``_ ring`` - a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live OUTPUT: @@ -1437,15 +1435,14 @@ cdef number *sa2si_ZZ(Integer d, ring *_ring): INPUT: - - ``elem`` - a sage Integer + - ``elem`` -- a sage Integer - - ``_ ring`` - a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live OUTPUT: - A (pointer to) a singular number - TESTS:: sage: P. = ZZ[] @@ -1650,7 +1647,7 @@ cdef object si2sa_intvec(intvec *v): INPUT: - - ``v`` -- a (pointer to) a singular intvec + - ``v`` -- a (pointer to) singular intvec OUTPUT: diff --git a/src/sage/misc/constructor_baseclass_metaclass.pyx b/src/sage/misc/constructor_baseclass_metaclass.pyx deleted file mode 100644 index fc3ca66f641..00000000000 --- a/src/sage/misc/constructor_baseclass_metaclass.pyx +++ /dev/null @@ -1,21 +0,0 @@ -from sage.misc.classcall_metaclass cimport ClasscallMetaclass - - -cdef class ConstructorBaseclassMetaclass(ClasscallMetaclass): - - def __cinit__(self, *args, **opts): - r""" - TESTS:: - """ - if '__constructor__' in self.__dict__: - def constructor(cls, *a, **o): - return self.__constructor__(*a, **o) - self.classcall = constructor - else: - self.classcall = None - - self.classcontains = getattr(self, "__classcontains__", None) - self.classget = getattr(self, "__classget__", None) - - - diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 8e5c3da9e17..7af5a6e69b9 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -1777,10 +1777,20 @@ def free_resolution(self, *args, **kwds): sage: ascii_art(res.chain_complex()) [x - y y*z] [ z x*z] - 0 <-- C_0 <-------------- C_1 <-- 0 + 0 <-- C_0 <-------------- C_1 <-- 0 """ - from sage.homology.free_resolution import FreeResolution - return FreeResolution(self, *args, **kwds) + 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) + + if isinstance(self, FreeModule_generic): + from sage.homology.free_resolution import FiniteFreeResolution_free_module + return FiniteFreeResolution_free_module(self, *args, **kwds) + + raise NotImplementedError("the module must be a free module or " + "have the base ring be a polynomial ring using Singular") + def graded_free_resolution(self, *args, **kwds): r""" @@ -1812,7 +1822,8 @@ def graded_free_resolution(self, *args, **kwds): 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 have the base ring be a polynomial ring using Singular") + raise NotImplementedError("the module must be a free module or " + "have the base ring be a polynomial ring using Singular") class FreeModule_generic(Module_free_ambient): diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 18f52b0ad74..92d73dff1b5 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -1794,8 +1794,8 @@ def free_resolution(self, *args, **kwds): sage: res S^1 <-- S^2 <-- S^1 <-- 0 sage: ascii_art(res.chain_complex()) - [-x^2] - [ y x^2] [ y] + [-x^2] + [ y x^2] [ y] 0 <-- C_0 <---------- C_1 <------- C_2 <-- 0 sage: q = ZZ['q'].fraction_field().gen() From 22dd075ca6183d0b971d311077fc31adeb650cc0 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 31 Aug 2022 15:14:51 +0900 Subject: [PATCH 401/742] Nonhomogeneous examples --- src/sage/homology/graded_resolution.py | 28 ++++++-------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index 88b6184fb03..da04739b047 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -96,11 +96,14 @@ class GradedFiniteFreeResolution(FiniteFreeResolution): - ``module`` -- a homogeneous submodule of a free module `M` of rank `n` over `S` or a homogeneous ideal of a multivariate polynomial ring `S` + - ``degrees`` -- (default: a list with all entries `1`) a list of integers or integer vectors giving degrees of variables of `S` + - ``shifts`` -- a list of integers or integer vectors giving shifts of degrees of `n` summands of the free module `M`; this is a list of zero degrees of length `n` by default + - ``name`` -- a string; name of the base ring .. WARNING:: @@ -121,9 +124,9 @@ def __init__(self, module, degrees=None, shifts=None, name='S', **kwds): An overdetermined system over a PID:: sage: from sage.homology.free_resolution import FreeResolution - sage: M = matrix([[x^2, 2], - ....: [3*x^2, 5], - ....: [5*x^2, 4]]) + sage: M = matrix([[x^2, 2*x^2], + ....: [3*x^2, 5*x^2], + ....: [5*x^2, 4*x^2]]) sage: res = FreeResolution(M, graded=True) sage: res S(0)⊕S(0) <-- S(-2)⊕S(0) <-- 0 @@ -330,13 +333,6 @@ class GradedFiniteFreeResolution_free_module(GradedFiniteFreeResolution, FiniteF sage: res = FreeResolution(M, graded=True) sage: res S(0)⊕S(0)⊕S(0) <-- S(-3)⊕S(-1) <-- 0 - - sage: M = matrix([[x^2, 2], - ....: [3*x^2, 5], - ....: [5*x^2, 4]]) - sage: res = FreeResolution(M, graded=True) - sage: res - S(0)⊕S(0) <-- S(-2)⊕S(0) <-- 0 """ def __init__(self, module, degrees=None, *args, **kwds): """ @@ -382,18 +378,6 @@ def _maps(self): sage: res._res_shifts [[3, 1]] - sage: M = matrix([[x^2, 2], - ....: [3*x^2, 5], - ....: [5*x^2, 4]]) - sage: res = FreeResolution(M, graded=True) - sage: res._maps - [ - [x^2 0] - [ 2 -1] - ] - sage: res._res_shifts - [[2, 0]] - sage: I = R.ideal([x^4]) sage: res = I.graded_free_resolution(shifts=[1], degrees=[2]) sage: res From 22f74a24bc8892e6d1c0b527f49f1ea8e06aa3af Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 31 Aug 2022 15:21:47 +0900 Subject: [PATCH 402/742] Remove ConstructorBaseclassMetaclass --- src/sage/homology/free_resolution.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 49fc3d7478f..8a81073e044 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -70,7 +70,6 @@ from sage.libs.singular.function import singular_function from sage.misc.lazy_attribute import lazy_attribute from sage.misc.abstract_method import abstract_method -from sage.misc.constructor_baseclass_metaclass import ConstructorBaseclassMetaclass from sage.structure.sage_object import SageObject from sage.structure.element import Matrix from sage.categories.principal_ideal_domains import PrincipalIdealDomains From 609b40d91ae190ad02078f55a554ac15e4415810 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 31 Aug 2022 15:21:47 +0900 Subject: [PATCH 403/742] Recover ClasscallMetaclass --- src/sage/homology/free_resolution.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 8a81073e044..452a41a6de8 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -70,6 +70,7 @@ from sage.libs.singular.function import singular_function from sage.misc.lazy_attribute import lazy_attribute from sage.misc.abstract_method import abstract_method +from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.structure.sage_object import SageObject from sage.structure.element import Matrix from sage.categories.principal_ideal_domains import PrincipalIdealDomains From b939bbc5cc7aba2d8f9636f16f3d35a9c02039cb Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 31 Aug 2022 15:31:31 +0900 Subject: [PATCH 404/742] Fix in projective_morphism.py --- src/sage/schemes/projective/projective_morphism.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 42402cfbc74..92d3b189502 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -88,7 +88,7 @@ from sage.categories.number_fields import NumberFields from sage.categories.homset import Hom, End from sage.categories.fields import Fields -from sage.homology.graded_resolution import GradedFreeResolution +from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular _NumberFields = NumberFields() _FiniteFields = FiniteFields() @@ -2691,7 +2691,7 @@ def projective_degrees(self): I = G.defining_ideal() # a bihomogeneous ideal degrees = xn*[vector([1,0])] + yn*[vector([0,1])] - res = GradedFreeResolution(I, degrees, algorithm='shreyer') + res = GradeFinitedFreeResolution_singular(I, degrees, algorithm='shreyer') kpoly = res.K_polynomial() L = kpoly.parent() From 1622605005feb13cee9956af3f2f395a2ecedb36 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 31 Aug 2022 15:38:16 +0900 Subject: [PATCH 405/742] Fix of _repr_() --- src/sage/homology/free_resolution.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 452a41a6de8..f6bc238ff4d 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -216,11 +216,11 @@ def _repr_(self): sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) sage: r = FreeResolution(m1, name='S') sage: print(FreeResolution._repr_(r)) - Free resolution with initial map: + Free resolution of the row space of the matrix: [z^2 - y*w y*z - x*w y^2 - x*z] """ if isinstance(self._module, Matrix): - return f"Free resolution of the :\n{self._module}" + return f"Free resolution of the row space of the matrix:\n{self._module}" return f"Free resolution of {self._module}" def _repr_module(self, i): From 81d6afb0ac2adee48cbabe59eb1946f96161d3a3 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 31 Aug 2022 15:46:43 +0900 Subject: [PATCH 406/742] Recover errorneously deleted constant_function.pyx --- src/sage/misc/constant_function.pyx | 128 ++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/sage/misc/constant_function.pyx diff --git a/src/sage/misc/constant_function.pyx b/src/sage/misc/constant_function.pyx new file mode 100644 index 00000000000..e94f36da403 --- /dev/null +++ b/src/sage/misc/constant_function.pyx @@ -0,0 +1,128 @@ +r""" +Constant functions +""" + +#***************************************************************************** +# Copyright (C) 2009 Nicolas M. Thiery +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.structure.richcmp cimport richcmp +from sage.structure.sage_object cimport SageObject + + +cdef class ConstantFunction(SageObject): + """ + A class for function objects implementing constant functions. + + EXAMPLES:: + + sage: f = ConstantFunction(3) + sage: f + The constant function (...) -> 3 + sage: f() + 3 + sage: f(5) + 3 + + Such a function could be implemented as a lambda expression, but + this is not (currently) picklable:: + + sage: g = lambda x: 3 + sage: g == loads(dumps(g)) + Traceback (most recent call last): + ... + PicklingError: Can't pickle ...: attribute lookup ... failed + sage: f == loads(dumps(f)) + True + + Also, in the long run, the information that this function is + constant could be used by some algorithms. + + .. TODO:: + + - Should constant functions have unique representation? + - Should the number of arguments be specified in the input? + - Should this go into ``sage.categories.maps``? + Then what should be the parent (e.g. for ``lambda x: True``)? + + TESTS: + + These tests do fail if we try to use ``UniqueRepresentation``:: + + sage: f = ConstantFunction(True) + sage: g = ConstantFunction(1) + sage: f(), g() + (True, 1) + + That's because ``1`` and ``True`` cannot be distinguished as keys + in a dictionary (argl!):: + + sage: { 1: 'a', True: 'b' } + {1: 'b'} + """ + cdef object _value + + def __init__(self, value): + """ + EXAMPLES:: + + sage: ConstantFunction(1)() + 1 + """ + self._value = value + + def __reduce__(self): + """ + TESTS:: + + sage: loads(dumps(ConstantFunction(5))) == ConstantFunction(5) # indirect doctest + True + + """ + return ConstantFunction, (self._value,) + + def _repr_(self): + """ + EXAMPLES:: + + sage: ConstantFunction(1) + The constant function (...) -> 1 + """ + return "The constant function (...) -> %s"%self._value + + def __call__(self, *args): + """ + EXAMPLES:: + + sage: ConstantFunction(1)() + 1 + sage: ConstantFunction(1)(5,3) + 1 + sage: ConstantFunction(True)() + True + """ + return self._value + + def __richcmp__(self, other, op): + """ + EXAMPLES:: + + sage: ConstantFunction(1) == ConstantFunction(1) + True + sage: ConstantFunction(1) == ConstantFunction(3) + False + sage: ConstantFunction(1) == 1 + False + sage: ConstantFunction(True) == ConstantFunction(1) # argl! + True + """ + if not isinstance(other, ConstantFunction): + return NotImplemented + return richcmp((self)._value, + (other)._value, op) From d8bc44fb999eaba5520cdb5f238c429b7cb052c1 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 31 Aug 2022 15:53:08 +0900 Subject: [PATCH 407/742] Minor fixes --- src/sage/homology/graded_resolution.py | 4 ++-- src/sage/schemes/projective/projective_morphism.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index da04739b047..1728193dfba 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -129,9 +129,9 @@ def __init__(self, module, degrees=None, shifts=None, name='S', **kwds): ....: [5*x^2, 4*x^2]]) sage: res = FreeResolution(M, graded=True) sage: res - S(0)⊕S(0) <-- S(-2)⊕S(0) <-- 0 + S(0)⊕S(0) <-- S(-2)⊕S(-2) <-- 0 sage: res._res_shifts - [[2, 0]] + [[2, 2]] """ super().__init__(module, name=name, **kwds) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 92d3b189502..e3347c409bc 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -2691,7 +2691,7 @@ def projective_degrees(self): I = G.defining_ideal() # a bihomogeneous ideal degrees = xn*[vector([1,0])] + yn*[vector([0,1])] - res = GradeFinitedFreeResolution_singular(I, degrees, algorithm='shreyer') + res = GradedFiniteFreeResolution_singular(I, degrees, algorithm='shreyer') kpoly = res.K_polynomial() L = kpoly.parent() From 610078f291df7378c453ffd0a4336355200334c0 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 31 Aug 2022 13:49:20 +0200 Subject: [PATCH 408/742] add doctests --- src/sage/rings/lazy_series.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 20e5b762521..410129b0155 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3306,7 +3306,26 @@ def derivative(self, *args): sage: (1/(1-z)).derivative(z) 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) - TESTS:: + TESTS: + + Check the derivative of the logarithm: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: -log(1-z).derivative() + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + + Check that differentiation of 'exact' series with nonzero + constant works:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: f = L([1,2], valuation=-2, constant=1) + sage: f + z^-2 + 2*z^-1 + 1 + z + z^2 + O(z^3) + sage: f.derivative() + -2*z^-3 - 2*z^-2 + 1 + 2*z + 3*z^2 + 4*z^3 + O(z^4) + + Check that differentiation with respect to a variable other + than the series variable works:: sage: R. = QQ[] sage: L. = LazyLaurentSeriesRing(R) From b7663b403da6bc6a81c7e2bdd399e0eb46ba3b58 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Wed, 31 Aug 2022 23:10:13 +0800 Subject: [PATCH 409/742] remove experimental warnings for composite elliptic-curve isogenies --- src/sage/schemes/elliptic_curves/ell_field.py | 6 ++---- src/sage/schemes/elliptic_curves/hom.py | 1 - src/sage/schemes/elliptic_curves/hom_composite.py | 13 +------------ 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 68b8375daee..6b64df4d075 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -1098,7 +1098,7 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al kernel point of odd order `\geq 5`. This algorithm is selected using ``algorithm="velusqrt"``. - - Factored Isogenies (*experimental* --- see + - Factored Isogenies (see :mod:`~sage.schemes.elliptic_curves.hom_composite`): Given a list of points which generate a composite-order subgroup, decomposes the isogeny into prime-degree steps. @@ -1200,9 +1200,7 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al sage: E = EllipticCurve(GF(2^32-5), [170246996, 2036646110]) sage: P = E.lift_x(2) - sage: E.isogeny(P, algorithm="factored") # experimental - doctest:warning - ... + sage: E.isogeny(P, algorithm="factored") Composite morphism of degree 1073721825 = 3^4*5^2*11*19*43*59: From: Elliptic Curve defined by y^2 = x^3 + 170246996*x + 2036646110 over Finite Field of size 4294967291 To: Elliptic Curve defined by y^2 = x^3 + 272790262*x + 1903695400 over Finite Field of size 4294967291 diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index 8d707e8e6b7..35c23e8fef2 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -221,7 +221,6 @@ def degree(self): is the product of the degrees of the individual factors:: sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite - doctest:warning ... sage: E = EllipticCurve(GF(419), [1,0]) sage: P, = E.gens() sage: phi = EllipticCurveHom_composite(E, P+P) diff --git a/src/sage/schemes/elliptic_curves/hom_composite.py b/src/sage/schemes/elliptic_curves/hom_composite.py index 32b1fa9e0bb..6528d7bef5d 100644 --- a/src/sage/schemes/elliptic_curves/hom_composite.py +++ b/src/sage/schemes/elliptic_curves/hom_composite.py @@ -7,12 +7,6 @@ while exposing (close to) the same interface as "normal", unfactored elliptic-curve isogenies. -.. WARNING:: - - This module is currently considered experimental. - It may change in a future release without prior warning, or even - be removed altogether if things turn out to be unfixably broken. - EXAMPLES: The following example would take quite literally forever with the @@ -20,8 +14,6 @@ decomposing into prime steps is exponentially faster:: sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite - doctest:warning - ... sage: p = 3 * 2^143 - 1 sage: GF(p^2).inject_variables() Defining z2 @@ -90,9 +82,6 @@ from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism -from sage.misc.superseded import experimental_warning -experimental_warning(32744, 'EllipticCurveHom_composite is experimental code.') - #TODO: implement sparse strategies? (cf. the SIKE cryptosystem) def _eval_factored_isogeny(phis, P): @@ -789,7 +778,7 @@ def make_default(): This method exists only temporarily to make testing more convenient while :class:`EllipticCurveHom_composite` is - experimental. + not yet the default. EXAMPLES:: From 52815744bde2b682245b6f985a112f7cb8666056 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 31 Aug 2022 08:58:07 -0700 Subject: [PATCH 410/742] build/pkgs/sympy: Update to 1.11.1 --- build/pkgs/sympy/checksums.ini | 6 +++--- build/pkgs/sympy/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sympy/checksums.ini b/build/pkgs/sympy/checksums.ini index d92eeec4219..f59c0083e07 100644 --- a/build/pkgs/sympy/checksums.ini +++ b/build/pkgs/sympy/checksums.ini @@ -1,5 +1,5 @@ tarball=sympy-VERSION.tar.gz -sha1=bb3ecaa4b223097831b5f0627d6579d8bd906840 -md5=973f746dd0b0d07b01f6b2b15603cbf8 -cksum=3499849170 +sha1=9e75c8cafa4324f2803a6488ac713d87adf5cb64 +md5=232141d248ab4164e92c8ac59a996914 +cksum=2645245679 upstream_url=https://github.com/sympy/sympy/releases/download/sympy-VERSION/sympy-VERSION.tar.gz diff --git a/build/pkgs/sympy/package-version.txt b/build/pkgs/sympy/package-version.txt index 09601587019..720c7384c61 100644 --- a/build/pkgs/sympy/package-version.txt +++ b/build/pkgs/sympy/package-version.txt @@ -1 +1 @@ -1.11 +1.11.1 From b81dbf016724ada9b5cb84407e7a68f18dbc7126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 31 Aug 2022 20:53:43 +0200 Subject: [PATCH 411/742] fix doctest --- src/sage/categories/modules.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 21ee46b24f1..46e1da5c694 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -943,4 +943,5 @@ def tensor_factors(self): doctest:warning... DeprecationWarning: implementations of Modules().TensorProducts() now must define the method tensor_factors See https://trac.sagemath.org/34393 for details. + (VectorFunctor, Integer Ring) """ From 731072a3bfc860f744f1b702708258cb2bc67fda Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 31 Aug 2022 22:14:05 +0200 Subject: [PATCH 412/742] remove unnecessary code leftover from merge, and remove unneccesary import detected by pyflakes --- src/sage/combinat/sf/sfa.py | 1 - src/sage/rings/lazy_series.py | 74 ----------------------------------- 2 files changed, 75 deletions(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index c573d2399c7..b99a5406568 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -4977,7 +4977,6 @@ def frobenius(self, n): # then convert back. parent = self.parent() m = parent.realization_of().monomial() - from sage.combinat.partition import Partition dct = {lam.stretch(n): coeff for lam, coeff in m(self)} result_in_m_basis = m._from_dict(dct) return parent(result_in_m_basis) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index bd56ffa83cb..ab454861d4c 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4428,80 +4428,6 @@ def revert(self): plethystic_inverse = revert compositional_inverse = revert - def _format_series(self, formatter, format_strings=False): - r""" - Return nonzero ``self`` formatted by ``formatter``. - - TESTS:: - - sage: h = SymmetricFunctions(ZZ).h() - sage: e = SymmetricFunctions(ZZ).e() - sage: L = LazySymmetricFunctions(tensor([h, e])) - sage: f = L(lambda n: sum(tensor([h[k], e[n-k]]) for k in range(n+1))) - sage: f._format_series(repr) - '(h[]#e[]) - + (h[]#e[1]+h[1]#e[]) - + (h[]#e[2]+h[1]#e[1]+h[2]#e[]) - + (h[]#e[3]+h[1]#e[2]+h[2]#e[1]+h[3]#e[]) - + (h[]#e[4]+h[1]#e[3]+h[2]#e[2]+h[3]#e[1]+h[4]#e[]) - + (h[]#e[5]+h[1]#e[4]+h[2]#e[3]+h[3]#e[2]+h[4]#e[1]+h[5]#e[]) - + (h[]#e[6]+h[1]#e[5]+h[2]#e[4]+h[3]#e[3]+h[4]#e[2]+h[5]#e[1]+h[6]#e[]) - + O^7' - """ - P = self.parent() - cs = self._coeff_stream - v = cs._approximate_order - if isinstance(cs, Stream_exact): - if not cs._constant: - m = cs._degree - else: - m = cs._degree + P.options.constant_length - else: - m = v + P.options.display_length - - atomic_repr = P._internal_poly_ring.base_ring()._repr_option('element_is_atomic') - mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] - if not isinstance(cs, Stream_exact) or cs._constant: - if P._internal_poly_ring.base_ring() is P.base_ring(): - bigO = ["O(%s)" % P._monomial(1, m)] - else: - bigO = ["O^%s" % m] - else: - bigO = [] - - from sage.misc.latex import latex - from sage.typeset.unicode_art import unicode_art - from sage.typeset.ascii_art import ascii_art - from sage.misc.repr import repr_lincomb - from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis - from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis - if formatter == repr: - poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) - elif formatter == latex: - poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) - elif formatter == ascii_art: - if atomic_repr: - poly = ascii_art(*(mons + bigO), sep = " + ") - else: - def parenthesize(m): - a = ascii_art(m) - h = a.height() - return ascii_art(ascii_left_parenthesis.character_art(h), - a, ascii_right_parenthesis.character_art(h)) - poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") - elif formatter == unicode_art: - if atomic_repr: - poly = unicode_art(*(mons + bigO), sep = " + ") - else: - def parenthesize(m): - a = unicode_art(m) - h = a.height() - return unicode_art(unicode_left_parenthesis.character_art(h), - a, unicode_right_parenthesis.character_art(h)) - poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") - - return poly - def symmetric_function(self, degree=None): r""" Return ``self`` as a symmetric function if ``self`` is actually so. From 18aa06f817e077ef4da917a28dac3e66e47e722c Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 1 Sep 2022 05:15:14 +0900 Subject: [PATCH 413/742] Fix typos --- src/sage/rings/finite_rings/element_givaro.pyx | 2 +- src/sage/rings/finite_rings/element_ntl_gf2e.pyx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index f17a32f558c..930eccbe57b 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -1,7 +1,7 @@ # distutils: libraries = givaro gmp m # distutils: language = c++ r""" -Givaro finite field flements +Givaro finite field elements Sage includes the Givaro finite field library, for highly optimized arithmetic in finite fields. diff --git a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx index 454f10c462d..a9c85582af7 100644 --- a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ r""" -Finite fields of characteristic 2 elements +Finite field of characteristic 2 elements This implementation uses NTL's GF2E class to perform the arithmetic and is the standard implementation for ``GF(2^n)`` for ``n >= 16``. From 04971318f032caf8dc1c0de9489346d894409091 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Wed, 31 Aug 2022 14:22:26 -0700 Subject: [PATCH 414/742] trac 34465: fix invalid escape sequence in functions/special.py --- src/sage/functions/special.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 02596e49620..901f02f9bee 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -849,7 +849,7 @@ class EllipticF(BuiltinFunction): - :wikipedia:`Elliptic_integral#Incomplete_elliptic_integral_of_the_first_kind` """ def __init__(self): - """ + r""" EXAMPLES:: sage: loads(dumps(elliptic_f)) From 3809a6fe0dde3a90f1b22f838d301d7125288ff5 Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Wed, 10 Aug 2022 13:58:34 +0200 Subject: [PATCH 415/742] remove outdated source tarballs with "sage --package clean" command --- build/sage_bootstrap/app.py | 26 ++++++++++++++++++++++++++ build/sage_bootstrap/cmdline.py | 22 ++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py index d48316dba46..d6094609d88 100644 --- a/build/sage_bootstrap/app.py +++ b/build/sage_bootstrap/app.py @@ -1,6 +1,11 @@ # -*- coding: utf-8 -*- """ Controller for the commandline actions + +AUTHORS: + + - Volker Braun (2016): initial version + - Thierry Monteil (2022): clean option to remove outdated source tarballs """ @@ -26,6 +31,7 @@ from sage_bootstrap.pypi import PyPiVersion, PyPiNotFound, PyPiError from sage_bootstrap.fileserver import FileServer from sage_bootstrap.expand_class import PackageClass +from sage_bootstrap.env import SAGE_DISTFILES class Application(object): @@ -303,3 +309,23 @@ def create(self, package_name, version=None, tarball=None, pkg_type=None, upstre else: update = ChecksumUpdater(package_name) update.fix_checksum() + + def clean(self): + """ + Remove outdated source tarballs from the upstream/ directory + + $ sage --package clean + 42 files were removed from the .../upstream directory + """ + log.debug('Cleaning upstream/ directory') + package_names = PackageClass(':all:').names + keep = [Package(package_name).tarball.filename for package_name in package_names] + count = 0 + for filename in os.listdir(SAGE_DISTFILES): + if filename not in keep: + filepath = os.path.join(SAGE_DISTFILES, filename) + if os.path.isfile(filepath): + log.debug('Removing file {}'.format(filepath)) + os.remove(filepath) + count += 1 + print('{} files were removed from the {} directory'.format(count, SAGE_DISTFILES)) diff --git a/build/sage_bootstrap/cmdline.py b/build/sage_bootstrap/cmdline.py index 8c0515c0ede..ee8b342590d 100644 --- a/build/sage_bootstrap/cmdline.py +++ b/build/sage_bootstrap/cmdline.py @@ -4,6 +4,11 @@ This module handles the main "sage-package" commandline utility, which is also exposed as "sage --package". + +AUTHORS: + + - Volker Braun (2016): initial version + - Thierry Monteil (2022): clean option to remove outdated source tarballs """ # **************************************************************************** @@ -174,6 +179,16 @@ Creating new package "foo" """ +epilog_clean = \ +""" +Remove outdated source tarballs from the upstream/ directory + +EXAMPLE: + + $ sage --package clean + 42 files were removed from the .../upstream directory +""" + def make_parser(): """ @@ -316,6 +331,11 @@ def make_parser(): '--pypi', action="store_true", help='Create a package for a Python package available on PyPI') + parser_clean = subparsers.add_parser( + 'clean', epilog=epilog_clean, + formatter_class=argparse.RawDescriptionHelpFormatter, + help='Remove outdated source tarballs from the upstream/ directory') + return parser @@ -356,6 +376,8 @@ def run(): app.upload_cls(args.package_name) elif args.subcommand == 'fix-checksum': app.fix_checksum_cls(*args.package_class) + elif args.subcommand == 'clean': + app.clean() else: raise RuntimeError('unknown subcommand: {0}'.format(args)) From 6e5a36871fa519802d47b0759a270df91063e5b6 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Thu, 1 Sep 2022 08:25:42 +0800 Subject: [PATCH 416/742] fix various complaints from linters --- src/sage/algebras/clifford_algebra.py | 2 +- src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py | 6 +++--- src/sage/functions/special.py | 2 +- src/sage/groups/cubic_braid.py | 1 + src/sage/schemes/elliptic_curves/hom_velusqrt.py | 3 +++ 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 0def7ae087b..8fc5d750dd6 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2984,7 +2984,7 @@ def groebner_basis(self, term_order=None, reduced=True): from sage.algebras.exterior_algebra_groebner import GroebnerStrategyDegLex as strategy else: raise ValueError("invalid term order") - if strategy == type(self._groebner_strategy): + if isinstance(self._groebner_strategy, strategy): if self._reduced or not reduced: return self._groebner_strategy.groebner_basis self._reduced = reduced diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 467313ce9b9..29ed81ff47d 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -1628,7 +1628,7 @@ def _tietze_to_finite_sub_basis_monomial(self, tietze_tup): def _create_matrix_list_for_one(self, representation_type): r""" Return the matrix list for the given representation type - for ``self.one()`. + for ``self.one()``. EXAMPLES:: @@ -2366,8 +2366,8 @@ def _reduce_all_gen_powers(self, braid_tietze): @cached_method def _reduce_gen_power(self, k): r""" - Return the ``k``-th power on an arbitrary generator, - for example ``c0^k` . + Return the `k`-th power on an arbitrary generator, + for example `c_0^k`. INPUT: diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 02596e49620..901f02f9bee 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -849,7 +849,7 @@ class EllipticF(BuiltinFunction): - :wikipedia:`Elliptic_integral#Incomplete_elliptic_integral_of_the_first_kind` """ def __init__(self): - """ + r""" EXAMPLES:: sage: loads(dumps(elliptic_f)) diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index 6abc64d782b..7f6c89748e9 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -963,6 +963,7 @@ def _test_matrix_group(self, **options): - Construction of matrix group was faithful. - Coercion maps to and from matrix group exist and are inverse to each other. + EXAMPLES:: sage: CBG2 = CubicBraidGroup(2) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 86ca9e51de0..894608fd3a4 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -322,11 +322,14 @@ def prod_with_derivative(pairs): class _aux: def __init__(self, f, df): self.f, self.df = f, df + def __mul__(self, other): return _aux(self.f * other.f, self.df * other.f + self.f * other.df) + def __iter__(self): yield self.f yield self.df + return tuple(prod(_aux(*tup) for tup in pairs)) From b0de177897ed1c4c9b4bbe39cb310313ad189a62 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 31 Aug 2022 21:23:02 -0700 Subject: [PATCH 417/742] src/sage/modules/free_module.py: Pass category through all __init__s, use Subobjects() for submodules --- src/sage/modules/free_module.py | 64 +++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index d508b22fcc7..54c500c4403 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -3500,7 +3500,7 @@ class FreeModule_generic_domain(FreeModule_generic): """ Base class for free modules over an integral domain. """ - def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None): + def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None, category=None): """ Create a free module over an integral domain. @@ -3511,7 +3511,7 @@ def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None): sage: FreeModule(PolynomialRing(GF(7),'x'), 2) Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Finite Field of size 7 """ - FreeModule_generic.__init__(self, base_ring, rank, degree, sparse, coordinate_ring) + FreeModule_generic.__init__(self, base_ring, rank, degree, sparse, coordinate_ring, category=category) def __add__(self, other): r""" @@ -3594,7 +3594,7 @@ class FreeModule_generic_pid(FreeModule_generic_domain): """ Base class for all free modules over a PID. """ - def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None): + def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None, category=None): """ Create a free module over a PID. @@ -3605,7 +3605,7 @@ def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None): sage: FreeModule(PolynomialRing(GF(7),'x'), 2) Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Finite Field of size 7 """ - super().__init__(base_ring, rank, degree, sparse, coordinate_ring) + super().__init__(base_ring, rank, degree, sparse, coordinate_ring, category=category) def index_in(self, other): """ @@ -4219,7 +4219,7 @@ class FreeModule_generic_field(FreeModule_generic_pid): """ Base class for all free modules over fields. """ - def __init__(self, base_field, dimension, degree, sparse=False): + def __init__(self, base_field, dimension, degree, sparse=False, category=None): """ Creates a vector space over a field. @@ -4240,7 +4240,7 @@ def __init__(self, base_field, dimension, degree, sparse=False): """ if not isinstance(base_field, ring.Field): raise TypeError("The base_field (=%s) must be a field"%base_field) - super().__init__(base_field, dimension, degree, sparse=sparse) + super().__init__(base_field, dimension, degree, sparse=sparse, category=category) def _Hom_(self, Y, category): r""" @@ -5207,7 +5207,7 @@ class FreeModule_ambient(FreeModule_generic): """ Ambient free module over a commutative ring. """ - def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None): + def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None, category=None): """ The free module of given rank over the given base_ring. @@ -5243,7 +5243,7 @@ def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None): True """ FreeModule_generic.__init__(self, base_ring, rank=rank, - degree=rank, sparse=sparse, coordinate_ring=coordinate_ring) + degree=rank, sparse=sparse, coordinate_ring=coordinate_ring, category=category) def __hash__(self): """ @@ -5912,7 +5912,7 @@ class FreeModule_ambient_domain(FreeModule_generic_domain, FreeModule_ambient): Ambient free module of rank 3 over the principal ideal domain Univariate Polynomial Ring in x over Finite Field of size 5 """ - def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None): + def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None, category=None): """ Create the ambient free module of given rank over the given integral domain. @@ -5922,7 +5922,7 @@ def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None): sage: A = FreeModule(PolynomialRing(GF(5),'x'), 3) sage: TestSuite(A).run() """ - FreeModule_ambient.__init__(self, base_ring, rank, sparse, coordinate_ring) + FreeModule_ambient.__init__(self, base_ring, rank, sparse, coordinate_ring, category=category) def _repr_(self): """ @@ -6081,7 +6081,7 @@ class FreeModule_ambient_pid(FreeModule_generic_pid, FreeModule_ambient_domain): """ Ambient free module over a principal ideal domain. """ - def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None): + def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None, category=None): """ Create the ambient free module of given rank over the given principal ideal domain. @@ -6114,7 +6114,7 @@ def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None): """ FreeModule_ambient_domain.__init__(self, base_ring=base_ring, - rank=rank, sparse=sparse, coordinate_ring=coordinate_ring) + rank=rank, sparse=sparse, coordinate_ring=coordinate_ring, category=category) def _repr_(self): """ @@ -6173,7 +6173,7 @@ class FreeModule_ambient_field(FreeModule_generic_field, FreeModule_ambient_pid) """ """ - def __init__(self, base_field, dimension, sparse=False): + def __init__(self, base_field, dimension, sparse=False, category=None): """ Create the ambient vector space of given dimension over the given field. @@ -6191,7 +6191,7 @@ def __init__(self, base_field, dimension, sparse=False): sage: QQ^3 Vector space of dimension 3 over Rational Field """ - FreeModule_ambient_pid.__init__(self, base_field, dimension, sparse=sparse) + FreeModule_ambient_pid.__init__(self, base_field, dimension, sparse=sparse, category=category) def _repr_(self): """ @@ -6352,7 +6352,8 @@ class FreeModule_submodule_with_basis_pid(FreeModule_generic_pid): [ 4 5 6] """ def __init__(self, ambient, basis, check=True, - echelonize=False, echelonized_basis=None, already_echelonized=False): + echelonize=False, echelonized_basis=None, already_echelonized=False, + category=None): r""" See :class:`FreeModule_submodule_with_basis_pid` for documentation. @@ -6405,9 +6406,20 @@ def __init__(self, ambient, basis, check=True, if echelonize and not already_echelonized: basis = self._echelonized_basis(ambient, basis) + # Adapted from Module_free_ambient.__init__ + if category is None: + from sage.categories.all import FreeModules + category = FreeModules(R.category()).FiniteDimensional() + try: + if base_ring.is_finite() or len(basis) == 0: + category = category.Enumerated().Finite() + except Exception: + pass + category = category.Subobjects() + FreeModule_generic_pid.__init__(self, base_ring=R, coordinate_ring=R_coord, rank=len(basis), degree=ambient.degree(), - sparse=ambient.is_sparse()) + sparse=ambient.is_sparse(), category=category) C = self.element_class w = [C(self, x.list(), coerce=False, copy=False) for x in basis] self.__basis = basis_seq(self, w) @@ -6698,6 +6710,9 @@ def ambient_module(self): """ return self.__ambient_module + # Subobjects.ParentMethods + ambient = ambient_module + def relations(self): r""" Return the submodule defining the relations of ``self`` as a @@ -7321,7 +7336,8 @@ class FreeModule_submodule_pid(FreeModule_submodule_with_basis_pid): sage: v = W.0 + W.1 sage: TestSuite(v).run() """ - def __init__(self, ambient, gens, check=True, already_echelonized=False): + def __init__(self, ambient, gens, check=True, already_echelonized=False, + category=None): """ Create an embedded free module over a PID. @@ -7336,7 +7352,8 @@ def __init__(self, ambient, gens, check=True, already_echelonized=False): [0 3 6] """ FreeModule_submodule_with_basis_pid.__init__(self, ambient, basis=gens, - echelonize=True, already_echelonized=already_echelonized) + echelonize=True, already_echelonized=already_echelonized, + category=category) def _repr_(self): """ @@ -7474,7 +7491,8 @@ class FreeModule_submodule_with_basis_field(FreeModule_generic_field, FreeModule sage: TestSuite(W).run() """ def __init__(self, ambient, basis, check=True, - echelonize=False, echelonized_basis=None, already_echelonized=False): + echelonize=False, echelonized_basis=None, already_echelonized=False, + category=None): """ Create a vector space with given basis. @@ -7490,7 +7508,8 @@ def __init__(self, ambient, basis, check=True, """ FreeModule_submodule_with_basis_pid.__init__( self, ambient, basis=basis, check=check, echelonize=echelonize, - echelonized_basis=echelonized_basis, already_echelonized=already_echelonized) + echelonized_basis=echelonized_basis, already_echelonized=already_echelonized, + category=category) def _repr_(self): """ @@ -7671,7 +7690,7 @@ class FreeModule_submodule_field(FreeModule_submodule_with_basis_field): sage: vector(QQ, W.coordinates(v)) * W.basis_matrix() (1, 5, 9) """ - def __init__(self, ambient, gens, check=True, already_echelonized=False): + def __init__(self, ambient, gens, check=True, already_echelonized=False, category=None): """ Create an embedded vector subspace with echelonized basis. @@ -7688,7 +7707,8 @@ def __init__(self, ambient, gens, check=True, already_echelonized=False): if is_FreeModule(gens): gens = gens.gens() FreeModule_submodule_with_basis_field.__init__(self, ambient, basis=gens, check=check, - echelonize=not already_echelonized, already_echelonized=already_echelonized) + echelonize=not already_echelonized, already_echelonized=already_echelonized, + category=category) def _repr_(self): """ From 653416a375abb25813bb9e694d1849e49919feda Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 31 Aug 2022 21:47:07 -0700 Subject: [PATCH 418/742] FreeModule_submodule_with_basis_pid.ambient: Implement general case, add examples --- src/sage/modules/free_module.py | 50 ++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 54c500c4403..8e48710511a 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -6710,8 +6710,56 @@ def ambient_module(self): """ return self.__ambient_module + # Sets.Subquotients.ParentMethods + def ambient(self): + """ + Return the ambient module or space for ``self``. + + EXAMPLES:: + + sage: M = ZZ^3 + sage: W = M.span_of_basis([[1,2,3],[4,5,6]]); W + Free module of degree 3 and rank 2 over Integer Ring + User basis matrix: + [1 2 3] + [4 5 6] + sage: W.ambient() + Ambient free module of rank 3 over the principal ideal domain Integer Ring + + Now we create a submodule of the ambient vector space, rather than + ``M`` itself:: + + sage: W = M.span_of_basis([[1,2,3/2],[4,5,6]]); W + Free module of degree 3 and rank 2 over Integer Ring + User basis matrix: + [ 1 2 3/2] + [ 4 5 6] + sage: W.ambient() + Vector space of dimension 3 over Rational Field + + A submodule of a submodule:: + + sage: M = ZZ^3 + sage: W = M.span_of_basis([[1,2,3],[4,5,6]]); W + Free module of degree 3 and rank 2 over Integer Ring + User basis matrix: + [1 2 3] + [4 5 6] + sage: U = W.span_of_basis([[5,7,9]]); U + Free module of degree 3 and rank 1 over Integer Ring + User basis matrix: + [5 7 9] + sage: U.ambient() + Ambient free module of rank 3 over the principal ideal domain Integer Ring + + """ + if self.base_ring() == self.coordinate_ring(): + return self.ambient_module() + else: + return self.ambient_vector_space() + # Subobjects.ParentMethods - ambient = ambient_module + # lift, retract def relations(self): r""" From 88c67d9704e6100b9585336802e2a746e7c15104 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 31 Aug 2022 22:20:48 -0700 Subject: [PATCH 419/742] FreeModule_submodule_with_basis_pid.{lift,retract}: New --- src/sage/modules/free_module.py | 69 ++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 8e48710511a..f069cf552a3 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -193,6 +193,7 @@ from sage.categories.principal_ideal_domains import PrincipalIdealDomains from sage.categories.integral_domains import IntegralDomains from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets +from sage.misc.lazy_attribute import lazy_attribute from sage.misc.randstate import current_randstate from sage.structure.factory import UniqueFactory from sage.structure.sequence import Sequence @@ -6758,8 +6759,72 @@ def ambient(self): else: return self.ambient_vector_space() - # Subobjects.ParentMethods - # lift, retract + # Sets.Subquotients.ParentMethods + @lazy_attribute + def lift(self): + r""" + The lift (embedding) map from ``self`` to the ambient module or space. + + EXAMPLES:: + + sage: M = ZZ^3 + sage: W = M.span_of_basis([[1,2,3],[4,5,6]]); W + Free module of degree 3 and rank 2 over Integer Ring + User basis matrix: + [1 2 3] + [4 5 6] + sage: W.lift + Generic morphism: + From: Free module of degree 3 and rank 2 over Integer Ring + User basis matrix: + [1 2 3] + [4 5 6] + To: Ambient free module of rank 3 over the principal ideal domain Integer Ring + sage: w = W([5,7,9]) + sage: m = W.lift(w); m + (5, 7, 9) + sage: m.parent() + Ambient free module of rank 3 over the principal ideal domain Integer Ring + """ + ambient = self.ambient() + return self.module_morphism(function=ambient, codomain=ambient) + + # Sets.Subquotients.ParentMethods + @lazy_attribute + def retract(self): + r""" + The retract map from the ambient space. + + This is a partial map, which gives an error for elements not in the subspace. + + Calling this map on elements of the ambient space is the same as calling the + element constructor of ``self``. + + EXAMPLES:: + + sage: M = ZZ^3 + sage: W = M.span_of_basis([[1,2,3],[4,5,6]]); W + Free module of degree 3 and rank 2 over Integer Ring + User basis matrix: + [1 2 3] + [4 5 6] + sage: W.retract + Generic morphism: + From: Ambient free module of rank 3 over the principal ideal domain Integer Ring + To: Free module of degree 3 and rank 2 over Integer Ring + User basis matrix: + [1 2 3] + [4 5 6] + sage: m = M([5, 7, 9]) + sage: w = W.retract(m); w + (5, 7, 9) + sage: w.parent() + Free module of degree 3 and rank 2 over Integer Ring + User basis matrix: + [1 2 3] + [4 5 6] + """ + return self.ambient().module_morphism(function=self, codomain=self) def relations(self): r""" From f531b93ab622ec98f3a828bd70de4723e31d10d7 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Thu, 1 Sep 2022 13:35:39 +0800 Subject: [PATCH 420/742] 34212: Correct doc and add an example --- src/sage/rings/number_field/number_field.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 594d103b6aa..48d93ce2381 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -9309,7 +9309,7 @@ def logarithmic_embedding(self, prec=53): The logarithmic embedding is defined as a map from the number field ``self`` to `\RR^n`. - It is defined under Definition 4.9.6 in [Cohen1993]_. + It is defined under Definition 4.9.6 in [Coh1993]_. INPUT: @@ -9336,6 +9336,15 @@ def logarithmic_embedding(self, prec=53): (-1, -1) sage: f(7) (1.94591014905531, 3.89182029811063) + + :: + + sage: K. = NumberField(x^4 - 8*x^2 + 3) + sage: f = logarithmic_embedding(K) + sage: f(0) + (-1, -1, -1, -1) + sage: f(7) + (3.89182029811063, 3.89182029811063, 3.89182029811063, 3.89182029811063) """ def closure_map(x, prec=53): """ From 6fb2387679f2b8279d3f6e6d1c871a0a42cde1de Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Thu, 1 Sep 2022 13:42:27 +0800 Subject: [PATCH 421/742] 34212: log embedding for relative number field --- .../rings/number_field/number_field_rel.py | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index d33980c4b10..499a89161a6 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -2062,6 +2062,75 @@ def automorphisms(self): check=False, universe=self.Hom(self)) return self.__automorphisms + def logarithmic_embedding(self, prec=53): + r""" + Return the morphism of ``self`` under the logarithmic embedding + in the category Set. + + The logarithmic embedding is defined as a map from the relative number field ``self`` to `\RR^n`. + + It is defined under Definition 4.9.6 in [Coh1993]_. + + INPUT: + + - ``prec`` -- desired floating point precision. + + OUTPUT: + + - the morphism of ``self`` under the logarithmic embedding in the category Set. + + EXAMPLES:: + + sage: K. = CyclotomicField(3) + sage: R. = K[] + sage: L. = K.extension(x^5 + 5) + sage: f = logarithmic_embedding(L) + sage: f(0) + (-1, -1, -1, -1, -1) + sage: f(5) + (3.21887582486820, 3.21887582486820, 3.21887582486820, + 3.21887582486820, 3.21887582486820) + + :: + + sage: K. = NumberField(x^2 + 1) + sage: t = K['t'].gen() + sage: L. = K.extension(t^4 - i) + sage: f = logarithmic_embedding(L) + sage: f(0) + (-1, -1, -1, -1, -1, -1, -1, -1) + sage: f(3) + (2.19722457733622, 2.19722457733622, 2.19722457733622, 2.19722457733622, + 2.19722457733622, 2.19722457733622, 2.19722457733622, 2.19722457733622) + """ + def closure_map(x, prec=53): + """ + The function closure of the logarithmic embedding. + """ + K = self + K_embeddings = K.places(prec) + r1, r2 = K.signature() + r = r1 + r2 - 1 + + from sage.rings.all import RealField + Reals = RealField(prec) + + if x == 0: + return vector([-1 for _ in range(r + 1)]) + + x_logs = [] + for i in range(r1): + sigma = K_embeddings[i] + x_logs.append(Reals(abs(sigma(x))).log()) + for i in range(r1, r + 1): + tau = K_embeddings[i] + x_logs.append(2 * Reals(abs(tau(x))).log()) + + return vector(x_logs) + + hom = Hom(self, VectorSpace(RR, len(closure_map(self(0), prec))), Sets()) + return hom(closure_map) + def places(self, all_complex=False, prec=None): """ Return the collection of all infinite places of self. From 03aabf5ae70f298d5e99c4b0a5a3f2452c0f3d45 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Thu, 1 Sep 2022 14:51:33 +0800 Subject: [PATCH 422/742] 34212: correct examples --- src/sage/rings/number_field/number_field.py | 6 +++--- src/sage/rings/number_field/number_field_rel.py | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 48d93ce2381..98d46464058 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -9339,12 +9339,12 @@ def logarithmic_embedding(self, prec=53): :: - sage: K. = NumberField(x^4 - 8*x^2 + 3) - sage: f = logarithmic_embedding(K) + sage: F. = NumberField(x^4 - 8*x^2 + 3) + sage: f = F.logarithmic_embedding() sage: f(0) (-1, -1, -1, -1) sage: f(7) - (3.89182029811063, 3.89182029811063, 3.89182029811063, 3.89182029811063) + (1.94591014905531, 1.94591014905531, 1.94591014905531, 1.94591014905531) """ def closure_map(x, prec=53): """ diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index 499a89161a6..9e80ef1e3c1 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -99,8 +99,12 @@ from sage.rings.number_field.morphism import RelativeNumberFieldHomomorphism_from_abs from sage.libs.pari.all import pari_gen -from sage.rings.rational_field import QQ -from sage.rings.integer_ring import ZZ +from sage.categories.homset import Hom +from sage.categories.sets_cat import Sets +from sage.modules.free_module import VectorSpace +from sage.modules.free_module_element import vector + +from sage.rings.all import RR, QQ, ZZ def is_RelativeNumberField(x): @@ -2084,7 +2088,7 @@ def logarithmic_embedding(self, prec=53): sage: K. = CyclotomicField(3) sage: R. = K[] sage: L. = K.extension(x^5 + 5) - sage: f = logarithmic_embedding(L) + sage: f = L.logarithmic_embedding() sage: f(0) (-1, -1, -1, -1, -1) sage: f(5) @@ -2096,7 +2100,7 @@ def logarithmic_embedding(self, prec=53): sage: K. = NumberField(x^2 + 1) sage: t = K['t'].gen() sage: L. = K.extension(t^4 - i) - sage: f = logarithmic_embedding(L) + sage: f = L.logarithmic_embedding() sage: f(0) (-1, -1, -1, -1, -1, -1, -1, -1) sage: f(3) From 946083dffc1deda6257ae9774e32d40b81544a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 1 Sep 2022 09:14:40 +0200 Subject: [PATCH 423/742] add missing r (raw) prefix to doc in pyx files in matroids --- .../algebras/exterior_algebra_groebner.pyx | 4 +-- src/sage/matroids/basis_exchange_matroid.pyx | 2 +- src/sage/matroids/basis_matroid.pyx | 3 +- src/sage/matroids/extension.pyx | 4 +-- src/sage/matroids/linear_matroid.pyx | 30 +++++++++---------- src/sage/matroids/matroid.pyx | 22 +++++++------- src/sage/modules/free_module_element.pyx | 2 +- 7 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index 98e338d3468..dc77faa590d 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -137,7 +137,7 @@ cdef class GroebnerStrategy: return self.int_to_bitset(max(self.bitset_to_int(k) for k in mc)) cdef inline partial_S_poly_left(self, GBElement f, GBElement g): - """ + r""" Compute one half of the `S`-polynomial for ``f`` and ``g``. This computes: @@ -154,7 +154,7 @@ cdef class GroebnerStrategy: return ret cdef inline partial_S_poly_right(self, GBElement f, GBElement g): - """ + r""" Compute one half of the `S`-polynomial for ``f`` and ``g``. This computes: diff --git a/src/sage/matroids/basis_exchange_matroid.pyx b/src/sage/matroids/basis_exchange_matroid.pyx index 7b72cd245df..5679814d32b 100644 --- a/src/sage/matroids/basis_exchange_matroid.pyx +++ b/src/sage/matroids/basis_exchange_matroid.pyx @@ -2115,7 +2115,7 @@ cdef class BasisExchangeMatroid(Matroid): return EQ[0] cpdef _is_isomorphism(self, other, morphism): - """ + r""" Version of is_isomorphism() that does no type checking. INPUT: diff --git a/src/sage/matroids/basis_matroid.pyx b/src/sage/matroids/basis_matroid.pyx index b8fd1cdc342..ff70add1ce2 100644 --- a/src/sage/matroids/basis_matroid.pyx +++ b/src/sage/matroids/basis_matroid.pyx @@ -1280,8 +1280,9 @@ cdef long set_to_index(bitset_t S): s = bitset_next(S, s + 1) return index + cdef index_to_set(bitset_t S, long index, long k, long n): - """ + r""" Compute the k-subset of `\{0, ..., n-1\}` of rank index """ bitset_clear(S) diff --git a/src/sage/matroids/extension.pyx b/src/sage/matroids/extension.pyx index f4f9d44516b..0408e60f86e 100644 --- a/src/sage/matroids/extension.pyx +++ b/src/sage/matroids/extension.pyx @@ -248,7 +248,7 @@ cdef class LinearSubclassesIter: cdef class LinearSubclasses: - """ + r""" An iterable set of linear subclasses of a matroid. Enumerate linear subclasses of a given matroid. A *linear subclass* is a @@ -412,7 +412,7 @@ cdef class LinearSubclasses: cdef class MatroidExtensions(LinearSubclasses): - """ + r""" An iterable set of single-element extensions of a given matroid. INPUT: diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 917017f6afe..0c9b0a1baff 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -761,7 +761,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): return {e: R[self._idx[e]] for e in self.groundset()} cpdef LeanMatrix _reduced_representation(self, B=None): - """ + r""" Return a reduced representation of the matroid, i.e. a matrix `R` such that `[I\ \ R]` represents the matroid. @@ -800,7 +800,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): # (field) isomorphism cpdef bint _is_field_isomorphism(self, LinearMatroid other, morphism): # not safe if self == other - """ + r""" Version of :meth:`` that does no type checking. @@ -966,7 +966,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): return self._is_field_isomorphism(other, morphism) cpdef is_field_isomorphism(self, other, morphism): - """ + r""" Test if a provided morphism induces a bijection between represented matroids. @@ -1322,7 +1322,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): return type(self)(reduced_matrix=M, groundset=rows + cols) cpdef dual(self): - """ + r""" Return the dual of the matroid. Let `M` be a matroid with ground set `E`. If `B` is the set of bases @@ -1354,7 +1354,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): return type(self)(reduced_matrix=R, groundset=cols + rows) cpdef has_line_minor(self, k, hyperlines=None, certificate=False): - """ + r""" Test if the matroid has a `U_{2, k}`-minor. The matroid `U_{2, k}` is a matroid on `k` elements in which every @@ -3130,7 +3130,7 @@ cdef class BinaryMatroid(LinearMatroid): self._one = GF2_one cpdef base_ring(self): - """ + r""" Return the base ring of the matrix representing the matroid, in this case `\GF{2}`. @@ -3308,7 +3308,7 @@ cdef class BinaryMatroid(LinearMatroid): return self._A.copy() # Deprecated Sage matrix operation cpdef LeanMatrix _reduced_representation(self, B=None): - """ + r""" Return a reduced representation of the matroid, i.e. a matrix `R` such that `[I\ \ R]` represents the matroid. @@ -4197,7 +4197,7 @@ cdef class TernaryMatroid(LinearMatroid): self._two = GF3_minus_one cpdef base_ring(self): - """ + r""" Return the base ring of the matrix representing the matroid, in this case `\GF{3}`. @@ -4381,7 +4381,7 @@ cdef class TernaryMatroid(LinearMatroid): return self._A.copy() # Deprecated Sage matrix operation cpdef LeanMatrix _reduced_representation(self, B=None): - """ + r""" Return a reduced representation of the matroid, i.e. a matrix `R` such that `[I\ \ R]` represents the matroid. @@ -4563,7 +4563,7 @@ cdef class TernaryMatroid(LinearMatroid): return self._t_invariant cpdef bicycle_dimension(self): - """ + r""" Return the bicycle dimension of the ternary matroid. The bicycle dimension of a linear subspace `V` is @@ -5096,7 +5096,7 @@ cdef class QuaternaryMatroid(LinearMatroid): self._x_one = (self._A)._x_one cpdef base_ring(self): - """ + r""" Return the base ring of the matrix representing the matroid, in this case `\GF{4}`. @@ -5273,7 +5273,7 @@ cdef class QuaternaryMatroid(LinearMatroid): return self._A.copy() # Deprecated Sage matrix operation cpdef LeanMatrix _reduced_representation(self, B=None): - """ + r""" Return a reduced representation of the matroid, i.e. a matrix `R` such that `[I\ \ R]` represents the matroid. @@ -5413,7 +5413,7 @@ cdef class QuaternaryMatroid(LinearMatroid): return self._q_invariant cpdef bicycle_dimension(self): - """ + r""" Return the bicycle dimension of the quaternary matroid. The bicycle dimension of a linear subspace `V` is @@ -5810,7 +5810,7 @@ cdef class RegularMatroid(LinearMatroid): return P cpdef base_ring(self): - """ + r""" Return the base ring of the matrix representing the matroid, in this case `\ZZ`. @@ -6230,7 +6230,7 @@ cdef class RegularMatroid(LinearMatroid): return {e:idx[m[str(e)]] for e in self.groundset() if str(e) in m} cpdef has_line_minor(self, k, hyperlines=None, certificate=False): - """ + r""" Test if the matroid has a `U_{2, k}`-minor. The matroid `U_{2, k}` is a matroid on `k` elements in which every diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 8263860cbec..7378d250e44 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -3150,7 +3150,7 @@ cdef class Matroid(SageObject): return Polyhedron(vertices) def independence_matroid_polytope(self): - """ + r""" Return the independence matroid polytope of ``self``. This is defined as the convex hull of the vertices @@ -3430,7 +3430,7 @@ cdef class Matroid(SageObject): return self._is_isomorphism(other, morphism) cpdef is_isomorphism(self, other, morphism): - """ + r""" Test if a provided morphism induces a matroid isomorphism. A *morphism* is a map from the groundset of ``self`` to the groundset @@ -3553,7 +3553,7 @@ cdef class Matroid(SageObject): return self._is_isomorphism(other, mf) cpdef _is_isomorphism(self, other, morphism): - """ + r""" Version of is_isomorphism() that does no type checking. INPUT: @@ -3942,7 +3942,7 @@ cdef class Matroid(SageObject): return self.delete(X) cpdef dual(self): - """ + r""" Return the dual of the matroid. Let `M` be a matroid with ground set `E`. If `B` is the set of bases @@ -4054,7 +4054,7 @@ cdef class Matroid(SageObject): return self._has_minor(N, certificate) cpdef has_line_minor(self, k, hyperlines=None, certificate=False): - """ + r""" Test if the matroid has a `U_{2, k}`-minor. The matroid `U_{2, k}` is a matroid on `k` elements in which every @@ -4125,7 +4125,7 @@ cdef class Matroid(SageObject): return self._has_line_minor(k, hyperlines, certificate) cpdef _has_line_minor(self, k, hyperlines, certificate=False): - """ + r""" Test if the matroid has a `U_{2, k}`-minor. Internal version that does no input checking. @@ -4313,7 +4313,7 @@ cdef class Matroid(SageObject): return self.dual().extension(element, subsets).dual() cpdef modular_cut(self, subsets): - """ + r""" Compute the modular cut generated by ``subsets``. A *modular cut* is a collection `C` of flats such that @@ -4403,7 +4403,7 @@ cdef class Matroid(SageObject): return final_list cpdef linear_subclasses(self, line_length=None, subsets=None): - """ + r""" Return an iterable set of linear subclasses of the matroid. A *linear subclass* is a set of hyperplanes (i.e. closed sets of rank @@ -4714,7 +4714,7 @@ cdef class Matroid(SageObject): return True cpdef is_cosimple(self): - """ + r""" Test if the matroid is cosimple. A matroid is *cosimple* if it contains no cocircuits of length 1 or 2. @@ -4791,7 +4791,7 @@ cdef class Matroid(SageObject): return components cpdef is_connected(self, certificate=False): - """ + r""" Test if the matroid is connected. A *separation* in a matroid is a partition `(X, Y)` of the @@ -7480,7 +7480,7 @@ cdef class Matroid(SageObject): return A cpdef tutte_polynomial(self, x=None, y=None): - """ + r""" Return the Tutte polynomial of the matroid. The *Tutte polynomial* of a matroid is the polynomial diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index de627d5939a..67991cebd52 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -3743,7 +3743,7 @@ cdef class FreeModuleElement(Vector): # abstract base class from sage.misc.latex import latex vector_delimiters = latex.vector_delimiters() s = '\\left' + vector_delimiters[0] - s += ',\,'.join(latex(a) for a in self.list()) + s += r',\,'.join(latex(a) for a in self.list()) return s + '\\right' + vector_delimiters[1] def dense_vector(self): From 111a621d34301115d49da6b946bcc3ea0debae89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 1 Sep 2022 09:47:22 +0200 Subject: [PATCH 424/742] modern super() and other pep details in matrix_space --- src/sage/matrix/matrix_space.py | 77 +++++++++++++++++---------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 26f058d3aeb..cfb8ce85931 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -49,7 +49,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.superseded import deprecated_function_alias - +from sage.misc.persist import register_unpickle_override from sage.categories.rings import Rings from sage.categories.fields import Fields from sage.categories.enumerated_sets import EnumeratedSets @@ -406,7 +406,6 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): return Matrix_generic_sparse - class MatrixSpace(UniqueRepresentation, Parent): """ The space of matrices of given size and base ring @@ -544,10 +543,10 @@ def __classcall__(cls, base_ring, nrows, ncols=None, sparse=False, implementatio sage: class MyMatrixSpace(MatrixSpace): ....: @staticmethod ....: def __classcall__(cls, base_ring, nrows, ncols=None, my_option=True, sparse=False, implementation=None): - ....: return super(MyMatrixSpace, cls).__classcall__(cls, base_ring, nrows, ncols=ncols, my_option=my_option, sparse=sparse, implementation=implementation) + ....: return super().__classcall__(cls, base_ring, nrows, ncols=ncols, my_option=my_option, sparse=sparse, implementation=implementation) ....: ....: def __init__(self, base_ring, nrows, ncols, sparse, implementation, my_option=True): - ....: super(MyMatrixSpace, self).__init__(base_ring, nrows, ncols, sparse, implementation) + ....: super().__init__(base_ring, nrows, ncols, sparse, implementation) ....: self._my_option = my_option sage: MS1 = MyMatrixSpace(ZZ, 2) @@ -558,7 +557,7 @@ def __classcall__(cls, base_ring, nrows, ncols=None, sparse=False, implementatio False """ if base_ring not in _Rings: - raise TypeError("base_ring (=%s) must be a ring"%base_ring) + raise TypeError("base_ring (=%s) must be a ring" % base_ring) nrows = int(nrows) if ncols is None: ncols = nrows @@ -574,8 +573,8 @@ def __classcall__(cls, base_ring, nrows, ncols=None, sparse=False, implementatio raise OverflowError("number of rows and columns may be at most %s" % sys.maxsize) matrix_cls = get_matrix_class(base_ring, nrows, ncols, sparse, implementation) - return super(MatrixSpace, cls).__classcall__( - cls, base_ring, nrows, ncols, sparse, matrix_cls, **kwds) + return super().__classcall__(cls, base_ring, nrows, + ncols, sparse, matrix_cls, **kwds) def __init__(self, base_ring, nrows, ncols, sparse, implementation): r""" @@ -1261,8 +1260,8 @@ def _repr_(self): s = "sparse" else: s = "dense" - s = "Full MatrixSpace of %s by %s %s matrices over %s"%( - self.__nrows, self.__ncols, s, self.base_ring()) + s = "Full MatrixSpace of %s by %s %s matrices over %s" % ( + self.__nrows, self.__ncols, s, self.base_ring()) if not self._has_default_implementation(): s += " (using {})".format(self.Element.__name__) @@ -1283,7 +1282,7 @@ def _repr_option(self, key): """ if key == 'element_ascii_art': return self.__nrows > 1 - return super(MatrixSpace, self)._repr_option(key) + return super()._repr_option(key) def _latex_(self): r""" @@ -1295,8 +1294,8 @@ def _latex_(self): sage: latex(MS3) \mathrm{Mat}_{6\times 6}(\Bold{Q}) """ - return "\\mathrm{Mat}_{%s\\times %s}(%s)"%(self.nrows(), self.ncols(), - latex.latex(self.base_ring())) + return "\\mathrm{Mat}_{%s\\times %s}(%s)" % (self.nrows(), self.ncols(), + latex.latex(self.base_ring())) def __len__(self): """ @@ -1504,14 +1503,14 @@ def __iter__(self): ... NotImplementedError: len() of an infinite set """ - #Make sure that we can iterate over the base ring + # Make sure that we can iterate over the base ring base_ring = self.base_ring() base_iter = iter(base_ring) - number_of_entries = (self.__nrows*self.__ncols) + number_of_entries = (self.__nrows * self.__ncols) - #If the number of entries is zero, then just - #yield the empty matrix in that case and return + # If the number of entries is zero, then just + # yield the empty matrix in that case and return if number_of_entries == 0: yield self(0) return @@ -1519,11 +1518,11 @@ def __iter__(self): import sage.combinat.integer_vector if not base_ring.is_finite(): - #When the base ring is not finite, then we should go - #through and yield the matrices by "weight", which is - #the total number of iterations that need to be done - #on the base ring to reach the matrix. - base_elements = [ next(base_iter) ] + # When the base ring is not finite, then we should go + # through and yield the matrices by "weight", which is + # the total number of iterations that need to be done + # on the base ring to reach the matrix. + base_elements = [next(base_iter)] weight = 0 while True: for iv in sage.combinat.integer_vector.IntegerVectors(weight, number_of_entries): @@ -1579,7 +1578,7 @@ def __getitem__(self, x): """ if isinstance(x, (integer.Integer, int)): return self.list()[x] - return super(MatrixSpace, self).__getitem__(x) + return super().__getitem__(x) def basis(self): """ @@ -1639,7 +1638,6 @@ def dims(self): """ return (self.__nrows, self.__ncols) - def submodule(self, gens, check=True, already_echelonized=False, unitriangular=False, support_order=None, category=None, *args, **opts): @@ -1733,6 +1731,7 @@ def submodule(self, gens, check=True, already_echelonized=False, category=category, *args, **opts) from sage.misc.cachefunc import cached_method + @cached_method def identity_matrix(self): """ @@ -1903,7 +1902,7 @@ def gen(self, n): r = n // self.__ncols c = n - (r * self.__ncols) z = self.zero_matrix().__copy__() - z[r,c] = 1 + z[r, c] = 1 return z @cached_method @@ -2208,10 +2207,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), \ + Z.randomize(density=float(1), nonzero=kwds.pop('nonzero', False), *args, **kwds) else: - Z.randomize(density=density, nonzero=kwds.pop('nonzero', True), \ + Z.randomize(density=density, nonzero=kwds.pop('nonzero', True), *args, **kwds) return Z @@ -2328,10 +2327,8 @@ def _magma_init_(self, magma): """ K = magma(self.base_ring()) if self.__nrows == self.__ncols: - s = 'MatrixAlgebra(%s,%s)'%(K.name(), self.__nrows) - else: - s = 'RMatrixSpace(%s,%s,%s)'%(K.name(), self.__nrows, self.__ncols) - return s + return 'MatrixAlgebra(%s,%s)' % (K.name(), self.__nrows) + return 'RMatrixSpace(%s,%s,%s)' % (K.name(), self.__nrows, self.__ncols) def _polymake_init_(self): r""" @@ -2384,6 +2381,7 @@ def _random_nonzero_element(self, *args, **kwds): rand_matrix = self.random_element(*args, **kwds) return rand_matrix + def dict_to_list(entries, nrows, ncols): r""" Given a dictionary of coordinate tuples, return the list given by @@ -2468,7 +2466,7 @@ def _test_trivial_matrices_inverse(ring, sparse=True, implementation=None, check """ # Check that the empty 0x0 matrix is it's own inverse with det=1. ms00 = MatrixSpace(ring, 0, 0, sparse=sparse) - m00 = ms00(0) + m00 = ms00(0) assert(m00.determinant() == ring(1)) assert(m00.is_invertible()) assert(m00.inverse() == m00) @@ -2479,7 +2477,7 @@ def _test_trivial_matrices_inverse(ring, sparse=True, implementation=None, check # computing the determinant raise the proper exception. for ms0 in [MatrixSpace(ring, 0, 3, sparse=sparse), MatrixSpace(ring, 3, 0, sparse=sparse)]: - mn0 = ms0(0) + mn0 = ms0(0) assert(not mn0.is_invertible()) try: d = mn0.determinant() @@ -2499,22 +2497,22 @@ def _test_trivial_matrices_inverse(ring, sparse=True, implementation=None, check # Check that the null 1x1 matrix is not invertible and that det=0 ms1 = MatrixSpace(ring, 1, 1, sparse=sparse) - m0 = ms1(0) + m0 = ms1(0) assert(not m0.is_invertible()) assert(m0.determinant() == ring(0)) try: m0.inverse() res = False except (ZeroDivisionError, RuntimeError): - #FIXME: Make pynac throw a ZeroDivisionError on division by - #zero instead of a runtime Error + # FIXME: Make pynac throw a ZeroDivisionError on division by + # zero instead of a runtime Error res = True assert(res) if checkrank: assert(m0.rank() == 0) # Check that the identity 1x1 matrix is its own inverse with det=1 - m1 = ms1(1) + m1 = ms1(1) assert(m1.is_invertible()) assert(m1.determinant() == ring(1)) inv = m1.inverse() @@ -2529,10 +2527,13 @@ def _test_trivial_matrices_inverse(ring, sparse=True, implementation=None, check # Fix unpickling Matrix_modn_dense and Matrix_integer_2x2 lazy_import('sage.matrix.matrix_modn_dense_double', 'Matrix_modn_dense_double') lazy_import('sage.matrix.matrix_integer_dense', 'Matrix_integer_dense') -from sage.misc.persist import register_unpickle_override + + def _MatrixSpace_ZZ_2x2(): from sage.rings.integer_ring import ZZ - return MatrixSpace(ZZ,2) + return MatrixSpace(ZZ, 2) + + register_unpickle_override('sage.matrix.matrix_modn_dense', 'Matrix_modn_dense', Matrix_modn_dense_double) register_unpickle_override('sage.matrix.matrix_integer_2x2', From 1b4745764a283f35f6b4f85360fdae3f21033ac8 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Thu, 1 Sep 2022 17:13:38 +0800 Subject: [PATCH 425/742] preempt merge conflict --- src/sage/functions/special.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 901f02f9bee..02596e49620 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -849,7 +849,7 @@ class EllipticF(BuiltinFunction): - :wikipedia:`Elliptic_integral#Incomplete_elliptic_integral_of_the_first_kind` """ def __init__(self): - r""" + """ EXAMPLES:: sage: loads(dumps(elliptic_f)) From 111f376bf91a9e153a3e563ebfe63e7ad0afd229 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Thu, 1 Sep 2022 11:16:51 +0100 Subject: [PATCH 426/742] Update based on comment 52 by tscrim. Mostly PEP8 formatting and improving some checks / way lists are handled. --- .../riemann_surfaces/riemann_surface.py | 91 ++++++++++--------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 4bacb2545b6..71d4d0f628b 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -60,7 +60,7 @@ We can look at an extended example of the Abel-Jacobi functionality. We will demonstrate a particular half-canonical divisor on Klein's Curve, known in -the literature.:: +the literature:: sage: f = x^3*y + y^3 + x sage: S = RiemannSurface(f, integration_method='rigorous') @@ -81,7 +81,7 @@ sage: if K-3*Pinf-1*Pinf_prime: Pinf, Pinf_prime = (Pinf_prime, Pinf); sage: D = P0 + 2*Pinf - Pinf_prime -Note we could check using exact techniques that `2D=K`:: +Note we could check using exact techniques that `2D = K`:: sage: Z = K - 2*D sage: (Z.degree()==0, len(Z.basis_differential_space())==S.genus, len(Z.basis_function_space())==1) @@ -371,7 +371,7 @@ def differential_basis_baker(f): if P.interior_contains(a)] -def find_closest_element(item, List): +def find_closest_element(item, lst): r""" Return the index of the closest element of a list. @@ -381,9 +381,9 @@ def find_closest_element(item, List): INPUT: - - ``item`` -- value to minimise the distance to over the list. + - ``item`` -- value to minimize the distance to over the list - - ``List`` -- list. List to look for closest element in. + - ``lst`` -- list to look for closest element in EXAMPLES:: @@ -396,11 +396,11 @@ def find_closest_element(item, List): Note that this method does no checks on the input, but will fail for inputs where the absolute value or subtraction do not make sense. """ - dists = [(item-l).abs() for l in List] + dists = [(item-l).abs() for l in lst] return dists.index(min(dists)) -def reparameterise_differential_minpoly(minpoly, z0): +def reparameterize_differential_minpoly(minpoly, z0): r""" Rewrites a minimal polynomial to write is around `z_0`. @@ -412,14 +412,13 @@ def reparameterise_differential_minpoly(minpoly, z0): INPUT: - ``minpoly`` -- a polynomial in two variables, where the first variables - corresponds to the base coordinate on the Riemann surface. - - - ``z0`` -- complex number of infinity. The point about which to - reparameterise. + corresponds to the base coordinate on the Riemann surface + - ``z0`` -- complex number or infinity; the point about which to + reparameterize OUTPUT: - A polynomial in two variables giving the reparameterise minimal polynomial. + A polynomial in two variables giving the reparameterize minimal polynomial. EXAMPLES: @@ -431,18 +430,18 @@ def reparameterise_differential_minpoly(minpoly, z0): Hence the transformed differential should have minimal polynomial `\bar{g}^2\bar{z}(1-\bar{z}^3)-1/4=0`, and we can check this:: - sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface, reparameterise_differential_minpoly + sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface, reparameterize_differential_minpoly sage: R. = QQ[] sage: S = RiemannSurface(w^2-z^3+1) sage: minpoly = S._cohomology_basis_bounding_data[1][0][2] sage: z0 = Infinity - sage: reparameterise_differential_minpoly(minpoly, z0) + sage: reparameterize_differential_minpoly(minpoly, z0) -zbar^4*gbar^2 + zbar*gbar^2 - 1/4 We can further check that reparameterising about `0` is the identity operation:: - sage: reparameterise_differential_minpoly(minpoly, 0)(*minpoly.parent().gens())==minpoly + sage: reparameterize_differential_minpoly(minpoly, 0)(*minpoly.parent().gens())==minpoly True .. NOTE:: @@ -450,7 +449,7 @@ def reparameterise_differential_minpoly(minpoly, z0): As part of the routine, when reparameterising about infinity, a rational function is reduced and then the numerator is taken. Over an inexact ring this is numerically unstable, and so it is advisable - to only reparameterise about infinity over an exact ring. + to only reparameterize about infinity over an exact ring. """ P = minpoly.parent() F = PolynomialRing(P.base_ring(), [str(v)+"bar" for v in P.gens()]) @@ -699,7 +698,7 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati # We now want to also check whether Infinity is a branch point of any # of the differentials. # This will be useful when calculating the Abel-Jacobi map. - minpoly_list = [reparameterise_differential_minpoly(mp, Infinity) + minpoly_list = [reparameterize_differential_minpoly(mp, Infinity) for mp in minpoly_list] discriminants = [] for minpoly in minpoly_list: @@ -875,7 +874,7 @@ def upstairs_graph(self): sage: G.is_connected() True """ - G = Graph(self.upstairs_edges()) + G = Graph(self.upstairs_edges(), immutable=True) G.set_pos({(i,j): [self._vertices[i].real(), self._vertices[i].imag(), self.w_values(self._vertices[i])[j].imag()] for i in range(len(self._vertices)) for j in range(self.degree)}, dim=3) @@ -1241,8 +1240,9 @@ def upstairs_edges(self): i0, i1 = e d_edge = (self._vertices[i0], self._vertices[i1]) # Epsilon for checking w-value later. - epsilon = min([abs(self._wvalues[i1][i] - self._wvalues[i1][n-j-1]) - for i in range(n) for j in range(n-i-1)])/3 + val = self._wvalues[i1] + epsilon = min(abs(val[i] - val[n-j-1]) + for i in range(n) for j in range(n-i-1)) / 3 # Homotopy continuation along e. self._L[e] = self.homotopy_continuation(d_edge) homotopycont = self._L[e][-1][1] @@ -1609,12 +1609,11 @@ def make_zw_interpolator(self, upstairs_edge, initial_continuation=None): INPUT: - - ``upstairs_edge`` -- tuple. ``((z_start, sb), (z_end,))`` giving the + - ``upstairs_edge`` -- tuple ``((z_start, sb), (z_end,))`` giving the start and end values of the base coordinate along the straight-line - path and the starting branch. - - - ``initial_continuation`` -- list (default: None). Output of - ``homotopy_continuation`` initialising the continuation data. + path and the starting branch + - ``initial_continuation`` -- list (optional); output of + ``homotopy_continuation`` initialising the continuation data OUTPUT: @@ -2757,7 +2756,7 @@ def _integrate_differentials_iteratively(self, upstairs_edge, cutoff_individuall The cohomology basis is integrated along a straight line using a version of the double exponential quadrature. This method of integrating the cohomology basis is especially useful when integrating out to infinity, - or near roots of `self._dfdw`. In order to aid with convergence of the + or near roots of ``self._dfdw``. In order to aid with convergence of the method, two main modification to a standard integrator are made, most importantly of which is the truncation of the integral near branch points, where the first term in the Puiseux series of the integrands are used to @@ -2830,7 +2829,7 @@ def _integrate_differentials_iteratively(self, upstairs_edge, cutoff_individuall mp_list = [bd[2] for bd in bounding_data_list] # Parameterise so zbar=0 corresponds to z=z_start - mp_list = [reparameterise_differential_minpoly(mp, z_start) + mp_list = [reparameterize_differential_minpoly(mp, z_start) for mp in mp_list] if z_start==self._CC(Infinity): @@ -2874,8 +2873,8 @@ def initialise(z, i): prec = self._prec # tau here is playing the role of the desired error. tau = self._RR(2)**(-prec+3) - ONE = self._RR(1) - LAMBDA = self._RR.pi()/2 + one = self._RR(1) + la = self._RR.pi()/2 if cutoff_individually is None: cutoffs = [0] @@ -2909,15 +2908,15 @@ def error_handle(out): return out V = VectorSpace(self._CC, self.genus) - h = ONE - Nh = (-lambert_w(-1,-tau/2)/LAMBDA).log().ceil() + h = one + Nh = (-lambert_w(-1,-tau/2)/la).log().ceil() h0 = Nh*h if cutoff_individually: z_fc_list = list(zip(fc_mp_list, fc_dmp_list)) def fv(hj, previous_estimate_and_validity): - u2 = LAMBDA*hj.sinh() + u2 = la*hj.sinh() t = 1/(2*u2.exp()*u2.cosh()) z0 = J*t outg = [] @@ -2951,7 +2950,7 @@ def fv(hj, previous_estimate_and_validity): if j==99: outg.append(error_handle(newg)) fj = V(outg) - u1 = LAMBDA*hj.cosh() + u1 = la*hj.cosh() w = u1/(2*u2.cosh()**2) return (fj, valid), w*fj @@ -2963,7 +2962,7 @@ def fv(hj, previous_estimate_and_validity): J -= cutoff_z def fv(hj, previous_estimate): - u2 = LAMBDA*hj.sinh() + u2 = la*hj.sinh() t = 1/(2*u2.exp()*u2.cosh()) z0 = cutoff_z+J*t outg = [] @@ -2985,11 +2984,11 @@ def fv(hj, previous_estimate): if j==99: outg.append(error_handle(newg)) fj = V(outg) - u1 = LAMBDA*hj.cosh() + u1 = la*hj.cosh() w = u1/(2*u2.cosh()**2) return fj, w*fj - u1, u2 = (LAMBDA*h0.cosh(),LAMBDA*h0.sinh()) + u1, u2 = (la*h0.cosh(),la*h0.sinh()) y, w = (1/(2*u2.exp()*u2.cosh()), u1/(2*u2.cosh()**2)) z0 = cutoff_z+J*y f0 = [initialise(z0, i) for i in range(self.genus)] @@ -3021,7 +3020,7 @@ def fv(hj, previous_estimate): else: D1 = (results[-1]-results[-2]).norm(Infinity) D2 = (results[-1]-results[-3]).norm(Infinity) - D = min(ONE,max(D1**(D1.log()/D2.log()),D2**2,tau*D3_over_tau,D4,tau)) + D = min(one, max(D1**(D1.log()/D2.log()),D2**2,tau*D3_over_tau,D4,tau)) if D <= tau: if cutoff_individually: @@ -3432,7 +3431,7 @@ def places_at_branch_locus(self): """ BP = [] K = self._R.base_ring() - if not K==QQ: + if K is not QQ: raise NotImplementedError C = self.curve() KC = C.function_field() @@ -3513,7 +3512,7 @@ def strong_approximation(self, divisor, S): i = S.index(p) Q = S[i] D = D_base+Q - if D==0: + if not D: ios = self.genus else: ios = len(D.basis_differential_space()) @@ -3536,7 +3535,7 @@ def strong_approximation(self, divisor, S): new_divisor += v*b.divisor() return new_divisor, B - def divisor_to_divisor_list(self, divisor): + def divisor_to_divisor_list(self, divisor, eps=None): r""" Turn a divisor into a list for :meth:`abel_jacobi`. @@ -3547,6 +3546,8 @@ def divisor_to_divisor_list(self, divisor): INPUT: - ``divisor`` -- an element of ``Curve(self.f).function_field().divisor_group()`` + - ``eps`` -- real number (optional); tolerance used to determine whether a complex + number is close enough to a root of a polynomial. OUTPUT: @@ -3571,7 +3572,8 @@ def divisor_to_divisor_list(self, divisor): """ # If this error bound is too restrictive, this method might fail and # not return. One might want to change the way this error is handled. - eps = self._RR(2)**(-self._prec+3) + if not eps: + eps = self._RR(2)**(-self._prec+3) dl = [] PZ = PolynomialRing(self._R.base(), 'z').fraction_field() @@ -3605,8 +3607,8 @@ def divisor_to_divisor_list(self, divisor): nys = [] else: nys = poly.roots() - ys += [ny[0] for ny in nys] - rys += [(v*m*n, (r, y)) for y, n in nys] + ys.extend(ny[0] for ny in nys) + rys.extend((v*m*n, (r, y)) for y, n in nys) if rys: dl.extend(rys) @@ -3615,8 +3617,7 @@ def divisor_to_divisor_list(self, divisor): ys = self._CCw(self.f(r, self._CCw.gen(0))).roots() dl.extend([(v*m*n, (r, y)) for y, n in ys]) if not sum([v[0] for v in dl])==divisor.degree(): - print(dl) - raise ValueError("Numerical instability, list of wrong degree") + raise ValueError("numerical instability, list of wrong degree, returning list {}".format(dl)) return dl From 60103619caa275cb7087e425d25afacdba48af9b Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 1 Sep 2022 13:59:09 +0200 Subject: [PATCH 427/742] remove ring argument from Stream_map_coefficient and Stream_function --- src/sage/data_structures/stream.py | 343 +++++++++++++---------------- src/sage/rings/lazy_series.py | 29 ++- src/sage/rings/lazy_series_ring.py | 12 +- 3 files changed, 173 insertions(+), 211 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index c10c0c73f80..fc5a99a7a60 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -21,10 +21,10 @@ example, we can add two streams:: sage: from sage.data_structures.stream import * - sage: f = Stream_function(lambda n: n, QQ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) sage: [f[i] for i in range(10)] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - sage: g = Stream_function(lambda n: 1, QQ, True, 0) + sage: g = Stream_function(lambda n: 1, True, 0) sage: [g[i] for i in range(10)] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] sage: h = Stream_add(f, g) @@ -52,7 +52,7 @@ Two streams can be composed:: - sage: g = Stream_function(lambda n: n, QQ, True, 1) + sage: g = Stream_function(lambda n: n, True, 1) sage: h = Stream_cauchy_compose(f, g) sage: [h[i] for i in range(10)] [0, 1, 4, 14, 46, 145, 444, 1331, 3926, 11434] @@ -71,7 +71,7 @@ Finally, we can apply an arbitrary functions to the elements of a stream:: - sage: h = Stream_map_coefficients(f, lambda n: n^2, QQ) + sage: h = Stream_map_coefficients(f, lambda n: n^2) sage: [h[i] for i in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] @@ -190,7 +190,7 @@ def __init__(self, is_sparse, approximate_order): sage: from sage.data_structures.stream import Stream_inexact sage: from sage.data_structures.stream import Stream_function - sage: g = Stream_function(lambda n: n, QQ, False, 0) + sage: g = Stream_function(lambda n: n, False, 0) sage: isinstance(g, Stream_inexact) True """ @@ -210,7 +210,7 @@ def is_nonzero(self): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function - sage: CS = Stream_function(lambda n: 1/n, ZZ, False, 1) + sage: CS = Stream_function(lambda n: 1/n, False, 1) sage: CS.is_nonzero() False sage: CS[1] @@ -303,7 +303,7 @@ def __getitem__(self, n): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: n^2, QQ, True, 0) + sage: f = Stream_function(lambda n: n^2, True, 0) sage: f[3] 9 sage: f._cache @@ -313,7 +313,7 @@ def __getitem__(self, n): sage: f._cache {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81} - sage: f = Stream_function(lambda n: n^2, QQ, False, 0) + sage: f = Stream_function(lambda n: n^2, False, 0) sage: f[3] 9 sage: f._cache @@ -351,14 +351,14 @@ def iterate_coefficients(self): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function, Stream_cauchy_compose - sage: f = Stream_function(lambda n: 1, ZZ, False, 1) - sage: g = Stream_function(lambda n: n^3, ZZ, False, 1) + sage: f = Stream_function(lambda n: 1, False, 1) + sage: g = Stream_function(lambda n: n^3, False, 1) sage: h = Stream_cauchy_compose(f, g) sage: n = h.iterate_coefficients() sage: [next(n) for i in range(10)] [1, 9, 44, 207, 991, 4752, 22769, 109089, 522676, 2504295] """ - n = self._approximate_order + n = self._approximate_order # TODO: shouldn't this be self._offset? while True: yield self.get_coefficient(n) n += 1 @@ -371,7 +371,7 @@ def order(self): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: n, QQ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) sage: f.order() 1 """ @@ -414,8 +414,8 @@ def __ne__(self, other): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: n, QQ, True, 0) - sage: g = Stream_function(lambda n: n^2, QQ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: f != g False sage: f[1], g[1] @@ -433,8 +433,8 @@ def __ne__(self, other): Checking the dense implementation:: - sage: f = Stream_function(lambda n: n if n > 0 else 0, QQ, False, -3) - sage: g = Stream_function(lambda n: n^2, QQ, False, 0) + sage: f = Stream_function(lambda n: n if n > 0 else 0, False, -3) + sage: g = Stream_function(lambda n: n^2, False, 0) sage: f != g False sage: g != f @@ -450,8 +450,8 @@ def __ne__(self, other): sage: g != f True - sage: f = Stream_function(lambda n: n if n > 0 else 0, QQ, False, -3) - sage: g = Stream_function(lambda n: n^2, QQ, False, 0) + sage: f = Stream_function(lambda n: n if n > 0 else 0, False, -3) + sage: g = Stream_function(lambda n: n^2, False, 0) sage: _ = f[5], g[1] sage: f != g False @@ -463,8 +463,8 @@ def __ne__(self, other): sage: g != f True - sage: f = Stream_function(lambda n: n if n > 0 else 0, QQ, False, -3) - sage: g = Stream_function(lambda n: n^2, QQ, False, 0) + sage: f = Stream_function(lambda n: n if n > 0 else 0, False, -3) + sage: g = Stream_function(lambda n: n^2, False, 0) sage: _ = g[5], f[1] sage: f != g False @@ -700,7 +700,7 @@ def __ne__(self, other): return ``False``:: sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: 2 if n == 0 else 1, ZZ, False, 0) + sage: f = Stream_function(lambda n: 2 if n == 0 else 1, False, 0) sage: s == f False sage: s != f @@ -757,7 +757,6 @@ class Stream_function(Stream_inexact): - ``function`` -- a function that generates the coefficients of the stream - - ``ring`` -- the base ring - ``is_sparse`` -- boolean; specifies whether the stream is sparse - ``approximate_order`` -- integer; a lower bound for the order of the stream @@ -765,62 +764,34 @@ class Stream_function(Stream_inexact): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: n^2, ZZ, False, 1) + sage: f = Stream_function(lambda n: n^2, False, 1) sage: f[3] 9 sage: [f[i] for i in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] - """ - def __init__(self, function, ring, is_sparse, approximate_order): + sage: f = Stream_function(lambda n: 1, False, 0) + sage: n = f.iterate_coefficients() + sage: [next(n) for _ in range(10)] + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + + sage: f = Stream_function(lambda n: n, True, 0) + sage: f.get_coefficient(4) + 4 + """ + def __init__(self, function, is_sparse, approximate_order): """ Initialize. TESTS:: sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: 1, ZZ, False, 1) + sage: f = Stream_function(lambda n: 1, False, 1) sage: TestSuite(f).run(skip="_test_pickling") """ - self._function = function - self._ring = ring + self.get_coefficient = function super().__init__(is_sparse, approximate_order) - def get_coefficient(self, n): - """ - Return the ``n``-th coefficient of ``self``. - - INPUT: - - - ``n`` -- integer; the degree for the coefficient - - EXAMPLES:: - - sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: n, QQ, True, 0) - sage: f.get_coefficient(4) - 4 - """ - return self._ring(self._function(n)) - - def iterate_coefficients(self): - """ - A generator for the coefficients of ``self``. - - EXAMPLES:: - - sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: 1, QQ, False, 0) - sage: n = f.iterate_coefficients() - sage: [next(n) for _ in range(10)] - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - """ - n = self._offset - ring = self._ring - while True: - yield ring(self._function(n)) - n += 1 - class Stream_uninitialized(Stream_inexact): r""" @@ -911,7 +882,7 @@ class Stream_unary(Stream_inexact): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_cauchy_invert, Stream_lmul) - sage: f = Stream_function(lambda n: 2*n, ZZ, False, 1) + sage: f = Stream_function(lambda n: 2*n, False, 1) sage: g = Stream_cauchy_invert(f) sage: [g[i] for i in range(10)] [-1, 1/2, 0, 0, 0, 0, 0, 0, 0, 0] @@ -945,7 +916,7 @@ def __hash__(self): sage: from sage.data_structures.stream import Stream_unary sage: from sage.data_structures.stream import Stream_function - sage: M = Stream_unary(Stream_function(lambda n: 1, ZZ, False, 1), True, 0) + sage: M = Stream_unary(Stream_function(lambda n: 1, False, 1), True, 0) sage: hash(M) == hash(M) True """ @@ -962,8 +933,8 @@ def __eq__(self, other): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_rmul) - sage: f = Stream_function(lambda n: 2*n, ZZ, False, 1) - sage: g = Stream_function(lambda n: n, ZZ, False, 1) + sage: f = Stream_function(lambda n: 2*n, False, 1) + sage: g = Stream_function(lambda n: n, False, 1) sage: h = Stream_rmul(f, 2) sage: n = Stream_rmul(g, 2) sage: h == n @@ -988,8 +959,8 @@ class Stream_binary(Stream_inexact): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_add, Stream_sub) - sage: f = Stream_function(lambda n: 2*n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: 2*n, True, 0) + sage: g = Stream_function(lambda n: n, True, 1) sage: h = Stream_add(f, g) sage: [h[i] for i in range(10)] [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] @@ -1027,8 +998,8 @@ def __hash__(self): sage: from sage.data_structures.stream import Stream_binary sage: from sage.data_structures.stream import Stream_function - sage: M = Stream_function(lambda n: n, ZZ, True, 0) - sage: N = Stream_function(lambda n: -2*n, ZZ, True, 0) + sage: M = Stream_function(lambda n: n, True, 0) + sage: N = Stream_function(lambda n: -2*n, True, 0) sage: O = Stream_binary(M, N, True, 0) sage: hash(O) == hash(O) True @@ -1046,9 +1017,9 @@ def __eq__(self, other): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_cauchy_mul) - sage: f = Stream_function(lambda n: 2*n, ZZ, False, 1) - sage: g = Stream_function(lambda n: n, ZZ, False, 1) - sage: h = Stream_function(lambda n: 1, ZZ, False, 1) + sage: f = Stream_function(lambda n: 2*n, False, 1) + sage: g = Stream_function(lambda n: n, False, 1) + sage: h = Stream_function(lambda n: 1, False, 1) sage: t = Stream_cauchy_mul(f, g) sage: u = Stream_cauchy_mul(g, h) sage: v = Stream_cauchy_mul(h, f) @@ -1071,8 +1042,8 @@ class Stream_binaryCommutative(Stream_binary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_add) - sage: f = Stream_function(lambda n: 2*n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: 2*n, True, 0) + sage: g = Stream_function(lambda n: n, True, 1) sage: h = Stream_add(f, g) sage: [h[i] for i in range(10)] [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] @@ -1089,8 +1060,8 @@ def __hash__(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_add) - sage: f = Stream_function(lambda n: 2*n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: 2*n, True, 0) + sage: g = Stream_function(lambda n: n, True, 1) sage: h = Stream_add(f, g) sage: u = Stream_add(g, f) sage: hash(h) == hash(u) @@ -1109,8 +1080,8 @@ def __eq__(self, other): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_add) - sage: f = Stream_function(lambda n: 2*n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: 2*n, True, 0) + sage: g = Stream_function(lambda n: n, True, 1) sage: h = Stream_add(f, g) sage: [h[i] for i in range(10)] [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] @@ -1235,8 +1206,8 @@ class Stream_add(Stream_binaryCommutative): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_add, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_function(lambda n: 1, ZZ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: 1, True, 0) sage: h = Stream_add(f, g) sage: [h[i] for i in range(10)] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] @@ -1251,8 +1222,8 @@ def __init__(self, left, right): TESTS:: sage: from sage.data_structures.stream import (Stream_function, Stream_add) - sage: f = Stream_function(lambda n: 1, ZZ, True, 0) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 0) + sage: f = Stream_function(lambda n: 1, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: h = Stream_add(f, g) """ if left._is_sparse != right._is_sparse: @@ -1272,8 +1243,8 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_add) - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: h = Stream_add(f, g) sage: h.get_coefficient(5) 30 @@ -1295,8 +1266,8 @@ class Stream_sub(Stream_binary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_sub, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_function(lambda n: 1, ZZ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: 1, True, 0) sage: h = Stream_sub(f, g) sage: [h[i] for i in range(10)] [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8] @@ -1312,8 +1283,8 @@ def __init__(self, left, right): TESTS:: sage: from sage.data_structures.stream import (Stream_function, Stream_sub) - sage: f = Stream_function(lambda n: 1, ZZ, True, 0) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 0) + sage: f = Stream_function(lambda n: 1, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: h = Stream_sub(f, g) """ if left._is_sparse != right._is_sparse: @@ -1333,8 +1304,8 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_sub) - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: h = Stream_sub(f, g) sage: h.get_coefficient(5) -20 @@ -1360,8 +1331,8 @@ class Stream_cauchy_mul(Stream_binary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_cauchy_mul, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_function(lambda n: 1, ZZ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: 1, True, 0) sage: h = Stream_cauchy_mul(f, g) sage: [h[i] for i in range(10)] [0, 1, 3, 6, 10, 15, 21, 28, 36, 45] @@ -1376,8 +1347,8 @@ def __init__(self, left, right): TESTS:: sage: from sage.data_structures.stream import (Stream_function, Stream_cauchy_mul) - sage: f = Stream_function(lambda n: 1, ZZ, True, 0) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 0) + sage: f = Stream_function(lambda n: 1, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: h = Stream_cauchy_mul(f, g) """ if left._is_sparse != right._is_sparse: @@ -1397,8 +1368,8 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_cauchy_mul) - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: h = Stream_cauchy_mul(f, g) sage: h.get_coefficient(5) 50 @@ -1422,7 +1393,7 @@ def is_nonzero(self): sage: from sage.data_structures.stream import (Stream_function, ....: Stream_cauchy_mul, Stream_cauchy_invert) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_cauchy_mul(f, f) sage: g.is_nonzero() False @@ -1449,7 +1420,7 @@ class Stream_dirichlet_convolve(Stream_binary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_dirichlet_convolve, Stream_function, Stream_exact) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_exact([0], True, constant=1) sage: h = Stream_dirichlet_convolve(f, g) sage: [h[i] for i in range(1, 10)] @@ -1466,7 +1437,7 @@ def __init__(self, left, right): Initialize ``self``. sage: from sage.data_structures.stream import (Stream_dirichlet_convolve, Stream_function, Stream_exact) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_exact([1], True, constant=0) sage: Stream_dirichlet_convolve(f, g) Traceback (most recent call last): @@ -1498,7 +1469,7 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_dirichlet_convolve, Stream_function, Stream_exact) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_exact([0], True, constant=1) sage: h = Stream_dirichlet_convolve(f, g) sage: h.get_coefficient(7) @@ -1527,7 +1498,7 @@ class Stream_dirichlet_invert(Stream_unary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_dirichlet_invert, Stream_function) - sage: f = Stream_function(lambda n: 1, ZZ, True, 1) + sage: f = Stream_function(lambda n: 1, True, 1) sage: g = Stream_dirichlet_invert(f) sage: [g[i] for i in range(10)] [0, 1, -1, -1, 0, -1, 1, -1, 0, 0] @@ -1596,8 +1567,8 @@ class Stream_cauchy_compose(Stream_binary): EXAMPLES:: sage: from sage.data_structures.stream import Stream_cauchy_compose, Stream_function - sage: f = Stream_function(lambda n: n, ZZ, True, 1) - sage: g = Stream_function(lambda n: 1, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) + sage: g = Stream_function(lambda n: 1, True, 1) sage: h = Stream_cauchy_compose(f, g) sage: [h[i] for i in range(10)] [0, 1, 3, 8, 20, 48, 112, 256, 576, 1280] @@ -1612,8 +1583,8 @@ def __init__(self, f, g): TESTS:: sage: from sage.data_structures.stream import Stream_function, Stream_cauchy_compose - sage: f = Stream_function(lambda n: 1, ZZ, True, 1) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 1) + sage: f = Stream_function(lambda n: 1, True, 1) + sage: g = Stream_function(lambda n: n^2, True, 1) sage: h = Stream_cauchy_compose(f, g) """ #assert g._approximate_order > 0 @@ -1640,8 +1611,8 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function, Stream_cauchy_compose - sage: f = Stream_function(lambda n: n, ZZ, True, 1) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) + sage: g = Stream_function(lambda n: n^2, True, 1) sage: h = Stream_cauchy_compose(f, g) sage: h.get_coefficient(5) 527 @@ -1667,14 +1638,14 @@ class Stream_plethysm(Stream_binary): Return the plethysm of ``f`` composed by ``g``. This is the plethysm `f \circ g = f(g)` when `g` is an element of - the ring of symmetric functions. + a ring of symmetric functions. INPUT: - ``f`` -- a :class:`Stream` - ``g`` -- a :class:`Stream` with positive order, unless ``f`` is of :class:`Stream_exact`. - - ``p`` -- the powersum symmetric functions + - ``p`` -- the ring of powersum symmetric functions containing ``g`` - ``ring`` (optional, default ``None``) -- the ring the result should be in, by default ``p`` - ``include`` -- a list of variables to be treated as degree one @@ -1687,8 +1658,8 @@ class Stream_plethysm(Stream_binary): sage: from sage.data_structures.stream import Stream_function, Stream_plethysm sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() - sage: f = Stream_function(lambda n: s[n], s, True, 1) - sage: g = Stream_function(lambda n: s[[1]*n], s, True, 1) + sage: f = Stream_function(lambda n: s[n], True, 1) + sage: g = Stream_function(lambda n: s[[1]*n], True, 1) sage: h = Stream_plethysm(f, g, p, s) sage: [h[i] for i in range(5)] [0, @@ -1709,7 +1680,7 @@ class Stream_plethysm(Stream_binary): sage: from sage.data_structures.stream import Stream_exact sage: f = Stream_exact([s[1]], True, order=1) - sage: g = Stream_function(lambda n: s[n], s, True, 0) + sage: g = Stream_function(lambda n: s[n], True, 0) sage: r = Stream_plethysm(f, g, p, s) sage: [r[n] for n in range(3)] [s[], s[1], s[2]] @@ -1758,8 +1729,8 @@ def __init__(self, f, g, p, ring=None, include=None, exclude=None): sage: from sage.data_structures.stream import Stream_function, Stream_plethysm sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() - sage: f = Stream_function(lambda n: s[n], s, True, 1) - sage: g = Stream_function(lambda n: s[n-1,1], s, True, 2) + sage: f = Stream_function(lambda n: s[n], True, 1) + sage: g = Stream_function(lambda n: s[n-1,1], True, 2) sage: h = Stream_plethysm(f, g, p) """ # assert g._approximate_order > 0 @@ -1769,21 +1740,22 @@ def __init__(self, f, g, p, ring=None, include=None, exclude=None): else: self._basis = ring self._p = p - p_g = Stream_map_coefficients(g, lambda x: x, p) - self._powers = [p_g] # a cache for the powers of p_g + g = Stream_map_coefficients(g, lambda x: p(x)) + self._powers = [g] # a cache for the powers of g R = self._basis.base_ring() - if HopfAlgebrasWithBasis(R).TensorProducts() in p.categories(): - self._tensor_power = len(p._sets) - p_f = Stream_map_coefficients(f, lambda x: x, p._sets[0]) - else: - self._tensor_power = None - p_f = Stream_map_coefficients(f, lambda x: x, p) + self._degree_one = _variables_recursive(R, include=include, exclude=exclude) if isinstance(f, Stream_exact) and not f._constant: self._degree_f = f._degree else: self._degree_f = None - self._degree_one = _variables_recursive(R, include=include, exclude=exclude) - super().__init__(p_f, p_g, f._is_sparse, val) + if HopfAlgebrasWithBasis(R).TensorProducts() in p.categories(): + self._tensor_power = len(p._sets) + p_f = p._sets[0] + f = Stream_map_coefficients(f, lambda x: p_f(x)) + else: + self._tensor_power = None + f = Stream_map_coefficients(f, lambda x: p(x)) + super().__init__(f, g, f._is_sparse, val) def get_coefficient(self, n): r""" @@ -1798,8 +1770,8 @@ def get_coefficient(self, n): sage: from sage.data_structures.stream import Stream_function, Stream_plethysm sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() - sage: f = Stream_function(lambda n: s[n], s, True, 1) - sage: g = Stream_function(lambda n: s[[1]*n], s, True, 1) + sage: f = Stream_function(lambda n: s[n], True, 1) + sage: g = Stream_function(lambda n: s[[1]*n], True, 1) sage: h = Stream_plethysm(f, g, p) sage: s(h.get_coefficient(5)) 4*s[1, 1, 1, 1, 1] + 4*s[2, 1, 1, 1] + 2*s[2, 2, 1] + 2*s[3, 1, 1] + s[3, 2] + s[4, 1] + s[5] @@ -1817,13 +1789,16 @@ def get_coefficient(self, n): return sum((c * self.compute_product(n, la) for k in range(self._left._approximate_order, self._degree_f) + if self._left[k] for la, c in self._left[k]), self._basis.zero()) - return sum((c * self.compute_product(n, la) - for k in range(self._left._approximate_order, n+1) - for la, c in self._left[k]), - self._basis.zero()) + res = sum((c * self.compute_product(n, la) + for k in range(self._left._approximate_order, n+1) + if self._left[k] + for la, c in self._left[k]), + self._basis.zero()) + return res def compute_product(self, n, la): r""" @@ -1845,7 +1820,7 @@ def compute_product(self, n, la): sage: p2 = tensor([p, p]) sage: f = Stream_zero(True) # irrelevant for this test - sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), p2, True, 1) + sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), True, 1) sage: h = Stream_plethysm(f, g, p2) sage: A = h.compute_product(7, Partition([2, 1])) sage: B = p[2, 1](sum(g[n] for n in range(7))) @@ -1854,7 +1829,7 @@ def compute_product(self, n, la): True sage: f = Stream_zero(True) # irrelevant for this test - sage: g = Stream_function(lambda n: s[n], p, True, 0) + sage: g = Stream_function(lambda n: s[n], True, 0) sage: h = Stream_plethysm(f, g, p) sage: B = p[2, 2, 1](sum(s[i] for i in range(7))) sage: all(h.compute_product(k, Partition([2, 2, 1])) == B.restrict_degree(k) for k in range(7)) @@ -1903,7 +1878,7 @@ def stretched_power_restrict_degree(self, i, m, d): sage: p2 = tensor([p, p]) sage: f = Stream_zero(True) # irrelevant for this test - sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), p2, True, 1) + sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), True, 1) sage: h = Stream_plethysm(f, g, p2) sage: A = h.stretched_power_restrict_degree(2, 3, 6) sage: B = p[2,2,2](sum(g[n] for n in range(7))) @@ -1943,7 +1918,7 @@ def __init__(self, series, scalar): TESTS:: sage: from sage.data_structures.stream import (Stream_rmul, Stream_function) - sage: f = Stream_function(lambda n: -1, ZZ, True, 0) + sage: f = Stream_function(lambda n: -1, True, 0) sage: g = Stream_rmul(f, 3) """ self._series = series @@ -1959,7 +1934,7 @@ def __hash__(self): sage: from sage.data_structures.stream import Stream_function sage: from sage.data_structures.stream import Stream_rmul - sage: a = Stream_function(lambda n: 2*n, ZZ, False, 1) + sage: a = Stream_function(lambda n: 2*n, False, 1) sage: f = Stream_rmul(a, 2) sage: hash(f) == hash(f) True @@ -1978,8 +1953,8 @@ def __eq__(self, other): sage: from sage.data_structures.stream import Stream_function sage: from sage.data_structures.stream import Stream_rmul, Stream_lmul - sage: a = Stream_function(lambda n: 2*n, ZZ, False, 1) - sage: b = Stream_function(lambda n: n, ZZ, False, 1) + sage: a = Stream_function(lambda n: 2*n, False, 1) + sage: b = Stream_function(lambda n: n, False, 1) sage: f = Stream_rmul(a, 2) sage: f == Stream_rmul(b, 2) False @@ -2001,7 +1976,7 @@ def is_nonzero(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_rmul, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_rmul(f, 2) sage: g.is_nonzero() False @@ -2030,7 +2005,7 @@ class Stream_rmul(Stream_scalar): sage: from sage.data_structures.stream import (Stream_rmul, Stream_function) sage: W = algebras.DifferentialWeyl(QQ, names=('x',)) sage: x, dx = W.gens() - sage: f = Stream_function(lambda n: x^n, W, True, 1) + sage: f = Stream_function(lambda n: x^n, True, 1) sage: g = Stream_rmul(f, dx) sage: [g[i] for i in range(5)] [0, x*dx + 1, x^2*dx + 2*x, x^3*dx + 3*x^2, x^4*dx + 4*x^3] @@ -2046,7 +2021,7 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_rmul, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_rmul(f, 3) sage: g.get_coefficient(5) 15 @@ -2071,7 +2046,7 @@ class Stream_lmul(Stream_scalar): sage: from sage.data_structures.stream import (Stream_lmul, Stream_function) sage: W = algebras.DifferentialWeyl(QQ, names=('x',)) sage: x, dx = W.gens() - sage: f = Stream_function(lambda n: x^n, W, True, 1) + sage: f = Stream_function(lambda n: x^n, True, 1) sage: g = Stream_lmul(f, dx) sage: [g[i] for i in range(5)] [0, x*dx, x^2*dx, x^3*dx, x^4*dx] @@ -2087,7 +2062,7 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_lmul, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_lmul(f, 3) sage: g.get_coefficient(5) 15 @@ -2108,7 +2083,7 @@ class Stream_neg(Stream_unary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_neg, Stream_function) - sage: f = Stream_function(lambda n: 1, ZZ, True, 1) + sage: f = Stream_function(lambda n: 1, True, 1) sage: g = Stream_neg(f) sage: [g[i] for i in range(10)] [0, -1, -1, -1, -1, -1, -1, -1, -1, -1] @@ -2120,7 +2095,7 @@ def __init__(self, series): TESTS:: sage: from sage.data_structures.stream import (Stream_neg, Stream_function) - sage: f = Stream_function(lambda n: -1, ZZ, True, 0) + sage: f = Stream_function(lambda n: -1, True, 0) sage: g = Stream_neg(f) """ super().__init__(series, series._is_sparse, series._approximate_order) @@ -2136,7 +2111,7 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_neg, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_neg(f) sage: g.get_coefficient(5) -5 @@ -2153,7 +2128,7 @@ def is_nonzero(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_neg, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_neg(f) sage: g.is_nonzero() False @@ -2178,7 +2153,7 @@ class Stream_cauchy_invert(Stream_unary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_cauchy_invert, Stream_function) - sage: f = Stream_function(lambda n: 1, ZZ, True, 1) + sage: f = Stream_function(lambda n: 1, True, 1) sage: g = Stream_cauchy_invert(f) sage: [g[i] for i in range(10)] [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0] @@ -2210,7 +2185,7 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_cauchy_invert, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_cauchy_invert(f) sage: g.get_coefficient(5) 0 @@ -2234,7 +2209,7 @@ def iterate_coefficients(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_cauchy_invert, Stream_function) - sage: f = Stream_function(lambda n: n^2, ZZ, False, 1) + sage: f = Stream_function(lambda n: n^2, False, 1) sage: g = Stream_cauchy_invert(f) sage: n = g.iterate_coefficients() sage: [next(n) for i in range(10)] @@ -2269,7 +2244,7 @@ def is_nonzero(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_cauchy_invert, Stream_function) - sage: f = Stream_function(lambda n: n^2, ZZ, False, 1) + sage: f = Stream_function(lambda n: n^2, False, 1) sage: g = Stream_cauchy_invert(f) sage: g.is_nonzero() True @@ -2279,36 +2254,35 @@ def is_nonzero(self): class Stream_map_coefficients(Stream_inexact): r""" - The stream with ``function`` applied to each nonzero - coefficient of ``series``. + The stream with ``function`` applied to each nonzero coefficient + of ``series``. INPUT: - ``series`` -- a :class:`Stream` - ``function`` -- a function that modifies the elements of the stream - - ``ring`` -- the base ring of the stream EXAMPLES:: sage: from sage.data_structures.stream import (Stream_map_coefficients, Stream_function) - sage: f = Stream_function(lambda n: 1, ZZ, True, 1) - sage: g = Stream_map_coefficients(f, lambda n: -n, ZZ) + sage: f = Stream_function(lambda n: 1, True, 1) + sage: g = Stream_map_coefficients(f, lambda n: -n) sage: [g[i] for i in range(10)] [0, -1, -1, -1, -1, -1, -1, -1, -1, -1] + """ - def __init__(self, series, function, ring): + def __init__(self, series, function): """ Initialize ``self``. TESTS:: sage: from sage.data_structures.stream import (Stream_map_coefficients, Stream_function) - sage: f = Stream_function(lambda n: -1, ZZ, True, 0) - sage: g = Stream_map_coefficients(f, lambda n: n + 1, ZZ) + sage: f = Stream_function(lambda n: -1, True, 0) + sage: g = Stream_map_coefficients(f, lambda n: n + 1) sage: TestSuite(g).run(skip="_test_pickling") """ self._function = function - self._ring = ring self._series = series super().__init__(series._is_sparse, series._approximate_order) @@ -2323,25 +2297,20 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_map_coefficients, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, -1) - sage: g = Stream_map_coefficients(f, lambda n: n^2 + 1, ZZ) + sage: f = Stream_function(lambda n: n, True, -1) + sage: g = Stream_map_coefficients(f, lambda n: n^2 + 1) sage: g.get_coefficient(5) 26 sage: [g.get_coefficient(i) for i in range(-1, 10)] [2, 0, 2, 5, 10, 17, 26, 37, 50, 65, 82] sage: R. = ZZ[] - sage: f = Stream_function(lambda n: n, ZZ, True, -1) - sage: g = Stream_map_coefficients(f, lambda n: n.degree() + 1, R) + sage: f = Stream_function(lambda n: n, True, -1) + sage: g = Stream_map_coefficients(f, lambda n: R(n).degree() + 1) sage: [g.get_coefficient(i) for i in range(-1, 3)] [1, 0, 1, 1] - - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_map_coefficients(f, lambda n: 5, GF(3)) - sage: [g.get_coefficient(i) for i in range(10)] - [0, 5, 5, 0, 5, 5, 0, 5, 5, 0] """ - c = self._ring(self._series[n]) + c = self._series[n] if c: return self._function(c) return c @@ -2353,13 +2322,13 @@ def __hash__(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_map_coefficients, Stream_function) - sage: f = Stream_function(lambda n: -1, ZZ, True, 0) - sage: g = Stream_map_coefficients(f, lambda n: n + 1, ZZ) + sage: f = Stream_function(lambda n: -1, True, 0) + sage: g = Stream_map_coefficients(f, lambda n: n + 1) sage: hash(g) == hash(g) True """ # We don't hash the function as it might not be hashable. - return hash((type(self), self._series, self._ring)) + return hash((type(self), self._series)) def __eq__(self, other): """ @@ -2372,18 +2341,16 @@ def __eq__(self, other): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_map_coefficients, Stream_function) - sage: f = Stream_function(lambda n: -1, ZZ, True, 0) + sage: f = Stream_function(lambda n: -1, True, 0) sage: def plus_one(n): return n + 1 - sage: g = Stream_map_coefficients(f, plus_one, ZZ) + sage: g = Stream_map_coefficients(f, plus_one) sage: g == f False - sage: g == Stream_map_coefficients(f, plus_one, QQ) + sage: g == Stream_map_coefficients(f, lambda n: n + 1) False - sage: g == Stream_map_coefficients(f, plus_one, ZZ) - True """ return (isinstance(other, type(self)) and self._series == other._series - and self._ring == other._ring and self._function == other._function) + and self._function == other._function) class Stream_shift(Stream_inexact): @@ -2419,7 +2386,7 @@ def __getitem__(self, n): sage: from sage.data_structures.stream import Stream_shift sage: from sage.data_structures.stream import Stream_function - sage: F = Stream_function(lambda n: n, ZZ, False, 1) + sage: F = Stream_function(lambda n: n, False, 1) sage: M = Stream_shift(F, 2) sage: [F[i] for i in range(6)] [0, 1, 2, 3, 4, 5] @@ -2436,7 +2403,7 @@ def __hash__(self): sage: from sage.data_structures.stream import Stream_shift sage: from sage.data_structures.stream import Stream_function - sage: F = Stream_function(lambda n: n, ZZ, False, 1) + sage: F = Stream_function(lambda n: n, False, 1) sage: M = Stream_shift(F, 2) sage: hash(M) == hash(M) True @@ -2455,7 +2422,7 @@ def __eq__(self, other): sage: from sage.data_structures.stream import Stream_shift sage: from sage.data_structures.stream import Stream_function - sage: F = Stream_function(lambda n: 1, ZZ, False, 1) + sage: F = Stream_function(lambda n: 1, False, 1) sage: M2 = Stream_shift(F, 2) sage: M3 = Stream_shift(F, 3) sage: M2 == M3 @@ -2476,7 +2443,7 @@ def is_nonzero(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_cauchy_invert, Stream_function) - sage: f = Stream_function(lambda n: n^2, ZZ, False, 1) + sage: f = Stream_function(lambda n: n^2, False, 1) sage: g = Stream_cauchy_invert(f) sage: g.is_nonzero() True @@ -2518,14 +2485,14 @@ def __getitem__(self, n): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function, Stream_derivative - sage: f = Stream_function(lambda n: 1/n if n else 0, QQ, True, -2) + sage: f = Stream_function(lambda n: 1/n if n else 0, True, -2) sage: [f[i] for i in range(-5, 3)] [0, 0, 0, -1/2, -1, 0, 1, 1/2] sage: f2 = Stream_derivative(f, 2) sage: [f2[i] for i in range(-5, 3)] [0, -3, -2, 0, 0, 1, 2, 3] - sage: f = Stream_function(lambda n: 1/n, QQ, True, 2) + sage: f = Stream_function(lambda n: 1/n, True, 2) sage: [f[i] for i in range(-1, 4)] [0, 0, 0, 1/2, 1/3] sage: f2 = Stream_derivative(f, 3) @@ -2543,7 +2510,7 @@ def __hash__(self): sage: from sage.data_structures.stream import Stream_function sage: from sage.data_structures.stream import Stream_derivative - sage: a = Stream_function(lambda n: 2*n, ZZ, False, 1) + sage: a = Stream_function(lambda n: 2*n, False, 1) sage: f = Stream_derivative(a, 1) sage: g = Stream_derivative(a, 2) sage: hash(f) == hash(f) @@ -2566,7 +2533,7 @@ def __eq__(self, other): sage: from sage.data_structures.stream import Stream_function sage: from sage.data_structures.stream import Stream_derivative - sage: a = Stream_function(lambda n: 2*n, ZZ, False, 1) + sage: a = Stream_function(lambda n: 2*n, False, 1) sage: f = Stream_derivative(a, 1) sage: g = Stream_derivative(a, 2) sage: f == g diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index b88a6ab82d2..a029fa656da 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -303,7 +303,7 @@ def __getitem__(self, n): coefficient = __getitem__ - def map_coefficients(self, func, ring=None): + def map_coefficients(self, func): r""" Return the series with ``func`` applied to each nonzero coefficient of ``self``. @@ -378,8 +378,7 @@ def map_coefficients(self, func, ring=None): degree=coeff_stream._degree, constant=BR(c)) return P.element_class(P, coeff_stream) - R = P._internal_poly_ring.base_ring() - coeff_stream = Stream_map_coefficients(self._coeff_stream, func, R) + coeff_stream = Stream_map_coefficients(self._coeff_stream, func) return P.element_class(P, coeff_stream) def truncate(self, d): @@ -3101,7 +3100,7 @@ def __call__(self, g, *, check=True): def coefficient(n): return sum(self[i] * (g**i)[n] for i in range(n+1)) R = P._internal_poly_ring.base_ring() - coeff_stream = Stream_function(coefficient, R, P._sparse, 1) + coeff_stream = Stream_function(coefficient, P._sparse, 1) return P.element_class(P, coeff_stream) coeff_stream = Stream_cauchy_compose(self._coeff_stream, g._coeff_stream) @@ -3380,8 +3379,7 @@ def derivative(self, *args): coeff_stream = Stream_derivative(self._coeff_stream, order) if vars: coeff_stream = Stream_map_coefficients(coeff_stream, - lambda c: c.derivative(vars), - R) + lambda c: c.derivative(vars)) return P.element_class(P, coeff_stream) def approximate_series(self, prec, name=None): @@ -3832,7 +3830,7 @@ def __call__(self, *g, check=True): # we assume that the valuation of self[i](g) is at least i def coefficient(n): return sum(self[i] * (g0**i)[n] for i in range(n+1)) - coeff_stream = Stream_function(coefficient, R, P._sparse, 1) + coeff_stream = Stream_function(coefficient, P._sparse, 1) return P.element_class(P, coeff_stream) coeff_stream = Stream_cauchy_compose(self._coeff_stream, g0._coeff_stream) @@ -3847,7 +3845,7 @@ def coefficient(n): # Make sure the element returned from the composition is in P r += P(self[i](g))[n] return r - coeff_stream = Stream_function(coefficient, R, P._sparse, sorder * gv) + coeff_stream = Stream_function(coefficient, P._sparse, sorder * gv) return P.element_class(P, coeff_stream) compose = __call__ @@ -4050,10 +4048,11 @@ def derivative(self, *args): return self if P._arity > 1: + v = gen_vars + vars + d = -len(gen_vars) coeff_stream = Stream_shift(Stream_map_coefficients(coeff_stream, - lambda c: c.derivative(gen_vars + vars), - P._laurent_poly_ring), - -len(gen_vars)) + lambda c: R(c).derivative(v)), + d) return P.element_class(P, coeff_stream) if (isinstance(coeff_stream, Stream_exact) @@ -4077,8 +4076,7 @@ def derivative(self, *args): coeff_stream = Stream_derivative(self._coeff_stream, order) if vars: coeff_stream = Stream_map_coefficients(coeff_stream, - lambda c: c.derivative(vars), - R) + lambda c: c.derivative(vars)) return P.element_class(P, coeff_stream) def _format_series(self, formatter, format_strings=False): @@ -4666,8 +4664,7 @@ def derivative_with_respect_to_p1(self, n=1): raise ValueError("arity must be equal to 1") coeff_stream = Stream_shift(Stream_map_coefficients(self._coeff_stream, - lambda c: c.derivative_with_respect_to_p1(n), - P._laurent_poly_ring), + lambda c: c.derivative_with_respect_to_p1(n)), -n) return P.element_class(P, coeff_stream) @@ -4982,7 +4979,7 @@ def coefficient(m): except ValueError: return ZZ.zero() R = P._internal_poly_ring.base_ring() - return P.element_class(P, Stream_function(coefficient, R, P._sparse, 1)) + return P.element_class(P, Stream_function(coefficient, P._sparse, 1)) def _format_series(self, formatter, format_strings=False): """ diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 9a12c626430..1bfdffef6d8 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -431,7 +431,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No if degree is None: if constant is not None: raise ValueError("constant may only be specified if the degree is specified") - coeff_stream = Stream_function(x, self.base_ring(), self._sparse, valuation) + coeff_stream = Stream_function(lambda i: BR(x(i)), self._sparse, valuation) return self.element_class(self, coeff_stream) # degree is not None @@ -1454,16 +1454,15 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No constant=constant, degree=degree) return self.element_class(self, coeff_stream) - coeff_ring = self._internal_poly_ring.base_ring() if check and len(self.variable_names()) > 1: def y(n): e = R(x(n)) if not e or e.is_homogeneous() and e.degree() == n: return e raise ValueError("coefficient %s at degree %s is not a homogeneous polynomial" % (e, n)) - coeff_stream = Stream_function(y, coeff_ring, self._sparse, valuation) + coeff_stream = Stream_function(y, self._sparse, valuation) else: - coeff_stream = Stream_function(x, coeff_ring, self._sparse, valuation) + coeff_stream = Stream_function(x, self._sparse, valuation) return self.element_class(self, coeff_stream) raise ValueError(f"unable to convert {x} into a lazy Taylor series") @@ -1784,16 +1783,15 @@ def check_homogeneous_of_degree(f, d): constant=0, degree=degree) return self.element_class(self, coeff_stream) - coeff_ring = self._internal_poly_ring.base_ring() if check: def y(n): e = R(x(n)) check_homogeneous_of_degree(e, n) return e - coeff_stream = Stream_function(y, coeff_ring, self._sparse, valuation) + coeff_stream = Stream_function(y, self._sparse, valuation) else: - coeff_stream = Stream_function(x, coeff_ring, self._sparse, valuation) + coeff_stream = Stream_function(x, self._sparse, valuation) return self.element_class(self, coeff_stream) raise ValueError(f"unable to convert {x} into a lazy completion element") From 760372aea66aa303303462adbe0bc7b4c16e1927 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 1 Sep 2022 14:23:44 +0200 Subject: [PATCH 428/742] address reviewer's comments --- src/sage/rings/lazy_series.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index fe97a42e889..2bacf7d2f27 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4729,7 +4729,6 @@ def functorial_composition(self, *args): labellings of their vertices with two 1's and two 2's. - The derivative of the symmetric function `\sum_n h_n`, times `p_1` is the neutral element with respect to functorial composition:: @@ -4787,16 +4786,16 @@ def g_cycle_type(s): m = moebius(d) if not m: continue - u = s.power(k/d) - g_u = g[u.size()] + u = s.power(k // d) + g_u = g[sum(u)] if g_u: e += m * u.aut() * g_u.coefficient(u) - res.extend([k] * ZZ(e/k)) + res.extend([k] * int(e // k)) res.reverse() return Partition(res) def coefficient(n): - res = p(0) + res = p.zero() for s in Partitions(n): t = g_cycle_type(s) f_t = f[t.size()] From 803f7e4437d853189d9c21ea73345fa672a9df5b Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Thu, 1 Sep 2022 15:14:33 +0200 Subject: [PATCH 429/742] Make FiniteRankFreeModule.tensor_module(0, 1) return the dual (#34474) --- .../tensor/modules/ext_pow_free_module.py | 74 +------------------ .../tensor/modules/finite_rank_free_module.py | 9 ++- src/sage/tensor/modules/tensor_free_module.py | 41 +--------- 3 files changed, 15 insertions(+), 109 deletions(-) diff --git a/src/sage/tensor/modules/ext_pow_free_module.py b/src/sage/tensor/modules/ext_pow_free_module.py index a5938417f0f..f1ce40c078a 100644 --- a/src/sage/tensor/modules/ext_pow_free_module.py +++ b/src/sage/tensor/modules/ext_pow_free_module.py @@ -573,21 +573,12 @@ class ExtPowerDualFreeModule(FiniteRankFreeModule_abstract): sage: latex(M.dual()) M^* - Since any tensor of type (0,1) is a linear form, there is a coercion map - from the set `T^{(0,1)}(M)` of such tensors to `M^*`:: + It also coincides with the module of type-`(0,1)` tensors:: - sage: T01 = M.tensor_module(0,1) ; T01 - Free module of type-(0,1) tensors on the Rank-3 free module M over the - Integer Ring - sage: M.dual().has_coerce_map_from(T01) - True - - There is also a coercion map in the reverse direction:: - - sage: T01.has_coerce_map_from(M.dual()) + sage: M.dual_exterior_power(1) is M.tensor_module(0,1) True - For a degree `p\geq 2`, the coercion holds only in the direction + For a degree `p\geq 2`, there is a coercion map `\Lambda^p(M^*)\rightarrow T^{(0,p)}(M)`:: sage: T02 = M.tensor_module(0,2) ; T02 @@ -598,24 +589,6 @@ class ExtPowerDualFreeModule(FiniteRankFreeModule_abstract): sage: A.has_coerce_map_from(T02) False - The coercion map `T^{(0,1)}(M) \rightarrow M^*` in action:: - - sage: b = T01([-2,1,4], basis=e, name='b') ; b - Type-(0,1) tensor b on the Rank-3 free module M over the Integer Ring - sage: b.display(e) - b = -2 e^0 + e^1 + 4 e^2 - sage: lb = M.dual()(b) ; lb - Linear form b on the Rank-3 free module M over the Integer Ring - sage: lb.display(e) - b = -2 e^0 + e^1 + 4 e^2 - - The coercion map `M^* \rightarrow T^{(0,1)}(M)` in action:: - - sage: tlb = T01(lb) ; tlb - Type-(0,1) tensor b on the Rank-3 free module M over the Integer Ring - sage: tlb == b - True - The coercion map `\Lambda^2(M^*)\rightarrow T^{(0,2)}(M)` in action:: sage: ta = T02(a) ; ta @@ -783,47 +756,6 @@ def _an_element_(self): resu.set_comp()[ind] = self._fmodule._ring.an_element() return resu - def _coerce_map_from_(self, other): - r""" - Determine whether coercion to ``self`` exists from other parent. - - EXAMPLES: - - Sets of type-`(0,1)` tensors coerce to ``self`` if the degree is 1:: - - sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: L1 = M.dual_exterior_power(1) ; L1 - Dual of the Rank-3 free module M over the Integer Ring - sage: T01 = M.tensor_module(0,1) ; T01 - Free module of type-(0,1) tensors on the Rank-3 free module M over - the Integer Ring - sage: L1._coerce_map_from_(T01) - True - - Of course, coercions from other tensor types are meaningless:: - - sage: L1._coerce_map_from_(M.tensor_module(1,0)) - False - sage: L1._coerce_map_from_(M.tensor_module(0,2)) - False - - If the degree is larger than 1, there is no coercion:: - - sage: L2 = M.dual_exterior_power(2) ; L2 - 2nd exterior power of the dual of the Rank-3 free module M over - the Integer Ring - sage: L2._coerce_map_from_(M.tensor_module(0,2)) - False - - """ - from sage.tensor.modules.tensor_free_module import TensorFreeModule - if isinstance(other, TensorFreeModule): - # coercion of a type-(0,1) tensor to a linear form - if self._fmodule is other._fmodule and self._degree == 1 and \ - other.tensor_type() == (0,1): - return True - return False - #### End of parent methods @cached_method diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index a49eda75404..407a01e82d1 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1195,11 +1195,16 @@ def tensor_module(self, k, l): sage: M.tensor_module(1,2) is T True - The base module is itself the module of all type-`(1,0)` tensors:: + The module of type-`(1,0)` tensors is the base module itself:: sage: M.tensor_module(1,0) is M True + while the module of type-`(0,1)` tensors is the dual of the base module:: + + sage: M.tensor_module(0, 1) is M.dual() + True + See :class:`~sage.tensor.modules.tensor_free_module.TensorFreeModule` for more documentation. @@ -1209,6 +1214,8 @@ def tensor_module(self, k, l): except KeyError: if (k, l) == (1, 0): T = self + elif (k, l) == (0, 1): + T = self.dual() else: from sage.tensor.modules.tensor_free_module import TensorFreeModule T = TensorFreeModule(self, (k,l)) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 0566d4de98d..a6b13d6c162 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -237,39 +237,11 @@ class TensorFreeModule(FiniteRankFreeModule_abstract): sage: ta.symmetries() # the antisymmetry is of course preserved no symmetry; antisymmetry: (0, 1) - For the degree `p=1`, there is a coercion in both directions:: + For the degree `p=1`, we have the identity `\Lambda^1(M^*) = T^{(0,1)}(M) = M^*`:: - sage: L1 = M.dual_exterior_power(1) ; L1 - Dual of the Rank-3 free module M over the Integer Ring - sage: T01 = M.tensor_module(0,1) ; T01 - Free module of type-(0,1) tensors on the Rank-3 free module M over the - Integer Ring - sage: T01.has_coerce_map_from(L1) - True - sage: L1.has_coerce_map_from(T01) + sage: M.dual_exterior_power(1) is M.tensor_module(0,1) True - - The coercion map `\Lambda^1(M^*)\rightarrow T^{(0,1)}(M)` in action:: - - sage: a = M.linear_form('a') - sage: a[:] = -2, 4, 1 ; a.display(e) - a = -2 e^0 + 4 e^1 + e^2 - sage: a.parent() is L1 - True - sage: ta = T01(a) ; ta - Type-(0,1) tensor a on the Rank-3 free module M over the Integer Ring - sage: ta.display(e) - a = -2 e^0 + 4 e^1 + e^2 - - The coercion map `T^{(0,1)}(M) \rightarrow \Lambda^1(M^*)` in action:: - - sage: ta.parent() is T01 - True - sage: lta = L1(ta) ; lta - Linear form a on the Rank-3 free module M over the Integer Ring - sage: lta.display(e) - a = -2 e^0 + 4 e^1 + e^2 - sage: lta == a + sage: M.tensor_module(0,1) is M.dual() True There is a canonical identification between tensors of type `(1,1)` and @@ -571,7 +543,7 @@ def _coerce_map_from_(self, other): but not to tensor modules of other types:: - sage: M.tensor_module(0,1)._coerce_map_from_(End(M)) + sage: M.tensor_module(0,2)._coerce_map_from_(End(M)) False and not to type-`(1,1)` tensor modules defined on another free module:: @@ -597,8 +569,6 @@ def _coerce_map_from_(self, other): Coercion from alternating forms:: - sage: M.tensor_module(0,1)._coerce_map_from_(M.dual_exterior_power(1)) - True sage: M.tensor_module(0,2)._coerce_map_from_(M.dual_exterior_power(2)) True sage: M.tensor_module(0,2)._coerce_map_from_(M.dual_exterior_power(3)) @@ -645,9 +615,6 @@ def _repr_(self): sage: M.tensor_module(1,1) Free module of type-(1,1) tensors on the 2-dimensional vector space M over the Rational Field - sage: M.tensor_module(0,1) - Free module of type-(0,1) tensors on the 2-dimensional vector space - M over the Rational Field """ description = "Free module of type-({},{}) tensors on the {}".format( From 3b215c0e7105fe9d3046409fa6462210cba6a008 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Thu, 1 Sep 2022 14:34:56 +0100 Subject: [PATCH 430/742] Added comments to integrate_differentials_iteratively Comments added to clarify the functionality, and explain how the flags cutoff_individually and riase_errors work. --- .../riemann_surfaces/riemann_surface.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 71d4d0f628b..d5c25ddb81d 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -2832,6 +2832,11 @@ def _integrate_differentials_iteratively(self, upstairs_edge, cutoff_individuall mp_list = [reparameterize_differential_minpoly(mp, z_start) for mp in mp_list] + # Depending on whether we have reparameterized about infinity or not, + # we initialise some values we will need in the calculation, inclduing + # the function `initalize', which at a given value of zbar, calculates + # the starting value for the i-th differential so it can be iterated + # from via homotopy continuation. if z_start==self._CC(Infinity): CCzg = PolynomialRing(self._CC, ['zbar','gbar']) mp_list = [CCzg(mp) for mp in mp_list] @@ -2865,6 +2870,9 @@ def initialise(z, i): newg = rs[sb] return newg + # As multiple calls of the minimal polynomial and it's derivative will + # be required for the homotopy continuaiton, we create fast-callable + # versions of these. fc_mp_list = [fast_callable(mp, domain=self._CC) for mp in mp_list] fc_dmp_list = [fast_callable(mp.derivative(CCzg.gen(1)), domain=self._CC) for mp in mp_list] @@ -2876,6 +2884,15 @@ def initialise(z, i): one = self._RR(1) la = self._RR.pi()/2 + # Cutoffs are used to allow us to not have to integrate as close into + # a singularity as we might otherwise have to, by knowing that we can + # truncate the integration interval and only introduce a finite error + # that can be bounded by knowledge of the asymptotics of the integrands, + # which we have from their minimal polynomials. This is really a + # precursor to what would be ideal to implement eventually, namely + # a method that uses Puiseux series to integrate into singularities. + # We allow for cutoffs to be tailored to each integrand, or we take a + # uniform value. if cutoff_individually is None: cutoffs = [0] cutoff_individually = False @@ -2896,6 +2913,14 @@ def initialise(z, i): aes.append(a) cutoff_individually = bool(not all(ai<=0 for ai in aes) and cutoff_individually) + # The `raise_errors' variable toggles what we do in the event that + # newton iteration hasn't converged to the desired precision in a + # fixed number of steps, here set to 100. + # If the default value of True is taken, then the failure to converge + # raises an error. If the value of False is taken, this failure to + # converge happens silently, thus allowing the user to get *an* + # answer out of the integration, but numerical imprecision is to be + # expected. if raise_errors: n_steps = self._prec-1 @@ -2912,6 +2937,11 @@ def error_handle(out): Nh = (-lambert_w(-1,-tau/2)/la).log().ceil() h0 = Nh*h + # Depending on how the cutoffs were defined, we now create the function + # which calculates the integrand we want to integrate via double- + # exponential methods. This will get the value at the next node by + # homotopy-continuing from the last node value. There is also a slight + # technical condition which implements the cutoffs. if cutoff_individually: z_fc_list = list(zip(fc_mp_list, fc_dmp_list)) @@ -2999,6 +3029,12 @@ def fv(hj, previous_estimate): D4 = D3_over_tau results = [] + # we now calculate the integral via double-exponential methods + # repeatedly halving the step size and then using a heuristic + # convergence check. We again use the error_handle function to deal + # with the case where we exceed the maximum number of steps allowed, + # currently set by to make sure the step size does not fall below the + # resolution set by the binary precision used. for k in range(n_steps): hj = h0 val = v0 From 319ecfaa335f8ba214ad59033fd91bf95579918f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:03:58 -0700 Subject: [PATCH 431/742] FiniteRankFreeModule.tensor: Use CompWithSym._canonicalize_sym_antisym --- .../tensor/modules/finite_rank_free_module.py | 27 +++++-------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 73b260a07c2..bb55959f4ed 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1609,7 +1609,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote the tensor; if none is provided, the LaTeX symbol is set to ``name`` - - ``sym`` -- (default: ``None``) a symmetry or a list of symmetries + - ``sym`` -- (default: ``None``) a symmetry or an iterable of symmetries among the tensor arguments: each symmetry is described by a tuple containing the positions of the involved arguments, with the convention ``position = 0`` for the first argument. For instance: @@ -1618,7 +1618,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, * ``sym = [(0,2), (1,3,4)]`` for a symmetry between the 1st and 3rd arguments and a symmetry between the 2nd, 4th and 5th arguments. - - ``antisym`` -- (default: ``None``) antisymmetry or list of + - ``antisym`` -- (default: ``None``) antisymmetry or iterable of antisymmetries among the arguments, with the same convention as for ``sym`` @@ -1653,33 +1653,20 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, for more examples and documentation. """ + from .comp import CompWithSym + sym, antisym = CompWithSym._canonicalize_sym_antisym( + tensor_type[0] + tensor_type[1], sym, antisym) # Special cases: if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) elif tensor_type == (0,1): return self.linear_form(name=name, latex_name=latex_name) elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a range - # object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - if isinstance(antisym, (tuple, list)): - antisym0 = antisym[0] - else: - antisym0 = antisym - if len(antisym0) == tensor_type[1]: + if len(antisym[0]) == tensor_type[1]: return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a range - # object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - if isinstance(antisym, (tuple, list)): - antisym0 = antisym[0] - else: - antisym0 = antisym - if len(antisym0) == tensor_type[0]: + if len(antisym[0]) == tensor_type[0]: return self.alternating_contravariant_tensor(tensor_type[0], name=name, latex_name=latex_name) # Generic case: From 8e93626a08496c71387cacd7bf9dae075803ebdc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:04:55 -0700 Subject: [PATCH 432/742] CompWithSym._canonicalize_sym_antisym: Add documentation --- src/sage/tensor/modules/comp.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 8e9cadbaa4a..9eea2bd1770 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -3000,10 +3000,28 @@ def __init__(self, ring, frame, nb_indices, start_index=0, nb_indices, sym, antisym) @staticmethod - def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): + def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, + trivial_symmetries='drop'): r""" Bring sym and antisym into their canonical form. + INPUT: + + - ``nb_indices`` -- number of integer indices labeling the components + + - ``sym`` -- (default: ``None``) a symmetry or an iterable of symmetries + among the tensor arguments: each symmetry is described by a tuple + containing the positions of the involved arguments, with the + convention ``position = 0`` for the first argument. For instance: + + * ``sym = (0,1)`` for a symmetry between the 1st and 2nd arguments + * ``sym = [(0,2), (1,3,4)]`` for a symmetry between the 1st and 3rd + arguments and a symmetry between the 2nd, 4th and 5th arguments. + + - ``antisym`` -- (default: ``None``) antisymmetry or iterable of + antisymmetries among the arguments, with the same convention + as for ``sym`` + EXAMPLES:: sage: from sage.tensor.modules.comp import CompWithSym From 564be353b347cecfd4496a169b5eaff0642de03d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:26:30 -0700 Subject: [PATCH 433/742] FiniteRankFreeModule.tensor: Restore error when trivial symmetries are passed --- src/sage/tensor/modules/comp.py | 24 ++++++++++++++----- .../tensor/modules/finite_rank_free_module.py | 3 ++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 9eea2bd1770..d9a676711e1 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -3022,6 +3022,10 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, antisymmetries among the arguments, with the same convention as for ``sym`` + - ``trivial_symmetries`` -- (default: ``"drop"``) if ``"error"``, raise + an :class:`IndexError` if any trivial symmetries are provided; + otherwise, silently drop them + EXAMPLES:: sage: from sage.tensor.modules.comp import CompWithSym @@ -3041,8 +3045,12 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, sym = [tuple(sym)] for isym in sym: if len(isym) < 2: - # Drop trivial symmetry - continue + if trivial_symmetries == 'error': + raise IndexError("at least two index positions must be " + + "provided to define a symmetry") + else: + # Drop trivial symmetry + continue for i in isym: if i < 0 or i > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + @@ -3053,16 +3061,20 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, antisym = [] else: # Handle the case that antisym is an iterator - antisym = list(antisym) + antisym = tuple(antisym) if antisym: if isinstance(antisym[0], (int, Integer)): # a single antisymmetry is provided as a tuple or a range # object; it is converted to a 1-item list: - antisym = [tuple(antisym)] + antisym = (tuple(antisym),) for isym in antisym: if len(isym) < 2: - # Drop trivial antisymmetry - continue + if trivial_symmetries == 'error': + raise IndexError("at least two index positions must be " + + "provided to define an antisymmetry") + else: + # Drop trivial antisymmetry + continue for i in isym: if i < 0 or i > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index bb55959f4ed..307605b2df4 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1655,7 +1655,8 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, """ from .comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym) + tensor_type[0] + tensor_type[1], sym, antisym, + trivial_symmetries='error') # Special cases: if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) From ffea896b41332047c9f6594358b8706873023c2e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:27:11 -0700 Subject: [PATCH 434/742] CompWithSym._canonicalize_sym_antisym: Code optimization --- src/sage/tensor/modules/comp.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index d9a676711e1..0854361076e 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -3032,17 +3032,20 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, sage: CompWithSym._canonicalize_sym_antisym(6, [(2, 1)]) (((1, 2),), ()) """ + if not sym and not antisym: + # fast path + return (), () result_sym = [] if sym is None: - sym = [] + sym = () else: # Handle the case that sym is an iterator - sym = list(sym) + sym = tuple(sym) if sym: if isinstance(sym[0], (int, Integer)): # a single symmetry is provided as a tuple or a range object; # it is converted to a 1-item list: - sym = [tuple(sym)] + sym = (tuple(sym),) for isym in sym: if len(isym) < 2: if trivial_symmetries == 'error': @@ -3083,9 +3086,9 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, # Final consistency check: index_list = [] for isym in result_sym: - index_list += isym + index_list.extend(isym) for isym in result_antisym: - index_list += isym + index_list.extend(isym) if len(index_list) != len(set(index_list)): # There is a repeated index position: raise IndexError("incompatible lists of symmetries: the same " + From fed09d56502962e93ee9f1981a3eb6af70dbe42f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:35:42 -0700 Subject: [PATCH 435/742] CompWithSym._canonicalize_sym_antisym: Sort earlier to validate indices faster --- src/sage/tensor/modules/comp.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 0854361076e..330fe576168 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -3054,11 +3054,11 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, else: # Drop trivial symmetry continue - for i in isym: - if i < 0 or i > nb_indices - 1: - raise IndexError("invalid index position: " + str(i) + - " not in [0," + str(nb_indices-1) + "]") - result_sym.append(tuple(isym)) + isym = tuple(sorted(isym)) + if isym[0] < 0 or isym[-1] > nb_indices - 1: + raise IndexError("invalid index position: " + str(i) + + " not in [0," + str(nb_indices-1) + "]") + result_sym.append(isym) result_antisym = [] if antisym is None: antisym = [] @@ -3078,11 +3078,11 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, else: # Drop trivial antisymmetry continue - for i in isym: - if i < 0 or i > nb_indices - 1: - raise IndexError("invalid index position: " + str(i) + - " not in [0," + str(nb_indices - 1) + "]") - result_antisym.append(tuple(isym)) + isym = tuple(sorted(isym)) + if isym[0] < 0 or isym[-1] > nb_indices - 1: + raise IndexError("invalid index position: " + str(i) + + " not in [0," + str(nb_indices - 1) + "]") + result_antisym.append(isym) # Final consistency check: index_list = [] for isym in result_sym: @@ -3094,8 +3094,6 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, raise IndexError("incompatible lists of symmetries: the same " + "index position appears more than once") # Canonicalize sort order, make tuples - result_sym = [tuple(sorted(s)) for s in result_sym] - result_antisym = [tuple(sorted(s)) for s in result_antisym] result_sym = tuple(sorted(result_sym)) result_antisym = tuple(sorted(result_antisym)) return result_sym, result_antisym From 421c660af21de39acfcf53dc895d51064024fd6e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:38:59 -0700 Subject: [PATCH 436/742] src/sage/tensor/modules/finite_rank_free_module.py: Add doctest --- src/sage/tensor/modules/finite_rank_free_module.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 307605b2df4..5ffce01fe4a 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1652,6 +1652,20 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, See :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor` for more examples and documentation. + TESTS: + + Errors are raised if trivial symmetries appear in the list of symmetries or + antisymmetries. + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: M.tensor((3,0), sym=[[1]]) + Traceback (most recent call last): + ... + IndexError: at least two index positions must be provided to define a symmetry + sage: M.tensor((3,0), antisym=[[]]) + Traceback (most recent call last): + ... + IndexError: at least two index positions must be provided to define an antisymmetry """ from .comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( From a1a3f364657633f837a59022e85f0a4ba72c2512 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:49:45 -0700 Subject: [PATCH 437/742] CompWithSym.__init__: Accept keyword 'trivial_symmetries', add tests --- src/sage/tensor/modules/comp.py | 19 +++++++++++++++++-- .../tensor/modules/finite_rank_free_module.py | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 330fe576168..060295be280 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -2983,9 +2983,24 @@ class CompWithSym(Components): sage: e + d == d + e True + TESTS: + + Errors are raised if trivial symmetries appear in the list of symmetries or + antisymmetries:: + + sage: CompWithSym(QQ, V.basis(), 3, sym=[[1]]) + Traceback (most recent call last): + ... + IndexError: at least two index positions must be provided to define a symmetry + sage: CompWithSym(QQ, V.basis(), 2, antisym=[[]]) + Traceback (most recent call last): + ... + IndexError: at least two index positions must be provided to define an antisymmetry + """ def __init__(self, ring, frame, nb_indices, start_index=0, - output_formatter=None, sym=None, antisym=None): + output_formatter=None, sym=None, antisym=None, + trivial_symmetries='error'): r""" TESTS:: @@ -2997,7 +3012,7 @@ def __init__(self, ring, frame, nb_indices, start_index=0, Components.__init__(self, ring, frame, nb_indices, start_index, output_formatter) self._sym, self._antisym = self._canonicalize_sym_antisym( - nb_indices, sym, antisym) + nb_indices, sym, antisym, trivial_symmetries=trivial_symmetries) @staticmethod def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 5ffce01fe4a..889bc3fb7b0 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1655,7 +1655,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, TESTS: Errors are raised if trivial symmetries appear in the list of symmetries or - antisymmetries. + antisymmetries:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: M.tensor((3,0), sym=[[1]]) From 8a2c71a6d56ca08d8fb5793ec0cd3faa4682850f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:55:28 -0700 Subject: [PATCH 438/742] VectorFieldModule.tensor, VectorFieldFreeModule.tensor: Use CompWithSym._canonicalize_sym_antisym --- .../differentiable/vectorfield_module.py | 72 ++++++------------- 1 file changed, 23 insertions(+), 49 deletions(-) diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 393218bc7c0..fbdd39b7aef 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -773,7 +773,11 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, AutomorphismField from sage.manifolds.differentiable.metric import (PseudoRiemannianMetric, DegenerateMetric) - if tensor_type==(1,0): + from sage.tensor.modules.comp import CompWithSym + sym, antisym = CompWithSym._canonicalize_sym_antisym( + tensor_type[0] + tensor_type[1], sym, antisym, + trivial_symmetries='error') + if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) elif tensor_type == (0,1): @@ -783,31 +787,14 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, return self.automorphism(name=name, latex_name=latex_name) elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a - # range object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - if isinstance(antisym, (tuple, list)): - antisym0 = antisym[0] - else: - antisym0 = antisym - if len(antisym0) == tensor_type[1]: + if len(antisym[0]) == tensor_type[1]: return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a - # range object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - if isinstance(antisym, (tuple, list)): - antisym0 = antisym[0] - else: - antisym0 = antisym - if len(antisym0) == tensor_type[0]: + if len(antisym[0]) == tensor_type[0]: return self.alternating_contravariant_tensor( - tensor_type[0], name=name, - latex_name=latex_name) - elif tensor_type==(0,2) and specific_type is not None: + tensor_type[0], name=name, latex_name=latex_name) + elif tensor_type == (0,2) and specific_type is not None: if issubclass(specific_type, PseudoRiemannianMetric): return self.metric(name, latex_name=latex_name) # NB: the signature is not treated @@ -816,9 +803,9 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, return self.metric(name, latex_name=latex_name, signature=(0, sign-1, 1)) # Generic case - return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + return self.tensor_module(*tensor_type).element_class( + self, tensor_type, name=name, latex_name=latex_name, + sym=sym, antisym=antisym) def alternating_contravariant_tensor(self, degree, name=None, latex_name=None): @@ -2088,6 +2075,10 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, AutomorphismField, AutomorphismFieldParal) from sage.manifolds.differentiable.metric import (PseudoRiemannianMetric, DegenerateMetric) + from sage.tensor.modules.comp import CompWithSym + sym, antisym = CompWithSym._canonicalize_sym_antisym( + tensor_type[0] + tensor_type[1], sym, antisym, + trivial_symmetries='error') if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) @@ -2098,31 +2089,14 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, (AutomorphismField, AutomorphismFieldParal)): return self.automorphism(name=name, latex_name=latex_name) elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a - # range object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - if isinstance(antisym, (tuple, list)): - antisym0 = antisym[0] - else: - antisym0 = antisym - if len(antisym0) == tensor_type[1]: + if len(antisym[0]) == tensor_type[1]: return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a - # range object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - if isinstance(antisym, (tuple, list)): - antisym0 = antisym[0] - else: - antisym0 = antisym - if len(antisym0) == tensor_type[0]: + if len(antisym[0]) == tensor_type[0]: return self.alternating_contravariant_tensor( - tensor_type[0], name=name, - latex_name=latex_name) - elif tensor_type==(0,2) and specific_type is not None: + tensor_type[0], name=name, latex_name=latex_name) + elif tensor_type == (0,2) and specific_type is not None: if issubclass(specific_type, PseudoRiemannianMetric): return self.metric(name, latex_name=latex_name) # NB: the signature is not treated @@ -2131,9 +2105,9 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, return self.metric(name, latex_name=latex_name, signature=(0, sign-1, 1)) # Generic case - return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + return self.tensor_module(*tensor_type).element_class( + self, tensor_type, name=name, latex_name=latex_name, + sym=sym, antisym=antisym) def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): From e34306bf0471fe2fa9da9e7b9bb86d5bf18cb8d9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 12:12:44 -0700 Subject: [PATCH 439/742] Revert "FiniteRankFreeModule.tensor: Restore error when trivial symmetries are passed" This reverts commit 564be353b347cecfd4496a169b5eaff0642de03d. --- src/sage/tensor/modules/comp.py | 24 +++++-------------- .../tensor/modules/finite_rank_free_module.py | 3 +-- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 060295be280..87d2dc0b473 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -3037,10 +3037,6 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, antisymmetries among the arguments, with the same convention as for ``sym`` - - ``trivial_symmetries`` -- (default: ``"drop"``) if ``"error"``, raise - an :class:`IndexError` if any trivial symmetries are provided; - otherwise, silently drop them - EXAMPLES:: sage: from sage.tensor.modules.comp import CompWithSym @@ -3063,12 +3059,8 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, sym = (tuple(sym),) for isym in sym: if len(isym) < 2: - if trivial_symmetries == 'error': - raise IndexError("at least two index positions must be " + - "provided to define a symmetry") - else: - # Drop trivial symmetry - continue + # Drop trivial symmetry + continue isym = tuple(sorted(isym)) if isym[0] < 0 or isym[-1] > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + @@ -3079,20 +3071,16 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, antisym = [] else: # Handle the case that antisym is an iterator - antisym = tuple(antisym) + antisym = list(antisym) if antisym: if isinstance(antisym[0], (int, Integer)): # a single antisymmetry is provided as a tuple or a range # object; it is converted to a 1-item list: - antisym = (tuple(antisym),) + antisym = [tuple(antisym)] for isym in antisym: if len(isym) < 2: - if trivial_symmetries == 'error': - raise IndexError("at least two index positions must be " + - "provided to define an antisymmetry") - else: - # Drop trivial antisymmetry - continue + # Drop trivial antisymmetry + continue isym = tuple(sorted(isym)) if isym[0] < 0 or isym[-1] > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 889bc3fb7b0..442b5576b49 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1669,8 +1669,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, """ from .comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym, - trivial_symmetries='error') + tensor_type[0] + tensor_type[1], sym, antisym) # Special cases: if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) From c6b6b2ed6ddc44044b8e0915d768cd22672f0dab Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 12:16:19 -0700 Subject: [PATCH 440/742] src/sage/tensor, src/sage/manifolds: Remove parameter 'trivial_symmetries' again --- .../differentiable/vectorfield_module.py | 6 ++--- src/sage/tensor/modules/comp.py | 23 +++---------------- .../tensor/modules/finite_rank_free_module.py | 12 ++++------ 3 files changed, 9 insertions(+), 32 deletions(-) diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index fbdd39b7aef..1e097907967 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -775,8 +775,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, DegenerateMetric) from sage.tensor.modules.comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym, - trivial_symmetries='error') + tensor_type[0] + tensor_type[1], sym, antisym) if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) @@ -2077,8 +2076,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, DegenerateMetric) from sage.tensor.modules.comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym, - trivial_symmetries='error') + tensor_type[0] + tensor_type[1], sym, antisym) if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 87d2dc0b473..0bc56fe728c 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -2982,25 +2982,9 @@ class CompWithSym(Components): ) sage: e + d == d + e True - - TESTS: - - Errors are raised if trivial symmetries appear in the list of symmetries or - antisymmetries:: - - sage: CompWithSym(QQ, V.basis(), 3, sym=[[1]]) - Traceback (most recent call last): - ... - IndexError: at least two index positions must be provided to define a symmetry - sage: CompWithSym(QQ, V.basis(), 2, antisym=[[]]) - Traceback (most recent call last): - ... - IndexError: at least two index positions must be provided to define an antisymmetry - """ def __init__(self, ring, frame, nb_indices, start_index=0, - output_formatter=None, sym=None, antisym=None, - trivial_symmetries='error'): + output_formatter=None, sym=None, antisym=None): r""" TESTS:: @@ -3012,11 +2996,10 @@ def __init__(self, ring, frame, nb_indices, start_index=0, Components.__init__(self, ring, frame, nb_indices, start_index, output_formatter) self._sym, self._antisym = self._canonicalize_sym_antisym( - nb_indices, sym, antisym, trivial_symmetries=trivial_symmetries) + nb_indices, sym, antisym) @staticmethod - def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, - trivial_symmetries='drop'): + def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): r""" Bring sym and antisym into their canonical form. diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 442b5576b49..53f1aa054b0 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1654,18 +1654,14 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, TESTS: - Errors are raised if trivial symmetries appear in the list of symmetries or - antisymmetries:: + Trivial symmetries in the list of symmetries or antisymmetries are silently + ignored:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: M.tensor((3,0), sym=[[1]]) - Traceback (most recent call last): - ... - IndexError: at least two index positions must be provided to define a symmetry + Type-(3,0) tensor on the Rank-3 free module M over the Integer Ring sage: M.tensor((3,0), antisym=[[]]) - Traceback (most recent call last): - ... - IndexError: at least two index positions must be provided to define an antisymmetry + Type-(3,0) tensor on the Rank-3 free module M over the Integer Ring """ from .comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( From 8ca3624bd3b63fe5e5238e0926e94fce4af81cbe Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 1 Sep 2022 23:45:44 +0200 Subject: [PATCH 441/742] polish functorial composition --- src/sage/rings/lazy_series.py | 103 +++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 32 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 2bacf7d2f27..eac2aefdac6 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4375,7 +4375,7 @@ def __call__(self, *g, check=True): sage: E1 = S(lambda n: s[n], valuation=1) sage: E = 1 + E1 sage: P = E(E1) - sage: [s(x) for x in P[:5]] + sage: P[:5] [s[], s[1], 2*s[2], s[2, 1] + 3*s[3], 2*s[2, 2] + 2*s[3, 1] + 5*s[4]] The plethysm with a tensor product is also implemented:: @@ -4496,15 +4496,16 @@ def __call__(self, *g, check=True): g._coeff_stream._approximate_order = 1 if P._arity == 1: - ps = P._laurent_poly_ring.realization_of().p() + ps = R.realization_of().p() else: - ps = tensor([P._laurent_poly_ring._sets[0].realization_of().p()]*P._arity) - coeff_stream = Stream_plethysm(self._coeff_stream, g._coeff_stream, ps) + ps = tensor([R._sets[0].realization_of().p()]*P._arity) + coeff_stream = Stream_plethysm(self._coeff_stream, g._coeff_stream, + ps, R) + return P.element_class(P, coeff_stream) + else: raise NotImplementedError("only implemented for arity 1") - return P.element_class(P, coeff_stream) - plethysm = __call__ def revert(self): @@ -4675,14 +4676,22 @@ def functorial_composition(self, *args): r""" Return the functorial composition of ``self`` and ``g``. - If `F` and `G` are species, their functorial composition is - the species `F \Box G` obtained by setting `(F \Box G) [A] = - F[ G[A] ]`. In other words, an `(F \Box G)`-structure on a - set `A` of labels is an `F`-structure whose labels are the - set of all `G`-structures on `A`. + Let `X` be a finite set of cardinality `m`. For a group + action of the symmetric group `g: S_n \to S_X` and a + (possibly virtual) representation of the symmetric group on + `X`, `f: S_X \to GL(V)`, the functorial composition is the + (virtual) representation of the symmetric group `f \Box g: + S_n \to GL(V)` given by `\sigma \mapsto f(g(\sigma))`. - It can be shown (as in section 2.2 of [BLL]_) that there is a - corresponding operation on cycle indices: + This is more naturally phrased in the language of + combinatorial species. Let `F` and `G` be species, then + their functorial composition is the species `F \Box G` with + `(F \Box G) [A] = F[ G[A] ]`. In other words, an `(F \Box + G)`-structure on a set `A` of labels is an `F`-structure + 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]_): .. MATH:: @@ -4691,8 +4700,6 @@ def functorial_composition(self, *args): \operatorname{fix} F[ (G[\sigma])_{1}, (G[\sigma])_{2}, \ldots ] \, p_{1}^{\sigma_{1}} p_{2}^{\sigma_{2}} \cdots. - This method implements that operation on cycle index series. - .. WARNING:: The operation `f \Box g` only makes sense when `g` @@ -4701,9 +4708,10 @@ def functorial_composition(self, *args): EXAMPLES: - The species `G` of simple graphs can be expressed in terms of a functorial - composition: `G = \mathfrak{p} \Box \mathfrak{p}_{2}`, where - `\mathfrak{p}` is the :class:`~sage.combinat.species.subset_species.SubsetSpecies`.:: + The species `G` of simple graphs can be expressed in terms of + a functorial composition: `G = \mathfrak{p} \Box + \mathfrak{p}_{2}`, where `\mathfrak{p}` is the + :class:`~sage.combinat.species.subset_species.SubsetSpecies`.:: sage: R. = QQ[] sage: h = SymmetricFunctions(R).h() @@ -4735,14 +4743,24 @@ def functorial_composition(self, *args): sage: p = SymmetricFunctions(QQ).p() sage: h = SymmetricFunctions(QQ).h() + sage: e = SymmetricFunctions(QQ).e() sage: L = LazySymmetricFunctions(h) sage: E = L(lambda n: h[n]) sage: Ep = p[1]*E.derivative_with_respect_to_p1(); Ep h[1] + (h[1,1]) + (h[2,1]) + (h[3,1]) + (h[4,1]) + (h[5,1]) + O^7 - sage: f = L(lambda n: randint(3, 6)*h[n]) + sage: f = L(lambda n: h[n-n//2, n//2]) sage: f - Ep.functorial_composition(f) O^7 + The functorial composition distributes over the sum:: + + sage: F1 = L(lambda n: h[n]) + sage: F2 = L(lambda n: e[n]) + sage: f1 = F1.functorial_composition(f) + sage: f2 = F2.functorial_composition(f) + sage: (F1 + F2).functorial_composition(f) - f1 - f2 + O^7 + TESTS: Check a corner case:: @@ -4752,6 +4770,17 @@ def functorial_composition(self, *args): sage: L(h[2,1]).functorial_composition(L([3*h[0]])) 3*h[] + O^7 + Check an instance of a non-group action:: + + sage: s = SymmetricFunctions(QQ).s() + sage: p = SymmetricFunctions(QQ).p() + sage: L = LazySymmetricFunctions(p) + sage: f = L(lambda n: s[n]) + sage: g = L(2*s[2, 1, 1] + s[2, 2] + 3*s[4]) + sage: r = f.functorial_composition(g); r[4] + Traceback (most recent call last): + ... + ValueError: the argument is not the Frobenius character of a permutation representation """ if len(args) != self.parent()._arity: raise ValueError("arity must be equal to the number of arguments provided") @@ -4770,16 +4799,16 @@ def functorial_composition(self, *args): g = Stream_map_coefficients(g._coeff_stream, p) f = Stream_map_coefficients(self._coeff_stream, p) - def g_cycle_type(s): + def g_cycle_type(s, n): # the cycle type of G[sigma] of any permutation sigma - # with cycle type s - if not s: + # with cycle type s, which is a partition of n + if not n: if g[0]: return Partition([1]*ZZ(g[0].coefficient([]))) return Partition([]) res = [] # in the species case, k is at most - # factorial(n) * g[n].coefficient([1]*n) with n = sum(s) + # factorial(n) * g[n].coefficient([1]*n) for k in range(1, lcm(s) + 1): e = 0 for d in divisors(k): @@ -4787,22 +4816,32 @@ def g_cycle_type(s): if not m: continue u = s.power(k // d) - g_u = g[sum(u)] + # it could be, that we never need to compute + # g[n], so we only do this here + g_u = g[n] if g_u: e += m * u.aut() * g_u.coefficient(u) - res.extend([k] * int(e // k)) + # e / k might not be an integer if g is not a + # group action, so it is good to check + res.extend([k] * ZZ(e / k)) res.reverse() return Partition(res) def coefficient(n): - res = p.zero() + terms = {} + t_size = None for s in Partitions(n): - t = g_cycle_type(s) - f_t = f[t.size()] - if f_t: - q = t.aut() * f_t.coefficient(t) / s.aut() - res += q * p(s) - return res + t = g_cycle_type(s, n) + if t_size is None: + t_size = sum(t) + f_t = f[t_size] + if not f_t: + break + elif t_size != sum(t): + raise ValueError("the argument is not the Frobenius character of a permutation representation") + + terms[s] = t.aut() * f_t.coefficient(t) / s.aut() + return R(p.element_class(p, terms)) coeff_stream = Stream_function(coefficient, P._sparse, 0) return P.element_class(P, coeff_stream) From b2ef1e45ff767766effe82c3def803334552d46a Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 1 Sep 2022 23:52:17 +0200 Subject: [PATCH 442/742] allow SymmetricFunctions as arguments of functorial composition --- src/sage/rings/lazy_series.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index eac2aefdac6..50f7979b3b3 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4767,7 +4767,7 @@ def functorial_composition(self, *args): sage: h = SymmetricFunctions(QQ).h() sage: L = LazySymmetricFunctions(h) - sage: L(h[2,1]).functorial_composition(L([3*h[0]])) + sage: L(h[2,1]).functorial_composition(3*h[0]) 3*h[] + O^7 Check an instance of a non-group action:: @@ -4776,7 +4776,7 @@ def functorial_composition(self, *args): sage: p = SymmetricFunctions(QQ).p() sage: L = LazySymmetricFunctions(p) sage: f = L(lambda n: s[n]) - sage: g = L(2*s[2, 1, 1] + s[2, 2] + 3*s[4]) + sage: g = 2*s[2, 1, 1] + s[2, 2] + 3*s[4] sage: r = f.functorial_composition(g); r[4] Traceback (most recent call last): ... @@ -4793,7 +4793,14 @@ def functorial_composition(self, *args): if len(args) == 1: g = args[0] P = g.parent() - R = P._laurent_poly_ring + if isinstance(g, LazySymmetricFunction): + R = P._laurent_poly_ring + else: + from sage.rings.lazy_series_ring import LazySymmetricFunctions + R = g.parent() + P = LazySymmetricFunctions(R) + g = P(g) + p = R.realization_of().p() # TODO: does the following introduce a memory leak? g = Stream_map_coefficients(g._coeff_stream, p) From 230d9f83340362816783fdde09d0073b055b268c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 19:44:49 -0700 Subject: [PATCH 443/742] src/sage/geometry/polyhedron/backend_normaliz.py: Update copyright according to git blame -w --date=format:%Y FILE | sort -k2 --- src/sage/geometry/polyhedron/backend_normaliz.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 86b89632a51..1f27c7e40e4 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -13,7 +13,15 @@ - Jean-Philippe Labbé (2019-04): Expose normaliz features and added functionalities """ # **************************************************************************** -# Copyright (C) 2016 Matthias Köppe +# Copyright (C) 2016-2022 Matthias Köppe +# 2016-2018 Travis Scrimshaw +# 2017 Jeroen Demeyer +# 2018-2020 Jean-Philippe Labbé +# 2019 Vincent Delecroix +# 2019-2021 Jonathan Kliem +# 2019-2021 Sophia Elia +# 2020 Frédéric Chapoton +# 2022 Yuan Zhou # # 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 7ff3df5686e7e9a8aef1f599b8d8195040524933 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 19:57:30 -0700 Subject: [PATCH 444/742] src/sage/geometry/polyhedron/{base,backend}_number_field.py: New, move some code here from backend_normaliz --- .../geometry/polyhedron/backend_normaliz.py | 92 +------------- .../polyhedron/backend_number_field.py | 29 +++++ .../geometry/polyhedron/base_number_field.py | 113 ++++++++++++++++++ 3 files changed, 143 insertions(+), 91 deletions(-) create mode 100644 src/sage/geometry/polyhedron/backend_number_field.py create mode 100644 src/sage/geometry/polyhedron/base_number_field.py diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 1f27c7e40e4..dfcd7a1785f 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ The Normaliz backend for polyhedral computations @@ -44,33 +43,9 @@ from sage.misc.functional import denominator from sage.matrix.constructor import vector -from .base import Polyhedron_base from .base_QQ import Polyhedron_QQ from .base_ZZ import Polyhedron_ZZ - - -def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds): - r""" - Like `number_field_elements_from_algebraics`, but for a list of lists of lists. - - EXAMPLES:: - - sage: rt2 = AA(sqrt(2)); rt2 # optional - sage.rings.number_field - 1.414213562373095? - sage: rt3 = AA(sqrt(3)); rt3 # optional - sage.rings.number_field - 1.732050807568878? - sage: from sage.geometry.polyhedron.backend_normaliz import _number_field_elements_from_algebraics_list_of_lists_of_lists - sage: K, results, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists([[[rt2], [1]], [[rt3]], [[1], []]]); results # optional - sage.rings.number_field - [[[-a^3 + 3*a], [1]], [[-a^2 + 2]], [[1], []]] - """ - from sage.rings.qqbar import number_field_elements_from_algebraics - numbers = [] - for lists in listss: - for list in lists: - numbers.extend(list) - K, K_numbers, hom = number_field_elements_from_algebraics(numbers, **kwds) - g = iter(K_numbers) - return K, [ [ [ next(g) for _ in list ] for list in lists ] for lists in listss ], hom +from .base_number_field import Polyhedron_base_number_field def _format_function_call(fn_name, *v, **k): @@ -918,71 +893,6 @@ def _test_far_facet_condition(self, tester=None, **options): tester.assertEqual(self.n_inequalities() + 1, len(nmz_ieqs)) tester.assertTrue(any(ieq == [0] * self.ambient_dim() + [1] for ieq in nmz_ieqs)) - def _compute_nmz_data_lists_and_field(self, data_lists, convert_QQ, convert_NF): - r""" - Compute data lists in Normaliz format and the number field to use with Normaliz. - - EXAMPLES:: - - sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], # optional - pynormaliz - ....: base_ring=AA, backend='normaliz') - sage: def convert_QQ(ieqs, eqs): # optional - pynormaliz - ....: return [ [ 1000*x for x in ieq ] for ieq in ieqs], \ - ....: [ [ 1000*x for x in eq ] for eq in eqs] - sage: def convert_NF(ieqs, eqs): # optional - pynormaliz - ....: return ieqs, eqs - sage: p._compute_nmz_data_lists_and_field([[[1]], [[1/2]]], # optional - pynormaliz - ....: convert_QQ, convert_NF) - (([[1000]], [[500]]), Rational Field) - sage: p._compute_nmz_data_lists_and_field([[[AA(1)]], [[1/2]]], # optional - pynormaliz - ....: convert_QQ, convert_NF) - (([[1000]], [[500]]), Rational Field) - sage: p._compute_nmz_data_lists_and_field([[[AA(sqrt(2))]], [[1/2]]], # optional - pynormaliz # optional - sage.rings.number_field - ....: convert_QQ, convert_NF) - ([[[a]], [[1/2]]], - Number Field in a with defining polynomial y^2 - 2 with a = 1.414213562373095?) - - TESTS:: - - sage: K. = QuadraticField(-5) # optional - sage.rings.number_field - sage: p = Polyhedron(vertices=[(a,1/2),(2,0),(4,5/6)], # indirect doctest # optional - pynormaliz # optional - sage.rings.number_field - ....: base_ring=K, backend='normaliz') - Traceback (most recent call last): - ... - ValueError: invalid base ring: Number Field in a ... is not real embedded - - Checks that :trac:`30248` is fixed:: - - sage: q = Polyhedron(backend='normaliz', base_ring=AA, # indirect doctest # optional - pynormaliz # optional - sage.rings.number_field - ....: rays=[(0, 0, 1), (0, 1, -1), (1, 0, -1)]); q - A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays - sage: -q # optional - pynormaliz # optional - sage.rings.number_field - A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays - """ - from sage.categories.number_fields import NumberFields - from sage.rings.real_double import RDF - - if self.base_ring() in (QQ, ZZ): - normaliz_field = QQ - nmz_data_lists = convert_QQ(*data_lists) - else: - # Allows to re-iterate if K is QQ below when data_lists contain - # iterators: - data_lists = [tuple(_) for _ in data_lists] - nmz_data_lists = convert_NF(*data_lists) - if self.base_ring() in NumberFields(): - if not RDF.has_coerce_map_from(self.base_ring()): - raise ValueError("invalid base ring: {} is a number field that is not real embedded".format(self.base_ring())) - normaliz_field = self.base_ring() - else: - K, nmz_data_lists, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists(nmz_data_lists, embedded=True) - normaliz_field = K - if K is QQ: - # Compute it with Normaliz, not QNormaliz - nmz_data_lists = convert_QQ(*[ [ [ QQ(x) for x in v ] for v in l] - for l in data_lists ]) - return nmz_data_lists, normaliz_field - def _init_Vrepresentation_from_normaliz(self): r""" Create the Vrepresentation objects from the normaliz polyhedron. diff --git a/src/sage/geometry/polyhedron/backend_number_field.py b/src/sage/geometry/polyhedron/backend_number_field.py new file mode 100644 index 00000000000..48629c4add3 --- /dev/null +++ b/src/sage/geometry/polyhedron/backend_number_field.py @@ -0,0 +1,29 @@ +r""" +The Python backend, using number fields internally +""" + +# **************************************************************************** +# Copyright (C) 2016-2022 Matthias Köppe +# 2016-2018 Travis Scrimshaw +# 2017 Jeroen Demeyer +# 2018-2020 Jean-Philippe Labbé +# 2019 Vincent Delecroix +# 2019-2021 Jonathan Kliem +# 2019-2021 Sophia Elia +# 2020 Frédéric Chapoton +# 2022 Yuan Zhou +# +# 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 .backend_field import Polyhedron_field +from .base_number_field import Polyhedron_base_number_field + + +class Polyhedron_number_field(Polyhedron_field, Polyhedron_base_number_field): + + pass diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py new file mode 100644 index 00000000000..3bcab0c468d --- /dev/null +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -0,0 +1,113 @@ +r""" +Support for internal use of number fields in backends for polyhedral computations +""" + +# **************************************************************************** +# Copyright (C) 2016-2022 Matthias Köppe +# 2016-2018 Travis Scrimshaw +# 2017 Jeroen Demeyer +# 2018-2020 Jean-Philippe Labbé +# 2019 Vincent Delecroix +# 2019-2021 Jonathan Kliem +# 2019-2021 Sophia Elia +# 2020 Frédéric Chapoton +# 2022 Yuan Zhou +# +# 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/ +# **************************************************************************** + + +def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds): + r""" + Like `number_field_elements_from_algebraics`, but for a list of lists of lists. + + EXAMPLES:: + + sage: rt2 = AA(sqrt(2)); rt2 # optional - sage.rings.number_field + 1.414213562373095? + sage: rt3 = AA(sqrt(3)); rt3 # optional - sage.rings.number_field + 1.732050807568878? + sage: from sage.geometry.polyhedron.backend_normaliz import _number_field_elements_from_algebraics_list_of_lists_of_lists + sage: K, results, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists([[[rt2], [1]], [[rt3]], [[1], []]]); results # optional - sage.rings.number_field + [[[-a^3 + 3*a], [1]], [[-a^2 + 2]], [[1], []]] + """ + from sage.rings.qqbar import number_field_elements_from_algebraics + numbers = [] + for lists in listss: + for list in lists: + numbers.extend(list) + K, K_numbers, hom = number_field_elements_from_algebraics(numbers, **kwds) + g = iter(K_numbers) + return K, [ [ [ next(g) for _ in list ] for list in lists ] for lists in listss ], hom + + +class Polyhedron_base_number_field(Polyhedron_base): + + def _compute_nmz_data_lists_and_field(self, data_lists, convert_QQ, convert_NF): + r""" + Compute data lists in Normaliz format and the number field to use with Normaliz. + + EXAMPLES:: + + sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], # optional - pynormaliz + ....: base_ring=AA, backend='normaliz') + sage: def convert_QQ(ieqs, eqs): # optional - pynormaliz + ....: return [ [ 1000*x for x in ieq ] for ieq in ieqs], \ + ....: [ [ 1000*x for x in eq ] for eq in eqs] + sage: def convert_NF(ieqs, eqs): # optional - pynormaliz + ....: return ieqs, eqs + sage: p._compute_nmz_data_lists_and_field([[[1]], [[1/2]]], # optional - pynormaliz + ....: convert_QQ, convert_NF) + (([[1000]], [[500]]), Rational Field) + sage: p._compute_nmz_data_lists_and_field([[[AA(1)]], [[1/2]]], # optional - pynormaliz + ....: convert_QQ, convert_NF) + (([[1000]], [[500]]), Rational Field) + sage: p._compute_nmz_data_lists_and_field([[[AA(sqrt(2))]], [[1/2]]], # optional - pynormaliz # optional - sage.rings.number_field + ....: convert_QQ, convert_NF) + ([[[a]], [[1/2]]], + Number Field in a with defining polynomial y^2 - 2 with a = 1.414213562373095?) + + TESTS:: + + sage: K. = QuadraticField(-5) # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=[(a,1/2),(2,0),(4,5/6)], # indirect doctest # optional - pynormaliz # optional - sage.rings.number_field + ....: base_ring=K, backend='normaliz') + Traceback (most recent call last): + ... + ValueError: invalid base ring: Number Field in a ... is not real embedded + + Checks that :trac:`30248` is fixed:: + + sage: q = Polyhedron(backend='normaliz', base_ring=AA, # indirect doctest # optional - pynormaliz # optional - sage.rings.number_field + ....: rays=[(0, 0, 1), (0, 1, -1), (1, 0, -1)]); q + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays + sage: -q # optional - pynormaliz # optional - sage.rings.number_field + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays + """ + from sage.categories.number_fields import NumberFields + from sage.rings.real_double import RDF + + if self.base_ring() in (QQ, ZZ): + normaliz_field = QQ + nmz_data_lists = convert_QQ(*data_lists) + else: + # Allows to re-iterate if K is QQ below when data_lists contain + # iterators: + data_lists = [tuple(_) for _ in data_lists] + nmz_data_lists = convert_NF(*data_lists) + if self.base_ring() in NumberFields(): + if not RDF.has_coerce_map_from(self.base_ring()): + raise ValueError("invalid base ring: {} is a number field that is not real embedded".format(self.base_ring())) + normaliz_field = self.base_ring() + else: + K, nmz_data_lists, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists(nmz_data_lists, embedded=True) + normaliz_field = K + if K is QQ: + # Compute it with Normaliz, not QNormaliz + nmz_data_lists = convert_QQ(*[ [ [ QQ(x) for x in v ] for v in l] + for l in data_lists ]) + return nmz_data_lists, normaliz_field From ba019c2b668cd68073f618157142b6bb12ea7412 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 20:30:46 -0700 Subject: [PATCH 445/742] Fix some imports --- src/sage/geometry/polyhedron/backend_normaliz.py | 4 ++-- src/sage/geometry/polyhedron/base_number_field.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index dfcd7a1785f..a5f550444ae 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -65,7 +65,7 @@ def _format_function_call(fn_name, *v, **k): ######################################################################### -class Polyhedron_normaliz(Polyhedron_base): +class Polyhedron_normaliz(Polyhedron_base_number_field): """ Polyhedra with normaliz @@ -222,7 +222,7 @@ def __init__(self, parent, Vrep, Hrep, normaliz_cone=None, normaliz_data=None, n else: if normaliz_field: raise ValueError("if Vrep or Hrep are given, cannot provide normaliz_field") - Polyhedron_base.__init__(self, parent, Vrep, Hrep, **kwds) + Polyhedron_base_number_field.__init__(self, parent, Vrep, Hrep, **kwds) def _nmz_result(self, normaliz_cone, property): """ diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py index 3bcab0c468d..f043c2b4c82 100644 --- a/src/sage/geometry/polyhedron/base_number_field.py +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -20,6 +20,8 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from .base import Polyhedron_base + def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds): r""" From ffe0fda0fdec0c4e8266eb8dbd0d33cdb73e66a9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 20:34:34 -0700 Subject: [PATCH 446/742] Fix remaining imports --- src/sage/geometry/polyhedron/base_number_field.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py index f043c2b4c82..5d8bf2e86c4 100644 --- a/src/sage/geometry/polyhedron/base_number_field.py +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -20,6 +20,9 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ + from .base import Polyhedron_base @@ -33,7 +36,7 @@ def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds 1.414213562373095? sage: rt3 = AA(sqrt(3)); rt3 # optional - sage.rings.number_field 1.732050807568878? - sage: from sage.geometry.polyhedron.backend_normaliz import _number_field_elements_from_algebraics_list_of_lists_of_lists + sage: from sage.geometry.polyhedron.base_number_field import _number_field_elements_from_algebraics_list_of_lists_of_lists sage: K, results, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists([[[rt2], [1]], [[rt3]], [[1], []]]); results # optional - sage.rings.number_field [[[-a^3 + 3*a], [1]], [[-a^2 + 2]], [[1], []]] """ From 4a84278e3baa8e005938d3501c0063b3adf2c031 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 20:41:59 -0700 Subject: [PATCH 447/742] src/sage/geometry/polyhedron/parent.py: Add Polyhedra_number_field --- src/sage/geometry/polyhedron/parent.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 10b541bd4ad..ab3786db5e3 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -121,6 +121,10 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * sage: SCR = SR.subring(no_variables=True) # optional - sage.symbolic sage: Polyhedra(SCR, 2, backend='normaliz') # optional - pynormaliz # optional - sage.symbolic Polyhedra in (Symbolic Constants Subring)^2 + + sage: Polyhedra(SCR, 2, backend='number_field') # optional - sage.symbolic + Polyhedra in (Symbolic Constants Subring)^2 + """ if ambient_space_or_base_ring is not None: if ambient_space_or_base_ring in Rings(): @@ -180,6 +184,8 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * except TypeError: raise ValueError(f"the 'polymake' backend for polyhedron cannot be used with {base_field}") return Polyhedra_polymake(base_field, ambient_dim, backend) + elif backend == 'number_field': + return Polyhedra_number_field(base_ring.fraction_field(), ambient_dim, backend) elif backend == 'field': if not base_ring.is_exact(): raise ValueError("the 'field' backend for polyhedron cannot be used with non-exact fields") @@ -1158,13 +1164,14 @@ def _make_Line(self, polyhedron, data): return obj - from sage.geometry.polyhedron.backend_cdd import Polyhedron_QQ_cdd lazy_import('sage.geometry.polyhedron.backend_cdd_rdf', 'Polyhedron_RDF_cdd') from sage.geometry.polyhedron.backend_ppl import Polyhedron_ZZ_ppl, Polyhedron_QQ_ppl from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz, Polyhedron_ZZ_normaliz, Polyhedron_QQ_normaliz from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake from sage.geometry.polyhedron.backend_field import Polyhedron_field +from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field + class Polyhedra_ZZ_ppl(Polyhedra_base): Element = Polyhedron_ZZ_ppl @@ -1245,6 +1252,9 @@ class Polyhedra_polymake(Polyhedra_base): class Polyhedra_field(Polyhedra_base): Element = Polyhedron_field +class Polyhedra_number_field(Polyhedra_base): + Element = Polyhedron_number_field + @cached_function def does_backend_handle_base_ring(base_ring, backend): r""" From 58218d22810d6fad9baec7cd1e726d4ba33e55f2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 20:55:10 -0700 Subject: [PATCH 448/742] src/sage/geometry/polyhedron/backend_number_field.py: Add stubs for methods in which conversion needs to be called --- .../polyhedron/backend_number_field.py | 100 +++++++++++++++++- src/sage/geometry/polyhedron/face.py | 2 +- 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_number_field.py b/src/sage/geometry/polyhedron/backend_number_field.py index 48629c4add3..85a64764cc5 100644 --- a/src/sage/geometry/polyhedron/backend_number_field.py +++ b/src/sage/geometry/polyhedron/backend_number_field.py @@ -25,5 +25,103 @@ class Polyhedron_number_field(Polyhedron_field, Polyhedron_base_number_field): + r""" + Polyhedra whose data can be converted to number field elements - pass + All computations are done internally using a fixed real embedded number field, + which is determined automatically. + + INPUT: + + - ``Vrep`` -- a list ``[vertices, rays, lines]`` or ``None``. + + - ``Hrep`` -- a list ``[ieqs, eqns]`` or ``None``. + + EXAMPLES: + + TODO --- examples where input is in SR. Can copy from backend_normaliz. + + + TESTS: + + Tests from backend_field -- here the data are already either in a number field or in AA. + + sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # optional - sage.rings.number_field + ....: rays=[(1,1)], lines=[], backend='number_field', base_ring=AA) + sage: TestSuite(p).run() # optional - sage.rings.number_field + + sage: K. = QuadraticField(3) # optional - sage.rings.number_field + sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)], backend='number_field') # optional - sage.rings.number_field + sage: TestSuite(p).run() # optional - sage.rings.number_field + + Check that :trac:`19013` is fixed:: + + sage: K. = NumberField(x^2-x-1, embedding=1.618) # optional - sage.rings.number_field + sage: P1 = Polyhedron([[0,1], [1,1], [1,-phi+1]], backend='number_field') # optional - sage.rings.number_field + sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]], backend='number_field') # optional - sage.rings.number_field + sage: P1.intersection(P2) # optional - sage.rings.number_field + The empty polyhedron in (Number Field in phi with defining polynomial x^2 - x - 1 with phi = 1.618033988749895?)^2 + + Check that :trac:`28654` is fixed:: + + sage: Polyhedron(lines=[[1]], backend='number_field') + A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex and 1 line + """ + + def _init_from_Vrepresentation(self, vertices, rays, lines, + minimize=True, verbose=False): + """ + Construct polyhedron from V-representation data. + + INPUT: + + - ``vertices`` -- list of points. Each point can be specified + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + + - ``rays`` -- list of rays. Each ray can be specified as any + iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + + - ``lines`` -- list of lines. Each line can be specified as + any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + + - ``verbose`` -- boolean (default: ``False``). Whether to print + verbose output for debugging purposes. + + EXAMPLES:: + + sage: p = Polyhedron(ambient_dim=2, backend='number_field') + sage: from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field + sage: Polyhedron_number_field._init_from_Vrepresentation(p, [(0,0)], [], []) + """ + # TODO: Transform data + super()._init_from_Vrepresentation(vertices, rays, lines, + minimize=minimize, verbose=verbose) + + def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): + """ + Construct polyhedron from H-representation data. + + INPUT: + + - ``ieqs`` -- list of inequalities. Each line can be specified + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + + - ``eqns`` -- list of equalities. Each line can be specified + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + + - ``verbose`` -- boolean (default: ``False``). Whether to print + verbose output for debugging purposes. + + TESTS:: + + sage: p = Polyhedron(ambient_dim=2, backend='number_field') + sage: from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field + sage: Polyhedron_number_field._init_from_Hrepresentation(p, [(1, 2, 3)], []) + """ + # TODO: Transform data + super()._init_from_Hrepresentation(ieqs, eqns, minimize=minimize, verbose=verbose) diff --git a/src/sage/geometry/polyhedron/face.py b/src/sage/geometry/polyhedron/face.py index d9dd5a6c4d6..421228813a9 100644 --- a/src/sage/geometry/polyhedron/face.py +++ b/src/sage/geometry/polyhedron/face.py @@ -1066,7 +1066,7 @@ def combinatorial_face_to_polyhedral_face(polyhedron, combinatorial_face): # Equations before inequalities in Hrep. H_indices = tuple(range(n_equations)) H_indices += tuple(x+n_equations for x in combinatorial_face.ambient_H_indices(add_equations=False)) - elif polyhedron.backend() in ('normaliz', 'cdd', 'field', 'polymake'): + elif polyhedron.backend() in ('normaliz', 'cdd', 'field', 'number_field', 'polymake'): # Equations after the inequalities in Hrep. n_ieqs = polyhedron.n_inequalities() H_indices = tuple(x for x in combinatorial_face.ambient_H_indices(add_equations=False)) From bec2f6540e63cca9b1c192ceb9ea1c15b7aee762 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 09:14:16 -0700 Subject: [PATCH 449/742] CompWithSym._canonicalize_sym_antisym: Refactor, fix index validation, add tests --- src/sage/tensor/modules/comp.py | 98 ++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 0bc56fe728c..dec039e5d1c 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -2998,10 +2998,61 @@ def __init__(self, ring, frame, nb_indices, start_index=0, self._sym, self._antisym = self._canonicalize_sym_antisym( nb_indices, sym, antisym) + @staticmethod + def _canonicalize_sym_or_antisym(nb_indices, sym_or_antisym): + r""" + Bring ``sym`` or ``antisym`` to its canonical form. + + INPUT: + + - ``nb_indices`` -- number of integer indices labeling the components + + - ``sym_or_antisym`` -- (default: ``None``) a symmetry/antisymmetry + or an iterable of symmetries or an iterable of antisymmetries + among the tensor arguments: each symmetry is described by a tuple + containing the positions of the involved arguments, with the + convention ``position = 0`` for the first argument. For instance: + + TESTS:: + + sage: from sage.tensor.modules.comp import CompWithSym + sage: CompWithSym._canonicalize_sym_or_antisym(3, [0, -1]) + Traceback (most recent call last): + ... + IndexError: invalid index position: -1 not in [0,2] + sage: CompWithSym._canonicalize_sym_or_antisym(3, [3, 1]) + Traceback (most recent call last): + ... + IndexError: invalid index position: 3 not in [0,2] + """ + if not sym_or_antisym: + return () + # Handle the case that sym_or_antisym is an iterator + sym_or_antisym = tuple(sym_or_antisym) + result_sym_or_antisym = [] + if isinstance(sym_or_antisym[0], (int, Integer)): + # a single symmetry is provided as a tuple or a range object; + # it is converted to a 1-item list: + sym_or_antisym = (tuple(sym_or_antisym),) + for isym in sym_or_antisym: + if len(isym) < 2: + # Drop trivial symmetry + continue + isym = tuple(sorted(isym)) + if isym[0] < 0: + raise IndexError("invalid index position: " + str(isym[0]) + + " not in [0," + str(nb_indices-1) + "]") + if isym[-1] > nb_indices - 1: + raise IndexError("invalid index position: " + str(isym[-1]) + + " not in [0," + str(nb_indices-1) + "]") + result_sym_or_antisym.append(isym) + # Canonicalize sort order, make tuples + return tuple(sorted(result_sym_or_antisym)) + @staticmethod def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): r""" - Bring sym and antisym into their canonical form. + Bring ``sym`` and ``antisym`` into their canonical form. INPUT: @@ -3029,46 +3080,8 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): if not sym and not antisym: # fast path return (), () - result_sym = [] - if sym is None: - sym = () - else: - # Handle the case that sym is an iterator - sym = tuple(sym) - if sym: - if isinstance(sym[0], (int, Integer)): - # a single symmetry is provided as a tuple or a range object; - # it is converted to a 1-item list: - sym = (tuple(sym),) - for isym in sym: - if len(isym) < 2: - # Drop trivial symmetry - continue - isym = tuple(sorted(isym)) - if isym[0] < 0 or isym[-1] > nb_indices - 1: - raise IndexError("invalid index position: " + str(i) + - " not in [0," + str(nb_indices-1) + "]") - result_sym.append(isym) - result_antisym = [] - if antisym is None: - antisym = [] - else: - # Handle the case that antisym is an iterator - antisym = list(antisym) - if antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a range - # object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - for isym in antisym: - if len(isym) < 2: - # Drop trivial antisymmetry - continue - isym = tuple(sorted(isym)) - if isym[0] < 0 or isym[-1] > nb_indices - 1: - raise IndexError("invalid index position: " + str(i) + - " not in [0," + str(nb_indices - 1) + "]") - result_antisym.append(isym) + result_sym = CompWithSym._canonicalize_sym_or_antisym(nb_indices, sym) + result_antisym = CompWithSym._canonicalize_sym_or_antisym(nb_indices, antisym) # Final consistency check: index_list = [] for isym in result_sym: @@ -3079,9 +3092,6 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): # There is a repeated index position: raise IndexError("incompatible lists of symmetries: the same " + "index position appears more than once") - # Canonicalize sort order, make tuples - result_sym = tuple(sorted(result_sym)) - result_antisym = tuple(sorted(result_antisym)) return result_sym, result_antisym def _repr_(self): From 66009e7700f8fc0610dc494a09089070bb6f609a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 09:24:03 -0700 Subject: [PATCH 450/742] src/sage/tensor/modules/comp.py: Fix docstring --- src/sage/tensor/modules/comp.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index dec039e5d1c..40f2cf292c7 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -3009,9 +3009,9 @@ def _canonicalize_sym_or_antisym(nb_indices, sym_or_antisym): - ``sym_or_antisym`` -- (default: ``None``) a symmetry/antisymmetry or an iterable of symmetries or an iterable of antisymmetries - among the tensor arguments: each symmetry is described by a tuple - containing the positions of the involved arguments, with the - convention ``position = 0`` for the first argument. For instance: + among the tensor arguments: each symmetry/antisymmetry is described + by a tuple containing the positions of the involved arguments, with + the convention ``position = 0`` for the first argument. TESTS:: From 7474abbe05d4ab21978b268669a3cd9e205dcec2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 10:35:11 -0700 Subject: [PATCH 451/742] FiniteRankFreeModule_abstract.tensor_product: Handle submodules with symmetries --- .../tensor/modules/finite_rank_free_module.py | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index b983789b62d..bfdca5c4846 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -644,13 +644,70 @@ def tensor_product(self, *others): sage: M.tensor_module(1,1).tensor_product(M.tensor_module(1,2)) Free module of type-(2,3) tensors on the 2-dimensional vector space over the Rational Field + sage: Sym2M = M.tensor_module(2, 0, sym=range(2)); Sym2M + Free module of fully symmetric type-(2,0) tensors on the 2-dimensional vector space over the Rational Field + sage: Sym01x23M = Sym2M.tensor_product(Sym2M); Sym01x23M + Free module of type-(4,0) tensors on the 2-dimensional vector space over the Rational Field, + with symmetry on the index positions (0, 1), with symmetry on the index positions (2, 3) + sage: Sym01x23M._index_maps + ((0, 1), (2, 3)) + + sage: N = M.tensor_module(3, 3, sym=[1, 2], antisym=[3, 4]); N + Free module of type-(3,3) tensors on the 2-dimensional vector space over the Rational Field, + with symmetry on the index positions (1, 2), + with antisymmetry on the index positions (3, 4) + sage: NxN = N.tensor_product(N); NxN + Free module of type-(6,6) tensors on the 2-dimensional vector space over the Rational Field, + with symmetry on the index positions (1, 2), with symmetry on the index positions (4, 5), + with antisymmetry on the index positions (6, 7), with antisymmetry on the index positions (9, 10) + sage: NxN._index_maps + ((0, 1, 2, 6, 7, 8), (3, 4, 5, 9, 10, 11)) """ from sage.modules.free_module_element import vector + from .comp import CompFullySym, CompFullyAntiSym, CompWithSym + base_module = self.base_module() if not all(module.base_module() == base_module for module in others): raise NotImplementedError('all factors must be tensor modules over the same base module') - tensor_type = sum(vector(module.tensor_type()) for module in [self] + list(others)) - return base_module.tensor_module(*tensor_type) + factors = [self] + list(others) + result_tensor_type = sum(vector(factor.tensor_type()) for factor in factors) + index_maps = [] + running_indices = vector([0, result_tensor_type[0]]) + result_sym = [] + result_antisym = [] + for factor in factors: + tensor_type = factor.tensor_type() + index_map = tuple(i + running_indices[0] for i in range(tensor_type[0])) + index_map += tuple(i + running_indices[1] for i in range(tensor_type[1])) + index_maps.append(index_map) + + if tensor_type[0] + tensor_type[1] > 1: + basis_sym = factor._basis_sym() + all_indices = tuple(range(tensor_type[0] + tensor_type[1])) + if isinstance(basis_sym, CompFullySym): + sym = [all_indices] + antisym = [] + elif isinstance(basis_sym, CompFullyAntiSym): + sym = [] + antisym = [all_indices] + elif isinstance(basis_sym, CompWithSym): + sym = basis_sym._sym + antisym = basis_sym._antisym + else: + sym = antisym = [] + + def map_isym(isym): + return tuple(index_map[i] for i in isym) + + result_sym.extend(tuple(index_map[i] for i in isym) for isym in sym) + result_antisym.extend(tuple(index_map[i] for i in isym) for isym in antisym) + + running_indices += vector(tensor_type) + + result = base_module.tensor_module(*result_tensor_type, + sym=result_sym, antisym=result_antisym) + result._index_maps = tuple(index_maps) + return result def rank(self) -> int: r""" From ed3c8d91bf060db1a4f38ed478fa96dabb14ae9d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 10:37:29 -0700 Subject: [PATCH 452/742] src/sage/tensor/modules/finite_rank_free_module.py (FiniteRankFreeModule_abstract.is_submodule): Fix typo in doctest --- src/sage/tensor/modules/finite_rank_free_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index bfdca5c4846..e81c0be5762 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -816,7 +816,7 @@ def is_submodule(self, other): EXAMPLES:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') - sage: N = FiniteRankFreeModule(ZZ, 4, name='M') + sage: N = FiniteRankFreeModule(ZZ, 4, name='N') sage: M.is_submodule(M) True sage: M.is_submodule(N) From fd89892e620cd4b81d46e9e441e9809eaea2685a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 10:47:55 -0700 Subject: [PATCH 453/742] src/sage/tensor/modules/tensor_free_submodule[_basis].py, finite_rank_free_module.py: Update AUTHORS --- src/sage/tensor/modules/finite_rank_free_module.py | 3 ++- src/sage/tensor/modules/tensor_free_submodule.py | 8 ++++++-- src/sage/tensor/modules/tensor_free_submodule_basis.py | 8 ++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index e81c0be5762..4f5b99fbc84 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -38,10 +38,11 @@ class :class:`~sage.modules.free_module.FreeModule_generic` AUTHORS: - Eric Gourgoulhon, Michal Bejger (2014-2015): initial version -- Travis Scrimshaw (2016): category set to Modules(ring).FiniteDimensional() +- Travis Scrimshaw (2016): category set to ``Modules(ring).FiniteDimensional()`` (:trac:`20770`) - Michael Jung (2019): improve treatment of the zero element - Eric Gourgoulhon (2021): unicode symbols for tensor and exterior products +- Matthias Koeppe (2022): ``FiniteRankFreeModule_abstract``, symmetric powers REFERENCES: diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index cfe6b09dccf..5f6964f8546 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -1,15 +1,19 @@ r""" Free submodules of tensor modules defined by monoterm symmetries + +AUTHORS: + +- Matthias Koeppe (2020-2022): initial version """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2020-2022 Matthias Koeppe # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** import itertools diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index d2b60298ee0..6c88b05af23 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -1,15 +1,19 @@ r""" Standard bases of free submodules of tensor modules defined by some monoterm symmetries + +AUTHORS: + +- Matthias Koeppe (2020-2022): initial version """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2020-2022 Matthias Koeppe # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.tensor.modules.free_module_basis import Basis_abstract From 644933a6eadec662ebdf59fcb93add2bc4190ca6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 10:48:21 -0700 Subject: [PATCH 454/742] src/sage/tensor/modules/finite_rank_free_module.py: Update copyright according to git blame -w --date=format:%Y FILE | sort -k2 --- src/sage/tensor/modules/finite_rank_free_module.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 4f5b99fbc84..4dfbcbbb41a 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -520,16 +520,19 @@ class :class:`~sage.modules.free_module.FreeModule_generic` [2, 0, -5] """ -#****************************************************************************** -# Copyright (C) 2015-2021 Eric Gourgoulhon -# Copyright (C) 2015 Michal Bejger -# Copyright (C) 2016 Travis Scrimshaw +# ****************************************************************************** +# Copyright (C) 2014-2021 Eric Gourgoulhon +# 2014-2016 Travis Scrimshaw +# 2015 Michal Bejger +# 2016 Frédéric Chapoton +# 2020 Michael Jung +# 2020-2022 Matthias Koeppe # # 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 __future__ import annotations from typing import Generator, Optional From 45bf6f359dba548b7749c6754ebe56b7c16db170 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 11:06:17 -0700 Subject: [PATCH 455/742] FiniteRankFreeModule_abstract.tensor_product: Add comment --- src/sage/tensor/modules/finite_rank_free_module.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 4dfbcbbb41a..f70d603d1b1 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -675,10 +675,12 @@ def tensor_product(self, *others): raise NotImplementedError('all factors must be tensor modules over the same base module') factors = [self] + list(others) result_tensor_type = sum(vector(factor.tensor_type()) for factor in factors) - index_maps = [] - running_indices = vector([0, result_tensor_type[0]]) result_sym = [] result_antisym = [] + # Keep track of reordering of the contravariant and covariant indices + # (compatible with FreeModuleTensor.__mul__) + index_maps = [] + running_indices = vector([0, result_tensor_type[0]]) for factor in factors: tensor_type = factor.tensor_type() index_map = tuple(i + running_indices[0] for i in range(tensor_type[0])) From 76476a05e30553002914abcc20ba3e5b2ace8243 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 11:37:07 -0700 Subject: [PATCH 456/742] VectorField[Free]Module.tensor_module: Accept trivial sym, antisym parameters --- src/sage/manifolds/differentiable/vectorfield_module.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index d86bdaa2496..f80244e39ba 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -501,7 +501,7 @@ def destination_map(self): """ return self._dest_map - def tensor_module(self, k, l): + def tensor_module(self, k, l, *, sym=None, antisym=None): r""" Return the module of type-`(k,l)` tensors on ``self``. @@ -549,6 +549,8 @@ def tensor_module(self, k, l): """ from sage.manifolds.differentiable.tensorfield_module import \ TensorFieldModule + if sym or antisym: + raise NotImplementedError if (k,l) not in self._tensor_modules: self._tensor_modules[(k,l)] = TensorFieldModule(self, (k,l)) return self._tensor_modules[(k,l)] @@ -1717,7 +1719,7 @@ def destination_map(self) -> DiffMap: """ return self._dest_map - def tensor_module(self, k, l): + def tensor_module(self, k, l, *, sym=None, antisym=None): r""" Return the free module of all tensors of type `(k, l)` defined on ``self``. @@ -1766,6 +1768,8 @@ def tensor_module(self, k, l): for more examples and documentation. """ + if sym or antisym: + raise NotImplementedError try: return self._tensor_modules[(k,l)] except KeyError: From d22f87a7fc6a9072bd40ffeb96ecfbac8ae8756c Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 2 Sep 2022 20:37:45 +0200 Subject: [PATCH 457/742] adapt code after merge --- src/sage/rings/lazy_series.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index bf7ccf3e46c..3b59fedadc7 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4941,8 +4941,8 @@ def arithmetic_product(self, *args, check=True): R = P._laurent_poly_ring p = R.realization_of().p() # TODO: does the following introduce a memory leak? - g = Stream_map_coefficients(g._coeff_stream, lambda x: x, p) - f = Stream_map_coefficients(self._coeff_stream, lambda x: x, p) + g = Stream_map_coefficients(g._coeff_stream, p) + f = Stream_map_coefficients(self._coeff_stream, p) if check: assert not f[0] @@ -4973,20 +4973,14 @@ def arith_prod_of_partitions(l1, l2): def arith_prod_sf(x, y): return p._apply_multi_module_morphism(x, y, arith_prod_of_partitions) - # Sage stores cycle index series by degree. Thus, to - # compute the arithmetic product `Z_M \boxdot Z_N` it is - # useful to compute all terms of a given degree `n` at - # once. def coefficient(n): - if n == 0: - res = p.zero() - else: - index_set = ((d, n // d) for d in divisors(n)) - res = sum(arith_prod_sf(f[i], g[j]) for i, j in index_set) + if not n: + return R.zero() - return res + index_set = ((d, n // d) for d in divisors(n)) + return R(sum(arith_prod_sf(f[i], g[j]) for i, j in index_set)) - coeff_stream = Stream_function(coefficient, R, P._sparse, 0) + coeff_stream = Stream_function(coefficient, P._sparse, 0) return P.element_class(P, coeff_stream) else: raise NotImplementedError("only implemented for arity 1") From 94f59b890768bc21c0176398f279385a9010d2b2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 13:53:02 -0700 Subject: [PATCH 458/742] FiniteRankDualFreeModule: New, remove special case from ExtPowerDualFreeModule --- .../tensor/modules/ext_pow_free_module.py | 34 +-- .../tensor/modules/finite_rank_free_module.py | 285 +++++++++++++++++- 2 files changed, 290 insertions(+), 29 deletions(-) diff --git a/src/sage/tensor/modules/ext_pow_free_module.py b/src/sage/tensor/modules/ext_pow_free_module.py index f1ce40c078a..92483ffe422 100644 --- a/src/sage/tensor/modules/ext_pow_free_module.py +++ b/src/sage/tensor/modules/ext_pow_free_module.py @@ -622,18 +622,12 @@ def __init__(self, fmodule, degree, name=None, latex_name=None): self._fmodule = fmodule self._degree = ZZ(degree) rank = binomial(fmodule._rank, degree) - if degree == 1: # case of the dual - if name is None and fmodule._name is not None: - name = fmodule._name + '*' - if latex_name is None and fmodule._latex_name is not None: - latex_name = fmodule._latex_name + r'^*' - else: - if name is None and fmodule._name is not None: - name = unicode_bigwedge + r'^{}('.format(degree) \ - + fmodule._name + '*)' - if latex_name is None and fmodule._latex_name is not None: - latex_name = r'\Lambda^{' + str(degree) + r'}\left(' \ - + fmodule._latex_name + r'^*\right)' + if name is None and fmodule._name is not None: + name = unicode_bigwedge + r'^{}('.format(degree) \ + + fmodule._name + '*)' + if latex_name is None and fmodule._latex_name is not None: + latex_name = r'\Lambda^{' + str(degree) + r'}\left(' \ + + fmodule._latex_name + r'^*\right)' super().__init__(fmodule._ring, rank, name=name, latex_name=latex_name) fmodule._all_modules.add(self) @@ -664,13 +658,6 @@ def _element_constructor_(self, comp=[], basis=None, name=None, sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') - sage: A = M.dual_exterior_power(1) - sage: a = A._element_constructor_(0) ; a - Linear form zero on the Rank-3 free module M over the Integer Ring - sage: a = A._element_constructor_([2,0,-1], name='a') ; a - Linear form a on the Rank-3 free module M over the Integer Ring - sage: a.display() - a = 2 e^0 - e^2 sage: A = M.dual_exterior_power(2) sage: a = A._element_constructor_(0) ; a Alternating form zero of degree 2 on the Rank-3 free module M over @@ -713,11 +700,6 @@ def _an_element_(self): sage: M = FiniteRankFreeModule(QQ, 4, name='M') sage: e = M.basis('e') - sage: a = M.dual_exterior_power(1)._an_element_() ; a - Linear form on the 4-dimensional vector space M over the Rational - Field - sage: a.display() - 1/2 e^0 sage: a = M.dual_exterior_power(2)._an_element_() ; a Alternating form of degree 2 on the 4-dimensional vector space M over the Rational Field @@ -790,8 +772,6 @@ def _repr_(self): EXAMPLES:: sage: M = FiniteRankFreeModule(ZZ, 5, name='M') - sage: M.dual_exterior_power(1)._repr_() - 'Dual of the Rank-5 free module M over the Integer Ring' sage: M.dual_exterior_power(2)._repr_() '2nd exterior power of the dual of the Rank-5 free module M over the Integer Ring' sage: M.dual_exterior_power(3)._repr_() @@ -804,8 +784,6 @@ def _repr_(self): '21st exterior power of the dual of the Rank-5 free module M over the Integer Ring' """ - if self._degree == 1: - return "Dual of the {}".format(self._fmodule) description = "{}".format(self._degree.ordinal_str()) description += " exterior power of the dual of the {}".format( self._fmodule) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 407a01e82d1..654d6d3858b 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -540,8 +540,9 @@ class :class:`~sage.modules.free_module.FreeModule_generic` from sage.rings.integer import Integer from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation +from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement - +from sage.tensor.modules.free_module_tensor import FreeModuleTensor class FiniteRankFreeModule_abstract(UniqueRepresentation, Parent): r""" @@ -1321,6 +1322,9 @@ def dual_exterior_power(self, p): OUTPUT: - for `p=0`, the base ring `R` + - for `p=1`, instance of + :class:`~sage.tensor.modules.finite_rank_free_module.FiniteRankDualFreeModule` + representing the dual `M^*` - for `p\geq 1`, instance of :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule` representing the free module `\Lambda^p(M^*)` @@ -1359,6 +1363,8 @@ def dual_exterior_power(self, p): except KeyError: if p == 0: L = self._ring + elif p == 1: + L = FiniteRankDualFreeModule(self) else: from sage.tensor.modules.ext_pow_free_module import ExtPowerDualFreeModule L = ExtPowerDualFreeModule(self, p) @@ -2960,3 +2966,280 @@ def tensor_type(self): """ return (1, 0) + + +class FiniteRankDualFreeModule(FiniteRankFreeModule_abstract): + r""" + Dual of a free module of finite rank over a commutative ring. + + Given a free module `M` of finite rank over a commutative ring `R`, + the *dual of* `M` is the set `M^*` of all linear forms `p` on `M`, + i.e., linear maps + + .. MATH:: + + M \longrightarrow R + + This is a Sage *parent* class, whose *element* class is + :class:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm`. + + INPUT: + + - ``fmodule`` -- free module `M` of finite rank, as an instance of + :class:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule` + - ``name`` -- (default: ``None``) string; name given to `\Lambda^p(M^*)` + - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote `M^*` + + EXAMPLES: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: A = M.dual(); A + Dual of the Rank-3 free module M over the Integer Ring + + ``A`` is a module (actually a free module) over `\ZZ`:: + + sage: A.category() + Category of finite dimensional modules over Integer Ring + sage: A in Modules(ZZ) + True + sage: A.rank() + 3 + sage: A.base_ring() + Integer Ring + sage: A.base_module() + Rank-3 free module M over the Integer Ring + + ``A`` is a *parent* object, whose elements are linear forms, + represented by instances of the class + :class:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm`:: + + sage: a = A.an_element() ; a + Linear form on the Rank-3 free module M over the Integer Ring + sage: a.display() # expansion with respect to M's default basis (e) + e^0 + sage: from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm + sage: isinstance(a, FreeModuleAltForm) + True + sage: a in A + True + sage: A.is_parent_of(a) + True + + Elements can be constructed from ``A``. In particular, 0 yields + the zero element of ``A``:: + + sage: A(0) + Linear form zero on the Rank-3 free module M over the Integer Ring + sage: A(0) is A.zero() + True + + while non-zero elements are constructed by providing their components in a + given basis:: + + sage: e + Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring + sage: comp = [0,3,-1] + sage: a = A(comp, basis=e, name='a') ; a + Linear form a on the Rank-3 free module M over the Integer Ring + sage: a.display(e) + a = 3 e^1 - e^2 + + An alternative is to construct the alternating form from an empty list of + components and to set the nonzero components afterwards:: + + sage: a = A([], name='a') + sage: a.set_comp(e)[0] = 3 + sage: a.set_comp(e)[1] = -1 + sage: a.set_comp(e)[2] = 4 + sage: a.display(e) + a = 3 e^0 - e^1 + 4 e^2 + + The dual is unique:: + + sage: A is M.dual() + True + + The exterior power `\Lambda^1(M^*)` is nothing but `M^*`:: + + sage: M.dual_exterior_power(1) is M.dual() + True + + It also coincides with the module of type-`(0,1)` tensors:: + + sage: M.dual_exterior_power(1) is M.tensor_module(0,1) + True + """ + + Element = FreeModuleAltForm + + def __init__(self, fmodule, name=None, latex_name=None): + r""" + TESTS:: + + sage: from sage.tensor.modules.finite_rank_free_module import FiniteRankDualFreeModule + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: A = FiniteRankDualFreeModule(M) ; A + Dual of the Rank-3 free module M over the Integer Ring + sage: TestSuite(A).run() + + """ + self._fmodule = fmodule + rank = fmodule._rank + if name is None and fmodule._name is not None: + name = fmodule._name + '*' + if latex_name is None and fmodule._latex_name is not None: + latex_name = fmodule._latex_name + r'^*' + super().__init__(fmodule._ring, rank, name=name, + latex_name=latex_name) + fmodule._all_modules.add(self) + + def construction(self): + r""" + TESTS:: + + sage: from sage.tensor.modules.ext_pow_free_module import ExtPowerDualFreeModule + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: A = M.dual() + sage: A.construction() is None + True + """ + # No construction until we extend VectorFunctor with a parameter 'dual' + return None + + #### Parent methods + + def _element_constructor_(self, comp=[], basis=None, name=None, + latex_name=None): + r""" + Construct a linear form. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: A = M.dual() + sage: a = A._element_constructor_(0) ; a + Linear form zero on the Rank-3 free module M over the Integer Ring + sage: a = A._element_constructor_([2,0,-1], name='a') ; a + Linear form a on the Rank-3 free module M over the Integer Ring + sage: a.display() + a = 2 e^0 - e^2 + """ + if isinstance(comp, (int, Integer)) and comp == 0: + return self.zero() + if isinstance(comp, FreeModuleTensor): + # coercion of a tensor of type (0,1) to a linear form + tensor = comp # for readability + if tensor.tensor_type() == (0,1) and self._degree == 1 and \ + tensor.base_module() is self._fmodule: + resu = self.element_class(self._fmodule, 1, name=tensor._name, + latex_name=tensor._latex_name) + for basis, comp in tensor._components.items(): + resu._components[basis] = comp.copy() + return resu + else: + raise TypeError("cannot coerce the {} ".format(tensor) + + "to an element of {}".format(self)) + # standard construction + resu = self.element_class(self._fmodule, 1, name=name, latex_name=latex_name) + if comp: + resu.set_comp(basis)[:] = comp + return resu + + def _an_element_(self): + r""" + Construct some (unnamed) alternating form. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(QQ, 4, name='M') + sage: e = M.basis('e') + sage: a = M.dual()._an_element_() ; a + Linear form on the 4-dimensional vector space M over the Rational + Field + sage: a.display() + 1/2 e^0 + + TESTS: + + When the base module has no default basis, a default + basis will be set for it:: + + sage: M2 = FiniteRankFreeModule(QQ, 4, name='M2') + sage: a = M2.dual()._an_element_(); a + Linear form on the 4-dimensional vector space M2 over the Rational Field + sage: a + a + Linear form on the 4-dimensional vector space M2 over the Rational Field + sage: M2.default_basis() + Basis (e_0,e_1,e_2,e_3) on the 4-dimensional vector space M2 over the Rational Field + + """ + resu = self.element_class(self._fmodule, 1) + # Make sure that the base module has a default basis + self._fmodule.an_element() + sindex = self._fmodule._sindex + ind = [sindex + i for i in range(resu._tensor_rank)] + resu.set_comp()[ind] = self._fmodule._ring.an_element() + return resu + + #### End of parent methods + + @cached_method + def zero(self): + r""" + Return the zero of ``self``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: A = M.dual() + sage: A.zero() + Linear form zero on the Rank-3 free module M over the Integer Ring + sage: A(0) is A.zero() + True + + """ + resu = self._element_constructor_(name='zero', latex_name='0') + for basis in self._fmodule._known_bases: + resu._components[basis] = resu._new_comp(basis) + # (since new components are initialized to zero) + resu._is_zero = True # This element is certainly zero + resu.set_immutable() + return resu + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 5, name='M') + sage: M.dual_exterior_power(1)._repr_() + 'Dual of the Rank-5 free module M over the Integer Ring' + """ + return "Dual of the {}".format(self._fmodule) + + def base_module(self): + r""" + Return the free module on which ``self`` is constructed. + + OUTPUT: + + - instance of :class:`FiniteRankFreeModule` representing the free + module on which the dual is defined. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 5, name='M') + sage: A = M.dual() + sage: A.base_module() + Rank-5 free module M over the Integer Ring + sage: A.base_module() is M + True + + """ + return self._fmodule From 37e41b9b5f3968e32967128bd94df4f101b685bb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 13:56:26 -0700 Subject: [PATCH 459/742] FiniteRankDualFreeModule.tensor_type: New; add tensor_product doctests --- .../tensor/modules/finite_rank_free_module.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 654d6d3858b..f970d9e7f17 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -633,6 +633,10 @@ def tensor_product(self, *others): sage: M = FiniteRankFreeModule(QQ, 2) sage: M.tensor_product(M) Free module of type-(2,0) tensors on the 2-dimensional vector space over the Rational Field + sage: M.tensor_product(M.dual()) + Free module of type-(1,1) tensors on the 2-dimensional vector space over the Rational Field + sage: M.dual().tensor_product(M, M.dual()) + Free module of type-(1,2) tensors on the 2-dimensional vector space over the Rational Field sage: M.tensor_product(M.tensor_module(1,2)) Free module of type-(2,2) tensors on the 2-dimensional vector space over the Rational Field sage: M.tensor_module(1,2).tensor_product(M) @@ -3243,3 +3247,16 @@ def base_module(self): """ return self._fmodule + + def tensor_type(self): + r""" + Return the tensor type of ``self``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: M.dual().tensor_type() + (0, 1) + + """ + return (0, 1) From f2a3caf66c90c4c3233e65c525d2e40ccd4923cd Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 2 Sep 2022 22:57:58 +0200 Subject: [PATCH 460/742] reimplement arithmetic_product by using the symmetric function version (which is more robust --- src/sage/rings/lazy_series.py | 159 +++++++++++++++++++++------------- 1 file changed, 101 insertions(+), 58 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 3b59fedadc7..ca2f4f80a85 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4310,7 +4310,7 @@ class LazySymmetricFunction(LazyCompletionGradedAlgebraElement): sage: s = SymmetricFunctions(ZZ).s() sage: L = LazySymmetricFunctions(s) """ - def __call__(self, *g, check=True): + def __call__(self, *args, check=True): r""" Return the composition of ``self`` with ``g``. @@ -4442,13 +4442,13 @@ def __call__(self, *g, check=True): 3 """ fP = parent(self) - if len(g) != fP._arity: + if len(args) != fP._arity: raise ValueError("arity must be equal to the number of arguments provided") # Find a good parent for the result from sage.structure.element import get_coercion_model cm = get_coercion_model() - P = cm.common_parent(self.base_ring(), *[parent(h) for h in g]) + P = cm.common_parent(self.base_ring(), *[parent(h) for h in args]) # f = 0 if isinstance(self._coeff_stream, Stream_zero): @@ -4458,15 +4458,15 @@ def __call__(self, *g, check=True): if all((not isinstance(h, LazyModuleElement) and not h) or (isinstance(h, LazyModuleElement) and isinstance(h._coeff_stream, Stream_zero)) - for h in g): + for h in args): f = self[0] # FIXME: TypeError: unable to convert 0 to a rational if f: return P(f.leading_coefficient()) return P.zero() - if len(g) == 1: - g = g[0] + if len(args) == 1: + g = args[0] if (isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant): @@ -4673,8 +4673,7 @@ def derivative_with_respect_to_p1(self, n=1): return P.element_class(P, coeff_stream) def functorial_composition(self, *args): - r""" - Return the functorial composition of ``self`` and ``g``. + r"""Return the functorial composition of ``self`` and ``g``. Let `X` be a finite set of cardinality `m`. For a group action of the symmetric group `g: S_n \to S_X` and a @@ -4695,10 +4694,10 @@ def functorial_composition(self, *args): .. MATH:: - Z_{F} \Box Z_{G} = \sum_{n \geq 0} \frac{1}{n!} - \sum_{\sigma \in \mathfrak{S}_{n}} - \operatorname{fix} F[ (G[\sigma])_{1}, (G[\sigma])_{2}, \ldots ] - \, p_{1}^{\sigma_{1}} p_{2}^{\sigma_{2}} \cdots. + \sum_{n \geq 0} \frac{1}{n!} \sum_{\sigma \in + \mathfrak{S}_{n}} \operatorname{fix} F[ (G[\sigma])_{1}, + (G[\sigma])_{2}, \ldots ] \, p_{1}^{\sigma_{1}} + p_{2}^{\sigma_{2}} \cdots. .. WARNING:: @@ -4737,9 +4736,8 @@ def functorial_composition(self, *args): labellings of their vertices with two 1's and two 2's. - The derivative of the symmetric function `\sum_n h_n`, times - `p_1` is the neutral element with respect to functorial - composition:: + The symmetric function `h_1 \sum_n h_n` is the neutral + element with respect to functorial composition:: sage: p = SymmetricFunctions(QQ).p() sage: h = SymmetricFunctions(QQ).h() @@ -4781,6 +4779,7 @@ def functorial_composition(self, *args): Traceback (most recent call last): ... ValueError: the argument is not the Frobenius character of a permutation representation + """ if len(args) != self.parent()._arity: raise ValueError("arity must be equal to the number of arguments provided") @@ -4859,16 +4858,39 @@ def arithmetic_product(self, *args, check=True): r""" Return the arithmetic product of ``self`` with ``g``. + The arithmetic product is a binary operation `\boxdot` on the + ring of symmetric functions which is bilinear in its two + arguments and satisfies + + .. MATH:: + + p_{\lambda} \boxdot p_{\mu} = \prod\limits_{i \geq 1, j \geq 1} + p_{\mathrm{lcm}(\lambda_i, \mu_j)}^{\mathrm{gcd}(\lambda_i, \mu_j)} + + for any two partitions `\lambda = (\lambda_1, \lambda_2, \lambda_3, + \dots )` and `\mu = (\mu_1, \mu_2, \mu_3, \dots )` (where `p_{\nu}` + denotes the power-sum symmetric function indexed by the partition + `\nu`, and `p_i` denotes the `i`-th power-sum symmetric function). + This is enough to define the arithmetic product if the base ring + is torsion-free as a `\ZZ`-module; for all other cases the + arithmetic product is uniquely determined by requiring it to be + functorial in the base ring. See + http://mathoverflow.net/questions/138148/ for a discussion of + this arithmetic product. + + If `f` and `g` are two symmetric functions which are homogeneous + of degrees `a` and `b`, respectively, then `f \boxdot g` is + homogeneous of degree `ab`. + + The arithmetic product is commutative and associative and has + unity `e_1 = p_1 = h_1`. + For species `M` and `N` such that `M[\varnothing] = N[\varnothing] = \varnothing`, their arithmetic product is the species `M \boxdot N` of "`M`-assemblies of cloned `N`-structures". This operation is defined and several examples are given in [MM2008]_. - The cycle index series for `M \boxdot N` can be computed in - terms of the component series `Z_M` and `Z_N`, as implemented - in this method. - INPUT: - ``g`` -- a cycle index series having the same parent as ``self``. @@ -4878,11 +4900,11 @@ def arithmetic_product(self, *args, check=True): OUTPUT: - The arithmetic product of ``self`` with ``g``. This is a - cycle index series defined in terms of ``self`` and ``g`` - such that if ``self`` and ``g`` are the cycle index series of - two species `M` and `N`, their arithmetic product is the - cycle index series of the species `M \boxdot N`. + The arithmetic product of ``self`` with ``g``. + + .. SEEALSO:: + + :meth:`sage.combinat.sf.sfa.SymmetricFunctionAlgebra_generic_Element.arithmetic_product` EXAMPLES: @@ -4901,17 +4923,17 @@ def arithmetic_product(self, *args, check=True): sage: C = species.CycleSpecies().cycle_index_series() sage: c = L(lambda n: C[n]) sage: Lplus = L(lambda n: p([1]*n), valuation=1) - sage: R = c.arithmetic_product(Lplus); R + sage: r = c.arithmetic_product(Lplus); r m[1] + (3*m[1,1]+2*m[2]) + (8*m[1,1,1]+4*m[2,1]+2*m[3]) + (42*m[1,1,1,1]+21*m[2,1,1]+12*m[2,2]+7*m[3,1]+3*m[4]) + (144*m[1,1,1,1,1]+72*m[2,1,1,1]+36*m[2,2,1]+24*m[3,1,1]+12*m[3,2]+6*m[4,1]+2*m[5]) + (1440*m[1,1,1,1,1,1]+720*m[2,1,1,1,1]+360*m[2,2,1,1]+184*m[2,2,2]+240*m[3,1,1,1]+120*m[3,2,1]+42*m[3,3]+60*m[4,1,1]+32*m[4,2]+12*m[5,1]+4*m[6]) + O^7 In particular, the number of regular octopuses is:: - sage: [R[n].coefficient([1]*n) for n in range(8)] + sage: [r[n].coefficient([1]*n) for n in range(8)] [0, 1, 3, 8, 42, 144, 1440, 5760] - It is shown in [MM2008]_ that the exponential generating function - for regular octopuses satisfies `(C \boxdot L_{+}) (x) = - \sum_{n \geq 1} \sigma (n) (n - 1)! \frac{x^{n}}{n!}` + It is shown in [MM2008]_ that the exponential generating + function for regular octopuses satisfies `(C \boxdot L_{+}) + (x) = \sum_{n \geq 1} \sigma (n) (n - 1)! \frac{x^{n}}{n!}` (where `\sigma (n)` is the sum of the divisors of `n`). :: sage: [sum(divisors(i))*factorial(i-1) for i in range(1,8)] @@ -4925,8 +4947,25 @@ def arithmetic_product(self, *args, check=True): - [MM2008]_ + TESTS: + + Check that the arithmetic product of symmetric functions of + finite support works:: + + sage: s = SymmetricFunctions(QQ).s() + sage: L = LazySymmetricFunctions(s) + sage: L(s([2])).arithmetic_product(s([1,1,1])) + s[2, 2, 1, 1] + s[3, 1, 1, 1] + s[3, 2, 1] + s[3, 3] + 2*s[4, 1, 1] + + Check the arithmetic product of symmetric functions over a + finite field works:: + + sage: s = SymmetricFunctions(FiniteField(2)).s() + sage: L = LazySymmetricFunctions(s) + sage: L(s([2])).arithmetic_product(s([1,1,1])) + s[2, 2, 1, 1] + s[3, 1, 1, 1] + s[3, 2, 1] + s[3, 3] + """ - from itertools import product, repeat, chain if len(args) != self.parent()._arity: raise ValueError("arity must be equal to the number of arguments provided") from sage.combinat.sf.sfa import is_SymmetricFunction @@ -4935,10 +4974,39 @@ def arithmetic_product(self, *args, check=True): or not g for g in args): raise ValueError("all arguments must be (possibly lazy) symmetric functions") + # f = 0 or g = (0, ..., 0) + if (isinstance(self._coeff_stream, Stream_zero) + or all((not isinstance(h, LazyModuleElement) and not h) + or (isinstance(h, LazyModuleElement) + and isinstance(h._coeff_stream, Stream_zero)) + for h in args)): + return P.zero() + if len(args) == 1: g = args[0] P = g.parent() - R = P._laurent_poly_ring + + if (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): + + if not isinstance(g, LazySymmetricFunction): + f = self.symmetric_function() + return f.arithmetic_product(g) + + if (isinstance(g._coeff_stream, Stream_exact) + and not g._coeff_stream._constant): + f = self.symmetric_function() + gs = g.symmetric_function() + return P(f.arithmetic_product(gs)) + + if isinstance(g, LazySymmetricFunction): + R = P._laurent_poly_ring + else: + from sage.rings.lazy_series_ring import LazySymmetricFunctions + R = g.parent() + P = LazySymmetricFunctions(R) + g = P(g) + p = R.realization_of().p() # TODO: does the following introduce a memory leak? g = Stream_map_coefficients(g._coeff_stream, p) @@ -4948,37 +5016,12 @@ def arithmetic_product(self, *args, check=True): assert not f[0] assert not g[0] - # We first define an operation `\boxtimes` on partitions - # as in Lemma 2.1 of [MM2008]_. - def arith_prod_of_partitions(l1, l2): - # Given two partitions `l_1` and `l_2`, we construct - # a new partition `l_1 \boxtimes l_2` by the - # following procedure: each pair of parts `a \in l_1` - # and `b \in l_2` contributes `\gcd (a, b)`` parts of - # size `\lcm (a, b)` to `l_1 \boxtimes l_2`. If `l_1` - # and `l_2` are partitions of integers `n` and `m`, - # respectively, then `l_1 \boxtimes l_2` is a - # partition of `nm`. Finally, we return the - # corresponding powersum symmetric function. - term_iterable = chain.from_iterable(repeat(lcm(pair), gcd(pair)) - for pair in product(l1, l2)) - return p(Partition(sorted(term_iterable, reverse=True))) - - # We then extend this to an operation on symmetric - # functions as per eq. (52) of [MM]_. (Maia and Mendez, - # in [MM]_, are talking about polynomials instead of - # symmetric functions, but this boils down to the same: - # Their x_i corresponds to the i-th power sum symmetric - # function.) - def arith_prod_sf(x, y): - return p._apply_multi_module_morphism(x, y, arith_prod_of_partitions) - def coefficient(n): if not n: return R.zero() - index_set = ((d, n // d) for d in divisors(n)) - return R(sum(arith_prod_sf(f[i], g[j]) for i, j in index_set)) + return sum(f[i].arithmetic_product(g[j]) + for i, j in index_set if f[i] and g[j]) coeff_stream = Stream_function(coefficient, P._sparse, 0) return P.element_class(P, coeff_stream) From ccc1f853a0ff5c0b201cd73959f2a516e1aa574d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 16:48:11 -0700 Subject: [PATCH 461/742] src/sage/rings/ring.pyx: Remove methods duplicated from category --- src/sage/categories/rings.py | 50 ++++++++++++++++++++++++-- src/sage/rings/ring.pyx | 70 ------------------------------------ 2 files changed, 48 insertions(+), 72 deletions(-) diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index fc1df0de372..512e799177b 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -866,6 +866,16 @@ def quo(self, I, names=None, **kwds): [0 1] ) + A test with a subclass of :class:`~sage.rings.ring.Ring`:: + + sage: R. = PolynomialRing(QQ,2) + sage: S. = R.quo((x^2, y)) + sage: S + Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y) + sage: S.gens() + (a, 0) + sage: a == b + False """ return self.quotient(I,names=names,**kwds) @@ -875,7 +885,22 @@ def quotient_ring(self, I, names=None, **kwds): NOTE: - This is a synonyme for :meth:`quotient`. + This is a synonym for :meth:`quotient`. + + INPUT: + + - ``I`` -- an ideal of `R` + + - ``names`` -- (optional) names of the generators of the quotient. (If + there are multiple generators, you can specify a single character + string and the generators are named in sequence starting with 0.) + + - further named arguments that may be passed to the quotient ring + constructor. + + OUTPUT: + + - ``R/I`` -- the quotient ring of `R` by the ideal `I` EXAMPLES:: @@ -906,8 +931,24 @@ def quotient_ring(self, I, names=None, **kwds): [0 1] ) + A test with a subclass of :class:`~sage.rings.ring.Ring`:: + + sage: R. = PolynomialRing(ZZ) + sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) + sage: S = R.quotient_ring(I, 'a') + sage: S.gens() + (a,) + + sage: R. = PolynomialRing(QQ,2) + sage: S. = R.quotient_ring((x^2, y)) + sage: S + Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y) + sage: S.gens() + (a, 0) + sage: a == b + False """ - return self.quotient(I,names=names, **kwds) + return self.quotient(I, names=names, **kwds) def __truediv__(self, I): """ @@ -923,6 +964,11 @@ def __truediv__(self, I): Traceback (most recent call last): ... TypeError: Use self.quo(I) or self.quotient(I) to construct the quotient ring. + + sage: QQ['x'] / ZZ + Traceback (most recent call last): + ... + TypeError: Use self.quo(I) or self.quotient(I) to construct the quotient ring. """ raise TypeError("Use self.quo(I) or self.quotient(I) to construct the quotient ring.") diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 1851af15fdb..433ba29bba4 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -650,76 +650,6 @@ cdef class Ring(ParentWithGens): import sage.rings.quotient_ring return sage.rings.quotient_ring.QuotientRing(self, I, names=names, **kwds) - def quo(self, I, names=None, **kwds): - """ - Create the quotient of `R` by the ideal `I`. This is a synonym for :meth:`.quotient` - - EXAMPLES:: - - sage: R. = PolynomialRing(QQ,2) - sage: S. = R.quo((x^2, y)) - sage: S - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y) - sage: S.gens() - (a, 0) - sage: a == b - False - """ - return self.quotient(I, names=names, **kwds) - - def __truediv__(self, I): - """ - Dividing one ring by another is not supported because there is no good - way to specify generator names. - - EXAMPLES:: - - sage: QQ['x'] / ZZ - Traceback (most recent call last): - ... - TypeError: Use self.quo(I) or self.quotient(I) to construct the quotient ring. - """ - raise TypeError("Use self.quo(I) or self.quotient(I) to construct the quotient ring.") - - def quotient_ring(self, I, names=None, **kwds): - """ - Return the quotient of self by the ideal `I` of ``self``. - (Synonym for ``self.quotient(I)``.) - - INPUT: - - - ``I`` -- an ideal of `R` - - - ``names`` -- (optional) names of the generators of the quotient. (If - there are multiple generators, you can specify a single character - string and the generators are named in sequence starting with 0.) - - - further named arguments that may be passed to the quotient ring - constructor. - - OUTPUT: - - - ``R/I`` -- the quotient ring of `R` by the ideal `I` - - EXAMPLES:: - - sage: R. = PolynomialRing(ZZ) - sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) - sage: S = R.quotient_ring(I, 'a') - sage: S.gens() - (a,) - - sage: R. = PolynomialRing(QQ,2) - sage: S. = R.quotient_ring((x^2, y)) - sage: S - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y) - sage: S.gens() - (a, 0) - sage: a == b - False - """ - return self.quotient(I, names, **kwds) - def zero(self): """ Return the zero element of this ring (cached). From ef266af585bc137b1c0e3a2944dc670777e53eba Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 17:00:53 -0700 Subject: [PATCH 462/742] src/sage/rings/ring.pyx: Remove another method duplicated from category --- src/sage/categories/rings.py | 25 ++++++++++++++++++++---- src/sage/rings/ring.pyx | 37 +----------------------------------- 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index 512e799177b..88ce6ef5bc0 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -781,16 +781,16 @@ def _ideal_class_(self,n=0): ## # Quotient rings - # Again, this is defined in sage.rings.ring.pyx def quotient(self, I, names=None, **kwds): """ Quotient of a ring by a two-sided ideal. INPUT: - - ``I``: A twosided ideal of this ring. - - ``names``: a list of strings to be used as names - for the variables in the quotient ring. + - ``I`` -- A twosided ideal of this ring. + - ``names`` -- (optional) names of the generators of the quotient (if + there are multiple generators, you can specify a single character + string and the generators are named in sequence starting with 0). - further named arguments that may be passed to the quotient ring constructor. @@ -823,6 +823,23 @@ def quotient(self, I, names=None, **kwds): xbar*ybar sage: Q.0*Q.1*Q.0 0 + + An example with polynomial rings:: + + sage: R. = PolynomialRing(ZZ) + sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) + sage: S = R.quotient(I, 'a') + sage: S.gens() + (a,) + + sage: R. = PolynomialRing(QQ,2) + sage: S. = R.quotient((x^2, y)) + sage: S + Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y) + sage: S.gens() + (a, 0) + sage: a == b + False """ from sage.rings.quotient_ring import QuotientRing return QuotientRing(self, I, names=names, **kwds) diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 433ba29bba4..75b0854d630 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -312,7 +312,7 @@ cdef class Ring(ParentWithGens): sage: F. = FreeAlgebra(ZZ, 3) sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F - sage: Q = sage.rings.ring.Ring.quotient(F,I) + sage: Q = F.quotient(I) sage: Q.ideal_monoid() Monoid of ideals of Quotient of Free Algebra on 3 generators (x, y, z) over Integer Ring by the ideal (x*y + y*z, x^2 + x*y - y*x - y^2) sage: F. = FreeAlgebra(ZZ, implementation='letterplace') @@ -615,41 +615,6 @@ cdef class Ring(ParentWithGens): return I return self._zero_ideal - def quotient(self, I, names=None, **kwds): - """ - Create the quotient of this ring by a twosided ideal ``I``. - - INPUT: - - - ``I`` -- a twosided ideal of this ring, `R`. - - - ``names`` -- (optional) names of the generators of the quotient (if - there are multiple generators, you can specify a single character - string and the generators are named in sequence starting with 0). - - - further named arguments that may be passed to the quotient ring - constructor. - - EXAMPLES:: - - sage: R. = PolynomialRing(ZZ) - sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) - sage: S = R.quotient(I, 'a') - sage: S.gens() - (a,) - - sage: R. = PolynomialRing(QQ,2) - sage: S. = R.quotient((x^2, y)) - sage: S - Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y) - sage: S.gens() - (a, 0) - sage: a == b - False - """ - import sage.rings.quotient_ring - return sage.rings.quotient_ring.QuotientRing(self, I, names=names, **kwds) - def zero(self): """ Return the zero element of this ring (cached). From c44607808c6b1212909292f3d9d0570546b641d1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 17:42:07 -0700 Subject: [PATCH 463/742] Modules.ParentMethods.quotient: New, delegates to .quotient_module; replaces alias Module_free_ambient.quotient --- src/sage/categories/modules.py | 17 +++++++++++++++++ src/sage/modules/free_module.py | 6 ++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index d37b4812209..755788eb4d3 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -675,6 +675,23 @@ def module_morphism(self, *, function, category=None, codomain, **keywords): category = Modules(self.base_ring()) return SetMorphism(Hom(self, codomain, category), function) + def quotient(self, submodule, check=True, **kwds): + r""" + Construct the quotient module ``self`` / ``submodule``. + + This method just delegates to :meth:`quotient_module`. + + INPUT: + + - ``submodule`` -- a submodule with basis of ``self``, or + something that can be turned into one via + ``self.submodule(submodule)`` + + - ``check``, other keyword arguments: passed on to + :meth:`quotient_module`. + """ + return self.quotient_module(submodule, check=check, **kwds) + class ElementMethods: pass diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index d508b22fcc7..c7685a6e27b 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -1782,8 +1782,6 @@ def quotient_module(self, sub, check=True): from .quotient_module import QuotientModule_free_ambient return QuotientModule_free_ambient(self, sub) - quotient = quotient_module - def __truediv__(self, sub): """ Return the quotient of ``self`` by the given submodule sub. @@ -4180,7 +4178,7 @@ def vector_space_span_of_basis(self, basis, check=True): """ return FreeModule_submodule_with_basis_field(self.ambient_vector_space(), basis, check=check) - def quotient(self, sub, check=True, **kwds): + def quotient_module(self, sub, check=True, **kwds): """ Return the quotient of ``self`` by the given submodule sub. @@ -4994,7 +4992,7 @@ def __truediv__(self, sub): """ return self.quotient(sub, check=True) - def quotient(self, sub, check=True): + def quotient_module(self, sub, check=True): """ Return the quotient of ``self`` by the given subspace sub. From 4958d6d8ef223efce6cae23e7470f87be8b36d67 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 2 Sep 2022 20:35:41 -0700 Subject: [PATCH 464/742] Modules.ParentMethods.quotient: Expand docstring --- src/sage/categories/modules.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 755788eb4d3..b92453740c3 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -679,8 +679,6 @@ def quotient(self, submodule, check=True, **kwds): r""" Construct the quotient module ``self`` / ``submodule``. - This method just delegates to :meth:`quotient_module`. - INPUT: - ``submodule`` -- a submodule with basis of ``self``, or @@ -689,6 +687,22 @@ def quotient(self, submodule, check=True, **kwds): - ``check``, other keyword arguments: passed on to :meth:`quotient_module`. + + This method just delegates to :meth:`quotient_module`. + Classes implementing modules should override that method. + + Parents in categories with additional structure may override + :meth:`quotient`. For example, in algebras, :meth:`quotient` will + be the same as :meth:`quotient_ring`. + + EXAMPLES:: + + sage: C = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: TA = TensorAlgebra(C) + sage: TA.quotient + + """ return self.quotient_module(submodule, check=check, **kwds) From 8b6a752a3326cd62f3316d6a09a3450166a7e0a5 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 3 Sep 2022 09:11:31 +0200 Subject: [PATCH 465/742] no period at end of input description, break long doctest --- src/sage/rings/lazy_series.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index ca2f4f80a85..f1358c23d31 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4893,10 +4893,10 @@ def arithmetic_product(self, *args, check=True): INPUT: - - ``g`` -- a cycle index series having the same parent as ``self``. + - ``g`` -- a cycle index series having the same parent as ``self`` - ``check`` -- (default: ``True``) a Boolean which, when set - to ``False``, will cause input checks to be skipped. + to ``False``, will cause input checks to be skipped OUTPUT: @@ -4924,7 +4924,12 @@ def arithmetic_product(self, *args, check=True): sage: c = L(lambda n: C[n]) sage: Lplus = L(lambda n: p([1]*n), valuation=1) sage: r = c.arithmetic_product(Lplus); r - m[1] + (3*m[1,1]+2*m[2]) + (8*m[1,1,1]+4*m[2,1]+2*m[3]) + (42*m[1,1,1,1]+21*m[2,1,1]+12*m[2,2]+7*m[3,1]+3*m[4]) + (144*m[1,1,1,1,1]+72*m[2,1,1,1]+36*m[2,2,1]+24*m[3,1,1]+12*m[3,2]+6*m[4,1]+2*m[5]) + (1440*m[1,1,1,1,1,1]+720*m[2,1,1,1,1]+360*m[2,2,1,1]+184*m[2,2,2]+240*m[3,1,1,1]+120*m[3,2,1]+42*m[3,3]+60*m[4,1,1]+32*m[4,2]+12*m[5,1]+4*m[6]) + O^7 + m[1] + (3*m[1,1]+2*m[2]) + + (8*m[1,1,1]+4*m[2,1]+2*m[3]) + + (42*m[1,1,1,1]+21*m[2,1,1]+12*m[2,2]+7*m[3,1]+3*m[4]) + + (144*m[1,1,1,1,1]+72*m[2,1,1,1]+36*m[2,2,1]+24*m[3,1,1]+12*m[3,2]+6*m[4,1]+2*m[5]) + + ... + + O^7 In particular, the number of regular octopuses is:: From f88a5c81a722b5da9ad9b7f7d78cc1f9876d3edb Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sat, 3 Sep 2022 10:38:59 +0200 Subject: [PATCH 466/742] fix arithmetic product with 0 and finite support --- src/sage/rings/lazy_series.py | 58 +++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index f1358c23d31..b01a5f4cf6d 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -163,11 +163,10 @@ from sage.functions.other import factorial from sage.arith.power import generic_power from sage.arith.functions import lcm -from sage.arith.misc import divisors, moebius, gcd +from sage.arith.misc import divisors, moebius from sage.combinat.partition import Partition, Partitions from sage.misc.misc_c import prod from sage.misc.derivative import derivative_parse -from sage.combinat.partition import Partition from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing @@ -4954,14 +4953,25 @@ def arithmetic_product(self, *args, check=True): TESTS: - Check that the arithmetic product of symmetric functions of - finite support works:: + Check that the product with zero works:: sage: s = SymmetricFunctions(QQ).s() sage: L = LazySymmetricFunctions(s) + sage: L(0).arithmetic_product(s[2]) + 0 + sage: L(s[2]).arithmetic_product(0) + 0 + + Check that the arithmetic product of symmetric functions of + finite support works:: + sage: L(s([2])).arithmetic_product(s([1,1,1])) s[2, 2, 1, 1] + s[3, 1, 1, 1] + s[3, 2, 1] + s[3, 3] + 2*s[4, 1, 1] + sage: f = 1/(1-L(s[1])) + sage: f.arithmetic_product(s[1]) - f + O^7 + Check the arithmetic product of symmetric functions over a finite field works:: @@ -4979,18 +4989,17 @@ def arithmetic_product(self, *args, check=True): or not g for g in args): raise ValueError("all arguments must be (possibly lazy) symmetric functions") - # f = 0 or g = (0, ..., 0) - if (isinstance(self._coeff_stream, Stream_zero) - or all((not isinstance(h, LazyModuleElement) and not h) - or (isinstance(h, LazyModuleElement) - and isinstance(h._coeff_stream, Stream_zero)) - for h in args)): - return P.zero() - if len(args) == 1: g = args[0] P = g.parent() + # f = 0 or g = (0, ..., 0) + if (isinstance(self._coeff_stream, Stream_zero) + or (not isinstance(g, LazyModuleElement) and not g) + or (isinstance(g, LazyModuleElement) + and isinstance(g._coeff_stream, Stream_zero))): + return P.zero() + if (isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant): @@ -5012,18 +5021,33 @@ def arithmetic_product(self, *args, check=True): P = LazySymmetricFunctions(R) g = P(g) + # compute the constant term in the case where not both f + # and g have finite support + # TODO: this should be done lazily if possible + c = R.zero() + if self[0]: + if (isinstance(g._coeff_stream, Stream_exact) + and not g._coeff_stream._constant): + gs = g.symmetric_function() + c += self[0].arithmetic_product(gs) + elif check: + raise ValueError("can only take the arithmetic product with a positive valuation series") + if g[0]: + if (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): + fs = self.symmetric_function() + c += fs.arithmetic_product(g[0]) + elif check: + raise ValueError("can only take the arithmetic product with a positive valuation series") + p = R.realization_of().p() # TODO: does the following introduce a memory leak? g = Stream_map_coefficients(g._coeff_stream, p) f = Stream_map_coefficients(self._coeff_stream, p) - if check: - assert not f[0] - assert not g[0] - def coefficient(n): if not n: - return R.zero() + return c index_set = ((d, n // d) for d in divisors(n)) return sum(f[i].arithmetic_product(g[j]) for i, j in index_set if f[i] and g[j]) From b7ddb8f6c67589400350d54fe1a8031d516bd99e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 3 Sep 2022 10:48:32 +0200 Subject: [PATCH 467/742] very tiny https detail --- src/sage/algebras/exterior_algebra_groebner.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index dc77faa590d..3d01aaf03a1 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -9,7 +9,7 @@ AUTHORS: - Trevor K. Karn, Travis Scrimshaw (July 2022): Initial implementation """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2022 Trevor K. Karn # (C) 2022 Travis Scrimshaw # @@ -17,8 +17,8 @@ AUTHORS: # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_check from sage.libs.gmp.mpz cimport mpz_sizeinbase, mpz_setbit, mpz_tstbit, mpz_cmp_si, mpz_sgn From 78ada7d31093789608bfbb8687844cb664e40bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 3 Sep 2022 16:03:48 +0200 Subject: [PATCH 468/742] very tiny additional commit --- src/sage/matrix/operation_table.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/matrix/operation_table.py b/src/sage/matrix/operation_table.py index ff22a20d7c1..13f0a88822a 100644 --- a/src/sage/matrix/operation_table.py +++ b/src/sage/matrix/operation_table.py @@ -4,19 +4,19 @@ This module implements general operation tables, which are very matrix-like. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Rob Beezer # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** - +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.sage_object import SageObject + class OperationTable(SageObject): r""" An object that represents a binary operation as a table. From 0d2539a6fe4a7786181f40436c9c0272e2d419ac Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 3 Sep 2022 14:03:28 -0700 Subject: [PATCH 469/742] VectorFieldModule: Faster fast path for tensor_module, exterior_power, dual_exterior_power --- .../differentiable/vectorfield_module.py | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index cf3f1dc687d..7b954d44e22 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -547,11 +547,14 @@ def tensor_module(self, k, l): for more examples and documentation. """ - from sage.manifolds.differentiable.tensorfield_module import \ + try: + return self._tensor_modules[(k,l)] + except KeyError: + from sage.manifolds.differentiable.tensorfield_module import \ TensorFieldModule - if (k,l) not in self._tensor_modules: - self._tensor_modules[(k,l)] = TensorFieldModule(self, (k,l)) - return self._tensor_modules[(k,l)] + T = TensorFieldModule(self, (k,l)) + self._tensor_modules[(k,l)] = T + return T def exterior_power(self, p): r""" @@ -600,13 +603,17 @@ def exterior_power(self, p): for more examples and documentation. """ - from sage.manifolds.differentiable.multivector_module import \ + try: + return self._exterior_powers[p] + except KeyError: + if p == 0: + L = self._ring + else: + from sage.manifolds.differentiable.multivector_module import \ MultivectorModule - if p == 0: - return self._ring - if p not in self._exterior_powers: - self._exterior_powers[p] = MultivectorModule(self, p) - return self._exterior_powers[p] + L = MultivectorModule(self, p) + self._exterior_powers[p] = L + return L def dual_exterior_power(self, p): r""" @@ -654,13 +661,17 @@ def dual_exterior_power(self, p): for more examples and documentation. """ - from sage.manifolds.differentiable.diff_form_module import \ + try: + return self._dual_exterior_powers[p] + except KeyError: + if p == 0: + L = self._ring + else: + from sage.manifolds.differentiable.diff_form_module import \ DiffFormModule - if p == 0: - return self._ring - if p not in self._dual_exterior_powers: - self._dual_exterior_powers[p] = DiffFormModule(self, p) - return self._dual_exterior_powers[p] + L = DiffFormModule(self, p) + self._dual_exterior_powers[p] = L + return L def dual(self): r""" From 0d4f3d5f06f0cb21bef759b5a3b8440bc90d644b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 4 Sep 2022 07:30:35 -0700 Subject: [PATCH 470/742] build/pkgs/igraph: Update to 0.9.10 --- build/pkgs/igraph/checksums.ini | 6 +++--- build/pkgs/igraph/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/igraph/checksums.ini b/build/pkgs/igraph/checksums.ini index 1e09d661bd2..2d7a72630b0 100644 --- a/build/pkgs/igraph/checksums.ini +++ b/build/pkgs/igraph/checksums.ini @@ -1,5 +1,5 @@ tarball=igraph-VERSION.tar.gz -sha1=66da9978e789e996e4b85cf970ab46e84dc971d7 -md5=fb0c24794bb88e88d4874802b78684bf -cksum=2298757908 +sha1=75aae4d9f1459d9e6f6bd03189e6dff4208c29ca +md5=351a276216a8f09e11a401d2313ea471 +cksum=1815245909 upstream_url=https://github.com/igraph/igraph/releases/download/VERSION/igraph-VERSION.tar.gz diff --git a/build/pkgs/igraph/package-version.txt b/build/pkgs/igraph/package-version.txt index c81aa44afbf..56f3151140c 100644 --- a/build/pkgs/igraph/package-version.txt +++ b/build/pkgs/igraph/package-version.txt @@ -1 +1 @@ -0.9.7 +0.9.10 From 76ffacf0fbcc1d2fd4782c1f9df35485765d142e Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Sun, 4 Sep 2022 15:59:10 +0100 Subject: [PATCH 471/742] Run rimeann_surface.py through black to reformat --- .../riemann_surfaces/riemann_surface.py | 1047 ++++++++++------- 1 file changed, 653 insertions(+), 394 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index d5c25ddb81d..d0638bf030c 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -231,9 +231,9 @@ def bisect(L, t): if t < L[min][0] or t > L[max][0]: raise ValueError("value for t out of range") # Main loop. - while (min < max-1): + while min < max - 1: # Bisect. - mid = (max+min)//2 + mid = (max + min) // 2 # If it's equal, return the index we bisected to. if t == L[mid][0]: return mid @@ -357,9 +357,10 @@ def differential_basis_baker(f): if len(B.monomials()) > 1: return None from sage.geometry.polyhedron.constructor import Polyhedron + D = {(k[0], k[1]): v for k, v in f.dict().items()} P = Polyhedron(D) - kT = k['t'] + kT = k["t"] # here we check the additional genericity conditions: that the polynomials # along the edges of the Newton polygon are square-free. for e in P.bounded_edges(): @@ -367,8 +368,11 @@ def differential_basis_baker(f): if not h.is_squarefree(): return None x, y = f.parent().gens() - return [x**(a[0] - 1) * y**(a[1] - 1) for a in P.integral_points() - if P.interior_contains(a)] + return [ + x ** (a[0] - 1) * y ** (a[1] - 1) + for a in P.integral_points() + if P.interior_contains(a) + ] def find_closest_element(item, lst): @@ -396,7 +400,7 @@ def find_closest_element(item, lst): Note that this method does no checks on the input, but will fail for inputs where the absolute value or subtraction do not make sense. """ - dists = [(item-l).abs() for l in lst] + dists = [(item - l).abs() for l in lst] return dists.index(min(dists)) @@ -450,22 +454,22 @@ def reparameterize_differential_minpoly(minpoly, z0): rational function is reduced and then the numerator is taken. Over an inexact ring this is numerically unstable, and so it is advisable to only reparameterize about infinity over an exact ring. - """ + """ P = minpoly.parent() - F = PolynomialRing(P.base_ring(), [str(v)+"bar" for v in P.gens()]) + F = PolynomialRing(P.base_ring(), [str(v) + "bar" for v in P.gens()]) try: - Inf = bool(z0==z0.parent()(Infinity)) + Inf = bool(z0 == z0.parent()(Infinity)) except TypeError: Inf = False if Inf: F = F.fraction_field() - mt = F(minpoly(F.gen(0)**(-1),-F.gen(0)**(+2)*F.gen(1))) + mt = F(minpoly(F.gen(0) ** (-1), -F.gen(0) ** (+2) * F.gen(1))) mt.reduce() mt = mt.numerator() else: - mt = minpoly(F.gen(0)+z0,F.gen(1)) + mt = minpoly(F.gen(0) + z0, F.gen(1)) return mt @@ -619,7 +623,15 @@ class RiemannSurface(object): sage: tau.algdep(6).degree() == 2 True """ - def __init__(self, f, prec=53, certification=True, differentials=None, integration_method="rigorous"): + + def __init__( + self, + f, + prec=53, + certification=True, + differentials=None, + integration_method="rigorous", + ): r""" TESTS:: @@ -631,14 +643,14 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati # Initializations. self._prec = prec self._certification = certification - if not (integration_method=="heuristic" or integration_method=="rigorous"): + if not (integration_method == "heuristic" or integration_method == "rigorous"): raise ValueError("Invalid integration method") self._integration_method = integration_method self._R = f.parent() if len(self._R.gens()) != 2: - raise ValueError('only bivariate polynomials supported.') + raise ValueError("only bivariate polynomials supported.") if f.degree() <= 1: - raise ValueError('equation must be of degree at least 2.') + raise ValueError("equation must be of degree at least 2.") z, w = self._R.gen(0), self._R.gen(1) self._CC = ComplexField(self._prec) self._RR = RealField(self._prec) @@ -659,7 +671,9 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati self._differentials = None self.genus = self._R.ideal(self.f).genus() if self.genus < 0: - raise ValueError("Singular reports negative genus. Specify differentials manually.") + raise ValueError( + "Singular reports negative genus. Specify differentials manually." + ) self.degree = self.f.degree(w) self._dfdw = self.f.derivative(w) self._dfdz = self.f.derivative(z) @@ -667,17 +681,22 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati # Coefficients of the polynomial for use in homotopy continuation. self._a0 = self._CCz(self.f.coefficient({w: self.degree})(self._CCz.gen(), 0)) self._a0roots = self._a0.roots(multiplicities=False) - self._aks = [self._CCz(self.f.coefficient({w: self.degree - k - 1}) - (self._CCz.gen(), 0)) for k in range(self.degree)] + self._aks = [ + self._CCz(self.f.coefficient({w: self.degree - k - 1})(self._CCz.gen(), 0)) + for k in range(self.degree) + ] # Compute the branch locus. Takes the square-free part of the discriminant # because of numerical issues. self.branch_locus = [] existing_factors = [x[0] for x in self._discriminant.factor()] for fac in existing_factors: - self.branch_locus += self._CCz(fac(self._CCz.gen(), 0)).roots(multiplicities=False) + self.branch_locus += self._CCz(fac(self._CCz.gen(), 0)).roots( + multiplicities=False + ) self._f_branch_locus = self.branch_locus - self._cohomology_basis_bounding_data = self._bounding_data(self.cohomology_basis(), - exact=True) + self._cohomology_basis_bounding_data = self._bounding_data( + self.cohomology_basis(), exact=True + ) RBzg, bounding_data_list = self._cohomology_basis_bounding_data minpoly_list = [bd[2] for bd in bounding_data_list] # We now want to calculate the additional branchpoints associated to @@ -687,45 +706,48 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati F = RBzg(minpoly) dF = F.derivative(RBzg.gen(1)) discriminants += [F.resultant(dF, RBzg.gen(1))] - combined_discriminant = lcm(discriminants)(*self._R.gens()) + combined_discriminant = lcm(discriminants)(*self._R.gens()) self._differentials_branch_locus = [] for x in combined_discriminant.factor(): if not x[0] in existing_factors: - self._differentials_branch_locus += self._CCz(x[0](self._CCz.gen(), - 0)).roots(multiplicities=False) + self._differentials_branch_locus += self._CCz( + x[0](self._CCz.gen(), 0) + ).roots(multiplicities=False) # We add these branchpoints to the existing. - #self.branch_locus = self.branch_locus+self._differentials_branch_locus + # self.branch_locus = self.branch_locus+self._differentials_branch_locus # We now want to also check whether Infinity is a branch point of any # of the differentials. # This will be useful when calculating the Abel-Jacobi map. - minpoly_list = [reparameterize_differential_minpoly(mp, Infinity) - for mp in minpoly_list] + minpoly_list = [ + reparameterize_differential_minpoly(mp, Infinity) for mp in minpoly_list + ] discriminants = [] for minpoly in minpoly_list: F = RBzg(minpoly) dF = F.derivative(RBzg.gen(1)) discriminants += [F.resultant(dF, RBzg.gen(1))] discriminant_about_infinity = RBzg(lcm(discriminants)) - if discriminant_about_infinity(0,0)==0: + if discriminant_about_infinity(0, 0) == 0: self._differentials_branch_locus.append(self._CC(Infinity)) # Voronoi diagram and the important points associated with it - self.voronoi_diagram = Voronoi(voronoi_ghost(self.branch_locus, - CC=self._CC)) - self._vertices = [self._CC(x0, y0) - for x0, y0 in self.voronoi_diagram.vertices] + self.voronoi_diagram = Voronoi(voronoi_ghost(self.branch_locus, CC=self._CC)) + self._vertices = [self._CC(x0, y0) for x0, y0 in self.voronoi_diagram.vertices] self._wvalues = [self.w_values(z0) for z0 in self._vertices] # We arbitrarily, but sensibly, set the basepoint to be the rightmost vertex - self._basepoint = (self._vertices.index(sorted(self._vertices, - key=lambda z:z.real())[-1]), 0) + self._basepoint = ( + self._vertices.index(sorted(self._vertices, key=lambda z: z.real())[-1]), + 0, + ) self._Sn = SymmetricGroup(range(self.degree)) self._L = {} self._integral_dict = {} self._fastcall_f = fast_callable(f, domain=self._CC) self._fastcall_dfdw = fast_callable(self._dfdw, domain=self._CC) self._fastcall_dfdz = fast_callable(self._dfdz, domain=self._CC) - self._fastcall_cohomology_basis = [fast_callable(h, domain = self._CC) - for h in self.cohomology_basis()] + self._fastcall_cohomology_basis = [ + fast_callable(h, domain=self._CC) for h in self.cohomology_basis() + ] def __repr__(self): r""" @@ -739,7 +761,10 @@ def __repr__(self): sage: RiemannSurface(f) Riemann surface defined by polynomial f = -z^4 + w^2 + 1 = 0, with 53 bits of precision """ - s = 'Riemann surface defined by polynomial f = %s = 0, with %s bits of precision' % (self.f, self._prec) + s = ( + "Riemann surface defined by polynomial f = %s = 0, with %s bits of precision" + % (self.f, self._prec) + ) return s def w_values(self, z0): @@ -772,7 +797,7 @@ def w_values(self, z0): sage: S.w_values(1) # abs tol 1e-14 [0.000000000000000] """ - return self.f(z0,self._CCw.gen(0)).roots(multiplicities=False) + return self.f(z0, self._CCw.gen(0)).roots(multiplicities=False) @cached_method def downstairs_edges(self): @@ -809,20 +834,23 @@ def downstairs_edges(self): # The regions of these points are all of the edges which don't go off # to infinity, which are exactly the ones we want. n = len(self.branch_locus) - desired_edges = [self.voronoi_diagram.regions[self.voronoi_diagram.point_region[i]] for i in range(n)] + desired_edges = [ + self.voronoi_diagram.regions[self.voronoi_diagram.point_region[i]] + for i in range(n) + ] # First construct the edges as a set because the regions will overlap # and we don't want to have two of the same edge. edges1 = set() for c in desired_edges: - for j in range(len(c)-1): - edges1.add(frozenset((c[j],c[j+1]))) - edges1.add(frozenset((c[0],c[-1]))) + for j in range(len(c) - 1): + edges1.add(frozenset((c[j], c[j + 1]))) + edges1.add(frozenset((c[0], c[-1]))) # Then make it into a list and sort it. # The sorting is important - it will make computing the monodromy group # MUCH easier. # We orient all the edges so that we go from lower to higher # numbered vertex for the continuation. - edges = [(i0,i1) if (i0 < i1) else (i1,i0) for (i0,i1) in edges1] + edges = [(i0, i1) if (i0 < i1) else (i1, i0) for (i0, i1) in edges1] edges.sort() return edges @@ -875,9 +903,18 @@ def upstairs_graph(self): True """ G = Graph(self.upstairs_edges(), immutable=True) - G.set_pos({(i,j): [self._vertices[i].real(), self._vertices[i].imag(), - self.w_values(self._vertices[i])[j].imag()] - for i in range(len(self._vertices)) for j in range(self.degree)}, dim=3) + G.set_pos( + { + (i, j): [ + self._vertices[i].real(), + self._vertices[i].imag(), + self.w_values(self._vertices[i])[j].imag(), + ] + for i in range(len(self._vertices)) + for j in range(self.degree) + }, + dim=3, + ) return G def _compute_delta(self, z1, epsilon, wvalues=None): @@ -935,22 +972,38 @@ def _compute_delta(self, z1, epsilon, wvalues=None): # For computation of rho. Need the branch locus + roots of a0. badpoints = self._f_branch_locus + self._a0roots rho = min(abs(z1 - z) for z in badpoints) / 2 - Y = max(abs(self._fastcall_dfdz(z1, wi)/self._fastcall_dfdw(z1, wi)) - for wi in wvalues) + Y = max( + abs(self._fastcall_dfdz(z1, wi) / self._fastcall_dfdw(z1, wi)) + for wi in wvalues + ) # compute M - upperbounds = [sum(ak[k] * (abs(z1) + rho)**k - for k in range(ak.degree())) - for ak in self._aks] + upperbounds = [ + sum(ak[k] * (abs(z1) + rho) ** k for k in range(ak.degree())) + for ak in self._aks + ] upperbounds.reverse() # If a0 is a constant polynomial, it is obviously bounded below. if not self._a0roots: lowerbound = self._CC(self._a0) / 2 else: - lowerbound = self._a0[self._a0.degree()]*prod(abs((zk - z1) - rho) for zk in self._a0roots) / 2 - M = 2 * max((upperbounds[k]/lowerbound).abs().nth_root(k+1) - for k in range(self.degree-1)) - return rho*(((rho*Y - epsilon)**2 + 4*epsilon*M).sqrt() - (rho*Y + epsilon))/(2*M - 2*rho*Y) + lowerbound = ( + self._a0[self._a0.degree()] + * prod(abs((zk - z1) - rho) for zk in self._a0roots) + / 2 + ) + M = 2 * max( + (upperbounds[k] / lowerbound).abs().nth_root(k + 1) + for k in range(self.degree - 1) + ) + return ( + rho + * ( + ((rho * Y - epsilon) ** 2 + 4 * epsilon * M).sqrt() + - (rho * Y + epsilon) + ) + / (2 * M - 2 * rho * Y) + ) else: # Instead, we just compute the minimum distance between branch # points and the point in question. @@ -1004,30 +1057,36 @@ def homotopy_continuation(self, edge): def path(t): return z_start * (1 - t) + z_end * t + # Primary procedure. T = ZERO currw = self.w_values(path(T)) n = len(currw) - epsilon = min([abs(currw[i] - currw[j]) for i in range(1,n) for j in range(i)])/3 - datastorage += [(T,currw,epsilon)] + epsilon = ( + min([abs(currw[i] - currw[j]) for i in range(1, n) for j in range(i)]) / 3 + ) + datastorage += [(T, currw, epsilon)] while T < ONE: - delta = self._compute_delta(path(T), epsilon, wvalues=currw)/path_length + delta = self._compute_delta(path(T), epsilon, wvalues=currw) / path_length # Move along the path by delta. T += delta # If T exceeds 1, just set it to 1 and compute. if T > ONE: - delta -= (T-ONE) + delta -= T - ONE T = ONE while True: try: - neww = self._determine_new_w(path(T),currw,epsilon) + neww = self._determine_new_w(path(T), currw, epsilon) except ConvergenceError: delta /= 2 T -= delta else: break currw = neww - epsilon = min([abs(currw[i] - currw[j]) for i in range(1,n) for j in range(i)])/3 + epsilon = ( + min([abs(currw[i] - currw[j]) for i in range(1, n) for j in range(i)]) + / 3 + ) datastorage += [(T, currw, epsilon)] return datastorage @@ -1119,8 +1178,11 @@ def _determine_new_w(self, z0, oldw, epsilon): Nnew_delta = new_delta.norm() # If we found the root exactly, or if delta only affects half the digits and # stops getting smaller, we decide that we have converged. - if (new_delta == 0) or (Nnew_delta >= Ndelta and - Ndelta.sign_mantissa_exponent()[2]+prec < wi.norm().sign_mantissa_exponent()[2]): + if (new_delta == 0) or ( + Nnew_delta >= Ndelta + and Ndelta.sign_mantissa_exponent()[2] + prec + < wi.norm().sign_mantissa_exponent()[2] + ): neww.append(wi) break delta = new_delta @@ -1128,7 +1190,9 @@ def _determine_new_w(self, z0, oldw, epsilon): wi -= delta # If we run 100 iterations without a result, terminate. else: - raise ConvergenceError("Newton iteration fails to converge after %s iterations" % j) + raise ConvergenceError( + "Newton iteration fails to converge after %s iterations" % j + ) return neww def _newton_iteration(self, z0, oldw, epsilon): @@ -1201,12 +1265,15 @@ def _newton_iteration(self, z0, oldw, epsilon): Nnew_delta = new_delta.norm() # If we found the root exactly, or if delta only affects half the digits and # stops getting smaller, we decide that we have converged. - if (new_delta == 0) or (Nnew_delta>=Ndelta and - Ndelta.sign_mantissa_exponent()[2]+prec < neww.norm().sign_mantissa_exponent()[2]): + if (new_delta == 0) or ( + Nnew_delta >= Ndelta + and Ndelta.sign_mantissa_exponent()[2] + prec + < neww.norm().sign_mantissa_exponent()[2] + ): return neww delta = new_delta Ndelta = Nnew_delta - neww-=delta + neww -= delta raise ConvergenceError("Newton iteration fails to converge") @cached_method @@ -1241,8 +1308,14 @@ def upstairs_edges(self): d_edge = (self._vertices[i0], self._vertices[i1]) # Epsilon for checking w-value later. val = self._wvalues[i1] - epsilon = min(abs(val[i] - val[n-j-1]) - for i in range(n) for j in range(n-i-1)) / 3 + epsilon = ( + min( + abs(val[i] - val[n - j - 1]) + for i in range(n) + for j in range(n - i - 1) + ) + / 3 + ) # Homotopy continuation along e. self._L[e] = self.homotopy_continuation(d_edge) homotopycont = self._L[e][-1][1] @@ -1288,15 +1361,18 @@ def _edge_permutation(self, edge): # find all upstairs edges that are lifts of the given # downstairs edge and store the corresponding indices at # start and end that label the branches upstairs. - L = [(j0, j1) for ((i0, j0), (i1, j1)) in self.upstairs_edges() - if edge == (i0, i1)] + L = [ + (j0, j1) + for ((i0, j0), (i1, j1)) in self.upstairs_edges() + if edge == (i0, i1) + ] # we should be finding exactly "degree" of these assert len(L) == self.degree # and as a corollary of how we construct them, the indices # at the start should be in order assert all(a == b[0] for a, b in enumerate(L)) return self._Sn([j1 for j0, j1 in L]) - raise ValueError('edge not in Voronoi diagram') + raise ValueError("edge not in Voronoi diagram") @cached_method def edge_permutations(self) -> dict: @@ -1340,7 +1416,7 @@ def edge_permutations(self) -> dict: """ D = {e: self._edge_permutation(e) for e in self.downstairs_edges()} for (a, b), p in list(D.items()): - D[(b, a)] = p**(-1) + D[(b, a)] = p ** (-1) return D @cached_method @@ -1392,15 +1468,19 @@ def monodromy_group(self): n = len(self.branch_locus) G = Graph(self.downstairs_edges()) # we get all the regions - loops = [self.voronoi_diagram.regions[i][:] - for i in self.voronoi_diagram.point_region] + loops = [ + self.voronoi_diagram.regions[i][:] + for i in self.voronoi_diagram.point_region + ] # and construct their Voronoi centers as complex numbers - centers = self.branch_locus + [self._CC(x, y) for x, y in self.voronoi_diagram.points[n:]] + centers = self.branch_locus + [ + self._CC(x, y) for x, y in self.voronoi_diagram.points[n:] + ] for center, loop in zip(centers, loops): if -1 in loop: # for loops involving infinity we take the finite part of the path i = loop.index(-1) - loop[:] = loop[i+1:]+loop[:i] + loop[:] = loop[i + 1 :] + loop[:i] else: # and for finite ones we close the paths loop.append(loop[0]) @@ -1415,7 +1495,7 @@ def monodromy_group(self): # infinity. There should be a unique way of doing so. inf_loops = loops[n:] inf_path = inf_loops.pop() - while (inf_loops): + while inf_loops: inf_path += (inf_loops.pop())[1:] assert inf_path[0] == inf_path[-1] @@ -1428,10 +1508,11 @@ def monodromy_group(self): SG = self._Sn for c in loops: to_loop = G.shortest_path(P0, c[0]) - to_loop_perm = SG.prod(edge_perms[(to_loop[i], to_loop[i + 1])] - for i in range(len(to_loop) - 1)) - c_perm = SG.prod(edge_perms[(c[i], c[i + 1])] - for i in range(len(c) - 1)) + to_loop_perm = SG.prod( + edge_perms[(to_loop[i], to_loop[i + 1])] + for i in range(len(to_loop) - 1) + ) + c_perm = SG.prod(edge_perms[(c[i], c[i + 1])] for i in range(len(c) - 1)) monodromy_gens.append(to_loop_perm * c_perm * ~to_loop_perm) return monodromy_gens @@ -1537,10 +1618,10 @@ def direction(center, neighbour): # score will be appropriately complemented at one of the # next vertices. - a_in = cycles[i][i0-1][0] - a_out = cycles[i][(i0+1) % len(cycles[i])][0] - b_in = cycles[j][i1-1][0] - b_out = cycles[j][(i1+1) % len(cycles[j])][0] + a_in = cycles[i][i0 - 1][0] + a_out = cycles[i][(i0 + 1) % len(cycles[i])][0] + b_in = cycles[j][i1 - 1][0] + b_out = cycles[j][(i1 + 1) % len(cycles[j])][0] # we can get the angles (and hence the rotation order) # by taking the arguments of the differences. @@ -1554,24 +1635,32 @@ def direction(center, neighbour): # problems occur with that. if (b_in != a_in) and (b_in != a_out): - if ((a_in_arg < b_in_arg < a_out_arg) + if ( + (a_in_arg < b_in_arg < a_out_arg) or (b_in_arg < a_out_arg < a_in_arg) - or (a_out_arg < a_in_arg < b_in_arg)): + or (a_out_arg < a_in_arg < b_in_arg) + ): intsum += 1 - elif ((a_out_arg < b_in_arg < a_in_arg) - or (b_in_arg < a_in_arg < a_out_arg) - or (a_in_arg < a_out_arg < b_in_arg)): + elif ( + (a_out_arg < b_in_arg < a_in_arg) + or (b_in_arg < a_in_arg < a_out_arg) + or (a_in_arg < a_out_arg < b_in_arg) + ): intsum -= 1 else: raise RuntimeError("impossible edge orientation") if (b_out != a_in) and (b_out != a_out): - if ((a_in_arg < b_out_arg < a_out_arg) + if ( + (a_in_arg < b_out_arg < a_out_arg) or (b_out_arg < a_out_arg < a_in_arg) - or (a_out_arg < a_in_arg < b_out_arg)): + or (a_out_arg < a_in_arg < b_out_arg) + ): intsum -= 1 - elif ((a_out_arg < b_out_arg < a_in_arg) - or (b_out_arg < a_in_arg < a_out_arg) - or (a_in_arg < a_out_arg < b_out_arg)): + elif ( + (a_out_arg < b_out_arg < a_in_arg) + or (b_out_arg < a_in_arg < a_out_arg) + or (a_in_arg < a_out_arg < b_out_arg) + ): intsum += 1 else: raise RuntimeError("impossible edge orientation") @@ -1598,7 +1687,9 @@ def direction(center, neighbour): if P[i][j] != 0: acycles[i] += [(P[i][j], [x for x in cycles[j]] + [cycles[j][0]])] if P[self.genus + i][j] != 0: - bcycles[i] += [(P[self.genus + i][j], [x for x in cycles[j]] + [cycles[j][0]])] + bcycles[i] += [ + (P[self.genus + i][j], [x for x in cycles[j]] + [cycles[j][0]]) + ] return acycles + bcycles def make_zw_interpolator(self, upstairs_edge, initial_continuation=None): @@ -1667,8 +1758,8 @@ def w_interpolate(t): w1 = w1[windex] t2, w2, _ = currL[i + 1] w2 = w2[windex] - z0 = (1-t)*z_start+t*z_end - w0 = self._CC(((t2-t)*w1+(t-t1)*w2)/(t2-t1)) + z0 = (1 - t) * z_start + t * z_end + w0 = self._CC(((t2 - t) * w1 + (t - t1) * w2) / (t2 - t1)) try: desired_result = self._newton_iteration(z0, w0, epsilon) except ConvergenceError: @@ -1679,7 +1770,7 @@ def w_interpolate(t): tnew = t while True: tnew = (t1 + tnew) / 2 - znew = (1-tnew)*z_start+tnew*z_end + znew = (1 - tnew) * z_start + tnew * z_end try: neww1 = self._determine_new_w(znew, currL[i][1], epsilon) except ConvergenceError: @@ -1690,6 +1781,7 @@ def w_interpolate(t): # once the loop has succeeded we insert our new value t1 = tnew currL.insert(i + 1, (t1, neww1, epsilon)) + return w_interpolate, (z_end - z_start) def simple_vector_line_integral(self, upstairs_edge, differentials): @@ -1739,8 +1831,10 @@ def simple_vector_line_integral(self, upstairs_edge, differentials): # for users. try: initial_continuation = self._L[d_edge] - upstairs_edge = ((self._vertices[d_edge[0]], upstairs_edge[0][1]), - (self._vertices[d_edge[1]], )) + upstairs_edge = ( + (self._vertices[d_edge[0]], upstairs_edge[0][1]), + (self._vertices[d_edge[1]],), + ) except KeyError: initial_continuation = self.homotopy_continuation(d_edge) w_of_t, Delta_z = self.make_zw_interpolator(upstairs_edge, initial_continuation) @@ -1782,7 +1876,7 @@ def cohomology_basis(self, option=1): """ if self.genus == 0: self._differentials = [] - return self._differentials #[0] + return self._differentials # [0] if self._differentials is None: # Computes differentials from the adjointIdeal using Singular # First we homogenize @@ -1795,26 +1889,31 @@ def cohomology_basis(self, option=1): # We load the relevant functionality into singularlib import sage.libs.singular.function_factory + sage.libs.singular.function_factory.lib("paraplanecurves.lib") adjointIdeal = sage.libs.singular.function.singular_function("adjointIdeal") libsing_options = sage.libs.singular.option.LibSingularVerboseOptions() # We compute the adjoint ideal (note we need to silence "redefine") - redef_save = libsing_options['redefine'] + redef_save = libsing_options["redefine"] try: - libsing_options['redefine'] = False + libsing_options["redefine"] = False J = adjointIdeal(fnew, option) finally: - libsing_options['redefine'] = redef_save + libsing_options["redefine"] = redef_save # We are interested in the (degree-3) subspace of the adjoint ideal. # We compute this by intersecting with (Z,W,U)^(degree-3). Then the # lowest degree generators are a basis of the relevant subspace. d = fnew.total_degree() - J2 = k.ideal(J).intersection(k.ideal([k.gen(0), k.gen(1), k.gen(2)])**(d - 3)) + J2 = k.ideal(J).intersection( + k.ideal([k.gen(0), k.gen(1), k.gen(2)]) ** (d - 3) + ) generators = [dehom(c) for c in J2.gens() if c.degree() == d - 3] if len(generators) != self.genus: - raise ValueError("computed regular differentials do not match stored genus") + raise ValueError( + "computed regular differentials do not match stored genus" + ) self._differentials = generators return self._differentials @@ -1892,29 +1991,33 @@ def _bounding_data(self, differentials, exact=False): # This copies previous work by NB, outputting the zipped list required # for a certified line integral. RB = self._R.base_ring() - P = PolynomialRing(RB, 'Z') + P = PolynomialRing(RB, "Z") k = P.fraction_field() - KP = PolynomialRing(k, 'W') # W->fraction field + KP = PolynomialRing(k, "W") # W->fraction field fZW = self.f(P.gen(0), KP.gen(0)) - L = k.extension(fZW, 'Wb') + L = k.extension(fZW, "Wb") dfdw_L = self._dfdw(P.gen(0), L.gen(0)) - integrand_list = [h/self._dfdw for h in differentials] + integrand_list = [h / self._dfdw for h in differentials] # minpoly_univ gives the minimal polynomial for h, in variable x, with # coefficients given by polynomials with coefficients in P (i.e. # rational polynomials in Z). - minpoly_univ = [(h(P.gen(0), L.gen(0))/dfdw_L).minpoly().numerator() - for h in differentials] - RBzg = PolynomialRing(RB, ['z', 'g']) + minpoly_univ = [ + (h(P.gen(0), L.gen(0)) / dfdw_L).minpoly().numerator() + for h in differentials + ] + RBzg = PolynomialRing(RB, ["z", "g"]) # The following line changes the variables in these minimal polynomials # as Z -> z, x -> G, then evaluates at G = QQzg.gens(1) ( = g ) - RBzgG = PolynomialRing(RBzg, 'G') - minpoly_list = [RBzgG([c(RBzg.gen(0)) for c in list(h)])(RBzg.gen(1)) - for h in minpoly_univ] + RBzgG = PolynomialRing(RBzg, "G") + minpoly_list = [ + RBzgG([c(RBzg.gen(0)) for c in list(h)])(RBzg.gen(1)) for h in minpoly_univ + ] # h(z,g)=0 --> dg/dz = - dhdz/dhdg - dgdz_list = [-h.derivative(RBzg.gen(0))/h.derivative(RBzg.gen(1)) - for h in minpoly_list] + dgdz_list = [ + -h.derivative(RBzg.gen(0)) / h.derivative(RBzg.gen(1)) for h in minpoly_list + ] - CCzg = PolynomialRing(self._CC, ['z','g']) + CCzg = PolynomialRing(self._CC, ["z", "g"]) CCminpoly_list = [CCzg(h) for h in minpoly_list] a0_list = [P(h.leading_coefficient()) for h in minpoly_univ] @@ -1922,10 +2025,18 @@ def _bounding_data(self, differentials, exact=False): # is embedded into CC, it has characteristic 0, and so we know the # irreducible factors are all separable, i.e. the roots have multiplicity # one. - a0_info = [(self._CC(a0.leading_coefficient()), - flatten([self._CCz(F).roots(multiplicities=False)*m - for F, m in a0.factor()])) - for a0 in a0_list] + a0_info = [ + ( + self._CC(a0.leading_coefficient()), + flatten( + [ + self._CCz(F).roots(multiplicities=False) * m + for F, m in a0.factor() + ] + ), + ) + for a0 in a0_list + ] if exact: return RBzg, list(zip(integrand_list, dgdz_list, minpoly_list, a0_info)) else: @@ -2024,22 +2135,25 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): # compatibility for users. try: initial_continuation = self._L[d_edge] - upstairs_edge = ((self._vertices[d_edge[0]], upstairs_edge[0][1]), - (self._vertices[d_edge[1]], )) + upstairs_edge = ( + (self._vertices[d_edge[0]], upstairs_edge[0][1]), + (self._vertices[d_edge[1]],), + ) except KeyError: initial_continuation = self.homotopy_continuation(d_edge) - zwt, z1_minus_z0 = self.make_zw_interpolator(upstairs_edge, - initial_continuation) + zwt, z1_minus_z0 = self.make_zw_interpolator( + upstairs_edge, initial_continuation + ) z0 = zwt(0)[0] z1 = zwt(1)[0] # list of (centre, radius) pairs that still need to be processed - ball_stack = [(self._RR(1/2), self._RR(1/2), 0)] - alpha = self._RR(912/1000) + ball_stack = [(self._RR(1 / 2), self._RR(1 / 2), 0)] + alpha = self._RR(912 / 1000) # alpha set manually for scaling purposes. Basic benchmarking shows # that ~0.9 is a sensible value. - E_global = self._RR(2)**(-self._prec+3) + E_global = self._RR(2) ** (-self._prec + 3) # Output will iteratively store the output of the integral. V = VectorSpace(self._CC, len(differentials)) @@ -2064,45 +2178,54 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): # possible to cover it entirely in a ball which encompasses an appropriate # ellipse. def local_N(ct, rt): - cz = (1-ct)*z0+ct*z1 # This is the central z-value of our ball. - distances = [(cz-b).abs() for b in self.branch_locus] + cz = (1 - ct) * z0 + ct * z1 # This is the central z-value of our ball. + distances = [(cz - b).abs() for b in self.branch_locus] rho_z = min(distances) - rho_t = rho_z/(z1_minus_z0).abs() - rho_t = alpha*rho_t+(1-alpha)*rt # sqrt(rho_t*rt) could also work - rho_z = rho_t*(z1-z0).abs() - delta_z = (alpha*rho_t+(1-alpha)*rt)*(z1_minus_z0).abs() - expr = rho_t/rt+((rho_t/rt)**2-1).sqrt() # Note this is really exp(arcosh(rho_t/rt)) + rho_t = rho_z / (z1_minus_z0).abs() + rho_t = alpha * rho_t + (1 - alpha) * rt # sqrt(rho_t*rt) could also work + rho_z = rho_t * (z1 - z0).abs() + delta_z = (alpha * rho_t + (1 - alpha) * rt) * (z1_minus_z0).abs() + expr = ( + rho_t / rt + ((rho_t / rt) ** 2 - 1).sqrt() + ) # Note this is really exp(arcosh(rho_t/rt)) Ni = 3 cw = zwt(ct)[1] - for g, dgdz, minpoly,(a0lc,a0roots) in bounding_data_list: - z_1 = a0lc.abs()*prod((cz-r).abs()-rho_z for r in a0roots) + for g, dgdz, minpoly, (a0lc, a0roots) in bounding_data_list: + z_1 = a0lc.abs() * prod((cz - r).abs() - rho_z for r in a0roots) n = minpoly.degree(CCzg.gen(1)) - ai_new = [(minpoly.coefficient({CCzg.gen(1):i}))(z=cz+self._CCz.gen(0)) - for i in range(n)] - ai_pos = [self._RRz([c.abs() for c in h.list()]) - for h in ai_new] - m = [a(rho_z)/z_1 for a in ai_pos] + ai_new = [ + (minpoly.coefficient({CCzg.gen(1): i}))(z=cz + self._CCz.gen(0)) + for i in range(n) + ] + ai_pos = [self._RRz([c.abs() for c in h.list()]) for h in ai_new] + m = [a(rho_z) / z_1 for a in ai_pos] l = len(m) - M_tilde = 2*max((m[i].abs())**(1/self._RR(l-i)) - for i in range(l)) - cg = g(cz,cw) - cdgdz = dgdz(cz,cg) - Delta = delta_z*cdgdz.abs() + (delta_z**2)*M_tilde/(rho_z*(rho_z-delta_z)) + M_tilde = 2 * max( + (m[i].abs()) ** (1 / self._RR(l - i)) for i in range(l) + ) + cg = g(cz, cw) + cdgdz = dgdz(cz, cg) + Delta = delta_z * cdgdz.abs() + (delta_z**2) * M_tilde / ( + rho_z * (rho_z - delta_z) + ) M = Delta - N_required = ((M*(self._RR.pi()+64/(15*(expr**2-1)))/E_global).log()/(2*expr.log())).ceil() + N_required = ( + (M * (self._RR.pi() + 64 / (15 * (expr**2 - 1))) / E_global).log() + / (2 * expr.log()) + ).ceil() Ni = max(Ni, N_required) return Ni while ball_stack: ct, rt, lN = ball_stack.pop() - ncts = [ct-rt/2, ct+rt/2] - nrt = rt/2 + ncts = [ct - rt / 2, ct + rt / 2] + nrt = rt / 2 if not lN: - cz = (1-ct)*z0+ct*z1 - distances = [(cz-b).abs() for b in self.branch_locus] + cz = (1 - ct) * z0 + ct * z1 + distances = [(cz - b).abs() for b in self.branch_locus] rho_z = min(distances) - rho_t = rho_z/(z1_minus_z0).abs() + rho_t = rho_z / (z1_minus_z0).abs() if rho_t <= rt: ball_stack.append((ncts[0], nrt, 0)) @@ -2118,20 +2241,20 @@ def local_N(ct, rt): ball_stack.append((ncts[1], nrt, nNs[1])) continue - if lN % 2 and not lN==3: - lN += 1 + if lN % 2 and not lN == 3: + lN += 1 - ct_minus_rt = ct-rt - two_rt = 2*rt + ct_minus_rt = ct - rt + two_rt = 2 * rt def integrand(t): zt, wt = zwt(ct_minus_rt + t * two_rt) dfdwt = self._fastcall_dfdw(zt, wt) return V([h(zt, wt) / dfdwt for h in differentials]) - output += two_rt*integrate_vector_N(integrand, self._prec, lN) + output += two_rt * integrate_vector_N(integrand, self._prec, lN) - return output*z1_minus_z0 + return output * z1_minus_z0 def matrix_of_integral_values(self, differentials, integration_method="heuristic"): r""" @@ -2191,9 +2314,9 @@ def normalize_pairs(L): else: R.append((L[i + 1], L[i])) return R + occurring_edges = set() - occurring_edges.update(*[normalize_pairs(p[1]) for h in cycles - for p in h]) + occurring_edges.update(*[normalize_pairs(p[1]) for h in cycles for p in h]) if differentials is self.cohomology_basis(): fcd = self._fastcall_cohomology_basis @@ -2293,8 +2416,11 @@ def riemann_matrix(self): True """ PeriodMatrix = self.period_matrix() - Am = PeriodMatrix[0:self.genus,0:self.genus] - RM = numerical_inverse(Am)*PeriodMatrix[0:self.genus,self.genus:2*self.genus] + Am = PeriodMatrix[0 : self.genus, 0 : self.genus] + RM = ( + numerical_inverse(Am) + * PeriodMatrix[0 : self.genus, self.genus : 2 * self.genus] + ) return RM def plot_paths(self): @@ -2316,6 +2442,7 @@ def plot_paths(self): Graphics object consisting of 2 graphics primitives """ from sage.plot.point import point2d + P = [] # trigger the computation of the homology basis, so that self._L is present @@ -2327,6 +2454,7 @@ def plot_paths(self): def path(t): return (1 - t) * z0 + t * z1 + T = self._L[e] P += [path(t[0]) for t in T] return point2d(P, size=1) + point2d(self.branch_locus, color="red") @@ -2352,6 +2480,7 @@ def plot_paths3d(self, thickness=0.01): """ from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes2 import point3d, line3d + P = Graphics() # trigger the computation of the homology basis, so that @@ -2363,16 +2492,24 @@ def plot_paths3d(self, thickness=0.01): z1 = self._vertices[e[1]] def path(t): - z = (1-t)*z0+t*z1 - return (z.real_part(),z.imag_part()) + z = (1 - t) * z0 + t * z1 + return (z.real_part(), z.imag_part()) + T = self._L[e] color = "blue" for i in range(self.degree): - P += line3d([path(t[0])+(t[1][i].imag_part(),) for t in T],color=color,thickness=thickness) - for z,ws in zip(self._vertices,self._wvalues): + P += line3d( + [path(t[0]) + (t[1][i].imag_part(),) for t in T], + color=color, + thickness=thickness, + ) + for z, ws in zip(self._vertices, self._wvalues): for w in ws: - P += point3d([z.real_part(), z.imag_part(), w.imag_part()], - color="purple", size=20) + P += point3d( + [z.real_part(), z.imag_part(), w.imag_part()], + color="purple", + size=20, + ) return P def endomorphism_basis(self, b=None, r=None): @@ -2416,7 +2553,7 @@ def endomorphism_basis(self, b=None, r=None): """ M = self.riemann_matrix() - return integer_matrix_relations(M,M,b,r) + return integer_matrix_relations(M, M, b, r) def homomorphism_basis(self, other, b=None, r=None): r""" @@ -2455,7 +2592,7 @@ def homomorphism_basis(self, other, b=None, r=None): """ M1 = self.riemann_matrix() M2 = other.riemann_matrix() - return integer_matrix_relations(M2,M1,b,r) + return integer_matrix_relations(M2, M1, b, r) def tangent_representation_numerical(self, Rs, other=None): r""" @@ -2550,7 +2687,7 @@ def tangent_representation_algebraic(self, Rs, other=None, epscomp=None): True """ if not epscomp: - epscomp = 2**(-self._prec + 30) + epscomp = 2 ** (-self._prec + 30) QQalg = QQ.algebraic_closure() def polynomialize_element(alpha): @@ -2568,7 +2705,7 @@ def algebraize_element(alpha): rt = tup[0] if (alpha - CC(rt)).abs() < epscomp: return rt - raise AssertionError('No close root found while algebraizing') + raise AssertionError("No close root found while algebraizing") def algebraize_matrices(Ts): nr = Ts[0].nrows() @@ -2579,7 +2716,7 @@ def algebraize_matrices(Ts): L = eltsAlg[0].parent() TsAlgL = [] for i in range(len(Ts)): - TAlgL = [eltsAlg[j] for j in range(i*nr*nc, (i + 1)*nr*nc)] + TAlgL = [eltsAlg[j] for j in range(i * nr * nc, (i + 1) * nr * nc)] TsAlgL.append(Matrix(L, nr, nc, TAlgL)) return TsAlgL @@ -2610,13 +2747,17 @@ def rosati_involution(self, R): sage: S.rosati_involution(S.rosati_involution(Rs[1])) == Rs[1] True """ + def standard_symplectic_matrix(n): one = Matrix.identity(n) zero = Matrix.zero(n) return Matrix.block([[zero, -one], [one, zero]]) + g = self.genus - if not(R.nrows() == 2 * g == R.ncols()): - raise AssertionError("Matrix is not the homology representation of an endomorphism") + if not (R.nrows() == 2 * g == R.ncols()): + raise AssertionError( + "Matrix is not the homology representation of an endomorphism" + ) J = standard_symplectic_matrix(g) return -J * R.transpose() * J @@ -2674,7 +2815,7 @@ def symplectic_isomorphisms(self, other=None, hom_basis=None, b=None, r=None): Rs = self.homomorphism_basis(other=other, b=b, r=r) r = len(Rs) g = self.genus - A = PolynomialRing(QQ, r, 'x') + A = PolynomialRing(QQ, r, "x") gensA = A.gens() # Use that the trace is positive definite; we could also put this as an # extra condition when determining the endomorphism basis to speed up @@ -2682,10 +2823,14 @@ def symplectic_isomorphisms(self, other=None, hom_basis=None, b=None, r=None): R = sum(gensA[i] * Rs[i].change_ring(A) for i in range(r)) tr = (R * self.rosati_involution(R)).trace() # Condition tr = 2 g creates ellipsoid - M = Matrix(ZZ, r, r, [tr.derivative(gen1).derivative(gen2) - for gen1 in gensA for gen2 in gensA]) - vs = M.__pari__().qfminim(4*g)[2].sage().transpose() - vs = [v for v in vs if v * M * v == 4*g] + M = Matrix( + ZZ, + r, + r, + [tr.derivative(gen1).derivative(gen2) for gen1 in gensA for gen2 in gensA], + ) + vs = M.__pari__().qfminim(4 * g)[2].sage().transpose() + vs = [v for v in vs if v * M * v == 4 * g] vs += [-v for v in vs] RsIso = [] for v in vs: @@ -2749,7 +2894,9 @@ def __add__(self, other): """ return RiemannSurfaceSum([self, other]) - def _integrate_differentials_iteratively(self, upstairs_edge, cutoff_individually=False, raise_errors=True, prec=None): + def _integrate_differentials_iteratively( + self, upstairs_edge, cutoff_individually=False, raise_errors=True, prec=None + ): r""" Integrate the cohomology basis along a straight line edge. @@ -2822,110 +2969,126 @@ def _integrate_differentials_iteratively(self, upstairs_edge, cutoff_individuall z_start = self._CC(z_start) z_end = self._CC(z_end) - if z_end==self._CC(Infinity): + if z_end == self._CC(Infinity): raise NotImplementedError _, bounding_data_list = self._cohomology_basis_bounding_data mp_list = [bd[2] for bd in bounding_data_list] # Parameterise so zbar=0 corresponds to z=z_start - mp_list = [reparameterize_differential_minpoly(mp, z_start) - for mp in mp_list] + mp_list = [reparameterize_differential_minpoly(mp, z_start) for mp in mp_list] # Depending on whether we have reparameterized about infinity or not, # we initialise some values we will need in the calculation, inclduing # the function `initalize', which at a given value of zbar, calculates - # the starting value for the i-th differential so it can be iterated - # from via homotopy continuation. - if z_start==self._CC(Infinity): - CCzg = PolynomialRing(self._CC, ['zbar','gbar']) + # the starting value for the i-th differential so it can be iterated + # from via homotopy continuation. + if z_start == self._CC(Infinity): + CCzg = PolynomialRing(self._CC, ["zbar", "gbar"]) mp_list = [CCzg(mp) for mp in mp_list] - J = 1/z_end - endscale = -z_end**(-2) + J = 1 / z_end + endscale = -(z_end ** (-2)) def initialise(z, i): - DF = ComplexField(2*self._prec) - DFw = PolynomialRing(DF,'wbar') + DF = ComplexField(2 * self._prec) + DFw = PolynomialRing(DF, "wbar") z = DF(z) - R = DF(z**(-1)) + R = DF(z ** (-1)) wR = DFw(self.f(R, DFw.gen(0))).roots(multiplicities=False)[w_start] - newg = -R**2*self.cohomology_basis()[i](R, wR)/self._dfdw(R, wR) - err = mp_list[i](z,newg).abs() - if err>tau: + newg = -(R**2) * self.cohomology_basis()[i](R, wR) / self._dfdw(R, wR) + err = mp_list[i](z, newg).abs() + if err > tau: rs = mp_list[i](z, DFw.gen(0)).roots(multiplicities=False) sb = find_closest_element(newg, rs) newg = rs[sb] return newg + else: CCzg = mp_list[0].parent() - J = z_end-z_start + J = z_end - z_start endscale = 1 def initialise(z, i): - newg = self.cohomology_basis()[i](z_start, w_start)/self._dfdw(z_start, w_start) + newg = self.cohomology_basis()[i](z_start, w_start) / self._dfdw( + z_start, w_start + ) err = mp_list[i](z, newg).abs() - if err>tau: + if err > tau: rs = mp_list[i](z, self._CCw.gen(0)).roots(multiplicities=False) sb = find_closest_element(newg, rs) newg = rs[sb] return newg - # As multiple calls of the minimal polynomial and it's derivative will - # be required for the homotopy continuaiton, we create fast-callable - # versions of these. + # As multiple calls of the minimal polynomial and it's derivative will + # be required for the homotopy continuaiton, we create fast-callable + # versions of these. fc_mp_list = [fast_callable(mp, domain=self._CC) for mp in mp_list] - fc_dmp_list = [fast_callable(mp.derivative(CCzg.gen(1)), domain=self._CC) - for mp in mp_list] + fc_dmp_list = [ + fast_callable(mp.derivative(CCzg.gen(1)), domain=self._CC) for mp in mp_list + ] if prec is None: prec = self._prec # tau here is playing the role of the desired error. - tau = self._RR(2)**(-prec+3) + tau = self._RR(2) ** (-prec + 3) one = self._RR(1) - la = self._RR.pi()/2 + la = self._RR.pi() / 2 - # Cutoffs are used to allow us to not have to integrate as close into - # a singularity as we might otherwise have to, by knowing that we can - # truncate the integration interval and only introduce a finite error + # Cutoffs are used to allow us to not have to integrate as close into + # a singularity as we might otherwise have to, by knowing that we can + # truncate the integration interval and only introduce a finite error # that can be bounded by knowledge of the asymptotics of the integrands, - # which we have from their minimal polynomials. This is really a + # which we have from their minimal polynomials. This is really a # precursor to what would be ideal to implement eventually, namely - # a method that uses Puiseux series to integrate into singularities. - # We allow for cutoffs to be tailored to each integrand, or we take a - # uniform value. + # a method that uses Puiseux series to integrate into singularities. + # We allow for cutoffs to be tailored to each integrand, or we take a + # uniform value. if cutoff_individually is None: cutoffs = [0] cutoff_individually = False else: cutoffs = [] - A = PolynomialRing(self._CC,'xyz') + A = PolynomialRing(self._CC, "xyz") aes = [] for mp in mp_list: d = mp.dict() - mp = sum([d[k]*CCzg.gen(0)**k[0]*CCzg.gen(1)**k[1] - for k in d.keys() if d[k].abs()>tau]) - cst = min([iz for (iz, ig) in d.keys() if ig==0]) - a = QQ(max([(cst-iz)/ig for (iz,ig) in d.keys() if ig>0])) - sum_coeffs = sum([d[k]*A.gen(0)**k[1] for k in d.keys() - if ((k[1]==0 and k[0]==cst) or k[1]*a+k[0]-cst==0)]) + mp = sum( + [ + d[k] * CCzg.gen(0) ** k[0] * CCzg.gen(1) ** k[1] + for k in d.keys() + if d[k].abs() > tau + ] + ) + cst = min([iz for (iz, ig) in d.keys() if ig == 0]) + a = QQ(max([(cst - iz) / ig for (iz, ig) in d.keys() if ig > 0])) + sum_coeffs = sum( + [ + d[k] * A.gen(0) ** k[1] + for k in d.keys() + if ((k[1] == 0 and k[0] == cst) or k[1] * a + k[0] - cst == 0) + ] + ) G = max([r.abs() for r in sum_coeffs.roots(multiplicities=False)]) - cutoffs.append(((a+1)*tau/G)**(1/self._CC(a+1))/J.abs()) + cutoffs.append(((a + 1) * tau / G) ** (1 / self._CC(a + 1)) / J.abs()) aes.append(a) - cutoff_individually = bool(not all(ai<=0 for ai in aes) and cutoff_individually) + cutoff_individually = bool( + not all(ai <= 0 for ai in aes) and cutoff_individually + ) - # The `raise_errors' variable toggles what we do in the event that - # newton iteration hasn't converged to the desired precision in a - # fixed number of steps, here set to 100. + # The `raise_errors' variable toggles what we do in the event that + # newton iteration hasn't converged to the desired precision in a + # fixed number of steps, here set to 100. # If the default value of True is taken, then the failure to converge - # raises an error. If the value of False is taken, this failure to - # converge happens silently, thus allowing the user to get *an* - # answer out of the integration, but numerical imprecision is to be - # expected. + # raises an error. If the value of False is taken, this failure to + # converge happens silently, thus allowing the user to get *an* + # answer out of the integration, but numerical imprecision is to be + # expected. if raise_errors: - n_steps = self._prec-1 + n_steps = self._prec - 1 def error_handle(out): raise ConvergenceError("Newton iteration fails to converge") + else: n_steps = 15 @@ -2934,28 +3097,28 @@ def error_handle(out): V = VectorSpace(self._CC, self.genus) h = one - Nh = (-lambert_w(-1,-tau/2)/la).log().ceil() - h0 = Nh*h + Nh = (-lambert_w(-1, -tau / 2) / la).log().ceil() + h0 = Nh * h # Depending on how the cutoffs were defined, we now create the function # which calculates the integrand we want to integrate via double- - # exponential methods. This will get the value at the next node by + # exponential methods. This will get the value at the next node by # homotopy-continuing from the last node value. There is also a slight - # technical condition which implements the cutoffs. + # technical condition which implements the cutoffs. if cutoff_individually: z_fc_list = list(zip(fc_mp_list, fc_dmp_list)) def fv(hj, previous_estimate_and_validity): - u2 = la*hj.sinh() - t = 1/(2*u2.exp()*u2.cosh()) - z0 = J*t + u2 = la * hj.sinh() + t = 1 / (2 * u2.exp() * u2.cosh()) + z0 = J * t outg = [] - valid = self.genus*[True] + valid = self.genus * [True] previous_estimate, validity = previous_estimate_and_validity for i in range(self.genus): co = cutoffs[i] pv = validity[i] - if t= Ndelta and - (Ndelta.sign_mantissa_exponent()[2] - +self._prec) < newg.norm().sign_mantissa_exponent()[2]): + if (new_delta == 0) or ( + Nnew_delta >= Ndelta + and (Ndelta.sign_mantissa_exponent()[2] + self._prec) + < newg.norm().sign_mantissa_exponent()[2] + ): outg.append(newg) break delta = new_delta Ndelta = Nnew_delta - newg-=delta - if j==99: + newg -= delta + if j == 99: outg.append(error_handle(newg)) fj = V(outg) - u1 = la*hj.cosh() - w = u1/(2*u2.cosh()**2) - return (fj, valid), w*fj + u1 = la * hj.cosh() + w = u1 / (2 * u2.cosh() ** 2) + return (fj, valid), w * fj - f0, v0 = fv(h0, (self.genus*[0], self.genus*[False])) + f0, v0 = fv(h0, (self.genus * [0], self.genus * [False])) else: cutoffs.append(1) cutoff = min(cutoffs) - cutoff_z = J*cutoff + cutoff_z = J * cutoff J -= cutoff_z def fv(hj, previous_estimate): - u2 = la*hj.sinh() - t = 1/(2*u2.exp()*u2.cosh()) - z0 = cutoff_z+J*t + u2 = la * hj.sinh() + t = 1 / (2 * u2.exp() * u2.cosh()) + z0 = cutoff_z + J * t outg = [] for F, dF, oldg in zip(fc_mp_list, fc_dmp_list, previous_estimate): delta = F(z0, oldg) / dF(z0, oldg) @@ -3003,43 +3168,45 @@ def fv(hj, previous_estimate): for j in range(100): new_delta = F(z0, newg) / dF(z0, newg) Nnew_delta = new_delta.norm() - if (new_delta == 0) or (Nnew_delta >= Ndelta and - (Ndelta.sign_mantissa_exponent()[2] - +self._prec) < newg.norm().sign_mantissa_exponent()[2]): + if (new_delta == 0) or ( + Nnew_delta >= Ndelta + and (Ndelta.sign_mantissa_exponent()[2] + self._prec) + < newg.norm().sign_mantissa_exponent()[2] + ): outg.append(newg) break delta = new_delta Ndelta = Nnew_delta - newg-=delta - if j==99: + newg -= delta + if j == 99: outg.append(error_handle(newg)) fj = V(outg) - u1 = la*hj.cosh() - w = u1/(2*u2.cosh()**2) - return fj, w*fj + u1 = la * hj.cosh() + w = u1 / (2 * u2.cosh() ** 2) + return fj, w * fj - u1, u2 = (la*h0.cosh(),la*h0.sinh()) - y, w = (1/(2*u2.exp()*u2.cosh()), u1/(2*u2.cosh()**2)) - z0 = cutoff_z+J*y + u1, u2 = (la * h0.cosh(), la * h0.sinh()) + y, w = (1 / (2 * u2.exp() * u2.cosh()), u1 / (2 * u2.cosh() ** 2)) + z0 = cutoff_z + J * y f0 = [initialise(z0, i) for i in range(self.genus)] f0 = V(f0) - v0 = w*f0 + v0 = w * f0 D3_over_tau = v0.norm(Infinity) D4 = D3_over_tau results = [] # we now calculate the integral via double-exponential methods - # repeatedly halving the step size and then using a heuristic + # repeatedly halving the step size and then using a heuristic # convergence check. We again use the error_handle function to deal - # with the case where we exceed the maximum number of steps allowed, + # with the case where we exceed the maximum number of steps allowed, # currently set by to make sure the step size does not fall below the - # resolution set by the binary precision used. + # resolution set by the binary precision used. for k in range(n_steps): hj = h0 val = v0 fj = f0 - for j in range(2*Nh): + for j in range(2 * Nh): hj -= h try: fj, v = fv(hj, fj) @@ -3047,24 +3214,33 @@ def fv(hj, previous_estimate): break D3_over_tau = max(v.norm(Infinity), D3_over_tau) val += v - if j==2*Nh-1: - results.append(h*val) + if j == 2 * Nh - 1: + results.append(h * val) D4 = max(D4, v.norm(Infinity)) - if len(results)>2: + if len(results) > 2: if results[-1] == results[-2] or results[2] == results[-3]: D = tau else: - D1 = (results[-1]-results[-2]).norm(Infinity) - D2 = (results[-1]-results[-3]).norm(Infinity) - D = min(one, max(D1**(D1.log()/D2.log()),D2**2,tau*D3_over_tau,D4,tau)) + D1 = (results[-1] - results[-2]).norm(Infinity) + D2 = (results[-1] - results[-3]).norm(Infinity) + D = min( + one, + max( + D1 ** (D1.log() / D2.log()), + D2**2, + tau * D3_over_tau, + D4, + tau, + ), + ) if D <= tau: if cutoff_individually: fj = fj[0] - return J*results[-1], endscale*fj + return J * results[-1], endscale * fj h /= 2 Nh *= 2 - return error_handle((J*results[-1], endscale*fj)) + return error_handle((J * results[-1], endscale * fj)) def _aj_based(self, P): r""" @@ -3115,7 +3291,7 @@ def _aj_based(self, P): ##### fcd = self._fastcall_cohomology_basis - if self._integration_method=="heuristic": + if self._integration_method == "heuristic": line_int = lambda edge: self.simple_vector_line_integral(edge, fcd) else: bd = self._cohomology_basis_bounding_data @@ -3125,64 +3301,88 @@ def _aj_based(self, P): zP, wP = P try: - Inf = bool(zP==zP.parent()(Infinity)) + Inf = bool(zP == zP.parent()(Infinity)) except TypeError: Inf = False if Inf: zV = self._vertices[B[0]] - if zV==0: + if zV == 0: zV += 1 upstairs_edge = (P, zV) ci = bool(self._CC(Infinity) in self._differentials_branch_locus) - AJ, endgs = self._integrate_differentials_iteratively(upstairs_edge, - cutoff_individually=ci) + AJ, endgs = self._integrate_differentials_iteratively( + upstairs_edge, cutoff_individually=ci + ) AJ = -AJ g0e = endgs[0] ws = self.w_values(zV) - g0s = [self.cohomology_basis()[0](zV, wi)/self._dfdw(zV, wi) for wi in ws] + g0s = [self.cohomology_basis()[0](zV, wi) / self._dfdw(zV, wi) for wi in ws] W_index = find_closest_element(g0e, g0s) - if (g0e - self.cohomology_basis()[0](zV, ws[W_index])/self._dfdw(zV, ws[W_index])).abs()>1e-10: - raise ConvergenceError("Integrand continuation failed to get representative values, higher precision required.") + if ( + g0e + - self.cohomology_basis()[0](zV, ws[W_index]) + / self._dfdw(zV, ws[W_index]) + ).abs() > 1e-10: + raise ConvergenceError( + "Integrand continuation failed to get representative values, higher precision required." + ) V_index = B[0] else: zP = self._CC(zP) wP = self._CC(wP) V_index = find_closest_element(zP, self._vertices) - if zP==self._vertices[V_index]: + if zP == self._vertices[V_index]: W_index = find_closest_element(wP, self._wvalues[V_index]) AJ = 0 else: b_index = find_closest_element(zP, self.branch_locus) b = self.branch_locus[b_index] - #bl = self.branch_locus+self._differentials_branch_locus - #b_index = find_closest_element(zP, bl) - #b = bl[b_index] + # bl = self.branch_locus+self._differentials_branch_locus + # b_index = find_closest_element(zP, bl) + # b = bl[b_index] scale = max(b.abs() for b in self.branch_locus) - d1 = self._CC(1e-2)*scale + d1 = self._CC(1e-2) * scale # We choose the first vertex we want to go to. # If the closest vertex is closer than the nearest branch point, just take that vertex # otherwise we need something smarter. - delta = self._RR(2)**(-self._prec+1) - if not ((zP-self._vertices[V_index]).abs() < (zP-b).abs() or (zP-b).abs()<=delta): - region = self.voronoi_diagram.regions[self.voronoi_diagram.point_region[b_index]] - args = [(self._vertices[i]-zP).argument() - (b-zP).argument() for i in region] - suitable_vertex_indices = [region[i] - for i in range(len(region)) if args[i].abs()-self._RR.pi()/2>=-self._RR(1e-15)] - suitable_vertices = [self._vertices[i] for i in suitable_vertex_indices] - if suitable_vertices==[]: - raise ValueError("There is no satisfactory choice of V for zP={}".format(zP)) - V_index = suitable_vertex_indices[find_closest_element(zP, suitable_vertices)] + delta = self._RR(2) ** (-self._prec + 1) + if not ( + (zP - self._vertices[V_index]).abs() < (zP - b).abs() + or (zP - b).abs() <= delta + ): + region = self.voronoi_diagram.regions[ + self.voronoi_diagram.point_region[b_index] + ] + args = [ + (self._vertices[i] - zP).argument() - (b - zP).argument() + for i in region + ] + suitable_vertex_indices = [ + region[i] + for i in range(len(region)) + if args[i].abs() - self._RR.pi() / 2 >= -self._RR(1e-15) + ] + suitable_vertices = [ + self._vertices[i] for i in suitable_vertex_indices + ] + if suitable_vertices == []: + raise ValueError( + "There is no satisfactory choice of V for zP={}".format(zP) + ) + V_index = suitable_vertex_indices[ + find_closest_element(zP, suitable_vertices) + ] ##### zV = self._vertices[V_index] - if (zP-b).abs() >= d1 or b in self._differentials_branch_locus: + if (zP - b).abs() >= d1 or b in self._differentials_branch_locus: wP_index = find_closest_element(wP, self.w_values(zP)) d_edge = (zP, zV) - u_edge = ((zP, wP_index), (zV, )) + u_edge = ((zP, wP_index), (zV,)) initial_continuation = self.homotopy_continuation(d_edge) AJ = -line_int(u_edge) @@ -3195,55 +3395,81 @@ def _aj_based(self, P): ##### # Here we need a block of code to change the vertex if the path # from zP to zV would go through a ramification point of the integrands - fl = [c for c in self._differentials_branch_locus if not c==self._CC(Infinity)] - ts = [((c-zP)*(zV-zP).conjugate()).real()/(zP-zV).norm()**2 - for c in fl] - ds = [(fl[i]-zP-ts[i]*(zV-zP)).abs() - for i in range(len(ts)) if (ts[i]>=0 and ts[i]<=1)] - while (len(ds)>=1 and min(ds)= 0 and ts[i] <= 1) + ] + while len(ds) >= 1 and min(ds) < delta: V_index = suitable_vertex_indices.pop() zV = self._vertices[V_index] - ts = [((c-zP)*(zV-zP).conjugate()).real()/(zP-zV).norm()**2 - for c in fl] - ds = [(fl[i]-zP-ts[i]*(zV-zP)).abs() - for i in range(len(ts)) if (ts[i]>=0 and ts[i]<=1)] + ts = [ + ((c - zP) * (zV - zP).conjugate()).real() + / (zP - zV).norm() ** 2 + for c in fl + ] + ds = [ + (fl[i] - zP - ts[i] * (zV - zP)).abs() + for i in range(len(ts)) + if (ts[i] >= 0 and ts[i] <= 1) + ] ##### - while self._dfdw(zs, ws).abs()==0: - zs = zs+delta*(zV-zs)/(zV-zs).abs()/2 + while self._dfdw(zs, ws).abs() == 0: + zs = zs + delta * (zV - zs) / (zV - zs).abs() / 2 ws_list = self.w_values(zs) wP_index = find_closest_element(ws, ws_list) ws = ws_list[wP_index] upstairs_edge = ((zs, ws), zV) - AJ, endgs = self._integrate_differentials_iteratively(upstairs_edge, - cutoff_individually=False) + AJ, endgs = self._integrate_differentials_iteratively( + upstairs_edge, cutoff_individually=False + ) AJ = -AJ g0e = endgs[0] ws = self.w_values(zV) - g0s = [self.cohomology_basis()[0](zV, wi)/self._dfdw(zV, wi) for wi in ws] + g0s = [ + self.cohomology_basis()[0](zV, wi) / self._dfdw(zV, wi) + for wi in ws + ] W_index = find_closest_element(g0e, g0s) - if (g0e - self.cohomology_basis()[0](zV, ws[W_index])/self._dfdw(zV, ws[W_index])).abs()>1e-10: - raise ConvergenceError("Integrand continuation failed to get representative values, higher precision required.") + if ( + g0e + - self.cohomology_basis()[0](zV, ws[W_index]) + / self._dfdw(zV, ws[W_index]) + ).abs() > 1e-10: + raise ConvergenceError( + "Integrand continuation failed to get representative values, higher precision required." + ) uV_index = (V_index, W_index) ##### G = self.upstairs_graph() path = G.shortest_path(B, uV_index) - edges = [(path[i],path[i+1]) for i in range(len(path)-1)] + edges = [(path[i], path[i + 1]) for i in range(len(path) - 1)] ##### for e in edges: - if e[1][0]>e[0][0]: + if e[1][0] > e[0][0]: s = 1 else: s = -1 e = tuple(reversed(e)) try: - AJ += s*self._integral_dict[e] + AJ += s * self._integral_dict[e] except KeyError: Ie = line_int(e) self._integral_dict[e] = Ie - AJ += s*Ie + AJ += s * Ie return AJ def abel_jacobi(self, divisor, verbose=False): @@ -3290,12 +3516,16 @@ def abel_jacobi(self, divisor, verbose=False): v, p = divisor[i] if verbose: print("starting computation for p = {}".format(p)) - ans += v*self._aj_based(p) + ans += v * self._aj_based(p) if verbose: - print("Done, {}% complete".format(numerical_approx(100*(i+1)/n, 11))) + print( + "Done, {}% complete".format(numerical_approx(100 * (i + 1) / n, 11)) + ) return ans - def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None, normalised=False): + def reduce_over_period_lattice( + self, vector, method="ip", b=None, r=None, normalised=False + ): r""" Reduce a vector over the period lattice. @@ -3360,54 +3590,61 @@ def reduce_over_period_lattice(self, vector, method="ip", b=None, r=None, normal True True """ - if not len(vector)==self.genus: + if not len(vector) == self.genus: raise ValueError("Input vector needs to be of length {}".format(self.genus)) - VR = VectorSpace(self._RR, 2*self.genus) + VR = VectorSpace(self._RR, 2 * self.genus) VC = VectorSpace(self._CC, self.genus) I = self._CC(0, 1) PM = self.period_matrix() if normalised: - AM = PM[:, 0:self.genus] + AM = PM[:, 0 : self.genus] AInv = numerical_inverse(AM) - PM = AInv*PM + PM = AInv * PM - if method=="svp": - H = max(max(z.real_part().abs() for z in vector), - max(z.imag_part().abs() for z in vector)) + if method == "svp": + H = max( + max(z.real_part().abs() for z in vector), + max(z.imag_part().abs() for z in vector), + ) if b is None: - b = self._prec-5-H.log2().floor() + b = self._prec - 5 - H.log2().floor() if r is None: - r = b//4 + r = b // 4 S = 2**b - if H*S > 2**(self._prec-4): + if H * S > 2 ** (self._prec - 4): raise ValueError("insufficient precision for b=%s" % b) def C2Z(v): - vR = [(S*z.real_part()).round() for z in v] - vR += [(S*z.imag_part()).round() for z in v] + vR = [(S * z.real_part()).round() for z in v] + vR += [(S * z.imag_part()).round() for z in v] return vR - M = Matrix(ZZ, 2*self.genus, 2*self.genus, - [C2Z(c) for c in PM.columns()]) + M = Matrix( + ZZ, 2 * self.genus, 2 * self.genus, [C2Z(c) for c in PM.columns()] + ) u = C2Z(vector) L = IntegerLattice(M) - u = VR(u)-VR(L.closest_vector(u)) - reduced = VC([self._CC(u[i]+I*u[i+self.genus])/S for i in range(self.genus)]) + u = VR(u) - VR(L.closest_vector(u)) + reduced = VC( + [self._CC(u[i] + I * u[i + self.genus]) / S for i in range(self.genus)] + ) - elif method=="ip": + elif method == "ip": def C2R(v): - return VR([z.real_part() for z in v]+[z.imag_part() for z in v]) + return VR([z.real_part() for z in v] + [z.imag_part() for z in v]) u = C2R(vector) basis_vecs = [C2R(c) for c in PM.columns()] M = Matrix([[ei.dot_product(ej) for ei in basis_vecs] for ej in basis_vecs]) v_dot_e = VR([u.dot_product(e) for e in basis_vecs]) coeffs = M.solve_right(v_dot_e) - u -= sum([t.round()*e for t, e in zip(coeffs, basis_vecs)]) - reduced = VC([self._CC(u[i]+I*u[i+self.genus]) for i in range(self.genus)]) + u -= sum([t.round() * e for t, e in zip(coeffs, basis_vecs)]) + reduced = VC( + [self._CC(u[i] + I * u[i + self.genus]) for i in range(self.genus)] + ) else: raise ValueError("Must give a valid method.") @@ -3524,7 +3761,7 @@ def strong_approximation(self, divisor, S): # To avoid current implementation issues with going between divisors # and divisor lists, we implement a method that handles only divisors K = self._R.base_ring() - if not K==QQ: + if not K == QQ: raise NotImplementedError C = self.curve() KC = C.function_field() @@ -3536,7 +3773,7 @@ def strong_approximation(self, divisor, S): rr = self._vertices[self._basepoint[0]].real() rr = rr.ceil() - Fac = g0-K(rr) + Fac = g0 - K(rr) p0 = MO.ideal(Fac).place() q0 = KC.places_above(p0)[0] @@ -3547,12 +3784,12 @@ def strong_approximation(self, divisor, S): v = divisor.valuation(p) i = S.index(p) Q = S[i] - D = D_base+Q + D = D_base + Q if not D: ios = self.genus else: ios = len(D.basis_differential_space()) - while ios>0: + while ios > 0: D += q0 ios = len(D.basis_differential_space()) LD = D.function_space() @@ -3560,15 +3797,15 @@ def strong_approximation(self, divisor, S): a = LD[1] b = 0 for s in S: - LDps = (D+s).function_space() + LDps = (D + s).function_space() Vps = LDps[0] ebd = [LDps[2](a(g)) for g in V.gens()] U = Vps.span(ebd) Quot = Vps.quotient(U) bs = LDps[1](Quot.lift(Quot.basis()[0])) b += bs - B.append((v,b)) - new_divisor += v*b.divisor() + B.append((v, b)) + new_divisor += v * b.divisor() return new_divisor, B def divisor_to_divisor_list(self, divisor, eps=None): @@ -3582,7 +3819,7 @@ def divisor_to_divisor_list(self, divisor, eps=None): INPUT: - ``divisor`` -- an element of ``Curve(self.f).function_field().divisor_group()`` - - ``eps`` -- real number (optional); tolerance used to determine whether a complex + - ``eps`` -- real number (optional); tolerance used to determine whether a complex number is close enough to a root of a polynomial. OUTPUT: @@ -3609,21 +3846,25 @@ def divisor_to_divisor_list(self, divisor, eps=None): # If this error bound is too restrictive, this method might fail and # not return. One might want to change the way this error is handled. if not eps: - eps = self._RR(2)**(-self._prec+3) + eps = self._RR(2) ** (-self._prec + 3) dl = [] - PZ = PolynomialRing(self._R.base(), 'z').fraction_field() - RF = PolynomialRing(PZ, 'w') + PZ = PolynomialRing(self._R.base(), "z").fraction_field() + RF = PolynomialRing(PZ, "w") for d in divisor.support(): if d.is_infinite_place(): - raise NotImplementedError("Conversion of infinite places not implemented yet.") + raise NotImplementedError( + "Conversion of infinite places not implemented yet." + ) v = divisor.valuation(d) gs = d._prime.gens() g0 = self._R(gs[0]) - gis = [sum([PZ(gi.list()[i])*RF.gen()**i - for i in range(len(gi.list()))]) for gi in gs[1:]] + gis = [ + sum([PZ(gi.list()[i]) * RF.gen() ** i for i in range(len(gi.list()))]) + for gi in gs[1:] + ] rs = self._CCz(g0).roots() rys = [] @@ -3637,23 +3878,27 @@ def divisor_to_divisor_list(self, divisor, eps=None): else: ers = 1 - if not ers<=eps: + if not ers <= eps: poly = self._CCw(gi(self._CCw.gen(0), r)) - if poly==0: + if poly == 0: nys = [] else: nys = poly.roots() ys.extend(ny[0] for ny in nys) - rys.extend((v*m*n, (r, y)) for y, n in nys) + rys.extend((v * m * n, (r, y)) for y, n in nys) if rys: dl.extend(rys) else: for r, m in rs: ys = self._CCw(self.f(r, self._CCw.gen(0))).roots() - dl.extend([(v*m*n, (r, y)) for y, n in ys]) - if not sum([v[0] for v in dl])==divisor.degree(): - raise ValueError("numerical instability, list of wrong degree, returning list {}".format(dl)) + dl.extend([(v * m * n, (r, y)) for y, n in ys]) + if not sum([v[0] for v in dl]) == divisor.degree(): + raise ValueError( + "numerical instability, list of wrong degree, returning list {}".format( + dl + ) + ) return dl @@ -3701,44 +3946,57 @@ def integer_matrix_relations(M1, M2, b=None, r=None): sage: [((m[:,:2]^(-1)*m)[:,2:]-M2).norm() < 1e-13 for m in M1t] [True, True] """ - if not(M1.is_square() and M2.is_square()): + if not (M1.is_square() and M2.is_square()): raise ValueError("matrices need to be square") - prec = min(M1.base_ring().precision(),M2.base_ring().precision()) - H = max(max(abs(m.real_part()) for m in M1.list() + M2.list()), - max(abs(m.imag_part()) for m in M1.list() + M2.list())) + prec = min(M1.base_ring().precision(), M2.base_ring().precision()) + H = max( + max(abs(m.real_part()) for m in M1.list() + M2.list()), + max(abs(m.imag_part()) for m in M1.list() + M2.list()), + ) if b is None: - b = prec-5-H.log2().floor() + b = prec - 5 - H.log2().floor() if r is None: - r = b//4 + r = b // 4 S = 2**b - if H*S > 2**(prec-4): + if H * S > 2 ** (prec - 4): raise ValueError("insufficient precision for b=%s" % b) g1 = M1.ncols() g2 = M2.ncols() - CC = M1.base_ring() if (M1.base_ring().precision() <= M2.base_ring().precision()) else M2.base_ring() - V = ["%s%s" % (n, i) for n in ["a","b","c","d"] for i in range(1,1+g1*g2)] + CC = ( + M1.base_ring() + if (M1.base_ring().precision() <= M2.base_ring().precision()) + else M2.base_ring() + ) + V = ["%s%s" % (n, i) for n in ["a", "b", "c", "d"] for i in range(1, 1 + g1 * g2)] R = PolynomialRing(CC, V) vars = R.gens() - A = Matrix(R, g1, g2, vars[:g1*g2]) - B = Matrix(R, g1, g2, vars[g1*g2:2*g1*g2]) - C = Matrix(R, g1, g2, vars[2*g1*g2:3*g1*g2]) - D = Matrix(R, g1, g2, vars[3*g1*g2:4*g1*g2]) - W = ((M1*A+B) - (M1*C+D)*M2).list() + A = Matrix(R, g1, g2, vars[: g1 * g2]) + B = Matrix(R, g1, g2, vars[g1 * g2 : 2 * g1 * g2]) + C = Matrix(R, g1, g2, vars[2 * g1 * g2 : 3 * g1 * g2]) + D = Matrix(R, g1, g2, vars[3 * g1 * g2 : 4 * g1 * g2]) + W = ((M1 * A + B) - (M1 * C + D) * M2).list() vars = R.gens() - mt = Matrix(ZZ,[[1 if i == j else 0 for j in range(4*g1*g2)] + - [(S*w.monomial_coefficient(vars[i]).real_part()).round() for w in W] + - [(S*w.monomial_coefficient(vars[i]).imag_part()).round() for w in W] for i in range(len(vars))]) + mt = Matrix( + ZZ, + [ + [1 if i == j else 0 for j in range(4 * g1 * g2)] + + [(S * w.monomial_coefficient(vars[i]).real_part()).round() for w in W] + + [(S * w.monomial_coefficient(vars[i]).imag_part()).round() for w in W] + for i in range(len(vars)) + ], + ) # we compute an LLL-reduced basis of this lattice: mtL = mt.LLL() def vectomat(v): - A = Matrix(g1,g2,v[:g1*g2].list()) - B = Matrix(g1,g2,v[g1*g2:2*g1*g2].list()) - C = Matrix(g1,g2,v[2*g1*g2:3*g1*g2].list()) - D = Matrix(g1,g2,v[3*g1*g2:4*g1*g2].list()) + A = Matrix(g1, g2, v[: g1 * g2].list()) + B = Matrix(g1, g2, v[g1 * g2 : 2 * g1 * g2].list()) + C = Matrix(g1, g2, v[2 * g1 * g2 : 3 * g1 * g2].list()) + D = Matrix(g1, g2, v[3 * g1 * g2 : 4 * g1 * g2].list()) return D.augment(B).stack(C.augment(A)) + c = 2**r - return [vectomat(v) for v in mtL if all(a.abs() <= c for a in v[g1*g2:])] + return [vectomat(v) for v in mtL if all(a.abs() <= c for a in v[g1 * g2 :])] class RiemannSurfaceSum(RiemannSurface): @@ -3763,6 +4021,7 @@ class RiemannSurfaceSum(RiemannSurface): sage: len(SC.homomorphism_basis(S1+S2)) 2 """ + def __init__(self, L): r""" TESTS:: @@ -3785,13 +4044,13 @@ def __init__(self, L): g = s.genus PM = s.period_matrix() PM1 = PM[:g, :g] - PM2 = PM[:g, g:2*g] + PM2 = PM[:g, g : 2 * g] tau = s.riemann_matrix() for s in it: g = s.genus PM = s.period_matrix() PM1 = PM1.block_sum(PM[:g, :g]) - PM2 = PM2.block_sum(PM[:g, g:2*g]) + PM2 = PM2.block_sum(PM[:g, g : 2 * g]) tau = tau.block_sum(s.riemann_matrix()) self.PM = block_matrix([[PM1, PM2]], subdivide=False) self.tau = tau From 019f9a2a19489238af61ecb80250c7fe866ccf9d Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Sun, 4 Sep 2022 16:05:21 +0100 Subject: [PATCH 472/742] Added more clarifying comments about the usage of error_handle --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index d0638bf030c..0c5a182d453 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3240,6 +3240,12 @@ def fv(hj, previous_estimate): return J * results[-1], endscale * fj h /= 2 Nh *= 2 + # Note that throughout this loop there is a return statement, intended + # to be activated when the sequence of integral approximations is + # deemed to have converged by the heuristic error. If this has no + # happened by the time we have gone through the process n_steps times, + # we have one final error handle. Again, this will throw an error if + # the raise_errors flag is true, but will just return the answer otherwise. return error_handle((J * results[-1], endscale * fj)) def _aj_based(self, P): From 1c2533f67ebccd1651557fe76811f5da0b9840e8 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Sun, 4 Sep 2022 16:22:05 +0100 Subject: [PATCH 473/742] use for/else to remove checks --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 0c5a182d453..597ade10214 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3142,8 +3142,8 @@ def fv(hj, previous_estimate_and_validity): delta = new_delta Ndelta = Nnew_delta newg -= delta - if j == 99: - outg.append(error_handle(newg)) + else: + outg.append(error_handle(newg)) fj = V(outg) u1 = la * hj.cosh() w = u1 / (2 * u2.cosh() ** 2) @@ -3178,8 +3178,8 @@ def fv(hj, previous_estimate): delta = new_delta Ndelta = Nnew_delta newg -= delta - if j == 99: - outg.append(error_handle(newg)) + else: + outg.append(error_handle(newg)) fj = V(outg) u1 = la * hj.cosh() w = u1 / (2 * u2.cosh() ** 2) From 50440246008572472fcaac446fc1f98e44e8e8a3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 4 Sep 2022 11:21:15 -0700 Subject: [PATCH 474/742] FiniteRankDualFreeModule: Doc fixes --- src/sage/tensor/modules/finite_rank_free_module.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index f970d9e7f17..1bd5d13b8b6 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -2977,7 +2977,7 @@ class FiniteRankDualFreeModule(FiniteRankFreeModule_abstract): Dual of a free module of finite rank over a commutative ring. Given a free module `M` of finite rank over a commutative ring `R`, - the *dual of* `M` is the set `M^*` of all linear forms `p` on `M`, + the *dual of* `M` is the set `M^*` of all linear forms on `M`, i.e., linear maps .. MATH:: @@ -2991,10 +2991,10 @@ class FiniteRankDualFreeModule(FiniteRankFreeModule_abstract): - ``fmodule`` -- free module `M` of finite rank, as an instance of :class:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule` - - ``name`` -- (default: ``None``) string; name given to `\Lambda^p(M^*)` + - ``name`` -- (default: ``None``) string; name given to `M^*` - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote `M^*` - EXAMPLES: + EXAMPLES:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') From fc66ad14915c1b2d02d72db4114fbab48e7b601f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 4 Sep 2022 11:45:44 -0700 Subject: [PATCH 475/742] FiniteRankFreeModule.dual_symmetric_power: Update for changes in #34474 --- src/sage/tensor/modules/finite_rank_free_module.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 414e48ee665..e84c57443df 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1413,8 +1413,8 @@ def dual_symmetric_power(self, p): sage: e = M.basis('e') sage: M.dual_symmetric_power(0) Free module of type-(0,0) tensors on the Rank-3 free module M over the Integer Ring - sage: M.dual_symmetric_power(1) # return the module itself - Free module of type-(0,1) tensors on the Rank-3 free module M over the Integer Ring + sage: M.dual_symmetric_power(1) # return the dual module + Dual of the Rank-3 free module M over the Integer Ring sage: M.dual_symmetric_power(2) Free module of fully symmetric type-(0,2) tensors on the Rank-3 free module M over the Integer Ring From 84d7b5eabff42af064f875ab7a0dca0354892d3a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 4 Sep 2022 11:51:37 -0700 Subject: [PATCH 476/742] ExtPower[Dual]FreeModule, FiniteRankDualFreeModule: Add docstring to construction method --- src/sage/tensor/modules/ext_pow_free_module.py | 8 ++++++++ src/sage/tensor/modules/finite_rank_free_module.py | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/src/sage/tensor/modules/ext_pow_free_module.py b/src/sage/tensor/modules/ext_pow_free_module.py index 92483ffe422..620f49909e7 100644 --- a/src/sage/tensor/modules/ext_pow_free_module.py +++ b/src/sage/tensor/modules/ext_pow_free_module.py @@ -253,6 +253,10 @@ def __init__(self, fmodule, degree, name=None, latex_name=None): def construction(self): r""" + Return the functorial construction of ``self``. + + This implementation just returns ``None``, as no functorial construction is implemented. + TESTS:: sage: from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule @@ -634,6 +638,10 @@ def __init__(self, fmodule, degree, name=None, latex_name=None): def construction(self): r""" + Return the functorial construction of ``self``. + + This implementation just returns ``None``, as no functorial construction is implemented. + TESTS:: sage: from sage.tensor.modules.ext_pow_free_module import ExtPowerDualFreeModule diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 1bd5d13b8b6..232c403ce39 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -3101,6 +3101,10 @@ def __init__(self, fmodule, name=None, latex_name=None): def construction(self): r""" + Return the functorial construction of ``self``. + + This implementation just returns ``None``, as no functorial construction is implemented. + TESTS:: sage: from sage.tensor.modules.ext_pow_free_module import ExtPowerDualFreeModule From 8db6cc563361cfb189a1d50b5c5383a3b832772f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 4 Sep 2022 12:36:17 -0700 Subject: [PATCH 477/742] TensorFreeModule.tensor_factors: Use dual --- src/sage/tensor/modules/tensor_free_module.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index f43291e900e..86f15aa9cd8 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -385,10 +385,7 @@ def tensor_factors(self): if self._tensor_type == (0,1): # case of the dual raise NotImplementedError factors = [self._fmodule] * self._tensor_type[0] - # Until https://trac.sagemath.org/ticket/30241 is done, the dual is identified with - # ExtPowerDualFreeModule of degree 1. But that class does not have a tensor_product method, - # so we use instead the (0,1)-tensor module. - dmodule = self._fmodule.tensor_module(0, 1) + dmodule = self._fmodule.dual() if self._tensor_type[1]: factors += [dmodule] * self._tensor_type[1] return factors From edec50edd9a1704578baaccc21d143da342c551a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 4 Sep 2022 16:20:38 -0700 Subject: [PATCH 478/742] src/sage/modules/free_module.py, src/sage/modules/fg_pid/fgp_morphism.py: Use ModulesWithBasis instead of FreeModules, which is only an alias defined in sage.categories.all --- src/sage/modules/fg_pid/fgp_morphism.py | 4 ++-- src/sage/modules/free_module.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/modules/fg_pid/fgp_morphism.py b/src/sage/modules/fg_pid/fgp_morphism.py index 8eaf32ed7bd..5f61c221d93 100644 --- a/src/sage/modules/fg_pid/fgp_morphism.py +++ b/src/sage/modules/fg_pid/fgp_morphism.py @@ -507,8 +507,8 @@ def __init__(self, X, Y, category=None): if category is None: from sage.modules.free_module import is_FreeModule if is_FreeModule(X) and is_FreeModule(Y): - from sage.categories.all import FreeModules - category = FreeModules(X.base_ring()) + from sage.categories.modules_with_basis import ModulesWithBasis + category = ModulesWithBasis(X.base_ring()) else: from sage.categories.all import Modules category = Modules(X.base_ring()) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index f069cf552a3..957e2f5dee7 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -870,8 +870,8 @@ def __init__(self, base_ring, degree, sparse=False, category=None): raise ValueError("degree (=%s) must be nonnegative" % degree) if category is None: - from sage.categories.all import FreeModules - category = FreeModules(base_ring.category()).FiniteDimensional() + from sage.categories.modules_with_basis import ModulesWithBasis + category = ModulesWithBasis(base_ring.category()).FiniteDimensional() try: if base_ring.is_finite() or degree == 0: category = category.Enumerated().Finite() @@ -6409,8 +6409,8 @@ def __init__(self, ambient, basis, check=True, # Adapted from Module_free_ambient.__init__ if category is None: - from sage.categories.all import FreeModules - category = FreeModules(R.category()).FiniteDimensional() + from sage.categories.modules_with_basis import ModulesWithBasis + category = ModulesWithBasis(R.category()).FiniteDimensional() try: if base_ring.is_finite() or len(basis) == 0: category = category.Enumerated().Finite() From 823073652e1a1e9f734589e6d5c74d0744de8f32 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 4 Sep 2022 16:25:39 -0700 Subject: [PATCH 479/742] FreeModule_submodule_with_basis_pid: Fix up category --- src/sage/modules/free_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 957e2f5dee7..e2250f643e8 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -6412,7 +6412,7 @@ def __init__(self, ambient, basis, check=True, from sage.categories.modules_with_basis import ModulesWithBasis category = ModulesWithBasis(R.category()).FiniteDimensional() try: - if base_ring.is_finite() or len(basis) == 0: + if R.is_finite() or len(basis) == 0: category = category.Enumerated().Finite() except Exception: pass From 80e2c380981e194309c4bcd3f6c26e1dac07439a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 4 Sep 2022 17:22:48 -0700 Subject: [PATCH 480/742] src/doc/en/thematic_tutorials/coercion_and_categories.rst: Update doctest output --- src/doc/en/thematic_tutorials/coercion_and_categories.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index bfb8247841e..7ecd47f09b3 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -160,9 +160,6 @@ This base class provides a lot more methods than a general parent:: 'order', 'prime_subfield', 'principal_ideal', - 'quo', - 'quotient', - 'quotient_ring', 'random_element', 'unit_ideal', 'zero', From cb82460b9a4a029a0516929024f98272ff3fd225 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 4 Sep 2022 19:03:08 -0700 Subject: [PATCH 481/742] src/doc/en/thematic_tutorials/coercion_and_categories.rst: Update doctest output (again) --- src/doc/en/thematic_tutorials/coercion_and_categories.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index 7ecd47f09b3..4efe68a2617 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -109,9 +109,7 @@ This base class provides a lot more methods than a general parent:: '__ideal_monoid', '__iter__', '__len__', - '__rtruediv__', '__rxor__', - '__truediv__', '__xor__', '_an_element_impl', '_coerce_', From 337ee55216b96a5308d3518349deab12b1f5c7a4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 4 Sep 2022 20:18:02 -0700 Subject: [PATCH 482/742] TrivialFamily.map: New --- src/sage/sets/family.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/sets/family.py b/src/sage/sets/family.py index c1bf734381c..2b4ed3cc7f9 100644 --- a/src/sage/sets/family.py +++ b/src/sage/sets/family.py @@ -1380,6 +1380,22 @@ def __setstate__(self, state): """ self.__init__(state['_enumeration']) + def map(self, f, name=None): + r""" + Returns the family `( f(\mathtt{self}[i]) )_{i \in I}`, where + `I` is the index set of self. + + The result is again a :class:`TrivialFamily`. + + EXAMPLES:: + + sage: from sage.sets.family import TrivialFamily + sage: f = TrivialFamily(['a', 'b', 'd']) + sage: g = f.map(lambda x: x + '1'); g + Family ('a1', 'b1', 'd1') + """ + return Family(tuple(f(x) for x in self._enumeration), name=name) + from sage.sets.non_negative_integers import NonNegativeIntegers from sage.rings.infinity import Infinity From 3b50063a30cf492749944378d862424f2ba439a6 Mon Sep 17 00:00:00 2001 From: Dave Witte Morris Date: Thu, 1 Sep 2022 13:49:59 -0600 Subject: [PATCH 483/742] trac 34477 minor typo --- src/sage/categories/sets_cat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index d096a950773..13ea3b0338f 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1616,7 +1616,7 @@ def algebra(self, base_ring, category=None, **kwds): of `S`, or ``None`` This returns the space of formal linear combinations of - elements of `G` with coefficients in `R`, endowed with + elements of `S` with coefficients in `K`, endowed with whatever structure can be induced from that of `S`. See the documentation of :mod:`sage.categories.algebra_functor` for details. From ab98f2e2b1c0f1f25db0a3dbc6f53b2438f65cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 5 Sep 2022 10:01:00 +0200 Subject: [PATCH 484/742] less verbose monomials in shuffle algebras --- src/sage/algebras/shuffle_algebra.py | 188 +++++++++++++++------------ 1 file changed, 106 insertions(+), 82 deletions(-) diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index 7ef009fd61f..26c8a40f485 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -58,10 +58,10 @@ class ShuffleAlgebra(CombinatorialFreeModule): Shuffle Algebra on 3 generators ['x', 'y', 'z'] over Rational Field sage: mul(F.gens()) - B[word: xyz] + B[word: xzy] + B[word: yxz] + B[word: yzx] + B[word: zxy] + B[word: zyx] + B[xyz] + B[xzy] + B[yxz] + B[yzx] + B[zxy] + B[zyx] sage: mul([ F.gen(i) for i in range(2) ]) + mul([ F.gen(i+1) for i in range(2) ]) - B[word: xy] + B[word: yx] + B[word: yz] + B[word: zy] + B[xy] + B[yx] + B[yz] + B[zy] sage: S = ShuffleAlgebra(ZZ, 'abcabc'); S Shuffle Algebra on 3 generators ['a', 'b', 'c'] over Integer Ring @@ -84,11 +84,11 @@ class ShuffleAlgebra(CombinatorialFreeModule): sage: L.is_commutative() True sage: s = a*b^2 * c^3; s - (12*B[word:abb]+12*B[word:bab]+12*B[word:bba])*B[word: ccc] + (12*B[abb]+12*B[bab]+12*B[bba])*B[ccc] sage: parent(s) Shuffle Algebra on 2 generators ['c', 'd'] over Shuffle Algebra on 2 generators ['a', 'b'] over Rational Field sage: c^3 * a * b^2 - (12*B[word:abb]+12*B[word:bab]+12*B[word:bba])*B[word: ccc] + (12*B[abb]+12*B[bab]+12*B[bba])*B[ccc] Shuffle algebras are commutative:: @@ -101,11 +101,11 @@ class ShuffleAlgebra(CombinatorialFreeModule): sage: F = ShuffleAlgebra(QQ, 'abc') sage: B = F.basis() sage: B[Word('bb')] * B[Word('ca')] - B[word: bbca] + B[word: bcab] + B[word: bcba] + B[word: cabb] - + B[word: cbab] + B[word: cbba] + B[bbca] + B[bcab] + B[bcba] + B[cabb] + + B[cbab] + B[cbba] sage: 1 - B[Word('bb')] * B[Word('ca')] / 2 - B[word: ] - 1/2*B[word: bbca] - 1/2*B[word: bcab] - 1/2*B[word: bcba] - - 1/2*B[word: cabb] - 1/2*B[word: cbab] - 1/2*B[word: cbba] + B[] - 1/2*B[bbca] - 1/2*B[bcab] - 1/2*B[bcba] + - 1/2*B[cabb] - 1/2*B[cbab] - 1/2*B[cbba] TESTS:: @@ -123,7 +123,7 @@ class ShuffleAlgebra(CombinatorialFreeModule): sage: W = A.basis().keys() sage: x = A(W([0,1,0])) sage: A_d(x) - -2*S[word: 001] + S[word: 010] + -2*S[001] + S[010] """ @staticmethod def __classcall_private__(cls, R, names, prefix=None): @@ -163,7 +163,7 @@ def __init__(self, R, names, prefix): sage: F = ShuffleAlgebra(QQ, 'xyz', prefix='f'); F Shuffle Algebra on 3 generators ['x', 'y', 'z'] over Rational Field sage: F.gens() - Family (f[word: x], f[word: y], f[word: z]) + Family (f[x], f[y], f[z]) """ if R not in Rings(): raise TypeError("argument R must be a ring") @@ -186,6 +186,18 @@ def variable_names(self): """ return self._alphabet + def _repr_term(self, t): + """ + Return a string representation of the basis element indexed by ``t``. + + EXAMPLES:: + + sage: R = ShuffleAlgebra(QQ,'xyz') + sage: R._repr_term(R._indices('xyzxxy')) + 'B[xyzxxy]' + """ + return "{!s}[{!s}]".format(self._print_options['prefix'], repr(t)[6:]) + def _repr_(self): r""" Text representation of this shuffle algebra. @@ -218,7 +230,7 @@ def one_basis(self): sage: A.one_basis() word: sage: A.one() - B[word: ] + B[] """ return self.basis().keys()([]) @@ -236,20 +248,20 @@ def product_on_basis(self, w1, w2): sage: A = ShuffleAlgebra(QQ,'abc') sage: W = A.basis().keys() sage: A.product_on_basis(W("acb"), W("cba")) - B[word: acbacb] + B[word: acbcab] + 2*B[word: acbcba] - + 2*B[word: accbab] + 4*B[word: accbba] + B[word: cabacb] - + B[word: cabcab] + B[word: cabcba] + B[word: cacbab] - + 2*B[word: cacbba] + 2*B[word: cbaacb] + B[word: cbacab] - + B[word: cbacba] + B[acbacb] + B[acbcab] + 2*B[acbcba] + + 2*B[accbab] + 4*B[accbba] + B[cabacb] + + B[cabcab] + B[cabcba] + B[cacbab] + + 2*B[cacbba] + 2*B[cbaacb] + B[cbacab] + + B[cbacba] sage: (a,b,c) = A.algebra_generators() sage: a * (1-b)^2 * c - 2*B[word: abbc] - 2*B[word: abc] + 2*B[word: abcb] + B[word: ac] - - 2*B[word: acb] + 2*B[word: acbb] + 2*B[word: babc] - - 2*B[word: bac] + 2*B[word: bacb] + 2*B[word: bbac] - + 2*B[word: bbca] - 2*B[word: bca] + 2*B[word: bcab] - + 2*B[word: bcba] + B[word: ca] - 2*B[word: cab] + 2*B[word: cabb] - - 2*B[word: cba] + 2*B[word: cbab] + 2*B[word: cbba] + 2*B[abbc] - 2*B[abc] + 2*B[abcb] + B[ac] + - 2*B[acb] + 2*B[acbb] + 2*B[babc] + - 2*B[bac] + 2*B[bacb] + 2*B[bbac] + + 2*B[bbca] - 2*B[bca] + 2*B[bcab] + + 2*B[bcba] + B[ca] - 2*B[cab] + 2*B[cabb] + - 2*B[cba] + 2*B[cbab] + 2*B[cbba] """ return sum(self.basis()[u] for u in w1.shuffle(w2)) @@ -262,7 +274,7 @@ def antipode_on_basis(self, w): sage: A = ShuffleAlgebra(QQ,'abc') sage: W = A.basis().keys() sage: A.antipode_on_basis(W("acb")) - -B[word: bca] + -B[bca] """ mone = -self.base_ring().one() return self.term(w.reversal(), mone**len(w)) @@ -279,7 +291,7 @@ def gen(self, i): sage: F = ShuffleAlgebra(ZZ,'xyz') sage: F.gen(0) - B[word: x] + B[x] sage: F.gen(4) Traceback (most recent call last): @@ -299,7 +311,7 @@ def some_elements(self): sage: F = ShuffleAlgebra(ZZ,'xyz') sage: F.some_elements() - [0, B[word: ], B[word: x], B[word: y], B[word: z], B[word: xz] + B[word: zx]] + [0, B[], B[x], B[y], B[z], B[xz] + B[zx]] """ gens = list(self.algebra_generators()) if gens: @@ -321,26 +333,26 @@ def coproduct_on_basis(self, w): sage: F = ShuffleAlgebra(QQ,'ab') sage: F.coproduct_on_basis(Word('a')) - B[word: ] # B[word: a] + B[word: a] # B[word: ] + B[] # B[a] + B[a] # B[] sage: F.coproduct_on_basis(Word('aba')) - B[word: ] # B[word: aba] + B[word: a] # B[word: ba] - + B[word: ab] # B[word: a] + B[word: aba] # B[word: ] + B[] # B[aba] + B[a] # B[ba] + + B[ab] # B[a] + B[aba] # B[] sage: F.coproduct_on_basis(Word()) - B[word: ] # B[word: ] + B[] # B[] TESTS:: sage: F = ShuffleAlgebra(QQ,'ab') sage: S = F.an_element(); S - B[word: ] + 2*B[word: a] + 3*B[word: b] + B[word: bab] + B[] + 2*B[a] + 3*B[b] + B[bab] sage: F.coproduct(S) - B[word: ] # B[word: ] + 2*B[word: ] # B[word: a] - + 3*B[word: ] # B[word: b] + B[word: ] # B[word: bab] - + 2*B[word: a] # B[word: ] + 3*B[word: b] # B[word: ] - + B[word: b] # B[word: ab] + B[word: ba] # B[word: b] - + B[word: bab] # B[word: ] + B[] # B[] + 2*B[] # B[a] + + 3*B[] # B[b] + B[] # B[bab] + + 2*B[a] # B[] + 3*B[b] # B[] + + B[b] # B[ab] + B[ba] # B[b] + + B[bab] # B[] sage: F.coproduct(F.one()) - B[word: ] # B[word: ] + B[] # B[] """ TS = self.tensor_square() return TS.sum_of_monomials((w[:i], w[i:]) for i in range(len(w) + 1)) @@ -353,7 +365,7 @@ def counit(self, S): sage: F = ShuffleAlgebra(QQ,'ab') sage: S = F.an_element(); S - B[word: ] + 2*B[word: a] + 3*B[word: b] + B[word: bab] + B[] + 2*B[a] + 3*B[b] + B[bab] sage: F.counit(S) 1 """ @@ -382,17 +394,17 @@ def algebra_generators(self): sage: A = ShuffleAlgebra(ZZ,'fgh'); A Shuffle Algebra on 3 generators ['f', 'g', 'h'] over Integer Ring sage: A.algebra_generators() - Family (B[word: f], B[word: g], B[word: h]) + Family (B[f], B[g], B[h]) sage: A = ShuffleAlgebra(QQ, ['x1','x2']) sage: A.algebra_generators() - Family (B[word: x1], B[word: x2]) + Family (B[x1], B[x2]) TESTS:: sage: A = ShuffleAlgebra(ZZ,[0,1]) sage: A.algebra_generators() - Family (B[word: 0], B[word: 1]) + Family (B[0], B[1]) """ Words = self.basis().keys() return Family([self.monomial(Words([a])) for a in self._alphabet]) @@ -411,13 +423,13 @@ def _element_constructor_(self, x): sage: R = ShuffleAlgebra(QQ,'xy') sage: x, y = R.gens() sage: R(3) - 3*B[word: ] + 3*B[] sage: R(x) - B[word: x] + B[x] sage: R('xyy') - B[word: xyy] + B[xyy] sage: R(Word('xyx')) - B[word: xyx] + B[xyx] """ if isinstance(x, (str, FiniteWord_class)): W = self.basis().keys() @@ -464,13 +476,13 @@ def _coerce_map_from_(self, R): sage: x, y, z = F.gens() sage: F.coerce(x*y) # indirect doctest - B[word: xy] + B[word: yx] + B[xy] + B[yx] Elements of the integers coerce in, since there is a coerce map from `\ZZ` to GF(7):: sage: F.coerce(1) # indirect doctest - B[word: ] + B[] There is no coerce map from `\QQ` to `\GF{7}`:: @@ -482,7 +494,7 @@ def _coerce_map_from_(self, R): Elements of the base ring coerce in:: sage: F.coerce(GF(7)(5)) - 5*B[word: ] + 5*B[] The shuffle algebra over `\ZZ` on `x, y, z` coerces in, since `\ZZ` coerces to `\GF{7}`:: @@ -490,7 +502,7 @@ def _coerce_map_from_(self, R): sage: G = ShuffleAlgebra(ZZ,'xyz') sage: Gx,Gy,Gz = G.gens() sage: z = F.coerce(Gx**2 * Gy);z - 2*B[word: xxy] + 2*B[word: xyx] + 2*B[word: yxx] + 2*B[xxy] + 2*B[xyx] + 2*B[yxx] sage: z.parent() is F True @@ -561,20 +573,20 @@ def to_dual_pbw_element(self, w): sage: A = ShuffleAlgebra(QQ, 'ab') sage: f = 2 * A(Word()) + A(Word('ab')); f - 2*B[word: ] + B[word: ab] + 2*B[] + B[ab] sage: A.to_dual_pbw_element(f) - 2*S[word: ] + S[word: ab] + 2*S[] + S[ab] sage: A.to_dual_pbw_element(A.one()) - S[word: ] + S[] sage: S = A.dual_pbw_basis() sage: elt = S.expansion_on_basis(Word('abba')); elt - 2*B[word: aabb] + B[word: abab] + B[word: abba] + 2*B[aabb] + B[abab] + B[abba] sage: A.to_dual_pbw_element(elt) - S[word: abba] + S[abba] sage: A.to_dual_pbw_element(2*A(Word('aabb')) + A(Word('abab'))) - S[word: abab] + S[abab] sage: S.expansion(S('abab')) - 2*B[word: aabb] + B[word: abab] + 2*B[aabb] + B[abab] """ D = self.dual_pbw_basis() l = {} @@ -628,13 +640,13 @@ class DualPBWBasis(CombinatorialFreeModule): sage: S The dual Poincare-Birkhoff-Witt basis of Shuffle Algebra on 2 generators ['a', 'b'] over Rational Field sage: S.one() - S[word: ] + S[] sage: S.one_basis() word: sage: T = ShuffleAlgebra(QQ, 'abcd').dual_pbw_basis(); T The dual Poincare-Birkhoff-Witt basis of Shuffle Algebra on 4 generators ['a', 'b', 'c', 'd'] over Rational Field sage: T.algebra_generators() - (S[word: a], S[word: b], S[word: c], S[word: d]) + (S[a], S[b], S[c], S[d]) TESTS: @@ -678,6 +690,18 @@ def __init__(self, R, names): CombinatorialFreeModule.__init__(self, R, Words(names), prefix='S', category=cat) + def _repr_term(self, t): + """ + Return a string representation of the basis element indexed by ``t``. + + EXAMPLES:: + + sage: R = ShuffleAlgebra(QQ,'xyz').dual_pbw_basis() + sage: R._repr_term(R._indices('xyzxxy')) + 'S[xyzxxy]' + """ + return "{!s}[{!s}]".format(self._print_options['prefix'], repr(t)[6:]) + def _repr_(self): """ Return a string representation of ``self``. @@ -698,11 +722,11 @@ def _element_constructor_(self, x): sage: A = ShuffleAlgebra(QQ, 'ab') sage: S = A.dual_pbw_basis() sage: S('abaab') - S[word: abaab] + S[abaab] sage: S(Word('aba')) - S[word: aba] + S[aba] sage: S(A('ab')) - S[word: ab] + S[ab] """ if isinstance(x, (str, FiniteWord_class)): W = self.basis().keys() @@ -776,7 +800,7 @@ def algebra_generators(self): sage: S = ShuffleAlgebra(QQ, 'ab').dual_pbw_basis() sage: S.algebra_generators() - (S[word: a], S[word: b]) + (S[a], S[b]) """ W = self.basis().keys() return tuple(self.monomial(W([a])) for a in self._alphabet) @@ -791,9 +815,9 @@ def gen(self, i): sage: S = ShuffleAlgebra(QQ, 'ab').dual_pbw_basis() sage: S.gen(0) - S[word: a] + S[a] sage: S.gen(1) - S[word: b] + S[b] """ return self.algebra_generators()[i] @@ -805,7 +829,7 @@ def some_elements(self): sage: F = ShuffleAlgebra(QQ,'xyz').dual_pbw_basis() sage: F.some_elements() - [0, S[word: ], S[word: x], S[word: y], S[word: z], S[word: zx]] + [0, S[], S[x], S[y], S[z], S[zx]] """ gens = list(self.algebra_generators()) if gens: @@ -833,11 +857,11 @@ def product(self, u, v): sage: S = ShuffleAlgebra(QQ, 'ab').dual_pbw_basis() sage: a,b = S.gens() sage: S.product(a, b) - S[word: ba] + S[ba] sage: S.product(b, a) - S[word: ba] + S[ba] sage: S.product(b^2*a, a*b*a) - 36*S[word: bbbaaa] + 36*S[bbbaaa] TESTS: @@ -848,9 +872,9 @@ def product(self, u, v): sage: S = A.dual_pbw_basis() sage: a,b = S.gens() sage: A(a*b) - B[word: ab] + B[word: ba] + B[ab] + B[ba] sage: A(a*b*a) - 2*B[word: aab] + 2*B[word: aba] + 2*B[word: baa] + 2*B[aab] + 2*B[aba] + 2*B[baa] sage: S(A(a)*A(b)*A(a)) == a*b*a True """ @@ -865,10 +889,10 @@ def antipode(self, elt): sage: A = ShuffleAlgebra(QQ, 'ab') sage: S = A.dual_pbw_basis() sage: w = S('abaab').antipode(); w - S[word: abaab] - 2*S[word: ababa] - S[word: baaba] - + 3*S[word: babaa] - 6*S[word: bbaaa] + S[abaab] - 2*S[ababa] - S[baaba] + + 3*S[babaa] - 6*S[bbaaa] sage: w.antipode() - S[word: abaab] + S[abaab] """ return self(self.expansion(elt).antipode()) @@ -881,11 +905,11 @@ def coproduct(self, elt): sage: A = ShuffleAlgebra(QQ, 'ab') sage: S = A.dual_pbw_basis() sage: S('ab').coproduct() - S[word: ] # S[word: ab] + S[word: a] # S[word: b] - + S[word: ab] # S[word: ] + S[] # S[ab] + S[a] # S[b] + + S[ab] # S[] sage: S('ba').coproduct() - S[word: ] # S[word: ba] + S[word: a] # S[word: b] - + S[word: b] # S[word: a] + S[word: ba] # S[word: ] + S[] # S[ba] + S[a] # S[b] + + S[b] # S[a] + S[ba] # S[] TESTS:: @@ -921,7 +945,7 @@ def expansion(self): sage: S = ShuffleAlgebra(QQ, 'ab').dual_pbw_basis() sage: f = S('ab') + S('aba') sage: S.expansion(f) - 2*B[word: aab] + B[word: ab] + B[word: aba] + 2*B[aab] + B[ab] + B[aba] """ return self.module_morphism(self.expansion_on_basis, codomain=self._alg) @@ -938,15 +962,15 @@ def expansion_on_basis(self, w): sage: S = ShuffleAlgebra(QQ, 'ab').dual_pbw_basis() sage: S.expansion_on_basis(Word()) - B[word: ] + B[] sage: S.expansion_on_basis(Word()).parent() Shuffle Algebra on 2 generators ['a', 'b'] over Rational Field sage: S.expansion_on_basis(Word('abba')) - 2*B[word: aabb] + B[word: abab] + B[word: abba] + 2*B[aabb] + B[abab] + B[abba] sage: S.expansion_on_basis(Word()) - B[word: ] + B[] sage: S.expansion_on_basis(Word('abab')) - 2*B[word: aabb] + B[word: abab] + 2*B[aabb] + B[abab] """ from sage.arith.all import factorial if not w: @@ -981,6 +1005,6 @@ def expand(self): sage: S = ShuffleAlgebra(QQ, 'ab').dual_pbw_basis() sage: f = S('ab') + S('bab') sage: f.expand() - B[word: ab] + 2*B[word: abb] + B[word: bab] + B[ab] + 2*B[abb] + B[bab] """ return self.parent().expansion(self) From 2929a9e799ab5a913f753bc4e46b78aaae4180be Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Sep 2022 08:20:59 -0700 Subject: [PATCH 485/742] src/sage/modules/free_module.py: Make 'except Exception' more specific --- src/sage/modules/free_module.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index e2250f643e8..1595858a6dd 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -875,7 +875,7 @@ def __init__(self, base_ring, degree, sparse=False, category=None): try: if base_ring.is_finite() or degree == 0: category = category.Enumerated().Finite() - except Exception: + except (ValueError, TypeError, AttributeError, NotImplementedError): pass if not hasattr(self, 'Element'): @@ -6414,7 +6414,7 @@ def __init__(self, ambient, basis, check=True, try: if R.is_finite() or len(basis) == 0: category = category.Enumerated().Finite() - except Exception: + except (ValueError, TypeError, AttributeError, NotImplementedError): pass category = category.Subobjects() From eba6657e37e00e183dbd270d261b16bb72673dfc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Sep 2022 10:48:08 -0700 Subject: [PATCH 486/742] src/sage/categories/pushout.py (EquivariantSubobjectConstructionFunctor): New --- src/sage/categories/pushout.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index ea4e3c22dcc..893984f24be 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3679,6 +3679,33 @@ def merge(self, other): new_domain) +class EquivariantSubobjectConstructionFunctor(ConstructionFunctor): + r""" + Constructor for a subobject invariant or equivariant under a given semigroup action. + + Let `S` be a semigroup that + - acts on a parent `X` as `s \cdot x` (``action``, ``side='left'``) or + - acts on `X` as `x \cdot s` (``action``, ``side='right'``), + and (possibly trivially) + - acts on `X` as `s * x` (``other_action``, ``other_side='left'``) or + - acts on `X` as `x * s` (``other_action``, ``other_side='right'``). + + The `S`-equivariant subobject is the subobject + + .. MATH:: + + X^S := \{x \in X : s \cdot x = s * x,\, \forall s \in S \} + + when ``side = other_side = 'left'`` and mutatis mutandis for the other values + of ``side`` and ``other_side``. + + When ``other_action`` is trivial, `X^S` is called the `S`-invariant subobject. + """ + def __init__(self, S, action=operator.mul, side='left', + other_action=None, other_side='left'): + raise NotImplementedError + + class BlackBoxConstructionFunctor(ConstructionFunctor): """ Construction functor obtained from any callable object. From 1ee54705b353289e20cc9a30ccfb9483cc1cba69 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Sep 2022 11:28:23 -0700 Subject: [PATCH 487/742] FiniteDimensionalInvariantModule.construction: New --- src/sage/categories/pushout.py | 34 ++++++++++++++++++++++-- src/sage/modules/with_basis/invariant.py | 22 ++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 893984f24be..746db12ad7b 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -2,6 +2,8 @@ Coercion via construction functors """ +import operator + from sage.misc.lazy_import import lazy_import from sage.structure.coerce_exceptions import CoercionException from .functor import Functor, IdentityFunctor_generic @@ -3681,7 +3683,7 @@ def merge(self, other): class EquivariantSubobjectConstructionFunctor(ConstructionFunctor): r""" - Constructor for a subobject invariant or equivariant under a given semigroup action. + Constructor for subobjects invariant or equivariant under given semigroup actions. Let `S` be a semigroup that - acts on a parent `X` as `s \cdot x` (``action``, ``side='left'``) or @@ -3700,10 +3702,38 @@ class EquivariantSubobjectConstructionFunctor(ConstructionFunctor): of ``side`` and ``other_side``. When ``other_action`` is trivial, `X^S` is called the `S`-invariant subobject. + + EXAMPLES:: + + sage: G = SymmetricGroup(3); G.rename('S3') + sage: M = FreeModule(ZZ, [1,2,3], prefix='M'); M.rename('M') + sage: action = lambda g, x: M.term(g(x)) + sage: I = M.invariant_module(G, action_on_basis=action); I + (S3)-invariant submodule of M + sage: from sage.categories.pushout import pushout + sage: pushout(I, QQ) + Traceback (most recent call last): + ... + sage.structure.coerce_exceptions.CoercionException: No common base ("join") found for EquivariantSubobjectConstructionFunctor(Representation of S3 indexed by {1, 2, 3} over Integer Ring) and FractionField(Integer Ring). """ def __init__(self, S, action=operator.mul, side='left', other_action=None, other_side='left'): - raise NotImplementedError + from sage.categories.sets_cat import Sets + super().__init__(Sets(), Sets()) + self.S = S + self.action = action + self.side = side + self.other_action = other_action + self.other_side = other_side + + def _apply_functor(self, X): + """ + Apply the functor to an object of ``self``'s domain. + """ + if self.other_action is not None: + raise NotImplementedError(f'non-trivial {other_action=} is not implemented') + # Currently only implemented for FiniteDimensionalModulesWithBasis + return X.invariant_module(self.S, action=self.action, side=self.side) class BlackBoxConstructionFunctor(ConstructionFunctor): diff --git a/src/sage/modules/with_basis/invariant.py b/src/sage/modules/with_basis/invariant.py index f180f442c19..dccee08a840 100644 --- a/src/sage/modules/with_basis/invariant.py +++ b/src/sage/modules/with_basis/invariant.py @@ -262,9 +262,29 @@ def _invariant_map(g, x): category=category, *args, **kwargs) + def construction(self): + r""" + Return the functorial construction of ``self``. + + EXAMPLES:: + + sage: G = CyclicPermutationGroup(3) + sage: R = G.regular_representation(); R + Left Regular Representation of Cyclic group of order 3 as a permutation group over Integer Ring + sage: I = R.invariant_module() + sage: I.construction() + (EquivariantSubobjectConstructionFunctor, + Left Regular Representation of Cyclic group of order 3 as a permutation group over Integer Ring) + """ + from sage.categories.pushout import EquivariantSubobjectConstructionFunctor + return (EquivariantSubobjectConstructionFunctor(self._semigroup, + self._action, + self._side), + self.ambient()) + def _repr_(self): r""" - Return a string representaion of ``self``. + Return a string representation of ``self``. EXAMPLES:: From e7f2f0588c61233cc9222e4619f086f5f8ee6af4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Sep 2022 14:54:36 -0700 Subject: [PATCH 488/742] src/sage/categories/pushout.py: Add example --- src/sage/categories/pushout.py | 57 ++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 746db12ad7b..1215c3417cf 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3715,6 +3715,63 @@ class EquivariantSubobjectConstructionFunctor(ConstructionFunctor): Traceback (most recent call last): ... sage.structure.coerce_exceptions.CoercionException: No common base ("join") found for EquivariantSubobjectConstructionFunctor(Representation of S3 indexed by {1, 2, 3} over Integer Ring) and FractionField(Integer Ring). + + Monoterm symmetries of a tensor, here only for matrices: row (index 0), + column (index 1); the order of the extra element 2 in a permutation determines + whether it is a symmetry or an antisymmetry:: + + sage: GSym01 = PermutationGroup([[(0,1),(2,),(3,)]]); GSym01 + Permutation Group with generators [(0,1)] + sage: GASym01 = PermutationGroup([[(0,1),(2,3)]]); GASym01 + Permutation Group with generators [(0,1)(2,3)] + sage: from sage.categories.action import Action + sage: from sage.structure.element import Matrix + sage: class TensorIndexAction(Action): + ....: def _act_(self, g, x): + ....: if isinstance(x, Matrix): + ....: if g(0) == 1: + ....: if g(2) == 2: + ....: return x.transpose() + ....: else: + ....: return -x.transpose() + ....: else: + ....: return x + ....: raise NotImplementedError + sage: M = matrix([[1, 2], [3, 4]]); M + [1 2] + [3 4] + sage: GSym01_action = TensorIndexAction(GSym01, M.parent()) + sage: GASym01_action = TensorIndexAction(GASym01, M.parent()) + sage: GSym01_action.act(GSym01.0, M) + [1 3] + [2 4] + sage: GASym01_action.act(GASym01.0, M) + [-1 -3] + [-2 -4] + sage: Sym01 = M.parent().invariant_module(GSym01, action=GSym01_action); Sym01 + (Permutation Group with generators [(0,1)])-invariant submodule + of Full MatrixSpace of 2 by 2 dense matrices over Integer Ring + sage: list(Sym01.basis()) + [B[0], B[1], B[2]] + sage: list(Sym01.basis().map(Sym01.lift)) + [ + [1 0] [0 1] [0 0] + [0 0], [1 0], [0 1] + ] + sage: ASym01 = M.parent().invariant_module(GASym01, action=GASym01_action); ASym01 + (Permutation Group with generators [(0,1)(2,3)])-invariant submodule + of Full MatrixSpace of 2 by 2 dense matrices over Integer Ring + sage: list(ASym01.basis()) + [B[0]] + sage: list(ASym01.basis().map(ASym01.lift)) + [ + [ 0 1] + [-1 0] + ] + sage: from sage.categories.pushout import pushout + sage: pushout(Sym01, QQ) + (Permutation Group with generators [(0,1)])-invariant submodule + of Full MatrixSpace of 2 by 2 dense matrices over Rational Field """ def __init__(self, S, action=operator.mul, side='left', other_action=None, other_side='left'): From 9e09c2f9acb727a59dc4955ceb2864c2308f6b26 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Sep 2022 14:59:39 -0700 Subject: [PATCH 489/742] src/sage/categories/pushout.py: Remove unfinished example --- src/sage/categories/pushout.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 1215c3417cf..c090df3b4f5 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3703,18 +3703,7 @@ class EquivariantSubobjectConstructionFunctor(ConstructionFunctor): When ``other_action`` is trivial, `X^S` is called the `S`-invariant subobject. - EXAMPLES:: - - sage: G = SymmetricGroup(3); G.rename('S3') - sage: M = FreeModule(ZZ, [1,2,3], prefix='M'); M.rename('M') - sage: action = lambda g, x: M.term(g(x)) - sage: I = M.invariant_module(G, action_on_basis=action); I - (S3)-invariant submodule of M - sage: from sage.categories.pushout import pushout - sage: pushout(I, QQ) - Traceback (most recent call last): - ... - sage.structure.coerce_exceptions.CoercionException: No common base ("join") found for EquivariantSubobjectConstructionFunctor(Representation of S3 indexed by {1, 2, 3} over Integer Ring) and FractionField(Integer Ring). + EXAMPLES: Monoterm symmetries of a tensor, here only for matrices: row (index 0), column (index 1); the order of the extra element 2 in a permutation determines From 86d9602e95f650e7b247780126a40aedd0f92769 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Sep 2022 15:13:03 -0700 Subject: [PATCH 490/742] src/sage/categories/pushout.py: Add missing doctests --- src/sage/categories/pushout.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index c090df3b4f5..cb37b2cd20e 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3764,6 +3764,18 @@ class EquivariantSubobjectConstructionFunctor(ConstructionFunctor): """ def __init__(self, S, action=operator.mul, side='left', other_action=None, other_side='left'): + """ + EXAMPLES:: + + sage: G = SymmetricGroup(3); G.rename('S3') + sage: M = FreeModule(ZZ, [1,2,3], prefix='M'); M.rename('M') + sage: action = lambda g, x: M.term(g(x)) + sage: I = M.invariant_module(G, action_on_basis=action); I + (S3)-invariant submodule of M + sage: I.construction() + (EquivariantSubobjectConstructionFunctor, + Representation of S3 indexed by {1, 2, 3} over Integer Ring) + """ from sage.categories.sets_cat import Sets super().__init__(Sets(), Sets()) self.S = S @@ -3775,8 +3787,23 @@ def __init__(self, S, action=operator.mul, side='left', def _apply_functor(self, X): """ Apply the functor to an object of ``self``'s domain. + + TESTS:: + + sage: from sage.categories.pushout import EquivariantSubobjectConstructionFunctor + sage: M2 = MatrixSpace(QQ, 2); M2 + Full MatrixSpace of 2 by 2 dense matrices over Rational Field + sage: F = EquivariantSubobjectConstructionFunctor(M2, + ....: operator.mul, 'left', + ....: operator.mul, 'right'); F + EquivariantSubobjectConstructionFunctor + sage: F(M2) + Traceback (most recent call last): + ... + NotImplementedError: non-trivial other_action= is not implemented """ - if self.other_action is not None: + other_action = self.other_action + if other_action is not None: raise NotImplementedError(f'non-trivial {other_action=} is not implemented') # Currently only implemented for FiniteDimensionalModulesWithBasis return X.invariant_module(self.S, action=self.action, side=self.side) From 8ddcaa15ac898e60a094f4de22e84682f8699e19 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Sep 2022 15:27:41 -0700 Subject: [PATCH 491/742] src/sage/categories/pushout.py: Add copyright according to 'git blame -w --date=format:%Y src/sage/categories/pushout.py | sort -k2' --- src/sage/categories/pushout.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index cb37b2cd20e..3136160f39d 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -2,6 +2,30 @@ Coercion via construction functors """ +# **************************************************************************** +# Copyright (C) 2007-2014 Robert Bradshaw +# 2007-2018 David Roe +# 2009-2013 Simon King +# 2010 John Cremona +# 2010-2011 Mike Hansen +# 2012 Julian Rueth +# 2013-2016 Peter Bruin +# 2014 Wilfried Luebbe +# 2015 Benjamin Hackl +# 2015 Daniel Krenn +# 2016-2020 Frédéric Chapoton +# 2017 Jori Mäntysalo +# 2018 Vincent Delecroix +# 2020 Marc Mezzarobba +# 2020-2022 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/ +# **************************************************************************** + import operator from sage.misc.lazy_import import lazy_import From bfd6eee17d7f6105e8f13d4c3796ff74edfe8a51 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Sep 2022 15:29:26 -0700 Subject: [PATCH 492/742] src/sage/modules/with_basis/invariant.py: Update copyright --- src/sage/modules/with_basis/invariant.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/with_basis/invariant.py b/src/sage/modules/with_basis/invariant.py index dccee08a840..33af946e8a0 100644 --- a/src/sage/modules/with_basis/invariant.py +++ b/src/sage/modules/with_basis/invariant.py @@ -4,7 +4,8 @@ # **************************************************************************** # Copyright (C) 2021 Trevor K. Karn -# Travis Scrimshaw +# 2021 Travis Scrimshaw +# 2022 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 7fe5763fb8b82c578cb3c49014361304c027568a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Sep 2022 19:19:06 -0700 Subject: [PATCH 493/742] src/sage/algebras/orlik_{solomon,terao}.py: No construction for subclasses of FiniteDimensionalInvariantModule --- src/sage/algebras/orlik_solomon.py | 20 ++++++++++++++++++-- src/sage/algebras/orlik_terao.py | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/orlik_solomon.py b/src/sage/algebras/orlik_solomon.py index ffbbbb6a5af..4f256fe7777 100644 --- a/src/sage/algebras/orlik_solomon.py +++ b/src/sage/algebras/orlik_solomon.py @@ -576,7 +576,7 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): .. NOTE:: The algebra structure only exists when the action on the - groundset yeilds an equivariant matroid, in the sense that + groundset yields an equivariant matroid, in the sense that `g \cdot I \in \mathcal{I}` for every `g \in G` and for every `I \in \mathcal{I}`. """ @@ -638,9 +638,25 @@ def action(g, m): *args, **kwargs) # To subclass FiniteDimensionalInvariant module, we also need a - # self._semigroup method. + # self._semigroup attribute. self._semigroup = G + def construction(self): + r""" + Return the functorial construction of ``self``. + + This implementation of the method only returns ``None``. + + TESTS:: + + sage: M = matroids.Wheel(3) + sage: from sage.algebras.orlik_solomon import OrlikSolomonAlgebra + sage: OS1 = OrlikSolomonAlgebra(QQ, M) + sage: OS1.construction() is None + True + """ + return None + def _basis_action(self, g, f): r""" Return the action of the group element ``g`` on the n.b.c. set ``f`` diff --git a/src/sage/algebras/orlik_terao.py b/src/sage/algebras/orlik_terao.py index 7bd25496745..55fd2bdb641 100644 --- a/src/sage/algebras/orlik_terao.py +++ b/src/sage/algebras/orlik_terao.py @@ -660,6 +660,25 @@ def action(g, m): self._semigroup = G + def construction(self): + r""" + Return the functorial construction of ``self``. + + This implementation of the method only returns ``None``. + + TESTS:: + + sage: A = matrix([[1,1,0],[-1,0,1],[0,-1,-1]]) + sage: M = Matroid(A) + sage: G = SymmetricGroup(3) + sage: def on_groundset(g,x): + ....: return g(x+1)-1 + sage: OTG = M.orlik_terao_algebra(QQ, invariant=(G,on_groundset)) + sage: OTG.construction() is None + True + """ + return None + def _basis_action(self, g, f): r""" Let ``f`` be an n.b.c. set so that it indexes a basis From 62f28a334262b6b6712c0a6d98e07291abcba5e2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 5 Sep 2022 21:33:20 -0700 Subject: [PATCH 494/742] src/sage/modules/free_module.py: Compute category more carefully --- src/sage/modules/free_module.py | 53 ++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 1595858a6dd..2699006e891 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -869,14 +869,14 @@ def __init__(self, base_ring, degree, sparse=False, category=None): if degree < 0: raise ValueError("degree (=%s) must be nonnegative" % degree) - if category is None: - from sage.categories.modules_with_basis import ModulesWithBasis - category = ModulesWithBasis(base_ring.category()).FiniteDimensional() - try: - if base_ring.is_finite() or degree == 0: - category = category.Enumerated().Finite() - except (ValueError, TypeError, AttributeError, NotImplementedError): - pass + from sage.categories.modules_with_basis import ModulesWithBasis + modules_category = ModulesWithBasis(base_ring.category()).FiniteDimensional() + try: + if base_ring.is_finite() or degree == 0: + modules_category = modules_category.Enumerated().Finite() + except (ValueError, TypeError, AttributeError, NotImplementedError): + pass + category = modules_category.or_subcategory(category, join=True) if not hasattr(self, 'Element'): self.Element = element_class(base_ring, sparse) @@ -6384,6 +6384,25 @@ def __init__(self, ambient, basis, check=True, sage: w = sqrt(2) * V([1,1]) sage: 3 * w (3*sqrt(2), 3*sqrt(2)) + + TESTS: + + Test that the category is determined as intended:: + + sage: from sage.modules.free_module import FreeModule_ambient_pid, FreeModule_submodule_with_basis_pid + sage: V = FreeModule_ambient_pid(QQ, 3, category=Algebras(QQ)) + sage: V.category() + Category of finite dimensional algebras with basis over Rational Field + sage: W = FreeModule_submodule_with_basis_pid(V, [[1,2,3]]) + sage: W.category() + Join of + Category of finite dimensional vector spaces with basis over (number fields and quotient fields and metric spaces) and + Category of subobjects of sets + sage: W = FreeModule_submodule_with_basis_pid(V, [[1,2,3]], category=Algebras(QQ)) + sage: W.category() + Join of + Category of finite dimensional algebras with basis over Rational Field and + Category of subobjects of sets """ if not isinstance(ambient, FreeModule_ambient_pid): raise TypeError("ambient (=%s) must be ambient." % ambient) @@ -6408,15 +6427,15 @@ def __init__(self, ambient, basis, check=True, basis = self._echelonized_basis(ambient, basis) # Adapted from Module_free_ambient.__init__ - if category is None: - from sage.categories.modules_with_basis import ModulesWithBasis - category = ModulesWithBasis(R.category()).FiniteDimensional() - try: - if R.is_finite() or len(basis) == 0: - category = category.Enumerated().Finite() - except (ValueError, TypeError, AttributeError, NotImplementedError): - pass - category = category.Subobjects() + from sage.categories.modules_with_basis import ModulesWithBasis + modules_category = ModulesWithBasis(R.category()).FiniteDimensional() + try: + if R.is_finite() or len(basis) == 0: + modules_category = modules_category.Enumerated().Finite() + except (ValueError, TypeError, AttributeError, NotImplementedError): + pass + modules_category = modules_category.Subobjects() + category = modules_category.or_subcategory(category, join=True) FreeModule_generic_pid.__init__(self, base_ring=R, coordinate_ring=R_coord, rank=len(basis), degree=ambient.degree(), From a77ff0c9c90b94bd83799351326f4dca6237c2f2 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Tue, 6 Sep 2022 08:46:38 +0200 Subject: [PATCH 495/742] 34282: pyflakes and missing import in doctest --- src/sage/features/latex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py index 501c82c0539..02bcb57a0ca 100644 --- a/src/sage/features/latex.py +++ b/src/sage/features/latex.py @@ -13,7 +13,6 @@ # **************************************************************************** from . import StaticFile, Executable, FeatureTestResult, FeatureNotPresentError -from sage.features.join_feature import JoinFeature latex_url = 'https://www.latex-project.org/' latex_spkg = 'texlive' @@ -179,6 +178,7 @@ def __init__(self, name, filename, **kwds): TESTS:: + sage: from sage.features.latex import TeXFile sage: TeXFile('nonexisting', 'xxxxxx-nonexisting-file.tex').is_present() # optional - latex FeatureTestResult('nonexisting', False) """ From d51e167dec946680487e98d5675855e0d520088e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 08:12:37 -0700 Subject: [PATCH 496/742] build/pkgs/igraph/spkg-configure.m4: Reject igraph >= 0.10 --- build/pkgs/igraph/spkg-configure.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/igraph/spkg-configure.m4 b/build/pkgs/igraph/spkg-configure.m4 index 441c926cdf6..b3ab621474a 100644 --- a/build/pkgs/igraph/spkg-configure.m4 +++ b/build/pkgs/igraph/spkg-configure.m4 @@ -1,7 +1,7 @@ SAGE_SPKG_CONFIGURE([igraph], [ SAGE_SPKG_DEPCHECK([glpk openblas gmp], [ dnl check for igraph with pkg-config - PKG_CHECK_MODULES([IGRAPH], [igraph >= 0.9.5], [], [ + PKG_CHECK_MODULES([IGRAPH], [igraph >= 0.9.5 igraph < 0.10], [], [ sage_spkg_install_igraph=yes]) ]) ]) From 0d338ed2608c3886b334dd70d503317f9139e28a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 08:16:21 -0700 Subject: [PATCH 497/742] build/pkgs/igraph: Update to 0.10.0 --- build/pkgs/igraph/checksums.ini | 6 +++--- build/pkgs/igraph/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/igraph/checksums.ini b/build/pkgs/igraph/checksums.ini index 2d7a72630b0..c38a75f5b7f 100644 --- a/build/pkgs/igraph/checksums.ini +++ b/build/pkgs/igraph/checksums.ini @@ -1,5 +1,5 @@ tarball=igraph-VERSION.tar.gz -sha1=75aae4d9f1459d9e6f6bd03189e6dff4208c29ca -md5=351a276216a8f09e11a401d2313ea471 -cksum=1815245909 +sha1=e4097fc00c3cb9b64a251003623a104c2ac4ae1f +md5=fbca766c3e76b2098c4555a13689fec6 +cksum=627334466 upstream_url=https://github.com/igraph/igraph/releases/download/VERSION/igraph-VERSION.tar.gz diff --git a/build/pkgs/igraph/package-version.txt b/build/pkgs/igraph/package-version.txt index 56f3151140c..78bc1abd14f 100644 --- a/build/pkgs/igraph/package-version.txt +++ b/build/pkgs/igraph/package-version.txt @@ -1 +1 @@ -0.9.10 +0.10.0 From a5f5420dcadcce388fe4ecc19855c46807793d06 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 08:16:57 -0700 Subject: [PATCH 498/742] build/pkgs/igraph/spkg-configure.m4: Update version constraints --- build/pkgs/igraph/spkg-configure.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/igraph/spkg-configure.m4 b/build/pkgs/igraph/spkg-configure.m4 index b3ab621474a..30b5fcf9c53 100644 --- a/build/pkgs/igraph/spkg-configure.m4 +++ b/build/pkgs/igraph/spkg-configure.m4 @@ -1,7 +1,7 @@ SAGE_SPKG_CONFIGURE([igraph], [ SAGE_SPKG_DEPCHECK([glpk openblas gmp], [ dnl check for igraph with pkg-config - PKG_CHECK_MODULES([IGRAPH], [igraph >= 0.9.5 igraph < 0.10], [], [ + PKG_CHECK_MODULES([IGRAPH], [igraph >= 0.10 igraph < 0.11], [], [ sage_spkg_install_igraph=yes]) ]) ]) From c498cacf70fee0b64dd9f2fece7438514647da35 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 08:17:26 -0700 Subject: [PATCH 499/742] build/pkgs/python_igraph: Update to 0.10.0 --- build/pkgs/python_igraph/checksums.ini | 6 +++--- build/pkgs/python_igraph/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/python_igraph/checksums.ini b/build/pkgs/python_igraph/checksums.ini index 5fbaf1821bc..8e53fc46eca 100644 --- a/build/pkgs/python_igraph/checksums.ini +++ b/build/pkgs/python_igraph/checksums.ini @@ -1,5 +1,5 @@ tarball=python-igraph-VERSION.tar.gz -sha1=b54b4f1a0c7ce8a80ddb35d35b4e5d1552592793 -md5=9ce0139a294d1c738abc4eb75aab84cd -cksum=4113725847 +sha1=86a35162babd0d4af520b2ee0f8d9bb555a744cc +md5=d9c1ec7ddad66f927490f1de893fe42f +cksum=4022167909 upstream_url=https://pypi.io/packages/source/i/igraph/igraph-VERSION.tar.gz diff --git a/build/pkgs/python_igraph/package-version.txt b/build/pkgs/python_igraph/package-version.txt index 8225a4ba4fd..78bc1abd14f 100644 --- a/build/pkgs/python_igraph/package-version.txt +++ b/build/pkgs/python_igraph/package-version.txt @@ -1 +1 @@ -0.9.11 +0.10.0 From 7aaa9d0a09c77429c98dc9aef858fac48b7209aa Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 08:55:40 -0700 Subject: [PATCH 500/742] build/pkgs/igraph/dependencies: Remove suitesparse, per https://sagemath.zulipchat.com/\#narrow/stream/271086-feedback/topic/hello/near/297431320 --- build/pkgs/igraph/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/igraph/dependencies b/build/pkgs/igraph/dependencies index 267354a48f6..a36c43a6a02 100644 --- a/build/pkgs/igraph/dependencies +++ b/build/pkgs/igraph/dependencies @@ -1,4 +1,4 @@ -$(MP_LIBRARY) glpk $(BLAS) suitesparse | cmake +$(MP_LIBRARY) glpk $(BLAS) | cmake ---------- All lines of this file are ignored except the first. From de176c58fb66f65400be031168db88e2f0bb05e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 6 Sep 2022 20:55:15 +0200 Subject: [PATCH 501/742] make some methods "gens" return tuples --- src/sage/algebras/finite_gca.py | 19 ++++++++------- src/sage/groups/perm_gps/permgroup.py | 20 ++++++++-------- src/sage/groups/perm_gps/permgroup_named.py | 4 ++-- .../semimonomial_transformation_group.py | 9 ++++---- src/sage/interfaces/magma.py | 23 ++++++++++--------- src/sage/quivers/homspace.py | 19 +++++++-------- src/sage/quivers/representation.py | 18 +++++++-------- 7 files changed, 58 insertions(+), 54 deletions(-) diff --git a/src/sage/algebras/finite_gca.py b/src/sage/algebras/finite_gca.py index 0a40e539438..5f21cdc8290 100644 --- a/src/sage/algebras/finite_gca.py +++ b/src/sage/algebras/finite_gca.py @@ -6,17 +6,16 @@ - Michael Jung (2021): initial version """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2021 Michael Jung # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** - +# https://www.gnu.org/licenses/ +# **************************************************************************** +from __future__ import annotations from sage.combinat.free_module import CombinatorialFreeModule from sage.categories.algebras import Algebras from sage.misc.cachefunc import cached_method @@ -27,6 +26,7 @@ from sage.sets.condition_set import ConditionSet from sage.rings.integer_ring import ZZ + class FiniteGCAlgebra(CombinatorialFreeModule, Algebra): r""" Finite dimensional graded commutative algebras. @@ -484,16 +484,15 @@ def one_basis(self): n = len(self._degrees) return self._weighted_vectors([0 for _ in range(n)]) - def gens(self): + def gens(self) -> tuple: r""" - Return the generators of ``self`` as a list. + Return the generators of ``self`` as a tuple. EXAMPLES:: sage: A. = GradedCommutativeAlgebra(QQ, degrees=(4,8,2), max_degree=10) sage: A.gens() - [x, y, z] - + (x, y, z) """ n = len(self._degrees) zero = [0 for _ in range(n)] @@ -502,7 +501,7 @@ def gens(self): ind = list(zero) ind[k] = 1 indices.append(self._weighted_vectors(ind)) - return [self.monomial(ind) for ind in indices] + return tuple([self.monomial(ind) for ind in indices]) @cached_method def gen(self, i): diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 3a0c780d677..4e12486310d 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -135,7 +135,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # **************************************************************************** - +from __future__ import annotations from functools import wraps from sage.misc.randstate import current_randstate @@ -492,7 +492,7 @@ def __init__(self, gens=None, gap_group=None, canonicalize=True, if isinstance(gap_group, LibGapElement): self._libgap = gap_group - #Handle the case where only the GAP group is specified. + # Handle the case where only the GAP group is specified. if gens is None: gens = [gen for gen in gap_group.GeneratorsOfGroup()] @@ -509,9 +509,9 @@ def __init__(self, gens=None, gap_group=None, canonicalize=True, # Fallback (not ideal: find a better solution?) domain = sorted(domain, key=str) - #Here we need to check if all of the points are integers - #to make the domain contain all integers up to the max. - #This is needed for backward compatibility + # Here we need to check if all of the points are integers + # to make the domain contain all integers up to the max. + # This is needed for backward compatibility if all(isinstance(p, (int, Integer)) for p in domain): domain = list(range(min([1] + domain), max([1] + domain)+1)) @@ -1237,9 +1237,11 @@ def elements(SGS): else: raise ValueError("the input algorithm (='%s') must be 'SGS', 'BFS' or 'DFS'" % algorithm) - def gens(self): + def gens(self) -> tuple: """ - Return tuple of generators of this group. These need not be + Return tuple of generators of this group. + + These need not be minimal, as they are the generators used in defining this group. EXAMPLES:: @@ -1270,14 +1272,14 @@ def gens(self): We make sure that the trivial group gets handled correctly:: sage: SymmetricGroup(1).gens() - [()] + ((),) """ return self._gens - def gens_small(self): """ For this group, returns a generating set which has few elements. + As neither irredundancy nor minimal length is proven, it is fast. EXAMPLES:: diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index d5078f03b40..a3be9f974fe 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -272,8 +272,8 @@ def __init__(self, domain=None): gens = [tuple(self._domain)] if len(self._domain) > 2: gens.append(tuple(self._domain[:2])) - self._gens = [self.element_class(g, self, check=False) - for g in gens] + self._gens = tuple([self.element_class(g, self, check=False) + for g in gens]) def _gap_init_(self, gap=None): """ diff --git a/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py b/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py index 6119a36d3ed..78c485bfc02 100644 --- a/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py +++ b/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py @@ -51,6 +51,7 @@ sage: TestSuite(S).run() sage: TestSuite(S.an_element()).run() """ +from __future__ import annotations from sage.rings.integer import Integer from sage.groups.group import FiniteGroup @@ -285,7 +286,7 @@ def __contains__(self, item) -> bool: return False return True - def gens(self): + def gens(self) -> tuple: r""" Return a tuple of generators of ``self``. @@ -293,11 +294,11 @@ def gens(self): sage: F. = GF(4) sage: SemimonomialTransformationGroup(F, 3).gens() - [((a, 1, 1); (), Ring endomorphism of Finite Field in a of size 2^2 + (((a, 1, 1); (), Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a), ((1, 1, 1); (1,2,3), Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a), ((1, 1, 1); (1,2), Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a), ((1, 1, 1); (), Ring endomorphism of Finite Field in a of size 2^2 - Defn: a |--> a + 1)] + Defn: a |--> a + 1)) """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup R = self.base_ring() @@ -306,7 +307,7 @@ def gens(self): l.append(self(perm=Permutation(g))) if R.is_field() and not R.is_prime_field(): l.append(self(autom=R.hom([R.primitive_element()**R.characteristic()]))) - return l + return tuple(l) def order(self) -> Integer: r""" diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index bd75a6a1850..e34e5a13aa3 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -197,7 +197,7 @@ magma.functions... """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -210,8 +210,8 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** - +# **************************************************************************** +from __future__ import annotations import re import sys @@ -2133,14 +2133,14 @@ def gen(self, n): """ if n <= 0: raise IndexError("index must be positive since Magma indexes are 1-based") - return self.gens()[n-1] + return self.gens()[n - 1] - def gens(self): + def gens(self) -> tuple: """ - Return generators for self. + Return generators for ``self``. If self is named X in Magma, this function evaluates X.1, X.2, - etc., in Magma until an error occurs. It then returns a Sage list + etc., in Magma until an error occurs. It then returns a Sage tuple of the resulting X.i. Note - I don't think there is a Magma command that returns the list of valid X.i. There are numerous ad hoc functions for various classes but nothing systematic. This function @@ -2154,9 +2154,9 @@ def gens(self): EXAMPLES:: sage: magma("VectorSpace(RationalField(),3)").gens() # optional - magma - [(1 0 0), (0 1 0), (0 0 1)] + ((1 0 0), (0 1 0), (0 0 1)) sage: magma("AbelianGroup(EllipticCurve([1..5]))").gens() # optional - magma - [$.1] + ($.1,) """ try: return self._magma_gens @@ -2172,8 +2172,9 @@ def gens(self): except (RuntimeError, TypeError): break i += 1 - self._magma_gens = G - return G + tG = tuple(G) + self._magma_gens = tG + return tG def gen_names(self): """ diff --git a/src/sage/quivers/homspace.py b/src/sage/quivers/homspace.py index 296ae15129c..cb9a36e3eed 100644 --- a/src/sage/quivers/homspace.py +++ b/src/sage/quivers/homspace.py @@ -17,6 +17,7 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +from __future__ import annotations from sage.categories.homset import Homset from sage.quivers.morphism import QuiverRepHom from sage.misc.cachefunc import cached_method @@ -53,8 +54,8 @@ class QuiverHomSpace(Homset): sage: H.dimension() 2 sage: H.gens() - [Homomorphism of representations of Multi-digraph on 2 vertices, - Homomorphism of representations of Multi-digraph on 2 vertices] + (Homomorphism of representations of Multi-digraph on 2 vertices, + Homomorphism of representations of Multi-digraph on 2 vertices) """ Element = QuiverRepHom @@ -499,25 +500,25 @@ def dimension(self): """ return self._space.dimension() - def gens(self): + def gens(self) -> tuple: """ - Return a list of generators of the hom space (as a `k`-vector + Return a tuple of generators of the hom space (as a `k`-vector space). OUTPUT: - - list of :class:`QuiverRepHom` objects, the generators + - tuple of :class:`QuiverRepHom` objects, the generators EXAMPLES:: sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup() sage: H = Q.S(QQ, 2).Hom(Q.P(QQ, 1)) sage: H.gens() - [Homomorphism of representations of Multi-digraph on 2 vertices, - Homomorphism of representations of Multi-digraph on 2 vertices] + (Homomorphism of representations of Multi-digraph on 2 vertices, + Homomorphism of representations of Multi-digraph on 2 vertices) """ - return [self.element_class(self._domain, self._codomain, f) - for f in self._space.gens()] + return tuple([self.element_class(self._domain, self._codomain, f) + for f in self._space.gens()]) def coordinates(self, hom): """ diff --git a/src/sage/quivers/representation.py b/src/sage/quivers/representation.py index 78ed8ce6d2a..859ff1b10b1 100644 --- a/src/sage/quivers/representation.py +++ b/src/sage/quivers/representation.py @@ -447,7 +447,7 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** - +from __future__ import annotations from sage.structure.factory import UniqueFactory from sage.modules.module import Module from sage.structure.element import ModuleElement @@ -1915,9 +1915,9 @@ def support(self): return sup - def gens(self, names='v'): + def gens(self, names='v') -> tuple: """ - Return a list of generators of ``self`` as a `k`-module. + Return a tuple of generators of ``self`` as a `k`-module. INPUT: @@ -1928,7 +1928,7 @@ def gens(self, names='v'): OUTPUT: - - list of :class:`QuiverRepElement` objects, the linear generators + - tuple of :class:`QuiverRepElement` objects, the linear generators of the module (over the base ring) .. NOTE:: @@ -1942,14 +1942,14 @@ def gens(self, names='v'): sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup() sage: M = Q.P(QQ, 1) sage: M.gens() - [v_0, v_1, v_2] + (v_0, v_1, v_2) If a string is given then it is used as the name of each generator, with the index of the generator appended in order to differentiate them:: sage: M.gens('generator') - [generator_0, generator_1, generator_2] + (generator_0, generator_1, generator_2) If a list or other iterable variable is given then each generator is named using the appropriate entry. The length of the variable @@ -1960,14 +1960,14 @@ def gens(self, names='v'): ... TypeError: can only concatenate list (not "str") to list sage: M.gens(['x', 'y', 'z']) - [x, y, z] + (x, y, z) Strings are iterable, so if the length of the string is equal to the number of generators then the characters of the string will be used as the names:: sage: M.gens('xyz') - [x, y, z] + (x, y, z) """ # Use names as a list if and only if it is the correct length uselist = (len(names) == self.dimension()) @@ -1986,7 +1986,7 @@ def gens(self, names='v'): basis.append(self({v: m}, names + "_" + str(i))) i += 1 - return basis + return tuple(basis) def coordinates(self, vector): """ From b9b9deb28299c936c0d8596c098c0a35f6643796 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 14:33:50 -0700 Subject: [PATCH 502/742] src/sage/tensor/modules/tensor_free_module.py: Update doctest output --- src/sage/tensor/modules/tensor_free_module.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 86f15aa9cd8..0a22d9cc5d1 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -378,9 +378,9 @@ def tensor_factors(self): sage: T.tensor_factors() [Rank-3 free module M over the Integer Ring, Rank-3 free module M over the Integer Ring, - Free module of type-(0,1) tensors on the Rank-3 free module M over the Integer Ring, - Free module of type-(0,1) tensors on the Rank-3 free module M over the Integer Ring, - Free module of type-(0,1) tensors on the Rank-3 free module M over the Integer Ring] + Dual of the Rank-3 free module M over the Integer Ring, + Dual of the Rank-3 free module M over the Integer Ring, + Dual of the Rank-3 free module M over the Integer Ring] """ if self._tensor_type == (0,1): # case of the dual raise NotImplementedError From b392efad6ac23fefe7210a99a4e9ba42a1b4d3aa Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 14:36:48 -0700 Subject: [PATCH 503/742] FiniteRankFreeModule_abstract.tensor: New --- .../tensor/modules/finite_rank_free_module.py | 115 ++++++++++++++---- 1 file changed, 93 insertions(+), 22 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index cc580d5a204..3d9c6861dbd 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -720,6 +720,28 @@ def map_isym(isym): result._index_maps = tuple(index_maps) return result + def tensor(self, *args, **kwds): + # Until https://trac.sagemath.org/ticket/30373 is done, + # TensorProductFunctor._functor_name is "tensor", so here we delegate. + r""" + Return the tensor product of ``self`` and ``others``. + + This method is invoked when :class:`~sage.categories.tensor.TensorProductFunctor` + is applied to parents. + + It just delegates to :meth:`tensor_product`. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(QQ, 2); M + 2-dimensional vector space over the Rational Field + sage: M20 = M.tensor_module(2, 0); M20 + Free module of type-(2,0) tensors on the 2-dimensional vector space over the Rational Field + sage: tensor([M20, M20]) + Free module of type-(4,0) tensors on the 2-dimensional vector space over the Rational Field + """ + return self.tensor_product(*args, **kwds) + def rank(self) -> int: r""" Return the rank of the free module ``self``. @@ -1897,10 +1919,81 @@ def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, - ``tensor_type`` -- pair ``(k, l)`` with ``k`` being the contravariant rank and ``l`` the covariant rank + - ``name`` -- (default: ``None``) string; name given to the tensor + - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote the tensor; if none is provided, the LaTeX symbol is set to ``name`` + + - ``sym`` -- (default: ``None``) a symmetry or an iterable of symmetries + among the tensor arguments: each symmetry is described by a tuple + containing the positions of the involved arguments, with the + convention ``position = 0`` for the first argument. For instance: + + * ``sym = (0,1)`` for a symmetry between the 1st and 2nd arguments + * ``sym = [(0,2), (1,3,4)]`` for a symmetry between the 1st and 3rd + arguments and a symmetry between the 2nd, 4th and 5th arguments. + + - ``antisym`` -- (default: ``None``) antisymmetry or iterable of + antisymmetries among the arguments, with the same convention + as for ``sym`` + + OUTPUT: + + - instance of + :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor` + representing the tensor defined on ``self`` with the provided + characteristics + + EXAMPLES: + + Tensors on a rank-3 free module:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: t = M._tensor((1,0), name='t') ; t + Element t of the Rank-3 free module M over the Integer Ring + """ + from .comp import CompWithSym + sym, antisym = CompWithSym._canonicalize_sym_antisym( + tensor_type[0] + tensor_type[1], sym, antisym) + # Special cases: + if tensor_type == (1,0): + return self.element_class(self, name=name, latex_name=latex_name) + elif tensor_type == (0,1): + return self.linear_form(name=name, latex_name=latex_name) + elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: + if len(antisym[0]) == tensor_type[1]: + return self.alternating_form(tensor_type[1], name=name, + latex_name=latex_name) + elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: + if len(antisym[0]) == tensor_type[0]: + return self.alternating_contravariant_tensor(tensor_type[0], + name=name, latex_name=latex_name) + # Generic case: + return self.tensor_module(*tensor_type).element_class(self, + tensor_type, name=name, latex_name=latex_name, + sym=sym, antisym=antisym) + + def tensor(self, *args, **kwds): + r""" + Construct a tensor on the free module ``self`` or a tensor product with other modules. + + If ``args`` consist of other parents, just delegate to :meth:`tensor_product`. + + Otherwise, construct a tensor from the following input. + + INPUT: + + - ``tensor_type`` -- pair ``(k, l)`` with ``k`` being the + contravariant rank and ``l`` the covariant rank + + - ``name`` -- (default: ``None``) string; name given to the tensor + + - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to + denote the tensor; if none is provided, the LaTeX symbol is set + to ``name`` + - ``sym`` -- (default: ``None``) a symmetry or an iterable of symmetries among the tensor arguments: each symmetry is described by a tuple containing the positions of the involved arguments, with the @@ -1955,28 +2048,6 @@ def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, sage: M.tensor((3,0), antisym=[[]]) Type-(3,0) tensor on the Rank-3 free module M over the Integer Ring """ - from .comp import CompWithSym - sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym) - # Special cases: - if tensor_type == (1,0): - return self.element_class(self, name=name, latex_name=latex_name) - elif tensor_type == (0,1): - return self.linear_form(name=name, latex_name=latex_name) - elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: - if len(antisym[0]) == tensor_type[1]: - return self.alternating_form(tensor_type[1], name=name, - latex_name=latex_name) - elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: - if len(antisym[0]) == tensor_type[0]: - return self.alternating_contravariant_tensor(tensor_type[0], - name=name, latex_name=latex_name) - # Generic case: - return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) - - def tensor(self, *args, **kwds): # Until https://trac.sagemath.org/ticket/30373 is done, # TensorProductFunctor._functor_name is "tensor", so this method # also needs to double as the tensor product construction From c7428e2f2d72b6840a6d557ab9838c307b47a58a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 16:53:53 -0700 Subject: [PATCH 504/742] src/sage/manifolds/differentiable/diff_form_module.py (VectorFieldDualFreeModule): New --- .../differentiable/diff_form_module.py | 172 ++++++++++++++++++ .../differentiable/vectorfield_module.py | 7 +- 2 files changed, 177 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index 0aa86ce31d5..980de5e64b8 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -905,3 +905,175 @@ def _repr_(self): description += "along the {} mapped into the {}".format( self._domain, self._ambient_domain) return description + + +class VectorFieldDualFreeModule(DiffFormFreeModule): + r""" + Free module of differential 1-forms along a differentiable manifold `U` + with values on a parallelizable manifold `M`. + + Given a differentiable manifold `U` and a differentiable map + `\Phi:\; U \rightarrow M` to a parallelizable manifold `M` of dimension + `n`, the set `\Omega^1(U, \Phi)` of 1-forms along `U` with values on `M` + is a free module of rank `n` over `C^k(U)`, the commutative + algebra of differentiable scalar fields on `U` (see + :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). + The standard case of 1-forms *on* a differentiable manifold `M` + corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are + `\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an + open interval of `\RR`). + + .. NOTE:: + + This class implements `\Omega^1(U, \Phi)` in the case where `M` is + parallelizable; `\Omega^1(U, \Phi)` is then a *free* module. If `M` + is not parallelizable, the class :class:`DiffFormModule` must be used + instead. + + INPUT: + + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector + fields along `U` associated with the map `\Phi: U \rightarrow V` + + EXAMPLES: + + Free module of 1-forms on a parallelizable 3-dimensional manifold:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: XM = M.vector_field_module() ; XM + Free module X(M) of vector fields on the 3-dimensional differentiable + manifold M + sage: A = M.diff_form_module(1) ; A + Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M + sage: latex(A) + \Omega^{1}\left(M\right) + + ``A`` is nothing but the dual of ``XM`` (the free module of vector fields on `M`) + and thus also equal to the 1st exterior + power of the dual, i.e. we have `\Omega^{1}(M) = \Lambda^1(\mathfrak{X}(M)^*) + = \mathfrak{X}(M)^*` (See + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`):: + + sage: A is XM.dual_exterior_power(1) + True + + `\Omega^{1}(M)` is a module over the algebra `C^k(M)` of (differentiable) + scalar fields on `M`:: + + sage: A.category() + Category of finite dimensional modules over Algebra of differentiable + scalar fields on the 3-dimensional differentiable manifold M + sage: CM = M.scalar_field_algebra() ; CM + Algebra of differentiable scalar fields on the 3-dimensional + differentiable manifold M + sage: A in Modules(CM) + True + sage: A.base_ring() + Algebra of differentiable scalar fields on + the 3-dimensional differentiable manifold M + sage: A.base_module() + Free module X(M) of vector fields on + the 3-dimensional differentiable manifold M + sage: A.base_module() is XM + True + sage: A.rank() + 3 + + Elements can be constructed from `A`. In particular, ``0`` yields + the zero element of `A`:: + + sage: A(0) + 1-form zero on the 3-dimensional differentiable manifold M + sage: A(0) is A.zero() + True + + while non-zero elements are constructed by providing their components + in a given vector frame:: + + sage: comp = [3*x,-z,4] + sage: a = A(comp, frame=X.frame(), name='a') ; a + 1-form a on the 3-dimensional differentiable manifold M + sage: a.display() + a = 3*x dx - z dy + 4 dz + + An alternative is to construct the 1-form from an empty list of + components and to set the nonzero nonredundant components afterwards:: + + sage: a = A([], name='a') + sage: a[0] = 3*x # component in the manifold's default frame + sage: a[1] = -z + sage: a[2] = 4 + sage: a.display() + a = 3*x dx - z dy + 4 dz + + Since any tensor field of type `(0,1)` is a 1-form, there is a coercion + map from the set `T^{(0,1)}(M)` of such tensors to `\Omega^1(M)`:: + + sage: T01 = M.tensor_field_module((0,1)) ; T01 + Free module T^(0,1)(M) of type-(0,1) tensors fields on the + 3-dimensional differentiable manifold M + sage: A.has_coerce_map_from(T01) + True + + There is also a coercion map in the reverse direction:: + + sage: T01.has_coerce_map_from(A) + True + + The coercion map `T^{(0,1)}(M) \rightarrow \Omega^1(M)` in action:: + + sage: b = T01([-x,2,3*y], name='b'); b + Tensor field b of type (0,1) on the 3-dimensional differentiable + manifold M + sage: b.display() + b = -x dx + 2 dy + 3*y dz + sage: lb = A(b) ; lb + 1-form b on the 3-dimensional differentiable manifold M + sage: lb.display() + b = -x dx + 2 dy + 3*y dz + + The coercion map `\Omega^1(M) \rightarrow T^{(0,1)}(M)` in action:: + + sage: tlb = T01(lb); tlb + Tensor field b of type (0,1) on + the 3-dimensional differentiable manifold M + sage: tlb == b + True + """ + + def __init__(self, vector_field_module): + r""" + Construct a free module of differential 1-forms. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: from sage.manifolds.differentiable.diff_form_module import DiffFormFreeModule + sage: A = DiffFormFreeModule(M.vector_field_module(), 1) ; A + Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M + sage: TestSuite(A).run() + Traceback (most recent call last): + ... + The following tests failed: _test_zero + + """ + DiffFormFreeModule.__init__(self, vector_field_module, 1) + + def tensor_type(self): + r""" + Return the tensor type of ``self``. + + EXAMPLES:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: from sage.manifolds.differentiable.diff_form_module import DiffFormFreeModule + sage: A = M.vector_field_module().dual(); A + Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M + sage: A.tensor_type() + (0, 1) + + """ + return (0, 1) diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 7b954d44e22..8ad69cc4ee3 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -1893,8 +1893,7 @@ def dual_exterior_power(self, p): Free module Omega^2(M) of 2-forms on the 2-dimensional differentiable manifold M sage: XM.dual_exterior_power(1) - Free module Omega^1(M) of 1-forms on the 2-dimensional - differentiable manifold M + Free module Omega^1(M) of 1-forms on the 2-dimensional differentiable manifold M sage: XM.dual_exterior_power(1) is XM.dual() True sage: XM.dual_exterior_power(0) @@ -1914,6 +1913,10 @@ def dual_exterior_power(self, p): except KeyError: if p == 0: L = self._ring + elif p == 1: + from sage.manifolds.differentiable.diff_form_module import \ + VectorFieldDualFreeModule + L = VectorFieldDualFreeModule(self) else: from sage.manifolds.differentiable.diff_form_module import \ DiffFormFreeModule From 8bfb9ff7897d4cb646ba95fa8c024b1a7428f0a1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 16:50:17 -0700 Subject: [PATCH 505/742] VectorFieldFreeModule.tensor_module: For (0,1), use the dual --- src/sage/manifolds/differentiable/vectorfield_module.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 8ad69cc4ee3..10e8d49382c 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -1794,6 +1794,8 @@ def tensor_module(self, k, l): except KeyError: if (k, l) == (1, 0): T = self + elif (k, l) == (0, 1): + T = self.dual() else: from sage.manifolds.differentiable.tensorfield_module import \ TensorFieldFreeModule From af96b069d20a84a55fdb7733b06b85478d06b2b2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 16:51:30 -0700 Subject: [PATCH 506/742] src/sage/manifolds/differentiable/diff_form_module.py: Update doctest output --- .../differentiable/diff_form_module.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index 980de5e64b8..bdf0921b462 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -665,8 +665,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): map from the set `T^{(0,1)}(M)` of such tensors to `\Omega^1(M)`:: sage: T01 = M.tensor_field_module((0,1)) ; T01 - Free module T^(0,1)(M) of type-(0,1) tensors fields on the - 3-dimensional differentiable manifold M + Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M sage: L1.has_coerce_map_from(T01) True @@ -689,8 +688,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): The coercion map `T^{(0,1)}(M) \rightarrow \Omega^1(M)` in action:: sage: b = T01([-x,2,3*y], name='b'); b - Tensor field b of type (0,1) on the 3-dimensional differentiable - manifold M + 1-form b on the 3-dimensional differentiable manifold M sage: b.display() b = -x dx + 2 dy + 3*y dz sage: lb = L1(b) ; lb @@ -701,8 +699,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): The coercion map `\Omega^1(M) \rightarrow T^{(0,1)}(M)` in action:: sage: tlb = T01(lb); tlb - Tensor field b of type (0,1) on - the 3-dimensional differentiable manifold M + 1-form b on the 3-dimensional differentiable manifold M sage: tlb == b True @@ -1011,8 +1008,7 @@ class VectorFieldDualFreeModule(DiffFormFreeModule): map from the set `T^{(0,1)}(M)` of such tensors to `\Omega^1(M)`:: sage: T01 = M.tensor_field_module((0,1)) ; T01 - Free module T^(0,1)(M) of type-(0,1) tensors fields on the - 3-dimensional differentiable manifold M + Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M sage: A.has_coerce_map_from(T01) True @@ -1024,8 +1020,7 @@ class VectorFieldDualFreeModule(DiffFormFreeModule): The coercion map `T^{(0,1)}(M) \rightarrow \Omega^1(M)` in action:: sage: b = T01([-x,2,3*y], name='b'); b - Tensor field b of type (0,1) on the 3-dimensional differentiable - manifold M + 1-form b on the 3-dimensional differentiable manifold M sage: b.display() b = -x dx + 2 dy + 3*y dz sage: lb = A(b) ; lb @@ -1036,8 +1031,7 @@ class VectorFieldDualFreeModule(DiffFormFreeModule): The coercion map `\Omega^1(M) \rightarrow T^{(0,1)}(M)` in action:: sage: tlb = T01(lb); tlb - Tensor field b of type (0,1) on - the 3-dimensional differentiable manifold M + 1-form b on the 3-dimensional differentiable manifold M sage: tlb == b True """ From bc99257b0540b3e1233250435b8f58bf8d10cdae Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 17:08:55 -0700 Subject: [PATCH 507/742] src/sage/manifolds/differentiable/diff_form_module.py: Fix doctests --- src/sage/manifolds/differentiable/diff_form_module.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index bdf0921b462..e3d00c2b11a 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -1044,13 +1044,9 @@ def __init__(self, vector_field_module): sage: M = Manifold(3, 'M') sage: X. = M.chart() - sage: from sage.manifolds.differentiable.diff_form_module import DiffFormFreeModule - sage: A = DiffFormFreeModule(M.vector_field_module(), 1) ; A + sage: A = M.vector_field_module().dual(); A Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M sage: TestSuite(A).run() - Traceback (most recent call last): - ... - The following tests failed: _test_zero """ DiffFormFreeModule.__init__(self, vector_field_module, 1) @@ -1063,7 +1059,6 @@ def tensor_type(self): sage: M = Manifold(3, 'M') sage: X. = M.chart() - sage: from sage.manifolds.differentiable.diff_form_module import DiffFormFreeModule sage: A = M.vector_field_module().dual(); A Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M sage: A.tensor_type() From 01550264f810b8f57537f05d431056dacba2fcda Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 17:28:44 -0700 Subject: [PATCH 508/742] src/sage/manifolds/differentiable/diff_form_module.py: Remove some doctests on coercions --- .../differentiable/diff_form_module.py | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index e3d00c2b11a..9aee83e2222 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -661,17 +661,12 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: L1 is XM.dual() True - Since any tensor field of type `(0,1)` is a 1-form, there is a coercion - map from the set `T^{(0,1)}(M)` of such tensors to `\Omega^1(M)`:: + Since any tensor field of type `(0,1)` is a 1-form, it is also equal to + the set `T^{(0,1)}(M)` of such tensors to `\Omega^1(M)`:: sage: T01 = M.tensor_field_module((0,1)) ; T01 Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M - sage: L1.has_coerce_map_from(T01) - True - - There is also a coercion map in the reverse direction:: - - sage: T01.has_coerce_map_from(L1) + sage: L1 is T01 True For a degree `p \geq 2`, the coercion holds only in the direction @@ -685,24 +680,6 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: A.has_coerce_map_from(T02) False - The coercion map `T^{(0,1)}(M) \rightarrow \Omega^1(M)` in action:: - - sage: b = T01([-x,2,3*y], name='b'); b - 1-form b on the 3-dimensional differentiable manifold M - sage: b.display() - b = -x dx + 2 dy + 3*y dz - sage: lb = L1(b) ; lb - 1-form b on the 3-dimensional differentiable manifold M - sage: lb.display() - b = -x dx + 2 dy + 3*y dz - - The coercion map `\Omega^1(M) \rightarrow T^{(0,1)}(M)` in action:: - - sage: tlb = T01(lb); tlb - 1-form b on the 3-dimensional differentiable manifold M - sage: tlb == b - True - The coercion map `\Omega^2(M) \rightarrow T^{(0,2)}(M)` in action:: sage: T02 = M.tensor_field_module((0,2)) ; T02 From 620df160109f99781c2b6c72ec596a176de5d2c5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 6 Sep 2022 18:04:30 -0700 Subject: [PATCH 509/742] src/sage/tensor/modules/tensor_free_submodule.py: Remove tensor_factors, add doctest for construction --- .../tensor/modules/tensor_free_submodule.py | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 49f1fba596c..ff4f739ac0d 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -178,13 +178,22 @@ def power_name(op, s, latex=False): latex_name=latex_name, category=category, ambient=ambient) - def tensor_factors(self): - raise NotImplementedError - def construction(self): - # TODO: Adapt from the code for the default name/latex_name in __init__. - # Define the symmetry group and its action (https://trac.sagemath.org/ticket/32029), - # use a construction functor for quotienting by the action + # TODO: Define the symmetry group and its action (https://trac.sagemath.org/ticket/34495), + # return the construction functor for invariant subobjects. + r""" + Return the functorial construction of ``self``. + + This implementation just returns ``None``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: Sym2M = M.tensor_module(2, 0, sym=range(2)); Sym2M + Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring + sage: Sym2M.construction() is None + True + """ return None @cached_method From 37d622c97d10adcf53a69f05765c378ffa543a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Sep 2022 07:38:31 +0200 Subject: [PATCH 510/742] fix doctests --- src/sage/groups/perm_gps/permgroup_element.pyx | 8 ++++---- .../characteristic_cohomology_class.py | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index 99cf04054cf..2204cb1b65c 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -88,7 +88,7 @@ We create element of a permutation group of large degree:: (1,30)(2,29)(3,28)(4,27)(5,26)(6,25)(7,24)(8,23)(9,22)(10,21)(11,20)(12,19)(13,18)(14,17)(15,16) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # Copyright (C) 2006 David Joyner # Copyright (C) 2019 Vincent Delecroix <20100.delecroix@gmail.com> @@ -97,8 +97,8 @@ We create element of a permutation group of large degree:: # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import copy import random @@ -944,7 +944,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): sage: S = SymmetricGroup(['a', 'b']) sage: latex(S.gens()) - \left[(\text{\texttt{a}},\text{\texttt{b}})\right] + \left((\text{\texttt{a}},\text{\texttt{b}})\right) """ from sage.misc.latex import latex return "".join(("(" + ",".join(latex(x) for x in cycle) + ")") diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 69744a312a5..902b3765044 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -271,14 +271,14 @@ """ -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2021 Michael Jung # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#****************************************************************************** +# ***************************************************************************** from sage.algebras.finite_gca import FiniteGCAlgebra from sage.combinat.free_module import IndexedFreeModuleElement @@ -693,10 +693,10 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): Algebra of characteristic cohomology classes of the Tangent bundle TM over the 8-dimensional differentiable manifold M sage: CR.gens() - [Characteristic cohomology class (p_1)(TM) of the Tangent bundle TM over + (Characteristic cohomology class (p_1)(TM) of the Tangent bundle TM over the 8-dimensional differentiable manifold M, Characteristic cohomology class (p_2)(TM) of the Tangent bundle TM - over the 8-dimensional differentiable manifold M] + over the 8-dimensional differentiable manifold M) The default base ring is `\QQ`:: @@ -712,12 +712,12 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): complex vector bundle E -> M of rank 2 over the base space 4-dimensional differentiable manifold M sage: CR_E.gens() - [Characteristic cohomology class (c_1)(E) of the Differentiable complex + (Characteristic cohomology class (c_1)(E) of the Differentiable complex vector bundle E -> M of rank 2 over the base space 4-dimensional differentiable manifold M, Characteristic cohomology class (c_2)(E) of the Differentiable complex vector bundle E -> M of rank 2 over the base space - 4-dimensional differentiable manifold M] + 4-dimensional differentiable manifold M) Characteristic cohomology class ring over an oriented manifold:: @@ -727,9 +727,9 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): True sage: CR = TS2.characteristic_cohomology_class_ring() sage: CR.gens() - [Characteristic cohomology class (e)(TS^2) of the Tangent bundle TS^2 + (Characteristic cohomology class (e)(TS^2) of the Tangent bundle TS^2 over the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean - space E^3] + space E^3) """ Element = CharacteristicCohomologyClassRingElement From 38a1c26680b667521a7bfb5d2a3eb8a3a7802cc9 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Wed, 7 Sep 2022 08:57:00 +0100 Subject: [PATCH 511/742] Altered how the raise_errors flag is used in _integrate_differentials_iteratively --- .../riemann_surfaces/riemann_surface.py | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 665eaaf0cd9..dee7059f539 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3083,19 +3083,13 @@ def initialise(z, i): # raises an error. If the value of False is taken, this failure to # converge happens silently, thus allowing the user to get *an* # answer out of the integration, but numerical imprecision is to be - # expected. + # expected. As such, we set the maximum number of steps in the sequence + # of DE integrations to be lower in the latter case. if raise_errors: n_steps = self._prec - 1 - - def error_handle(out): - raise ConvergenceError("Newton iteration fails to converge") - else: n_steps = 15 - def error_handle(out): - return out - V = VectorSpace(self._CC, self.genus) h = one Nh = (-lambert_w(-1, -tau / 2) / la).log().ceil() @@ -3144,7 +3138,10 @@ def fv(hj, previous_estimate_and_validity): Ndelta = Nnew_delta newg -= delta else: - outg.append(error_handle(newg)) + if raise_errors: + ConvergenceError("Newton iteration fails to converge") + else: + outg.append(newg) fj = V(outg) u1 = la * hj.cosh() w = u1 / (2 * u2.cosh() ** 2) @@ -3180,7 +3177,10 @@ def fv(hj, previous_estimate): Ndelta = Nnew_delta newg -= delta else: - outg.append(error_handle(newg)) + if raise_errors: + ConvergenceError("Newton iteration fails to converge") + else: + outg.append(newg) fj = V(outg) u1 = la * hj.cosh() w = u1 / (2 * u2.cosh() ** 2) @@ -3199,9 +3199,8 @@ def fv(hj, previous_estimate): # we now calculate the integral via double-exponential methods # repeatedly halving the step size and then using a heuristic - # convergence check. We again use the error_handle function to deal - # with the case where we exceed the maximum number of steps allowed, - # currently set by to make sure the step size does not fall below the + # convergence check. The maximum number of steps allowed is + # currently set to make sure the step size does not fall below the # resolution set by the binary precision used. for k in range(n_steps): hj = h0 @@ -3246,8 +3245,11 @@ def fv(hj, previous_estimate): # deemed to have converged by the heuristic error. If this has no # happened by the time we have gone through the process n_steps times, # we have one final error handle. Again, this will throw an error if - # the raise_errors flag is true, but will just return the answer otherwise. - return error_handle((J * results[-1], endscale * fj)) + # the raise_errors flag is true, but will just return the answer otherwise. + if raise_errors: + ConvergenceError("Newton iteration fails to converge") + + return (J * results[-1], endscale * fj) def _aj_based(self, P): r""" From de510a5732c108d8f916857d9e7af3f8b50754a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Sep 2022 10:09:51 +0200 Subject: [PATCH 512/742] trying to fix things in the categories --- src/sage/categories/groups.py | 21 ----------------- src/sage/categories/magmas.py | 4 +--- src/sage/categories/monoids.py | 42 ++++++++++++++++++++++++++++------ 3 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index b921570a63c..ef681dbb07a 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -640,27 +640,6 @@ def order(self): from sage.misc.misc_c import prod return prod(c.cardinality() for c in self.cartesian_factors()) - class ElementMethods: - def multiplicative_order(self): - r""" - Return the multiplicative order of this element. - - EXAMPLES:: - - sage: G1 = SymmetricGroup(3) - sage: G2 = SL(2,3) - sage: G = cartesian_product([G1,G2]) - sage: G((G1.gen(0), G2.gen(1))).multiplicative_order() - 12 - """ - from sage.rings.infinity import Infinity - orders = [x.multiplicative_order() for x in self.cartesian_factors()] - if any(o is Infinity for o in orders): - return Infinity - else: - from sage.arith.functions import LCM_list - return LCM_list(orders) - class Topological(TopologicalSpacesCategory): """ Category of topological groups. diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index c4a35fe6f1a..c1f255a6eb9 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -671,9 +671,7 @@ def __invert__(self): ZeroDivisionError: rational division by zero sage: ~C([2,2,2,2]) - Traceback (most recent call last): - ... - TypeError: no conversion of this rational to integer + (1/2, 1/2, 0.500000000000000, 3) """ # variant without coercion: # return self.parent()._cartesian_product_of_elements( diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index e8dd994ee3e..debf640d30d 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -252,18 +252,18 @@ def _div_(left, right): sage: c1._div_(c2) (x0*x1^-1, x1*x0^-1) - With this implementation, division will fail as soon - as ``right`` is not invertible, even if ``right`` + With this default implementation, division will fail as + soon as ``right`` is not invertible, even if ``right`` actually divides ``left``:: - sage: x = cartesian_product([2, 1]) + sage: x = cartesian_product([2, 0]) sage: y = cartesian_product([1, 1]) sage: x / y - (2, 1) - sage: x / x + (2, 0) + sage: y / x Traceback (most recent call last): ... - TypeError: no conversion of this rational to integer + ZeroDivisionError: rational division by zero TESTS:: @@ -367,7 +367,7 @@ def __invert__(self): [ 1 0] [-1 1] """ - return self.parent().one()._div_(self) + raise NotImplementedError("please implement __invert__") def inverse(self): """ @@ -669,3 +669,31 @@ def lift(i, gen): lambda g: (i, g)) for i, M in enumerate(F)]) return Family(gens_prod, lift, name="gen") + + class ElementMethods: + def multiplicative_order(self): + r""" + Return the multiplicative order of this element. + + EXAMPLES:: + + sage: G1 = SymmetricGroup(3) + sage: G2 = SL(2,3) + sage: G = cartesian_product([G1,G2]) + sage: G((G1.gen(0), G2.gen(1))).multiplicative_order() + 12 + """ + from sage.rings.infinity import Infinity + orders = [x.multiplicative_order() for x in self.cartesian_factors()] + if any(o is Infinity for o in orders): + return Infinity + else: + from sage.arith.functions import LCM_list + return LCM_list(orders) + + def __invert__(self): + """ + Return the inverse. + """ + build = self.parent()._cartesian_product_of_elements + return build([x.__invert__() for x in self.cartesian_factors()]) From 01ed9103d0b7d71a13f0ab0372aa0f479cea26ae Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 7 Sep 2022 19:03:29 +0900 Subject: [PATCH 513/742] Using the free_resolution() hook to let each class decide what to build. --- src/sage/homology/free_resolution.py | 96 ++++++++++++++------------ src/sage/homology/graded_resolution.py | 8 +-- src/sage/rings/ideal.py | 2 + src/sage/rings/polynomial/ideal.py | 1 - 4 files changed, 54 insertions(+), 53 deletions(-) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index f6bc238ff4d..59059ea1d40 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -84,11 +84,22 @@ class FreeResolution(SageObject, metaclass=ClasscallMetaclass): - """ - Abstract base class for free resolutions. + r""" + A free resolution. + + Let `R` be a commutative ring. A *free resolution* of an `R`-module `M` + is a (possibly infinite) chain complex of free `R`-modules + + .. MATH:: + + 0 \xleftarrow{d_0} R^{n_1} \xleftarrow{d_1} R^{n_1} \xleftarrow{d_2} + \cdots \xleftarrow{d_k} R^{n_k} \xleftarrow{d_{k+1}} \cdots + + that is exact (all homology groups are zero) such that the image + of `d_1` is `M`. """ @staticmethod - def __classcall_private__(cls, module, degrees=None, shifts=None, name='S', graded=False, **kwds): + def __classcall_private__(cls, module, *args, graded=False, degrees=None, shifts=None, **kwds): """ Dispatch to the correct constructor. @@ -127,23 +138,13 @@ def __classcall_private__(cls, module, degrees=None, shifts=None, name='S', grad False sage: xb, yb = Q.gens() sage: FreeResolution(Q.ideal([xb])) # has torsion - Traceback (most recent call last): - ... - NotImplementedError: the module must be a free module or have the base ring be a polynomial ring using Singular + NotImplementedError: the ring must be a polynomial ring using Singular """ - # The module might still be free even if is_free_module is False. - # This is just to handle the cases when we trivially know it is. - is_free_module = False - if isinstance(module, Ideal_generic): - S = module.ring() - if len(module.gens()) == 1 and S in IntegralDomains(): - is_free_module = True - elif isinstance(module, Module_free_ambient): - S = module.base_ring() - if (S in PrincipalIdealDomains() - or isinstance(module, FreeModule_generic)): - is_free_module = True - elif isinstance(module, Matrix): + if degrees is not None or shifts is not None: + graded = True + + if isinstance(module, Matrix): + is_free_module = False S = module.base_ring() if S in PrincipalIdealDomains(): module = module.echelon_form() @@ -155,33 +156,36 @@ def __classcall_private__(cls, module, degrees=None, shifts=None, name='S', grad # We need to make an immutable copy of the matrix module = copy(module) module.set_immutable() - else: - raise TypeError('no module, matrix, or ideal') + if is_free_module: + if graded: + from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + return GradedFiniteFreeResolution_free_module(module, + *args, + degrees=degrees, + shifts=shifts, + **kwds) + return FiniteFreeResolution_free_module(module, *args, **kwds) - if not is_free_module: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular if not isinstance(S, MPolynomialRing_libsingular): - raise NotImplementedError("the module must be a free module or have the base ring be a polynomial ring using Singular") + raise NotImplementedError("the matrix must be over a PID or a " + " polynomial ring that is using Singular") - if graded or degrees is not None or shifts is not None: + if graded: # We are computing a graded resolution from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular - return GradedFiniteFreeResolution_singular(module, degrees=degrees, shifts=shifts, name=name, **kwds) - - return FiniteFreeResolution_singular(module, name=name, **kwds) + return GradedFiniteFreeResolution_singular(module, *args, degrees=degrees, + shifts=shifts, **kwds) - # Otherwise we know it is a free module + return FiniteFreeResolution_singular(module, **kwds) - if graded or degrees is not None or shifts is not None: - # We are computing a graded resolution - from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module - return GradedFiniteFreeResolution_free_module(module, degrees=degrees, shifts=shifts, name=name, **kwds) - - return FiniteFreeResolution_free_module(module, name=name, **kwds) + if graded: + return module.graded_free_resolution(*args, **kwds) + return module.free_resolution(*args, **kwds) def __init__(self, module, name='S', **kwds): """ - Initialize. + Initialize ``self``. INPUT: @@ -303,9 +307,6 @@ class FiniteFreeResolution(FreeResolution): r""" Finite free resolutions. - A subclass must provide a ``_maps`` attribute that contains a list of the - maps defining the resolution. - The matrix at index `i` in the list defines the differential map from `(i + 1)`-th free module to the `i`-th free module over the base ring by multiplication on the left. The number of matrices in the list is the @@ -315,6 +316,9 @@ class FiniteFreeResolution(FreeResolution): Note that the first matrix in the list defines the differential map at homological index `1`. + A subclass must provide a ``_maps`` attribute that contains a list of the + maps defining the resolution. + A subclass can define ``_initial_differential`` attribute that contains the `0`-th differential map whose codomain is the target of the free resolution. @@ -576,7 +580,7 @@ def _initial_differential(self): S = module.ring() M = FreeModule(S, 1) N = M.submodule([vector([g]) for g in module.gens()]) - elif isinstance(ideal, Module_free_ambient): + elif isinstance(module, Module_free_ambient): S = module.base_ring() M = module.ambient_module() N = module @@ -600,7 +604,8 @@ def _m(self): sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = FreeResolution(I) sage: r._m() - Ideal (-z^2 + y*w, y*z - x*w, -y^2 + x*z) of Multivariate Polynomial Ring in x, y, z, w over Rational Field + Ideal (-z^2 + y*w, y*z - x*w, -y^2 + x*z) of + Multivariate Polynomial Ring in x, y, z, w over Rational Field sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() sage: r = FreeResolution(m, name='S') @@ -638,7 +643,8 @@ class FiniteFreeResolution_free_module(FiniteFreeResolution): sage: w = M([0, x, 2*x]) sage: S = M.submodule([v, w]) sage: S - Free module of degree 3 and rank 2 over Univariate Polynomial Ring in x over Rational Field + Free module of degree 3 and rank 2 over + Univariate Polynomial Ring in x over Rational Field Echelon basis matrix: [ x^2 2*x^2 3*x^2] [ 0 x 2*x] @@ -737,9 +743,7 @@ class FiniteFreeResolution_singular(FiniteFreeResolution): - ``module`` -- a submodule of a free module `M` of rank `n` over `S` or an ideal of a multi-variate polynomial ring - - ``name`` -- string (optional); name of the base ring - - ``algorithm`` -- (default: ``'heuristic'``) Singular algorithm to compute a resolution of ``ideal`` @@ -748,8 +752,8 @@ class FiniteFreeResolution_singular(FiniteFreeResolution): If ``module`` is an ideal of `S`, it is considered as a submodule of a free module of rank `1` over `S`. - The available algorithms and the corresponding Singular commands are shown - below: + The available algorithms and the corresponding Singular commands + are shown below: ============= ============================ algorithm Singular commands @@ -816,7 +820,7 @@ class FiniteFreeResolution_singular(FiniteFreeResolution): """ def __init__(self, module, name='S', algorithm='heuristic', **kwds): r""" - Initialize. + Initialize ``self``. TESTS:: diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index 1728193dfba..97a3cb9624b 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -87,7 +87,6 @@ FiniteFreeResolution_free_module, FiniteFreeResolution_singular) - class GradedFiniteFreeResolution(FiniteFreeResolution): r""" Graded finite free resolutions. @@ -96,14 +95,11 @@ class GradedFiniteFreeResolution(FiniteFreeResolution): - ``module`` -- a homogeneous submodule of a free module `M` of rank `n` over `S` or a homogeneous ideal of a multivariate polynomial ring `S` - - ``degrees`` -- (default: a list with all entries `1`) a list of integers or integer vectors giving degrees of variables of `S` - - ``shifts`` -- a list of integers or integer vectors giving shifts of degrees of `n` summands of the free module `M`; this is a list of zero degrees of length `n` by default - - ``name`` -- a string; name of the base ring .. WARNING:: @@ -111,8 +107,8 @@ class GradedFiniteFreeResolution(FiniteFreeResolution): This does not check that the module is homogeneous. """ def __init__(self, module, degrees=None, shifts=None, name='S', **kwds): - """ - Initialize. + r""" + Initialize ``self``. TESTS:: diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index b1537ee3651..311b9c45a10 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -1217,6 +1217,8 @@ def free_resolution(self, *args, **kwds): sage: I.free_resolution() S^1 <-- S^1 <-- 0 """ + if not self.is_principal(): + raise NotImplementedError("the ideal must be a prinical ideal") from sage.homology.free_resolution import FiniteFreeResolution_free_module return FiniteFreeResolution_free_module(self, *args, **kwds) diff --git a/src/sage/rings/polynomial/ideal.py b/src/sage/rings/polynomial/ideal.py index b768ed1a96b..857718c9a10 100644 --- a/src/sage/rings/polynomial/ideal.py +++ b/src/sage/rings/polynomial/ideal.py @@ -84,4 +84,3 @@ 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) - From 35a97798ab87f572f5fa6ca1d865359d0a039c06 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 7 Sep 2022 19:08:28 +0900 Subject: [PATCH 514/742] Using the hook in projective morphism. --- src/sage/schemes/projective/projective_morphism.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index e3347c409bc..fb3c7d4781b 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -88,7 +88,6 @@ from sage.categories.number_fields import NumberFields from sage.categories.homset import Hom, End from sage.categories.fields import Fields -from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular _NumberFields = NumberFields() _FiniteFields = FiniteFields() @@ -2691,7 +2690,7 @@ def projective_degrees(self): I = G.defining_ideal() # a bihomogeneous ideal degrees = xn*[vector([1,0])] + yn*[vector([0,1])] - res = GradedFiniteFreeResolution_singular(I, degrees, algorithm='shreyer') + res = I.graded_free_resolution(degrees=degrees, algorithm='shreyer') kpoly = res.K_polynomial() L = kpoly.parent() From 0e19786c4715fa582ec87121592595626c4a56ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Sep 2022 12:22:03 +0200 Subject: [PATCH 515/742] add doctest --- src/sage/categories/monoids.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index debf640d30d..c7119e0275f 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -694,6 +694,15 @@ def multiplicative_order(self): def __invert__(self): """ Return the inverse. + + EXAMPLES:: + + sage: a1 = Permutation((4,2,1,3)) + sage: a2 = SL(2,3)([2,1,1,1]) + sage: h = cartesian_product([a1,a2]) + sage: ~h + ([2, 4, 1, 3], [1 2] + [2 2]) """ build = self.parent()._cartesian_product_of_elements return build([x.__invert__() for x in self.cartesian_factors()]) From 5c35ae5b0a0b6893f1a060319757aa5cb64dffd6 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 7 Sep 2022 19:43:11 +0900 Subject: [PATCH 516/742] Making singular.pyx full coverage. --- src/sage/libs/singular/singular.pyx | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index bb729cf2db2..d8ea7b07f3c 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -653,6 +653,24 @@ cpdef list si2sa_resolution(Resolution res): - ``res`` -- Singular resolution The procedure is destructive and ``res`` is not usable afterward. + + EXAMPLES:: + + sage: from sage.libs.singular.singular import si2sa_resolution + sage: from sage.libs.singular.function import singular_function + sage: module = singular_function("module") + sage: mres = singular_function('mres') + + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: mod = module(I) + sage: r = mres(mod, 0) + sage: si2sa_resolution(r) + [ + [ y x] + [-z -y] + [z^2 - y*w y*z - x*w y^2 - x*z], [ w z] + ] """ cdef ring *singular_ring cdef syStrategy singular_res @@ -754,6 +772,27 @@ cpdef tuple si2sa_resolution_graded(Resolution res, tuple degrees): - ``degrees`` -- list of integers or integer vectors The procedure is destructive, and ``res`` is not usable afterward. + + EXAMPLES:: + + sage: from sage.libs.singular.singular import si2sa_resolution_graded + sage: from sage.libs.singular.function import singular_function + sage: module = singular_function("module") + sage: mres = singular_function('mres') + + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: mod = module(I) + sage: r = mres(mod, 0) + sage: res_mats, res_degs = si2sa_resolution_graded(r, (1, 1, 1, 1)) + sage: res_mats + [ + [ y x] + [-z -y] + [z^2 - y*w y*z - x*w y^2 - x*z], [ w z] + ] + sage: res_degs + [[[2], [2], [2]], [[1, 1, 1], [1, 1, 1]]] """ cdef ring *singular_ring cdef syStrategy singular_res From 7b832f26298289eec02f369c66b06faa14847587 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Wed, 7 Sep 2022 11:50:23 +0100 Subject: [PATCH 517/742] Added to author list. --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index dee7059f539..24feb919881 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -25,6 +25,7 @@ - Alexandre Zotine, Nils Bruin (2017-06-10): initial version - Nils Bruin, Jeroen Sijsling (2018-01-05): algebraization, isomorphisms - Linden Disney-Hogg, Nils Bruin (2021-06-23): efficient integration +- Linden Disney-Hogg, Nils Bruin (2022-09-07): Abel-Jacobi map EXAMPLES: From 250c5cb139df7c52eadb6608437df8cb4d1cdc24 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 7 Sep 2022 20:26:37 +0900 Subject: [PATCH 518/742] Some edits --- src/sage/homology/free_resolution.py | 4 ++++ src/sage/rings/ideal.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 59059ea1d40..7bdd8583ca0 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -138,6 +138,8 @@ def __classcall_private__(cls, module, *args, graded=False, degrees=None, shifts False sage: xb, yb = Q.gens() sage: FreeResolution(Q.ideal([xb])) # has torsion + Traceback (most recent call last): + ... NotImplementedError: the ring must be a polynomial ring using Singular """ if degrees is not None or shifts is not None: @@ -743,7 +745,9 @@ class FiniteFreeResolution_singular(FiniteFreeResolution): - ``module`` -- a submodule of a free module `M` of rank `n` over `S` or an ideal of a multi-variate polynomial ring + - ``name`` -- string (optional); name of the base ring + - ``algorithm`` -- (default: ``'heuristic'``) Singular algorithm to compute a resolution of ``ideal`` diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 311b9c45a10..8e584ee0141 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -1218,7 +1218,7 @@ def free_resolution(self, *args, **kwds): S^1 <-- S^1 <-- 0 """ if not self.is_principal(): - raise NotImplementedError("the ideal must be a prinical ideal") + raise NotImplementedError("the ideal must be a principal ideal") from sage.homology.free_resolution import FiniteFreeResolution_free_module return FiniteFreeResolution_free_module(self, *args, **kwds) From 24b88a5991a41d2bf9cf4fe9c2281b05f9fefcf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Sep 2022 14:03:14 +0200 Subject: [PATCH 519/742] fix doc --- src/sage/categories/monoids.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index c7119e0275f..2daeab2ac71 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -358,7 +358,8 @@ def __invert__(self): r""" Return the inverse of ``self``. - The default implementation is to divide ``self.one()``. + There is no default implementation, to avoid conflict + with the default implementation of ``_div_``. EXAMPLES:: From 6dba5e5ca91ec27e175aa73c3526a2bc15f39121 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 8 Sep 2022 01:17:39 +0900 Subject: [PATCH 520/742] Hot fixes --- src/sage/homology/free_resolution.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 7bdd8583ca0..7d3ea29057e 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -6,7 +6,7 @@ .. MATH:: - 0 \xleftarrow{d_0} R^{n_1} \xleftarrow{d_1} R^{n_1} \xleftarrow{d_2} + R^{n_1} \xleftarrow{d_1} R^{n_1} \xleftarrow{d_2} \cdots \xleftarrow{d_k} R^{n_k} \xleftarrow{d_{k+1}} 0 terminating with a zero module at the end that is exact (all homology groups @@ -92,7 +92,7 @@ class FreeResolution(SageObject, metaclass=ClasscallMetaclass): .. MATH:: - 0 \xleftarrow{d_0} R^{n_1} \xleftarrow{d_1} R^{n_1} \xleftarrow{d_2} + R^{n_1} \xleftarrow{d_1} R^{n_1} \xleftarrow{d_2} \cdots \xleftarrow{d_k} R^{n_k} \xleftarrow{d_{k+1}} \cdots that is exact (all homology groups are zero) such that the image @@ -285,7 +285,10 @@ def differential(self, i): def target(self): r""" - Return the codomain of the ``0``-th differential map. + Return the codomain of the `0`-th differential map. + + The codomain of the `0`-th differential map is the cokernel of + the first differential map. EXAMPLES:: From b6a5773fc8c6b861150dc9e03d241ddf41741c24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Sep 2022 18:44:31 +0200 Subject: [PATCH 521/742] fix typo --- src/sage/categories/monoids.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index 2daeab2ac71..33229d27390 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -374,7 +374,7 @@ def inverse(self): """ Return the inverse of ``self``. - This an alias for inversion, defined in ``__invert__``. + This is an alias for inversion, defined in ``__invert__``. Element classes should implement ``__invert__`` only. From 87df84eecb0cb1bc7e99b834de0ee266bcc56f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Sep 2022 19:56:35 +0200 Subject: [PATCH 522/742] really fix doctest --- .../differentiable/characteristic_cohomology_class.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 902b3765044..689760625da 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -729,7 +729,7 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): sage: CR.gens() (Characteristic cohomology class (e)(TS^2) of the Tangent bundle TS^2 over the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean - space E^3) + space E^3,) """ Element = CharacteristicCohomologyClassRingElement @@ -1043,6 +1043,7 @@ def _repr_(self): repr = f'Algebra of characteristic cohomology classes of the {vbundle}' return repr + # ***************************************************************************** # ALGORITHMS # ***************************************************************************** @@ -1103,6 +1104,7 @@ def multiplicative_sequence(q, n=None): for p in Partitions(k)}) return Sym.e()(mon_pol) + def additive_sequence(q, k, n=None): r""" Turn the polynomial ``q`` into its additive sequence. @@ -1845,4 +1847,4 @@ def get_gen_pow(self, nab, i, n): return nab._domain._one_scalar_field # no computation necessary if i == 0: return fast_wedge_power(EulerAlgorithm().get(nab)[0], n) - return fast_wedge_power(PontryaginAlgorithm().get(nab)[i-1], n) + return fast_wedge_power(PontryaginAlgorithm().get(nab)[i - 1], n) From 4c9be6b79b6fa8f79edf3f2298c924d0e185f1fd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 7 Sep 2022 11:10:11 -0700 Subject: [PATCH 523/742] src/sage/manifolds/differentiable/diff_form_module.py: doc: add that the case p=1 of M parallelizable is implemented via VectorFieldDualFreeModule --- src/sage/manifolds/differentiable/diff_form_module.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index 9aee83e2222..a3026864ffc 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -12,6 +12,8 @@ (in practice, not parallelizable) differentiable manifold `M` - :class:`DiffFormFreeModule` for differential forms with values on a parallelizable manifold `M` + (the subclass :class:`VectorFieldDualFreeModule` implements the special + case of differential 1-forms on a parallelizable manifold `M`) AUTHORS: @@ -575,6 +577,8 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): is not parallelizable, the class :class:`DiffFormModule` must be used instead. + For the special case of `-forms, use the class :class:`VectorFieldDualFreeModule`. + INPUT: - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector From 06710c12cc1d73cafe81e087742a514808985f86 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 7 Sep 2022 11:11:06 -0700 Subject: [PATCH 524/742] src/sage/manifolds/differentiable/diff_form_module.py, vectorfield_module.py: Update copyright using 'git blame -w --date=format:%Y FILE.py | sort -k2', add to AUTHORS --- src/sage/manifolds/differentiable/diff_form_module.py | 7 +++++-- .../manifolds/differentiable/vectorfield_module.py | 11 ++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index a3026864ffc..cf69dd22c28 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -19,6 +19,7 @@ - Eric Gourgoulhon (2015): initial version - Travis Scrimshaw (2016): review tweaks +- Matthias Koeppe (2022): :class:`VectorFieldDualFreeModule` REFERENCES: @@ -27,8 +28,10 @@ """ # ***************************************************************************** -# Copyright (C) 2015 Eric Gourgoulhon -# Copyright (C) 2016 Travis Scrimshaw +# Copyright (C) 2015-2021 Eric Gourgoulhon +# 2016 Travis Scrimshaw +# 2020 Michael Jung +# 2022 Matthias Koeppe # # 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/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 10e8d49382c..e7a9fcc8867 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -28,9 +28,14 @@ """ # ****************************************************************************** -# Copyright (C) 2015 Eric Gourgoulhon -# Copyright (C) 2015 Michal Bejger -# Copyright (C) 2016 Travis Scrimshaw +# Copyright (C) 2015-2021 Eric Gourgoulhon +# 2015 Michal Bejger +# 2016 Travis Scrimshaw +# 2018 Florentin Jaffredo +# 2019 Hans Fotsing Tetsing +# 2020 Michael Jung +# 2020-2022 Matthias Koeppe +# 2021-2022 Tobias Diez # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of From e08cd7a4e9fb5d6492e8a611040dd562bdddf6cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 8 Sep 2022 09:17:10 +0200 Subject: [PATCH 525/742] tweak doc --- src/sage/categories/monoids.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index 33229d27390..541e867074f 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -374,15 +374,15 @@ def inverse(self): """ Return the inverse of ``self``. - This is an alias for inversion, defined in ``__invert__``. - - Element classes should implement ``__invert__`` only. + This is an alias for inversion, which can also be invoked + by ``~x`` for an element ``x``. EXAMPLES:: sage: AA(sqrt(~2)).inverse() 1.414213562373095? """ + # Nota Bene: Element classes should implement ``__invert__`` only. return self.__invert__() class Commutative(CategoryWithAxiom): From d0fbe93d4de3b38b40034b4c1743399f37393a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 8 Sep 2022 11:28:56 +0200 Subject: [PATCH 526/742] tweak doc again --- src/sage/categories/monoids.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index 541e867074f..93638b04078 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -356,7 +356,7 @@ def powers(self, n): def __invert__(self): r""" - Return the inverse of ``self``. + Return the multiplicative inverse of ``self``. There is no default implementation, to avoid conflict with the default implementation of ``_div_``. @@ -372,7 +372,7 @@ def __invert__(self): def inverse(self): """ - Return the inverse of ``self``. + Return the multiplicative inverse of ``self``. This is an alias for inversion, which can also be invoked by ``~x`` for an element ``x``. From 4676b51a0f360a33b0b1bdddf644d6f499f18e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 8 Sep 2022 11:45:47 +0200 Subject: [PATCH 527/742] using items in indexed_element.pyx --- .../modules/with_basis/indexed_element.pyx | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index cd1f17112f0..ecfcdf14a04 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -8,7 +8,7 @@ AUTHORS: - Travis Scrimshaw (29-08-2022): Implemented ``copy`` as the identity map. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017, 2022 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ AUTHORS: # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from sage.structure.element cimport parent from sage.structure.richcmp cimport richcmp, rich_to_bool @@ -30,12 +30,14 @@ from sage.typeset.unicode_art import UnicodeArt, empty_unicode_art, unicode_art from sage.categories.all import Category, Sets, ModulesWithBasis from sage.data_structures.blas_dict cimport add, negate, scal, axpy + cdef class IndexedFreeModuleElement(ModuleElement): def __init__(self, M, x): """ - Create a combinatorial module element. This should never be - called directly, but only through the parent combinatorial - free module's :meth:`__call__` method. + Create a combinatorial module element. + + This should never be called directly, but only through the + parent combinatorial free module's :meth:`__call__` method. TESTS:: @@ -60,19 +62,17 @@ cdef class IndexedFreeModuleElement(ModuleElement): sage: [i for i in sorted(f)] [('a', 1), ('c', 3)] - :: - sage: s = SymmetricFunctions(QQ).schur() sage: a = s([2,1]) + s([3]) sage: [i for i in sorted(a)] [([2, 1], 1), ([3], 1)] """ - return iter(self._monomial_coefficients.iteritems()) + return iter(self._monomial_coefficients.items()) def __contains__(self, x): """ - Returns whether or not a combinatorial object x indexing a basis - element is in the support of self. + Return whether or not a combinatorial object ``x`` indexing a basis + element is in the support of ``self``. EXAMPLES:: @@ -84,8 +84,6 @@ cdef class IndexedFreeModuleElement(ModuleElement): sage: 'b' in f False - :: - sage: s = SymmetricFunctions(QQ).schur() sage: a = s([2,1]) + s([3]) sage: Partition([2,1]) in a @@ -129,7 +127,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): hash value of the parent. See :trac:`15959`. """ if not self._hash_set: - self._hash = hash(frozenset(self._monomial_coefficients.iteritems())) + self._hash = hash(frozenset(self._monomial_coefficients.items())) self._hash_set = True return self._hash @@ -148,7 +146,8 @@ cdef class IndexedFreeModuleElement(ModuleElement): def __setstate__(self, state): r""" For unpickling old ``CombinatorialFreeModuleElement`` classes. - See :trac:`22632` and register_unpickle_override below. + + See :trac:`22632` and ``register_unpickle_override`` below. EXAMPLES:: @@ -178,7 +177,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): 2*B['x'] + 2*B['y'] """ self._set_parent(state[0]) - for k, v in state[1].iteritems(): + for k, v in state[1].items(): setattr(self, k, v) def __copy__(self): @@ -257,7 +256,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): def _sorted_items_for_printing(self): """ - Returns the items (i.e terms) of ``self``, sorted for printing + Return the items (i.e. terms) of ``self``, sorted for printing. EXAMPLES:: @@ -274,7 +273,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): .. SEEALSO:: :meth:`_repr_`, :meth:`_latex_`, :meth:`print_options` """ print_options = self._parent.print_options() - v = list(self._monomial_coefficients.iteritems()) + v = list(self._monomial_coefficients.items()) try: v.sort(key=lambda monomial_coeff: print_options['sorting_key'](monomial_coeff[0]), @@ -361,7 +360,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): except AttributeError: one_basis = None - for (monomial,c) in terms: + for monomial, c in terms: b = repr_monomial(monomial) # PCR if c != 0: break_points = [] @@ -620,8 +619,8 @@ cdef class IndexedFreeModuleElement(ModuleElement): if op == Py_NE: return True - v = sorted(self._monomial_coefficients.iteritems()) - w = sorted(elt._monomial_coefficients.iteritems()) + v = sorted(self._monomial_coefficients.items()) + w = sorted(elt._monomial_coefficients.items()) return richcmp(v, w, op) cpdef _add_(self, other): @@ -938,11 +937,12 @@ cdef class IndexedFreeModuleElement(ModuleElement): D = self._monomial_coefficients if not B.is_field(): return type(self)(F, {k: c._divide_if_possible(x) - for k, c in D.iteritems()}) + for k, c in D.items()}) x_inv = B(x) ** -1 return type(self)(F, scal(x_inv, D)) + def _unpickle_element(C, d): """ Unpickle an element in ``C`` given by ``d``. From fbf37700b85f01775b5b079998807c5ec994f457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 8 Sep 2022 12:05:30 +0200 Subject: [PATCH 528/742] deprecated old py2-like iteritems and itervalues in weak_dict --- src/sage/misc/weak_dict.pyx | 59 +++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/src/sage/misc/weak_dict.pyx b/src/sage/misc/weak_dict.pyx index ac7bf3bbbd2..d52bedacfa4 100644 --- a/src/sage/misc/weak_dict.pyx +++ b/src/sage/misc/weak_dict.pyx @@ -129,6 +129,8 @@ from cpython.object cimport PyObject_Hash from cpython.ref cimport Py_INCREF, Py_XINCREF, Py_XDECREF from sage.cpython.dict_del_by_value cimport * +from sage.misc.superseded import deprecation + cdef extern from "Python.h": PyObject* Py_None # we need this redefinition because we want to be able to call @@ -369,7 +371,7 @@ cdef class WeakValueDictionary(dict): True """ - return WeakValueDictionary(self.iteritems()) + return WeakValueDictionary(self.items()) def __deepcopy__(self, memo): """ @@ -403,7 +405,7 @@ cdef class WeakValueDictionary(dict): """ out = WeakValueDictionary() - for k,v in self.iteritems(): + for k,v in self.items(): out[deepcopy(k, memo)] = v return out @@ -526,7 +528,7 @@ cdef class WeakValueDictionary(dict): sage: _ = gc.collect() sage: len(D) 1 - sage: D.items() + sage: list(D.items()) [(2, Integer Ring)] Check that :trac:`15956` has been fixed, i.e., a ``TypeError`` is @@ -620,7 +622,7 @@ cdef class WeakValueDictionary(dict): KeyError: 'popitem(): weak value dictionary is empty' """ - for k,v in self.iteritems(): + for k,v in self.items(): del self[k] return k, v raise KeyError('popitem(): weak value dictionary is empty') @@ -811,6 +813,24 @@ cdef class WeakValueDictionary(dict): return list(iter(self)) def itervalues(self): + """ + Deprecated. + + EXAMPLES:: + + sage: import sage.misc.weak_dict + sage: class Vals(): pass + sage: L = [Vals() for _ in range(10)] + sage: D = sage.misc.weak_dict.WeakValueDictionary(enumerate(L)) + sage: T = list(D.itervalues()) + doctest:warning...: + DeprecationWarning: use values instead + See https://trac.sagemath.org/34488 for details. + """ + deprecation(34488, "use values instead") + return self.values() + + def values(self): """ Iterate over the values of this dictionary. @@ -842,7 +862,7 @@ cdef class WeakValueDictionary(dict): sage: del D[2] sage: del L[5] - sage: for v in sorted(D.itervalues()): + sage: for v in sorted(D.values()): ....: print(v) <0> <1> @@ -866,7 +886,7 @@ cdef class WeakValueDictionary(dict): finally: self._exit_iter() - def values(self): + def values_list(self): """ Return the list of values. @@ -893,13 +913,28 @@ cdef class WeakValueDictionary(dict): sage: del D[2] sage: del L[5] - sage: sorted(D.values()) + sage: sorted(D.values_list()) [<0>, <1>, <3>, <4>, <6>, <7>, <8>, <9>] - """ - return list(self.itervalues()) + return list(self.values()) def iteritems(self): + """ + EXAMPLES:: + + sage: import sage.misc.weak_dict + sage: class Vals(): pass + sage: L = [Vals() for _ in range(10)] + sage: D = sage.misc.weak_dict.WeakValueDictionary(enumerate(L)) + sage: T = list(D.iteritems()) + doctest:warning...: + DeprecationWarning: use items instead + See https://trac.sagemath.org/34488 for details. + """ + deprecation(34488, "use items instead") + return self.items() + + def items(self): """ Iterate over the items of this dictionary. @@ -946,7 +981,7 @@ cdef class WeakValueDictionary(dict): sage: del D[Keys(2)] sage: del L[5] - sage: for k,v in sorted(D.iteritems()): + sage: for k,v in sorted(D.items()): ....: print("{} {}".format(k, v)) [0] <0> [1] <1> @@ -970,7 +1005,7 @@ cdef class WeakValueDictionary(dict): finally: self._exit_iter() - def items(self): + def items_list(self): """ The key-value pairs of this dictionary. @@ -1022,7 +1057,7 @@ cdef class WeakValueDictionary(dict): ([8], <8>), ([9], <9>)] """ - return list(self.iteritems()) + return list(self.items()) cdef int _enter_iter(self) except -1: """ From 312a91d4f327802ca1e6d48975cd1d221128833e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 8 Sep 2022 13:50:17 +0200 Subject: [PATCH 529/742] re-introduce default inversion --- src/sage/structure/element.pyx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index ff18599617e..b5d83ef71b6 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -2613,6 +2613,15 @@ cdef class MultiplicativeGroupElement(MonoidElement): """ return self * ~right + def __invert__(self): + r""" + Return the multiplicative inverse of ``self``. + + This may cause infinite recursion because of the default definition + of division using inversion in ``_div_``. + """ + return self._parent.one() / self + def is_RingElement(x): """ From 54a7e3cc9bfe46eecd463826850507254e35d103 Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Thu, 8 Sep 2022 13:22:43 +0100 Subject: [PATCH 530/742] Edit documentation to improve readability. Based on comment 69 by TS, made some edits to the documentation to make it easier to parse. Edits to the code itself for the sake of formatting, aside from occurences of ** as exponentiation, was not done to avoid making the run through black redundant. --- .../riemann_surfaces/riemann_surface.py | 119 +++++++++--------- 1 file changed, 58 insertions(+), 61 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 24feb919881..d3faed36a0c 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -85,7 +85,7 @@ Note we could check using exact techniques that `2D = K`:: sage: Z = K - 2*D - sage: (Z.degree()==0, len(Z.basis_differential_space())==S.genus, len(Z.basis_function_space())==1) + sage: (Z.degree() == 0, len(Z.basis_differential_space()) == S.genus, len(Z.basis_function_space()) == 1) (True, True, True) We can also check this using our Abel-Jacobi functions:: @@ -325,10 +325,10 @@ def differential_basis_baker(f): sage: from sage.schemes.riemann_surfaces.riemann_surface import differential_basis_baker sage: R. = QQ[] - sage: f = x^3+y^3+x^5*y^5 + sage: f = x^3 + y^3 + x^5*y^5 sage: differential_basis_baker(f) [y^2, x*y, x*y^2, x^2, x^2*y, x^2*y^2, x^2*y^3, x^3*y^2, x^3*y^3] - sage: f = y^2-(x-3)^2*x + sage: f = y^2 - (x-3)^2*x sage: differential_basis_baker(f) is None True sage: differential_basis_baker(x^2+y^2-1) @@ -370,7 +370,7 @@ def differential_basis_baker(f): return None x, y = f.parent().gens() return [ - x ** (a[0] - 1) * y ** (a[1] - 1) + x**(a[0] - 1) * y**(a[1] - 1) for a in P.integral_points() if P.interior_contains(a) ] @@ -427,13 +427,17 @@ def reparameterize_differential_minpoly(minpoly, z0): EXAMPLES: - On the curve given by `w^2-z^3+1=0`, we have differential + On the curve given by `w^2 - z^3 + 1 = 0`, we have differential `\frac{dz}{2w} = \frac{dz}{2\sqrt{z^3-1}}` - with minimal polynomial `g^2(z^3-1)-1/4=0`. We can make the substitution - `\bar{z}=z^{-1}` to parameterise the differential about `z=\Infty` as - `\frac{-\bar{z}^{-2} d\bar{z}}{2\sqrt{\bar{z}^{-3}-1}} = \frac{-d\bar{z}}{2\sqrt{\bar{z}(1-\bar{z}^3)}}`. + with minimal polynomial `g^2(z^3-1) - 1/4=0`. We can make the substitution + `\bar{z}=z^{-1}` to parameterise the differential about `z=\infty` as + + .. MATH:: + + `\frac{-\bar{z}^{-2} d\bar{z}}{2\sqrt{\bar{z}^{-3}-1}} = \frac{-d\bar{z}}{2\sqrt{\bar{z}(1-\bar{z}^3)}}`. + Hence the transformed differential should have minimal polynomial - `\bar{g}^2\bar{z}(1-\bar{z}^3)-1/4=0`, and we can check this:: + `\bar{g}^2 \bar{z} (1 - \bar{z}^3) - 1/4 = 0`, and we can check this:: sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface, reparameterize_differential_minpoly sage: R. = QQ[] @@ -446,7 +450,7 @@ def reparameterize_differential_minpoly(minpoly, z0): We can further check that reparameterising about `0` is the identity operation:: - sage: reparameterize_differential_minpoly(minpoly, 0)(*minpoly.parent().gens())==minpoly + sage: reparameterize_differential_minpoly(minpoly, 0)(*minpoly.parent().gens()) == minpoly True .. NOTE:: @@ -466,7 +470,7 @@ def reparameterize_differential_minpoly(minpoly, z0): if Inf: F = F.fraction_field() - mt = F(minpoly(F.gen(0) ** (-1), -F.gen(0) ** (+2) * F.gen(1))) + mt = F(minpoly(F.gen(0)**(-1), -F.gen(0)**2 * F.gen(1))) mt.reduce() mt = mt.numerator() else: @@ -531,7 +535,7 @@ class RiemannSurface(object): sage: Qt. = QQ[] sage: K. = NumberField(t^2-t+3,embedding=CC(0.5+1.6*I)) sage: R. = K[] - sage: f = y^2+y-(x^3+(1-a)*x^2-(2+a)*x-2) + sage: f = y^2 + y - (x^3 + (1-a)*x^2 - (2+a)*x - 2) sage: S = RiemannSurface(f, prec=100, differentials=[1]) sage: A = S.endomorphism_basis() sage: len(A) @@ -562,7 +566,7 @@ class RiemannSurface(object): rigorous method, but for slower computations the rigorous method can be much faster:: - sage: f = z*w^3+z^3+w + sage: f = z*w^3 + z^3 + w sage: p = 53 sage: Sh = RiemannSurface(f, prec=p, integration_method='heuristic') sage: Sr = RiemannSurface(f, prec=p, integration_method='rigorous') @@ -585,21 +589,15 @@ class RiemannSurface(object): being significantly slower than the rigorous method. For a worse conditioned curve, this effect is more pronounced:: - sage: q = 1/10 - sage: f = y^2-(x^2-2*x+1+q^2)*(x^2+2*x+1+q^2) + sage: q = 1 / 10 + sage: f = y^2 - (x^2 - 2*x + 1 + q^2) * (x^2 + 2*x + 1 + q^2) sage: p = 500 sage: Sh = RiemannSurface(f, prec=p, integration_method='heuristic') sage: Sr = RiemannSurface(f, prec=p, integration_method='rigorous') sage: nodes.cache.clear() - sage: ct = time.time() sage: Rh = Sh.riemann_matrix() # long time (8 seconds) - sage: ct1 = time.time()-ct sage: nodes.cache.clear() - sage: ct = time.time() sage: Rr = Sr.riemann_matrix() # long time (1 seconds) - sage: ct2 = time.time()-ct - sage: ct2/ct1 # random - 0.19453288941244148 This disparity in timings can get increasingly worse, and testing has shown that even for random quadrics the heuristic method can be as bad as 30 times @@ -632,7 +630,7 @@ def __init__( prec=53, certification=True, differentials=None, - integration_method="rigorous", + integration_method="rigorous" ): r""" TESTS:: @@ -646,13 +644,13 @@ def __init__( self._prec = prec self._certification = certification if not (integration_method == "heuristic" or integration_method == "rigorous"): - raise ValueError("Invalid integration method") + raise ValueError("invalid integration method") self._integration_method = integration_method self._R = f.parent() if len(self._R.gens()) != 2: - raise ValueError("only bivariate polynomials supported.") + raise ValueError('only bivariate polynomials supported') if f.degree() <= 1: - raise ValueError("equation must be of degree at least 2.") + raise ValueError('equation must be of degree at least 2') z, w = self._R.gen(0), self._R.gen(1) self._CC = ComplexField(self._prec) self._RR = RealField(self._prec) @@ -981,7 +979,7 @@ def _compute_delta(self, z1, epsilon, wvalues=None): # compute M upperbounds = [ - sum(ak[k] * (abs(z1) + rho) ** k for k in range(ak.degree())) + sum(ak[k] * (abs(z1) + rho)**k for k in range(ak.degree())) for ak in self._aks ] upperbounds.reverse() @@ -1001,7 +999,7 @@ def _compute_delta(self, z1, epsilon, wvalues=None): return ( rho * ( - ((rho * Y - epsilon) ** 2 + 4 * epsilon * M).sqrt() + ((rho * Y - epsilon)**2 + 4 * epsilon * M).sqrt() - (rho * Y + epsilon) ) / (2 * M - 2 * rho * Y) @@ -1019,7 +1017,7 @@ def homotopy_continuation(self, edge): INPUT: - ``edge`` -- a tuple ``(z_start, z_end)`` indicating the straight line - over which to perform the homotopy continutation. + over which to perform the homotopy continutation OUTPUT: @@ -1418,7 +1416,7 @@ def edge_permutations(self) -> dict: """ D = {e: self._edge_permutation(e) for e in self.downstairs_edges()} for (a, b), p in list(D.items()): - D[(b, a)] = p ** (-1) + D[(b, a)] = p**(-1) return D @cached_method @@ -1909,7 +1907,7 @@ def cohomology_basis(self, option=1): # lowest degree generators are a basis of the relevant subspace. d = fnew.total_degree() J2 = k.ideal(J).intersection( - k.ideal([k.gen(0), k.gen(1), k.gen(2)]) ** (d - 3) + k.ideal([k.gen(0), k.gen(1), k.gen(2)])**(d - 3) ) generators = [dehom(c) for c in J2.gens() if c.degree() == d - 3] if len(generators) != self.genus: @@ -1928,13 +1926,12 @@ def _bounding_data(self, differentials, exact=False): INPUT: - - ``differentials`` -- list. A list of polynomials in ``self._R`` giving + - ``differentials`` -- list of polynomials in ``self._R`` giving the numerators of the differentials, as per the output of - :meth:`cohomology_basis`. + :meth:`cohomology_basis` - - ``exact`` -- logical (default: False). Whether to return the minimal - polynomials over the exact base ring, or whether to return them over - ``self._CC``. + - ``exact`` -- boolean (default: ``False``); whether to return the minimal + polynomials over the exact base ring, or over ``self._CC`` OUTPUT: @@ -1961,7 +1958,7 @@ def _bounding_data(self, differentials, exact=False): sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface sage: R. = QQ[] - sage: f = y^2-x^3+1 + sage: f = y^2 - x^3 + 1 sage: S = RiemannSurface(f) sage: differentials = S.cohomology_basis(); differentials [1] @@ -2155,7 +2152,7 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): alpha = self._RR(912 / 1000) # alpha set manually for scaling purposes. Basic benchmarking shows # that ~0.9 is a sensible value. - E_global = self._RR(2) ** (-self._prec + 3) + E_global = self._RR(2)**(-self._prec + 3) # Output will iteratively store the output of the integral. V = VectorSpace(self._CC, len(differentials)) @@ -2188,7 +2185,7 @@ def local_N(ct, rt): rho_z = rho_t * (z1 - z0).abs() delta_z = (alpha * rho_t + (1 - alpha) * rt) * (z1_minus_z0).abs() expr = ( - rho_t / rt + ((rho_t / rt) ** 2 - 1).sqrt() + rho_t / rt + ((rho_t / rt)**2 - 1).sqrt() ) # Note this is really exp(arcosh(rho_t/rt)) Ni = 3 cw = zwt(ct)[1] @@ -2203,7 +2200,7 @@ def local_N(ct, rt): m = [a(rho_z) / z_1 for a in ai_pos] l = len(m) M_tilde = 2 * max( - (m[i].abs()) ** (1 / self._RR(l - i)) for i in range(l) + (m[i].abs())**(1 / self._RR(l - i)) for i in range(l) ) cg = g(cz, cw) cdgdz = dgdz(cz, cg) @@ -2689,7 +2686,7 @@ def tangent_representation_algebraic(self, Rs, other=None, epscomp=None): True """ if not epscomp: - epscomp = 2 ** (-self._prec + 30) + epscomp = 2**(-self._prec + 30) QQalg = QQ.algebraic_closure() def polynomialize_element(alpha): @@ -2989,13 +2986,13 @@ def _integrate_differentials_iteratively( CCzg = PolynomialRing(self._CC, ["zbar", "gbar"]) mp_list = [CCzg(mp) for mp in mp_list] J = 1 / z_end - endscale = -(z_end ** (-2)) + endscale = -(z_end**(-2)) def initialise(z, i): DF = ComplexField(2 * self._prec) DFw = PolynomialRing(DF, "wbar") z = DF(z) - R = DF(z ** (-1)) + R = DF(z**(-1)) wR = DFw(self.f(R, DFw.gen(0))).roots(multiplicities=False)[w_start] newg = -(R**2) * self.cohomology_basis()[i](R, wR) / self._dfdw(R, wR) err = mp_list[i](z, newg).abs() @@ -3032,7 +3029,7 @@ def initialise(z, i): if prec is None: prec = self._prec # tau here is playing the role of the desired error. - tau = self._RR(2) ** (-prec + 3) + tau = self._RR(2)**(-prec + 3) one = self._RR(1) la = self._RR.pi() / 2 @@ -3056,7 +3053,7 @@ def initialise(z, i): d = mp.dict() mp = sum( [ - d[k] * CCzg.gen(0) ** k[0] * CCzg.gen(1) ** k[1] + d[k] * CCzg.gen(0)**k[0] * CCzg.gen(1)**k[1] for k in d.keys() if d[k].abs() > tau ] @@ -3065,13 +3062,13 @@ def initialise(z, i): a = QQ(max([(cst - iz) / ig for (iz, ig) in d.keys() if ig > 0])) sum_coeffs = sum( [ - d[k] * A.gen(0) ** k[1] + d[k] * A.gen(0)**k[1] for k in d.keys() if ((k[1] == 0 and k[0] == cst) or k[1] * a + k[0] - cst == 0) ] ) G = max([r.abs() for r in sum_coeffs.roots(multiplicities=False)]) - cutoffs.append(((a + 1) * tau / G) ** (1 / self._CC(a + 1)) / J.abs()) + cutoffs.append(((a + 1) * tau / G)**(1 / self._CC(a + 1)) / J.abs()) aes.append(a) cutoff_individually = bool( not all(ai <= 0 for ai in aes) and cutoff_individually @@ -3145,7 +3142,7 @@ def fv(hj, previous_estimate_and_validity): outg.append(newg) fj = V(outg) u1 = la * hj.cosh() - w = u1 / (2 * u2.cosh() ** 2) + w = u1 / (2 * u2.cosh()**2) return (fj, valid), w * fj f0, v0 = fv(h0, (self.genus * [0], self.genus * [False])) @@ -3184,7 +3181,7 @@ def fv(hj, previous_estimate): outg.append(newg) fj = V(outg) u1 = la * hj.cosh() - w = u1 / (2 * u2.cosh() ** 2) + w = u1 / (2 * u2.cosh()**2) return fj, w * fj u1, u2 = (la * h0.cosh(), la * h0.sinh()) @@ -3227,7 +3224,7 @@ def fv(hj, previous_estimate): D = min( one, max( - D1 ** (D1.log() / D2.log()), + D1**(D1.log() / D2.log()), D2**2, tau * D3_over_tau, D4, @@ -3359,7 +3356,7 @@ def _aj_based(self, P): # We choose the first vertex we want to go to. # If the closest vertex is closer than the nearest branch point, just take that vertex # otherwise we need something smarter. - delta = self._RR(2) ** (-self._prec + 1) + delta = self._RR(2)**(-self._prec + 1) if not ( (zP - self._vertices[V_index]).abs() < (zP - b).abs() or (zP - b).abs() <= delta @@ -3412,7 +3409,7 @@ def _aj_based(self, P): ] ts = [ ((c - zP) * (zV - zP).conjugate()).real() - / (zP - zV).norm() ** 2 + / (zP - zV).norm()**2 for c in fl ] ds = [ @@ -3425,7 +3422,7 @@ def _aj_based(self, P): zV = self._vertices[V_index] ts = [ ((c - zP) * (zV - zP).conjugate()).real() - / (zP - zV).norm() ** 2 + / (zP - zV).norm()**2 for c in fl ] ds = [ @@ -3623,7 +3620,7 @@ def reduce_over_period_lattice( if r is None: r = b // 4 S = 2**b - if H * S > 2 ** (self._prec - 4): + if H * S > 2**(self._prec - 4): raise ValueError("insufficient precision for b=%s" % b) def C2Z(v): @@ -3662,7 +3659,7 @@ def C2R(v): def curve(self): r""" - Return the curve from which this Riemann surface is obtained + Return the curve from which this Riemann surface is obtained. Riemann surfaces explicitly obtained from a curve return that same object. For others, the curve is constructed and cached, so that an identical curve is @@ -3691,7 +3688,7 @@ def places_at_branch_locus(self): Return a list of the of places above the branch locus. This must be done over the base ring, and so the places are given in terms of the factors of the discriminant. Currently, this method only works when - ``self._R.base_ring()==QQ`` as for other rings, the function field + ``self._R.base_ring() == QQ`` as for other rings, the function field for ``Curve(self.f)`` is not implemented. To go from these divisors to a divisor list, see :meth:`divisor_to_divisor_list`. @@ -3734,14 +3731,14 @@ def strong_approximation(self, divisor, S): As described in [Neu2018]_, apply the method of strong approximation to ``divisor`` with list of places to avoid ``S``. Currently, this method - only works when ``self._R.base_ring()==QQ`` as for other rings, the function + only works when ``self._R.base_ring() == QQ`` as for other rings, the function field for ``Curve(self.f)`` is not implemented. INPUT: - ``divisor`` -- an element of ``Curve(self.f).function_field().divisor_group()`` - - ``S`` -- list. A list of places to avoid. + - ``S`` -- list of places to avoid OUTPUT: @@ -3830,7 +3827,7 @@ def divisor_to_divisor_list(self, divisor, eps=None): - ``divisor`` -- an element of ``Curve(self.f).function_field().divisor_group()`` - ``eps`` -- real number (optional); tolerance used to determine whether a complex - number is close enough to a root of a polynomial. + number is close enough to a root of a polynomial OUTPUT: @@ -3856,7 +3853,7 @@ def divisor_to_divisor_list(self, divisor, eps=None): # If this error bound is too restrictive, this method might fail and # not return. One might want to change the way this error is handled. if not eps: - eps = self._RR(2) ** (-self._prec + 3) + eps = self._RR(2)**(-self._prec + 3) dl = [] PZ = PolynomialRing(self._R.base(), "z").fraction_field() @@ -3872,7 +3869,7 @@ def divisor_to_divisor_list(self, divisor, eps=None): g0 = self._R(gs[0]) gis = [ - sum([PZ(gi.list()[i]) * RF.gen() ** i for i in range(len(gi.list()))]) + sum([PZ(gi.list()[i]) * RF.gen()**i for i in range(len(gi.list()))]) for gi in gs[1:] ] @@ -3968,7 +3965,7 @@ def integer_matrix_relations(M1, M2, b=None, r=None): if r is None: r = b // 4 S = 2**b - if H * S > 2 ** (prec - 4): + if H * S > 2**(prec - 4): raise ValueError("insufficient precision for b=%s" % b) g1 = M1.ncols() g2 = M2.ncols() From a4768fac6e4cc4df9e1e1b303b4acf8f8490046d Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 8 Sep 2022 21:13:00 +0200 Subject: [PATCH 531/742] 34508: initial --- src/sage/features/join_feature.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/features/join_feature.py b/src/sage/features/join_feature.py index b29241eb462..d76f7b73072 100644 --- a/src/sage/features/join_feature.py +++ b/src/sage/features/join_feature.py @@ -9,6 +9,17 @@ class JoinFeature(Feature): r""" Join of several :class:`~sage.features.Feature` instances. + In the generic form this creates a new feature as the union of some given + features. Typically these are executables of a SPKG. For an example see + :class:`~sage.features.rubics.Rubics`. + + Furthermore, it can also be used to map a given feature to a more convenient + name to be used in `optional` tags of doctests. Thus you can equip features + such as :class:`~sage.features.PythonModule` features with a tag name that + differs from the systematic tag name. As an example for this use case see + :class:`~sage.features.meataxe.Meataxe`. See also the corresponding + discussion in :trac:`34282`. + EXAMPLES:: sage: from sage.features import Executable From da3d534332540f3b55cfd70729593b35629e3645 Mon Sep 17 00:00:00 2001 From: Yuan Zhou Date: Thu, 8 Sep 2022 19:01:38 -0400 Subject: [PATCH 532/742] assert isinstance(polymake_base_field, PolymakeElement) to muffle pyflakes and keep polymake tests --- src/sage/geometry/polyhedron/parent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 10b541bd4ad..ba1987b1fe2 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -174,9 +174,9 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * elif backend == 'polymake': base_field = base_ring.fraction_field() try: - from sage.interfaces.polymake import polymake + from sage.interfaces.polymake import polymake, PolymakeElement polymake_base_field = polymake(base_field) - assert polymake_base_field # to muffle pyflakes + assert isinstance(polymake_base_field, PolymakeElement) # to muffle pyflakes except TypeError: raise ValueError(f"the 'polymake' backend for polyhedron cannot be used with {base_field}") return Polyhedra_polymake(base_field, ambient_dim, backend) From e14dd1e88e8cbce5c18fe200ec94af61c17acedc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 8 Sep 2022 19:38:48 -0700 Subject: [PATCH 533/742] src/sage/categories: Update doctest output --- src/sage/categories/additive_magmas.py | 2 +- src/sage/categories/additive_semigroups.py | 2 +- src/sage/categories/monoids.py | 7 +++---- src/sage/categories/semigroups.py | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/additive_magmas.py b/src/sage/categories/additive_magmas.py index e81dcf9d4b9..cf2fdf242b9 100644 --- a/src/sage/categories/additive_magmas.py +++ b/src/sage/categories/additive_magmas.py @@ -519,7 +519,7 @@ def algebra_generators(self): An example of a commutative semigroup: the free commutative semigroup generated by ('a', 'b', 'c', 'd') sage: A = S.algebra(QQ) sage: A.algebra_generators() - Finite family {0: B[a], 1: B[b], 2: B[c], 3: B[d]} + Family (B[a], B[b], B[c], B[d]) .. TODO:: diff --git a/src/sage/categories/additive_semigroups.py b/src/sage/categories/additive_semigroups.py index fde92f27896..0527867154b 100644 --- a/src/sage/categories/additive_semigroups.py +++ b/src/sage/categories/additive_semigroups.py @@ -153,7 +153,7 @@ def algebra_generators(self): An example of a commutative semigroup: the free commutative semigroup generated by ('a', 'b', 'c', 'd') sage: A = S.algebra(QQ) sage: A.algebra_generators() - Finite family {0: B[a], 1: B[b], 2: B[c], 3: B[d]} + Family (B[a], B[b], B[c], B[d]) """ return self.basis().keys().additive_semigroup_generators().map(self.monomial) diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index b630ee04ee5..0950c5944d7 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -525,18 +525,17 @@ def algebra_generators(self): sage: Z12.semigroup_generators() Family (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) sage: Z12.algebra(QQ).algebra_generators() - Finite family {0: B[0], 1: B[1], 2: B[2], 3: B[3], 4: B[4], 5: B[5], - 6: B[6], 7: B[7], 8: B[8], 9: B[9], 10: B[10], 11: B[11]} + Family (B[0], B[1], B[2], B[3], B[4], B[5], B[6], B[7], B[8], B[9], B[10], B[11]) sage: GroupAlgebras(QQ).example(AlternatingGroup(10)).algebra_generators() - Finite family {0: (8,9,10), 1: (1,2,3,4,5,6,7,8,9)} + Family ((8,9,10), (1,2,3,4,5,6,7,8,9)) sage: A = DihedralGroup(3).algebra(QQ); A Algebra of Dihedral group of order 6 as a permutation group over Rational Field sage: A.algebra_generators() - Finite family {0: (1,2,3), 1: (1,3)} + Family ((1,2,3), (1,3)) """ monoid = self.basis().keys() try: diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index 007401e5474..d053b20e3c0 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -882,7 +882,7 @@ def algebra_generators(self): sage: M.semigroup_generators() Family ('a', 'b', 'c', 'd') sage: M.algebra(ZZ).algebra_generators() - Finite family {0: B['a'], 1: B['b'], 2: B['c'], 3: B['d']} + Family (B['a'], B['b'], B['c'], B['d']) """ return self.basis().keys().semigroup_generators().map(self.monomial) From 23d9d6c4ffd24f363a609c8fd6e3a3a61fe009fe Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 9 Sep 2022 07:59:12 +0200 Subject: [PATCH 534/742] 34508: typo --- src/sage/features/join_feature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/features/join_feature.py b/src/sage/features/join_feature.py index d76f7b73072..7eb77975b87 100644 --- a/src/sage/features/join_feature.py +++ b/src/sage/features/join_feature.py @@ -11,7 +11,7 @@ class JoinFeature(Feature): In the generic form this creates a new feature as the union of some given features. Typically these are executables of a SPKG. For an example see - :class:`~sage.features.rubics.Rubics`. + :class:`~sage.features.rubiks.Rubiks`. Furthermore, it can also be used to map a given feature to a more convenient name to be used in `optional` tags of doctests. Thus you can equip features From 0de1c13a55bc168b6c7a1fc0411a5f81b28dbf88 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 9 Sep 2022 08:14:07 +0200 Subject: [PATCH 535/742] add a warning and an example for the arithmetic product with a constant term --- src/sage/rings/lazy_series.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index b01a5f4cf6d..068e57a13f9 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4877,6 +4877,14 @@ def arithmetic_product(self, *args, check=True): http://mathoverflow.net/questions/138148/ for a discussion of this arithmetic product. + .. WARNING:: + + The operation `f \boxdot g` was originally defined only + for symmetric functions `f` and `g` without constant + term. We extend this definition using the convention + that the least common multiple of any integer with `0` is + `0`. + If `f` and `g` are two symmetric functions which are homogeneous of degrees `a` and `b`, respectively, then `f \boxdot g` is homogeneous of degree `ab`. @@ -4972,6 +4980,14 @@ def arithmetic_product(self, *args, check=True): sage: f.arithmetic_product(s[1]) - f O^7 + Check that the arithmetic product of symmetric functions with +constant a term works as advertised:: + + sage: p = SymmetricFunctions(QQ).p() + sage: L = LazySymmetricFunctions(p) + sage: L(5).arithmetic_product(3*p[2,1]) + 15*p[] + Check the arithmetic product of symmetric functions over a finite field works:: @@ -4979,7 +4995,6 @@ def arithmetic_product(self, *args, check=True): sage: L = LazySymmetricFunctions(s) sage: L(s([2])).arithmetic_product(s([1,1,1])) s[2, 2, 1, 1] + s[3, 1, 1, 1] + s[3, 2, 1] + s[3, 3] - """ if len(args) != self.parent()._arity: raise ValueError("arity must be equal to the number of arguments provided") From 8e5de35ee5f302a46f1af008d1e06f62bdf37f7b Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 9 Sep 2022 08:53:11 +0200 Subject: [PATCH 536/742] add missing whitespace in docstring --- src/sage/rings/lazy_series.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 068e57a13f9..5e2994d082b 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4981,7 +4981,7 @@ def arithmetic_product(self, *args, check=True): O^7 Check that the arithmetic product of symmetric functions with -constant a term works as advertised:: + constant a term works as advertised:: sage: p = SymmetricFunctions(QQ).p() sage: L = LazySymmetricFunctions(p) @@ -4995,6 +4995,7 @@ def arithmetic_product(self, *args, check=True): sage: L = LazySymmetricFunctions(s) sage: L(s([2])).arithmetic_product(s([1,1,1])) s[2, 2, 1, 1] + s[3, 1, 1, 1] + s[3, 2, 1] + s[3, 3] + """ if len(args) != self.parent()._arity: raise ValueError("arity must be equal to the number of arguments provided") From 805b8b7f7e3555259aab93cc0c7783abd4aa6fe7 Mon Sep 17 00:00:00 2001 From: Yuan Zhou Date: Fri, 9 Sep 2022 03:50:37 -0400 Subject: [PATCH 537/742] transform data to number field --- src/sage/geometry/polyhedron/backend_field.py | 40 +++++++++------- .../polyhedron/backend_number_field.py | 46 ++++++++++++++++--- 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_field.py b/src/sage/geometry/polyhedron/backend_field.py index 6b921d23a68..a965ed5d8ef 100644 --- a/src/sage/geometry/polyhedron/backend_field.py +++ b/src/sage/geometry/polyhedron/backend_field.py @@ -162,66 +162,74 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep): self._init_Hrepresentation(*Hrep) def _init_from_Vrepresentation(self, vertices, rays, lines, - minimize=True, verbose=False): + minimize=True, verbose=False, number_field=None): """ Construct polyhedron from V-representation data. INPUT: - ``vertices`` -- list of points. Each point can be specified - as any iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + as any iterable container of ``number_field`` elements. - ``rays`` -- list of rays. Each ray can be specified as any - iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + iterable container of ``number_field`` elements. - ``lines`` -- list of lines. Each line can be specified as - any iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + any iterable container of ``number_field`` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. + - ``number_field`` -- the number field of the generators' components. + Defualt is ``None``, in which case, it is set to + :meth:`~sage.geometry.polyhedron.base.base_ring`. + EXAMPLES:: sage: p = Polyhedron(ambient_dim=2, backend='field') sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field sage: Polyhedron_field._init_from_Vrepresentation(p, [(0,0)], [], []) """ + if number_field is None: + number_field = self.base_ring() from sage.geometry.polyhedron.double_description_inhomogeneous import Hrep2Vrep, Vrep2Hrep - H = Vrep2Hrep(self.base_ring(), self.ambient_dim(), vertices, rays, lines) - V = Hrep2Vrep(self.base_ring(), self.ambient_dim(), + H = Vrep2Hrep(number_field, self.ambient_dim(), vertices, rays, lines) + V = Hrep2Vrep(number_field, self.ambient_dim(), H.inequalities, H.equations) self._init_Vrepresentation_backend(V) self._init_Hrepresentation_backend(H) - def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): + def _init_from_Hrepresentation(self, ieqs, eqns, + minimize=True, verbose=False, number_field=None): """ Construct polyhedron from H-representation data. INPUT: - ``ieqs`` -- list of inequalities. Each line can be specified - as any iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + as any iterable container of ``number_field`` elements. - ``eqns`` -- list of equalities. Each line can be specified - as any iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + as any iterable container of ``number_field`` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. + - ``number_field`` -- the number field of the generators' components. + Defualt is ``None``, in which case, it is set to + :meth:`~sage.geometry.polyhedron.base.base_ring`. + TESTS:: sage: p = Polyhedron(ambient_dim=2, backend='field') sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field sage: Polyhedron_field._init_from_Hrepresentation(p, [(1, 2, 3)], []) """ + if number_field is None: + number_field = self.base_ring() from sage.geometry.polyhedron.double_description_inhomogeneous import Hrep2Vrep, Vrep2Hrep - V = Hrep2Vrep(self.base_ring(), self.ambient_dim(), ieqs, eqns) - H = Vrep2Hrep(self.base_ring(), self.ambient_dim(), + V = Hrep2Vrep(number_field, self.ambient_dim(), ieqs, eqns) + H = Vrep2Hrep(number_field, self.ambient_dim(), V.vertices, V.rays, V.lines) self._init_Vrepresentation_backend(V) self._init_Hrepresentation_backend(H) diff --git a/src/sage/geometry/polyhedron/backend_number_field.py b/src/sage/geometry/polyhedron/backend_number_field.py index 85a64764cc5..96262d84428 100644 --- a/src/sage/geometry/polyhedron/backend_number_field.py +++ b/src/sage/geometry/polyhedron/backend_number_field.py @@ -37,9 +37,23 @@ class Polyhedron_number_field(Polyhedron_field, Polyhedron_base_number_field): - ``Hrep`` -- a list ``[ieqs, eqns]`` or ``None``. - EXAMPLES: + EXAMPLES:: - TODO --- examples where input is in SR. Can copy from backend_normaliz. + sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], backend='number_field') # optional - sage.rings.number_field + sage: P # optional - sage.rings.number_field + A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices + sage: P.vertices() # optional - sage.rings.number_field + (A vertex at (1), A vertex at (sqrt(2))) + + sage: P = polytopes.icosahedron(exact=True, backend='number_field') # optional - sage.rings.number_field + sage: P # optional - sage.rings.number_field + A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 defined as the convex hull of 12 vertices + + sage: x = polygen(ZZ); P = Polyhedron(vertices=[[sqrt(2)], [AA.polynomial_root(x^3-2, RIF(0,3))]], backend='number_field') # optional - sage.rings.number_field + sage: P # optional - sage.rings.number_field + A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices + sage: P.vertices() # optional - sage.rings.number_field + (A vertex at (sqrt(2)), A vertex at (2^(1/3))) TESTS: @@ -95,10 +109,25 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, sage: p = Polyhedron(ambient_dim=2, backend='number_field') sage: from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field sage: Polyhedron_number_field._init_from_Vrepresentation(p, [(0,0)], [], []) + + TESTS: + + Check that the coordinates of a vertex get simplified in the Symbolic Ring:: + + sage: p = Polyhedron(ambient_dim=2, base_ring=SR, backend='number_field') + sage: from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field + sage: Polyhedron_number_field._init_from_Vrepresentation(p, [(0,1/2),(sqrt(2),0),(4,5/6)], [], []); p + A 2-dimensional polyhedron in (Symbolic Ring)^2 defined as the convex hull of 3 vertices + sage: p.vertices()[0][0] + 0 """ - # TODO: Transform data + (vertices, rays, lines), number_field \ + = self._compute_nmz_data_lists_and_field((vertices, rays, lines), + lambda *x: x, lambda *x: x) + self._number_field = number_field super()._init_from_Vrepresentation(vertices, rays, lines, - minimize=minimize, verbose=verbose) + minimize=minimize, verbose=verbose, + number_field=number_field) def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): """ @@ -123,5 +152,10 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): sage: from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field sage: Polyhedron_number_field._init_from_Hrepresentation(p, [(1, 2, 3)], []) """ - # TODO: Transform data - super()._init_from_Hrepresentation(ieqs, eqns, minimize=minimize, verbose=verbose) + (ieqs, eqns), number_field \ + = self._compute_nmz_data_lists_and_field((ieqs, eqns), + lambda *x: x, lambda *x: x) + self._number_field = number_field + super()._init_from_Hrepresentation(ieqs, eqns, + minimize=minimize, verbose=verbose, + number_field=number_field) From 63f6f3c74314a056e924dff1864d87ae2969d5e7 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Wed, 31 Aug 2022 18:42:56 +0800 Subject: [PATCH 538/742] compute CRT_list via tree --- src/sage/arith/misc.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index e57076646f4..ddc0e25fa3f 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -3229,6 +3229,9 @@ def CRT_list(v, moduli): ``moduli``, find a single element that reduces to each element of ``v`` modulo the corresponding moduli. + The result is computed using a binary tree. In typical cases, + this scales much better than folding the list from one side. + .. SEEALSO:: - :func:`crt` @@ -3298,13 +3301,13 @@ def CRT_list(v, moduli): return ZZ.zero() if len(v) == 1: return moduli[0].parent()(v[0]) - x = v[0] - m = moduli[0] from sage.arith.functions import lcm - for i in range(1, len(v)): - x = CRT(x, v[i], m, moduli[i]) - m = lcm(m, moduli[i]) - return x % m + while len(v) > 1: + for i in range(0, len(v)-1, 2): + v[i] = CRT(v[i], v[i+1], moduli[i], moduli[i+1]) + moduli[i] = lcm(moduli[i], moduli[i+1]) + v, moduli = v[::2], moduli[::2] + return v[0] % moduli[0] def CRT_basis(moduli): From c8dff33ab174483247969e59eec03ffb5de4b27c Mon Sep 17 00:00:00 2001 From: "Linden Disney-Hogg (Work)" Date: Fri, 9 Sep 2022 11:16:10 +0100 Subject: [PATCH 539/742] Fixed issue with failure to raise error. --- src/sage/schemes/riemann_surfaces/riemann_surface.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index d3faed36a0c..f85a7295dbc 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -3137,7 +3137,7 @@ def fv(hj, previous_estimate_and_validity): newg -= delta else: if raise_errors: - ConvergenceError("Newton iteration fails to converge") + raise ConvergenceError("Newton iteration fails to converge") else: outg.append(newg) fj = V(outg) @@ -3176,7 +3176,7 @@ def fv(hj, previous_estimate): newg -= delta else: if raise_errors: - ConvergenceError("Newton iteration fails to converge") + raise ConvergenceError("Newton iteration fails to converge") else: outg.append(newg) fj = V(outg) @@ -3245,7 +3245,7 @@ def fv(hj, previous_estimate): # we have one final error handle. Again, this will throw an error if # the raise_errors flag is true, but will just return the answer otherwise. if raise_errors: - ConvergenceError("Newton iteration fails to converge") + raise ConvergenceError("Newton iteration fails to converge") return (J * results[-1], endscale * fj) From 68d4fe24ea13e4e9226979086daa42c6fbaf2a7d Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 9 Sep 2022 22:23:07 +0900 Subject: [PATCH 540/742] Some edits --- src/sage/features/join_feature.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/features/join_feature.py b/src/sage/features/join_feature.py index 7eb77975b87..92e9851d635 100644 --- a/src/sage/features/join_feature.py +++ b/src/sage/features/join_feature.py @@ -9,16 +9,16 @@ class JoinFeature(Feature): r""" Join of several :class:`~sage.features.Feature` instances. - In the generic form this creates a new feature as the union of some given - features. Typically these are executables of a SPKG. For an example see + This creates a new feature as the union of the given features. Typically + these are executables of an SPKG. For an example, see :class:`~sage.features.rubiks.Rubiks`. - Furthermore, it can also be used to map a given feature to a more convenient - name to be used in `optional` tags of doctests. Thus you can equip features - such as :class:`~sage.features.PythonModule` features with a tag name that - differs from the systematic tag name. As an example for this use case see - :class:`~sage.features.meataxe.Meataxe`. See also the corresponding - discussion in :trac:`34282`. + Furthermore, this can be the union of a single feature. This is used to map + the given feature to a more convenient name to be used in ``optional`` tags + of doctests. Thus you can equip a feature such as a + :class:`~sage.features.PythonModule` with a tag name that differs from the + systematic tag name. As an example for this use case, see + :class:`~sage.features.meataxe.Meataxe`. EXAMPLES:: From 60b1d5451d50e45401a6d4668dc21a7e7f072c93 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 9 Sep 2022 07:43:23 -0700 Subject: [PATCH 541/742] TrivialFamily.map: Fix docstring, build tuple via list --- src/sage/sets/family.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/sets/family.py b/src/sage/sets/family.py index 2b4ed3cc7f9..10c59a02490 100644 --- a/src/sage/sets/family.py +++ b/src/sage/sets/family.py @@ -1382,8 +1382,8 @@ def __setstate__(self, state): def map(self, f, name=None): r""" - Returns the family `( f(\mathtt{self}[i]) )_{i \in I}`, where - `I` is the index set of self. + Return the family `( f(\mathtt{self}[i]) )_{i \in I}`, + where `I` is the index set of ``self``. The result is again a :class:`TrivialFamily`. @@ -1394,7 +1394,8 @@ def map(self, f, name=None): sage: g = f.map(lambda x: x + '1'); g Family ('a1', 'b1', 'd1') """ - return Family(tuple(f(x) for x in self._enumeration), name=name) + # tuple([... for ...]) is faster than tuple(... for ...) + return Family(tuple([f(x) for x in self._enumeration]), name=name) from sage.sets.non_negative_integers import NonNegativeIntegers From 7fc5a445834cfc67fa84185fc87338dbbdd8f73c Mon Sep 17 00:00:00 2001 From: David Roe Date: Fri, 9 Sep 2022 12:02:41 -0400 Subject: [PATCH 542/742] Undo Python's limit on string to int and int to string conversions --- src/sage/all.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/all.py b/src/sage/all.py index 584c0614181..5600674ddf4 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -285,6 +285,12 @@ def quit_sage(verbose=True): sage.misc.lazy_import.finish_startup() +### Python broke large ints; see trac #34506 + +if hasattr(sys, "set_int_max_str_digits"): + sys.set_int_max_str_digits(0) + + def sage_globals(): r""" Return the Sage namespace. From 20f06e6eb4bdd093fe952911bb568f7ebf9141f1 Mon Sep 17 00:00:00 2001 From: David Roe Date: Fri, 9 Sep 2022 12:37:38 -0400 Subject: [PATCH 543/742] Add test --- src/sage/all.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/all.py b/src/sage/all.py index 5600674ddf4..965230969f6 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -38,6 +38,10 @@ sage: interacts + +Check that :trac:`34506` is resolved:: + + sage: x = int('1'*4301) """ # **************************************************************************** # Copyright (C) 2005-2012 William Stein From e538c5dfac10a7855521c874cdcf46a96257d32a Mon Sep 17 00:00:00 2001 From: David Roe Date: Fri, 9 Sep 2022 12:39:06 -0400 Subject: [PATCH 544/742] Fix bug in decomposition_type --- src/sage/rings/number_field/number_field.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 78e0eb50e92..4ffa62f66cf 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -5998,12 +5998,21 @@ def decomposition_type(self, p): 2 sage: M.decomposition_type(Q1) [(2, 5, 1)] + + Check that :trac:`34514` is fixed:: + + sage: K. = NumberField(x^4 + 18*x^2 - 1) + sage: R. = K[] + sage: L. = K.extension(y^2 + 9*a^3 - 2*a^2 + 162*a - 38) + sage: [L.decomposition_type(i) for i in K.primes_above(3)] + [[(1, 1, 2)], [(1, 1, 2)], [(1, 2, 1)]] """ v0 = self.base_ring().valuation(p) e0 = v0.value_group().gen().denominator() - f0 = v0.residue_field().degree() + # Ideally we would compute f using the degree, but residue fields of relative extensions are currently implemented using polynomial quotient rings (this will hopefully be improved after #28485). + C0 = v0.residue_field().cardinality() valuations = v0.extensions(self) - ef = [(v.value_group().gen().denominator() // e0, v.residue_field().degree() // f0) for v in valuations] + ef = [(v.value_group().gen().denominator() // e0, v.residue_field().cardinality().exact_log(C0)) for v in valuations] return sorted([(e, f, g) for ((e, f), g) in Counter(ef).items()]) def gen(self, n=0): From ad74e4d3d3cd8e483e95a00ebb4fa120ec828008 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 9 Sep 2022 10:06:26 -0700 Subject: [PATCH 545/742] polyopes.generalized_polyhedron: Restructure doctests, add backend='number_field' tests --- src/sage/geometry/polyhedron/library.py | 120 +++++++++++++++--------- 1 file changed, 74 insertions(+), 46 deletions(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index b71e1e29d2b..880eb4ee008 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -2575,7 +2575,6 @@ def tri(m): return parent([verts, [], []], [ieqs, eqns], Vrep_minimal=True, Hrep_minimal=True, pref_rep="Hrep") - def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regular=False, backend=None): r""" Return the generalized permutahedron of type ``coxeter_type`` as the @@ -2638,38 +2637,19 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula A vertex at (1, 0), A vertex at (1, 1)) - Setting ``regular=True`` applies a linear transformation to get - isometric vertex figures and the result is inscribed. Even though there - are traces of small numbers, the internal computations are done using - an exact embedded NumberField:: + It works also with Coxeter types that lead to non-rational coordinates:: - sage: perm_a2_reg = polytopes.generalized_permutahedron(['A',2],regular=True) - sage: V = sorted(perm_a2_reg.vertices()); V # random - [A vertex at (-1, 0), - A vertex at (-1/2, -0.866025403784439?), - A vertex at (-1/2, 0.866025403784439?), - A vertex at (1/2, -0.866025403784439?), - A vertex at (1/2, 0.866025403784439?), - A vertex at (1.000000000000000?, 0.?e-18)] - sage: for v in V: - ....: for x in v: - ....: x.exactify() - sage: V - [A vertex at (-1, 0), - A vertex at (-1/2, -0.866025403784439?), - A vertex at (-1/2, 0.866025403784439?), - A vertex at (1/2, -0.866025403784439?), - A vertex at (1/2, 0.866025403784439?), - A vertex at (1, 0)] - sage: perm_a2_reg.is_inscribed() - True - sage: perm_a3_reg = polytopes.generalized_permutahedron(['A',3],regular=True) # long time - sage: perm_a3_reg.is_inscribed() # long time - True + sage: perm_b3 = polytopes.generalized_permutahedron(['B',3]); perm_b3 # long time # optional - sage.rings.number_field + A 3-dimensional polyhedron + in (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^3 + defined as the convex hull of 48 vertices - The same is possible with vertices in ``RDF``:: + Setting ``regular=True`` applies a linear transformation to get + isometric vertex figures and the result is inscribed. This cannot be done using + rational coordinates. We first do the computations using floating point + approximations (``RDF``):: - sage: perm_a2_inexact = polytopes.generalized_permutahedron(['A',2],exact=False) + sage: perm_a2_inexact = polytopes.generalized_permutahedron(['A',2], exact=False) sage: sorted(perm_a2_inexact.vertices()) [A vertex at (-1.0, -1.0), A vertex at (-1.0, 0.0), @@ -2678,7 +2658,7 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula A vertex at (1.0, 0.0), A vertex at (1.0, 1.0)] - sage: perm_a2_inexact_reg = polytopes.generalized_permutahedron(['A',2],exact=False,regular=True) + sage: perm_a2_inexact_reg = polytopes.generalized_permutahedron(['A',2], exact=False, regular=True) sage: sorted(perm_a2_inexact_reg.vertices()) [A vertex at (-1.0, 0.0), A vertex at (-0.5, -0.8660254038), @@ -2687,29 +2667,77 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula A vertex at (0.5, 0.8660254038), A vertex at (1.0, 0.0)] - It works also with types with non-rational coordinates:: + We can do the same computation using exact arithmetic with the field ``AA``:: + + sage: perm_a2_reg = polytopes.generalized_permutahedron(['A',2], regular=True) # optional - sage.rings.number_field + sage: V = sorted(perm_a2_reg.vertices()); V # random # optional - sage.rings.number_field + [A vertex at (-1, 0), + A vertex at (-1/2, -0.866025403784439?), + A vertex at (-1/2, 0.866025403784439?), + A vertex at (1/2, -0.866025403784439?), + A vertex at (1/2, 0.866025403784439?), + A vertex at (1.000000000000000?, 0.?e-18)] + + Even though the numbers look like floating point approximations, the computation is + actually exact. We can clean up the display a bit using ``exactify``:: - sage: perm_b3 = polytopes.generalized_permutahedron(['B',3]); perm_b3 # long time - A 3-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^3 defined as the convex hull of 48 vertices + sage: for v in V: # optional - sage.rings.number_field + ....: for x in v: + ....: x.exactify() + sage: V # optional - sage.rings.number_field + [A vertex at (-1, 0), + A vertex at (-1/2, -0.866025403784439?), + A vertex at (-1/2, 0.866025403784439?), + A vertex at (1/2, -0.866025403784439?), + A vertex at (1/2, 0.866025403784439?), + A vertex at (1, 0)] + sage: perm_a2_reg.is_inscribed() # optional - sage.rings.number_field + True + + Larger examples take longer:: - sage: perm_b3_reg = polytopes.generalized_permutahedron(['B',3],regular=True); perm_b3_reg # not tested - long time (12sec on 64 bits). + sage: perm_a3_reg = polytopes.generalized_permutahedron(['A',3], regular=True); perm_a3_reg # long time # optional - sage.rings.number_field + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices + sage: perm_a3_reg.is_inscribed() # long time # optional - sage.rings.number_field + True + sage: perm_b3_reg = polytopes.generalized_permutahedron(['B',3], regular=True); perm_b3_reg # not tested - long time (12sec on 64 bits). A 3-dimensional polyhedron in AA^3 defined as the convex hull of 48 vertices - It is faster with the backend ``'normaliz'``:: + It is faster with the backend ``'number_field'``, which internally uses an embedded + number field instead of doing the computations directly with the base ring (``AA``):: - sage: perm_b3_reg_norm = polytopes.generalized_permutahedron(['B',3],regular=True,backend='normaliz') # optional - pynormaliz - sage: perm_b3_reg_norm # optional - pynormaliz + sage: perm_a3_reg_nf = polytopes.generalized_permutahedron( # optional - sage.rings.number_field + ....: ['A',3], regular=True, backend='number_field'); perm_a3_reg_nf + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices + sage: perm_a3_reg_nf.is_inscribed() # optional - sage.rings.number_field + True + sage: perm_b3_reg_nf = polytopes.generalized_permutahedron( # long time # optional - sage.rings.number_field + ....: ['B',3], regular=True, backend='number_field'); perm_b3_reg_nf A 3-dimensional polyhedron in AA^3 defined as the convex hull of 48 vertices - The backend ``'normaliz'`` allows further faster computation in the - non-rational case:: + It is even faster with the backend ``'normaliz'``:: + + sage: perm_a3_reg_norm = polytopes.generalized_permutahedron( # optional - pynormaliz + ....: ['A',3], regular=True, backend='normaliz'); perm_a3_reg_norm + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices + sage: perm_a3_reg_norm.is_inscribed() # optional - pynormaliz + True + sage: perm_b3_reg_norm = polytopes.generalized_permutahedron( # optional - pynormaliz + ....: ['B',3], regular=True, backend='normaliz'); perm_b3_reg_norm + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 48 vertices - sage: perm_h3 = polytopes.generalized_permutahedron(['H',3],backend='normaliz') # optional - pynormaliz - sage: perm_h3 # optional - pynormaliz - A 3-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?)^3 defined as the convex hull of 120 vertices - sage: perm_f4 = polytopes.generalized_permutahedron(['F',4],backend='normaliz') # optional - pynormaliz, long time - sage: perm_f4 # optional - pynormaliz, long time - A 4-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^4 defined as the convex hull of 1152 vertices + The speedups from using backend ``'normaliz'`` allow us to go even further:: + + sage: perm_h3 = polytopes.generalized_permutahedron(['H',3], backend='normaliz') # optional - pynormaliz + sage: perm_h3 # optional - pynormaliz + A 3-dimensional polyhedron + in (Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?)^3 + defined as the convex hull of 120 vertices + sage: perm_f4 = polytopes.generalized_permutahedron(['F',4], backend='normaliz') # long time # optional - pynormaliz + sage: perm_f4 # long time # optional - pynormaliz + A 4-dimensional polyhedron + in (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^4 + defined as the convex hull of 1152 vertices .. SEEALSO:: From 8380bb1db74907a55b0c148415ab2321c6e0ee10 Mon Sep 17 00:00:00 2001 From: Yuan Zhou Date: Fri, 9 Sep 2022 17:28:39 -0400 Subject: [PATCH 546/742] rename _compute_nmz_data_lists_and_field to _compute_data_lists_and_internal_base_ring --- src/sage/geometry/polyhedron/backend_normaliz.py | 16 +++++++--------- .../geometry/polyhedron/backend_number_field.py | 4 ++-- .../geometry/polyhedron/base_number_field.py | 8 ++++---- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index f6b91eed988..40501156a13 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -527,9 +527,8 @@ def vert_ray_line_NF(vertices, rays, lines): lines = [] (nmz_vertices, nmz_rays, nmz_lines), normaliz_field \ - = self._compute_nmz_data_lists_and_field((vertices, rays, lines), - vert_ray_line_QQ, - vert_ray_line_NF) + = self._compute_data_lists_and_internal_base_ring( + (vertices, rays, lines), vert_ray_line_QQ, vert_ray_line_NF) if not nmz_vertices and not nmz_rays and not nmz_lines: # Special case to avoid: @@ -626,9 +625,8 @@ def nmz_ieqs_eqns_QQ(ieqs, eqns): eqns = [] (nmz_ieqs, nmz_eqns), normaliz_field \ - = self._compute_nmz_data_lists_and_field((ieqs, eqns), - nmz_ieqs_eqns_QQ, - nmz_ieqs_eqns_NF) + = self._compute_data_lists_and_internal_base_ring( + (ieqs, eqns), nmz_ieqs_eqns_QQ, nmz_ieqs_eqns_NF) if not nmz_ieqs: # If normaliz gets an empty list of inequalities, it adds # nonnegativities. So let's add a tautological inequality to work @@ -834,9 +832,9 @@ def rays_subspace_lattice_ieqs_NF(vertices, rays, lines, ieqs): return nmz_vertices + nmz_rays, nmz_lines, nmz_lattice, nmz_ieqs (nmz_extreme_rays, nmz_subspace, nmz_lattice, nmz_ieqs), normaliz_field \ - = self._compute_nmz_data_lists_and_field((vertices, rays, lines, ieqs), - rays_subspace_lattice_ieqs_QQ, - rays_subspace_lattice_ieqs_NF) + = self._compute_data_lists_and_internal_base_ring( + (vertices, rays, lines, ieqs), rays_subspace_lattice_ieqs_QQ, + rays_subspace_lattice_ieqs_NF) data = {"extreme_rays": nmz_extreme_rays, "maximal_subspace": nmz_subspace, diff --git a/src/sage/geometry/polyhedron/backend_number_field.py b/src/sage/geometry/polyhedron/backend_number_field.py index 96262d84428..4251de6f883 100644 --- a/src/sage/geometry/polyhedron/backend_number_field.py +++ b/src/sage/geometry/polyhedron/backend_number_field.py @@ -122,7 +122,7 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, 0 """ (vertices, rays, lines), number_field \ - = self._compute_nmz_data_lists_and_field((vertices, rays, lines), + = self._compute_data_lists_and_internal_base_ring((vertices, rays, lines), lambda *x: x, lambda *x: x) self._number_field = number_field super()._init_from_Vrepresentation(vertices, rays, lines, @@ -153,7 +153,7 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): sage: Polyhedron_number_field._init_from_Hrepresentation(p, [(1, 2, 3)], []) """ (ieqs, eqns), number_field \ - = self._compute_nmz_data_lists_and_field((ieqs, eqns), + = self._compute_data_lists_and_internal_base_ring((ieqs, eqns), lambda *x: x, lambda *x: x) self._number_field = number_field super()._init_from_Hrepresentation(ieqs, eqns, diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py index 5d8bf2e86c4..35c7e73a635 100644 --- a/src/sage/geometry/polyhedron/base_number_field.py +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -52,7 +52,7 @@ def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds class Polyhedron_base_number_field(Polyhedron_base): - def _compute_nmz_data_lists_and_field(self, data_lists, convert_QQ, convert_NF): + def _compute_data_lists_and_internal_base_ring(self, data_lists, convert_QQ, convert_NF): r""" Compute data lists in Normaliz format and the number field to use with Normaliz. @@ -65,13 +65,13 @@ def _compute_nmz_data_lists_and_field(self, data_lists, convert_QQ, convert_NF): ....: [ [ 1000*x for x in eq ] for eq in eqs] sage: def convert_NF(ieqs, eqs): # optional - pynormaliz ....: return ieqs, eqs - sage: p._compute_nmz_data_lists_and_field([[[1]], [[1/2]]], # optional - pynormaliz + sage: p_compute_data_lists_and_internal_base_ring([[[1]], [[1/2]]], # optional - pynormaliz ....: convert_QQ, convert_NF) (([[1000]], [[500]]), Rational Field) - sage: p._compute_nmz_data_lists_and_field([[[AA(1)]], [[1/2]]], # optional - pynormaliz + sage: p._compute_data_lists_and_internal_base_ring([[[AA(1)]], [[1/2]]], # optional - pynormaliz ....: convert_QQ, convert_NF) (([[1000]], [[500]]), Rational Field) - sage: p._compute_nmz_data_lists_and_field([[[AA(sqrt(2))]], [[1/2]]], # optional - pynormaliz # optional - sage.rings.number_field + sage: p._compute_data_lists_and_internal_base_ring([[[AA(sqrt(2))]], [[1/2]]], # optional - pynormaliz # optional - sage.rings.number_field ....: convert_QQ, convert_NF) ([[[a]], [[1/2]]], Number Field in a with defining polynomial y^2 - 2 with a = 1.414213562373095?) From 6b661a11365ed3febd9105c3a8f61beae1a87404 Mon Sep 17 00:00:00 2001 From: Yuan Zhou Date: Fri, 9 Sep 2022 17:43:15 -0400 Subject: [PATCH 547/742] rename number_field in the output of Polyhedron_base_number_field._compute_data_lists_and_internal_base_ring to internal_base_ring --- src/sage/geometry/polyhedron/backend_field.py | 38 ++++++++++--------- .../polyhedron/backend_number_field.py | 12 +++--- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_field.py b/src/sage/geometry/polyhedron/backend_field.py index a965ed5d8ef..2e82ecddb6f 100644 --- a/src/sage/geometry/polyhedron/backend_field.py +++ b/src/sage/geometry/polyhedron/backend_field.py @@ -162,25 +162,26 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep): self._init_Hrepresentation(*Hrep) def _init_from_Vrepresentation(self, vertices, rays, lines, - minimize=True, verbose=False, number_field=None): + minimize=True, verbose=False, + internal_base_ring=None): """ Construct polyhedron from V-representation data. INPUT: - ``vertices`` -- list of points. Each point can be specified - as any iterable container of ``number_field`` elements. + as any iterable container of ``internal_base_ring`` elements. - ``rays`` -- list of rays. Each ray can be specified as any - iterable container of ``number_field`` elements. + iterable container of ``internal_base_ring`` elements. - - ``lines`` -- list of lines. Each line can be specified as - any iterable container of ``number_field`` elements. + - ``lines`` -- list of lines. Each line can be specified asinternal_base_ring + any iterable container of ``internal_base_ring`` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. - - ``number_field`` -- the number field of the generators' components. + - ``internal_base_ring`` -- the base ring of the generators' components. Defualt is ``None``, in which case, it is set to :meth:`~sage.geometry.polyhedron.base.base_ring`. @@ -190,32 +191,33 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field sage: Polyhedron_field._init_from_Vrepresentation(p, [(0,0)], [], []) """ - if number_field is None: - number_field = self.base_ring() + if internal_base_ring is None: + internal_base_ring = self.base_ring() from sage.geometry.polyhedron.double_description_inhomogeneous import Hrep2Vrep, Vrep2Hrep - H = Vrep2Hrep(number_field, self.ambient_dim(), vertices, rays, lines) - V = Hrep2Vrep(number_field, self.ambient_dim(), + H = Vrep2Hrep(internal_base_ring, self.ambient_dim(), vertices, rays, lines) + V = Hrep2Vrep(internal_base_ring, self.ambient_dim(), H.inequalities, H.equations) self._init_Vrepresentation_backend(V) self._init_Hrepresentation_backend(H) def _init_from_Hrepresentation(self, ieqs, eqns, - minimize=True, verbose=False, number_field=None): + minimize=True, verbose=False, + internal_base_ring=None): """ Construct polyhedron from H-representation data. INPUT: - ``ieqs`` -- list of inequalities. Each line can be specified - as any iterable container of ``number_field`` elements. + as any iterable container of ``internal_base_ring`` elements. - ``eqns`` -- list of equalities. Each line can be specified - as any iterable container of ``number_field`` elements. + as any iterable container of ``internal_base_ring`` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. - - ``number_field`` -- the number field of the generators' components. + - ``internal_base_ring`` -- the base ring of the generators' components. Defualt is ``None``, in which case, it is set to :meth:`~sage.geometry.polyhedron.base.base_ring`. @@ -225,11 +227,11 @@ def _init_from_Hrepresentation(self, ieqs, eqns, sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field sage: Polyhedron_field._init_from_Hrepresentation(p, [(1, 2, 3)], []) """ - if number_field is None: - number_field = self.base_ring() + if internal_base_ring is None: + internal_base_ring = self.base_ring() from sage.geometry.polyhedron.double_description_inhomogeneous import Hrep2Vrep, Vrep2Hrep - V = Hrep2Vrep(number_field, self.ambient_dim(), ieqs, eqns) - H = Vrep2Hrep(number_field, self.ambient_dim(), + V = Hrep2Vrep(internal_base_ring, self.ambient_dim(), ieqs, eqns) + H = Vrep2Hrep(internal_base_ring, self.ambient_dim(), V.vertices, V.rays, V.lines) self._init_Vrepresentation_backend(V) self._init_Hrepresentation_backend(H) diff --git a/src/sage/geometry/polyhedron/backend_number_field.py b/src/sage/geometry/polyhedron/backend_number_field.py index 4251de6f883..1f3596ec035 100644 --- a/src/sage/geometry/polyhedron/backend_number_field.py +++ b/src/sage/geometry/polyhedron/backend_number_field.py @@ -121,13 +121,13 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, sage: p.vertices()[0][0] 0 """ - (vertices, rays, lines), number_field \ + (vertices, rays, lines), internal_base_ring \ = self._compute_data_lists_and_internal_base_ring((vertices, rays, lines), lambda *x: x, lambda *x: x) - self._number_field = number_field + self._internal_base_ring = internal_base_ring super()._init_from_Vrepresentation(vertices, rays, lines, minimize=minimize, verbose=verbose, - number_field=number_field) + internal_base_ring=internal_base_ring) def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): """ @@ -152,10 +152,10 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): sage: from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field sage: Polyhedron_number_field._init_from_Hrepresentation(p, [(1, 2, 3)], []) """ - (ieqs, eqns), number_field \ + (ieqs, eqns), internal_base_ring \ = self._compute_data_lists_and_internal_base_ring((ieqs, eqns), lambda *x: x, lambda *x: x) - self._number_field = number_field + self._internal_base_ring = internal_base_ring super()._init_from_Hrepresentation(ieqs, eqns, minimize=minimize, verbose=verbose, - number_field=number_field) + internal_base_ring=internal_base_ring) From 278f6a7e8cd0a54df9159d6dc73a112c533d8db2 Mon Sep 17 00:00:00 2001 From: Yuan Zhou Date: Fri, 9 Sep 2022 17:49:36 -0400 Subject: [PATCH 548/742] rename variables inside _compute_data_lists_and_internal_base_ring --- .../geometry/polyhedron/base_number_field.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py index 35c7e73a635..9c208da4acf 100644 --- a/src/sage/geometry/polyhedron/base_number_field.py +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -54,7 +54,7 @@ class Polyhedron_base_number_field(Polyhedron_base): def _compute_data_lists_and_internal_base_ring(self, data_lists, convert_QQ, convert_NF): r""" - Compute data lists in Normaliz format and the number field to use with Normaliz. + Compute data lists in Normaliz or ``number_field`` backend format and the internal base ring of the data. EXAMPLES:: @@ -97,22 +97,22 @@ def _compute_data_lists_and_internal_base_ring(self, data_lists, convert_QQ, con from sage.rings.real_double import RDF if self.base_ring() in (QQ, ZZ): - normaliz_field = QQ - nmz_data_lists = convert_QQ(*data_lists) + internal_base_ring = QQ + internal_data_lists = convert_QQ(*data_lists) else: # Allows to re-iterate if K is QQ below when data_lists contain # iterators: data_lists = [tuple(_) for _ in data_lists] - nmz_data_lists = convert_NF(*data_lists) + internal_data_lists = convert_NF(*data_lists) if self.base_ring() in NumberFields(): if not RDF.has_coerce_map_from(self.base_ring()): raise ValueError("invalid base ring: {} is a number field that is not real embedded".format(self.base_ring())) - normaliz_field = self.base_ring() + internal_base_ring = self.base_ring() else: - K, nmz_data_lists, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists(nmz_data_lists, embedded=True) - normaliz_field = K + K, internal_data_lists, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists(internal_data_lists, embedded=True) + internal_base_ring = K if K is QQ: # Compute it with Normaliz, not QNormaliz - nmz_data_lists = convert_QQ(*[ [ [ QQ(x) for x in v ] for v in l] + internal_data_lists = convert_QQ(*[ [ [ QQ(x) for x in v ] for v in l] for l in data_lists ]) - return nmz_data_lists, normaliz_field + return internal_data_lists, internal_base_ring From 1a9dd7052077e8afaf36cdd263d096e04c1a7b4e Mon Sep 17 00:00:00 2001 From: Yuan Zhou Date: Fri, 9 Sep 2022 18:01:00 -0400 Subject: [PATCH 549/742] rename normaliz_field to internal_base_ring --- .../geometry/polyhedron/backend_normaliz.py | 64 +++++++++---------- src/sage/geometry/polyhedron/base5.py | 2 +- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 40501156a13..073e2e41f1c 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -191,7 +191,7 @@ class Polyhedron_normaliz(Polyhedron_base_number_field): (A vertex at (2^(1/3)), A vertex at (sqrt(2))) """ - def __init__(self, parent, Vrep, Hrep, normaliz_cone=None, normaliz_data=None, normaliz_field=None, **kwds): + def __init__(self, parent, Vrep, Hrep, normaliz_cone=None, normaliz_data=None, internal_base_ring=None, **kwds): """ Initializes the polyhedron. @@ -213,15 +213,15 @@ def __init__(self, parent, Vrep, Hrep, normaliz_cone=None, normaliz_data=None, n if Hrep is not None or Vrep is not None or normaliz_data is not None: raise ValueError("only one of Vrep, Hrep, normaliz_cone, or normaliz_data can be different from None") Element.__init__(self, parent=parent) - self._init_from_normaliz_cone(normaliz_cone, normaliz_field) + self._init_from_normaliz_cone(normaliz_cone, internal_base_ring) elif normaliz_data: if Hrep is not None or Vrep is not None: raise ValueError("only one of Vrep, Hrep, normaliz_cone, or normaliz_data can be different from None") Element.__init__(self, parent=parent) - self._init_from_normaliz_data(normaliz_data, normaliz_field) + self._init_from_normaliz_data(normaliz_data, internal_base_ring) else: - if normaliz_field: - raise ValueError("if Vrep or Hrep are given, cannot provide normaliz_field") + if internal_base_ring: + raise ValueError("if Vrep or Hrep are given, cannot provide internal_base_ring") Polyhedron_base_number_field.__init__(self, parent, Vrep, Hrep, **kwds) def _nmz_result(self, normaliz_cone, property): @@ -260,13 +260,13 @@ def rational_handler(list): def nfelem_handler(coords): # coords might be too short which is not accepted by Sage number field - v = list(coords) + [0] * (self._normaliz_field.degree() - len(coords)) - return self._normaliz_field(v) + v = list(coords) + [0] * (self._internal_base_ring.degree() - len(coords)) + return self._internal_base_ring(v) return NmzResult(normaliz_cone, property, RationalHandler=rational_handler, NumberfieldElementHandler=nfelem_handler) - def _init_from_normaliz_cone(self, normaliz_cone, normaliz_field): + def _init_from_normaliz_cone(self, normaliz_cone, internal_base_ring): """ Construct polyhedron from a PyNormaliz wrapper of a normaliz cone. @@ -276,9 +276,9 @@ def _init_from_normaliz_cone(self, normaliz_cone, normaliz_field): sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz # optional - pynormaliz sage: Polyhedron_normaliz._init_from_Hrepresentation(p, [], []) # indirect doctest # optional - pynormaliz """ - if normaliz_field is None: - normaliz_field = QQ - self._normaliz_field = normaliz_field + if internal_base_ring is None: + internal_base_ring = QQ + self._internal_base_ring = internal_base_ring if normaliz_cone and self._nmz_result(normaliz_cone, "AffineDim") < 0: # Empty polyhedron. Special case because Normaliz defines the @@ -339,7 +339,7 @@ def _QQ_pair(x): # number field return [ _QQ_pair(c) for c in x.list() ] - def _init_from_normaliz_data(self, data, normaliz_field=None, verbose=False): + def _init_from_normaliz_data(self, data, internal_base_ring=None, verbose=False): """ Construct polyhedron from normaliz ``data`` (a dictionary). @@ -360,15 +360,15 @@ def _init_from_normaliz_data(self, data, normaliz_field=None, verbose=False): sage: from sage.geometry.polyhedron.parent import Polyhedra_normaliz # optional - pynormaliz sage: parent = Polyhedra_normaliz(AA, 2, 'normaliz') # optional - pynormaliz # optional - sage.rings.number_field sage: Polyhedron_normaliz(parent, None, None, normaliz_data=data, # indirect doctest, optional - pynormaliz # optional - sage.rings.number_field - ....: normaliz_field=QuadraticField(2)) + ....: internal_base_ring=QuadraticField(2)) A 2-dimensional polyhedron in AA^2 defined as the convex hull of 1 vertex and 2 rays sage: _.inequalities_list() # optional - pynormaliz # optional - sage.rings.number_field [[0, -1/2, 1], [0, 2, -1]] """ - if normaliz_field is None: - normaliz_field = QQ + if internal_base_ring is None: + internal_base_ring = QQ cone = self._cone_from_normaliz_data(data, verbose) - self._init_from_normaliz_cone(cone, normaliz_field) + self._init_from_normaliz_cone(cone, internal_base_ring) def _cone_from_normaliz_data(self, data, verbose=False): """ @@ -526,7 +526,7 @@ def vert_ray_line_NF(vertices, rays, lines): if lines is None: lines = [] - (nmz_vertices, nmz_rays, nmz_lines), normaliz_field \ + (nmz_vertices, nmz_rays, nmz_lines), internal_base_ring \ = self._compute_data_lists_and_internal_base_ring( (vertices, rays, lines), vert_ray_line_QQ, vert_ray_line_NF) @@ -539,10 +539,10 @@ def vert_ray_line_NF(vertices, rays, lines): data = {"vertices": nmz_vertices, "cone": nmz_rays, "subspace": nmz_lines} - number_field_data = self._number_field_triple(normaliz_field) + number_field_data = self._number_field_triple(internal_base_ring) if number_field_data: data["number_field"] = number_field_data - self._init_from_normaliz_data(data, normaliz_field=normaliz_field, verbose=verbose) + self._init_from_normaliz_data(data, internal_base_ring=internal_base_ring, verbose=verbose) def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): r""" @@ -624,7 +624,7 @@ def nmz_ieqs_eqns_QQ(ieqs, eqns): if eqns is None: eqns = [] - (nmz_ieqs, nmz_eqns), normaliz_field \ + (nmz_ieqs, nmz_eqns), internal_base_ring \ = self._compute_data_lists_and_internal_base_ring( (ieqs, eqns), nmz_ieqs_eqns_QQ, nmz_ieqs_eqns_NF) if not nmz_ieqs: @@ -634,10 +634,10 @@ def nmz_ieqs_eqns_QQ(ieqs, eqns): nmz_ieqs.append([0] * self.ambient_dim() + [0]) data = {"inhom_equations": nmz_eqns, "inhom_inequalities": nmz_ieqs} - number_field_data = self._number_field_triple(normaliz_field) + number_field_data = self._number_field_triple(internal_base_ring) if number_field_data: data["number_field"] = number_field_data - self._init_from_normaliz_data(data, normaliz_field=normaliz_field, verbose=verbose) + self._init_from_normaliz_data(data, internal_base_ring=internal_base_ring, verbose=verbose) def _cone_from_Vrepresentation_and_Hrepresentation(self, vertices, rays, lines, ieqs, eqns=None, verbose=False, homogeneous=False): r""" @@ -831,7 +831,7 @@ def rays_subspace_lattice_ieqs_NF(vertices, rays, lines, ieqs): return nmz_vertices + nmz_rays, nmz_lines, nmz_lattice, nmz_ieqs - (nmz_extreme_rays, nmz_subspace, nmz_lattice, nmz_ieqs), normaliz_field \ + (nmz_extreme_rays, nmz_subspace, nmz_lattice, nmz_ieqs), internal_base_ring \ = self._compute_data_lists_and_internal_base_ring( (vertices, rays, lines, ieqs), rays_subspace_lattice_ieqs_QQ, rays_subspace_lattice_ieqs_NF) @@ -845,7 +845,7 @@ def rays_subspace_lattice_ieqs_NF(vertices, rays, lines, ieqs): if not homogeneous: data["dehomogenization"] = [[0] * (ambient_dim - 1) + [1]] - number_field_data = self._number_field_triple(normaliz_field) + number_field_data = self._number_field_triple(internal_base_ring) if number_field_data: data["number_field"] = number_field_data return self._cone_from_normaliz_data(data, verbose=verbose) @@ -973,7 +973,7 @@ def _init_empty_polyhedron(self): self._normaliz_cone = None @classmethod - def _from_normaliz_cone(cls, parent, normaliz_cone, normaliz_field=None): + def _from_normaliz_cone(cls, parent, normaliz_cone, internal_base_ring=None): r""" Initializes a polyhedron from a PyNormaliz wrapper of a normaliz cone. @@ -983,12 +983,12 @@ def _from_normaliz_cone(cls, parent, normaliz_cone, normaliz_field=None): ....: backend='normaliz') sage: PI = P.integral_hull() # indirect doctest; optional - pynormaliz """ - return cls(parent, None, None, normaliz_cone=normaliz_cone, normaliz_field=normaliz_field) + return cls(parent, None, None, normaliz_cone=normaliz_cone, internal_base_ring=internal_base_ring) @staticmethod - def _number_field_triple(normaliz_field): + def _number_field_triple(internal_base_ring): r""" - Construct the PyNormaliz triple that describes the number field ``normaliz_field``. + Construct the PyNormaliz triple that describes ``internal_base_ring``. TESTS:: @@ -998,7 +998,7 @@ def _number_field_triple(normaliz_field): sage: Pn._number_field_triple(QuadraticField(5)) # optional - sage.rings.number_field ['a^2 - 5', 'a', '[2.236067977499789 +/- 8.06e-16]'] """ - R = normaliz_field + R = internal_base_ring if R is QQ: return None from sage.rings.real_arb import RealBallField @@ -1179,7 +1179,7 @@ def __getstate__(self): A vertex at (0, 0, 1, 0), A vertex at (0, 1, 0, 0), A vertex at (1, 0, 0, 0)), - '_normaliz_field': Rational Field, + '_internal_base_ring': Rational Field, '_pickle_equations': [(-1, 1, 1, 1, 1)], '_pickle_inequalities': [(0, 0, 0, 0, 1), (0, 0, 0, 1, 0), @@ -1246,7 +1246,7 @@ def __setstate__(self, state): sage: P = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field sage: P1 = loads(dumps(P)) # optional - pynormaliz # optional - sage.rings.number_field - sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone, normaliz_field=P1._normaliz_field) # optional - pynormaliz # optional - sage.rings.number_field + sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone, internal_base_ring=P1._internal_base_ring) # optional - pynormaliz # optional - sage.rings.number_field sage: P == P2 # optional - pynormaliz # optional - sage.rings.number_field True @@ -1453,7 +1453,7 @@ def _volume_normaliz(self, measure='euclidean'): if measure == 'euclidean': return self._nmz_result(cone, 'EuclideanVolume') elif measure == 'induced_lattice': - if self._normaliz_field in (ZZ, QQ): + if self._internal_base_ring in (ZZ, QQ): return self._nmz_result(cone, 'Volume') else: return self._nmz_result(cone, 'RenfVolume') diff --git a/src/sage/geometry/polyhedron/base5.py b/src/sage/geometry/polyhedron/base5.py index f16bce682b9..7a77f9685a3 100644 --- a/src/sage/geometry/polyhedron/base5.py +++ b/src/sage/geometry/polyhedron/base5.py @@ -2440,7 +2440,7 @@ def _test_lawrence(self, tester=None, **options): if self.backend() == 'normaliz' and not self.base_ring() in (ZZ, QQ): # Speeds up the doctest for significantly. - self = self.change_ring(self._normaliz_field) + self = self.change_ring(self._internal_base_ring) if not self.is_compact(): with tester.assertRaises(NotImplementedError): From 60516e7807900e9e620375aacdf46619036dad01 Mon Sep 17 00:00:00 2001 From: Yuan Zhou Date: Fri, 9 Sep 2022 18:22:30 -0400 Subject: [PATCH 550/742] fix a typo --- src/sage/geometry/polyhedron/base_number_field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py index 9c208da4acf..08040db3794 100644 --- a/src/sage/geometry/polyhedron/base_number_field.py +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -65,7 +65,7 @@ def _compute_data_lists_and_internal_base_ring(self, data_lists, convert_QQ, con ....: [ [ 1000*x for x in eq ] for eq in eqs] sage: def convert_NF(ieqs, eqs): # optional - pynormaliz ....: return ieqs, eqs - sage: p_compute_data_lists_and_internal_base_ring([[[1]], [[1/2]]], # optional - pynormaliz + sage: p._compute_data_lists_and_internal_base_ring([[[1]], [[1/2]]], # optional - pynormaliz ....: convert_QQ, convert_NF) (([[1000]], [[500]]), Rational Field) sage: p._compute_data_lists_and_internal_base_ring([[[AA(1)]], [[1/2]]], # optional - pynormaliz From 3eb2cc30285b367a770b14c6e2664c2826a90e33 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 9 Sep 2022 16:47:52 -0700 Subject: [PATCH 551/742] src/sage/geometry/polyhedron: Fix typos, reformat doctests --- src/sage/geometry/polyhedron/backend_field.py | 4 +-- .../polyhedron/backend_number_field.py | 29 +++++++++++-------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_field.py b/src/sage/geometry/polyhedron/backend_field.py index 2e82ecddb6f..93c46c66309 100644 --- a/src/sage/geometry/polyhedron/backend_field.py +++ b/src/sage/geometry/polyhedron/backend_field.py @@ -182,7 +182,7 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, verbose output for debugging purposes. - ``internal_base_ring`` -- the base ring of the generators' components. - Defualt is ``None``, in which case, it is set to + Default is ``None``, in which case, it is set to :meth:`~sage.geometry.polyhedron.base.base_ring`. EXAMPLES:: @@ -218,7 +218,7 @@ def _init_from_Hrepresentation(self, ieqs, eqns, verbose output for debugging purposes. - ``internal_base_ring`` -- the base ring of the generators' components. - Defualt is ``None``, in which case, it is set to + Default is ``None``, in which case, it is set to :meth:`~sage.geometry.polyhedron.base.base_ring`. TESTS:: diff --git a/src/sage/geometry/polyhedron/backend_number_field.py b/src/sage/geometry/polyhedron/backend_number_field.py index 1f3596ec035..9e87988b9ca 100644 --- a/src/sage/geometry/polyhedron/backend_number_field.py +++ b/src/sage/geometry/polyhedron/backend_number_field.py @@ -41,24 +41,31 @@ class Polyhedron_number_field(Polyhedron_field, Polyhedron_base_number_field): sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], backend='number_field') # optional - sage.rings.number_field sage: P # optional - sage.rings.number_field - A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices + A 1-dimensional polyhedron + in (Symbolic Ring)^1 defined as the convex hull of 2 vertices sage: P.vertices() # optional - sage.rings.number_field (A vertex at (1), A vertex at (sqrt(2))) sage: P = polytopes.icosahedron(exact=True, backend='number_field') # optional - sage.rings.number_field sage: P # optional - sage.rings.number_field - A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 defined as the convex hull of 12 vertices - - sage: x = polygen(ZZ); P = Polyhedron(vertices=[[sqrt(2)], [AA.polynomial_root(x^3-2, RIF(0,3))]], backend='number_field') # optional - sage.rings.number_field + A 3-dimensional polyhedron + in (Number Field in sqrt5 with defining polynomial x^2 - 5 + with sqrt5 = 2.236067977499790?)^3 + defined as the convex hull of 12 vertices + + sage: x = polygen(ZZ); P = Polyhedron( # optional - sage.rings.number_field + ....: vertices=[[sqrt(2)], [AA.polynomial_root(x^3-2, RIF(0,3))]], + ....: backend='number_field') sage: P # optional - sage.rings.number_field - A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices + A 1-dimensional polyhedron + in (Symbolic Ring)^1 defined as the convex hull of 2 vertices sage: P.vertices() # optional - sage.rings.number_field (A vertex at (sqrt(2)), A vertex at (2^(1/3))) - TESTS: - Tests from backend_field -- here the data are already either in a number field or in AA. + Tests from :class:`~sage.geometry.polyhedron.backend_field.Polyhedron_field` -- + here the data are already either in a number field or in ``AA``. sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # optional - sage.rings.number_field ....: rays=[(1,1)], lines=[], backend='number_field', base_ring=AA) @@ -68,15 +75,13 @@ class Polyhedron_number_field(Polyhedron_field, Polyhedron_base_number_field): sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)], backend='number_field') # optional - sage.rings.number_field sage: TestSuite(p).run() # optional - sage.rings.number_field - Check that :trac:`19013` is fixed:: - sage: K. = NumberField(x^2-x-1, embedding=1.618) # optional - sage.rings.number_field sage: P1 = Polyhedron([[0,1], [1,1], [1,-phi+1]], backend='number_field') # optional - sage.rings.number_field sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]], backend='number_field') # optional - sage.rings.number_field sage: P1.intersection(P2) # optional - sage.rings.number_field - The empty polyhedron in (Number Field in phi with defining polynomial x^2 - x - 1 with phi = 1.618033988749895?)^2 - - Check that :trac:`28654` is fixed:: + The empty polyhedron + in (Number Field in phi with defining polynomial x^2 - x - 1 + with phi = 1.618033988749895?)^2 sage: Polyhedron(lines=[[1]], backend='number_field') A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex and 1 line From bc7aba3fcd50991bbd271b0297645b5bc534a512 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 9 Sep 2022 16:52:28 -0700 Subject: [PATCH 552/742] src/doc/en/reference/discrete_geometry/index.rst: Add backend_number_field --- src/doc/en/reference/discrete_geometry/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/en/reference/discrete_geometry/index.rst b/src/doc/en/reference/discrete_geometry/index.rst index 0289ea570d9..e9e9255877e 100644 --- a/src/doc/en/reference/discrete_geometry/index.rst +++ b/src/doc/en/reference/discrete_geometry/index.rst @@ -112,6 +112,7 @@ Backends for Polyhedra sage/geometry/polyhedron/backend_cdd sage/geometry/polyhedron/backend_cdd_rdf sage/geometry/polyhedron/backend_field + sage/geometry/polyhedron/backend_number_field sage/geometry/polyhedron/backend_normaliz sage/geometry/polyhedron/backend_polymake sage/geometry/polyhedron/backend_ppl From c729884f9c1c4b6921fa2b6f0d6da92256f6811d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 9 Sep 2022 17:11:58 -0700 Subject: [PATCH 553/742] src/sage/geometry/polyhedron/backend_number_field.py: Fix doc markup --- src/sage/geometry/polyhedron/backend_number_field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/backend_number_field.py b/src/sage/geometry/polyhedron/backend_number_field.py index 9e87988b9ca..437550de3aa 100644 --- a/src/sage/geometry/polyhedron/backend_number_field.py +++ b/src/sage/geometry/polyhedron/backend_number_field.py @@ -65,7 +65,7 @@ class Polyhedron_number_field(Polyhedron_field, Polyhedron_base_number_field): TESTS: Tests from :class:`~sage.geometry.polyhedron.backend_field.Polyhedron_field` -- - here the data are already either in a number field or in ``AA``. + here the data are already either in a number field or in ``AA``:: sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # optional - sage.rings.number_field ....: rays=[(1,1)], lines=[], backend='number_field', base_ring=AA) From 35b8b6ec6dcbd3dcf25e54937aec668322e5ad1c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 15:33:02 -0700 Subject: [PATCH 554/742] ModulesWithBasis.ElementMethod.support: Return a SupportView --- src/sage/categories/modules_with_basis.py | 8 ++--- src/sage/structure/support_view.py | 44 +++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 src/sage/structure/support_view.py diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 22f5a6d8f07..0664ae33b7d 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1534,7 +1534,7 @@ def length(self): def support(self): """ - Return a list of the objects indexing the basis of + Return an iterable of the objects indexing the basis of ``self.parent()`` whose corresponding coefficients of ``self`` are non-zero. @@ -1555,9 +1555,9 @@ def support(self): sage: sorted(z.support()) [[1], [1, 1, 1], [2, 1], [4]] """ - zero = self.parent().base_ring().zero() - return [key for key, coeff in self.monomial_coefficients(copy=False).items() - if coeff != zero] + from sage.structure.support_view import SupportView + mc = self.monomial_coefficients(copy=False) + return SupportView(mc) def monomials(self): """ diff --git a/src/sage/structure/support_view.py b/src/sage/structure/support_view.py new file mode 100644 index 00000000000..13631e3d89e --- /dev/null +++ b/src/sage/structure/support_view.py @@ -0,0 +1,44 @@ +r""" +Iterable of the keys of a Mapping associated with nonzero values +""" + +from collections.abc import MappingView, Sequence, Set + + +class SupportView(MappingView, Sequence, Set): + + def __init__(self, mapping, *, zero=None): + self._mapping = mapping + self._zero = zero + + def __len__(self): + length = 0 + for key in self: + length += 1 + return length + + def __getitem__(self, index): + for i, key in enumerate(self): + if i == index: + return key + raise IndexError + + def __iter__(self): + zero = self._zero + if zero is None: + for key, value in self._mapping.items(): + if value: + yield key + else: + for key, value in self._mapping.items(): + if value != zero: + yield key + + def __contains__(self, key): + try: + value = self._mapping[key] + except KeyError: + return False + if zero is None: + return bool(value) + return value != zero From 8ae8f09538745e3388340d9307e2b661eae0148a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 15:34:08 -0700 Subject: [PATCH 555/742] src/sage/combinat/crystals, src/sage/categories/*crystals*: Use collections.abc for isinstance --- src/sage/categories/crystals.py | 15 ++++++++------- src/sage/combinat/crystals/subcrystal.py | 4 +++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index ec7a5865398..1cfbf9175ab 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -19,6 +19,7 @@ # https://www.gnu.org/licenses/ #***************************************************************************** +import collections.abc from sage.misc.cachefunc import cached_method from sage.misc.abstract_method import abstract_method @@ -779,10 +780,10 @@ def crystal_morphism(self, on_gens, codomain=None, if codomain is None: if hasattr(on_gens, 'codomain'): codomain = on_gens.codomain() - elif isinstance(on_gens, (list, tuple)): + elif isinstance(on_gens, collections.abc.Sequence): if on_gens: codomain = on_gens[0].parent() - elif isinstance(on_gens, dict): + elif isinstance(on_gens, collections.abc.Mapping): if on_gens: codomain = next(iter(on_gens.values())).parent() else: @@ -1845,7 +1846,7 @@ def __init__(self, parent, cartan_type=None, scaling_factors = {i: 1 for i in index_set} if virtualization is None: virtualization = {i: (i,) for i in index_set} - elif not isinstance(virtualization, dict): + elif not isinstance(virtualization, collections.abc.Mapping): try: virtualization = dict(virtualization) except (TypeError, ValueError): @@ -2057,16 +2058,16 @@ def __init__(self, parent, on_gens, cartan_type=None, virtualization, scaling_factors) if gens is None: - if isinstance(on_gens, dict): + if isinstance(on_gens, collections.abc.Mapping): gens = on_gens.keys() else: gens = parent.domain().module_generators self._gens = tuple(gens) # Make sure on_gens is a function - if isinstance(on_gens, dict): + if isinstance(on_gens, collections.abc.Mapping): f = lambda x: on_gens[x] - elif isinstance(on_gens, (list, tuple)): + elif isinstance(on_gens, collections.abc.Sequence): if len(self._gens) != len(on_gens): raise ValueError("invalid generator images") d = {x: y for x, y in zip(self._gens, on_gens)} @@ -2579,7 +2580,7 @@ def __call__(self, on_gens, cartan_type=None, index_set=None, generators=None, if automorphism is not None: if virtualization is not None: raise ValueError("the automorphism and virtualization cannot both be specified") - if not isinstance(automorphism, dict): + if not isinstance(automorphism, collections.abc.Mapping): try: automorphism = dict(automorphism) virtualization = {i: (automorphism[i],) for i in automorphism} diff --git a/src/sage/combinat/crystals/subcrystal.py b/src/sage/combinat/crystals/subcrystal.py index 9881a021e27..c62815af4be 100644 --- a/src/sage/combinat/crystals/subcrystal.py +++ b/src/sage/combinat/crystals/subcrystal.py @@ -23,6 +23,8 @@ # http://www.gnu.org/licenses/ #**************************************************************************** +import collections.abc + from sage.misc.lazy_attribute import lazy_attribute from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent @@ -126,7 +128,7 @@ def __classcall_private__(cls, ambient, contained=None, generators=None, sage: S1 is S2 True """ - if isinstance(contained, (list, tuple, set, frozenset)): + if isinstance(contained, (collections.abc.Sequence, collections.abc.Set)): contained = frozenset(contained) #elif contained in Sets(): From c5857f82c435f706ddce6ff496949cb3fb9fd242 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 15:35:08 -0700 Subject: [PATCH 556/742] Convert result of support() to list or tuple in two places --- src/sage/categories/loop_crystals.py | 2 +- src/sage/combinat/ncsf_qsym/tutorial.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/loop_crystals.py b/src/sage/categories/loop_crystals.py index aa96f2b5594..e065b7ef4f6 100644 --- a/src/sage/categories/loop_crystals.py +++ b/src/sage/categories/loop_crystals.py @@ -456,7 +456,7 @@ def b_sharp(self): bsharp = None for b in self: phi = b.Phi() - if phi.support() == [0] and phi[0] < ell: + if list(phi.support()) == [0] and phi[0] < ell: bsharp = b ell = phi[0] return bsharp diff --git a/src/sage/combinat/ncsf_qsym/tutorial.py b/src/sage/combinat/ncsf_qsym/tutorial.py index 5efc8d43728..78978507cb3 100644 --- a/src/sage/combinat/ncsf_qsym/tutorial.py +++ b/src/sage/combinat/ncsf_qsym/tutorial.py @@ -111,7 +111,7 @@ sage: sorted(z.coefficients()) [1, 2, 3] - sage: sorted(z.monomials(), key=lambda x: x.support()) + sage: sorted(z.monomials(), key=lambda x: tuple(x.support())) [M[1, 2], M[3, 3], M[6]] sage: z.monomial_coefficients() From 12da4ed7451883da43371a0296f0f29a3b9af347 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 15:44:09 -0700 Subject: [PATCH 557/742] ModulesWithBasis.ElementMethod.len: Use support --- src/sage/categories/modules_with_basis.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 0664ae33b7d..79d98764dd8 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1506,9 +1506,7 @@ def __len__(self): sage: len(z) 4 """ - zero = self.parent().base_ring().zero() - return len([key for key, coeff in self.monomial_coefficients(copy=False).items() - if coeff != zero]) + return len(self.support()) def length(self): """ @@ -1556,8 +1554,9 @@ def support(self): [[1], [1, 1, 1], [2, 1], [4]] """ from sage.structure.support_view import SupportView + zero = self.parent().base_ring().zero() mc = self.monomial_coefficients(copy=False) - return SupportView(mc) + return SupportView(mc, zero=zero) def monomials(self): """ From 1ddb29bcae0394d86153231bf2c4e6090bccd757 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 15:55:27 -0700 Subject: [PATCH 558/742] src/sage/structure/support_view.py: Fix up --- src/sage/structure/support_view.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/structure/support_view.py b/src/sage/structure/support_view.py index 13631e3d89e..1c7babee506 100644 --- a/src/sage/structure/support_view.py +++ b/src/sage/structure/support_view.py @@ -39,6 +39,7 @@ def __contains__(self, key): value = self._mapping[key] except KeyError: return False + zero = self._zero if zero is None: return bool(value) return value != zero From 31559b26eacad4c2d1591bd8212d3b4e4f3fcead Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 15:55:45 -0700 Subject: [PATCH 559/742] IndexedFreeModuleElement.__contains__: Deprecate --- src/sage/modules/with_basis/indexed_element.pyx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index cd1f17112f0..c9b92640d78 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -25,6 +25,7 @@ from cpython.object cimport Py_NE, Py_EQ from sage.misc.repr import repr_lincomb from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.superseded import deprecation from sage.typeset.ascii_art import AsciiArt, empty_ascii_art, ascii_art from sage.typeset.unicode_art import UnicodeArt, empty_unicode_art, unicode_art from sage.categories.all import Category, Sets, ModulesWithBasis @@ -93,7 +94,8 @@ cdef class IndexedFreeModuleElement(ModuleElement): sage: Partition([1,1,1]) in a False """ - return x in self._monomial_coefficients and self._monomial_coefficients[x] != 0 + deprecation(34509, "using 'index in vector' is deprecated; use 'index in vector.support()' instead") + return x in self.support() def __hash__(self): """ From eb2c92d58022493a6b005e4fcca6e982e41f95ad Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 16:09:06 -0700 Subject: [PATCH 560/742] ModulesWithBasis.support: Try to cache the SupportView object --- src/sage/categories/modules_with_basis.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 79d98764dd8..26b51ef4b87 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1553,10 +1553,19 @@ def support(self): sage: sorted(z.support()) [[1], [1, 1, 1], [2, 1], [4]] """ - from sage.structure.support_view import SupportView - zero = self.parent().base_ring().zero() - mc = self.monomial_coefficients(copy=False) - return SupportView(mc, zero=zero) + try: + return self._support_view + except AttributeError: + from sage.structure.support_view import SupportView + zero = self.parent().base_ring().zero() + mc = self.monomial_coefficients(copy=False) + support_view = SupportView(mc, zero=zero) + try: + # Try to cache it for next time, but this may fail for Cython classes + self._support_view = support_view + except AttributeError: + pass + return support_view def monomials(self): """ From bf91ea48ff7409cc2de2fecd236808bb1abd1a06 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 16:09:32 -0700 Subject: [PATCH 561/742] src/sage/combinat/ncsf_qsym/generic_basis_code.py: Replace deprecated 'index in vector' --- src/sage/combinat/ncsf_qsym/generic_basis_code.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/ncsf_qsym/generic_basis_code.py b/src/sage/combinat/ncsf_qsym/generic_basis_code.py index 98ebd37a0de..87364ac04c6 100644 --- a/src/sage/combinat/ncsf_qsym/generic_basis_code.py +++ b/src/sage/combinat/ncsf_qsym/generic_basis_code.py @@ -472,7 +472,7 @@ def skew(self, x, y, side='left'): y = self.dual()(y) v = 1 if side == 'left' else 0 return self.sum(coeff * y[IJ[1-v]] * self[IJ[v]] \ - for (IJ, coeff) in x.coproduct() if IJ[1-v] in y) + for (IJ, coeff) in x.coproduct() if IJ[1-v] in y.support()) else: return self._skew_by_coercion(x, y, side=side) From b3abc6c4094959e0ab6b75a67c06c8ce1acb004d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 16:14:52 -0700 Subject: [PATCH 562/742] src/sage/combinat/sf/sfa.py: Replace deprecated 'index in vector' --- src/sage/combinat/sf/sfa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index afeaf70a3e0..7eac828fa4b 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -2601,7 +2601,7 @@ def _inner_plethysm_pk_g(self, k, g, cache): for d in degrees: for mu in Partitions_n(d): mu_k = mu.power(k) - if mu_k in g: + if mu_k in g.support(): res += g.coefficient(mu_k)*mu_k.centralizer_size()/mu.centralizer_size()*p(mu) cache[(k,g)] = res From 82d8b62091f58f3ff68a8287be7e30515000f61f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 16:41:35 -0700 Subject: [PATCH 563/742] src/sage/structure/support_view.py: Add tests --- src/sage/structure/support_view.py | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/sage/structure/support_view.py b/src/sage/structure/support_view.py index 1c7babee506..ea7d38cf096 100644 --- a/src/sage/structure/support_view.py +++ b/src/sage/structure/support_view.py @@ -6,8 +6,56 @@ class SupportView(MappingView, Sequence, Set): + r""" + Dynamic view of the set of keys of a dictionary that are associated with nonzero values + + It behaves like the objects returned by the :meth:`keys`, :meth:`values`, + :meth:`items` of a dictionary (or other :class:`collections.abc.Mapping` + classes). + + INPUT: + + - ``mapping`` -- a :class:`dict` or another :class:`collections.abc.Mapping`. + + - ``zero`` -- (optional) test for zeroness by comparing with this value. + + EXAMPLES:: + + sage: d = {'a': 47, 'b': 0, 'c': 11} + sage: from sage.structure.support_view import SupportView + sage: supp = SupportView(d); supp + SupportView({'a': 47, 'b': 0, 'c': 11}) + sage: 'a' in supp, 'b' in supp, 'z' in supp + (True, False, False) + sage: len(supp) + 2 + sage: list(supp) + ['a', 'c'] + sage: supp[0], supp[1] + ('a', 'c') + sage: supp[-1] + 'c' + sage: supp[:] + ('a', 'c') + sage: supp[2] + Traceback (most recent call last): + ... + IndexError + + sage: d['b'] = 815 + sage: len(supp) + 3 + """ def __init__(self, mapping, *, zero=None): + r""" + TESTS:: + + sage: from sage.structure.support_view import SupportView + sage: supp = SupportView({'a': 'b', 'c': ''}, zero='') + sage: len(supp) + 1 + """ self._mapping = mapping self._zero = zero @@ -18,6 +66,10 @@ def __len__(self): return length def __getitem__(self, index): + if isinstance(index, slice): + return tuple(self)[index] + if index < 0: + return tuple(self)[index] for i, key in enumerate(self): if i == index: return key From 1f48aa0a04db254a63ad3eb953d64f167a2295cc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 16:57:32 -0700 Subject: [PATCH 564/742] src/sage/structure/support_view.py: Add more tests --- src/sage/structure/support_view.py | 48 +++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/sage/structure/support_view.py b/src/sage/structure/support_view.py index ea7d38cf096..49fc788868d 100644 --- a/src/sage/structure/support_view.py +++ b/src/sage/structure/support_view.py @@ -37,10 +37,8 @@ class SupportView(MappingView, Sequence, Set): 'c' sage: supp[:] ('a', 'c') - sage: supp[2] - Traceback (most recent call last): - ... - IndexError + + It reflects changes to the underlying dictionary:: sage: d['b'] = 815 sage: len(supp) @@ -60,12 +58,34 @@ def __init__(self, mapping, *, zero=None): self._zero = zero def __len__(self): + r""" + TESTS:: + + sage: d = {'a': 47, 'b': 0, 'c': 11} + sage: from sage.structure.support_view import SupportView + sage: supp = SupportView(d); supp + SupportView({'a': 47, 'b': 0, 'c': 11}) + sage: len(supp) + 2 + """ length = 0 for key in self: length += 1 return length def __getitem__(self, index): + r""" + TESTS:: + + sage: d = {'a': 47, 'b': 0, 'c': 11} + sage: from sage.structure.support_view import SupportView + sage: supp = SupportView(d); supp + SupportView({'a': 47, 'b': 0, 'c': 11}) + sage: supp[2] + Traceback (most recent call last): + ... + IndexError + """ if isinstance(index, slice): return tuple(self)[index] if index < 0: @@ -76,6 +96,16 @@ def __getitem__(self, index): raise IndexError def __iter__(self): + r""" + TESTS:: + + sage: d = {'a': 47, 'b': 0, 'c': 11} + sage: from sage.structure.support_view import SupportView + sage: supp = SupportView(d); supp + SupportView({'a': 47, 'b': 0, 'c': 11}) + sage: iter(supp) + + """ zero = self._zero if zero is None: for key, value in self._mapping.items(): @@ -87,6 +117,16 @@ def __iter__(self): yield key def __contains__(self, key): + r""" + TESTS:: + + sage: d = {'a': 47, 'b': 0, 'c': 11} + sage: from sage.structure.support_view import SupportView + sage: supp = SupportView(d); supp + SupportView({'a': 47, 'b': 0, 'c': 11}) + sage: 'a' in supp, 'b' in supp, 'z' in supp + (True, False, False) + """ try: value = self._mapping[key] except KeyError: From 2583a37c57bf2ea04c48eec6cc65a45b02c4938d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 17:05:30 -0700 Subject: [PATCH 565/742] IndexedFreeModuleElement: Add doc --- .../modules/with_basis/indexed_element.pyx | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index c9b92640d78..22309d2d364 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -32,6 +32,23 @@ from sage.categories.all import Category, Sets, ModulesWithBasis from sage.data_structures.blas_dict cimport add, negate, scal, axpy cdef class IndexedFreeModuleElement(ModuleElement): + r""" + Element class for :class:`~sage.combinat.free_module.CombinatorialFreeModule` + + TESTS:: + + sage: import collections.abc + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: B = F.basis() + sage: f = B['a'] + 3*B['c']; f + B['a'] + 3*B['c'] + sage: isinstance(f, collections.abc.Sized) + True + sage: isinstance(f, collections.abc.Iterable) + True + sage: isinstance(f, collections.abc.Collection) # known bug - will be fixed by removing __contains__ + False + """ def __init__(self, M, x): """ Create a combinatorial module element. This should never be @@ -81,6 +98,9 @@ cdef class IndexedFreeModuleElement(ModuleElement): sage: B = F.basis() sage: f = B['a'] + 3*B['c'] sage: 'a' in f + doctest:warning... + DeprecationWarning: using 'index in vector' is deprecated; use 'index in vector.support()' instead + See https://trac.sagemath.org/34509 for details. True sage: 'b' in f False From 88fe278795354296ad74dcc41b61b2aeb301d900 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 17:12:19 -0700 Subject: [PATCH 566/742] src/sage/structure/support_view.py: Fix doctest output --- src/sage/structure/support_view.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/structure/support_view.py b/src/sage/structure/support_view.py index 49fc788868d..6af9408bd29 100644 --- a/src/sage/structure/support_view.py +++ b/src/sage/structure/support_view.py @@ -104,7 +104,7 @@ def __iter__(self): sage: supp = SupportView(d); supp SupportView({'a': 47, 'b': 0, 'c': 11}) sage: iter(supp) - + """ zero = self._zero if zero is None: From 026d8a5061f8d7de5e6366679f7047e4a83f541e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 17:54:09 -0700 Subject: [PATCH 567/742] src/sage/algebras/steenrod/steenrod_algebra.py: Use key=...tuple(....support()) for sorting by lex support --- src/sage/algebras/steenrod/steenrod_algebra.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index 9e9ad450358..8feec0d6d98 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -402,13 +402,13 @@ (1, (2, 1)) sage: c.monomial_coefficients() == {(2, 1): 1, (5,): 1} True - sage: sorted(c.monomials(), key=lambda x: x.support()) + sage: sorted(c.monomials(), key=lambda x: tuple(x.support())) [Sq(2,1), Sq(5)] sage: sorted(c.support()) [(2, 1), (5,)] sage: Adem = SteenrodAlgebra(basis='adem') sage: elt = Adem.Sq(10) + Adem.Sq(9) * Adem.Sq(1) - sage: sorted(elt.monomials(), key=lambda x: x.support()) + sage: sorted(elt.monomials(), key=lambda x: tuple(x.support())) [Sq^9 Sq^1, Sq^10] sage: A7 = SteenrodAlgebra(p=7) @@ -3100,7 +3100,7 @@ class Element(CombinatorialFreeModule.Element): (1, (2, 1)) sage: c.monomial_coefficients() == {(2, 1): 1, (5,): 1} True - sage: sorted(c.monomials(), key=lambda x: x.support()) + sage: sorted(c.monomials(), key=lambda x: tuple(x.support())) [Sq(2,1), Sq(5)] sage: sorted(c.support()) [(2, 1), (5,)] @@ -3458,7 +3458,7 @@ def excess(self): sage: (Sq(0,0,1) + Sq(4,1) + Sq(7)).excess() 1 sage: elt = Sq(0,0,1) + Sq(4,1) + Sq(7) - sage: M = sorted(elt.monomials(), key=lambda x: x.support()) + sage: M = sorted(elt.monomials(), key=lambda x: tuple(x.support())) sage: [m.excess() for m in M] [1, 5, 7] sage: [m for m in M] From a4174115ef0899344ecfb301c42f032de5b1950e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 18:06:12 -0700 Subject: [PATCH 568/742] SupportView.__eq__, __ne__: New --- src/sage/structure/support_view.py | 40 ++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/sage/structure/support_view.py b/src/sage/structure/support_view.py index 6af9408bd29..0212afb5414 100644 --- a/src/sage/structure/support_view.py +++ b/src/sage/structure/support_view.py @@ -4,6 +4,8 @@ from collections.abc import MappingView, Sequence, Set +from sage.misc.superseded import deprecation + class SupportView(MappingView, Sequence, Set): r""" @@ -135,3 +137,41 @@ def __contains__(self, key): if zero is None: return bool(value) return value != zero + + def __eq__(self, other): + r""" + TESTS:: + + sage: d = {1: 17, 2: 0} + sage: from sage.structure.support_view import SupportView + sage: supp = SupportView(d); supp + SupportView({1: 17, 2: 0}) + sage: supp == [1] + doctest:warning... + DeprecationWarning: comparing a SupportView with a list is deprecated + See https://trac.sagemath.org/34509 for details. + True + """ + if isinstance(other, list): + deprecation(34509, 'comparing a SupportView with a list is deprecated') + return list(self) == other + return NotImplemented + + def __ne__(self, other): + r""" + TESTS:: + + sage: d = {1: 17, 2: 0} + sage: from sage.structure.support_view import SupportView + sage: supp = SupportView(d); supp + SupportView({1: 17, 2: 0}) + sage: supp != [1] + doctest:warning... + DeprecationWarning: comparing a SupportView with a list is deprecated + See https://trac.sagemath.org/34509 for details. + False + """ + if isinstance(other, list): + deprecation(34509, 'comparing a SupportView with a list is deprecated') + return list(self) != other + return NotImplemented From b80989ff00667e5578f04a28a3d7ec6ff679c498 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 18:08:31 -0700 Subject: [PATCH 569/742] src/sage/combinat/sf/character.py: Use list(....support()) --- src/sage/combinat/sf/character.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index e55f356f5d1..e5752c307eb 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -104,7 +104,7 @@ def _other_to_self(self, sexpr): """ if sexpr == 0: return self(0) - if sexpr.support() == [[]]: + if list(sexpr.support()) == [[]]: return self._from_dict({self.one_basis(): sexpr.coefficient([])}, remove_zeros=False) out = self.zero() From 57273ea3262a27501953d1af04f6d8f35110b0da Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 21:13:33 -0700 Subject: [PATCH 570/742] src/doc/en/thematic_tutorials/lie/weyl_character_ring.rst: Use key=...tuple(....support()) for sorting by lex support --- src/doc/en/thematic_tutorials/lie/weyl_character_ring.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/en/thematic_tutorials/lie/weyl_character_ring.rst b/src/doc/en/thematic_tutorials/lie/weyl_character_ring.rst index a7052507284..ddc33a325a8 100644 --- a/src/doc/en/thematic_tutorials/lie/weyl_character_ring.rst +++ b/src/doc/en/thematic_tutorials/lie/weyl_character_ring.rst @@ -164,7 +164,7 @@ coefficients) through the usual free module accessors:: [((0, 0, 0), 1), ((1, 0, 0), 1), ((1, 1, 0), 1), ((1, 1, 1), 1)] sage: pprint(dict(chi)) {(0, 0, 0): 1, (1, 0, 0): 1, (1, 1, 0): 1, (1, 1, 1): 1} - sage: M = sorted(chi.monomials(), key=lambda x: x.support()); M + sage: M = sorted(chi.monomials(), key=lambda x: tuple(x.support())); M [B3(0,0,0), B3(1,0,0), B3(1,1,0), B3(1,1,1)] sage: sorted(chi.support()) [(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 1, 1)] @@ -485,7 +485,7 @@ itself, that is, the integral of `|tr(g)|^{10}`:: sage: tr^5 5*A2(2,2,1) + 6*A2(3,1,1) + 5*A2(3,2,0) + 4*A2(4,1,0) + A2(5,0,0) - sage: sorted((tr^5).monomials(), key=lambda x: x.support()) + sage: sorted((tr^5).monomials(), key=lambda x: tuple(x.support())) [A2(2,2,1), A2(3,1,1), A2(3,2,0), A2(4,1,0), A2(5,0,0)] sage: sorted((tr^5).coefficients()) [1, 4, 5, 5, 6] From 6ce669c687776a781f01c86439fc8739a25eb4cc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 21:14:26 -0700 Subject: [PATCH 571/742] src/sage/modules/tutorial_free_modules.py: Fix doctest output --- src/sage/modules/tutorial_free_modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modules/tutorial_free_modules.py b/src/sage/modules/tutorial_free_modules.py index 88810b2e42b..d58acd4ae9f 100644 --- a/src/sage/modules/tutorial_free_modules.py +++ b/src/sage/modules/tutorial_free_modules.py @@ -162,7 +162,7 @@ (2, 3) sage: f.support() - [0, 1, 2] + SupportView({0: 2, 1: 2, 2: 3}) sage: f.monomials() [a[0], a[1], a[2]] sage: f.coefficients() From 2fe3b981c7ebf07dfe8992d5f591b3bb73841ede Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Sep 2022 21:17:48 -0700 Subject: [PATCH 572/742] src/sage/algebras/quantum_groups/fock_space.py: Use sorted() with support, not sort --- src/sage/algebras/quantum_groups/fock_space.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sage/algebras/quantum_groups/fock_space.py b/src/sage/algebras/quantum_groups/fock_space.py index dea28fd1760..3352f143a7c 100644 --- a/src/sage/algebras/quantum_groups/fock_space.py +++ b/src/sage/algebras/quantum_groups/fock_space.py @@ -1354,9 +1354,8 @@ def _G_to_fock_basis(self, la): return fock.sum_of_terms((fock._indices([[]]*k + list(pt)), c) for pt,c in cur) cur = R.A()._A_to_fock_basis(la) - s = cur.support() - s.sort() # Sort lex, which respects dominance order - s.pop() # Remove the largest + s = sorted(cur.support()) # Sort lex, which respects dominance order + s.pop() # Remove the largest q = R._q while s: @@ -2189,9 +2188,8 @@ def add_cols(nu): # Perform the triangular reduction cur = self.realization_of().A(algorithm)._A_to_fock_basis(la) - s = cur.support() - s.sort() # Sort lex, which respects dominance order - s.pop() # Remove the largest + s = sorted(cur.support()) # Sort lex, which respects dominance order + s.pop() # Remove the largest q = self.realization_of()._q while s: From eac0595a621dedb89d1ad7b3ad8ece726275d236 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 11 Sep 2022 18:36:54 +0800 Subject: [PATCH 573/742] avoid mutating inputs by doing first layer out-of-place --- src/sage/arith/misc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index ddc0e25fa3f..cc066bf2f57 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -3302,6 +3302,8 @@ def CRT_list(v, moduli): if len(v) == 1: return moduli[0].parent()(v[0]) from sage.arith.functions import lcm + v = [CRT(v[i], v[i+1], moduli[i], moduli[i+1]) for i in range(0, len(v)-1, 2)] + v[len(v)//2*2:] + moduli = [lcm(moduli[i], moduli[i+1]) for i in range(0, len(moduli)-1, 2)] + moduli[len(moduli)//2*2:] while len(v) > 1: for i in range(0, len(v)-1, 2): v[i] = CRT(v[i], v[i+1], moduli[i], moduli[i+1]) From 367b86236c861a41d7684a4228e26075207910fb Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sun, 11 Sep 2022 19:32:47 +0200 Subject: [PATCH 574/742] #34519 fix msolve interface msolve's output in "parameterization" mode has changed with v0.3.0(?), and, as far as I understand, should now be stable. --- src/sage/rings/polynomial/msolve.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index b32f9f8505a..d05d103b159 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -158,7 +158,10 @@ def _variety(ideal, ring, proof): # Interpret output - data = sage_eval(msolve_out.stdout[:-2]) + try: + data = sage_eval(msolve_out.stdout[:-2]) + except SyntaxError: + raise NotImplementedError(f"unsupported msolve output format: {data}") dim = data[0] if dim == -1: @@ -176,10 +179,11 @@ def to_poly(p, upol=PolynomialRing(base, 't')): assert len(p[1]) == p[0] + 1 return upol(p[1]) - if len(data) != 3: + try: + [dim1, nvars, _, vars, _, [one, [elim, den, param]]] = data[1] + except (IndexError, ValueError): raise NotImplementedError( f"unsupported msolve output format: {data}") - [dim1, nvars, _, vars, _, [one, elim, den, param]] = data[1] assert dim1.is_zero() assert one.is_one() assert len(vars) == nvars From 1f4fdcd4a207a3792a37621162f30a4d0a7b2a08 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 11 Sep 2022 19:56:17 +0200 Subject: [PATCH 575/742] trac #34520: remove doctest in RandomHolmeKim generator --- src/sage/graphs/generators/random.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 93cf637b8dd..1b0f4cd9d4d 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -805,19 +805,7 @@ def RandomHolmeKim(n, m, p, seed=None): may not be all linked to a new node on the first iteration like the BA model. - EXAMPLES: - - We check that a random graph on 8 nodes with 2 random edges per node and a - probability `p = 0.5` of forming triangles contains a triangle:: - - sage: G = graphs.RandomHolmeKim(8, 2, 0.5) - sage: G.order(), G.size() - (8, 12) - sage: C3 = graphs.CycleGraph(3) - sage: G.subgraph_search(C3) - Subgraph of (): Graph on 3 vertices - - :: + EXAMPLES:: sage: G = graphs.RandomHolmeKim(12, 3, .3) sage: G.show() # long time From ea64d4a71b92f5ea94b2431afb8c3819a07a6683 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Mon, 12 Sep 2022 08:15:37 +0200 Subject: [PATCH 576/742] =?UTF-8?q?#34519=20msolve:=20real=20solving=20wit?= =?UTF-8?q?h=20=E2=84=93=20>=201?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Attempt to support the case ℓ > 1 described in §4 of the msolve tutorial when computing zero-dimensional varieties over the reals. Last I heard this is not yet actually used in msolve but will be in the future. --- src/sage/rings/polynomial/msolve.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index d05d103b159..88f1c6889bb 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -205,10 +205,9 @@ def to_poly(p, upol=PolynomialRing(base, 't')): else: - if len(data) != 2 or data[1][0] != 1: + if len(data[1]) < 2 or len(data[1]) != data[1][0] + 1: raise NotImplementedError( f"unsupported msolve output format: {data}") - _, [_, variety] = data if isinstance(ring, (RealIntervalField_class, RealBallField)): to_out_ring = ring else: @@ -217,7 +216,8 @@ def to_poly(p, upol=PolynomialRing(base, 't')): to_out_ring = lambda iv: ring.coerce(myRIF(iv).center()) vars = out_ring.gens() variety = [[to_out_ring(iv) for iv in point] - for point in variety] + for l in data[1][1:] + for point in l] return [KeyConvertingDict(out_ring, zip(vars, point)) for point in variety] From a8aad93d2a4aa903976bf7fc77d71234b2e19411 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Mon, 12 Sep 2022 09:30:54 -0400 Subject: [PATCH 577/742] src/sage/lfunctions/pari.py: apply pycodestyle to the examples strings --- src/sage/lfunctions/pari.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/lfunctions/pari.py b/src/sage/lfunctions/pari.py index d2b20f1891b..34db7ab81eb 100644 --- a/src/sage/lfunctions/pari.py +++ b/src/sage/lfunctions/pari.py @@ -126,7 +126,7 @@ def init_coeffs(self, v, cutoff=None, w=1, *args, **kwds): EXAMPLES:: sage: from sage.lfunctions.pari import lfun_generic, LFunction - sage: lf = lfun_generic(conductor=1, gammaV=[0,1], weight=12, eps=1) + sage: lf = lfun_generic(conductor=1, gammaV=[0, 1], weight=12, eps=1) sage: pari_coeffs = pari('k->vector(k,n,(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5)))') sage: lf.init_coeffs(pari_coeffs) @@ -144,7 +144,7 @@ def init_coeffs(self, v, cutoff=None, w=1, *args, **kwds): Illustrate that one can give a list of complex numbers for v (see :trac:`10937`):: - sage: l2 = lfun_generic(conductor=1, gammaV=[0,1], weight=12, eps=1) + sage: l2 = lfun_generic(conductor=1, gammaV=[0, 1], weight=12, eps=1) sage: l2.init_coeffs(list(delta_qexp(1000))[1:]) sage: L2 = LFunction(l2) sage: L2(14) @@ -155,7 +155,7 @@ def init_coeffs(self, v, cutoff=None, w=1, *args, **kwds): Verify that setting the `w` parameter does not raise an error (see :trac:`10937`):: - sage: L2 = lfun_generic(conductor=1, gammaV=[0,1], weight=12, eps=1) + sage: L2 = lfun_generic(conductor=1, gammaV=[0, 1], weight=12, eps=1) sage: L2.init_coeffs(list(delta_qexp(1000))[1:], w=[1..1000]) Additional arguments are ignored for compatibility with the old @@ -250,12 +250,12 @@ def lfun_character(chi): Check the values:: - sage: chi = DirichletGroup(24)([1,-1,-1]); chi + sage: chi = DirichletGroup(24)([1, -1, -1]); chi Dirichlet character modulo 24 of conductor 24 mapping 7 |--> 1, 13 |--> -1, 17 |--> -1 sage: Lchi = lfun_character(chi) sage: v = [0] + Lchi.lfunan(30).sage() - sage: all(v[i] == chi(i) for i in (7,13,17)) + sage: all(v[i] == chi(i) for i in (7, 13, 17)) True """ if not chi.is_primitive(): @@ -285,7 +285,7 @@ def lfun_elliptic_curve(E): Over number fields:: sage: K. = QuadraticField(2) - sage: E = EllipticCurve([1,a]) + sage: E = EllipticCurve([1, a]) sage: L = LFunction(lfun_elliptic_curve(E)) sage: L(3) 1.00412346717019 @@ -338,10 +338,10 @@ def lfun_eta_quotient(scalings, exponents): sage: L(1) 0.0374412812685155 - sage: lfun_eta_quotient([6],[4]) + sage: lfun_eta_quotient([6], [4]) [[Vecsmall([7]), [Vecsmall([6]), Vecsmall([4])]], 0, [0, 1], 2, 36, 1] - sage: lfun_eta_quotient([2,1,4], [5,-2,-2]) + sage: lfun_eta_quotient([2, 1, 4], [5, -2, -2]) Traceback (most recent call last): ... PariError: sorry, noncuspidal eta quotient is not yet implemented @@ -377,7 +377,7 @@ def lfun_quadratic_form(qf): EXAMPLES:: sage: from sage.lfunctions.pari import lfun_quadratic_form, LFunction - sage: Q = QuadraticForm(ZZ,2,[2,3,4]) + sage: Q = QuadraticForm(ZZ, 2, [2, 3, 4]) sage: L = LFunction(lfun_quadratic_form(Q)) sage: L(3) 0.377597233183583 From 1dda15c32c9516db2ade8396bd5e1dc64efc4433 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Mon, 12 Sep 2022 09:31:59 -0400 Subject: [PATCH 578/742] src/sage/lfunctions/pari.py: apply pycodestyle to the examples string 2 --- src/sage/lfunctions/pari.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/lfunctions/pari.py b/src/sage/lfunctions/pari.py index 34db7ab81eb..662c9abc70a 100644 --- a/src/sage/lfunctions/pari.py +++ b/src/sage/lfunctions/pari.py @@ -409,7 +409,7 @@ def lfun_genus2(C): sage: L(3) 0.965946926261520 - sage: C = HyperellipticCurve(x^2+x, x^3+x^2+1) + sage: C = HyperellipticCurve(x^2 + x, x^3 + x^2 + 1) sage: L = LFunction(lfun_genus2(C)) sage: L(2) 0.364286342944359 @@ -445,11 +445,11 @@ class LFunction(SageObject): 0.000000000000000 sage: L.derivative(1) 0.305999773834052 - sage: L.derivative(1,2) + sage: L.derivative(1, 2) 0.373095594536324 sage: L.num_coeffs() 50 - sage: L.taylor_series(1,4) + sage: L.taylor_series(1, 4) 0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + O(z^4) sage: L.check_functional_equation() # abs tol 4e-19 1.08420217248550e-19 @@ -463,9 +463,9 @@ class LFunction(SageObject): sage: L = E.lseries().dokchitser(algorithm="pari") sage: L.num_coeffs() 163 - sage: L.derivative(1,E.rank()) + sage: L.derivative(1, E.rank()) 1.51863300057685 - sage: L.taylor_series(1,4) + sage: L.taylor_series(1, 4) ...e-19 + (...e-19)*z + 0.759316500288427*z^2 - 0.430302337583362*z^3 + O(z^4) .. RUBRIC:: Number field @@ -481,7 +481,7 @@ class LFunction(SageObject): 348 sage: L(2) 1.10398438736918 - sage: L.taylor_series(2,3) + sage: L.taylor_series(2, 3) 1.10398438736918 - 0.215822638498759*z + 0.279836437522536*z^2 + O(z^3) .. RUBRIC:: Ramanujan `\Delta` L-function @@ -489,7 +489,7 @@ class LFunction(SageObject): The coefficients are given by Ramanujan's tau function:: sage: from sage.lfunctions.pari import lfun_generic, LFunction - sage: lf = lfun_generic(conductor=1, gammaV=[0,1], weight=12, eps=1) + sage: lf = lfun_generic(conductor=1, gammaV=[0, 1], weight=12, eps=1) sage: tau = pari('k->vector(k,n,(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5)))') sage: lf.init_coeffs(tau) sage: L = LFunction(lf) @@ -498,7 +498,7 @@ class LFunction(SageObject): sage: L(1) 0.0374412812685155 - sage: L.taylor_series(1,3) + sage: L.taylor_series(1, 3) 0.0374412812685155 + 0.0709221123619322*z + 0.0380744761270520*z^2 + O(z^3) """ def __init__(self, lfun, prec=None): @@ -608,7 +608,7 @@ def Lambda(self, s): sage: L = LFunction(lfun_number_field(QQ)) sage: L.Lambda(2) 0.523598775598299 - sage: L.Lambda(1-2) + sage: L.Lambda(1 - 2) 0.523598775598299 """ s = self._CCin(s) @@ -630,7 +630,7 @@ def hardy(self, t): TESTS:: - sage: L.hardy(.4+.3*I) + sage: L.hardy(.4 + .3*I) Traceback (most recent call last): ... PariError: incorrect type in lfunhardy (t_COMPLEX) @@ -694,7 +694,7 @@ def taylor_series(self, s, k=6, var='z'): sage: E = EllipticCurve('389a') sage: L = E.lseries().dokchitser(200,algorithm="pari") - sage: L.taylor_series(1,3) + sage: L.taylor_series(1, 3) 2...e-63 + (...e-63)*z + 0.75931650028842677023019260789472201907809751649492435158581*z^2 + O(z^3) Check that :trac:`25402` is fixed:: @@ -757,7 +757,7 @@ def __call__(self, s): sage: L = E.lseries().dokchitser(100, algorithm="pari") sage: L(1) 0.00000000000000000000000000000 - sage: L(1+I) + sage: L(1 + I) -1.3085436607849493358323930438 + 0.81298000036784359634835412129*I """ s = self._CC(s) From 469f86608efb1f214225671017644bd61befa063 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Mon, 12 Sep 2022 09:33:32 -0400 Subject: [PATCH 579/742] src/sage/lfunctions/pari.py: remove old deprecation warning --- src/sage/lfunctions/pari.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/sage/lfunctions/pari.py b/src/sage/lfunctions/pari.py index 662c9abc70a..615b876ceda 100644 --- a/src/sage/lfunctions/pari.py +++ b/src/sage/lfunctions/pari.py @@ -157,18 +157,7 @@ def init_coeffs(self, v, cutoff=None, w=1, *args, **kwds): sage: L2 = lfun_generic(conductor=1, gammaV=[0, 1], weight=12, eps=1) sage: L2.init_coeffs(list(delta_qexp(1000))[1:], w=[1..1000]) - - Additional arguments are ignored for compatibility with the old - Dokchitser script:: - - sage: L2.init_coeffs(list(delta_qexp(1000))[1:], foo="bar") - doctest:...: DeprecationWarning: additional arguments for initializing an lfun_generic are ignored - See https://trac.sagemath.org/26098 for details. """ - if args or kwds: - from sage.misc.superseded import deprecation - deprecation(26098, "additional arguments for initializing an lfun_generic are ignored") - v = pari(v) if v.type() not in ('t_CLOSURE', 't_VEC'): raise TypeError("v (coefficients) must be a list or a function") From 4c9486b75fb02b14a21278bb69e44998c5045ccd Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Mon, 12 Sep 2022 09:58:08 -0400 Subject: [PATCH 580/742] src/sage/lfunctions/pari.py: remove unnecessary arguments, last pycodestyle --- src/sage/lfunctions/pari.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/lfunctions/pari.py b/src/sage/lfunctions/pari.py index 615b876ceda..da783d28310 100644 --- a/src/sage/lfunctions/pari.py +++ b/src/sage/lfunctions/pari.py @@ -108,7 +108,7 @@ def __init__(self, conductor, gammaV, weight, eps, poles=[], if args or kwds: self.init_coeffs(*args, **kwds) - def init_coeffs(self, v, cutoff=None, w=1, *args, **kwds): + def init_coeffs(self, v, cutoff=None, w=1): """ Set the coefficients `a_n` of the `L`-series. @@ -298,7 +298,7 @@ def lfun_number_field(K): sage: L(3) 1.20205690315959 - sage: K = NumberField(x**2-2, 'a') + sage: K = NumberField(x**2 - 2, 'a') sage: L = LFunction(lfun_number_field(K)) sage: L(3) 1.15202784126080 From d252ea46cf7ede4cd737cfdc586c92c44a2ecbcb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 12 Sep 2022 10:19:57 -0700 Subject: [PATCH 581/742] build/pkgs/pynormaliz/distros: Add arch, conda --- build/pkgs/pynormaliz/distros/arch.txt | 1 + build/pkgs/pynormaliz/distros/conda.txt | 1 + 2 files changed, 2 insertions(+) create mode 100644 build/pkgs/pynormaliz/distros/arch.txt create mode 100644 build/pkgs/pynormaliz/distros/conda.txt diff --git a/build/pkgs/pynormaliz/distros/arch.txt b/build/pkgs/pynormaliz/distros/arch.txt new file mode 100644 index 00000000000..140dd0508e9 --- /dev/null +++ b/build/pkgs/pynormaliz/distros/arch.txt @@ -0,0 +1 @@ +python-pynormaliz diff --git a/build/pkgs/pynormaliz/distros/conda.txt b/build/pkgs/pynormaliz/distros/conda.txt new file mode 100644 index 00000000000..276703b325b --- /dev/null +++ b/build/pkgs/pynormaliz/distros/conda.txt @@ -0,0 +1 @@ +pynormaliz From d90b64c6b7957b6c2294a1f0efb0447fcce138fa Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 12 Sep 2022 11:27:17 -0700 Subject: [PATCH 582/742] Revert "build/pkgs/git_trac_command: New" This reverts commit ac2c48db84c1a59e333552e5abfcdc3229fb9084. --- build/pkgs/git_trac_command/SPKG.rst | 14 -------------- build/pkgs/git_trac_command/requirements.txt | 1 - build/pkgs/git_trac_command/trees.txt | 1 - build/pkgs/git_trac_command/type | 1 - 4 files changed, 17 deletions(-) delete mode 100644 build/pkgs/git_trac_command/SPKG.rst delete mode 100644 build/pkgs/git_trac_command/requirements.txt delete mode 100644 build/pkgs/git_trac_command/trees.txt delete mode 100644 build/pkgs/git_trac_command/type diff --git a/build/pkgs/git_trac_command/SPKG.rst b/build/pkgs/git_trac_command/SPKG.rst deleted file mode 100644 index d8da01bd818..00000000000 --- a/build/pkgs/git_trac_command/SPKG.rst +++ /dev/null @@ -1,14 +0,0 @@ -git_trac_command: Provides the subcommand "git trac" -==================================================== - -Description ------------ - -This module implements a subcommand ``git trac``. -See https://doc.sagemath.org/html/en/developer/git_trac.html - - -Upstream Contact ----------------- - -https://github.com/sagemath/git-trac-command diff --git a/build/pkgs/git_trac_command/requirements.txt b/build/pkgs/git_trac_command/requirements.txt deleted file mode 100644 index 4f36b5eae53..00000000000 --- a/build/pkgs/git_trac_command/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -git+https://github.com/sagemath/git-trac-command diff --git a/build/pkgs/git_trac_command/trees.txt b/build/pkgs/git_trac_command/trees.txt deleted file mode 100644 index b268580307d..00000000000 --- a/build/pkgs/git_trac_command/trees.txt +++ /dev/null @@ -1 +0,0 @@ -# Users should install this manually in their environment. It should not be installed in SAGE_VENV diff --git a/build/pkgs/git_trac_command/type b/build/pkgs/git_trac_command/type deleted file mode 100644 index 134d9bc32d5..00000000000 --- a/build/pkgs/git_trac_command/type +++ /dev/null @@ -1 +0,0 @@ -optional From 9a03d7fe7beb1bae71415938f7cb3ef9417c9fb1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 12 Sep 2022 17:26:45 -0700 Subject: [PATCH 583/742] build/sage_bootstrap/installcheck.py: Make error message more specific --- build/sage_bootstrap/installcheck.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/sage_bootstrap/installcheck.py b/build/sage_bootstrap/installcheck.py index 83f28c07c6d..a02db3c74fd 100644 --- a/build/sage_bootstrap/installcheck.py +++ b/build/sage_bootstrap/installcheck.py @@ -153,7 +153,7 @@ def spkg_type(pkg): if not pth.isdir(pkgbase): raise argparse.ArgumentTypeError( - "'{0}' is not a known spkg".format(pkg)) + "'{0}' is not an spkg listed in '{1}'".format(pkg, PKGS)) return pkg From bccc17d8d2e236c74c49fe512dbe4e563dd6c509 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 12 Sep 2022 17:42:30 -0700 Subject: [PATCH 584/742] build/pkgs/numpy: Update to 1.23.3 --- build/pkgs/numpy/checksums.ini | 6 +++--- build/pkgs/numpy/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/numpy/checksums.ini b/build/pkgs/numpy/checksums.ini index 9c688839a58..544f35fbfb8 100644 --- a/build/pkgs/numpy/checksums.ini +++ b/build/pkgs/numpy/checksums.ini @@ -1,5 +1,5 @@ tarball=numpy-VERSION.tar.gz -sha1=1cbc6c34a5c4522322951d502982060e0e48811e -md5=9bf2a361509797de14ceee607387fe0f -cksum=1967048071 +sha1=570c995d7b155c7e4ac43bc46594172cedf1e4fa +md5=6efc60a3f6c1b74c849d53fbcc07807b +cksum=3973735135 upstream_url=https://pypi.io/packages/source/n/numpy/numpy-VERSION.tar.gz diff --git a/build/pkgs/numpy/package-version.txt b/build/pkgs/numpy/package-version.txt index 14bee92c9e7..ac1df3fce34 100644 --- a/build/pkgs/numpy/package-version.txt +++ b/build/pkgs/numpy/package-version.txt @@ -1 +1 @@ -1.23.2 +1.23.3 From 70ba7b581c14aff406bec3d453199dfef47cc1fa Mon Sep 17 00:00:00 2001 From: Dennis Jahn Date: Tue, 13 Sep 2022 09:48:00 +0200 Subject: [PATCH 585/742] added Dy1994 and JS2021 to master reference file --- src/doc/en/reference/references/index.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 46e46557a02..564a89f42f6 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -2129,6 +2129,9 @@ REFERENCES: .. [Dy1993] \M. J. Dyer. *Hecke algebras and shellings of Bruhat intervals*. Compositio Mathematica, 1993, 89(1): 91-115. +.. [Dy1994] \M. J. Dyer. *Bruhat intervals, polyhedral cones and + Kazhdan-Lusztig-Stanley polynomials*. Math.Z., 215(2):223-236, 1994. + .. _ref-E: **E** @@ -3297,6 +3300,10 @@ REFERENCES: J. Algebra. **324** (2010). 2512-2542. :doi:`10.1016/j.bbr.2011.03.031`, :arxiv:`0909.2442`. +.. [JS2021] \D. Jahn, C. Stump. + *Bruhat intervals, subword complexes and brick polyhedra for + finite Coxeter groups*, 2021, :arxiv:`2103.03715`. + .. [JV2000] \J. Justin, L. Vuillon, *Return words in Sturmian and episturmian words*, Theor. Inform. Appl. 34 (2000) 343--356. From 648e6340df54ecdf456a4019a84dae2853661660 Mon Sep 17 00:00:00 2001 From: Dennis Jahn Date: Tue, 13 Sep 2022 09:49:43 +0200 Subject: [PATCH 586/742] moved references and deleted empty lines --- .../combinat/root_system/reflection_group_real.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/root_system/reflection_group_real.py b/src/sage/combinat/root_system/reflection_group_real.py index 38bfee60855..9e5c2e2c1b0 100644 --- a/src/sage/combinat/root_system/reflection_group_real.py +++ b/src/sage/combinat/root_system/reflection_group_real.py @@ -27,11 +27,6 @@ - Christian Stump (initial version 2011--2015) -REFERENCES: - -.. [Dye] Dyer. *Bruhat intervals, polyhedral cones and Kazhdan-Lusztig-Stanley polynomials*. Math.Z., 215(2):223-236, 1994. -.. [JahStu] Jahn and Stump. *Bruhat intervals, subword complexes and brick polyhedra for finite Coxeter groups*. Preprint, available at :arxiv:`2103.03715`, 2021. - .. WARNING:: Uses the GAP3 package *Chevie* which is available as an @@ -727,9 +722,7 @@ def bruhat_cone(self, x, y, side='upper', backend='cdd'): INPUT: - ``x`` - an element in the group `W` - - ``y`` - an element in the group `W` - - ``side`` (default: ``'upper'``) -- must be one of the following: * ``'upper'`` - return the upper Bruhat cone of the interval [``x``, ``y``] @@ -763,8 +756,8 @@ def bruhat_cone(self, x, y, side='upper', backend='cdd'): REFERENCES: - - [Dye]_ - - [JahStu]_ + - [Dy1994]_ + - [JS2021]_ """ if side == 'upper': roots = [self.reflection_to_positive_root(x * r * x.inverse()) From 65bce216c6aea9b27fff8f1551ef355f1e951a1a Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Tue, 13 Sep 2022 23:59:58 +0800 Subject: [PATCH 587/742] improve readability --- src/sage/arith/misc.py | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index cc066bf2f57..524fd2e0dfa 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -3224,10 +3224,10 @@ def crt(a, b, m=None, n=None): CRT = crt -def CRT_list(v, moduli): - r""" Given a list ``v`` of elements and a list of corresponding +def CRT_list(values, moduli): + r""" Given a list ``values`` of elements and a list of corresponding ``moduli``, find a single element that reduces to each element of - ``v`` modulo the corresponding moduli. + ``values`` modulo the corresponding moduli. The result is computed using a binary tree. In typical cases, this scales much better than folding the list from one side. @@ -3292,24 +3292,32 @@ def CRT_list(v, moduli): sage: from gmpy2 import mpz sage: CRT_list([mpz(2),mpz(3),mpz(2)], [mpz(3),mpz(5),mpz(7)]) 23 + + Make sure we are not mutating the input lists:: + + sage: xs = [1,2,3] + sage: ms = [5,7,9] + sage: CRT_list(xs, ms) + 156 + sage: xs + [1, 2, 3] + sage: ms + [5, 7, 9] """ - if not isinstance(v, list) or not isinstance(moduli, list): + if not isinstance(values, list) or not isinstance(moduli, list): raise ValueError("arguments to CRT_list should be lists") - if len(v) != len(moduli): + if len(values) != len(moduli): raise ValueError("arguments to CRT_list should be lists of the same length") - if not v: + if not values: return ZZ.zero() - if len(v) == 1: - return moduli[0].parent()(v[0]) from sage.arith.functions import lcm - v = [CRT(v[i], v[i+1], moduli[i], moduli[i+1]) for i in range(0, len(v)-1, 2)] + v[len(v)//2*2:] - moduli = [lcm(moduli[i], moduli[i+1]) for i in range(0, len(moduli)-1, 2)] + moduli[len(moduli)//2*2:] - while len(v) > 1: - for i in range(0, len(v)-1, 2): - v[i] = CRT(v[i], v[i+1], moduli[i], moduli[i+1]) - moduli[i] = lcm(moduli[i], moduli[i+1]) - v, moduli = v[::2], moduli[::2] - return v[0] % moduli[0] + while len(values) > 1: + vs, ms = values[::2], moduli[::2] + for i,(v,m) in enumerate(zip(values[1::2], moduli[1::2])): + vs[i] = CRT(vs[i], v, ms[i], m) + ms[i] = lcm(ms[i], m) + values, moduli = vs, ms + return values[0] % moduli[0] def CRT_basis(moduli): From 4ddf379b64475385ab662e78edf45f81c4b0717d Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Thu, 8 Sep 2022 17:43:18 -0500 Subject: [PATCH 588/742] Add tests, remove buggy check, add to check --- src/sage/combinat/integer_vector.py | 31 ++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index ee73284a59c..7295ba97571 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -453,9 +453,29 @@ def check(self): sage: IV = IntegerVectors() sage: elt = IV([1,2,1]) sage: elt.check() + + Check :trac:`34510`:: + + sage: IV3 = IntegerVectors(n=3) + sage: IV3([2,2]) + Traceback (most recent call last): + ... + ValueError: [2, 2] doesn't satisfy correct constraints + sage: IVk3 = IntegerVectors(k=3) + sage: IVk3([2,2]) + Traceback (most recent call last): + ... + ValueError: [2, 2] doesn't satisfy correct constraints + sage: IV33 = IntegerVectors(n=3, k=3) + sage: IV33([2,2]) + Traceback (most recent call last): + ... + ValueError: [2, 2] doesn't satisfy correct constraints """ if any(x < 0 for x in self): raise ValueError("all entries must be non-negative") + if self not in self.parent(): + raise ValueError(f"{self} doesn't satisfy correct constraints") class IntegerVectors(Parent, metaclass=ClasscallMetaclass): @@ -1015,10 +1035,15 @@ def __contains__(self, x): False sage: [3,2,2,1] in IntegerVectors(8, 4) True - """ - if isinstance(x, IntegerVector) and x.parent() is self: - return True + Check :trac:`34510`:: + + sage: IV33 = IntegerVectors(n=3, k=3) + sage: IV33([0]) + Traceback (most recent call last): + ... + ValueError: [0] doesn't satisfy correct constraints + """ if not IntegerVectors.__contains__(self, x): return False From 43e68135a00c4a1707545061bef649d2506070f3 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 13 Sep 2022 11:16:21 -0500 Subject: [PATCH 589/742] List/tuple -> sequence --- src/sage/combinat/integer_vector.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index 7295ba97571..e0cd57a3eec 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -30,6 +30,7 @@ from sage.combinat.integer_lists import IntegerListsLex from itertools import product +from collections.abc import Sequence import numbers from sage.structure.parent import Parent @@ -696,7 +697,7 @@ def __contains__(self, x): if isinstance(x, IntegerVector): return True - if not isinstance(x, (list, tuple)): + if not isinstance(x, Sequence): return False for i in x: From 1463b3ed10ef383a6fb447e405d04c1db1024094 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 13 Sep 2022 13:48:33 -0500 Subject: [PATCH 590/742] Register Composition as a sequence --- src/sage/combinat/composition.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index cc709bc5091..ad401487471 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -20,6 +20,7 @@ - Mike Hansen, Nicolas M. Thiéry - MuPAD-Combinat developers (algorithms and design inspiration) - Travis Scrimshaw (2013-02-03): Removed ``CombinatorialClass`` +- Trevor K. Karn (2022-09-13): Make ``Composition`` a ``collections.abc.Sequence`` """ # **************************************************************************** # Copyright (C) 2007 Mike Hansen @@ -30,6 +31,7 @@ # **************************************************************************** from __future__ import annotations from itertools import accumulate +from collections.abc import Sequence from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -109,6 +111,12 @@ class Composition(CombinatorialElement): sage: Composition(descents=({0,1,3},5)) [1, 1, 2, 1] + Check :trac:`34527`:: + + sage: from collections.abc import Sequence + sage: isinstance(Composition([3,2,3]), Sequence) + True + EXAMPLES:: sage: C = Composition([3,1,2]) @@ -1350,6 +1358,7 @@ def wll_gt(self, co2) -> bool: return False return False +Sequence.register(Composition) ############################################################## From 819d3d3863491de3c29056792261ae3e892f6068 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 14 Sep 2022 13:20:30 +0900 Subject: [PATCH 591/742] Move implementation comment to code block --- src/sage/arith/misc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 524fd2e0dfa..eaded5d7532 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -3229,9 +3229,6 @@ def CRT_list(values, moduli): ``moduli``, find a single element that reduces to each element of ``values`` modulo the corresponding moduli. - The result is computed using a binary tree. In typical cases, - this scales much better than folding the list from one side. - .. SEEALSO:: - :func:`crt` @@ -3310,6 +3307,9 @@ def CRT_list(values, moduli): raise ValueError("arguments to CRT_list should be lists of the same length") if not values: return ZZ.zero() + + # The result is computed using a binary tree. In typical cases, + # this scales much better than folding the list from one side. from sage.arith.functions import lcm while len(values) > 1: vs, ms = values[::2], moduli[::2] From a338ac024d2da4733721059b767a272445921962 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Wed, 14 Sep 2022 08:53:02 +0200 Subject: [PATCH 592/742] trac #34529: remove deprecated method spring_layout_fast_split --- src/sage/graphs/generic_graph_pyx.pyx | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index a2f98dd755c..022c02c3b06 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -120,30 +120,6 @@ def layout_split(layout_function, G, **options): return pos -def spring_layout_fast_split(G, **options): - """ - Graph each component of ``G`` separately, placing them adjacent to each - other. - - In ticket :trac:`29522` the function was modified so that it can - work with any layout method and renamed ``layout_split``. - Please use :func:`layout_split` from now on. - - TESTS:: - - sage: from sage.graphs.generic_graph_pyx import spring_layout_fast_split - sage: G = Graph(4) - sage: _ = spring_layout_fast_split(G) - doctest:...: DeprecationWarning: spring_layout_fast_split is deprecated, please use layout_split instead - See https://trac.sagemath.org/29522 for details. - - """ - from sage.misc.superseded import deprecation - deprecation(29522, ('spring_layout_fast_split is deprecated, please use ' - 'layout_split instead'), stacklevel=3) - return layout_split(spring_layout_fast, G, **options) - - def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True, bint height=False, by_component=False, **options): """ From 0cb07dfcc3c067278dc1cf3f4a867e51df42d7e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 14 Sep 2022 12:23:23 +0200 Subject: [PATCH 593/742] some details in LS paths crystal --- src/sage/combinat/crystals/littelmann_path.py | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/crystals/littelmann_path.py b/src/sage/combinat/crystals/littelmann_path.py index 9eb8ecd6dcd..49f9bef352e 100644 --- a/src/sage/combinat/crystals/littelmann_path.py +++ b/src/sage/combinat/crystals/littelmann_path.py @@ -9,7 +9,7 @@ - Travis Scrimshaw (2016): Implemented :class:`~sage.combinat.crystals.littelmann_path.InfinityCrystalOfLSPaths` """ -#**************************************************************************** +# *************************************************************************** # Copyright (C) 2012 Mark Shimozono # Anne Schilling # @@ -22,8 +22,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#**************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** from sage.misc.cachefunc import cached_in_parent_method, cached_method from sage.structure.unique_representation import UniqueRepresentation @@ -147,10 +147,7 @@ def __classcall_private__(cls, starting_weight, cartan_type = None, starting_wei """ if cartan_type is not None: cartan_type, starting_weight = CartanType(starting_weight), cartan_type - if cartan_type.is_affine(): - extended = True - else: - extended = False + extended = cartan_type.is_affine() R = RootSystem(cartan_type) P = R.weight_space(extended = extended) @@ -333,7 +330,7 @@ def split_step(self, which_step, r): sage: b.split_step(0,1/3) (1/3*Lambda[1] + 1/3*Lambda[2], 2/3*Lambda[1] + 2/3*Lambda[2]) """ - assert 0 <= which_step and which_step <= len(self.value) + assert 0 <= which_step <= len(self.value) v = self.value[which_step] return self.parent()(self.value[:which_step] + (r*v,(1-r)*v) + self.value[which_step+1:]) @@ -476,7 +473,7 @@ def e(self, i, power=1, to_string_end=False, length_only=False): ix = len(data)-1 while ix >= 0 and data[ix][1] < M + p: - # get the index of the current step to be processed + # get the index of the current step to be processed j = data[ix][0] # find the i-height where the current step might need to be split if ix == 0: @@ -621,7 +618,7 @@ def _latex_(self): ##################################################################### -## Projected level-zero +# Projected level-zero class CrystalOfProjectedLevelZeroLSPaths(CrystalOfLSPaths): @@ -1143,7 +1140,9 @@ def energy_function(self): Wd = WeylGroup(cartan_dual, prefix='s', implementation="permutation") G = Wd.quantum_bruhat_graph(J) Qd = RootSystem(cartan_dual).root_lattice() - dualize = lambda x: Qv.from_vector(x.to_vector()) + + def dualize(x): + return Qv.from_vector(x.to_vector()) L = [Wd.from_reduced_word(x.reduced_word()) for x in L] def stretch_short_root(a): @@ -1176,7 +1175,7 @@ def stretch_short_root(a): ##################################################################### -## B(\infty) +# B(\infty) class InfinityCrystalOfLSPaths(UniqueRepresentation, Parent): @@ -1463,7 +1462,7 @@ def phi(self,i): ##################################################################### -## Helper functions +# Helper functions def positively_parallel_weights(v, w): From 99446784265889212b137e55e7a6d1adc3e82d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 14 Sep 2022 14:38:02 +0200 Subject: [PATCH 594/742] modernize super in manifolds --- src/sage/manifolds/catalog.py | 2 +- .../differentiable/examples/euclidean.py | 2 +- .../differentiable/examples/real_line.py | 22 ++++++------ .../differentiable/examples/sphere.py | 16 ++++----- .../manifolds/differentiable/vectorframe.py | 28 +++++++-------- src/sage/manifolds/local_frame.py | 35 ++++++++++--------- src/sage/manifolds/utilities.py | 5 +-- 7 files changed, 56 insertions(+), 54 deletions(-) diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index 4e10184fd3e..62fc5710d6f 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -29,7 +29,7 @@ # 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/ # ***************************************************************************** # Lazy import from examples folders: diff --git a/src/sage/manifolds/differentiable/examples/euclidean.py b/src/sage/manifolds/differentiable/examples/euclidean.py index 8b3cb23531d..9528d5a5f8a 100644 --- a/src/sage/manifolds/differentiable/examples/euclidean.py +++ b/src/sage/manifolds/differentiable/examples/euclidean.py @@ -717,7 +717,7 @@ def __classcall_private__(cls, n=None, name=None, latex_name=None, start_index=start_index, unique_tag=unique_tag) - return super(cls, EuclideanSpace).__classcall__(cls, + return super().__classcall__(cls, n, name=name, latex_name=latex_name, coordinates=coordinates, symbols=symbols, metric_name=metric_name, diff --git a/src/sage/manifolds/differentiable/examples/real_line.py b/src/sage/manifolds/differentiable/examples/real_line.py index 35636dc0bd7..10a44c7e149 100644 --- a/src/sage/manifolds/differentiable/examples/real_line.py +++ b/src/sage/manifolds/differentiable/examples/real_line.py @@ -320,10 +320,10 @@ def __classcall_private__(cls, lower, upper, ambient_interval=None, coordinate = None names = None start_index = 0 - return super(cls, OpenInterval).__classcall__(cls, lower, upper, - ambient_interval=ambient_interval, name=name, - latex_name=latex_name, coordinate=coordinate, - names=names, start_index=start_index) + return super().__classcall__(cls, lower, upper, + ambient_interval=ambient_interval, name=name, + latex_name=latex_name, coordinate=coordinate, + names=names, start_index=start_index) def __init__(self, lower, upper, ambient_interval=None, name=None, latex_name=None, @@ -495,9 +495,9 @@ def _element_constructor_(self, coords=None, chart=None, name=None, """ if coords in SR: coords = (coords,) - return super(OpenInterval, self)._element_constructor_(coords=coords, - chart=chart, name=name, latex_name=latex_name, - check_coords=check_coords) + return super()._element_constructor_(coords=coords, + chart=chart, name=name, latex_name=latex_name, + check_coords=check_coords) def _Hom_(self, other, category=None): r""" @@ -879,10 +879,10 @@ def __classcall__(cls, name=unicode_mathbbR, latex_name=r'\Bold{R}', True """ - return super(cls, RealLine).__classcall__(cls, name=name, - latex_name=latex_name, - coordinate=coordinate, - names=names, start_index=start_index) + return super().__classcall__(cls, name=name, + latex_name=latex_name, + coordinate=coordinate, + names=names, start_index=start_index) def __init__(self, name=unicode_mathbbR, latex_name=r'\Bold{R}', coordinate=None, names=None, start_index=0): diff --git a/src/sage/manifolds/differentiable/examples/sphere.py b/src/sage/manifolds/differentiable/examples/sphere.py index 1183448251a..4ccc6f7440b 100644 --- a/src/sage/manifolds/differentiable/examples/sphere.py +++ b/src/sage/manifolds/differentiable/examples/sphere.py @@ -320,14 +320,14 @@ def __classcall_private__(cls, n=None, radius=1, ambient_space=None, from sage.misc.prandom import getrandbits from time import time if unique_tag is None: - unique_tag = getrandbits(128)*time() - - return super(cls, Sphere).__classcall__(cls, n, radius=radius, - ambient_space=ambient_space, - center=center, - name=name, latex_name=latex_name, - coordinates=coordinates, names=names, - unique_tag=unique_tag) + unique_tag = getrandbits(128) * time() + + return super().__classcall__(cls, n, radius=radius, + ambient_space=ambient_space, + center=center, + name=name, latex_name=latex_name, + coordinates=coordinates, names=names, + unique_tag=unique_tag) def __init__(self, n, radius=1, ambient_space=None, center=None, name=None, latex_name=None, coordinates='spherical', names=None, diff --git a/src/sage/manifolds/differentiable/vectorframe.py b/src/sage/manifolds/differentiable/vectorframe.py index 6df9c54c0d1..8f8c26c0c61 100644 --- a/src/sage/manifolds/differentiable/vectorframe.py +++ b/src/sage/manifolds/differentiable/vectorframe.py @@ -452,10 +452,10 @@ def set_name(self, symbol, latex_symbol=None, indices=None, \left(M, \left(e^{\xi},e^{\zeta}\right)\right) """ - super(CoFrame, self).set_name(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - index_position=index_position) + super().set_name(symbol, latex_symbol=latex_symbol, + indices=indices, + latex_indices=latex_indices, + index_position=index_position) if include_domain: # Redefinition of the name and the LaTeX name to include the domain self._name = "({}, {})".format(self._domain._name, self._name) @@ -672,12 +672,12 @@ def __classcall_private__(cls, vector_field_module, symbol, symbol_dual = tuple(symbol_dual) if isinstance(latex_symbol_dual, list): latex_symbol_dual = tuple(latex_symbol_dual) - return super(VectorFrame, cls).__classcall__(cls, vector_field_module, - symbol, latex_symbol=latex_symbol, - from_frame=from_frame, indices=indices, - latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + return super().__classcall__(cls, vector_field_module, + symbol, latex_symbol=latex_symbol, + from_frame=from_frame, indices=indices, + latex_indices=latex_indices, + symbol_dual=symbol_dual, + latex_symbol_dual=latex_symbol_dual) def __init__(self, vector_field_module, symbol, latex_symbol=None, from_frame=None, indices=None, latex_indices=None, @@ -1570,10 +1570,10 @@ def set_name(self, symbol, latex_symbol=None, indices=None, \left(M, \left(E_{\alpha},E_{\beta}\right)\right) """ - super(VectorFrame, self).set_name(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - index_position=index_position) + super().set_name(symbol, latex_symbol=latex_symbol, + indices=indices, + latex_indices=latex_indices, + index_position=index_position) if include_domain: # Redefinition of the name and the LaTeX name to include the domain self._name = "({}, {})".format(self._domain._name, self._name) diff --git a/src/sage/manifolds/local_frame.py b/src/sage/manifolds/local_frame.py index 4d7db5c7d55..fffe607efda 100644 --- a/src/sage/manifolds/local_frame.py +++ b/src/sage/manifolds/local_frame.py @@ -162,20 +162,21 @@ """ -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2013-2018 Eric Gourgoulhon # Copyright (C) 2019 Michael Jung # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.tensor.modules.free_module_basis import (FreeModuleBasis, FreeModuleCoBasis) from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule + class LocalCoFrame(FreeModuleCoBasis): r""" Local coframe on a vector bundle. @@ -398,10 +399,10 @@ def set_name(self, symbol, latex_symbol=None, indices=None, \left(E|_{M}, \left(e^{\xi},e^{\zeta}\right)\right) """ - super(LocalCoFrame, self).set_name(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - index_position=index_position) + super().set_name(symbol, latex_symbol=latex_symbol, + indices=indices, + latex_indices=latex_indices, + index_position=index_position) if include_domain: # Redefinition of the name and the LaTeX name to include the domain self._name = "({}|_{}, {})".format(self._vbundle._name, @@ -597,12 +598,12 @@ def __classcall_private__(cls, section_module, symbol, symbol_dual = tuple(symbol_dual) if isinstance(latex_symbol_dual, list): latex_symbol_dual = tuple(latex_symbol_dual) - return super(LocalFrame, cls).__classcall__(cls, section_module, - symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + return super().__classcall__(cls, section_module, + symbol, latex_symbol=latex_symbol, + indices=indices, + latex_indices=latex_indices, + symbol_dual=symbol_dual, + latex_symbol_dual=latex_symbol_dual) def __init__(self, section_module, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): @@ -1239,10 +1240,10 @@ def set_name(self, symbol, latex_symbol=None, indices=None, \left(E|_{M}, \left(E_{\alpha},E_{\beta}\right)\right) """ - super(LocalFrame, self).set_name(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - index_position=index_position) + super().set_name(symbol, latex_symbol=latex_symbol, + indices=indices, + latex_indices=latex_indices, + index_position=index_position) if include_domain: # Redefinition of the name and the LaTeX name to include the domain self._name = "({}|_{}, {})".format(self._vbundle._name, diff --git a/src/sage/manifolds/utilities.py b/src/sage/manifolds/utilities.py index 75a07519b0d..de83d63326f 100644 --- a/src/sage/manifolds/utilities.py +++ b/src/sage/manifolds/utilities.py @@ -204,7 +204,8 @@ def arithmetic(self, ex, operator): simpl = SR(1)/simpl return simpl # If operator is not a square root, we default to ExpressionTreeWalker: - return super(SimplifySqrtReal, self).arithmetic(ex, operator) + return super().arithmetic(ex, operator) + class SimplifyAbsTrig(ExpressionTreeWalker): r""" @@ -340,7 +341,7 @@ def composition(self, ex, operator): ex = -cos(x) return ex # If no pattern is found, we default to ExpressionTreeWalker: - return super(SimplifyAbsTrig, self).composition(ex, operator) + return super().composition(ex, operator) def simplify_sqrt_real(expr): From 67c914c6079204194708ff1188871724ca81adb9 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Wed, 14 Sep 2022 13:25:59 -0700 Subject: [PATCH 595/742] trac 34533: silence warning during doctesting about "chained fixups" --- src/sage/doctest/parsing.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 064414befbc..1752caa851a 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -43,6 +43,8 @@ ld_warning_regex = re.compile(r'^.*dylib.*was built for newer macOS version.*than being linked.*') # :trac:`30845` -- suppress warning on conda about ld ld_pie_warning_regex = re.compile(r'ld: warning: -pie being ignored. It is only used when linking a main executable') +# :trac:`34533` -- suppress warning on OS X 12.6 about chained fixups +chained_fixup_warning_regex = re.compile(r'ld: warning: -undefined dynamic_lookup may not work with chained fixups') sympow_cache_warning_regex = re.compile(r'\*\*WARNING\*\* /var/cache/sympow/datafiles/le64 yields insufficient permissions') find_sage_prompt = re.compile(r"^(\s*)sage: ", re.M) find_sage_continuation = re.compile(r"^(\s*)\.\.\.\.:", re.M) @@ -117,6 +119,9 @@ def fake_RIFtol(*args): (lambda g, w: "Long-step" in g, lambda g, w: (glpk_simplex_warning_regex.sub('', g), w)), + (lambda g, w: "chained fixups" in g, + lambda g, w: (chained_fixup_warning_regex.sub('', g), w)), + (lambda g, w: "insufficient permissions" in g, lambda g, w: (sympow_cache_warning_regex.sub('', g), w)), From 6ceb44edbd932b7c772d3844c74103e2e3d6732c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 14 Sep 2022 15:15:25 -0700 Subject: [PATCH 596/742] build/pkgs/auditwheel_or_delocate/SPKG.rst: Explain that we use delocate also on Linux --- build/pkgs/auditwheel_or_delocate/SPKG.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/build/pkgs/auditwheel_or_delocate/SPKG.rst b/build/pkgs/auditwheel_or_delocate/SPKG.rst index 845a8da1c24..710ea0224e0 100644 --- a/build/pkgs/auditwheel_or_delocate/SPKG.rst +++ b/build/pkgs/auditwheel_or_delocate/SPKG.rst @@ -4,8 +4,11 @@ auditwheel_or_delocate: Repair wheels on Linux or macOS Description ----------- -This package represents auditwheel on Linux -and delocate on macOS. +This package represents ``auditwheel`` on Linux and ``delocate`` on macOS. + +(Actually, we install ``delocate`` also on Linux because our script +``make -j list-broken-packages`` uses a small subroutine of ``delocate`` +even on Linux.) License ------- From 3c70a38483a15327118ccfcaeabf154e5d9f2af1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 14 Sep 2022 15:24:01 -0700 Subject: [PATCH 597/742] build/sage_bootstrap/installcheck.py: Update comment on stamp files --- build/sage_bootstrap/installcheck.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build/sage_bootstrap/installcheck.py b/build/sage_bootstrap/installcheck.py index a02db3c74fd..1448ccdcbc9 100644 --- a/build/sage_bootstrap/installcheck.py +++ b/build/sage_bootstrap/installcheck.py @@ -51,8 +51,7 @@ def installcheck(spkg_name, sage_local, verbose=False): spkg_inst = pth.join(sage_local, 'var', 'lib', 'sage', 'installed') # Find all stamp files for the package; there should be only one, but if - # there is somehow more than one we'll work with the most recent and delete - # the rest + # there is somehow more than one we'll work with the most recent one. pattern = pth.join(spkg_inst, '{0}-*'.format(spkg_name)) stamp_files = sorted(glob.glob(pattern), key=pth.getmtime) From bd5424046c252a9b231d3f10a4c3998b2ec83bbd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 14 Sep 2022 15:33:19 -0700 Subject: [PATCH 598/742] src/doc/en/installation/source.rst: Move gcc/gfortran details into SPKG.rst --- README.md | 2 +- build/pkgs/gcc/SPKG.rst | 42 +++++++++++- build/pkgs/gfortran/SPKG.rst | 24 ++++++- src/doc/en/installation/source.rst | 106 +---------------------------- 4 files changed, 64 insertions(+), 110 deletions(-) diff --git a/README.md b/README.md index 7a21328c9a4..a06f57e5771 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ If your Mac uses the Apple Silicon (M1, arm64) architecture: https://brew.sh/ required because it provides a version of ``gfortran`` with necessary changes for this platform that are not in a released upstream version of GCC. (The ``gfortran`` package that comes with the Sage - distribution is not suitable for the M1.) + distribution is not suitable for the M1/M2.) If your Mac uses the Intel (x86_64) architecture: diff --git a/build/pkgs/gcc/SPKG.rst b/build/pkgs/gcc/SPKG.rst index 1f5684b86b2..87a056f83d5 100644 --- a/build/pkgs/gcc/SPKG.rst +++ b/build/pkgs/gcc/SPKG.rst @@ -1,10 +1,46 @@ -gcc: The GNU Compiler Collection, including the C, C++ and Fortran compiler -=========================================================================== +gcc: The GNU Compiler Collection or other suitable C and C++ compilers +====================================================================== Description ----------- -The GNU Compiler Collection, including the C, C++ and Fortran compiler. +This package represents the required C and C++ compilers. + +- GCC (GNU Compiler Collection) versions 8.x to 12.x are supported. + +- Clang (LLVM) is also supported. + +The required Fortran compiler is represented by the package ``gfortran``. + +You can pass the names of compilers to use to ``./configure`` using +the environment variables :envvar:`CC`, :envvar:`CXX`, and +:envvar:`FC`, for C, C++, and Fortran compilers, respectively. + +For example, if your C compiler is ``clang``, your C++ compiler is +``clang++``, and your Fortran compiler is ``flang``, then you would +need to run:: + + $ ./configure CC=clang CXX=clang++ FC=flang + +Vendor and versions of the C and C++ compilers should match. + +This package uses the non-standard default +``configure --with-system-gcc=force``, giving an error at ``configure`` +time when no suitable system compilers are configured. + +You can override this using ``./configure --without-system-gcc``. In +this case, Sage builds and installs the GNU Compiler Collection, +including the C, C++ and Fortran compiler. This is not recommended. +You will need suitable C and C++ compilers from which GCC can +bootstrap itself. There are some known problems with old assemblers, +in particular when building the ``ecm`` and ``fflas_ffpack`` +packages. You should ensure that your assembler understands all +instructions for your processor. On Linux, this means you need a +recent version of ``binutils`` (not provided by an SPKG); on macOS +you need a recent version of Xcode. + +(Installing the +``gfortran`` SPKG becomes a no-op in this case.) License ------- diff --git a/build/pkgs/gfortran/SPKG.rst b/build/pkgs/gfortran/SPKG.rst index 1bea5fae5fe..83d2d0bb92a 100644 --- a/build/pkgs/gfortran/SPKG.rst +++ b/build/pkgs/gfortran/SPKG.rst @@ -4,8 +4,28 @@ gfortran: Fortran compiler from the GNU Compiler Collection Description ----------- -The GNU Compiler Collection, including the C, C++ and Fortran compiler. -This particular package is meant to only make gfortran available. +This package represents the required Fortran compiler. + +Officially we support ``gfortran`` from `GNU Compiler Collection (GCC) +`_. It has also been reported that using ``flang`` +(from LLVM) might work. + +You can pass the names of compilers to use to ``./configure`` using +the environment variables :envvar:`CC`, :envvar:`CXX`, and +:envvar:`FC`, for C, C++, and Fortran compilers, respectively. + +For example, if your C compiler is ``clang``, your C++ compiler is +``clang++``, and your Fortran compiler is ``flang``, then you would +need to run:: + + $ ./configure CC=clang CXX=clang++ FC=flang + +Building Sage from source on Apple Silicon (M1/M2) requires the use of +​the `Homebrew package manager `_ (recommended) or +conda-forge, which package versions of GCC 12.x (including +``gfortran``) with the necessary changes for this platform. These +changes are not in a released upstream version of GCC, and hence +also the ``gfortran`` SPKG is not suitable for the M1/M2. License ------- diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index ca362d68d3e..8ef0c56cae0 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -59,9 +59,6 @@ and the :wikipedia:`bash ` shell, the following standard command-line development tools must be installed on your computer: -- A **C/C++ compiler**: GCC versions 8.x to 12.x are supported. - Clang (LLVM) is also supported. - See also `Using alternative compilers`_. - **make**: GNU make, version 3.80 or later. Version 3.82 or later is recommended. - **m4**: GNU m4 1.4.2 or later (non-GNU or older versions might also work). - **perl**: version 5.8.0 or later. @@ -74,54 +71,6 @@ computer: Other versions of these may work, but they are untested. -Fortran and compiler suites -########################### - -Sage installation also needs a Fortran compiler. It is determined -automatically whether Sage's GCC package, or just its part containing -Fortran compiler ``gfortran`` needs to be installed. This can be -overwritten by running ``./configure`` with option -``--without-system-gcc``. - -Officially we support -gfortran from `GNU Compiler Collection (GCC) `_. -If C and C++ compilers also come from there (i.e., gcc and g++), their versions -should match. -Alternatively, one may use C and C++ compilers from -`Clang: a C language family frontend for LLVM `_, -and thus matching versions of -clang, clang++ , along with a recent gfortran. (Flang (or other LLVM-based -Fortran compilers) are not officially supported, however it is possible to -to build Sage using flang, with some extra efforts needed to set various flags; -this is work in progress at the moment (May 2019)). - -Therefore, if you plan on using your own GCC compilers, then make sure that -their versions match. - -To force using specific compilers, set environment variables ``CC``, -``CXX``, and ``FC`` (for C, C++, and Fortran compilers, respectively) -to the desired values, and run ``./configure``. For example, -``./configure CC=clang CXX=clang++ FC=gfortran`` will configure Sage -to be built with Clang C/C++ compilers and Fortran compiler -``gfortran``. - -Alternatively, Sage includes a GCC package, so that C, C++ and Fortran -compilers will be built when the build system detects that it is needed, -e.g., non-GCC compilers, or -versions of the GCC compilers known to miscompile some components of Sage, -or simply a missing Fortran compiler. -In any case, you always need at least a C/C++ compiler to build the GCC -package and its prerequisites before the compilers it provides can be used. - -Note that you can always override this behavior through the configure -options ``--without-system-gcc`` and ``--with-system-gcc``, see -:ref:`section_compilers`. - -There are some known problems with old assemblers, in particular when -building the ``ecm`` and ``fflas_ffpack`` packages. You should ensure -that your assembler understands all instructions for your -processor. On Linux, this means you need a recent version of -``binutils``; on macOS you need a recent version of Xcode. Python for venv ^^^^^^^^^^^^^^^ @@ -316,21 +265,8 @@ a registration. macOS recommended installation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Although Sage can in theory build its own version of gfortran, this -can take a while, and the process fails on some recent versions of -OS X. So instead you can install your own copy. One advantage of this -is that you can install it once, and it will get used every time you -build Sage, rather than building gfortran every time. - -One way to do that is with the `Homebrew package manager -`_. Install Homebrew as their web page describes, and -then the command :: - - $ brew install gcc - -will install Homebrew's gcc package, which includes gfortran. Sage -will also use other Homebrew packages, if they are present. You can -install the following: +If you use the `Homebrew package manager +`_, you can install the following: .. literalinclude:: homebrew.txt @@ -553,44 +489,6 @@ Specific notes for ``make`` and ``tar`` On macOS, the system-wide BSD ``tar`` supplied will build Sage, so there is no need to install the GNU ``tar``. -.. _section_compilers: - -Using alternative compilers -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Sage developers tend to use fairly recent versions of GCC. -Nonetheless, the Sage build process on Linux -should succeed with any reasonable C/C++ compiler; -(we do not recommend GCC older than version 5.1). -This is because Sage will build GCC first (if needed) and then use that newly -built GCC to compile Sage. - -If you don't want this and want to try building Sage with a different set of -compilers, -you need to pass Sage's ``./configure`` compiler names, via environment -variables ``CC``, ``CXX``, and ``FC``, for C, C++, and Fortran compilers, -respectively, e.g. if you C compiler is ``clang``, your C++ compiler is ``clang++``, -and your Fortran compiler is ``flang`` then you would need to run:: - - $ CC=clang CXX=clang++ FC=flang ./configure - -before running ``make``. It is recommended that you inspect the output of ``./configure`` -in order to check that Sage will not try to build GCC. Namely, there should be lines like:: - - gcc-7.2.0 will not be installed (configure check) - ... - gfortran-7.2.0 will not be installed (configure check) - -indicating that Sage will not attempt to build ``gcc/g++/gfortran``. - -If you are interested in working on support for commercial compilers from -`HP `_, -`IBM `_, -`Intel `_, -`Sun/Oracle `_, -etc, -please email the sage-devel mailing list at https://groups.google.com/group/sage-devel. - Additional software ------------------- From eeaa4aa3754af787dc93b343bf2120b2a49a1a7a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 14 Sep 2022 17:22:55 -0700 Subject: [PATCH 599/742] src/doc/en/installation/source.rst: Move _prereq details into SPKG.rst --- build/pkgs/_prereq/SPKG.rst | 33 +++++++++++++++++++++++++++- src/doc/en/installation/source.rst | 35 +----------------------------- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/build/pkgs/_prereq/SPKG.rst b/build/pkgs/_prereq/SPKG.rst index a798c656ed0..279ace25843 100644 --- a/build/pkgs/_prereq/SPKG.rst +++ b/build/pkgs/_prereq/SPKG.rst @@ -4,5 +4,36 @@ _prereq: Represents system packages required for installing SageMath from source Description ----------- -This script package represents the minimal requirements (system packages) +This dummy package represents the minimal requirements (system packages) for installing SageMath from source. + +In addition to standard :wikipedia:`POSIX ` utilities +and the :wikipedia:`bash ` shell, +the following standard command-line development tools must be installed on your +computer: + +- **make**: GNU make, version 3.80 or later. Version 3.82 or later is recommended. +- **m4**: GNU m4 1.4.2 or later (non-GNU or older versions might also work). +- **perl**: version 5.8.0 or later. +- **ar** and **ranlib**: can be obtained as part of GNU binutils. +- **tar**: GNU tar version 1.17 or later, or BSD tar (as provided on macOS). +- **python**: Python 3.4 or later, or Python 2.7. + (This range of versions is a minimal requirement for internal purposes of the SageMath + build system, which is referred to as ``sage-bootstrap-python``.) + +Other versions of these may work, but they are untested. + +On macOS, suitable versions of all of these tools are provided either +by the Xcode Command Line Tools. To install them, open a terminal +window and run ``xcode-select --install``; then click "Install" in the +pop-up window. If the Xcode Command Line Tools are already installed, +you may want to check if they need to be updated by typing +``softwareupdate -l``. + +On Linux, ``ar`` and ``ranlib`` are in the `binutils +`_ package. The other +programs are usually located in packages with their respective names. + +On Redhat-derived systems not all perl components are installed by +default and you might have to install the ``perl-ExtUtils-MakeMaker`` +package. diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index 8ef0c56cae0..9d827e9ee06 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -51,27 +51,6 @@ Your computer comes with at least 6 GB of free disk space. It is recommended to have at least 2 GB of RAM, but you might get away with less (be sure to have some swap space in this case). -Command-line tools -^^^^^^^^^^^^^^^^^^ - -In addition to standard :wikipedia:`POSIX ` utilities -and the :wikipedia:`bash ` shell, -the following standard command-line development tools must be installed on your -computer: - -- **make**: GNU make, version 3.80 or later. Version 3.82 or later is recommended. -- **m4**: GNU m4 1.4.2 or later (non-GNU or older versions might also work). -- **perl**: version 5.8.0 or later. -- **ar** and **ranlib**: can be obtained as part of GNU binutils. -- **tar**: GNU tar version 1.17 or later, or BSD tar. -- **python**: Python 3.4 or later, or Python 2.7. - (This range of versions is a minimal requirement for internal purposes of the SageMath - build system, which is referred to as ``sage-bootstrap-python``.) - -Other versions of these may work, but they are untested. - - - Python for venv ^^^^^^^^^^^^^^^ @@ -113,13 +92,7 @@ On macOS, there are various developer tools needed which may require some registration on Apple's developer site; see :ref:`section_macprereqs`. -On Redhat-derived systems not all perl components are installed by -default and you might have to install the ``perl-ExtUtils-MakeMaker`` -package. - -On Linux systems (e.g., Ubuntu, Redhat, etc), ``ar`` and ``ranlib`` are in the -`binutils `_ package. -The other programs are usually located in packages with their respective names. +On Linux systems (e.g., Ubuntu, Redhat, etc), Assuming you have sufficient privileges, you can install the ``binutils`` and other necessary/standard components. The lists provided below are longer than the minimal prerequisites, which are basically ``binutils``, ``gcc``/``clang``, ``make``, @@ -483,12 +456,6 @@ If you don't want conda to be used by sage, deactivate conda (for the current sh Then SageMath will be built either using the compilers provided by the operating system, or its own compilers. -Specific notes for ``make`` and ``tar`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -On macOS, the system-wide BSD ``tar`` supplied will build Sage, so there is no -need to install the GNU ``tar``. - Additional software ------------------- From e74e0b2662607ded26b38b7f64960952ddf139d0 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Wed, 14 Sep 2022 22:22:45 -0500 Subject: [PATCH 600/742] Update doctest --- src/sage/combinat/composition.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index ad401487471..2373f3947d5 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -20,7 +20,6 @@ - Mike Hansen, Nicolas M. Thiéry - MuPAD-Combinat developers (algorithms and design inspiration) - Travis Scrimshaw (2013-02-03): Removed ``CombinatorialClass`` -- Trevor K. Karn (2022-09-13): Make ``Composition`` a ``collections.abc.Sequence`` """ # **************************************************************************** # Copyright (C) 2007 Mike Hansen @@ -113,8 +112,8 @@ class Composition(CombinatorialElement): Check :trac:`34527`:: - sage: from collections.abc import Sequence - sage: isinstance(Composition([3,2,3]), Sequence) + sage: import collections.abc + sage: isinstance(Composition([3,2,3]), collections.abc.Sequence) True EXAMPLES:: From 1f3e2853f1cd98272220cd6f384c58fc7dfadacb Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Wed, 14 Sep 2022 23:51:15 -0500 Subject: [PATCH 601/742] Add _floordiv_ --- .../polynomial/infinite_polynomial_element.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/rings/polynomial/infinite_polynomial_element.py b/src/sage/rings/polynomial/infinite_polynomial_element.py index 659e903ce75..40d1521cf7e 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_element.py +++ b/src/sage/rings/polynomial/infinite_polynomial_element.py @@ -349,6 +349,21 @@ def __call__(self, *args, **kwargs): except Exception: return res + def _floordiv_(self, right): + """ + Implement a floor division by passing to the finite polynomial ring. + + EXAMPLES:: + + sage: R. = InfinitePolynomialRing(QQ) + sage: (z[10]+z[0]) // (z[10] + z[0]) + 1 + sage: z[10] // (z[10] + z[0]) + 0 + """ + R = self.parent()._P + return self.parent()(R(self)._floordiv_(R(right))) + def _getAttributeNames(self): """ This method implements tab completion, see :trac:`6854`. From 27b986acad2252c66ec110b06b7ddd911749892f Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Thu, 15 Sep 2022 00:22:50 -0500 Subject: [PATCH 602/742] More updates to doctest --- src/sage/combinat/composition.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 2373f3947d5..72df25b263c 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -113,8 +113,18 @@ class Composition(CombinatorialElement): Check :trac:`34527`:: sage: import collections.abc - sage: isinstance(Composition([3,2,3]), collections.abc.Sequence) + sage: C = Composition([3,2,3]) + sage: isinstance(C, collections.abc.Sequence) True + sage: issubclass(C.__class__, collections.abc.Sequence) + True + sage: C.count + Traceback (most recent call last): + ... + AttributeError: 'Compositions_all_with_category.element_class' object + has no attribute 'count' + sage: type(reversed(C)) + EXAMPLES:: From c71dc3f2672ec4ab7d0ae7050776afef3a93e9bd Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Thu, 1 Sep 2022 14:49:39 +0800 Subject: [PATCH 603/742] =?UTF-8?q?increase=20minimum=20degree=20for=20?= =?UTF-8?q?=E2=88=9A=C3=A9lu=20formulas=20to=209?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is mainly done to exclude curves over GF(3) with 7 rational points, which cause trouble for √élu as they don't have any points defined only in a quadratic extension of the base field. Hence, the resulting isogeny won't be defined over GF(3). Since √élu is still much slower than Vélu for degrees this small, noone will miss the functionality thus excluded. --- src/sage/schemes/elliptic_curves/hom_velusqrt.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 86ca9e51de0..5b8838514ba 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -756,7 +756,7 @@ class EllipticCurveHom_velusqrt(EllipticCurveHom): INPUT: - ``E`` -- an elliptic curve over a finite field - - ``P`` -- a point on `E` of odd order `\geq 5` + - ``P`` -- a point on `E` of odd order `\geq 9` - ``codomain`` -- codomain elliptic curve (optional) - ``model`` -- string (optional); input to :meth:`~sage.schemes.elliptic_curves.ell_field.compute_model` @@ -884,8 +884,8 @@ def __init__(self, E, P, *, codomain=None, model=None, Q=None): self._P = self._pre_iso(P) self._degree = self._P.order() - if self._degree % 2 != 1 or self._degree < 5: - raise NotImplementedError('only implemented for odd degrees >= 5') + if self._degree % 2 != 1 or self._degree < 9: + raise NotImplementedError('only implemented for odd degrees >= 9') if Q is not None: self._Q = E(Q) @@ -1196,10 +1196,10 @@ def _random_example_for_testing(): True """ from sage.all import prime_range, choice, randrange, GF, gcd - p = choice(prime_range(3, 100)) - e = randrange(1,5) - F,t = GF((p,e),'t').objgen() while True: + p = choice(prime_range(2, 100)) + e = randrange(1,5) + F,t = GF((p,e),'t').objgen() try: E = EllipticCurve([F.random_element() for _ in range(5)]) except ArithmeticError: @@ -1208,11 +1208,11 @@ def _random_example_for_testing(): E.short_weierstrass_model() except ValueError: continue - if E.cardinality() < 5: + if E.cardinality() < 9: continue A = E.abelian_group() ds = max(A.invariants()).prime_to_m_part(2).divisors() - ds = [d for d in ds if 5 <= d < 1000] + ds = [d for d in ds if 9 <= d < 1000] if ds: deg = choice(ds) break From 467eda55e5ff8ea839cb5cdf06915eb0fc482b9a Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Thu, 15 Sep 2022 13:57:43 +0800 Subject: [PATCH 604/742] add failing example --- .../schemes/elliptic_curves/hom_velusqrt.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 5b8838514ba..56d8603fbb6 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -864,6 +864,26 @@ def __init__(self, E, P, *, codomain=None, model=None, Q=None): Elliptic-curve isogeny (using √élu) of degree 105: From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 419 To: Elliptic Curve defined by y^2 = x^3 + 6*x^2 + x over Finite Field of size 419 + + Note that the implementation in fact also works in almost all + cases when the degree is `5` or `7`. The reason we restrict to + degrees `\geq 9` is that (only!) when trying to compute a + `7`-isogeny from a rational point on an elliptic curve defined + over `\GF{3}`, the point `Q` required in the formulas has to be + defined over a cubic extension rather than an at most quadratic + extension, which can result in the constructed isogeny being + irrational. See :trac:`34467`. The assertion in the following + example currently fails if the minimum degree is lowered:: + + sage: E = EllipticCurve(GF(3), [2,1]) + sage: P, = E.gens() + sage: P.order() + 7 + sage: psi = E.isogeny(P) + sage: phi = E.isogeny(P, algorithm='velusqrt') # not tested + sage: phi._Q.base_ring() # not tested + Finite Field in z3 of size 3^3 + sage: assert phi.codomain().is_isomorphic(psi.codomain()) # not tested """ if not isinstance(E, EllipticCurve_finite_field): raise NotImplementedError('only implemented for elliptic curves over finite fields') From 0a10960baf902d883579b97e4ba4fe7823085ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 15 Sep 2022 17:23:57 +0200 Subject: [PATCH 605/742] some details in "argument groups" --- src/sage/groups/misc_gps/argument_groups.py | 30 ++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sage/groups/misc_gps/argument_groups.py b/src/sage/groups/misc_gps/argument_groups.py index a02305df78e..9fa0fe07974 100644 --- a/src/sage/groups/misc_gps/argument_groups.py +++ b/src/sage/groups/misc_gps/argument_groups.py @@ -31,15 +31,15 @@ Classes and Methods =================== """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2018 Daniel Krenn # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.element import MultiplicativeGroupElement from sage.structure.factory import UniqueFactory @@ -48,6 +48,7 @@ from sage.structure.unique_representation import UniqueRepresentation import sage.rings.abc + class AbstractArgument(MultiplicativeGroupElement): r""" An element of :class:`AbstractArgumentGroup`. This abstract class @@ -488,7 +489,7 @@ def _symbolic_(self, R=None): if R is None: R = SR - return exp(2*R('pi')*R('I') * self.exponent) + return exp(2 * R('pi') * R('I') * self.exponent) def _mul_(self, other): r""" @@ -609,7 +610,7 @@ def is_minus_one(self): False """ from sage.rings.rational_field import QQ - return self.exponent == QQ(1)/QQ(2) + return self.exponent == QQ((1, 2)) class UnitCircleGroup(AbstractArgumentGroup): @@ -750,7 +751,7 @@ def _element_constructor_(self, data, exponent=None, **kwds): exponent = 0 elif data == -1 or data == '-1': - exponent = QQ(1)/QQ(2) + exponent = QQ((1, 2)) else: try: @@ -762,7 +763,7 @@ def _element_constructor_(self, data, exponent=None, **kwds): if data.is_one(): exponent = 0 elif data.is_minus_one(): - exponent = QQ(1)/QQ(2) + exponent = QQ((1, 2)) elif isinstance(P, UnitCircleGroup): exponent = data.exponent @@ -961,11 +962,11 @@ def _repr_(self): from sage.rings.rational_field import QQ if self.exponent == 0: return '1' - if self.exponent == QQ(1)/QQ(2): + if self.exponent == QQ((1, 2)): return '-1' - if self.exponent == QQ(1)/QQ(4): + if self.exponent == QQ((1, 4)): return 'I' - if self.exponent == QQ(3)/QQ(4): + if self.exponent == QQ((3, 4)): return '-I' num = self.exponent_numerator() den = self.exponent_denominator() @@ -1008,8 +1009,7 @@ def __classcall__(cls, category=None): Category of commutative groups """ category = cls._determine_category_(category) - return super(AbstractArgumentGroup, cls).__classcall__( - cls, category) + return super(AbstractArgumentGroup, cls).__classcall__(cls, category) def __init__(self, category): r""" @@ -1143,7 +1143,7 @@ def _symbolic_(self, R=None): if R is None: R = SR - return exp(R('I')*arg(self._element_)) + return exp(R('I') * arg(self._element_)) def _mul_(self, other): r""" @@ -1624,9 +1624,9 @@ def __classcall__(cls, category=None): sage: from sage.groups.misc_gps.argument_groups import SignGroup sage: S = SignGroup() sage: S.category() # indirect doctest - Category of commutative groups + Category of finite commutative groups """ - category = cls._determine_category_(category) + category = cls._determine_category_(category).Finite() return super(AbstractArgumentGroup, cls).__classcall__( cls, category) From 1f0a3d0e3b92773526e526aa0257c73f98694b37 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Thu, 15 Sep 2022 13:19:20 -0500 Subject: [PATCH 606/742] Update floordiv --- .../polynomial/infinite_polynomial_element.py | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/sage/rings/polynomial/infinite_polynomial_element.py b/src/sage/rings/polynomial/infinite_polynomial_element.py index 40d1521cf7e..3a88f14b727 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_element.py +++ b/src/sage/rings/polynomial/infinite_polynomial_element.py @@ -349,21 +349,6 @@ def __call__(self, *args, **kwargs): except Exception: return res - def _floordiv_(self, right): - """ - Implement a floor division by passing to the finite polynomial ring. - - EXAMPLES:: - - sage: R. = InfinitePolynomialRing(QQ) - sage: (z[10]+z[0]) // (z[10] + z[0]) - 1 - sage: z[10] // (z[10] + z[0]) - 0 - """ - R = self.parent()._P - return self.parent()(R(self)._floordiv_(R(right))) - def _getAttributeNames(self): """ This method implements tab completion, see :trac:`6854`. @@ -573,6 +558,11 @@ def _add_(self, x): sage: x[1] + x[2] # indirect doctest x_2 + x_1 + Check adding from a different parent:: + + sage: Y. = PolynomialRing(QQ) + sage: x[0] - x_0 + 0 """ # One may need a new parent for self._p and x._p try: @@ -705,6 +695,29 @@ def _div_(self, x): # there remains a problem in reduction return FractionFieldElement(field, self, x, reduce=False) + def _floordiv_(self, x): + """ + EXAMPLES:: + + sage: X. = InfinitePolynomialRing(ZZ) + sage: x[2]//x[2] # indirect doctest + 1 + """ + try: + return InfinitePolynomial_sparse(self.parent(),self._p//x._p) + except Exception: + pass + ## We can now assume that self._p and x._p actually are polynomials, + ## hence, their parent is not just the underlying ring. + VarList = list(set(self._p.parent().variable_names()).union(set(x._p.parent().variable_names()))) + VarList.sort(key=self.parent().varname_key,reverse=True) + if VarList: + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self._p.base_ring(),VarList,order=self.parent()._order) + else: + R = self._p.base_ring() + return InfinitePolynomial_sparse(self.parent(),R(self._p) // R(x._p)) + def _sub_(self, x): """ EXAMPLES:: From cf9b1e69faa1db451c19e47ae8160f641575f395 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 15 Sep 2022 20:56:06 -0700 Subject: [PATCH 607/742] trac 33093: fixes for octave interface - fix failing doctests - do not create file 'octave-workspace' in the current directory --- src/sage/interfaces/octave.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index 4923aec71da..ae1b87c55cb 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -146,6 +146,7 @@ import pexpect from sage.misc.verbose import verbose from sage.misc.instancedoc import instancedoc +from sage.misc.temporary_file import tmp_filename from sage.cpython.string import bytes_to_str @@ -156,13 +157,13 @@ class Octave(Expect): EXAMPLES:: sage: octave.eval("a = [ 1, 1, 2; 3, 5, 8; 13, 21, 33 ]") # optional - octave - 'a =\n\n 1 1 2\n 3 5 8\n 13 21 33\n\n' + 'a =\n\n 1 1 2\n 3 5 8\n 13 21 33\n' sage: octave.eval("b = [ 1; 3; 13]") # optional - octave - 'b =\n\n 1\n 3\n 13\n\n' - sage: octave.eval("c=a \\ b") # solves linear equation: a*c = b # optional - octave; random output - 'c =\n\n 1\n 7.21645e-16\n -7.21645e-16\n\n' + 'b =\n\n 1\n 3\n 13\n' + sage: octave.eval(r"c=a \ b") # solves linear equation: a*c = b # optional - octave; random output + 'c =\n\n 1\n 7.21645e-16\n -7.21645e-16\n' sage: octave.eval("c") # optional - octave; random output - 'c =\n\n 1\n 7.21645e-16\n -7.21645e-16\n\n' + 'c =\n\n 1\n 7.21645e-16\n -7.21645e-16\n' TESTS: @@ -186,12 +187,14 @@ def __init__(self, maxread=None, script_subdirectory=None, logfile=None, command = os.getenv('SAGE_OCTAVE_COMMAND') or 'octave-cli' if server is None: server = os.getenv('SAGE_OCTAVE_SERVER') or None + # Use a temporary workspace file. + workspace_file = tmp_filename() Expect.__init__(self, name='octave', # We want the prompt sequence to be unique to avoid confusion with syntax error messages containing >>> prompt=r'octave\:\d+> ', # We don't want any pagination of output - command=command + " --no-line-editing --silent --eval 'PS2(PS1());more off' --persist", + command=command + f" --no-line-editing --silent --eval 'PS2(PS1());more off; octave_core_file_name (\"{workspace_file}\")' --persist", maxread=maxread, server=server, server_tmpdir=server_tmpdir, @@ -510,9 +513,9 @@ def solve_linear_system(self, A, b): sb = self.sage2octave_matrix_string(b) self.eval("a = " + sA ) self.eval("b = " + sb ) - soln = octave.eval("c = a \\ b") + soln = octave.eval(r"c = a \ b") soln = soln.replace("\n\n ","[") - soln = soln.replace("\n\n","]") + soln = soln.rstrip() + "]" soln = soln.replace("\n",",") sol = soln[3:] return eval(sol) From d5565cf9042197e380bcc4b8ac3fca73750b385b Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Tue, 13 Sep 2022 19:00:53 +0200 Subject: [PATCH 608/742] #34519 msolve: varieties over finite fields --- src/sage/rings/polynomial/msolve.py | 54 ++++++++++++++----- .../polynomial/multi_polynomial_ideal.py | 30 +++++++++-- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index 88f1c6889bb..22b66385369 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -28,6 +28,7 @@ from sage.misc.converting_dict import KeyConvertingDict from sage.misc.sage_eval import sage_eval from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.rational_field import QQ from sage.rings.real_arb import RealBallField from sage.rings.real_double import RealDoubleField_class @@ -44,7 +45,27 @@ def _variety(ideal, ring, proof): TESTS:: - sage: K. = PolynomialRing(QQ, 2, order='lex') + sage: p = 536870909 + sage: R. = PolynomialRing(GF(p), 2, order='lex') + sage: I = Ideal([ x*y - 1, (x-2)^2 + (y-1)^2 - 1]) + + sage: sorted(I.variety(algorithm="msolve", proof=False), key=str) # optional - msolve + [{x: 1, y: 1}, {x: 267525699, y: 473946006}] + + sage: K. = GF(p^2) + sage: sorted(I.variety(K, algorithm="msolve", proof=False), key=str) # optional - msolve + [{x: 1, y: 1}, + {x: 118750849*a + 194048031, y: 510295713*a + 18174854}, + {x: 267525699, y: 473946006}, + {x: 418120060*a + 75297182, y: 26575196*a + 44750050}] + + sage: R. = PolynomialRing(GF(2147483659), 2, order='lex') + sage: ideal([x, y]).variety(algorithm="msolve", proof=False) + Traceback (most recent call last): + ... + NotImplementedError: unsupported base field: Finite Field of size 2147483659 + + sage: R. = PolynomialRing(QQ, 2, order='lex') sage: I = Ideal([ x*y - 1, (x-2)^2 + (y-1)^2 - 1]) sage: I.variety(algorithm='msolve', proof=False) # optional - msolve @@ -98,13 +119,13 @@ def _variety(ideal, ring, proof): ... ValueError: positive-dimensional ideal - sage: K. = PolynomialRing(RR, 2, order='lex') + sage: R. = PolynomialRing(RR, 2, order='lex') sage: Ideal(x, y).variety(algorithm='msolve', proof=False) Traceback (most recent call last): ... NotImplementedError: unsupported base field: Real Field with 53 bits of precision - sage: K. = PolynomialRing(QQ, 2, order='lex') + sage: R. = PolynomialRing(QQ, 2, order='lex') sage: Ideal(x, y).variety(ZZ, algorithm='msolve', proof=False) Traceback (most recent call last): ... @@ -119,11 +140,8 @@ def _variety(ideal, ring, proof): proof = sage.structure.proof.proof.get_flag(proof, "polynomial") if proof: raise ValueError("msolve relies on heuristics; please use proof=False") - # As of msolve 0.2.4, prime fields seem to be supported, by I cannot - # make sense of msolve's output in the positive characteristic case. - # if not (base is QQ or isinstance(base, FiniteField) and - # base.is_prime_field() and base.characteristic() < 2**31): - if base is not QQ: + if not (base is QQ or isinstance(base, FiniteField) and + base.is_prime_field() and base.characteristic() < 2**31): raise NotImplementedError(f"unsupported base field: {base}") if not ring.has_coerce_map_from(base): raise ValueError( @@ -175,24 +193,32 @@ def _variety(ideal, ring, proof): if parameterization: - def to_poly(p, upol=PolynomialRing(base, 't')): - assert len(p[1]) == p[0] + 1 - return upol(p[1]) + def to_poly(p, d=1, *, upol=PolynomialRing(base, 't')): + assert len(p[1]) == p[0] + 1 or p == [-1, [0]] + return upol(p[1])/d try: - [dim1, nvars, _, vars, _, [one, [elim, den, param]]] = data[1] + [char, nvars, deg, vars, _, [one, [elim, den, param]]] = data[1] except (IndexError, ValueError): raise NotImplementedError( f"unsupported msolve output format: {data}") - assert dim1.is_zero() + assert char == base.characteristic() assert one.is_one() assert len(vars) == nvars ringvars = out_ring.variable_names() assert sorted(vars[:len(ringvars)]) == sorted(ringvars) vars = [out_ring(name) for name in vars[:len(ringvars)]] elim = to_poly(elim) + # Criterion suggested by Mohab Safey El Din to avoid cases where there + # is no rational parameterization or where the one returned by msolve + # has a significant probability of being incorrect. + if deg >= char > 0 or 0 < char <= 2**17 and deg != elim.degree(): + raise NotImplementedError(f"characteristic {char} too small") den = to_poly(den) - param = [to_poly(f)/d for [f, d] in param] + # As of msolve 0.4.4, param is of the form [pol, denom] in char 0, but + # [pol] in char p > 0. My understanding is that both cases will + # eventually use the same format, so let's not be too picky. + param = [to_poly(*f) for f in param] elim_roots = elim.roots(ring, multiplicities=False) variety = [] for rt in elim_roots: diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 10c0db501af..64cb6d9ea5a 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2373,9 +2373,6 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True sage: I.variety(ring=AA) [{y: 1, x: 1}, {y: 0.3611030805286474?, x: 2.769292354238632?}] - sage: I.variety(RBF, algorithm='msolve', proof=False) # optional - msolve - [{x: [2.76929235423863 +/- 2.08e-15], y: [0.361103080528647 +/- 4.53e-16]}, - {x: 1.000000000000000, y: 1.000000000000000}] and a total of four intersections:: @@ -2394,6 +2391,13 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True {y: 0.3611030805286474?, x: 2.769292354238632?}, {y: 1, x: 1}] + We can also use the external program msolve to compute the variety. + See :mod:`~sage.rings.polynomial.msolve` for more information. :: + + sage: I.variety(RBF, algorithm='msolve', proof=False) # optional - msolve + [{x: [2.76929235423863 +/- 2.08e-15], y: [0.361103080528647 +/- 4.53e-16]}, + {x: 1.000000000000000, y: 1.000000000000000}] + Computation over floating point numbers may compute only a partial solution, or even none at all. Notice that x values are missing from the following variety:: @@ -2437,6 +2441,26 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True sage: v["y"] -7.464101615137755? + msolve also works over finite fields:: + + sage: R. = PolynomialRing(GF(536870909), 2, order='lex') + sage: I = Ideal([ x^2 - 1, y^2 - 1 ]) + sage: sorted(I.variety(algorithm='msolve', proof=False), key=str) # optional - msolve + [{x: 1, y: 1}, + {x: 1, y: 536870908}, + {x: 536870908, y: 1}, + {x: 536870908, y: 536870908}] + + but may fail in small characteristic, especially with ideals of high + degree with respect to the characteristic:: + + sage: R. = PolynomialRing(GF(3), 2, order='lex') + sage: I = Ideal([ x^2 - 1, y^2 - 1 ]) + sage: I.variety(algorithm='msolve', proof=False) # optional - msolve + Traceback (most recent call last): + ... + NotImplementedError: characteristic 3 too small + ALGORITHM: - With ``algorithm`` = ``"triangular_decomposition"`` (default), From 7b09d5d5aebdc741a6b6575283b5ec03590ce584 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Thu, 15 Sep 2022 13:48:30 +0200 Subject: [PATCH 609/742] #34519 msolve._variety() -> msolve.variety() --- src/sage/rings/polynomial/msolve.py | 2 +- src/sage/rings/polynomial/multi_polynomial_ideal.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index 22b66385369..1ae069572d0 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -36,7 +36,7 @@ from sage.rings.real_mpfi import RealIntervalField_class, RealIntervalField -def _variety(ideal, ring, proof): +def variety(ideal, ring, *, proof=True): r""" Compute the variety of a zero-dimensional ideal using msolve. diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 64cb6d9ea5a..3a49865fd80 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2477,7 +2477,7 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True return self._variety_triangular_decomposition(ring) elif algorithm == "msolve": from . import msolve - return msolve._variety(self, ring, proof) + return msolve.variety(self, ring, proof=proof) else: raise ValueError(f"unknown algorithm {algorithm!r}") From 7db567860e57be5a4bb1ba51eb5fa92dd7e4d07a Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Thu, 15 Sep 2022 19:00:47 +0200 Subject: [PATCH 610/742] #34519 _run_msolve() extract reusable code from msolve.variety() --- src/sage/rings/polynomial/msolve.py | 73 +++++++++++++++++------------ 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index 1ae069572d0..3ed1dd6e29e 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -35,6 +35,40 @@ from sage.rings.real_mpfr import RealField_class from sage.rings.real_mpfi import RealIntervalField_class, RealIntervalField +def _run_msolve(ideal, options): + r""" + Internal utility function + """ + + base = ideal.base_ring() + if not (base is QQ or isinstance(base, FiniteField) and + base.is_prime_field() and base.characteristic() < 2**31): + raise NotImplementedError(f"unsupported base field: {base}") + + # Run msolve + + msolve().require() + + drlpolring = ideal.ring().change_ring(order='degrevlex') + polys = ideal.change_ring(drlpolring).gens() + msolve_in = tempfile.NamedTemporaryFile(mode='w', + encoding='ascii', delete=False) + command = ["msolve", "-f", msolve_in.name] + options + try: + print(",".join(drlpolring.variable_names()), file=msolve_in) + print(base.characteristic(), file=msolve_in) + print(*(pol._repr_().replace(" ", "") for pol in polys), + sep=',\n', file=msolve_in) + msolve_in.close() + msolve_out = subprocess.run(command, capture_output=True, text=True) + finally: + os.unlink(msolve_in.name) + msolve_out.check_returncode() + + return msolve_out.stdout + +def groebner_basis_degrevlex(ideal, *, proof=True): + pass def variety(ideal, ring, *, proof=True): r""" @@ -132,52 +166,31 @@ def variety(ideal, ring, *, proof=True): ValueError: no coercion from base field Rational Field to output ring Integer Ring """ - # Normalize and check input + proof = sage.structure.proof.proof.get_flag(proof, "polynomial") + if proof: + raise ValueError("msolve relies on heuristics; please use proof=False") base = ideal.base_ring() if ring is None: ring = base - proof = sage.structure.proof.proof.get_flag(proof, "polynomial") - if proof: - raise ValueError("msolve relies on heuristics; please use proof=False") - if not (base is QQ or isinstance(base, FiniteField) and - base.is_prime_field() and base.characteristic() < 2**31): - raise NotImplementedError(f"unsupported base field: {base}") if not ring.has_coerce_map_from(base): raise ValueError( f"no coercion from base field {base} to output ring {ring}") - # Run msolve - - msolve().require() - - drlpolring = ideal.ring().change_ring(order='degrevlex') - polys = ideal.change_ring(drlpolring).gens() - msolve_in = tempfile.NamedTemporaryFile(mode='w', - encoding='ascii', delete=False) - command = ["msolve", "-f", msolve_in.name] if isinstance(ring, (RealIntervalField_class, RealBallField, RealField_class, RealDoubleField_class)): parameterization = False - command += ["-p", str(ring.precision())] + options = ["-p", str(ring.precision())] else: parameterization = True - command += ["-P", "1"] - try: - print(",".join(drlpolring.variable_names()), file=msolve_in) - print(base.characteristic(), file=msolve_in) - print(*(pol._repr_().replace(" ", "") for pol in polys), - sep=',\n', file=msolve_in) - msolve_in.close() - msolve_out = subprocess.run(command, capture_output=True, text=True) - finally: - os.unlink(msolve_in.name) - msolve_out.check_returncode() + options = ["-P", "1"] + + msolve_out = _run_msolve(ideal, options) # Interpret output try: - data = sage_eval(msolve_out.stdout[:-2]) + data = sage_eval(msolve_out[:-2]) except SyntaxError: raise NotImplementedError(f"unsupported msolve output format: {data}") @@ -202,7 +215,7 @@ def to_poly(p, d=1, *, upol=PolynomialRing(base, 't')): except (IndexError, ValueError): raise NotImplementedError( f"unsupported msolve output format: {data}") - assert char == base.characteristic() + assert char == ideal.base_ring().characteristic() assert one.is_one() assert len(vars) == nvars ringvars = out_ring.variable_names() From e43bc6ec7c5c9875411abaa054fba0aa6d4c6d1e Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Thu, 15 Sep 2022 19:08:44 +0200 Subject: [PATCH 611/742] =?UTF-8?q?#34519=20Gr=C3=B6bner=20bases=20using?= =?UTF-8?q?=20msolve?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/rings/polynomial/msolve.py | 48 ++++++++++++++++++- .../polynomial/multi_polynomial_ideal.py | 31 +++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index 3ed1dd6e29e..2dafacbba66 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -34,6 +34,7 @@ from sage.rings.real_double import RealDoubleField_class from sage.rings.real_mpfr import RealField_class from sage.rings.real_mpfi import RealIntervalField_class, RealIntervalField +from sage.structure.sequence import Sequence def _run_msolve(ideal, options): r""" @@ -67,8 +68,51 @@ def _run_msolve(ideal, options): return msolve_out.stdout -def groebner_basis_degrevlex(ideal, *, proof=True): - pass +def groebner_basis_degrevlex(ideal): + r""" + Compute a degrevlex Gröbner basis using msolve + + EXAMPLES:: + + sage: from sage.rings.polynomial.msolve import groebner_basis_degrevlex + + sage: R. = PolynomialRing(GF(101), 3, order='lex') + sage: I = sage.rings.ideal.Katsura(R,3) + sage: gb = groebner_basis_degrevlex(I); gb # optional - msolve + [a + 2*b + 2*c - 1, b*c - 19*c^2 + 10*b + 40*c, + b^2 - 41*c^2 + 20*b - 20*c, c^3 + 28*c^2 - 37*b + 13*c] + sage: gb.universe() is R # optional - msolve + False + sage: gb.universe().term_order() # optional - msolve + Degree reverse lexicographic term order + sage: ideal(gb).transformed_basis(other_ring=R) # optional - msolve + [c^4 + 38*c^3 - 6*c^2 - 6*c, 30*c^3 + 32*c^2 + b - 14*c, + a + 2*b + 2*c - 1] + + TESTS:: + + sage: R. = PolynomialRing(GF(536870909), 2) + sage: I = Ideal([ foo^2 - 1, bar^2 - 1 ]) + sage: I.groebner_basis(algorithm='msolve') # optional - msolve + [bar^2 - 1, foo^2 - 1] + + sage: R. = PolynomialRing(QQ, 2) + sage: I = Ideal([ x*y - 1, (x-2)^2 + (y-1)^2 - 1]) + sage: I.groebner_basis(algorithm='msolve') # optional - msolve + Traceback (most recent call last): + ... + NotImplementedError: unsupported base field: Rational Field + """ + + base = ideal.base_ring() + if not (isinstance(base, FiniteField) and base.is_prime_field() and + base.characteristic() < 2**31): + raise NotImplementedError(f"unsupported base field: {base}") + + drlpolring = ideal.ring().change_ring(order='degrevlex') + msolve_out = _run_msolve(ideal, ["-g", "2"]) + gbasis = sage_eval(msolve_out[:-2], locals=drlpolring.gens_dict()) + return Sequence(gbasis) def variety(ideal, ring, *, proof=True): r""" diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 3a49865fd80..caa74226fd3 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -4012,6 +4012,10 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal 'macaulay2:mgb' Macaulay2's ``GroebnerBasis`` command with the strategy "MGB" (if available) + 'msolve' + `msolve `_ (if available, degrevlex order, + prime fields) + 'magma:GroebnerBasis' Magma's ``Groebnerbasis`` command (if available) @@ -4135,6 +4139,15 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal sage: I.groebner_basis('macaulay2:mgb') # optional - macaulay2 [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] + Over prime fields of small characteristic, we can also use + `msolve `_ (if available in the system program + search path):: + + sage: R. = PolynomialRing(GF(101), 3) + sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching + sage: I.groebner_basis('msolve') # optional - msolve + [a + 2*b + 2*c - 1, b*c - 19*c^2 + 10*b + 40*c, b^2 - 41*c^2 + 20*b - 20*c, c^3 + 28*c^2 - 37*b + 13*c] + :: sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching @@ -4353,6 +4366,15 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: I.groebner_basis('magma:GroebnerBasis') # optional - magma [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] + + msolve currently supports the degrevlex order only:: + + sage: R. = PolynomialRing(GF(101), 3, order='lex') + sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching + sage: I.groebner_basis('msolve') # optional - msolve + Traceback (most recent call last): + ... + NotImplementedError: msolve only supports the degrevlex order (use transformed_basis()) """ from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -4438,7 +4460,14 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal elif algorithm == 'giac:gbasis': from sage.libs.giac import groebner_basis as groebner_basis_libgiac gb = groebner_basis_libgiac(self, prot=prot, *args, **kwds) - + elif algorithm == 'msolve': + if self.ring().term_order() != 'degrevlex': + raise NotImplementedError("msolve only supports the degrevlex order " + "(use transformed_basis())") + if not (deg_bound is mult_bound is None) or prot: + raise NotImplementedError("unsupported options for msolve") + from . import msolve + return msolve.groebner_basis_degrevlex(self, *args, **kwds) else: raise NameError("Algorithm '%s' unknown."%algorithm) From 774a3de6e00dd71461bb0500c9effa26bb1d7a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 16 Sep 2022 11:25:16 +0200 Subject: [PATCH 612/742] enhance detail in free dendriform algebras --- src/sage/combinat/free_dendriform_algebra.py | 27 ++++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/free_dendriform_algebra.py b/src/sage/combinat/free_dendriform_algebra.py index 04b8cf1208e..1bdcd1dbe31 100644 --- a/src/sage/combinat/free_dendriform_algebra.py +++ b/src/sage/combinat/free_dendriform_algebra.py @@ -12,7 +12,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** from sage.categories.hopf_algebras import HopfAlgebras @@ -30,6 +30,7 @@ from sage.misc.cachefunc import cached_method from sage.sets.family import Family from sage.structure.coerce_exceptions import CoercionException +from sage.rings.infinity import Infinity class FreeDendriformAlgebra(CombinatorialFreeModule): @@ -115,6 +116,16 @@ class FreeDendriformAlgebra(CombinatorialFreeModule): sage: w * w * w B[[., [., [., .]]]] + B[[., [[., .], .]]] + B[[[., .], [., .]]] + B[[[., [., .]], .]] + B[[[[., .], .], .]] + The set `E` can be infinite:: + + sage: F = algebras.FreeDendriform(QQ, ZZ) + sage: w = F.gen(1); w + B[1[., .]] + sage: x = F.gen(2); x + B[-1[., .]] + sage: w*x + B[-1[1[., .], .]] + B[1[., -1[., .]]] + REFERENCES: - [LR1998]_ @@ -193,14 +204,20 @@ def _repr_(self): Free Dendriform algebra on one generator ['@'] over Rational Field """ n = self.algebra_generators().cardinality() - if n == 1: + finite = bool(n < Infinity) + if not finite: + gen = "generators indexed by" + elif n == 1: gen = "one generator" else: gen = "{} generators".format(n) s = "Free Dendriform algebra on {} {} over {}" - try: - return s.format(gen, self._alphabet.list(), self.base_ring()) - except NotImplementedError: + if finite: + try: + return s.format(gen, self._alphabet.list(), self.base_ring()) + except NotImplementedError: + return s.format(gen, self._alphabet, self.base_ring()) + else: return s.format(gen, self._alphabet, self.base_ring()) def gen(self, i): From b5adcc93998366100ad6e9273fe8203b8dbb20d4 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Fri, 16 Sep 2022 11:50:48 +0200 Subject: [PATCH 613/742] #34519 update doc on msolve --- .../polynomial_rings_multivar.rst | 2 ++ src/sage/features/msolve.py | 8 ++++--- src/sage/rings/polynomial/msolve.py | 22 ++++++++++++++----- .../polynomial/multi_polynomial_ideal.py | 4 ++-- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/doc/en/reference/polynomial_rings/polynomial_rings_multivar.rst b/src/doc/en/reference/polynomial_rings/polynomial_rings_multivar.rst index 46388f58f25..6147929ccf2 100644 --- a/src/doc/en/reference/polynomial_rings/polynomial_rings_multivar.rst +++ b/src/doc/en/reference/polynomial_rings/polynomial_rings_multivar.rst @@ -36,6 +36,8 @@ are implemented using the PolyBoRi library (cf. :mod:`sage.rings.polynomial.pbor sage/rings/polynomial/multi_polynomial_libsingular sage/rings/polynomial/multi_polynomial_ideal_libsingular + sage/rings/polynomial/msolve + sage/rings/polynomial/polydict sage/rings/polynomial/hilbert diff --git a/src/sage/features/msolve.py b/src/sage/features/msolve.py index fa6679c2014..a7c7d5441b7 100644 --- a/src/sage/features/msolve.py +++ b/src/sage/features/msolve.py @@ -2,9 +2,11 @@ r""" Feature for testing the presence of msolve -`msolve `_ is a multivariate polynomial system solver -developed mainly by Jérémy Berthomieu (Sorbonne University), Christian Eder -(TU Kaiserslautern), and Mohab Safey El Din (Sorbonne University). +`msolve `_ is a multivariate polynomial system solver. + +.. SEEALSO:: + + - :mod:`sage.rings.polynomial.msolve` """ import subprocess diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index 2dafacbba66..65ae859f751 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -3,19 +3,17 @@ Solution of polynomial systems using msolve `msolve `_ is a multivariate polynomial system solver -developed mainly by Jérémy Berthomieu (Sorbonne University), Christian Eder -(TU Kaiserslautern), and Mohab Safey El Din (Sorbonne University). +based on Gröbner bases. This module provide implementations of some operations on polynomial ideals -based on msolve. Currently the only supported operation is the computation of -the variety of zero-dimensional ideal over the rationals. +based on msolve. Note that msolve must be installed separately. .. SEEALSO:: -- :mod:`sage.features.msolve` -- :mod:`sage.rings.polynomial.multi_polynomial_ideal` + - :mod:`sage.features.msolve` + - :mod:`sage.rings.polynomial.multi_polynomial_ideal` """ import os @@ -121,6 +119,18 @@ def variety(ideal, ring, *, proof=True): Part of the initial implementation was loosely based on the example interfaces available as part of msolve, with the authors' permission. + EXAMPLES:: + + sage: from sage.rings.polynomial.msolve import variety + sage: p = 536870909 + sage: R. = PolynomialRing(GF(p), 2, order='lex') + sage: I = Ideal([ x*y - 1, (x-2)^2 + (y-1)^2 - 1]) + sage: sorted(variety(I, GF(p^2), proof=False), key=str) # optional - msolve + [{x: 1, y: 1}, + {x: 254228855*z2 + 114981228, y: 232449571*z2 + 402714189}, + {x: 267525699, y: 473946006}, + {x: 282642054*z2 + 154363985, y: 304421338*z2 + 197081624}] + TESTS:: sage: p = 536870909 diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index caa74226fd3..243bb9e557b 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -4285,8 +4285,8 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal ALGORITHM: - Uses Singular, Magma (if available), Macaulay2 (if available), - Giac (if available), or a toy implementation. + Uses Singular, one of the other systems listed above (if available), + or a toy implementation. TESTS: From d2cede66b70b2a54be78a037618e93a88d0aee90 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 11 Sep 2022 12:33:29 -0700 Subject: [PATCH 614/742] build/pkgs/msolve: New --- build/pkgs/msolve/SPKG.rst | 18 ++++++++++++++++++ build/pkgs/msolve/checksums.ini | 5 +++++ build/pkgs/msolve/dependencies | 4 ++++ build/pkgs/msolve/package-version.txt | 1 + build/pkgs/msolve/spkg-install.in | 4 ++++ build/pkgs/msolve/type | 1 + 6 files changed, 33 insertions(+) create mode 100644 build/pkgs/msolve/SPKG.rst create mode 100644 build/pkgs/msolve/checksums.ini create mode 100644 build/pkgs/msolve/dependencies create mode 100644 build/pkgs/msolve/package-version.txt create mode 100644 build/pkgs/msolve/spkg-install.in create mode 100644 build/pkgs/msolve/type diff --git a/build/pkgs/msolve/SPKG.rst b/build/pkgs/msolve/SPKG.rst new file mode 100644 index 00000000000..bfa38b87cae --- /dev/null +++ b/build/pkgs/msolve/SPKG.rst @@ -0,0 +1,18 @@ +msolve: Multivariate polynomial system solver +============================================= + +Description +----------- + +Open source C library implementing computer algebra algorithms for solving +polynomial systems (with rational coefficients or coefficients in a prime field). + +License +------- + +GPL v2+ + +Upstream Contact +---------------- + +https://gitlab.lip6.fr/safey/msolve diff --git a/build/pkgs/msolve/checksums.ini b/build/pkgs/msolve/checksums.ini new file mode 100644 index 00000000000..bd23c2a9a4e --- /dev/null +++ b/build/pkgs/msolve/checksums.ini @@ -0,0 +1,5 @@ +tarball=msolve-VERSION.tar.gz +sha1=d2097ba38370f1c5ba368d8f3874f510b0cd9369 +md5=4116a3df364a5cfc986bc791f7b232d0 +cksum=2848317901 +upstream_url=https://trac.sagemath.org/raw-attachment/ticket/31664/msolve-VERSION.tar.gz diff --git a/build/pkgs/msolve/dependencies b/build/pkgs/msolve/dependencies new file mode 100644 index 00000000000..4f96ff0a6c9 --- /dev/null +++ b/build/pkgs/msolve/dependencies @@ -0,0 +1,4 @@ +$(MP_LIBRARY) flint mpfr + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/msolve/package-version.txt b/build/pkgs/msolve/package-version.txt new file mode 100644 index 00000000000..6f2743d65dc --- /dev/null +++ b/build/pkgs/msolve/package-version.txt @@ -0,0 +1 @@ +0.4.4 diff --git a/build/pkgs/msolve/spkg-install.in b/build/pkgs/msolve/spkg-install.in new file mode 100644 index 00000000000..2aaf0e99043 --- /dev/null +++ b/build/pkgs/msolve/spkg-install.in @@ -0,0 +1,4 @@ +cd src +sdh_configure +sdh_make +sdh_make_install diff --git a/build/pkgs/msolve/type b/build/pkgs/msolve/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/msolve/type @@ -0,0 +1 @@ +optional From 95e2e545c17a0cfc10eb522957d8260afcef9417 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 11 Sep 2022 12:59:21 -0700 Subject: [PATCH 615/742] build/pkgs/msolve: Use msolve-0.4.4+sage-2022-09-11 --- build/pkgs/msolve/SPKG.rst | 4 ++++ build/pkgs/msolve/checksums.ini | 6 +++--- build/pkgs/msolve/package-version.txt | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/build/pkgs/msolve/SPKG.rst b/build/pkgs/msolve/SPKG.rst index bfa38b87cae..d9909588a68 100644 --- a/build/pkgs/msolve/SPKG.rst +++ b/build/pkgs/msolve/SPKG.rst @@ -16,3 +16,7 @@ Upstream Contact ---------------- https://gitlab.lip6.fr/safey/msolve + +Upstream does not make source tarballs. + +We make tarballs from the fork https://github.com/sagemath/msolve (branch 0.4.4+sage) diff --git a/build/pkgs/msolve/checksums.ini b/build/pkgs/msolve/checksums.ini index bd23c2a9a4e..0b7558afd2b 100644 --- a/build/pkgs/msolve/checksums.ini +++ b/build/pkgs/msolve/checksums.ini @@ -1,5 +1,5 @@ tarball=msolve-VERSION.tar.gz -sha1=d2097ba38370f1c5ba368d8f3874f510b0cd9369 -md5=4116a3df364a5cfc986bc791f7b232d0 -cksum=2848317901 +sha1=5b227de8b222bfe8d143e1d7ea77ad71cd209dc8 +md5=2f34bd9ccb089688ae169201281108dc +cksum=941373315 upstream_url=https://trac.sagemath.org/raw-attachment/ticket/31664/msolve-VERSION.tar.gz diff --git a/build/pkgs/msolve/package-version.txt b/build/pkgs/msolve/package-version.txt index 6f2743d65dc..fb78594e923 100644 --- a/build/pkgs/msolve/package-version.txt +++ b/build/pkgs/msolve/package-version.txt @@ -1 +1 @@ -0.4.4 +0.4.4+sage-2022-09-11 From e552a50ec9067514853f3c6dc3695ee7240abf0f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 12 Sep 2022 07:40:53 -0700 Subject: [PATCH 616/742] build/pkgs/msolve/SPKG.rst: Point to upstream github --- build/pkgs/msolve/SPKG.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build/pkgs/msolve/SPKG.rst b/build/pkgs/msolve/SPKG.rst index d9909588a68..00c1c417208 100644 --- a/build/pkgs/msolve/SPKG.rst +++ b/build/pkgs/msolve/SPKG.rst @@ -15,8 +15,7 @@ GPL v2+ Upstream Contact ---------------- -https://gitlab.lip6.fr/safey/msolve +https://github.com/algebraic-solving/msolve Upstream does not make source tarballs. - -We make tarballs from the fork https://github.com/sagemath/msolve (branch 0.4.4+sage) +We make tarballs from the fork https://github.com/mkoeppe/msolve (branch 0.4.4+sage) From 91d69ccf6b4e03f74bb40709a71f93ded3bc809e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 15 Sep 2022 12:39:01 -0700 Subject: [PATCH 617/742] Link to msolve spkg page --- src/sage/rings/polynomial/msolve.py | 2 +- .../rings/polynomial/multi_polynomial_ideal.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index 65ae859f751..3789c56c270 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -8,7 +8,7 @@ This module provide implementations of some operations on polynomial ideals based on msolve. -Note that msolve must be installed separately. +Note that the `optional package msolve <../spkg/msolve.html>`_ must be installed. .. SEEALSO:: diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 243bb9e557b..c5007777ad1 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2391,7 +2391,8 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True {y: 0.3611030805286474?, x: 2.769292354238632?}, {y: 1, x: 1}] - We can also use the external program msolve to compute the variety. + We can also use the `optional package msolve <../spkg/msolve.html>`_ + to compute the variety. See :mod:`~sage.rings.polynomial.msolve` for more information. :: sage: I.variety(RBF, algorithm='msolve', proof=False) # optional - msolve @@ -2467,9 +2468,9 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True uses triangular decomposition, via Singular if possible, falling back on a toy implementation otherwise. - - With ``algorithm`` = ``"msolve"``, calls the external program - `msolve `_ (if available in the system - program search path). Note that msolve uses heuristics and therefore + - With ``algorithm`` = ``"msolve"``, uses the + `optional package msolve <../spkg/msolve.html>`_. + Note that msolve uses heuristics and therefore requires setting the ``proof`` flag to ``False``. See :mod:`~sage.rings.polynomial.msolve` for more information. """ @@ -4013,7 +4014,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal Macaulay2's ``GroebnerBasis`` command with the strategy "MGB" (if available) 'msolve' - `msolve `_ (if available, degrevlex order, + `optional package msolve <../spkg/msolve.html>`_ (degrevlex order, prime fields) 'magma:GroebnerBasis' @@ -4139,9 +4140,8 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal sage: I.groebner_basis('macaulay2:mgb') # optional - macaulay2 [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] - Over prime fields of small characteristic, we can also use - `msolve `_ (if available in the system program - search path):: + Over prime fields of small characteristic, we can also use the + `optional package msolve <../spkg/msolve.html>`_:: sage: R. = PolynomialRing(GF(101), 3) sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching From fa77041c3b64c493295361258aa7970cf210e597 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 15 Sep 2022 12:39:17 -0700 Subject: [PATCH 618/742] src/sage/rings/polynomial/msolve.py: Use absolute filename of msolve --- src/sage/rings/polynomial/msolve.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index 3789c56c270..6dd9579b0bd 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -46,13 +46,11 @@ def _run_msolve(ideal, options): # Run msolve - msolve().require() - drlpolring = ideal.ring().change_ring(order='degrevlex') polys = ideal.change_ring(drlpolring).gens() msolve_in = tempfile.NamedTemporaryFile(mode='w', encoding='ascii', delete=False) - command = ["msolve", "-f", msolve_in.name] + options + command = [msolve().absolute_filename(), "-f", msolve_in.name] + options try: print(",".join(drlpolring.variable_names()), file=msolve_in) print(base.characteristic(), file=msolve_in) From 44025613a6194e6a491f550c2dd91f2a4e7d8033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 16 Sep 2022 12:14:10 +0200 Subject: [PATCH 619/742] some details in misc/ --- src/sage/misc/sage_input.py | 26 +++++++++++++++++--------- src/sage/misc/sageinspect.py | 10 +++++----- src/sage/misc/table.py | 22 +++++++++++----------- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/sage/misc/sage_input.py b/src/sage/misc/sage_input.py index 24586170e4e..b49763dbf27 100644 --- a/src/sage/misc/sage_input.py +++ b/src/sage/misc/sage_input.py @@ -161,7 +161,7 @@ - Vincent Delecroix (2015-02): documentation formatting """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Carl Witty # 2015 Vincent Delecroix <20100.delecroix@gmail.com> # @@ -169,8 +169,8 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** def sage_input(x, preparse=True, verify=False, allow_locals=False): @@ -240,7 +240,7 @@ def sage_input(x, preparse=True, verify=False, allow_locals=False): sage: sage_input((3, lambda x: x)) Traceback (most recent call last): ... - ValueError: Can't convert at 0x...> to sage_input form + ValueError: cannot convert at 0x...> to sage_input form But we can have :func:`sage_input` continue anyway, and return an input form for the rest of the expression, with ``allow_locals=True``.:: @@ -272,6 +272,7 @@ def sage_input(x, preparse=True, verify=False, allow_locals=False): return final_answer + class SageInputBuilder: r""" An instance of this class is passed to ``_sage_input_`` methods. @@ -427,7 +428,7 @@ def __call__(self, x, coerced=False): sage: sage_input(lambda x: x) Traceback (most recent call last): ... - ValueError: Can't convert at 0x...> to sage_input form + ValueError: cannot convert at 0x...> to sage_input form sage: sage_input(lambda x: x, allow_locals=True, verify=True) LOCALS: _sil1: at 0x...> @@ -519,7 +520,7 @@ def __call__(self, x, coerced=False): self._locals[loc_name] = x return SIE_literal_stringrep(self, loc_name) else: - raise ValueError("Can't convert {} to sage_input form".format(x)) + raise ValueError("cannot convert {} to sage_input form".format(x)) def preparse(self): r""" @@ -815,7 +816,7 @@ def dict(self, entries): """ if isinstance(entries, dict): entries = list(entries.items()) - entries = [(self(key),self(val)) for (key,val) in entries] + entries = [(self(key), self(val)) for (key, val) in entries] return SIE_dict(self, entries) def getattr(self, sie, attr): @@ -1077,7 +1078,7 @@ def prod(self, factors, simplify=False): neg = False break if isinstance(factor, SIE_literal_stringrep) and factor._sie_value == '1': - factors[i:i+1] = [] + factors[i:i + 1] = [] else: i += 1 if len(factors) == 0: @@ -1123,7 +1124,7 @@ def sum(self, terms, simplify=False): while i < len(terms): term = terms[i] if isinstance(term, SIE_literal_stringrep) and term._sie_value == '0': - terms[i:i+1] = [] + terms[i:i + 1] = [] else: i += 1 if len(terms) == 0: @@ -1174,6 +1175,7 @@ def result(self, e): else: return SageInputAnswer(sif._commands, sif.format(e, 0)) + # Python's precedence levels. Hand-transcribed from section 5.14 of # the Python 2 reference manual. In the Python 3 reference manual # this is section 6.16. @@ -1200,6 +1202,7 @@ def result(self, e): _prec_funcall = 40 _prec_atomic = 42 + class SageInputExpression(): r""" Subclasses of this class represent expressions for :func:`sage_input`. @@ -1687,6 +1690,7 @@ def _sie_format_statement(self, sif): result, prec = self._sie_format(sif) return result + class SIE_literal(SageInputExpression): r""" An abstract base class for ``literals`` (basically, values which @@ -1730,6 +1734,7 @@ def _sie_is_simple(self): # times in an expression, it might be better to do the replacement. return not self._sie_share + class SIE_literal_stringrep(SIE_literal): r""" Values in this class are leaves in a :func:`sage_input` expression @@ -1813,6 +1818,7 @@ def _sie_format(self, sif): """ return self._sie_value, _prec_atomic + class SIE_call(SageInputExpression): r""" This class represents a function-call node in a :func:`sage_input` @@ -2024,6 +2030,7 @@ def _sie_format(self, sif): key = sif.format(self._sie_key, 0) return '%s[%s]' % (coll, key), _prec_subscript + class SIE_getattr(SageInputExpression): r""" This class represents a getattr node in a :func:`sage_input` @@ -2222,6 +2229,7 @@ def _sie_format(self, sif): else: return '(%s)' % ', '.join(values), _prec_atomic + class SIE_dict(SageInputExpression): r""" This class represents a dict node in a :func:`sage_input` diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index be8f2527bde..fbca2defc20 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -1018,14 +1018,14 @@ def split_string(s, quot): if s[i] == '\\': escaped = not escaped continue - if not escaped and s[i:i+l] == quot: - return s[:i], s[i+l:] + if not escaped and s[i:i + l] == quot: + return s[:i], s[i + l:] escaped = False raise SyntaxError("EOF while scanning string literal") # 1. s is a triple-quoted string if s.startswith('"""'): a, b = split_string(s[3:], '"""') - return '"""'+a+'"""', b.strip() + return '"""' + a + '"""', b.strip() if s.startswith('r"""'): a, b = split_string(s[4:], '"""') return 'r"""'+a+'"""', b.strip() @@ -1313,7 +1313,7 @@ def _sage_getargspec_cython(source): name = None nb_stars = 0 else: - raise SyntaxError("varargs can't be defined twice") + raise SyntaxError("varargs cannot be defined twice") elif nb_stars == 2: if keywords is None: keywords = name @@ -1323,7 +1323,7 @@ def _sage_getargspec_cython(source): name = None nb_stars = 0 else: - raise SyntaxError("varargs can't be defined twice") + raise SyntaxError("varargs cannot be defined twice") else: raise SyntaxError("variable declaration comprises at most two '*'") else: diff --git a/src/sage/misc/table.py b/src/sage/misc/table.py index 8610f06df0d..cbd8b083a6b 100644 --- a/src/sage/misc/table.py +++ b/src/sage/misc/table.py @@ -207,7 +207,7 @@ class table(SageObject): sage: table(rows=[[1,2,3], [4,5,6]], columns=[[0,0,0], [0,0,1024]]) Traceback (most recent call last): ... - ValueError: Don't set both 'rows' and 'columns' when defining a table. + ValueError: do not set both 'rows' and 'columns' when defining a table sage: table(columns=[[0,0,0], [0,0,1024]]) 0 0 @@ -251,7 +251,7 @@ def __init__(self, rows=None, columns=None, header_row=False, """ # If both rows and columns are set, raise an error. if rows and columns: - raise ValueError("Don't set both 'rows' and 'columns' when defining a table.") + raise ValueError("do not set both 'rows' and 'columns' when defining a table") # If columns is set, use its transpose for rows. if columns: rows = list(zip(*columns)) @@ -268,7 +268,7 @@ def __init__(self, rows=None, columns=None, header_row=False, self._options['header_column'] = True elif header_column: self._options['header_column'] = True - rows = [(a,) + tuple(x) for (a,x) in zip(header_column, rows)] + rows = [(a,) + tuple(x) for (a, x) in zip(header_column, rows)] else: self._options['header_column'] = False @@ -442,7 +442,7 @@ def _repr_(self): if len(rows) == 0 or nc == 0: return "" - frame_line = "+" + "+".join("-" * (x+2) for x in self._widths()) + "+\n" + frame_line = "+" + "+".join("-" * (x + 2) for x in self._widths()) + "+\n" if self._options['header_column'] and self._options['frame']: frame_line = "+" + frame_line[1:].replace('+', '++', 1) @@ -503,7 +503,7 @@ def _str_table_row(self, row, header_row=False): """ frame = self._options['frame'] widths = self._widths() - frame_line = "+" + "+".join("-" * (x+2) for x in widths) + "+\n" + frame_line = "+" + "+".join("-" * (x + 2) for x in widths) + "+\n" align = self._options['align'] if align == 'right': @@ -607,16 +607,16 @@ def _latex_(self): # table header s = "\\begin{tabular}{" s += frame_char + align_char + frame_char + head_col_char - s += frame_char.join([align_char] * (nc-1)) + s += frame_char.join([align_char] * (nc - 1)) s += frame_char + "}" + frame_str + "\n" # first row s += " & ".join(LatexExpr(x) if isinstance(x, (str, LatexExpr)) - else '$' + latex(x).strip() + '$' for x in rows[0]) + else '$' + latex(x).strip() + '$' for x in rows[0]) s += " \\\\" + frame_str + head_row_str + "\n" # other rows for row in rows[1:]: s += " & ".join(LatexExpr(x) if isinstance(x, (str, LatexExpr)) - else '$' + latex(x).strip() + '$' for x in row) + else '$' + latex(x).strip() + '$' for x in row) s += " \\\\" + frame_str + "\n" s += "\\end{tabular}" return s @@ -724,7 +724,7 @@ def _html_(self): if rows: s.writelines([ # If the table has < 100 rows, don't truncate the output in the notebook - '
\n' if len(rows) <= 100 else '
' , + '
\n' if len(rows) <= 100 else '
', '\n'.format(frame), '\n', ]) @@ -813,7 +813,7 @@ def _html_table_row(self, file, row, header=False): # first entry of row entry = row[0] if isinstance(entry, Graphics): - file.write(first_column_tag % entry.show(linkmode = True)) + file.write(first_column_tag % entry.show(linkmode=True)) elif isinstance(entry, str): file.write(first_column_tag % math_parse(entry)) else: @@ -822,7 +822,7 @@ def _html_table_row(self, file, row, header=False): # other entries for column in range(1, len(row)): if isinstance(row[column], Graphics): - file.write(column_tag % row[column].show(linkmode = True)) + file.write(column_tag % row[column].show(linkmode=True)) elif isinstance(row[column], str): file.write(column_tag % math_parse(row[column])) else: From 722dd2f2900510f1d425aa17ee5751bf7105c8e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 16 Sep 2022 15:44:56 +0200 Subject: [PATCH 620/742] cleaning up in posets/ --- src/sage/combinat/posets/hasse_diagram.py | 12 +- src/sage/combinat/posets/lattices.py | 19 +-- src/sage/combinat/posets/moebius_algebra.py | 4 +- src/sage/combinat/posets/poset_examples.py | 148 ++++++++++---------- src/sage/combinat/posets/posets.py | 20 +-- 5 files changed, 107 insertions(+), 96 deletions(-) diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index 515b762278c..d857092f9c7 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -3489,15 +3489,15 @@ def _glue_spectra(a_spec, b_spec, orientation): p = len(a_spec) q = len(b_spec) - for r in range(1, p+q+1): + for r in range(1, p + q + 1): new_a_spec.append(0) - for i in range(max(1, r-q), min(p, r) + 1): - k_val = binomial(r-1, i-1) * binomial(p+q-r, p-i) + for i in range(max(1, r - q), min(p, r) + 1): + k_val = binomial(r - 1, i - 1) * binomial(p + q - r, p - i) if orientation: - inner_sum = sum(b_spec[j-1] for j in range(r-i + 1, len(b_spec) + 1)) + inner_sum = sum(b_spec[j - 1] for j in range(r - i + 1, len(b_spec) + 1)) else: - inner_sum = sum(b_spec[j-1] for j in range(1, r-i + 1)) - new_a_spec[-1] = new_a_spec[-1] + (a_spec[i-1] * k_val * inner_sum) + inner_sum = sum(b_spec[j - 1] for j in range(1, r - i + 1)) + new_a_spec[-1] = new_a_spec[-1] + (a_spec[i - 1] * k_val * inner_sum) return new_a_spec diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py index 00f50e68f19..dba3c15c549 100644 --- a/src/sage/combinat/posets/lattices.py +++ b/src/sage/combinat/posets/lattices.py @@ -1307,9 +1307,9 @@ def is_semidistributive(self): """ H = self._hasse_diagram # See trac #21528 for explanation. - return ( (H.in_degree_sequence().count(1) == + return ((H.in_degree_sequence().count(1) == H.out_degree_sequence().count(1)) and - self.is_meet_semidistributive() ) + self.is_meet_semidistributive()) def is_meet_semidistributive(self, certificate=False): r""" @@ -1693,11 +1693,11 @@ def is_cosectionally_complemented(self, certificate=False): H = self._hasse_diagram jn = H.join_matrix() n = H.order() - for e in range(n-2, -1, -1): + for e in range(n - 2, -1, -1): t = 0 for uc in H.neighbors_out(e): t = jn[t, uc] - if t == n-1: + if t == n - 1: break else: if certificate: @@ -1882,8 +1882,8 @@ def is_sectionally_complemented(self, certificate=False): H = self._hasse_diagram mt = H.meet_matrix() - n = H.order()-1 - for e in range(2, n+1): + n = H.order() - 1 + for e in range(2, n + 1): t = n for lc in H.neighbors_in(e): t = mt[t, lc] @@ -3085,9 +3085,9 @@ def vertical_decomposition(self, elements_only=False): if elements_only: return [self[e] for e in self._hasse_diagram.vertical_decomposition(return_list=True)] - elms = ( [0] + - self._hasse_diagram.vertical_decomposition(return_list=True) + - [self.cardinality() - 1] ) + elms = ([0] + + self._hasse_diagram.vertical_decomposition(return_list=True) + + [self.cardinality() - 1]) n = len(elms) result = [] for i in range(n - 1): @@ -4975,6 +4975,7 @@ def _log_2(n): return bits return bits + 1 + ############################################################################ FiniteMeetSemilattice._dual_class = FiniteJoinSemilattice diff --git a/src/sage/combinat/posets/moebius_algebra.py b/src/sage/combinat/posets/moebius_algebra.py index 9ed121e66c2..aada2725078 100644 --- a/src/sage/combinat/posets/moebius_algebra.py +++ b/src/sage/combinat/posets/moebius_algebra.py @@ -102,7 +102,7 @@ def __init__(self, R, L): TESTS:: - sage: L = posets.BooleanLattice(4) + sage: L = posets.BooleanLattice(3) sage: M = L.moebius_algebra(QQ) sage: TestSuite(M).run() """ @@ -632,7 +632,7 @@ def __init__(self, M, prefix='KL'): TESTS:: - sage: L = posets.BooleanLattice(4) + sage: L = posets.BooleanLattice(3) sage: M = L.quantum_moebius_algebra() sage: TestSuite(M.KL()).run() # long time """ diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index e415dc300f2..377fc569fde 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -219,7 +219,7 @@ def BooleanLattice(n, facade=None, use_subsets=False): from sage.sets.set import Set V = [Set(), Set([1])] return LatticePoset((V, [V]), facade=facade) - return LatticePoset(([0,1], [[0,1]]), facade=facade) + return LatticePoset(([0, 1], [[0, 1]]), facade=facade) if use_subsets: from sage.sets.set import Set @@ -288,7 +288,7 @@ def ChainPoset(n, facade=None): raise TypeError("number of elements must be an integer, not {0}".format(n)) if n < 0: raise ValueError("number of elements must be non-negative, not {0}".format(n)) - D = DiGraph([range(n), [[x,x+1] for x in range(n-1)]], + D = DiGraph([range(n), [[x, x + 1] for x in range(n - 1)]], format='vertices_and_edges') return FiniteLatticePoset(hasse_diagram=D, category=FiniteLatticePosets(), @@ -377,7 +377,7 @@ def PentagonPoset(facade=None): sage: posets.DiamondPoset(5).is_distributive() False """ - return LatticePoset([[1,2],[4],[3],[4],[]], facade=facade) + return LatticePoset([[1, 2], [4], [3], [4], []], facade=facade) @staticmethod def DiamondPoset(n, facade=None): @@ -404,10 +404,10 @@ def DiamondPoset(n, facade=None): raise TypeError("number of elements must be an integer, not {0}".format(n)) if n <= 2: raise ValueError("n must be an integer at least 3") - c = [[n-1] for x in range(n)] - c[0] = [x for x in range(1,n-1)] - c[n-1] = [] - D = DiGraph({v:c[v] for v in range(n)}, format='dict_of_lists') + c = [[n - 1] for x in range(n)] + c[0] = [x for x in range(1, n - 1)] + c[n - 1] = [] + D = DiGraph({v: c[v] for v in range(n)}, format='dict_of_lists') return FiniteLatticePoset(hasse_diagram=D, category=FiniteLatticePosets(), facade=facade) @@ -441,8 +441,8 @@ def Crown(n, facade=None): raise TypeError("number of elements must be an integer, not {0}".format(n)) if n < 2: raise ValueError("n must be an integer at least 2") - D = {i: [i+n, i+n+1] for i in range(n-1)} - D[n-1] = [n, n+n-1] + D = {i: [i + n, i + n + 1] for i in range(n - 1)} + D[n - 1] = [n, n + n - 1] return FinitePoset(hasse_diagram=DiGraph(D), category=FinitePosets(), facade=facade) @@ -485,7 +485,7 @@ def DivisorLattice(n, facade=None): if n <= 0: raise ValueError("n must be a positive integer") Div_n = divisors(n) - hasse = DiGraph([Div_n, lambda a, b: b%a==0 and is_prime(b//a)]) + hasse = DiGraph([Div_n, lambda a, b: b % a == 0 and is_prime(b // a)]) return FiniteLatticePoset(hasse, elements=Div_n, facade=facade, category=FiniteLatticePosets()) @@ -509,7 +509,8 @@ def IntegerCompositions(n): """ from sage.combinat.composition import Compositions C = Compositions(n) - return Poset((C, [[c,d] for c in C for d in C if d.is_finer(c)]), cover_relations=False) + return Poset((C, [[c, d] for c in C for d in C if d.is_finer(c)]), + cover_relations=False) @staticmethod def IntegerPartitions(n): @@ -535,19 +536,19 @@ def lower_covers(partition): of elements in the poset of integer partitions. """ lc = [] - for i in range(len(partition)-1): - for j in range(i+1,len(partition)): + for i in range(len(partition) - 1): + for j in range(i + 1, len(partition)): new_partition = partition[:] del new_partition[j] del new_partition[i] - new_partition.append(partition[i]+partition[j]) + new_partition.append(partition[i] + partition[j]) new_partition.sort(reverse=True) tup = tuple(new_partition) if tup not in lc: lc.append(tup) return lc from sage.combinat.partition import Partitions - H = DiGraph(dict([[tuple(p),lower_covers(p)] for p in Partitions(n)])) + H = DiGraph(dict([[tuple(p), lower_covers(p)] for p in Partitions(n)])) return Poset(H.reverse()) @staticmethod @@ -574,20 +575,20 @@ def lower_covers(partition): restricted poset of integer partitions. """ lc = [] - for i in range(len(partition)-1): - for j in range(i+1,len(partition)): + for i in range(len(partition) - 1): + for j in range(i + 1, len(partition)): if partition[i] != partition[j]: new_partition = partition[:] del new_partition[j] del new_partition[i] - new_partition.append(partition[i]+partition[j]) + new_partition.append(partition[i] + partition[j]) new_partition.sort(reverse=True) tup = tuple(new_partition) if tup not in lc: lc.append(tup) return lc from sage.combinat.partition import Partitions - H = DiGraph(dict([[tuple(p),lower_covers(p)] for p in Partitions(n)])) + H = DiGraph(dict([[tuple(p), lower_covers(p)] for p in Partitions(n)])) return Poset(H.reverse()) @staticmethod @@ -677,9 +678,8 @@ def PowerPoset(n): all_pos_n.add(P.relabel(list(r))) return MeetSemilattice((all_pos_n, - lambda A, B: all(B.is_lequal(x, y) for x,y in A.cover_relations_iterator()) - )) - + lambda A, B: all(B.is_lequal(x, y) + for x, y in A.cover_relations_iterator()))) @staticmethod def ProductOfChains(chain_lengths, facade=None): @@ -794,7 +794,7 @@ def RandomPoset(n, p): p = float(p) except Exception: raise TypeError("probability must be a real number, not {0}".format(p)) - if p < 0 or p> 1: + if p < 0 or p > 1: raise ValueError("probability must be between 0 and 1, not {0}".format(p)) D = DiGraph(loops=False, multiedges=False) @@ -904,7 +904,7 @@ def RandomLattice(n, p, properties=None): if n <= 3: return posets.ChainPoset(n) covers = _random_lattice(n, p) - covers_dict = {i:covers[i] for i in range(n)} + covers_dict = {i: covers[i] for i in range(n)} D = DiGraph(covers_dict) D.relabel([i-1 for i in Permutations(n).random_element()]) return LatticePoset(D, cover_relations=True) @@ -1173,9 +1173,11 @@ def SymmetricGroupWeakOrderPoset(n, labels="permutations", side="right"): Finite poset containing 24 elements """ if n < 10 and labels == "permutations": - element_labels = dict([[s,"".join(map(str,s))] for s in Permutations(n)]) + element_labels = dict([[s, "".join(map(str, s))] + for s in Permutations(n)]) if n < 10 and labels == "reduced_words": - element_labels = dict([[s,"".join(map(str,s.reduced_word_lexmin()))] for s in Permutations(n)]) + element_labels = dict([[s, "".join(map(str, s.reduced_word_lexmin()))] + for s in Permutations(n)]) if side == "left": def weak_covers(s): @@ -1193,7 +1195,8 @@ def weak_covers(s): """ return [v for v in s.bruhat_succ() if s.length() + (s.inverse().left_action_product(v)).length() == v.length()] - return Poset(dict([[s, weak_covers(s)] for s in Permutations(n)]),element_labels) + return Poset(dict([[s, weak_covers(s)] for s in Permutations(n)]), + element_labels) @staticmethod def TetrahedralPoset(n, *colors, **labels): @@ -1253,33 +1256,33 @@ def TetrahedralPoset(n, *colors, **labels): if c not in ('green', 'red', 'yellow', 'orange', 'silver', 'blue'): raise ValueError("color input must be from the following: 'green', 'red', 'yellow', 'orange', 'silver', and 'blue'") elem = [(i, j, k) for i in range(n) - for j in range(n-i) for k in range(n-i-j)] + for j in range(n - i) for k in range(n - i - j)] rels = [] elem_labels = {} if 'labels' in labels: if labels['labels'] == 'integers': labelcount = 0 - for (i,j,k) in elem: - elem_labels[(i,j,k)] = labelcount + for (i, j, k) in elem: + elem_labels[(i, j, k)] = labelcount labelcount += 1 for c in colors: - for (i,j,k) in elem: - if i+j+k < n-1: + for (i, j, k) in elem: + if i + j + k < n - 1: if c == 'green': - rels.append([(i,j,k),(i+1,j,k)]) + rels.append([(i, j, k), (i + 1, j, k)]) if c == 'red': - rels.append([(i,j,k),(i,j,k+1)]) + rels.append([(i, j, k), (i, j, k + 1)]) if c == 'yellow': - rels.append([(i,j,k),(i,j+1,k)]) - if j < n-1 and k > 0: + rels.append([(i, j, k), (i, j + 1, k)]) + if j < n - 1 and k > 0: if c == 'orange': - rels.append([(i,j,k),(i,j+1,k-1)]) - if i < n-1 and j > 0: + rels.append([(i, j, k), (i, j + 1, k - 1)]) + if i < n - 1 and j > 0: if c == 'silver': - rels.append([(i,j,k),(i+1,j-1,k)]) - if i < n-1 and k > 0: + rels.append([(i, j, k), (i + 1, j - 1, k)]) + if i < n - 1 and k > 0: if c == 'blue': - rels.append([(i,j,k),(i+1,j,k-1)]) + rels.append([(i, j, k), (i + 1, j, k - 1)]) return Poset([elem, rels], elem_labels) # shard intersection order @@ -1684,9 +1687,9 @@ def PermutationPattern(n): if n <= 0: raise ValueError("number of elements must be nonnegative, not {}".format(n)) elem = [] - for i in range(1, n+1): + for i in range(1, n + 1): elem += Permutations(i) - return Poset((elem, lambda a,b: b.has_pattern(a))) + return Poset((elem, lambda a, b: b.has_pattern(a))) @staticmethod def PermutationPatternInterval(bottom, top): @@ -1737,7 +1740,7 @@ def PermutationPatternInterval(bottom, top): level = 0 # Consider the top element to be level 0, and then go down from there. rel = [] # List of covering relations to be fed into poset constructor. while len(top) - len(bottom) >= level + 1: - elem.append([]) # Add a new empty level + elem.append([]) # Add a new empty level for upper in elem[level]: # Run through all permutations on current level # and find relations for which it is upper cover @@ -1746,17 +1749,17 @@ def PermutationPatternInterval(bottom, top): # Try and remove the ith element from the permutation lower = list(upper) j = lower.pop(i) - for k in range(len(top)-level-1): # Standardize result + for k in range(len(top)-level-1): # Standardize result if lower[k] > j: lower[k] = lower[k] - 1 lower_perm = P(lower) - if lower_perm.has_pattern(bottom): # Check to see if result is in interval + if lower_perm.has_pattern(bottom): # Check to see if result is in interval rel += [[lower_perm, upper_perm]] - if lower not in elem[level+1]: - elem[level+1].append(lower_perm) + if lower not in elem[level + 1]: + elem[level + 1].append(lower_perm) level += 1 elem = [item for sublist in elem for item in sublist] - return Poset((elem,rel)) + return Poset((elem, rel)) @staticmethod def PermutationPatternOccurrenceInterval(bottom, top, pos): @@ -1793,13 +1796,13 @@ def PermutationPatternOccurrenceInterval(bottom, top, pos): P = Permutations() top = P(top) bottom = P(bottom) - if not to_standard([top[z] for z in pos]) == list(bottom): # check input + if not to_standard([top[z] for z in pos]) == list(bottom): # check input raise ValueError("cannot find 'bottom' in 'top' given by 'pos'") elem = [[(top, pos)]] level = 0 rel = [] while len(top) - len(bottom) >= level + 1: - elem.append([]) # Add a new empty level + elem.append([]) # Add a new empty level for upper in elem[level]: for i in range(len(top)-level): # Try and remove the ith element from the permutation @@ -1816,11 +1819,11 @@ def PermutationPatternOccurrenceInterval(bottom, top, pos): lower_pos[f] = upper[1][f] - 1 rel += [[(P(lower_perm), tuple(lower_pos)), (P(upper[0]), upper[1])]] - if (P(lower_perm), tuple(lower_pos)) not in elem[level+1]: - elem[level+1].append((P(lower_perm), tuple(lower_pos))) + if (P(lower_perm), tuple(lower_pos)) not in elem[level + 1]: + elem[level + 1].append((P(lower_perm), tuple(lower_pos))) level += 1 elem = [item for sublist in elem for item in sublist] - return Poset([elem,rel]) + return Poset([elem, rel]) @staticmethod def RibbonPoset(n, descents): @@ -1838,7 +1841,9 @@ def RibbonPoset(n, descents): sage: sorted(R.cover_relations()) [[0, 1], [2, 1], [3, 2], [3, 4]] """ - return Mobile(DiGraph([list(range(n)), [(i+1, i) if i in descents else (i, i+1) for i in range(n-1) ]])) + return Mobile(DiGraph([list(range(n)), + [(i + 1, i) if i in descents else (i, i + 1) + for i in range(n - 1)]])) @staticmethod def MobilePoset(ribbon, hangers, anchor=None): @@ -1889,15 +1894,15 @@ def MobilePoset(ribbon, hangers, anchor=None): for r, hangs in hangers.items(): for i, h in enumerate(hangs): for v in h._elements: - elements.append((r,i,v)) + elements.append((r, i, v)) for cr in h.cover_relations(): cover_relations.append(((r, i, cr[0]), (r, i, cr[1]))) - cover_relations.append(((r,i,h.top()), r)) + cover_relations.append(((r, i, h.top()), r)) return Mobile(DiGraph([elements, cover_relations])) -## RANDOM LATTICES +# RANDOM LATTICES # Following are helper functions for random lattice generation. # There is no parameter checking, 0, 1, ..., n may or may not be a @@ -1939,8 +1944,8 @@ def _random_lattice(n, p): from sage.misc.functional import sqrt from sage.misc.prandom import random - n = n-1 - meets = [[None]*n for _ in range(n)] + n = n - 1 + meets = [[None] * n for _ in range(n)] meets[0][0] = 0 maxs = set([0]) lc_all = [[]] # No lower covers for the bottom element. @@ -2008,11 +2013,11 @@ def _random_dismantlable_lattice(n): """ from sage.misc.prandom import randint - D = DiGraph({0: [n-1]}) - for i in range(1, n-1): - a = randint(0, i//2) + D = DiGraph({0: [n - 1]}) + for i in range(1, n - 1): + a = randint(0, i // 2) b_ = list(D.depth_first_search(a)) - b = b_[randint(1, len(b_)-1)] + b = b_[randint(1, len(b_) - 1)] D.add_vertex(i) D.add_edge(a, i) D.add_edge(i, b) @@ -2053,19 +2058,19 @@ def _random_planar_lattice(n): """ from sage.misc.prandom import randint - G = DiGraph({0: [n-1]}) + G = DiGraph({0: [n - 1]}) while G.order() < n: - i = G.order()-1 - a = randint(0, i//2) + i = G.order() - 1 + a = randint(0, i // 2) b_ = list(G.depth_first_search(a)) - b = b_[randint(1, len(b_)-1)] + b = b_[randint(1, len(b_) - 1)] G1 = G.copy() G.add_vertex(i) G.add_edge(a, i) G.add_edge(i, b) G.delete_edge(a, b) G2 = G.copy() - G2.add_edge(n-1, 0) + G2.add_edge(n - 1, 0) if not G2.is_planar(): G = G1.copy() return G @@ -2102,7 +2107,7 @@ def _random_distributive_lattice(n): from sage.graphs.digraph_generators import digraphs if n < 4: - return digraphs.Path(n-1) + return digraphs.Path(n - 1) H = HasseDiagram({0: []}) while sum(1 for _ in H.antichains_iterator()) < n: @@ -2123,7 +2128,7 @@ def _random_distributive_lattice(n): for b in D.neighbors_out(to_delete): D.add_edge(a, b) D.delete_vertex(to_delete) - D.relabel({z:z-1 for z in range(to_delete + 1, D.order() + 1)}) + D.relabel({z: z - 1 for z in range(to_delete + 1, D.order() + 1)}) H = HasseDiagram(D) return D @@ -2177,4 +2182,5 @@ def _random_stone_lattice(n): return result + posets = Posets diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 2c236e4a4ae..98f7a13b1df 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -286,6 +286,7 @@ from __future__ import annotations from collections import defaultdict from copy import copy, deepcopy +from typing import List from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute @@ -765,7 +766,8 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio # Check for duplicate elements elif len(elements) != len(set(elements)): raise ValueError("the provided list of elements is not a linear " - "extension for the poset as it contains duplicate elements") + "extension for the poset as it contains " + "duplicate elements") else: elements = None return FinitePoset(D, elements=elements, category=category, facade=facade, key=key) @@ -2652,7 +2654,7 @@ def relations_number(self): # Maybe this should also be deprecated. intervals_number = relations_number - def linear_intervals_count(self) -> list[int]: + def linear_intervals_count(self) -> List[int]: """ Return the enumeration of linear intervals w.r.t. their cardinality. @@ -8106,7 +8108,7 @@ def is_eulerian(self, k=None, certificate=False): for rank_diff in range(2, k + 1, 2): for level in range(height - rank_diff): for i in levels[level]: - for j in levels[level+rank_diff]: + for j in levels[level + rank_diff]: if H.is_lequal(i, j) and M[i, j] != 1: if certificate: return (False, (self._vertex_to_element(i), @@ -8160,13 +8162,13 @@ def is_greedy(self, certificate=False): True """ H = self._hasse_diagram - N1 = H.order()-1 + N1 = H.order() - 1 it = H.greedy_linear_extensions_iterator() A = next(it) - A_jumps = sum(1 for i in range(N1) if H.has_edge(A[i], A[i+1])) + A_jumps = sum(1 for i in range(N1) if H.has_edge(A[i], A[i + 1])) for B in it: - B_jumps = sum(1 for i in range(N1) if H.has_edge(B[i], B[i+1])) + B_jumps = sum(1 for i in range(N1) if H.has_edge(B[i], B[i + 1])) if A_jumps != B_jumps: if certificate: if A_jumps > B_jumps: @@ -8452,13 +8454,15 @@ def p_partition_enumerator(self, tup, R, weights=None, check=False): # The simple case: ``weights == None``. F = QR.Fundamental() for lin in self.linear_extensions(facade=True): - descents = [i + 1 for i in range(n-1) if tupdict[lin[i]] > tupdict[lin[i+1]]] + descents = [i + 1 for i in range(n - 1) + if tupdict[lin[i]] > tupdict[lin[i + 1]]] res += F(Composition(from_subset=(descents, n))) return res for lin in self.linear_extensions(facade=True): M = QR.Monomial() lin_weights = Composition([weights.get(lin[i], 1) for i in range(n)]) - descents = [i + 1 for i in range(n-1) if tupdict[lin[i]] > tupdict[lin[i+1]]] + descents = [i + 1 for i in range(n - 1) + if tupdict[lin[i]] > tupdict[lin[i + 1]]] d_c = Composition(from_subset=(descents, n)) for comp in d_c.finer(): res += M[lin_weights.fatten(comp)] From 17ea8dd39a33b231c88b7ed59dc7b259b28baf34 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Fri, 16 Sep 2022 20:06:46 +0200 Subject: [PATCH 621/742] #34519 update doctest --- src/sage/misc/cachefunc.pyx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/misc/cachefunc.pyx b/src/sage/misc/cachefunc.pyx index c0691cff9c5..9fa967ce737 100644 --- a/src/sage/misc/cachefunc.pyx +++ b/src/sage/misc/cachefunc.pyx @@ -849,8 +849,6 @@ cdef class CachedFunction(): sage: print(sage_getdoc(I.groebner_basis)) # indirect doctest Return the reduced Groebner basis of this ideal. ... - ALGORITHM: Uses Singular, Magma (if available), Macaulay2 (if - available), Giac (if available), or a toy implementation. Test that :trac:`15184` is fixed:: From 2d8eb5caae28f95bc49d74ad82e3c2e28c6e105e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 16 Sep 2022 16:59:35 -0700 Subject: [PATCH 622/742] src/doc/en/installation/source.rst: Move python3 venv details to SPKG.rst --- build/pkgs/python3/SPKG.rst | 16 +++++++++++++++- src/doc/en/installation/source.rst | 18 ------------------ 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/build/pkgs/python3/SPKG.rst b/build/pkgs/python3/SPKG.rst index 10d444bd020..8c393d4a05b 100644 --- a/build/pkgs/python3/SPKG.rst +++ b/build/pkgs/python3/SPKG.rst @@ -4,7 +4,21 @@ python3: The Python programming language Description ----------- -The Python programming language +By default, Sage will try to use system's ``python3`` to set up a virtual +environment, a.k.a. `venv `_ +rather than building a Python 3 installation from scratch. + +Sage will accept versions 3.8.x to 3.10.x. + +You can also use ``--with-python=/path/to/python3_binary`` to tell Sage to use +``/path/to/python3_binary`` to set up the venv. Note that setting up venv requires +a number of Python modules to be available within the Python in question. Currently, +as of Sage 9.7, these modules are as follows: ``sqlite3``, ``ctypes``, ``math``, +``hashlib``, ``crypt``, ``socket``, ``zlib``, ``distutils.core``, ``ssl`` - +they will be checked for by the ``configure`` script. + +Use the ``configure`` option ``--without-system-python3`` in case you want Python 3 +built from scratch. Upstream Contact diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index 9d827e9ee06..fa322b13c4e 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -51,24 +51,6 @@ Your computer comes with at least 6 GB of free disk space. It is recommended to have at least 2 GB of RAM, but you might get away with less (be sure to have some swap space in this case). -Python for venv -^^^^^^^^^^^^^^^ - -By default, Sage will try to use system's ``python3`` to set up a virtual -environment, a.k.a. `venv `_ -rather than building a Python 3 installation from scratch. -Use the ``configure`` option ``--without-system-python3`` in case you want Python 3 -built from scratch. - -Sage will accept versions 3.8.x to 3.10.x. - -You can also use ``--with-python=/path/to/python3_binary`` to tell Sage to use -``/path/to/python3_binary`` to set up the venv. Note that setting up venv requires -a number of Python modules to be available within the Python in question. Currently, -for Sage 9.6, these modules are as follows: ``sqlite3``, ``ctypes``, ``math``, -``hashlib``, ``crypt``, ``socket``, ``zlib``, ``distutils.core``, ``ssl`` - -they will be checked for by the ``configure`` script. - Other notes ^^^^^^^^^^^ From 311d55b896ea0c115682d3247272614a246e4030 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 16 Sep 2022 17:51:23 -0700 Subject: [PATCH 623/742] README.md: Point to build/pkgs/{gcc,gfortran,_prereq}/SPKG.rst instead of install manual --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a06f57e5771..dc4139a8172 100644 --- a/README.md +++ b/README.md @@ -184,14 +184,20 @@ in the Installation Guide. - Compilers: `gcc`, `gfortran`, `g++` (GCC 8.x to 12.x and recent versions of Clang (LLVM) are supported). - See the Installation Manual for a discussion of suitable compilers. + See [build/pkgs/gcc/SPKG.rst](build/pkgs/gcc/SPKG.rst) and + [build/pkgs/gfortran/SPKG.rst](build/pkgs/gfortran/SPKG.rst) + for a discussion of suitable compilers. - Build tools: GNU `make`, GNU `m4`, `perl` (including ``ExtUtils::MakeMaker``), `ranlib`, `git`, `tar`, `bc`. + See [build/pkgs/_prereq/SPKG.rst](build/pkgs/_prereq/SPKG.rst) for + more details. - Python 3.4 or later, or Python 2.7, a full installation including `urllib`; but ideally version 3.8.x, 3.9.x, or 3.10.x, which will avoid having to build Sage's own copy of Python 3. + See [build/pkgs/python3/SPKG.rst](build/pkgs/python3/SPKG.rst) + for more details. We have collected lists of system packages that provide these build prerequisites. See, in the folder From 714db9cc200efbd2452f8c17f5ea4f9a082ecef2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 16 Sep 2022 18:16:15 -0700 Subject: [PATCH 624/742] src/doc/en/installation/source.rst: Get rid of defunct link https://www.sagemath.org/packages/optional/ --- src/doc/en/installation/source.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index fa322b13c4e..e750f44b0a3 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -549,7 +549,7 @@ General procedure serious consequences if you are logged in as root. Typing ``make`` performs the usual steps for each Sage's dependency, - but installs all the resulting files into the local build tree. + but installs all the resulting files into the installation prefix. Depending on the age and the architecture of your system, it can take from a few tens of minutes to several hours to build Sage from source. On really slow hardware, it can even take a few days to build Sage. @@ -714,9 +714,10 @@ General procedure Now typing ``sage`` within your terminal emulator should start Sage. #. Optional: - Install optional Sage packages and databases. - Type ``sage --optional`` to see a list of them (this requires an Internet - connection), or visit https://www.sagemath.org/packages/optional/. + Install optional Sage packages and databases. See `the list of optional packages + in the reference manual <../reference/spkg/index.html#optional-packages>`_ for + detailed information, or type ``sage --optional`` (this requires an Internet connection). + Then type ``sage -i `` to automatically download and install a given package. From 6b5a210ce77c3001449c50b9378b1cb04daf3a61 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 16 Sep 2022 19:02:59 -0700 Subject: [PATCH 625/742] src/doc/en/installation/source.rst: Move instructions how to check for prereqs to _prereq/SPKG.rst --- build/pkgs/_prereq/SPKG.rst | 13 +++++++++++++ src/doc/en/installation/source.rst | 13 ------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/build/pkgs/_prereq/SPKG.rst b/build/pkgs/_prereq/SPKG.rst index 279ace25843..686154277ef 100644 --- a/build/pkgs/_prereq/SPKG.rst +++ b/build/pkgs/_prereq/SPKG.rst @@ -37,3 +37,16 @@ programs are usually located in packages with their respective names. On Redhat-derived systems not all perl components are installed by default and you might have to install the ``perl-ExtUtils-MakeMaker`` package. + +To check if you have the above prerequisites installed, for example ``perl``, +type:: + + $ command -v perl + +or:: + + $ which perl + +on the command line. If it gives an error (or returns nothing), then +either ``perl`` is not installed, or it is installed but not in your +:wikipedia:`PATH `. diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index e750f44b0a3..7baf30c7fbd 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -91,19 +91,6 @@ you would use Installing prerequisites ~~~~~~~~~~~~~~~~~~~~~~~~ -To check if you have the above prerequisites installed, for example ``perl``, -type:: - - $ command -v perl - -or:: - - $ which perl - -on the command line. If it gives an error (or returns nothing), then -either ``perl`` is not installed, or it is installed but not in your -:wikipedia:`PATH `. - .. _sec-installation-from-sources-linux-recommended-installation: Debian/Ubuntu prerequisite installation From 435f27524ecc96e908cb938e0022e3312f3cb655 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 16 Sep 2022 19:38:45 -0700 Subject: [PATCH 626/742] src/doc/en/installation/source.rst: Add links to the SPKG.rst files, rewrite prereq/recommended instructions --- src/doc/en/installation/source.rst | 145 +++++++++++++++++------------ 1 file changed, 84 insertions(+), 61 deletions(-) diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index 7baf30c7fbd..3b72a7d4e89 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -38,12 +38,6 @@ will not need to read them. Prerequisites ------------- -General requirements -~~~~~~~~~~~~~~~~~~~~ - -This section details the technical prerequisites needed on all platforms. See -also the `System-specific requirements`_ below. - Disk space and memory ^^^^^^^^^^^^^^^^^^^^^ @@ -51,60 +45,76 @@ Your computer comes with at least 6 GB of free disk space. It is recommended to have at least 2 GB of RAM, but you might get away with less (be sure to have some swap space in this case). -Other notes -^^^^^^^^^^^ +Software prerequisites and recommended packages +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -After extracting the Sage source tarball, the subdirectory :file:`upstream` -contains the source distributions for everything on which Sage depends. +Sage depends on `a large number of software packages +<../reference/spkg/index.html>`_. Sage provides its own software +distribution providing most of these packages, so you do not have to +worry about having to download and install these packages yourself. -If cloned from a git repository, the upstream tarballs will be downloaded, -verified, and cached as part of the Sage installation process. -We emphasize that all of this software is included with Sage, so you do not -have to worry about trying to download and install any one of these packages -(such as Python, for example) yourself. +If you extracted Sage from a source tarball, the subdirectory +:file:`upstream` contains the source distributions for all standard +packages on which Sage depends. If cloned from a git repository, the +upstream tarballs will be downloaded, verified, and cached as part of +the Sage installation process. -When the Sage installation program is run, -it will check that you have each of the above-listed prerequisites, -and inform you of any that are missing, or have unsuitable versions. +However, there are minimal prerequisites for building Sage that +already must be installed on your system: -System-specific requirements -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- `Fundamental system packages required for installing from source + <../reference/spkg/_prereq>`_ -On macOS, there are various developer tools needed which may require -some registration on Apple's developer site; see -:ref:`section_macprereqs`. +- `C/C++ compilers <../reference/spkg/gcc>`_ -On Linux systems (e.g., Ubuntu, Redhat, etc), -Assuming you have sufficient privileges, you can install the ``binutils`` and -other necessary/standard components. The lists provided below are longer than -the minimal prerequisites, which are basically ``binutils``, ``gcc``/``clang``, ``make``, -``tar``, but there is no real need to build compilers and other standard tools -and libraries on a modern Linux system, in order to be able to build Sage. +If you have the sufficient privileges (for example, on Linux you can +use ``sudo`` to become the ``root`` user), then you can install these packages +using the commands for your platform indicated in the pages linked above. If you do not have the privileges to do this, ask your system administrator to -do this, or build the components from source code. -The method of installing additional software varies from distribution to -distribution, but on a `Debian `_ based system (e.g. -`Ubuntu `_ or `Mint `_), -you would use -:wikipedia:`apt-get `. +do this for you. + +In addition to these minimal prerequisites, we strongly recommend to use system +installations of the following: + +- `Fortran compiler <../reference/spkg/gfortran>`_ + +- `Python <../reference/spkg/python3>`_ + +Sage developers will also need the `system packages required for +bootstrapping <../reference/spkg/_bootstrap>`_; they cannot be +installed by Sage. + +When the ``./configure`` script runs, it will check for the presence of many +packages (including the above) and inform you of any that are +missing, or have unsuitable versions. **Please read the messages that +``./configure`` prints:** It will inform you which additional system packages +you can install to avoid having to build them from source. This can save a lot of +time. + +The following sections provide the commands to install a large +recommended set of packages on various systems, which will minimize +the time it takes to build Sage. This is intended as a convenient +shortcut, but of course you can choose to take a more fine-grained +approach. -Installing prerequisites -~~~~~~~~~~~~~~~~~~~~~~~~ .. _sec-installation-from-sources-linux-recommended-installation: -Debian/Ubuntu prerequisite installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Debian/Ubuntu package installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -On Debian ("buster" or newer) or Ubuntu ("bionic" or newer): +On Debian ("buster" or newer) or Ubuntu ("bionic" or newer), we recommend that you +install: .. literalinclude:: debian.txt -If you wish to do Sage development, additionally install the following: +If you wish to do Sage development, we recommend that you additionally +install the following: .. literalinclude:: debian-develop.txt -For all users, we recommend the following: +For all users, we recommend that you install the following system packages, +which provide additional functionality and cannot be installed by Sage: .. literalinclude:: debian-recommended.txt @@ -114,16 +124,20 @@ install: .. literalinclude:: debian-optional.txt -Fedora/Redhat/CentOS prerequisite installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Fedora/Redhat/CentOS package installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On Fedora/Redhat/CentOS, we recommend that you install: .. literalinclude:: fedora.txt -If you wish to do Sage development, additionally install the following: +If you wish to do Sage development, we recommend that you additionally +install the following: .. literalinclude:: fedora-develop.txt -For all users, we recommend the following: +For all users, we recommend that you install the following system packages, +which provide additional functionality and cannot be installed by Sage: .. literalinclude:: fedora-recommended.txt @@ -133,16 +147,20 @@ install: .. literalinclude:: fedora-optional.txt -Arch Linux prerequisite installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Arch Linux package installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On ArchLinux, we recommend that you install: .. literalinclude:: arch.txt -If you wish to do Sage development, additionally install the following: +If you wish to do Sage development, we recommend that you additionally +install the following: .. literalinclude:: arch-develop.txt -For all users, we recommend the following: +For all users, we recommend that you install the following system packages, +which provide additional functionality and cannot be installed by Sage: .. literalinclude:: arch-recommended.txt @@ -152,16 +170,20 @@ install: .. literalinclude:: arch-optional.txt -OpenSUSE prerequisite installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +OpenSUSE package installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On OpenSUSE, we recommend that you install: .. literalinclude:: opensuse.txt -If you wish to do Sage development, additionally install the following: +If you wish to do Sage development, we recommend that you additionally +install the following: .. literalinclude:: opensuse-develop.txt -For all users, we recommend the following: +For all users, we recommend that you install the following system packages, +which provide additional functionality and cannot be installed by Sage: .. literalinclude:: opensuse-recommended.txt @@ -173,8 +195,8 @@ install: .. _section_macprereqs: -macOS prerequisite installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +macOS prerequisites +^^^^^^^^^^^^^^^^^^^ On macOS systems, you need a recent version of `Command Line Tools `_. @@ -203,9 +225,8 @@ a registration. to Command Line Tools. - -macOS recommended installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +macOS package installation +^^^^^^^^^^^^^^^^^^^^^^^^^^ If you use the `Homebrew package manager `_, you can install the following: @@ -222,11 +243,13 @@ Sage, run :: command like this to your shell profile if you want the settings to persist between shell sessions. -If you wish to do Sage development, additionally install the following: +If you wish to do Sage development, we recommend that you additionally +install the following: .. literalinclude:: homebrew-develop.txt -For all users, we recommend the following: +For all users, we recommend that you install the following system packages, +which provide additional functionality and cannot be installed by Sage: .. literalinclude:: homebrew-recommended.txt From 0bf7d8af580b1644036ec666dd76ade047f0cf68 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 16 Sep 2022 20:17:05 -0700 Subject: [PATCH 627/742] src/doc/en/installation/source.rst: Update timestamp --- src/doc/en/installation/source.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index 3b72a7d4e89..6be356076b4 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -1189,4 +1189,4 @@ a single copy of Sage in a multi-user computer network. $ sudo chown -R root SAGE_LOCAL -**This page was last updated in May 2022 (Sage 9.7).** +**This page was last updated in September 2022 (Sage 9.8).** From 59ac11a9375feaada4486b63ed9900651e0a6fdb Mon Sep 17 00:00:00 2001 From: Release Manager Date: Sat, 17 Sep 2022 11:36:29 +0200 Subject: [PATCH 628/742] Updated SageMath version to 9.7.rc2 --- .zenodo.json | 8 ++++---- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/sage_conf/install-requires.txt | 2 +- build/pkgs/sage_docbuild/install-requires.txt | 2 +- build/pkgs/sage_setup/install-requires.txt | 2 +- build/pkgs/sage_sws2rst/install-requires.txt | 2 +- build/pkgs/sagelib/install-requires.txt | 2 +- build/pkgs/sagemath_categories/install-requires.txt | 2 +- build/pkgs/sagemath_environment/install-requires.txt | 2 +- build/pkgs/sagemath_objects/install-requires.txt | 2 +- pkgs/sage-conf/VERSION.txt | 2 +- pkgs/sage-conf_pypi/VERSION.txt | 2 +- pkgs/sage-docbuild/VERSION.txt | 2 +- pkgs/sage-setup/VERSION.txt | 2 +- pkgs/sage-sws2rst/VERSION.txt | 2 +- pkgs/sagemath-categories/VERSION.txt | 2 +- pkgs/sagemath-environment/VERSION.txt | 2 +- pkgs/sagemath-objects/VERSION.txt | 2 +- pkgs/sagemath-repl/VERSION.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 24 files changed, 33 insertions(+), 33 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index d7b2439a788..49b22d68dc7 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,10 +1,10 @@ { "description": "Mirror of the Sage https://sagemath.org/ source tree", "license": "other-open", - "title": "sagemath/sage: 9.7.rc1", - "version": "9.7.rc1", + "title": "sagemath/sage: 9.7.rc2", + "version": "9.7.rc2", "upload_type": "software", - "publication_date": "2022-09-07", + "publication_date": "2022-09-17", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.7.rc1", + "identifier": "https://github.com/sagemath/sage/tree/9.7.rc2", "relation": "isSupplementTo" }, { diff --git a/VERSION.txt b/VERSION.txt index affcafdf359..b63eff86bef 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.7.rc1, Release Date: 2022-09-07 +SageMath version 9.7.rc2, Release Date: 2022-09-17 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index ec99cd206cc..48189ef845c 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=fae7f3b6b614f4317d549df685c71f3d73266f53 -md5=b5f77a97a8ef2f292a0413af8fce6b4b -cksum=1358596786 +sha1=70b1e96e1bd71efd90b1d1345b9c8d4d12de432b +md5=bf9529bff5e1c938c51668f0687ae5a0 +cksum=1982975454 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index c1a4e286897..37da2e9a6db 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -d049cd8b3d2b86dc91acfca862daee4d105099c7 +4f225f4cc66a7d515ea6598ebe9b2ff48e114a15 diff --git a/build/pkgs/sage_conf/install-requires.txt b/build/pkgs/sage_conf/install-requires.txt index 806746abbe4..496914816ad 100644 --- a/build/pkgs/sage_conf/install-requires.txt +++ b/build/pkgs/sage_conf/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 9.7rc1 +sage-conf ~= 9.7rc2 diff --git a/build/pkgs/sage_docbuild/install-requires.txt b/build/pkgs/sage_docbuild/install-requires.txt index 9a762283dae..56ba1015d98 100644 --- a/build/pkgs/sage_docbuild/install-requires.txt +++ b/build/pkgs/sage_docbuild/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 9.7rc1 +sage-docbuild ~= 9.7rc2 diff --git a/build/pkgs/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt index 72ddc44f5ef..60e2ed2c881 100644 --- a/build/pkgs/sage_setup/install-requires.txt +++ b/build/pkgs/sage_setup/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 9.7rc1 +sage-setup ~= 9.7rc2 diff --git a/build/pkgs/sage_sws2rst/install-requires.txt b/build/pkgs/sage_sws2rst/install-requires.txt index 0c11aa3cd0d..47283b61993 100644 --- a/build/pkgs/sage_sws2rst/install-requires.txt +++ b/build/pkgs/sage_sws2rst/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 9.7rc1 +sage-sws2rst ~= 9.7rc2 diff --git a/build/pkgs/sagelib/install-requires.txt b/build/pkgs/sagelib/install-requires.txt index 17a9b7fbd9e..d009d8b4834 100644 --- a/build/pkgs/sagelib/install-requires.txt +++ b/build/pkgs/sagelib/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagelib ~= 9.7rc1 +sagelib ~= 9.7rc2 diff --git a/build/pkgs/sagemath_categories/install-requires.txt b/build/pkgs/sagemath_categories/install-requires.txt index faa6593b049..984fcd77cb0 100644 --- a/build/pkgs/sagemath_categories/install-requires.txt +++ b/build/pkgs/sagemath_categories/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 9.7rc1 +sagemath-categories ~= 9.7rc2 diff --git a/build/pkgs/sagemath_environment/install-requires.txt b/build/pkgs/sagemath_environment/install-requires.txt index 9dd9d149e08..6de5c339724 100644 --- a/build/pkgs/sagemath_environment/install-requires.txt +++ b/build/pkgs/sagemath_environment/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 9.7rc1 +sagemath-environment ~= 9.7rc2 diff --git a/build/pkgs/sagemath_objects/install-requires.txt b/build/pkgs/sagemath_objects/install-requires.txt index 7d5feaa7bb8..614677a4a19 100644 --- a/build/pkgs/sagemath_objects/install-requires.txt +++ b/build/pkgs/sagemath_objects/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 9.7rc1 +sagemath-objects ~= 9.7rc2 diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index 37d25ab1334..13ac8fa02e9 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -9.7.rc1 +9.7.rc2 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index 37d25ab1334..13ac8fa02e9 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -9.7.rc1 +9.7.rc2 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index 37d25ab1334..13ac8fa02e9 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -9.7.rc1 +9.7.rc2 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index 37d25ab1334..13ac8fa02e9 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -9.7.rc1 +9.7.rc2 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index 37d25ab1334..13ac8fa02e9 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -9.7.rc1 +9.7.rc2 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index 37d25ab1334..13ac8fa02e9 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -9.7.rc1 +9.7.rc2 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index 37d25ab1334..13ac8fa02e9 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -9.7.rc1 +9.7.rc2 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index 37d25ab1334..13ac8fa02e9 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -9.7.rc1 +9.7.rc2 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index 37d25ab1334..13ac8fa02e9 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -9.7.rc1 +9.7.rc2 diff --git a/src/VERSION.txt b/src/VERSION.txt index 37d25ab1334..13ac8fa02e9 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.7.rc1 +9.7.rc2 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index a18cc712d08..6f4e41fabfc 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.7.rc1' -SAGE_RELEASE_DATE='2022-09-07' -SAGE_VERSION_BANNER='SageMath version 9.7.rc1, Release Date: 2022-09-07' +SAGE_VERSION='9.7.rc2' +SAGE_RELEASE_DATE='2022-09-17' +SAGE_VERSION_BANNER='SageMath version 9.7.rc2, Release Date: 2022-09-17' diff --git a/src/sage/version.py b/src/sage/version.py index 4862a5603a6..8e72819281d 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '9.7.rc1' -date = '2022-09-07' -banner = 'SageMath version 9.7.rc1, Release Date: 2022-09-07' +version = '9.7.rc2' +date = '2022-09-17' +banner = 'SageMath version 9.7.rc2, Release Date: 2022-09-17' From debca31b188013b645644f70905144863c5c56c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Fri, 29 Jul 2022 11:36:53 +0530 Subject: [PATCH 629/742] Update docker build The docker images are using Ubuntu impish. We should instead build against the latest LTS version jammy. Also, the README on Docker Hub is quite outdated. Finally, we drop the CircleCI setup here. To my knowledge nobody is using it and I it's likely broken by now anyway. --- .circleci/before-script.sh | 26 ----------- .circleci/config.yml | 89 -------------------------------------- docker/Dockerfile | 32 +++++++++++++- docker/README.md | 12 ++--- 4 files changed, 36 insertions(+), 123 deletions(-) delete mode 100644 .circleci/before-script.sh delete mode 100644 .circleci/config.yml diff --git a/.circleci/before-script.sh b/.circleci/before-script.sh deleted file mode 100644 index 3b9c7949cd4..00000000000 --- a/.circleci/before-script.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -# Source this script during a CI run to set environment variables and print -# some informational messages about the system we are running on. - -# **************************************************************************** -# Copyright (C) 2018 Julian Rüth -# -# 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/ -# **************************************************************************** - -# CircleCI has no mechanism to hide secret variables. -# Therefore we roll our own to protect $SECRET_* variables. -. .ci/protect-secrets.sh -# Collect debug infos about the system we are running on -.ci/describe-system.sh -# Set MAKEFLAGS and SAGE_NUM_THREADS -. .ci/setup-make-parallelity.sh - -# Set DOCKER_TAG according to the current branch/tag -export DOCKER_TAG=${CIRCLE_TAG:-$CIRCLE_BRANCH} -. .ci/update-env.sh diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 2b425783ce6..00000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,89 +0,0 @@ -# This file configures automatic builds of Sage on [CircleCI](https://circleci.com). -# To make the build time not too excessive, we seed the build cache with -# sagemath/sagemath-dev:develop. When basic SPKGs change, this does not help much, -# as the full build will often exceed CircleCI's limits for open source -# projcets (five hours on 2 vCPUs as of early 2018.) -# You might want to try to build locally or with GitLab CI, see -# `.gitlab-ci.yml` for more options. - -# As of early 2018, a run on CircleCI takes usually about 25 minutes. Most of -# the time is spent pulling/pushing from/to Docker Hub and copying files -# locally during the docker build. We could probably save five minutes by not -# building and testing the sagemath-dev image for most branches. - -version: 2 -jobs: - build-test-release: &build-test-release - docker: - - image: docker:latest - environment: - DEFAULT_ARTIFACT_BASE: sagemath/sagemath-dev:develop - steps: - - run: apk --update add git openssh - - checkout - - setup_remote_docker: - version: 18.05.0-ce - - run: &build - # The docker commands sometimes take a while to produce output - no_output_timeout: 30m - name: build - command: | - . .circleci/before-script.sh - .ci/build-docker.sh - - run: &test-dev - name: test-dev - command: | - . .circleci/before-script.sh - .ci/test-dev.sh $DOCKER_IMAGE_DEV - - run: &test-cli - name: test-cli - command: | - . .circleci/before-script.sh - .ci/test-cli.sh $DOCKER_IMAGE_CLI - - run: &test-jupyter - name: test-jupyter - command: | - . .circleci/before-script.sh - .ci/test-jupyter.sh $DOCKER_IMAGE_CLI localhost - - run: &release - # The docker commands sometimes take a while to produce output - no_output_timeout: 30m - name: release - command: | - . .circleci/before-script.sh - # Push docker images to dockerhub if a dockerhub user has been configured - .ci/push-dockerhub.sh sagemath-dev - .ci/push-dockerhub.sh sagemath - build-from-latest-test-release: - <<: *build-test-release - build-from-clean-test-release: - <<: *build-test-release - environment: - ARTIFACT_BASE: source-clean - -workflows: - version: 2 - build-branch-from-clean: - jobs: - - build-from-clean-test-release: - filters: - branches: - only: - - master - - develop - build-tag-from-clean: - jobs: - - build-from-clean-test-release: - filters: - branches: - ignore: /.*/ - tags: - only: /.*/ - build-branch-from-latest: - jobs: - - build-from-latest-test-release: - filters: - branches: - ignore: - - master - - develop diff --git a/docker/Dockerfile b/docker/Dockerfile index 269b4667ed9..bf14547cd38 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -41,12 +41,40 @@ # local branch for this to work. # ################################################################################ +################################################################################ +# HOWTO use this file to manually create new images for Docker Hub # +################################################################################ +# Make sure you have the tag checked out that you are trying to build. Then # +# from the root directory of the sage repository run: # +# # +# bash # open a subshell so 'set -e' does not close your shell on error # +# export ARTIFACT_BASE=source-clean # +# export DOCKER_TAG=9.6 # replace with the version you are building for # +# export CI_COMMIT_SHA=`git rev-parse --short HEAD` # +# export CPUTHREADS=8 # +# export RAMTHREADS=8 # +# export RAMTHREADS_DOCBUILD=8 # +# . .ci/update-env.sh # +# . .ci/setup-make-parallelity.sh # +# .ci/build-docker.sh # +# # +# Now you can push the relevant images to the Docker Hub: # +# # +# docker push sagemath/sagemath:$DOCKER_TAG # +# docker tag sagemath/sagemath:$DOCKER_TAG sagemath/sagemath:latest # +# docker push sagemath/sagemath:latest # +# docker push sagemath/sagemath-dev:$DOCKER_TAG # +# docker tag sagemath/sagemath-dev:$DOCKER_TAG sagemath/sagemath-dev:latest # +# docker push sagemath/sagemath-dev:latest # +################################################################################ + + ARG ARTIFACT_BASE=source-clean ################################################################################ # Image containing the run-time dependencies for Sage # ################################################################################ -FROM ubuntu:impish as run-time-dependencies +FROM ubuntu:jammy as run-time-dependencies LABEL maintainer="Erik M. Bray , Julian Rüth " # Set sane defaults for common environment variables. ENV LC_ALL C.UTF-8 @@ -82,7 +110,7 @@ WORKDIR $HOME FROM run-time-dependencies as build-time-dependencies # Install the build time dependencies & git & rdfind RUN sudo apt-get -qq update \ - && sudo apt-get -qq install -y wget build-essential automake m4 dpkg-dev python libssl-dev git rdfind \ + && sudo apt-get -qq install -y wget build-essential automake m4 dpkg-dev python3 libssl-dev git rdfind \ && sudo apt-get -qq clean \ && sudo rm -r /var/lib/apt/lists/* diff --git a/docker/README.md b/docker/README.md index e77008fc886..b1a674e2482 100644 --- a/docker/README.md +++ b/docker/README.md @@ -4,8 +4,8 @@ * `latest` — the stable `master` branch [![GitHub last commit (branch)](https://img.shields.io/github/last-commit/sagemath/sage/master.svg)](https://github.com/sagemath/sage/commits/master) [![GitLab CI](https://gitlab.com/sagemath/sage/badges/master/pipeline.svg)](https://gitlab.com/sagemath/sage/commits/master) * `x.x` — all stable releases of Sage are tagged with their version number. -* `x.x.{beta,rc}x` - betas and release candidates of Sage as [tagged in our git repository](https://github.com/sagemath/sage/tags). -* `develop` — the current development version of Sage which gets merged into the `master` branch when a new version of Sage is released [![GitHub last commit (branch)](https://img.shields.io/github/last-commit/sagemath/sage/develop.svg)](https://github.com/sagemath/sage/commits/develop) [![GitLab CI](https://gitlab.com/sagemath/sage/badges/develop/pipeline.svg)](https://gitlab.com/sagemath/sage/commits/develop) +* `x.x.{beta,rc}x` - betas and release candidates of Sage as [tagged in our git repository](https://github.com/sagemath/sage/tags); since docker images are built and uploaded manually at the moment, there are often no recent betas here anymore. +* `develop` — the current development version of Sage which gets merged into the `master` branch when a new version of Sage is released [![GitHub last commit (branch)](https://img.shields.io/github/last-commit/sagemath/sage/develop.svg)](https://github.com/sagemath/sage/commits/develop) [![GitLab CI](https://gitlab.com/sagemath/sage/badges/develop/pipeline.svg)](https://gitlab.com/sagemath/sage/commits/develop); again, there is often no recent develop built here anymore. * `-py3` - until Sage 9.1, we provided Python 2 builds (with no suffix) and Python 3 builds (with the `-py3` suffix). From Sage 9.2.beta0 on, all images we provide are based on Python 3 and the `-py3` suffix survives only for historical reasons: with or without it, you get Python 3. # What is SageMath @@ -26,7 +26,7 @@ There are several flavours of this image. ``` docker run -p8888:8888 sagemath/sagemath:latest sage-jupyter ``` -* [`sagemath/sagemath-dev`![image size](https://img.shields.io/microbadger/image-size/sagemath/sagemath-dev.svg)](https://hub.docker.com/r/sagemath/sagemath-dev) contains all the build artifacts to rebuild Sage quickly. This version is probably only relevant for Sage developers. Run this image with: +* [`sagemath/sagemath-dev`![image size](https://img.shields.io/microbadger/image-size/sagemath/sagemath-dev.svg)](https://hub.docker.com/r/sagemath/sagemath-dev) contains all the build artifacts to rebuild Sage quickly (currently, this is broken, see [#34241](https://trac.sagemath.org/ticket/34241#comment).) This version is probably only relevant for Sage developers. Run this image with: ``` docker run -it sagemath/sagemath-dev:develop ``` @@ -41,11 +41,11 @@ Run `docker build -f docker/Dockerfile --build-arg ARTIFACT_BASE=sagemath/sagema # How these images get updated -Every push to our [github repository](https://github.com/sagemath/sage) triggers a "build" on our [Docker Hub](https://hub.docker.com) repositories. This build is mostly disabled by the `hooks/` and only updates the `README.md`. +Currently, these images are updated manually after every release. Instructions for this are at the top of `docker/Dockerfile`. -Every push to our [GitLab repository](https://gitlab.com/sagemath/sage) triggers a pipeline in GitLab CI which pushes the actual images to Docker Hub. +Every push to our [GitLab repository](https://gitlab.com/sagemath/sage) used to trigger a pipeline in GitLab CI which pushed the actual images to Docker Hub. These pipelines are not running anymore since nobody is maintaining them or providing the CI resources for it. -Have a look at `.circleci/` and `.gitlab-ci.yml` if you want to setup CircleCI or GitLab CI for your own fork of the SageMath repository. +Have a look at `.gitlab-ci.yml` if you want to setup CircleCI or GitLab CI for your own fork of the SageMath repository. # Report bugs and issues From 417ca3104a5d3c729dc6ba223c06356b88745308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Fri, 29 Jul 2022 11:42:52 +0530 Subject: [PATCH 630/742] Fix grammar --- docker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/README.md b/docker/README.md index b1a674e2482..05aa89ebae0 100644 --- a/docker/README.md +++ b/docker/README.md @@ -5,7 +5,7 @@ * `latest` — the stable `master` branch [![GitHub last commit (branch)](https://img.shields.io/github/last-commit/sagemath/sage/master.svg)](https://github.com/sagemath/sage/commits/master) [![GitLab CI](https://gitlab.com/sagemath/sage/badges/master/pipeline.svg)](https://gitlab.com/sagemath/sage/commits/master) * `x.x` — all stable releases of Sage are tagged with their version number. * `x.x.{beta,rc}x` - betas and release candidates of Sage as [tagged in our git repository](https://github.com/sagemath/sage/tags); since docker images are built and uploaded manually at the moment, there are often no recent betas here anymore. -* `develop` — the current development version of Sage which gets merged into the `master` branch when a new version of Sage is released [![GitHub last commit (branch)](https://img.shields.io/github/last-commit/sagemath/sage/develop.svg)](https://github.com/sagemath/sage/commits/develop) [![GitLab CI](https://gitlab.com/sagemath/sage/badges/develop/pipeline.svg)](https://gitlab.com/sagemath/sage/commits/develop); again, there is often no recent develop built here anymore. +* `develop` — the current development version of Sage which gets merged into the `master` branch when a new version of Sage is released [![GitHub last commit (branch)](https://img.shields.io/github/last-commit/sagemath/sage/develop.svg)](https://github.com/sagemath/sage/commits/develop) [![GitLab CI](https://gitlab.com/sagemath/sage/badges/develop/pipeline.svg)](https://gitlab.com/sagemath/sage/commits/develop); again, there is often no recent develop build here anymore. * `-py3` - until Sage 9.1, we provided Python 2 builds (with no suffix) and Python 3 builds (with the `-py3` suffix). From Sage 9.2.beta0 on, all images we provide are based on Python 3 and the `-py3` suffix survives only for historical reasons: with or without it, you get Python 3. # What is SageMath From 27910f11cd88e65a355919039cb61d1af8dd3b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Fri, 29 Jul 2022 11:43:34 +0530 Subject: [PATCH 631/742] Link to trac ticket correctly in README --- docker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/README.md b/docker/README.md index 05aa89ebae0..c3145f8e90e 100644 --- a/docker/README.md +++ b/docker/README.md @@ -26,7 +26,7 @@ There are several flavours of this image. ``` docker run -p8888:8888 sagemath/sagemath:latest sage-jupyter ``` -* [`sagemath/sagemath-dev`![image size](https://img.shields.io/microbadger/image-size/sagemath/sagemath-dev.svg)](https://hub.docker.com/r/sagemath/sagemath-dev) contains all the build artifacts to rebuild Sage quickly (currently, this is broken, see [#34241](https://trac.sagemath.org/ticket/34241#comment).) This version is probably only relevant for Sage developers. Run this image with: +* [`sagemath/sagemath-dev`![image size](https://img.shields.io/microbadger/image-size/sagemath/sagemath-dev.svg)](https://hub.docker.com/r/sagemath/sagemath-dev) contains all the build artifacts to rebuild Sage quickly (currently, this is broken, see [#34241](https://trac.sagemath.org/ticket/34241).) This version is probably only relevant for Sage developers. Run this image with: ``` docker run -it sagemath/sagemath-dev:develop ``` From f1f5a0f8020ee446f76927cf568eb35655edfb8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Fri, 29 Jul 2022 11:45:18 +0530 Subject: [PATCH 632/742] Let volunteers know that they are welcome to help with docker --- docker/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/README.md b/docker/README.md index c3145f8e90e..eb0f1ba344d 100644 --- a/docker/README.md +++ b/docker/README.md @@ -43,9 +43,9 @@ Run `docker build -f docker/Dockerfile --build-arg ARTIFACT_BASE=sagemath/sagema Currently, these images are updated manually after every release. Instructions for this are at the top of `docker/Dockerfile`. -Every push to our [GitLab repository](https://gitlab.com/sagemath/sage) used to trigger a pipeline in GitLab CI which pushed the actual images to Docker Hub. These pipelines are not running anymore since nobody is maintaining them or providing the CI resources for it. +Every push to our [GitLab repository](https://gitlab.com/sagemath/sage) used to trigger a pipeline in GitLab CI which pushed the actual images to Docker Hub. These pipelines are not running anymore since nobody is maintaining them or providing the CI resources for it. (Please reach out to [sage-devel](https://groups.google.com/forum/#!forum/sage-devel) if you want to help!) -Have a look at `.gitlab-ci.yml` if you want to setup CircleCI or GitLab CI for your own fork of the SageMath repository. +Have a look at `.gitlab-ci.yml` if you want to setup GitLab CI for your own fork of the SageMath repository. # Report bugs and issues From 77cbf42a5eafaadd08caa449155f6b429e3078c0 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sat, 17 Sep 2022 08:48:35 -0500 Subject: [PATCH 633/742] PEP8 compliance --- .../polynomial/infinite_polynomial_element.py | 249 +++++++++--------- 1 file changed, 128 insertions(+), 121 deletions(-) diff --git a/src/sage/rings/polynomial/infinite_polynomial_element.py b/src/sage/rings/polynomial/infinite_polynomial_element.py index 3a88f14b727..ac21b71553f 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_element.py +++ b/src/sage/rings/polynomial/infinite_polynomial_element.py @@ -165,7 +165,7 @@ def InfinitePolynomial(A, p): """ from sage.structure.element import parent - if hasattr(A,'_P'): + if hasattr(A, '_P'): if parent(p) is A._P or (A._P.base_ring().has_coerce_map_from(parent(p))): return InfinitePolynomial_dense(A, p) # MPolynomialRing_polydict is crab. So, in that case, use sage_eval @@ -173,14 +173,14 @@ def InfinitePolynomial(A, p): if isinstance(A._P, MPolynomialRing_polydict): from sage.rings.polynomial.infinite_polynomial_ring import GenDictWithBasering from sage.misc.sage_eval import sage_eval - p = sage_eval(repr(p), GenDictWithBasering(A._P,A._P.gens_dict())) + p = sage_eval(repr(p), GenDictWithBasering(A._P, A._P.gens_dict())) return InfinitePolynomial_dense(A, p) else: # Now there remains to fight the oddities and bugs of libsingular. PP = p.parent() if A._P.has_coerce_map_from(PP): - if A._P.ngens() == PP.ngens(): # coercion is sometimes by position! - f = PP.hom(PP.variable_names(),A._P) + if A._P.ngens() == PP.ngens(): # coercion is sometimes by position! + f = PP.hom(PP.variable_names(), A._P) try: return InfinitePolynomial_dense(A, f(p)) except (ValueError, TypeError): @@ -205,6 +205,7 @@ def InfinitePolynomial(A, p): return InfinitePolynomial_dense(A, sage_eval(repr(p), GenDictWithBasering(A._P, A._P.gens_dict()))) return InfinitePolynomial_sparse(A, p) + class InfinitePolynomial_sparse(RingElement): """ Element of a sparse Polynomial Ring with a Countably Infinite Number of Variables. @@ -317,8 +318,8 @@ def __call__(self, *args, **kwargs): x_100 + x_0 """ - #Replace any InfinitePolynomials by their underlying polynomials - if hasattr(self._p,'variables'): + # Replace any InfinitePolynomials by their underlying polynomials + if hasattr(self._p, 'variables'): V = [str(x) for x in self._p.variables()] else: V = [] @@ -327,19 +328,19 @@ def __call__(self, *args, **kwargs): if isinstance(value, InfinitePolynomial_sparse): kwargs[kw] = value._p V.append(kw) - if hasattr(value._p,'variables'): + if hasattr(value._p, 'variables'): V.extend([str(x) for x in value._p.variables()]) args = list(args) for i, arg in enumerate(args): if isinstance(arg, InfinitePolynomial_sparse): args[i] = arg._p - if hasattr(arg._p,'variables'): + if hasattr(arg._p, 'variables'): V.extend([str(x) for x in arg._p.variables()]) - V=list(set(V)) + V = list(set(V)) V.sort(key=self.parent().varname_key, reverse=True) if V: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(self._p.base_ring(),V,order=self.parent()._order) + R = PolynomialRing(self._p.base_ring(), V, order=self.parent()._order) else: return self res = R(self._p)(*args, **kwargs) @@ -422,14 +423,15 @@ def __getattr__(self, s): True """ - if s=='__members__': + if s == '__members__': return dir(self._p) - if s=='__methods__': - return [X for X in dir(self._p) if hasattr(self._p,X) and ('method' in str(type(getattr(self._p,X))))] + if s == '__methods__': + return [X for X in dir(self._p) if hasattr(self._p, X) + and ('method' in str(type(getattr(self._p, X))))] try: - return getattr(self._p,s) + return getattr(self._p, s) except AttributeError: - raise AttributeError('%s has no attribute %s'%(self.__class__, s)) + raise AttributeError('%s has no attribute %s' % (self.__class__, s)) def ring(self): """ @@ -566,19 +568,19 @@ def _add_(self, x): """ # One may need a new parent for self._p and x._p try: - return InfinitePolynomial_sparse(self.parent(),self._p+x._p) + return InfinitePolynomial_sparse(self.parent(), self._p + x._p) except Exception: pass - ## We can now assume that self._p and x._p actually are polynomials, - ## hence, their parent is not simply the underlying ring. + # We can now assume that self._p and x._p actually are polynomials, + # hence, their parent is not simply the underlying ring. VarList = list(set(self._p.parent().variable_names()).union(set(x._p.parent().variable_names()))) VarList.sort(key=self.parent().varname_key, reverse=True) if VarList: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(self._p.base_ring(),VarList,order=self.parent()._order) + R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) else: R = self._p.base_ring() - return InfinitePolynomial_sparse(self.parent(),R(self._p) + R(x._p)) + return InfinitePolynomial_sparse(self.parent(), R(self._p) + R(x._p)) def _mul_(self, x): """ @@ -590,19 +592,19 @@ def _mul_(self, x): """ try: - return InfinitePolynomial_sparse(self.parent(),self._p*x._p) + return InfinitePolynomial_sparse(self.parent(), self._p * x._p) except Exception: pass - ## We can now assume that self._p and x._p actually are polynomials, - ## hence, their parent is not just the underlying ring. + # We can now assume that self._p and x._p actually are polynomials, + # hence, their parent is not just the underlying ring. VarList = list(set(self._p.parent().variable_names()).union(set(x._p.parent().variable_names()))) - VarList.sort(key=self.parent().varname_key,reverse=True) + VarList.sort(key=self.parent().varname_key, reverse=True) if VarList: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(self._p.base_ring(),VarList,order=self.parent()._order) + R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) else: R = self._p.base_ring() - return InfinitePolynomial_sparse(self.parent(),R(self._p) * R(x._p)) + return InfinitePolynomial_sparse(self.parent(), R(self._p) * R(x._p)) def gcd(self, x): """ @@ -620,7 +622,7 @@ def gcd(self, x): P = self.parent() self._p = P._P(self._p) x._p = P._P(x._p) - return InfinitePolynomial_sparse(self.parent(),self._p.gcd(x._p)) + return InfinitePolynomial_sparse(self.parent(), self._p.gcd(x._p)) def _rmul_(self, left): """ @@ -631,7 +633,7 @@ def _rmul_(self, left): 4 """ - return InfinitePolynomial_sparse(self.parent(),left*self._p) + return InfinitePolynomial_sparse(self.parent(), left * self._p) def _lmul_(self, right): """ @@ -642,7 +644,7 @@ def _lmul_(self, right): 4*alpha_3 """ - return InfinitePolynomial_sparse(self.parent(),self._p*right) + return InfinitePolynomial_sparse(self.parent(), self._p * right) def _div_(self, x): r""" @@ -686,9 +688,9 @@ def _div_(self, x): """ if not x.variables(): p = self.base_ring()(x._p) - divisor = self.base_ring().one()/p # use induction + divisor = self.base_ring().one() / p # use induction OUTP = self.parent().tensor_with_ring(divisor.base_ring()) - return OUTP(self)*OUTP(divisor) + return OUTP(self) * OUTP(divisor) else: from sage.rings.fraction_field_element import FractionFieldElement field = self.parent().fraction_field() @@ -704,19 +706,19 @@ def _floordiv_(self, x): 1 """ try: - return InfinitePolynomial_sparse(self.parent(),self._p//x._p) + return InfinitePolynomial_sparse(self.parent(), self._p // x._p) except Exception: pass - ## We can now assume that self._p and x._p actually are polynomials, - ## hence, their parent is not just the underlying ring. + # We can now assume that self._p and x._p actually are polynomials, + # hence, their parent is not just the underlying ring. VarList = list(set(self._p.parent().variable_names()).union(set(x._p.parent().variable_names()))) - VarList.sort(key=self.parent().varname_key,reverse=True) + VarList.sort(key=self.parent().varname_key, reverse=True) if VarList: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(self._p.base_ring(),VarList,order=self.parent()._order) + R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) else: R = self._p.base_ring() - return InfinitePolynomial_sparse(self.parent(),R(self._p) // R(x._p)) + return InfinitePolynomial_sparse(self.parent(), R(self._p) // R(x._p)) def _sub_(self, x): """ @@ -728,19 +730,19 @@ def _sub_(self, x): """ try: - return InfinitePolynomial_sparse(self.parent(),self._p-x._p) + return InfinitePolynomial_sparse(self.parent(), self._p - x._p) except Exception: pass - ## We can now assume that self._p and x._p actually are polynomials, - ## hence, their parent is not just the underlying ring. + # We can now assume that self._p and x._p actually are polynomials, + # hence, their parent is not just the underlying ring. VarList = list(set(self._p.parent().variable_names()).union(x._p.parent().variable_names())) - VarList.sort(key=self.parent().varname_key,reverse=True) + VarList.sort(key=self.parent().varname_key, reverse=True) if VarList: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - R = PolynomialRing(self._p.base_ring(),VarList, order=self.parent()._order) + R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) else: R = self._p.base_ring() - return InfinitePolynomial_sparse(self.parent(),R(self._p) - R(x._p)) + return InfinitePolynomial_sparse(self.parent(), R(self._p) - R(x._p)) def __pow__(self, n): """ @@ -766,15 +768,18 @@ def __pow__(self, n): if callable(n): if (self._p.parent() == self._p.base_ring()): return self - if not (hasattr(self._p,'variables') and self._p.variables()): + if not (hasattr(self._p, 'variables') and self._p.variables()): return self - if hasattr(n,'to_cycles') and hasattr(n,'__len__'): # duck typing Permutation + if hasattr(n, 'to_cycles') and hasattr(n, '__len__'): # duck typing Permutation # auxiliary function, necessary since n(m) raises an error if m>len(n) l = len(n) - p = lambda m: n(m) if 0=i: + if Lbig[j] >= i: ExpoBigSave = [e for e in Fbig[Lbig[j]]] ExpoBig = Fbig[Lbig[j]] found = True for k in gens: - if ExpoBig[k]len(n) l = len(n) - p = lambda m: n(m) if 0 Date: Sat, 17 Sep 2022 09:06:39 -0500 Subject: [PATCH 634/742] Add to documentation and remove reversed type-check --- src/sage/combinat/composition.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 72df25b263c..47808008981 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -110,7 +110,11 @@ class Composition(CombinatorialElement): sage: Composition(descents=({0,1,3},5)) [1, 1, 2, 1] - Check :trac:`34527`:: + An integer composition may be regarded as a sequence. Thus it is an + instance of the Python abstract base class ``Sequence`` allows us to check if objects + behave "like" sequences based on implemented methods. Note that + ``collections.abc.Sequence`` is not the same as + :class:`sage.structure.sequence.Sequence`:: sage: import collections.abc sage: C = Composition([3,2,3]) @@ -118,13 +122,15 @@ class Composition(CombinatorialElement): True sage: issubclass(C.__class__, collections.abc.Sequence) True + + Typically, instances of ``collections.abc.Sequence`` have a ``.count`` method. + This is *not* the case for ``Composition``s:: + sage: C.count Traceback (most recent call last): ... AttributeError: 'Compositions_all_with_category.element_class' object has no attribute 'count' - sage: type(reversed(C)) - EXAMPLES:: From b0a87c62f2bdb6e7982390331725d6f3654b1881 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sat, 17 Sep 2022 20:47:45 -0500 Subject: [PATCH 635/742] Fix documentation --- src/sage/combinat/composition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 47808008981..7123d9e35cb 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -124,7 +124,7 @@ class Composition(CombinatorialElement): True Typically, instances of ``collections.abc.Sequence`` have a ``.count`` method. - This is *not* the case for ``Composition``s:: + This is *not* the case for a ``Composition``:: sage: C.count Traceback (most recent call last): From 22385d98106c739db2f5cbee71e264e3831a5039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 18 Sep 2022 11:49:20 +0200 Subject: [PATCH 636/742] adding one doctest for integral --- src/sage/symbolic/integration/integral.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index a7eec1b72a5..f9914e438a1 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -321,7 +321,7 @@ def _tderivative_(self, f, x, a, b, diff_param=None): def _print_latex_(self, f, x, a, b): r""" - Convert this integral to LaTeX notation + Convert this integral to LaTeX notation. EXAMPLES:: @@ -345,7 +345,7 @@ def _print_latex_(self, f, x, a, b): def _sympy_(self, f, x, a, b): """ - Convert this integral to the equivalent SymPy object + Convert this integral to the equivalent SymPy object. The resulting SymPy integral can be evaluated using ``doit()``. @@ -1038,6 +1038,12 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False): sage: x,m = SR.var('x,m', domain='real') # long time sage: integrate(elliptic_e(x,m).diff(x), x) # long time elliptic_e(x, m) + + Check that :trac:`20467` is fixed:: + + sage: k = var('k') + sage: integral(sin(k*x)/x*erf(x^2), x, 0, oo, algorithm='maxima') + integrate(erf(x^2)*sin(k*x)/x, x, 0, +Infinity) """ expression, v, a, b = _normalize_integral_input(expression, v, a, b) if algorithm is not None: From fa1a2e025a46879f47094a2b7cd7882a3d1f15c5 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 18 Sep 2022 18:35:05 +0900 Subject: [PATCH 637/742] Uniformize headline in graphs and plots --- src/sage/graphs/base/graph_backends.pyx | 2 +- src/sage/graphs/base/static_sparse_graph.pyx | 2 +- src/sage/graphs/chrompoly.pyx | 2 +- src/sage/graphs/graph_input.py | 2 +- src/sage/graphs/graph_plot.py | 2 +- src/sage/graphs/matchpoly.pyx | 2 +- src/sage/graphs/path_enumeration.pyx | 2 +- src/sage/graphs/schnyder.py | 2 +- src/sage/graphs/traversals.pyx | 2 +- src/sage/plot/bar_chart.py | 2 +- src/sage/plot/bezier_path.py | 2 +- src/sage/plot/complex_plot.pyx | 2 +- src/sage/plot/contour_plot.py | 2 +- src/sage/plot/density_plot.py | 2 +- src/sage/plot/line.py | 2 +- src/sage/plot/matrix_plot.py | 2 +- src/sage/plot/misc.py | 4 +++- src/sage/plot/plot.py | 2 +- src/sage/plot/plot3d/base.pyx | 16 ++++++++-------- src/sage/plot/plot3d/implicit_plot3d.py | 2 +- src/sage/plot/plot3d/implicit_surface.pyx | 2 +- src/sage/plot/plot3d/index_face_set.pyx | 2 +- src/sage/plot/plot3d/list_plot3d.py | 2 +- src/sage/plot/plot3d/parametric_plot3d.py | 2 +- src/sage/plot/plot3d/parametric_surface.pyx | 2 +- src/sage/plot/plot3d/platonic.py | 2 +- src/sage/plot/plot3d/plot3d.py | 2 +- src/sage/plot/plot3d/plot_field3d.py | 2 +- src/sage/plot/plot3d/shapes.pyx | 2 +- src/sage/plot/plot3d/texture.py | 2 +- src/sage/plot/plot3d/transform.pyx | 4 +++- src/sage/plot/scatter_plot.py | 2 +- src/sage/plot/streamline_plot.py | 2 +- 33 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/sage/graphs/base/graph_backends.pyx b/src/sage/graphs/base/graph_backends.pyx index 9daf0702185..3ff36d5cee2 100644 --- a/src/sage/graphs/base/graph_backends.pyx +++ b/src/sage/graphs/base/graph_backends.pyx @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- r""" -Backends for Sage (di)graphs. +Backends for Sage (di)graphs This module implements :class:`GenericGraphBackend` (the base class for backends). diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 23fe59aa8e3..6c4bc1b7edd 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -1,7 +1,7 @@ # cython: binding=True # distutils: language = c++ r""" -Static Sparse Graphs +Static sparse graphs What is the point ? ------------------- diff --git a/src/sage/graphs/chrompoly.pyx b/src/sage/graphs/chrompoly.pyx index d3afec0e278..441ba58643d 100644 --- a/src/sage/graphs/chrompoly.pyx +++ b/src/sage/graphs/chrompoly.pyx @@ -1,6 +1,6 @@ # cython: binding=True """ -Chromatic Polynomial +Chromatic polynomial AUTHORS: diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 9b571953fed..34df7dd3c76 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -1,5 +1,5 @@ r""" -Functions for reading/building graphs/digraphs. +Functions for reading/building graphs/digraphs This module gathers functions needed to build a graph from any other data. diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index 16fd32608d8..5d646060add 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- r""" -Graph Plotting +Graph plotting *(For LaTeX drawings of graphs, see the* :mod:`~sage.graphs.graph_latex` *module.)* diff --git a/src/sage/graphs/matchpoly.pyx b/src/sage/graphs/matchpoly.pyx index 444d99ebee3..4a8c24be8ca 100644 --- a/src/sage/graphs/matchpoly.pyx +++ b/src/sage/graphs/matchpoly.pyx @@ -1,6 +1,6 @@ # cython: binding=True """ -Matching Polynomial +Matching polynomial This module contains the following methods: diff --git a/src/sage/graphs/path_enumeration.pyx b/src/sage/graphs/path_enumeration.pyx index 2e3122b6134..0ef63dd0c17 100644 --- a/src/sage/graphs/path_enumeration.pyx +++ b/src/sage/graphs/path_enumeration.pyx @@ -2,7 +2,7 @@ # cython: binding=True # distutils: language = c++ r""" -Path Enumeration +Path enumeration This module is meant for all functions related to path enumeration in graphs. diff --git a/src/sage/graphs/schnyder.py b/src/sage/graphs/schnyder.py index a29bce8dd3c..5816d1c7952 100644 --- a/src/sage/graphs/schnyder.py +++ b/src/sage/graphs/schnyder.py @@ -1,5 +1,5 @@ """ -Schnyder's Algorithm for straight-line planar embeddings +Schnyder's algorithm for straight-line planar embeddings A module for computing the (x,y) coordinates for a straight-line planar embedding of any connected planar graph with at least three vertices. Uses diff --git a/src/sage/graphs/traversals.pyx b/src/sage/graphs/traversals.pyx index 14374831be8..a16ac6d701e 100644 --- a/src/sage/graphs/traversals.pyx +++ b/src/sage/graphs/traversals.pyx @@ -2,7 +2,7 @@ # cython: binding=True # distutils: language = c++ r""" -Graph traversals. +Graph traversals **This module implements the following graph traversals** diff --git a/src/sage/plot/bar_chart.py b/src/sage/plot/bar_chart.py index 1f0d7d62cf7..34ed242af4c 100644 --- a/src/sage/plot/bar_chart.py +++ b/src/sage/plot/bar_chart.py @@ -1,5 +1,5 @@ """ -Bar Charts +Bar charts """ # ***************************************************************************** diff --git a/src/sage/plot/bezier_path.py b/src/sage/plot/bezier_path.py index 99290dc9a9d..27c95f10c0c 100644 --- a/src/sage/plot/bezier_path.py +++ b/src/sage/plot/bezier_path.py @@ -1,5 +1,5 @@ r""" -Bezier Paths +Bezier paths """ #***************************************************************************** # Copyright (C) 2006 Alex Clemesha , diff --git a/src/sage/plot/complex_plot.pyx b/src/sage/plot/complex_plot.pyx index 47617d9a353..6f0aeab87ae 100644 --- a/src/sage/plot/complex_plot.pyx +++ b/src/sage/plot/complex_plot.pyx @@ -1,5 +1,5 @@ """ -Complex Plots +Complex plots AUTHORS: diff --git a/src/sage/plot/contour_plot.py b/src/sage/plot/contour_plot.py index 3cf3d0f932d..c0cab456686 100644 --- a/src/sage/plot/contour_plot.py +++ b/src/sage/plot/contour_plot.py @@ -1,5 +1,5 @@ """ -Contour Plots +Contour plots """ # **************************************************************************** # Copyright (C) 2006 Alex Clemesha , diff --git a/src/sage/plot/density_plot.py b/src/sage/plot/density_plot.py index 741b5d9be00..155ac8d7a8e 100644 --- a/src/sage/plot/density_plot.py +++ b/src/sage/plot/density_plot.py @@ -1,5 +1,5 @@ """ -Density Plots +Density plots """ #***************************************************************************** diff --git a/src/sage/plot/line.py b/src/sage/plot/line.py index e4b3b4ddc82..691e3c31307 100644 --- a/src/sage/plot/line.py +++ b/src/sage/plot/line.py @@ -1,5 +1,5 @@ """ -Line Plots +Line plots """ # ***************************************************************************** diff --git a/src/sage/plot/matrix_plot.py b/src/sage/plot/matrix_plot.py index e15b007184e..f62d362ea11 100644 --- a/src/sage/plot/matrix_plot.py +++ b/src/sage/plot/matrix_plot.py @@ -1,5 +1,5 @@ """ -Matrix Plots +Matrix plots """ #***************************************************************************** # Copyright (C) 2006 Alex Clemesha , diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index a64457ef661..37a8000f9aa 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -1,4 +1,6 @@ -"Plotting utilities" +""" +Plotting utilities +""" # **************************************************************************** # Distributed under the terms of the GNU General Public License (GPL) diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index d41b4bad908..b36ee57227c 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -1,5 +1,5 @@ r""" -2D Plotting +2D plotting Sage provides extensive 2D plotting functionality. The underlying rendering is done using the matplotlib Python library. diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index ae1fd739499..77dabadc78e 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -1,5 +1,5 @@ r""" -Base Classes for 3D Graphics Objects and Plotting +Base classes for 3D graphics objects and plotting The most important facts about these classes are that you can simply add graphics objects @@ -9,7 +9,7 @@ choosing a viewer and setting various parameters for displaying the graphics. Most of the other methods of these classes are technical and -for special usage. +for special usage. AUTHORS: @@ -999,7 +999,7 @@ cdef class Graphics3d(SageObject): "camera_position","updir", # "look_at", # omit look_at. viewdir is sufficient for most purposes "viewdir") - + # The tachyon "aspectratio" parameter is outdated for normal users: # From the tachyon documentation: # "By using the aspect ratio parameter, one can produce images which look @@ -1085,7 +1085,7 @@ cdef class Graphics3d(SageObject): updir = _flip_orientation(updir) camera_position = _flip_orientation(camera_position) light_position = _flip_orientation(light_position) - + return """ begin_scene resolution {resolution_x:d} {resolution_y:d} @@ -1167,9 +1167,9 @@ end_scene""".format( def _tostring(s): r""" Converts vector information to a space-separated string. - + EXAMPLES:: - + sage: sage.plot.plot3d.base.Graphics3d._tostring((1.0,1.2,-1.3)) '1.00000000000000 1.20000000000000 -1.30000000000000' """ @@ -1682,7 +1682,7 @@ end_scene""".format( the viewpoint, with respect to the cube $[-1,1]\\times[-1,1]\\times[-1,1]$, into which the bounding box of the scene - is scaled and centered. + is scaled and centered. The default viewing direction is towards the origin. - ``viewdir`` (for tachyon) -- (default: None) three coordinates @@ -1713,7 +1713,7 @@ end_scene""".format( * ``'lowest'``: worst quality rendering, preview (and fastest). Sets tachyon command line flag ``-lowestshade``. - + - ``extra_opts`` (for tachyon) -- string (default: empty string); extra options that will be appended to the tachyon command line. diff --git a/src/sage/plot/plot3d/implicit_plot3d.py b/src/sage/plot/plot3d/implicit_plot3d.py index 2eb18f7d64d..aa05059878d 100644 --- a/src/sage/plot/plot3d/implicit_plot3d.py +++ b/src/sage/plot/plot3d/implicit_plot3d.py @@ -1,5 +1,5 @@ """ -Implicit Plots +Implicit plots """ from .implicit_surface import ImplicitSurface diff --git a/src/sage/plot/plot3d/implicit_surface.pyx b/src/sage/plot/plot3d/implicit_surface.pyx index aaa2db0c3a8..0a2d99cb5a7 100644 --- a/src/sage/plot/plot3d/implicit_surface.pyx +++ b/src/sage/plot/plot3d/implicit_surface.pyx @@ -1,5 +1,5 @@ r""" -Graphics 3D Object for Representing and Triangulating Isosurfaces. +Graphics 3D object for representing and triangulating isosurfaces AUTHORS: diff --git a/src/sage/plot/plot3d/index_face_set.pyx b/src/sage/plot/plot3d/index_face_set.pyx index 867529d59c5..642397e9ecf 100644 --- a/src/sage/plot/plot3d/index_face_set.pyx +++ b/src/sage/plot/plot3d/index_face_set.pyx @@ -1,5 +1,5 @@ """ -Indexed Face Sets +Indexed face sets Graphics3D object that consists of a list of polygons, also used for triangulations of other objects. diff --git a/src/sage/plot/plot3d/list_plot3d.py b/src/sage/plot/plot3d/list_plot3d.py index 417b9a3528a..c8179d036c5 100644 --- a/src/sage/plot/plot3d/list_plot3d.py +++ b/src/sage/plot/plot3d/list_plot3d.py @@ -1,5 +1,5 @@ """ -List Plots +List plots """ from sage.structure.element import is_Matrix diff --git a/src/sage/plot/plot3d/parametric_plot3d.py b/src/sage/plot/plot3d/parametric_plot3d.py index f0411e199fe..e16df517fb8 100644 --- a/src/sage/plot/plot3d/parametric_plot3d.py +++ b/src/sage/plot/plot3d/parametric_plot3d.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ -Parametric Plots +Parametric plots """ from .parametric_surface import ParametricSurface diff --git a/src/sage/plot/plot3d/parametric_surface.pyx b/src/sage/plot/plot3d/parametric_surface.pyx index ad6ea410e4d..68b388b587e 100644 --- a/src/sage/plot/plot3d/parametric_surface.pyx +++ b/src/sage/plot/plot3d/parametric_surface.pyx @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- r""" -Parametric Surface +Parametric surface Graphics 3D object for triangulating surfaces, and a base class for many other objects that can be represented by a 2D parametrization. diff --git a/src/sage/plot/plot3d/platonic.py b/src/sage/plot/plot3d/platonic.py index ef9a22aabdd..eee95d3290f 100644 --- a/src/sage/plot/plot3d/platonic.py +++ b/src/sage/plot/plot3d/platonic.py @@ -1,5 +1,5 @@ r""" -Platonic Solids +Platonic solids EXAMPLES: The five platonic solids in a row: diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index 44620a0edcb..a2bddd8a3a0 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -1,5 +1,5 @@ r""" -Plotting Functions +Plotting functions EXAMPLES:: diff --git a/src/sage/plot/plot3d/plot_field3d.py b/src/sage/plot/plot3d/plot_field3d.py index 4f1a28cc197..bdf39391d3e 100644 --- a/src/sage/plot/plot3d/plot_field3d.py +++ b/src/sage/plot/plot3d/plot_field3d.py @@ -1,5 +1,5 @@ """ -Plotting 3D Fields +Plotting 3D fields """ #***************************************************************************** # Copyright (C) 2009 Jason Grout diff --git a/src/sage/plot/plot3d/shapes.pyx b/src/sage/plot/plot3d/shapes.pyx index 340f034c235..0cea5676e2a 100644 --- a/src/sage/plot/plot3d/shapes.pyx +++ b/src/sage/plot/plot3d/shapes.pyx @@ -1,5 +1,5 @@ """ -Basic objects such as Sphere, Box, Cone, etc. +Basic objects such as Sphere, Box, Cone, etc AUTHORS: diff --git a/src/sage/plot/plot3d/texture.py b/src/sage/plot/plot3d/texture.py index deb400773d7..c2aa4f652d1 100644 --- a/src/sage/plot/plot3d/texture.py +++ b/src/sage/plot/plot3d/texture.py @@ -1,5 +1,5 @@ r""" -Texture Support +Texture support This module provides texture/material support for 3D Graphics objects and plotting. This is a very rough common interface for diff --git a/src/sage/plot/plot3d/transform.pyx b/src/sage/plot/plot3d/transform.pyx index 7e91d30823b..b140a1c1c41 100644 --- a/src/sage/plot/plot3d/transform.pyx +++ b/src/sage/plot/plot3d/transform.pyx @@ -1,4 +1,6 @@ -"Transformations" +""" +Transformations +""" #***************************************************************************** # Copyright (C) 2007 Robert Bradshaw diff --git a/src/sage/plot/scatter_plot.py b/src/sage/plot/scatter_plot.py index 83e1836479b..c78b33a5258 100644 --- a/src/sage/plot/scatter_plot.py +++ b/src/sage/plot/scatter_plot.py @@ -1,5 +1,5 @@ """ -Scatter Plots +Scatter plots """ # ***************************************************************************** diff --git a/src/sage/plot/streamline_plot.py b/src/sage/plot/streamline_plot.py index 8e34bcc297b..bd9156bf000 100644 --- a/src/sage/plot/streamline_plot.py +++ b/src/sage/plot/streamline_plot.py @@ -1,5 +1,5 @@ """ -Streamline Plots +Streamline plots """ # **************************************************************************** # Copyright (C) 2006 Alex Clemesha , From 693c524b1ce0792c9ff6c1f40bb23cd69174340f Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 18 Sep 2022 21:11:26 +0900 Subject: [PATCH 638/742] Recover etc. --- src/sage/plot/plot3d/shapes.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/plot/plot3d/shapes.pyx b/src/sage/plot/plot3d/shapes.pyx index 0cea5676e2a..340f034c235 100644 --- a/src/sage/plot/plot3d/shapes.pyx +++ b/src/sage/plot/plot3d/shapes.pyx @@ -1,5 +1,5 @@ """ -Basic objects such as Sphere, Box, Cone, etc +Basic objects such as Sphere, Box, Cone, etc. AUTHORS: From 25768de9c84a378af1c28eb7a3353e2795a4be98 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 18 Sep 2022 21:23:09 -0700 Subject: [PATCH 639/742] build/pkgs/igraph: Update to 0.10.1 --- build/pkgs/igraph/checksums.ini | 6 +++--- build/pkgs/igraph/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/igraph/checksums.ini b/build/pkgs/igraph/checksums.ini index c38a75f5b7f..9da572238e5 100644 --- a/build/pkgs/igraph/checksums.ini +++ b/build/pkgs/igraph/checksums.ini @@ -1,5 +1,5 @@ tarball=igraph-VERSION.tar.gz -sha1=e4097fc00c3cb9b64a251003623a104c2ac4ae1f -md5=fbca766c3e76b2098c4555a13689fec6 -cksum=627334466 +sha1=74abe82bdebdefc295a4f04b54170880dcb265e8 +md5=4e61e5e86ebe4fe478df415b7407e87e +cksum=2574937983 upstream_url=https://github.com/igraph/igraph/releases/download/VERSION/igraph-VERSION.tar.gz diff --git a/build/pkgs/igraph/package-version.txt b/build/pkgs/igraph/package-version.txt index 78bc1abd14f..571215736a6 100644 --- a/build/pkgs/igraph/package-version.txt +++ b/build/pkgs/igraph/package-version.txt @@ -1 +1 @@ -0.10.0 +0.10.1 From 4ab41e64da92a48691dff2027fa2b6d8cea309f9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 18 Sep 2022 21:23:16 -0700 Subject: [PATCH 640/742] build/pkgs/python_igraph: Update to 0.10.1 --- build/pkgs/python_igraph/checksums.ini | 6 +++--- build/pkgs/python_igraph/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/python_igraph/checksums.ini b/build/pkgs/python_igraph/checksums.ini index 8e53fc46eca..9ddab211f0d 100644 --- a/build/pkgs/python_igraph/checksums.ini +++ b/build/pkgs/python_igraph/checksums.ini @@ -1,5 +1,5 @@ tarball=python-igraph-VERSION.tar.gz -sha1=86a35162babd0d4af520b2ee0f8d9bb555a744cc -md5=d9c1ec7ddad66f927490f1de893fe42f -cksum=4022167909 +sha1=75eae8ca6de2daa8c5ca43f99487cf20b5cdf432 +md5=18a54cd2fe507f5602e6c10584f665ee +cksum=594785782 upstream_url=https://pypi.io/packages/source/i/igraph/igraph-VERSION.tar.gz diff --git a/build/pkgs/python_igraph/package-version.txt b/build/pkgs/python_igraph/package-version.txt index 78bc1abd14f..571215736a6 100644 --- a/build/pkgs/python_igraph/package-version.txt +++ b/build/pkgs/python_igraph/package-version.txt @@ -1 +1 @@ -0.10.0 +0.10.1 From bac7eb44e680379ce9f19547dd58d90fd6744de2 Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 19 Sep 2022 08:46:41 +0200 Subject: [PATCH 641/742] Trac #32921: Show full output in example for shifted_inhomogeneities The input consists of two inhomogeneities, but the output of the example in the doctests only shows one entry (this is legal due to the `...` at the end). I think that this is confusing, so I add the full output. --- src/sage/combinat/k_regular_sequence.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index e35ff0bfb12..6afb313151c 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2555,7 +2555,8 @@ def shifted_inhomogeneities(self, recurrence_rules): sage: recurrence_rules = RR(M=3, m=0, ll=-14, uu=14, ....: inhomogeneities={0: S, 1: S}) sage: RP.shifted_inhomogeneities(recurrence_rules) - {0: 2-regular sequence 4, 5, 7, 9, 11, 11, 11, 12, 13, 13, ...} + {0: 2-regular sequence 4, 5, 7, 9, 11, 11, 11, 12, 13, 13, ..., + 1: 2-regular sequence 4, 5, 7, 9, 11, 11, 11, 12, 13, 13, ...} TESTS:: From 105dae177cb01ba13622024100b54d2f1df14d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 16 Sep 2022 11:56:46 +0200 Subject: [PATCH 642/742] refresh the infinite polynomial ring --- .../polynomial/infinite_polynomial_ring.py | 248 +++++++++--------- 1 file changed, 121 insertions(+), 127 deletions(-) diff --git a/src/sage/rings/polynomial/infinite_polynomial_ring.py b/src/sage/rings/polynomial/infinite_polynomial_ring.py index 68e20e1aa74..1bc126c1e00 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_ring.py +++ b/src/sage/rings/polynomial/infinite_polynomial_ring.py @@ -19,7 +19,7 @@ - ``R``, the base ring. It has to be a commutative ring, and in some applications it must even be a field -- ``names``, a list of generator names. Generator names must be alpha-numeric. +- ``names``, a finite list of generator names. Generator names must be alpha-numeric. - ``order`` (optional string). The default order is ``'lex'`` (lexicographic). ``'deglex'`` is degree lexicographic, and ``'degrevlex'`` (degree reverse lexicographic) is possible but discouraged. @@ -180,7 +180,7 @@ If the type of monomial orderings (e.g., 'degrevlex' versus 'lex') or -if the implementations don't match, there is no simplified +if the implementations do not match, there is no simplified construction available:: sage: X. = InfinitePolynomialRing(ZZ) @@ -254,18 +254,24 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +import operator +import re +from functools import reduce from sage.rings.ring import CommutativeRing from sage.categories.rings import Rings from sage.structure.all import SageObject, parent from sage.structure.factory import UniqueFactory from sage.misc.cachefunc import cached_method -import operator -import re -from functools import reduce + +################################################### +# The Construction Functor + +from sage.categories.pushout import InfinitePolynomialFunctor + ############################################################### -## Ring Factory framework +# Ring Factory framework class InfinitePolynomialRingFactory(UniqueFactory): """ @@ -326,23 +332,21 @@ def create_key(self, R, names=('x',), order='lex', implementation='dense'): Traceback (most recent call last): ... ValueError: Infinite Polynomial Rings must have at least one generator - """ if isinstance(names, list): names = tuple(names) if not names: raise ValueError("Infinite Polynomial Rings must have at least one generator") - if len(names)>len(set(names)): - raise ValueError("The variable names must be distinct") - F = InfinitePolynomialFunctor(names,order,implementation) - while hasattr(R,'construction'): + if len(names) > len(set(names)): + raise ValueError("the variable names must be distinct") + F = InfinitePolynomialFunctor(names, order, implementation) + while hasattr(R, 'construction'): C = R.construction() if C is None: break - F = F*C[0] + F = F * C[0] R = C[1] - return (F,R) - + return (F, R) def create_object(self, version, key): """ @@ -352,36 +356,32 @@ def create_object(self, version, key): sage: InfinitePolynomialRing.create_object('1.0', InfinitePolynomialRing.create_key(ZZ, ('x3',))) Infinite polynomial ring in x3 over Integer Ring - """ - if len(key)>2: + if len(key) > 2: # We got an old pickle. By calling the ring constructor, it will automatically # be transformed into the new scheme return InfinitePolynomialRing(*key) # By now, we have different unique keys, based on construction functors - C,R = key + C, R = key from sage.categories.pushout import CompositeConstructionFunctor, InfinitePolynomialFunctor - if isinstance(C,CompositeConstructionFunctor): + if isinstance(C, CompositeConstructionFunctor): F = C.all[-1] - if len(C.all)>1: + if len(C.all) > 1: R = CompositeConstructionFunctor(*C.all[:-1])(R) else: F = C if not isinstance(F, InfinitePolynomialFunctor): - raise TypeError("We expected an InfinitePolynomialFunctor, not %s"%type(F)) - if F._imple=='sparse': + raise TypeError("we expected an InfinitePolynomialFunctor, not %s" % type(F)) + if F._imple == 'sparse': return InfinitePolynomialRing_sparse(R, F._gens, order=F._order) return InfinitePolynomialRing_dense(R, F._gens, order=F._order) -InfinitePolynomialRing = InfinitePolynomialRingFactory('InfinitePolynomialRing') -################################################### -## The Construction Functor +InfinitePolynomialRing = InfinitePolynomialRingFactory('InfinitePolynomialRing') -from sage.categories.pushout import InfinitePolynomialFunctor ############################################################## -## An auxiliary dictionary-like class that returns variables +# An auxiliary dictionary-like class that returns variables class InfiniteGenDict: """ @@ -421,9 +421,8 @@ def __init__(self, Gens): [InfiniteGenDict defined by ['a', 'b'], {'1': 1}] sage: D._D == loads(dumps(D._D)) # indirect doctest True - """ - self._D = dict(zip([(hasattr(X,'_name') and X._name) or repr(X) for X in Gens],Gens)) + self._D = dict(zip(((hasattr(X, '_name') and X._name) or repr(X) for X in Gens), Gens)) def __eq__(self, other): """ @@ -481,16 +480,16 @@ def __getitem__(self, k): sage: type(_) """ - if not isinstance(k, str): - raise KeyError("String expected") + raise KeyError("string expected") L = k.split('_') try: - if len(L)==2: + if len(L) == 2: return self._D[L[0]][int(L[1])] except Exception: pass - raise KeyError("%s is not a variable name"%k) + raise KeyError("%s is not a variable name" % k) + class GenDictWithBasering: """ @@ -513,10 +512,8 @@ class GenDictWithBasering: sage: sage_eval('3*a_3*b_5-1/2*a_7', D) -1/2*a_7 + 3*a_3*b_5 - """ - - def __init__(self,parent, start): + def __init__(self, parent, start): """ INPUT: @@ -547,14 +544,13 @@ def __init__(self,parent, start): KeyError: 'a' sage: D['a'] a - """ P = self._P = parent - if isinstance(start,list): + if isinstance(start, list): self._D = start return self._D = [start] - while hasattr(P,'base_ring') and (P.base_ring() is not P): + while hasattr(P, 'base_ring') and (P.base_ring() is not P): P = P.base_ring() D = P.gens_dict() if isinstance(D, GenDictWithBasering): @@ -562,6 +558,7 @@ def __init__(self,parent, start): break else: self._D.append(D) + def __next__(self): """ Return a dictionary that can be used to interprete strings in the base ring of ``self``. @@ -576,10 +573,9 @@ def __next__(self): GenDict of Univariate Polynomial Ring in t over Rational Field sage: sage_eval('t^2', next(D)) t^2 - """ - if len(self._D)<=1: - raise ValueError("No next term for %s available"%self) + if len(self._D) <= 1: + raise ValueError("no next term for %s available" % self) return GenDictWithBasering(self._P.base_ring(), self._D[1:]) next = __next__ @@ -593,7 +589,7 @@ def __repr__(self): sage: D GenDict of Infinite polynomial ring in a, b over Integer Ring """ - return "GenDict of "+repr(self._P) + return "GenDict of " + repr(self._P) def __getitem__(self, k): """ @@ -613,10 +609,11 @@ def __getitem__(self, k): return D[k] except KeyError: pass - raise KeyError("%s is not a variable name of %s or its iterated base rings"%(k,self._P)) + raise KeyError("%s is not a variable name of %s or its iterated base rings" % (k, self._P)) + ############################################################## -## The sparse implementation +# The sparse implementation class InfinitePolynomialRing_sparse(CommutativeRing): r""" @@ -697,20 +694,19 @@ def __init__(self, R, names, order): True sage: X.gen(1)[2]*Y.gen(0)[1] alpha_1*beta_2 - """ if not names: names = ['x'] for n in names: if not (isinstance(n, str) and n.isalnum() and (not n[0].isdigit())): - raise ValueError("generator names must be alpha-numeric strings not starting with a digit, but %s isn't"%n) + raise ValueError("generator names must be alpha-numeric strings not starting with a digit, but %s is not" % n) if len(names) != len(set(names)): raise ValueError("generator names must be pairwise different") self._names = tuple(names) if not isinstance(order, str): - raise TypeError("The monomial order must be given as a string") + raise TypeError("the monomial order must be given as a string") if R not in Rings().Commutative(): - raise TypeError("The given 'base ring' (= %s) must be a commutative ring" % R) + raise TypeError("the given 'base ring' (= %s) must be a commutative ring" % R) # now, the input is accepted if hasattr(R, '_underlying_ring'): @@ -722,7 +718,7 @@ def __init__(self, R, names, order): self._identify_variable = lambda x, y: (-self._names.index(x), int(y)) self._find_maxshift = re.compile('_([0-9]+)') # findall yields stringrep of the shifts self._find_variables = re.compile('[a-zA-Z0-9]+_[0-9]+') - self._find_varpowers = re.compile(r'([a-zA-Z0-9]+)_([0-9]+)\^?([0-9]*)') # findall yields triple "generator_name", "index", "exponent" + self._find_varpowers = re.compile(r'([a-zA-Z0-9]+)_([0-9]+)\^?([0-9]*)') # findall yields triple "generator_name", "index", "exponent" # Create some small underlying polynomial ring. # It is used to ensure that the parent of the underlying @@ -753,9 +749,8 @@ def __repr__(self): sage: X. = InfinitePolynomialRing(ZZ, order='deglex'); X Infinite polynomial ring in alpha, beta over Integer Ring - """ - return "Infinite polynomial ring in %s over %s"%(", ".join(self._names), self._base) + return "Infinite polynomial ring in %s over %s" % (", ".join(self._names), self._base) def _latex_(self): r""" @@ -794,10 +789,10 @@ def one(self): 1 """ from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial - return InfinitePolynomial(self,self._base(1)) + return InfinitePolynomial(self, self._base(1)) ##################### - ## coercion + # coercion def construction(self): """ @@ -887,7 +882,7 @@ def _element_constructor_(self, x): sage: Y('1/3') Traceback (most recent call last): ... - ValueError: Can't convert 1/3 into an element of Infinite polynomial ring in x over Integer Ring + ValueError: cannot convert 1/3 into an element of Infinite polynomial ring in x over Integer Ring """ from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial # In many cases, the easiest solution is to "simply" evaluate @@ -897,20 +892,20 @@ def _element_constructor_(self, x): try: x = sage_eval(x, self.gens_dict()) except Exception: - raise ValueError("Can't convert %s into an element of %s" % (x, self)) + raise ValueError("cannot convert %s into an element of %s" % (x, self)) P = parent(x) if P is self: return x elif self._base.has_coerce_map_from(P): return InfinitePolynomial(self, self._base(x)) else: - raise ValueError("Can't convert %s into an element of %s" % (x, self)) + raise ValueError("cannot convert %s into an element of %s" % (x, self)) if isinstance(parent(x), InfinitePolynomialRing_sparse): # the easy case - parent == self - is already past - if x.parent() is self._base: # another easy case - return InfinitePolynomial(self,x) - xmaxind = x.max_index() # save for later + if x.parent() is self._base: # another easy case + return InfinitePolynomial(self, x) + xmaxind = x.max_index() # save for later x = x._p else: xmaxind = -1 @@ -932,26 +927,26 @@ def _element_constructor_(self, x): # By now, we can assume that x has a parent, because # types like int have already been done in the previous step; # and also it is not an InfinitePolynomial. - # If it isn't a polynomial (duck typing: we need + # If it is not a polynomial (duck typing: we need # the variables attribute), we fall back to using strings - if not hasattr(x,'variables'): + if not hasattr(x, 'variables'): try: return sage_eval(repr(x), self.gens_dict()) except Exception: - raise ValueError("Can't convert %s into an element of %s" % (x, self)) + raise ValueError("cannot convert %s into an element of %s" % (x, self)) # direct conversion will only be used if the underlying polynomials are libsingular. from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomial_libsingular, MPolynomialRing_libsingular # try interpretation in self._P, if we have a dense implementation - if hasattr(self,'_P'): + if hasattr(self, '_P'): if x.parent() is self._P: - return InfinitePolynomial(self,x) + return InfinitePolynomial(self, x) # It's a shame to use sage_eval. However, it's even more of a shame - # that MPolynomialRing_polydict doesn't work in complicated settings. + # that MPolynomialRing_polydict does not work in complicated settings. # So, if self._P is libsingular (and this will be the case in many # applications!), we do it "nicely". Otherwise, we have to use sage_eval. - if isinstance(x, MPolynomial_libsingular) and isinstance(self._P,MPolynomialRing_libsingular): - if xmaxind == -1: # Otherwise, x has been an InfinitePolynomial + if isinstance(x, MPolynomial_libsingular) and isinstance(self._P, MPolynomialRing_libsingular): + if xmaxind == -1: # Otherwise, x has been an InfinitePolynomial # We infer the correct variable shift. # Note: Since we are in the "libsingular" case, there are # no further "variables" hidden in the base ring of x.parent() @@ -963,7 +958,7 @@ def _element_constructor_(self, x): # This tests admissibility on the fly: VarList.sort(key=self.varname_key, reverse=True) except ValueError: - raise ValueError("Can't convert %s into an element of %s - variables aren't admissible"%(x,self)) + raise ValueError("cannot convert %s into an element of %s - variables are not admissible" % (x, self)) xmaxind = max([int(v.split('_')[1]) for v in VarList]) try: # Apparently, in libsingular, the polynomial conversion is not done by @@ -975,17 +970,17 @@ def _element_constructor_(self, x): if self._max < xmaxind: self.gen()[xmaxind] if self._P.ngens() == x.parent().ngens(): - self.gen()[self._max+1] + self.gen()[self._max + 1] # conversion to self._P will be done in InfinitePolynomial.__init__ return InfinitePolynomial(self, x) except (ValueError, TypeError, NameError): - raise ValueError("Can't convert %s (from %s, but variables %s) into an element of %s - no conversion into underlying polynomial ring %s"%(x,x.parent(),x.variables(),self,self._P)) + raise ValueError("cannot convert %s (from %s, but variables %s) into an element of %s - no conversion into underlying polynomial ring %s" % (x, x.parent(), x.variables(), self, self._P)) # By now, x or self._P are not libsingular. Since MPolynomialRing_polydict # is too buggy, we use string evaluation try: return sage_eval(repr(x), self.gens_dict()) except (ValueError, TypeError, NameError): - raise ValueError("Can't convert %s into an element of %s - no conversion into underlying polynomial ring"%(x,self)) + raise ValueError("cannot convert %s into an element of %s - no conversion into underlying polynomial ring" % (x, self)) # By now, we are in the sparse case. try: @@ -996,48 +991,48 @@ def _element_constructor_(self, x): # This tests admissibility on the fly: VarList.sort(key=self.varname_key, reverse=True) except ValueError: - raise ValueError("Can't convert %s into an element of %s - variables aren't admissible"%(x,self)) + raise ValueError("cannot convert %s into an element of %s - variables are not admissible" % (x, self)) - if len(VarList)==1: + if len(VarList) == 1: # univariate polynomial rings are crab. So, make up another variable. - if VarList[0]==self._names[0]+'_0': - VarList.append(self._names[0]+'_1') + if VarList[0] == self._names[0] + '_0': + VarList.append(self._names[0] + '_1') else: - VarList.append(self._names[0]+'_0') + VarList.append(self._names[0] + '_0') # We ensure that polynomial conversion is done by names; # the problem is that it is done by names if the number of variables coincides. - if len(VarList)==x.parent().ngens(): + if len(VarList) == x.parent().ngens(): BigList = x.parent().variable_names() ind = 2 - while self._names[0]+'_'+str(ind) in BigList: - ind+=1 - VarList.append(self._names[0]+'_'+str(ind)) + while self._names[0] + '_' + str(ind) in BigList: + ind += 1 + VarList.append(self._names[0] + '_' + str(ind)) try: VarList.sort(key=self.varname_key, reverse=True) except ValueError: - raise ValueError("Can't convert %s into an element of %s; the variables aren't admissible"%(x,self)) + raise ValueError("cannot convert %s into an element of %s; the variables are not admissible" % (x, self)) from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R = PolynomialRing(self._base, VarList, order=self._order) - if isinstance(R, MPolynomialRing_libsingular) and isinstance(x,MPolynomial_libsingular): # everything else is so buggy that it's even not worth to try. + if isinstance(R, MPolynomialRing_libsingular) and isinstance(x, MPolynomial_libsingular): # everything else is so buggy that it's even not worth to try. try: # Problem: If there is only a partial overlap in the variables # of x.parent() and R, then R(x) raises an error (which, I think, # is a bug, since we talk here about conversion, not coercion). # Hence, for being on the safe side, we coerce into a pushout ring: - x = R(1)*x - return InfinitePolynomial(self,x) + x = R(1) * x + return InfinitePolynomial(self, x) except Exception: # OK, last resort, to be on the safe side try: return sage_eval(repr(x), self.gens_dict()) - except (ValueError,TypeError,NameError): - raise ValueError("Can't convert %s into an element of %s; conversion of the underlying polynomial failed"%(x,self)) + except (ValueError, TypeError, NameError): + raise ValueError("cannot convert %s into an element of %s; conversion of the underlying polynomial failed" % (x, self)) else: try: return sage_eval(repr(x), self.gens_dict()) - except (ValueError,TypeError,NameError): - raise ValueError("Can't convert %s into an element of %s"%(x,self)) + except (ValueError, TypeError, NameError): + raise ValueError("cannot convert %s into an element of %s" % (x, self)) def tensor_with_ring(self, R): """ @@ -1073,20 +1068,20 @@ def tensor_with_ring(self, R): True """ if not R.has_coerce_map_from(self._underlying_ring): - raise TypeError("We can't tensor with "+repr(R)) + raise TypeError("we cannot tensor with " + repr(R)) B = self.base_ring() - if hasattr(B,'tensor_with_ring'): + if hasattr(B, 'tensor_with_ring'): return InfinitePolynomialRing(B.tensor_with_ring(R), self._names, self._order, implementation='sparse') - if hasattr(B,'change_ring'): # e.g., polynomial rings + if hasattr(B, 'change_ring'): # e.g., polynomial rings return InfinitePolynomialRing(B.change_ring(R), self._names, self._order, implementation='sparse') # try to find the correct base ring in other ways: try: - o = B.one()*R.one() + o = B.one() * R.one() except Exception: - raise TypeError("We can't tensor with "+repr(R)) + raise TypeError("we cannot tensor with " + repr(R)) return InfinitePolynomialRing(o.parent(), self._names, self._order, implementation='sparse') - ## Basic Ring Properties + # Basic Ring Properties # -- some stuff that is useful for quotient rings etc. def is_noetherian(self): """ @@ -1230,7 +1225,6 @@ def gen(self, i=None): sage: XX = InfinitePolynomialRing(GF(5)) sage: XX.gen(0) is XX.gen() True - """ if i is not None and i > len(self._names): raise ValueError @@ -1449,48 +1443,49 @@ def __getitem__(self, i): alpha_1 """ if int(i) != i: - raise ValueError("The index (= %s) must be an integer" % i) + raise ValueError("the index (= %s) must be an integer" % i) i = int(i) if i < 0: - raise ValueError("The index (= %s) must be non-negative" % i) + raise ValueError("the index (= %s) must be non-negative" % i) P = self._parent from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial_dense, InfinitePolynomial_sparse from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing OUT = self._output.get(i) - if hasattr(P,'_P'): + if hasattr(P, '_P'): if i <= P._max: - #return InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name+'_'+str(i)))) + # return InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name+'_'+str(i)))) if OUT is None: - self._output[i] = InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name+'_'+str(i)))) + self._output[i] = InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name + '_' + str(i)))) else: if OUT._p.parent() is not P._P: OUT._p = P._P(OUT._p) return self._output[i] - #Calculate all of the new names needed + # Calculate all of the new names needed try: - names = [ [name+'_'+str(j) for name in P._names] for j in range(i+1)] + names = [[name + '_' + str(j) for name in P._names] + for j in range(i + 1)] except OverflowError: - raise IndexError("Variable index is too big - consider using the sparse implementation") + raise IndexError("variable index is too big - consider using the sparse implementation") names = reduce(operator.add, names) names.sort(key=P.varname_key, reverse=True) - #Create the new polynomial ring - P._P = PolynomialRing(P.base_ring(), names, order = P._order) - ##Get the generators + # Create the new polynomial ring + P._P = PolynomialRing(P.base_ring(), names, order=P._order) + # Get the generators P._max = i - #return InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name+'_'+str(i)))) - self._output[i] = InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name+'_'+str(i)))) + # return InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name+'_'+str(i)))) + self._output[i] = InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name + '_' + str(i)))) return self._output[i] # Now, we are in the sparse implementation - if OUT is not None: # in the sparse implementation, this is ok + if OUT is not None: # in the sparse implementation, this is ok return OUT - if i==0: - names = [self._name+'_0',self._name+'_1'] + if i == 0: + names = [self._name + '_0', self._name + '_1'] else: - names = [self._name+'_0',self._name+'_'+str(i)] + names = [self._name + '_0', self._name + '_' + str(i)] names.sort(key=P.varname_key, reverse=True) Pol = PolynomialRing(P.base_ring(), names, order=P._order) - #return InfinitePolynomial_sparse(P, Pol.gen(names.index(self._name+'_'+str(i)))) - self._output[i] = InfinitePolynomial_sparse(P, Pol.gen(names.index(self._name+'_'+str(i)))) + # return InfinitePolynomial_sparse(P, Pol.gen(names.index(self._name+'_'+str(i)))) + self._output[i] = InfinitePolynomial_sparse(P, Pol.gen(names.index(self._name + '_' + str(i)))) return self._output[i] def _repr_(self): @@ -1500,9 +1495,8 @@ def _repr_(self): sage: X. = InfinitePolynomialRing(QQ) sage: x # indirect doctest x_* - """ - return self._name+'_*' + return self._name + '_*' def __str__(self): """ @@ -1511,12 +1505,12 @@ def __str__(self): sage: X. = InfinitePolynomialRing(QQ) sage: print(x) # indirect doctest Generator for the x's in Infinite polynomial ring in x, y over Rational Field - """ - return "Generator for the %s's in %s"%(self._name, self._parent) + return "Generator for the %s's in %s" % (self._name, self._parent) + ############################################################## -## The dense implementation +# The dense implementation class InfinitePolynomialRing_dense(InfinitePolynomialRing_sparse): """ @@ -1537,14 +1531,14 @@ def __init__(self, R, names, order): """ if not names: names = ['x'] - #Generate the initial polynomial ring + # Generate the initial polynomial ring self._max = 0 InfinitePolynomialRing_sparse.__init__(self, R, names, order) self._P = self._minP - #self._pgens = self._P.gens() + # self._pgens = self._P.gens() ##################### - ## Coercion + # Coercion def construction(self): """ @@ -1598,17 +1592,17 @@ def tensor_with_ring(self, R): """ if not R.has_coerce_map_from(self._underlying_ring): - raise TypeError("We can't tensor with "+repr(R)) + raise TypeError("we cannot tensor with " + repr(R)) B = self.base_ring() - if hasattr(B,'tensor_with_ring'): + if hasattr(B, 'tensor_with_ring'): return InfinitePolynomialRing(B.tensor_with_ring(R), self._names, self._order, implementation='dense') - if hasattr(B,'change_ring'): # e.g., polynomial rings + if hasattr(B, 'change_ring'): # e.g., polynomial rings return InfinitePolynomialRing(B.change_ring(R), self._names, self._order, implementation='dense') # try to find the correct base ring in other ways: try: - o = B.one()*R.one() + o = B.one() * R.one() except Exception: - raise TypeError("We can't tensor with "+repr(R)) + raise TypeError("we cannot tensor with " + repr(R)) return InfinitePolynomialRing(o.parent(), self._names, self._order, implementation='dense') def polynomial_ring(self): From e2d8f1d413375197e95038a6b12a891fe35d0fcc Mon Sep 17 00:00:00 2001 From: Clemens Heuberger Date: Mon, 19 Sep 2022 09:41:25 +0200 Subject: [PATCH 643/742] Trac #32921: `shifted_inhomogeneities`: doctest demonstrating blocks I think that the sentence in the description of the output is hard to understand, but I have no idea for improvement. Therefore I propose to explain it via a doctest. --- src/sage/combinat/k_regular_sequence.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 6afb313151c..9a1fdb83025 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -2554,10 +2554,28 @@ def shifted_inhomogeneities(self, recurrence_rules): ....: ['M', 'm', 'll', 'uu', 'inhomogeneities']) sage: recurrence_rules = RR(M=3, m=0, ll=-14, uu=14, ....: inhomogeneities={0: S, 1: S}) - sage: RP.shifted_inhomogeneities(recurrence_rules) + sage: SI = RP.shifted_inhomogeneities(recurrence_rules) + sage: SI {0: 2-regular sequence 4, 5, 7, 9, 11, 11, 11, 12, 13, 13, ..., 1: 2-regular sequence 4, 5, 7, 9, 11, 11, 11, 12, 13, 13, ...} + The first blocks of the corresponding vector-valued sequence correspond + to the corresponding shifts of the inhomogeneity. In this particular + case, there are no other blocks:: + + sage: lower = -2 + sage: upper = 3 + sage: SI[0].dimension() == S.dimension() * (upper - lower + 1) + True + sage: all( + ....: Seq2( + ....: SI[0].mu, + ....: vector((i - lower)*[0, 0] + list(S.left) + (upper - i)*[0, 0]), + ....: SI[0].right) + ....: == S.subsequence(1, i) + ....: for i in range(lower, upper+1)) + True + TESTS:: sage: Seq2 = kRegularSequenceSpace(2, ZZ) From d1b282e09c49bd26e9cce8b9c5f2c280e6cb2cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 19 Sep 2022 12:12:27 +0200 Subject: [PATCH 644/742] clean one file about N=2 super-conformal Lie algebras --- .../n2_lie_conformal_algebra.py | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) 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 5ee696bee17..23af0d3f7dd 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 @@ -19,18 +19,19 @@ - Reimundo Heluani (2020-06-03): Initial implementation. """ -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2020 Reimundo Heluani # # 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 .graded_lie_conformal_algebra import GradedLieConformalAlgebra + class N2LieConformalAlgebra(GradedLieConformalAlgebra): """ The N=2 super Lie conformal algebra. @@ -70,7 +71,7 @@ class N2LieConformalAlgebra(GradedLieConformalAlgebra): sage: G.bracket(G) {0: 2*L, 2: 2/3*C} """ - def __init__(self,R): + def __init__(self, R): """ Initialize self. @@ -79,24 +80,25 @@ def __init__(self,R): sage: V = lie_conformal_algebras.N2(QQ) sage: TestSuite(V).run() """ - n2dict =\ - {('L','L'):{0:{('L',1):1}, 1:{('L',0): 2}, - 3:{('C', 0):R(2).inverse_of_unit()}}, - ('L','G1'):{0:{('G1',1):1}, 1:{('G1',0):3*R(2).\ - inverse_of_unit()}}, - ('L','G2'):{0:{('G2',1):1}, 1:{('G2',0):3*R(2).\ - inverse_of_unit()}}, - ('G1','G2'): {0:{('L',0):1,('J',1):R(2).inverse_of_unit()}, - 1:{('J',0):1}, 2:{('C',0):R(3).inverse_of_unit()}}, - ('L','J'): {0:{('J',1):1},1:{('J',0):1}}, - ('J','J'): {1:{('C',0):R(3).inverse_of_unit()}}, - ('J','G1'): {0:{('G1',0):1}}, - ('J','G2'): {0:{('G2',0):-1}}} + n2dict = {('L', 'L'): {0: {('L', 1): 1}, + 1: {('L', 0): 2}, + 3: {('C', 0): R(2).inverse_of_unit()}}, + ('L', 'G1'): {0: {('G1', 1): 1}, + 1: {('G1', 0): 3 * R(2).inverse_of_unit()}}, + ('L', 'G2'): {0: {('G2', 1): 1}, + 1: {('G2', 0): 3 * R(2).inverse_of_unit()}}, + ('G1', 'G2'): {0: {('L', 0): 1, ('J', 1): R(2).inverse_of_unit()}, + 1: {('J', 0): 1}, + 2: {('C', 0): R(3).inverse_of_unit()}}, + ('L', 'J'): {0: {('J', 1): 1}, 1: {('J', 0): 1}}, + ('J', 'J'): {1: {('C', 0): R(3).inverse_of_unit()}}, + ('J', 'G1'): {0: {('G1', 0): 1}}, + ('J', 'G2'): {0: {('G2', 0): -1}}} from sage.rings.rational_field import QQ - weights = (2,1,QQ(3/2),QQ(3/2)) - parity = (0,0,1,1) - GradedLieConformalAlgebra.__init__(self,R,n2dict, - names=('L', 'J','G1','G2'), + weights = (2, 1, QQ(3) / 2, QQ(3) / 2) + parity = (0, 0, 1, 1) + GradedLieConformalAlgebra.__init__(self, R, n2dict, + names=('L', 'J', 'G1', 'G2'), central_elements=('C',), weights=weights, parity=parity) @@ -108,7 +110,5 @@ def _repr_(self): sage: R = lie_conformal_algebras.N2(QQbar); R The N=2 super Lie conformal algebra over Algebraic Field - """ - return "The N=2 super Lie conformal algebra over {}".\ - format(self.base_ring()) + return f"The N=2 super Lie conformal algebra over {self.base_ring()}" From 04a80af5353ba0b31a48999e60319a93c87832a9 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 19 Sep 2022 21:25:22 +0900 Subject: [PATCH 645/742] Fix a doctest error --- .../rings/polynomial/polynomial_element.pyx | 63 +++++++++---------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 4d5bd945ef0..1c338c2b54d 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -1,45 +1,50 @@ # coding: utf-8 """ -Univariate Polynomial Base Class +Univariate polynomial base class + +TESTS:: + + sage: R. = ZZ[] + sage: f = x^5 + 2*x^2 + (-1) + sage: f == loads(dumps(f)) + True + + sage: PolynomialRing(ZZ,'x').objgen() + (Univariate Polynomial Ring in x over Integer Ring, x) AUTHORS: -- William Stein: first version. +- William Stein: first version -- Martin Albrecht: Added singular coercion. +- Martin Albrecht: added singular coercion -- Robert Bradshaw: Move Polynomial_generic_dense to Cython. +- Robert Bradshaw: moved Polynomial_generic_dense to Cython -- Miguel Marco: Implemented resultant in the case where PARI fails. +- Miguel Marco: implemented resultant in the case where PARI fails -- Simon King: Use a faster way of conversion from the base ring. +- Simon King: used a faster way of conversion from the base ring -- Julian Rueth (2012-05-25,2014-05-09): Fixed is_squarefree() for imperfect - fields, fixed division without remainder over QQbar; added ``_cache_key`` - for polynomials with unhashable coefficients +- Kwankyu Lee (2013-06-02): enhanced :meth:`quo_rem` -- Simon King (2013-10): Implement copying of :class:`PolynomialBaseringInjection`. +- Julian Rueth (2012-05-25,2014-05-09): fixed is_squarefree() for imperfect + fields, fixed division without remainder over QQbar; added ``_cache_key`` + for polynomials with unhashable coefficients -- Kiran Kedlaya (2016-03): Added root counting. +- Simon King (2013-10): implemented copying of :class:`PolynomialBaseringInjection` -- Edgar Costa (2017-07): Added rational reconstruction. +- Bruno Grenet (2014-07-13): enhanced :meth:`quo_rem` -- Kiran Kedlaya (2017-09): Added reciprocal transform, trace polynomial. +- Kiran Kedlaya (2016-03): added root counting -- David Zureick-Brown (2017-09): Added is_weil_polynomial. +- Edgar Costa (2017-07): added rational reconstruction -- Sebastian Oehms (2018-10): made :meth:`roots` and :meth:`factor` work over more - cases of proper integral domains (see :trac:`26421`) +- Kiran Kedlaya (2017-09): added reciprocal transform, trace polynomial -TESTS:: +- David Zureick-Brown (2017-09): added is_weil_polynomial - sage: R. = ZZ[] - sage: f = x^5 + 2*x^2 + (-1) - sage: f == loads(dumps(f)) - True +- Sebastian Oehms (2018-10): made :meth:`roots` and :meth:`factor` work over more + cases of proper integral domains (see :trac:`26421`) - sage: PolynomialRing(ZZ,'x').objgen() - (Univariate Polynomial Ring in x over Integer Ring, x) """ # **************************************************************************** @@ -11334,7 +11339,7 @@ cdef class Polynomial_generic_dense(Polynomial): sage: class BrokenRational(Rational): ....: def __bool__(self): ....: raise NotImplementedError("cannot check whether number is non-zero") - ....: + ....: sage: z = BrokenRational() sage: R. = QQ[] sage: from sage.rings.polynomial.polynomial_element import Polynomial_generic_dense @@ -11634,18 +11639,12 @@ cdef class Polynomial_generic_dense(Polynomial): Raises a ``ZerodivisionError`` if ``other`` is zero. Raises an ``ArithmeticError`` if the division is not exact. - AUTHORS: - - - Kwankyu Lee (2013-06-02) - - - Bruno Grenet (2014-07-13) - EXAMPLES:: sage: P. = QQ[] sage: R. = P[] - sage: f = R.random_element(10) - sage: g = y^5+R.random_element(4) + sage: f = y^10 + R.random_element(9) + sage: g = y^5 + R.random_element(4) sage: q,r = f.quo_rem(g) sage: f == q*g + r True From d2c22bf0072d1b440731e24b4d3153d3ff43d223 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 19 Sep 2022 15:26:30 -0700 Subject: [PATCH 646/742] trac 34528: minor edits --- build/pkgs/_prereq/SPKG.rst | 2 +- build/pkgs/gfortran/SPKG.rst | 2 +- build/pkgs/python3/SPKG.rst | 2 +- src/doc/en/installation/source.rst | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/pkgs/_prereq/SPKG.rst b/build/pkgs/_prereq/SPKG.rst index 686154277ef..2b64020a823 100644 --- a/build/pkgs/_prereq/SPKG.rst +++ b/build/pkgs/_prereq/SPKG.rst @@ -23,7 +23,7 @@ computer: Other versions of these may work, but they are untested. -On macOS, suitable versions of all of these tools are provided either +On macOS, suitable versions of all of these tools are provided by the Xcode Command Line Tools. To install them, open a terminal window and run ``xcode-select --install``; then click "Install" in the pop-up window. If the Xcode Command Line Tools are already installed, diff --git a/build/pkgs/gfortran/SPKG.rst b/build/pkgs/gfortran/SPKG.rst index 83d2d0bb92a..b6ba9b9bb4d 100644 --- a/build/pkgs/gfortran/SPKG.rst +++ b/build/pkgs/gfortran/SPKG.rst @@ -25,7 +25,7 @@ Building Sage from source on Apple Silicon (M1/M2) requires the use of conda-forge, which package versions of GCC 12.x (including ``gfortran``) with the necessary changes for this platform. These changes are not in a released upstream version of GCC, and hence -also the ``gfortran`` SPKG is not suitable for the M1/M2. +the ``gfortran`` SPKG is not suitable for the M1/M2. License ------- diff --git a/build/pkgs/python3/SPKG.rst b/build/pkgs/python3/SPKG.rst index 8c393d4a05b..94a163de1f3 100644 --- a/build/pkgs/python3/SPKG.rst +++ b/build/pkgs/python3/SPKG.rst @@ -11,7 +11,7 @@ rather than building a Python 3 installation from scratch. Sage will accept versions 3.8.x to 3.10.x. You can also use ``--with-python=/path/to/python3_binary`` to tell Sage to use -``/path/to/python3_binary`` to set up the venv. Note that setting up venv requires +``/path/to/python3_binary`` to set up the venv. Note that setting up the venv requires a number of Python modules to be available within the Python in question. Currently, as of Sage 9.7, these modules are as follows: ``sqlite3``, ``ctypes``, ``math``, ``hashlib``, ``crypt``, ``socket``, ``zlib``, ``distutils.core``, ``ssl`` - diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index 6be356076b4..89dbfb10be4 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -67,7 +67,7 @@ already must be installed on your system: - `C/C++ compilers <../reference/spkg/gcc>`_ -If you have the sufficient privileges (for example, on Linux you can +If you have sufficient privileges (for example, on Linux you can use ``sudo`` to become the ``root`` user), then you can install these packages using the commands for your platform indicated in the pages linked above. If you do not have the privileges to do this, ask your system administrator to @@ -86,7 +86,7 @@ installed by Sage. When the ``./configure`` script runs, it will check for the presence of many packages (including the above) and inform you of any that are -missing, or have unsuitable versions. **Please read the messages that +missing or have unsuitable versions. **Please read the messages that ``./configure`` prints:** It will inform you which additional system packages you can install to avoid having to build them from source. This can save a lot of time. From 78f3a9218b8a51f643855917280b4e97b46db0c2 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 19 Sep 2022 17:36:55 -0500 Subject: [PATCH 647/742] Add .count --- src/sage/combinat/composition.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 7123d9e35cb..ee711e52f9f 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -124,13 +124,10 @@ class Composition(CombinatorialElement): True Typically, instances of ``collections.abc.Sequence`` have a ``.count`` method. - This is *not* the case for a ``Composition``:: + ``Composition.count`` counts the number of parts of a specified size:: - sage: C.count - Traceback (most recent call last): - ... - AttributeError: 'Compositions_all_with_category.element_class' object - has no attribute 'count' + sage: C.count(3) + 2 EXAMPLES:: @@ -1373,6 +1370,22 @@ def wll_gt(self, co2) -> bool: return False return False + def count(self, n): + r""" + Return the number of parts of size ``n``. + + EXAMPLES:: + + sage: C = Composition([3,2,3]) + sage: C.count(3) + 2 + sage: C.count(2) + 1 + sage: C.count(1) + 0 + """ + return sum(i == n for i in self) + Sequence.register(Composition) ############################################################## From 627b2bdfe922e2f9eed9d190c19df778674bdcfb Mon Sep 17 00:00:00 2001 From: Release Manager Date: Tue, 20 Sep 2022 00:38:18 +0200 Subject: [PATCH 648/742] Updated SageMath version to 9.7 --- .zenodo.json | 8 ++++---- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/sage_conf/install-requires.txt | 2 +- build/pkgs/sage_docbuild/install-requires.txt | 2 +- build/pkgs/sage_setup/install-requires.txt | 2 +- build/pkgs/sage_sws2rst/install-requires.txt | 2 +- build/pkgs/sagelib/install-requires.txt | 2 +- build/pkgs/sagemath_categories/install-requires.txt | 2 +- build/pkgs/sagemath_environment/install-requires.txt | 2 +- build/pkgs/sagemath_objects/install-requires.txt | 2 +- pkgs/sage-conf/VERSION.txt | 2 +- pkgs/sage-conf_pypi/VERSION.txt | 2 +- pkgs/sage-docbuild/VERSION.txt | 2 +- pkgs/sage-setup/VERSION.txt | 2 +- pkgs/sage-sws2rst/VERSION.txt | 2 +- pkgs/sagemath-categories/VERSION.txt | 2 +- pkgs/sagemath-environment/VERSION.txt | 2 +- pkgs/sagemath-objects/VERSION.txt | 2 +- pkgs/sagemath-repl/VERSION.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 24 files changed, 33 insertions(+), 33 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index 49b22d68dc7..91b74285b39 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,10 +1,10 @@ { "description": "Mirror of the Sage https://sagemath.org/ source tree", "license": "other-open", - "title": "sagemath/sage: 9.7.rc2", - "version": "9.7.rc2", + "title": "sagemath/sage: 9.7", + "version": "9.7", "upload_type": "software", - "publication_date": "2022-09-17", + "publication_date": "2022-09-19", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.7.rc2", + "identifier": "https://github.com/sagemath/sage/tree/9.7", "relation": "isSupplementTo" }, { diff --git a/VERSION.txt b/VERSION.txt index b63eff86bef..6e6a77791e1 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.7.rc2, Release Date: 2022-09-17 +SageMath version 9.7, Release Date: 2022-09-19 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 48189ef845c..60fd713965e 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=70b1e96e1bd71efd90b1d1345b9c8d4d12de432b -md5=bf9529bff5e1c938c51668f0687ae5a0 -cksum=1982975454 +sha1=db02cdbab3867dce3649cd49823a54dac6a3835b +md5=3580c14fc2c2671103073cb9cb7f8176 +cksum=2388907413 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 37da2e9a6db..efaab3b5685 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -4f225f4cc66a7d515ea6598ebe9b2ff48e114a15 +59ac11a9375feaada4486b63ed9900651e0a6fdb diff --git a/build/pkgs/sage_conf/install-requires.txt b/build/pkgs/sage_conf/install-requires.txt index 496914816ad..a0356056891 100644 --- a/build/pkgs/sage_conf/install-requires.txt +++ b/build/pkgs/sage_conf/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 9.7rc2 +sage-conf ~= 9.7 diff --git a/build/pkgs/sage_docbuild/install-requires.txt b/build/pkgs/sage_docbuild/install-requires.txt index 56ba1015d98..202df450687 100644 --- a/build/pkgs/sage_docbuild/install-requires.txt +++ b/build/pkgs/sage_docbuild/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 9.7rc2 +sage-docbuild ~= 9.7 diff --git a/build/pkgs/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt index 60e2ed2c881..1b631d955d2 100644 --- a/build/pkgs/sage_setup/install-requires.txt +++ b/build/pkgs/sage_setup/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 9.7rc2 +sage-setup ~= 9.7 diff --git a/build/pkgs/sage_sws2rst/install-requires.txt b/build/pkgs/sage_sws2rst/install-requires.txt index 47283b61993..344cda711c9 100644 --- a/build/pkgs/sage_sws2rst/install-requires.txt +++ b/build/pkgs/sage_sws2rst/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 9.7rc2 +sage-sws2rst ~= 9.7 diff --git a/build/pkgs/sagelib/install-requires.txt b/build/pkgs/sagelib/install-requires.txt index d009d8b4834..edd78431534 100644 --- a/build/pkgs/sagelib/install-requires.txt +++ b/build/pkgs/sagelib/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagelib ~= 9.7rc2 +sagelib ~= 9.7 diff --git a/build/pkgs/sagemath_categories/install-requires.txt b/build/pkgs/sagemath_categories/install-requires.txt index 984fcd77cb0..848ad97d3e1 100644 --- a/build/pkgs/sagemath_categories/install-requires.txt +++ b/build/pkgs/sagemath_categories/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 9.7rc2 +sagemath-categories ~= 9.7 diff --git a/build/pkgs/sagemath_environment/install-requires.txt b/build/pkgs/sagemath_environment/install-requires.txt index 6de5c339724..92b35788acb 100644 --- a/build/pkgs/sagemath_environment/install-requires.txt +++ b/build/pkgs/sagemath_environment/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 9.7rc2 +sagemath-environment ~= 9.7 diff --git a/build/pkgs/sagemath_objects/install-requires.txt b/build/pkgs/sagemath_objects/install-requires.txt index 614677a4a19..17764575b14 100644 --- a/build/pkgs/sagemath_objects/install-requires.txt +++ b/build/pkgs/sagemath_objects/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 9.7rc2 +sagemath-objects ~= 9.7 diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index 13ac8fa02e9..9d5e716c055 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -9.7.rc2 +9.7 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index 13ac8fa02e9..9d5e716c055 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -9.7.rc2 +9.7 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index 13ac8fa02e9..9d5e716c055 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -9.7.rc2 +9.7 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index 13ac8fa02e9..9d5e716c055 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -9.7.rc2 +9.7 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index 13ac8fa02e9..9d5e716c055 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -9.7.rc2 +9.7 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index 13ac8fa02e9..9d5e716c055 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -9.7.rc2 +9.7 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index 13ac8fa02e9..9d5e716c055 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -9.7.rc2 +9.7 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index 13ac8fa02e9..9d5e716c055 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -9.7.rc2 +9.7 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index 13ac8fa02e9..9d5e716c055 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -9.7.rc2 +9.7 diff --git a/src/VERSION.txt b/src/VERSION.txt index 13ac8fa02e9..9d5e716c055 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.7.rc2 +9.7 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 6f4e41fabfc..7fc8e994958 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.7.rc2' -SAGE_RELEASE_DATE='2022-09-17' -SAGE_VERSION_BANNER='SageMath version 9.7.rc2, Release Date: 2022-09-17' +SAGE_VERSION='9.7' +SAGE_RELEASE_DATE='2022-09-19' +SAGE_VERSION_BANNER='SageMath version 9.7, Release Date: 2022-09-19' diff --git a/src/sage/version.py b/src/sage/version.py index 8e72819281d..139e6f07404 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '9.7.rc2' -date = '2022-09-17' -banner = 'SageMath version 9.7.rc2, Release Date: 2022-09-17' +version = '9.7' +date = '2022-09-19' +banner = 'SageMath version 9.7, Release Date: 2022-09-19' From 5d5f9aefa7a2f38643c8bb264fe234683af47eff Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 19 Sep 2022 16:04:49 -0700 Subject: [PATCH 649/742] trac 34558: add "::" so code block renders correctly --- src/doc/en/developer/git_trac.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/en/developer/git_trac.rst b/src/doc/en/developer/git_trac.rst index 580c791ce60..25977e5ef23 100644 --- a/src/doc/en/developer/git_trac.rst +++ b/src/doc/en/developer/git_trac.rst @@ -17,6 +17,8 @@ perform every development task with just git and a web browser. Installing the Git-Trac Command =============================== +:: + [user@localhost]$ git clone https://github.com/sagemath/git-trac-command.git Cloning into 'git-trac-command'... [...] From f8a5eea2cf1d80bc00e442a824498a7c77468869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 19 Sep 2022 16:42:02 +0200 Subject: [PATCH 650/742] refactor MZV using a new file for a better auxiliary F_algebra --- src/sage/modular/multiple_zeta.py | 313 ++------ src/sage/modular/multiple_zeta_F_algebra.py | 747 ++++++++++++++++++++ 2 files changed, 816 insertions(+), 244 deletions(-) create mode 100644 src/sage/modular/multiple_zeta_F_algebra.py diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index dcd3d681eac..fd9fb808f9c 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -170,8 +170,6 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.richcmp import op_EQ, op_NE from sage.structure.element import parent -from sage.algebras.free_zinbiel_algebra import FreeZinbielAlgebra -from sage.arith.misc import bernoulli from sage.categories.cartesian_product import cartesian_product from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis from sage.categories.rings import Rings @@ -189,10 +187,9 @@ from sage.misc.cachefunc import cached_function, cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod -from sage.modules.free_module_element import vector +from sage.modular.multiple_zeta_F_algebra import F_algebra, W_Odds from sage.modules.free_module import VectorSpace from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ from sage.rings.semirings.non_negative_integer_semiring import NN @@ -959,7 +956,7 @@ def phi(self): r""" Return the morphism ``phi``. - This sends multiple zeta values to the algebra :func:`F_ring`, + This sends multiple zeta values to the auxiliary F-algebra, which is a shuffle algebra in odd generators `f_3,f_5,f_7,\dots` over the polynomial ring in one variable `f_2`. @@ -975,12 +972,12 @@ def phi(self): sage: m = Multizeta(2,2) + 2*Multizeta(1,3); m 2*ζ(1,3) + ζ(2,2) sage: M.phi(m) - 1/2*f2^2*Z[] + 1/2*f2^2 sage: Z = Multizeta sage: B5 = [3*Z(1,4) + 2*Z(2,3) + Z(3,2), 3*Z(1,4) + Z(2,3)] sage: [M.phi(b) for b in B5] - [f2*Z[f3] - 1/2*Z[f5], 1/2*Z[f5]] + [-1/2*f5 + f2*f3, 1/2*f5] """ M_it = Multizetas_iterated(self.base_ring()) return M_it.phi * self.iterated @@ -1201,10 +1198,10 @@ def single_valued(self): """ phi_im = self.phi() zin = phi_im.parent() - BR2 = zin.base_ring() - sv = zin.sum_of_terms((w, BR2(cf(0))) - for (a, b), cf in phi_im.coproduct() - for w in shuffle(a, b.reversal(), False)) + phi_no_f2 = phi_im.without_f2() + sv = zin.sum_of_terms(((0, W_Odds(w, check=False)), cf) + for (a, b), cf in phi_no_f2.coproduct() + for w in shuffle(a[1], b[1].reversal(), False)) return rho_inverse(sv) def simplify(self): @@ -1351,13 +1348,13 @@ def phi(self): """ Return the image of ``self`` by the morphism ``phi``. - This sends multiple zeta values to the algebra :func:`F_ring`. + This sends multiple zeta values to the auxiliary F-algebra. EXAMPLES:: sage: M = Multizetas(QQ) sage: M((1,2)).phi() - Z[f3] + f3 TESTS:: @@ -1366,7 +1363,7 @@ def phi(self): sage: M = Multizetas(A) sage: tst = u*M((1,2))+M((3,)) sage: tst.phi() - (u+1)*Z[f3] + (u+1)*f3 """ return self.parent().phi(self) @@ -1397,7 +1394,7 @@ def phi_as_vector(self): """ if not self.is_homogeneous(): raise ValueError('only defined for homogeneous elements') - return f_to_vector(self.parent().phi(self)) + return self.parent().phi(self).to_vector() def _numerical_approx_pari(self): r""" @@ -1837,7 +1834,7 @@ def phi_extended(self, w): OUTPUT: - an element in the algebra :func:`F_ring` + an element in the auxiliary F-algebra The coefficients are in the base ring. @@ -1846,52 +1843,50 @@ def phi_extended(self, w): sage: from sage.modular.multiple_zeta import Multizetas_iterated sage: M = Multizetas_iterated(QQ) sage: M.phi_extended((1,0)) - -f2*Z[] + -f2 sage: M.phi_extended((1,0,0)) - -Z[f3] + -f3 sage: M.phi_extended((1,1,0)) - Z[f3] + f3 sage: M.phi_extended((1,0,1,0,0)) - 3*f2*Z[f3] - 11/2*Z[f5] + -11/2*f5 + 3*f2*f3 More complicated examples:: sage: from sage.modular.multiple_zeta import composition_to_iterated sage: M.phi_extended(composition_to_iterated((4,3))) - 2/5*f2^2*Z[f3] + 10*f2*Z[f5] - 18*Z[f7] + -18*f7 + 10*f2*f5 + 2/5*f2^2*f3 sage: M.phi_extended(composition_to_iterated((3,4))) - -10*f2*Z[f5] + 17*Z[f7] + 17*f7 - 10*f2*f5 sage: M.phi_extended(composition_to_iterated((4,2))) - 10/21*f2^3*Z[] - 2*Z[f3,f3] + -2*f3f3 + 10/21*f2^3 sage: M.phi_extended(composition_to_iterated((3,5))) - -5*Z[f5,f3] + -5*f5f3 sage: M.phi_extended(composition_to_iterated((3,7))) - -6*Z[f5,f5] - 14*Z[f7,f3] + -6*f5f5 - 14*f7f3 sage: M.phi_extended(composition_to_iterated((3,3,2))) - -793/875*f2^4*Z[] - 4*f2*Z[f3,f3] + 9*Z[f3,f5] - 9/2*Z[f5,f3] + 9*f3f5 - 9/2*f5f3 - 4*f2*f3f3 - 793/875*f2^4 TESTS:: sage: M.phi_extended(tuple()) - Z[] + 1 """ # this is now hardcoded # prec = 1024 - f = F_ring_generator + F = F_algebra(self.base_ring()) + f = F.custom_gen if not w: - F = F_ring(self.base_ring()) - empty = F.indices()([]) - return F.monomial(empty) + return F.one() N = len(w) compo = tuple(iterated_to_composition(w)) - BRf2 = PolynomialRing(self.base_ring(), 'f2') if compo in B_data[N]: # do not forget the sign result_QQ = (-1)**len(compo) * phi_on_multiplicative_basis(compo) - return result_QQ.base_extend(BRf2) + return result_QQ u = compute_u_on_basis(w) rho_inverse_u = rho_inverse(u) xi = self.composition_on_basis(w, QQ) @@ -1899,14 +1894,14 @@ def phi_extended(self, w): c_xi /= Multizeta(N)._numerical_approx_pari() c_xi = c_xi.bestappr().sage() # in QQ result_QQ = u + c_xi * f(N) - return result_QQ.base_extend(BRf2) + return result_QQ @lazy_attribute def phi(self): """ Return the morphism ``phi``. - This sends multiple zeta values to the algebra :func:`F_ring`. + This sends multiple zeta values to the auxiliary F-algebra. EXAMPLES:: @@ -1915,19 +1910,19 @@ def phi(self): sage: m = Multizeta(1,0,1,0) + 2*Multizeta(1,1,0,0); m 2*I(1100) + I(1010) sage: M.phi(m) - 1/2*f2^2*Z[] + 1/2*f2^2 sage: Z = Multizeta sage: B5 = [3*Z(1,4) + 2*Z(2,3) + Z(3,2), 3*Z(1,4) + Z(2,3)] sage: [M.phi(b.iterated()) for b in B5] - [f2*Z[f3] - 1/2*Z[f5], 1/2*Z[f5]] + [-1/2*f5 + f2*f3, 1/2*f5] sage: B6 = [6*Z(1,5) + 3*Z(2,4) + Z(3,3), ....: 6*Z(1,1,4) + 4*Z(1,2,3) + 2*Z(1,3,2) + 2*Z(2,1,3) + Z(2,2,2)] sage: [M.phi(b.iterated()) for b in B6] - [Z[f3,f3], 1/6*f2^3*Z[]] + [f3f3, 1/6*f2^3] """ - cod = F_ring(self.base_ring()) + cod = F_algebra(self.base_ring()) return self.module_morphism(self.phi_extended, codomain=cod) def _element_constructor_(self, x): @@ -2051,14 +2046,14 @@ def phi(self): """ Return the image of ``self`` by the morphism ``phi``. - This sends multiple zeta values to the algebra :func:`F_ring`. + This sends multiple zeta values to the auxiliary F-algebra. EXAMPLES:: sage: from sage.modular.multiple_zeta import Multizetas_iterated sage: M = Multizetas_iterated(QQ) sage: M((1,1,0)).phi() - Z[f3] + f3 """ return self.parent().phi(self) @@ -2452,100 +2447,6 @@ def regularise(self): # **************** procedures after F. Brown ************ - -def F_ring(basering, N=18): - r""" - Return the free Zinbiel algebra on many generators `f_3,f_5,\dots` - over the polynomial ring with generator `f_2`. - - For the moment, only with a finite number of variables. - - INPUT: - - - ``N`` -- an integer (default 18), upper bound for indices of generators - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import F_ring - sage: F_ring(QQ) - Free Zinbiel algebra on generators (Z[f3], Z[f5], Z[f7], Z[f9], ...) - over Univariate Polynomial Ring in f2 over Rational Field - """ - ring = PolynomialRing(basering, ['f2']) - return FreeZinbielAlgebra(ring, ['f{}'.format(k) - for k in range(3, N, 2)]) - - -def F_prod(a, b): - """ - Return the associative and commutative product of ``a`` and ``b``. - - INPUT: - - - ``a``, ``b`` -- two elements of the F ring - - OUTPUT: - - an element of the F ring - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import F_ring_generator, F_prod - sage: f2 = F_ring_generator(2) - sage: f3 = F_ring_generator(3) - sage: F_prod(f2,f2) - f2^2*Z[] - sage: F_prod(f2,f3) - f2*Z[f3] - sage: F_prod(f3,f3) - 2*Z[f3,f3] - sage: F_prod(3*f2+5*f3,6*f2+f3) - 18*f2^2*Z[] + 33*f2*Z[f3] + 10*Z[f3,f3] - """ - F = a.parent() - empty = F.indices()([]) - one = F.monomial(empty) - ct_a = a.coefficient(empty) - ct_b = b.coefficient(empty) - rem_a = a - ct_a * one - rem_b = b - ct_b * one - resu = ct_a * ct_b * one + ct_a * rem_b + ct_b * rem_a - return resu + rem_a * rem_b + rem_b * rem_a - - -def F_ring_generator(i): - r""" - Return the generator of the F ring over `\QQ`. - - INPUT: - - - ``i`` -- a nonnegative integer - - If ``i`` is odd, this returns a single generator `f_i` of the free - shuffle algebra. - - Otherwise, it returns an appropriate multiple of a power of `f_2`. - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import F_ring_generator - sage: [F_ring_generator(i) for i in range(2,8)] - [f2*Z[], Z[f3], 2/5*f2^2*Z[], Z[f5], 8/35*f2^3*Z[], Z[f7]] - """ - F = F_ring(QQ) - one = F.monomial(Word([])) - f2 = F.base_ring().gen() - if i == 2: - return f2 * one - # now i odd >= 3 - if i % 2: - return F.monomial(Word(['f{}'.format(i)])) - i = i // 2 - B = bernoulli(2 * i) * (-1)**(i - 1) - B *= ZZ(2)**(3 * i - 1) * ZZ(3)**i / ZZ(2 * i).factorial() - return B * f2**i * one - - def coeff_phi(w): """ Return the coefficient of `f_k` in the image by ``phi``. @@ -2577,8 +2478,8 @@ def coeff_phi(w): M = Multizetas_iterated(QQ) z = M.phi_extended(w) W = z.parent().basis().keys() - w = W(['f{}'.format(k)], check=False) - return z.coefficient(w).lc() # in QQ + w = W((0, [k])) + return z.coefficient(w) # in QQ def phi_on_multiplicative_basis(compo): @@ -2597,16 +2498,14 @@ def phi_on_multiplicative_basis(compo): sage: from sage.modular.multiple_zeta import phi_on_multiplicative_basis sage: phi_on_multiplicative_basis((2,)) - f2*Z[] + f2 sage: phi_on_multiplicative_basis((3,)) - Z[f3] + f3 """ - f = F_ring_generator - F = F_ring(QQ) - one = F.monomial(Word([])) + f = F_algebra(QQ).custom_gen if tuple(compo) == (2,): - return f(2) * one + return f(2) if len(compo) == 1: n, = compo @@ -2633,18 +2532,14 @@ def phi_on_basis(L): sage: from sage.modular.multiple_zeta import phi_on_basis sage: phi_on_basis([(3,),(3,)]) - 2*Z[f3,f3] + 2*f3f3 sage: phi_on_basis([(2,),(2,)]) - f2^2*Z[] + f2^2 sage: phi_on_basis([(2,),(3,),(3,)]) - 2*f2*Z[f3,f3] + 2*f2*f3f3 """ - # beware that the default * is the half-shuffle ! - F = F_ring(QQ) - resu = F.monomial(Word([])) - for compo in L: - resu = F_prod(resu, phi_on_multiplicative_basis(compo)) - return resu + F = F_algebra(QQ) + return F.prod(phi_on_multiplicative_basis(compo) for compo in L) def D_on_compo(k, compo): @@ -2707,11 +2602,11 @@ def compute_u_on_compo(compo): sage: from sage.modular.multiple_zeta import compute_u_on_compo sage: compute_u_on_compo((2,4)) - 2*Z[f3,f3] + 2*f3f3 sage: compute_u_on_compo((2,3,2)) - -11/2*f2*Z[f5] + -11/2*f2*f5 sage: compute_u_on_compo((3,2,3,2)) - 11*f2*Z[f3,f5] - 75/4*Z[f3,f7] - 9*f2*Z[f5,f3] + 81/4*Z[f5,f5] + 75/8*Z[f7,f3] + -75/4*f3f7 + 81/4*f5f5 + 75/8*f7f3 + 11*f2*f3f5 - 9*f2*f5f3 """ it = composition_to_iterated(compo) return (-1)**len(compo) * compute_u_on_basis(it) @@ -2733,103 +2628,29 @@ def compute_u_on_basis(w): sage: from sage.modular.multiple_zeta import compute_u_on_basis sage: compute_u_on_basis((1,0,0,0,1,0)) - -2*Z[f3,f3] + -2*f3f3 sage: compute_u_on_basis((1,1,1,0,0)) - f2*Z[f3] + f2*f3 sage: compute_u_on_basis((1,0,0,1,0,0,0,0)) - -5*Z[f5,f3] + -5*f5f3 sage: compute_u_on_basis((1,0,1,0,0,1,0)) - 11/2*f2*Z[f5] + 11/2*f2*f5 sage: compute_u_on_basis((1,0,0,1,0,1,0,0,1,0)) - 11*f2*Z[f3,f5] - 75/4*Z[f3,f7] - 9*f2*Z[f5,f3] + 81/4*Z[f5,f5] - + 75/8*Z[f7,f3] + -75/4*f3f7 + 81/4*f5f5 + 75/8*f7f3 + 11*f2*f3f5 - 9*f2*f5f3 """ M = Multizetas_iterated(QQ) - F = F_ring(QQ) - f = F_ring_generator + F = F_algebra(QQ) N = len(w) xi_dict = {} for k in range(3, N, 2): xi_dict[k] = F.sum(cf * coeff_phi(ww[0]) * M.phi_extended(tuple(ww[1])) for ww, cf in M.D_on_basis(k, w)) - return F.sum(f(k) * xi_dict[k] for k in range(3, N, 2)) - - -def f_to_vector(elt): - """ - Convert an element of F ring to a vector. - - INPUT: - - an homogeneous element of :func:`F_ring` over some base ring - - OUTPUT: - - a vector with coefficients in the base ring - - .. SEEALSO:: :func:`vector_to_f` - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import F_ring, vector_to_f, f_to_vector - sage: F = F_ring(QQ) - sage: f2 = F.base_ring().gen() - sage: x = f2**4*F.monomial(Word([]))+f2*F.monomial(Word(['f3','f3'])) - sage: f_to_vector(x) - (0, 0, 1, 1) - sage: vector_to_f(_,8) - f2^4*Z[] + f2*Z[f3,f3] - - sage: x = F.monomial(Word(['f11'])); x - Z[f11] - sage: f_to_vector(x) - (1, 0, 0, 0, 0, 0, 0, 0, 0) - """ - F = elt.parent() - BR = F.base_ring().base_ring() - if not elt: - return vector(BR, []) - a, b = next(iter(elt)) - N = sum(int(x[1:]) for x in a) + 2 * b.degree() - W = F.basis().keys() - return vector(BR, [elt.coefficient(W(b, check=False)).lc() - for _, b in basis_f_iterator(N)]) - - -def vector_to_f(vec, N): - """ - Convert back a vector to an element of the F ring. - - INPUT: - - a vector with coefficients in some base ring - - OUTPUT: - - an homogeneous element of :func:`F_ring` over this base ring - - .. SEEALSO:: :func:`f_to_vector` - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import vector_to_f, f_to_vector - sage: vector_to_f((4,5),6) - 5*f2^3*Z[] + 4*Z[f3,f3] - sage: f_to_vector(_) - (4, 5) - """ - if isinstance(vec, (list, tuple)): - vec = vector(vec) - BR = vec.base_ring() - F = F_ring(BR) - f2 = F.base_ring().gen() - basis_F = (f2**k * F.monomial(b) - for k, b in basis_f_iterator(N)) - return sum(cf * bi for cf, bi in zip(vec, basis_F)) + return F.sum(F.half_product(F.custom_gen(k), xi_dict[k]) + for k in range(3, N, 2)) @cached_function @@ -2859,7 +2680,7 @@ def rho_matrix_inverse(n): resu = [] for b in base: phi_b = phi_on_basis(b) - resu.append(f_to_vector(phi_b)) + resu.append(phi_b.to_vector()) dN = len(resu) return ~matrix(QQ, dN, dN, resu) @@ -2878,13 +2699,16 @@ def rho_inverse(elt): EXAMPLES:: - sage: from sage.modular.multiple_zeta import F_ring_generator, rho_inverse - sage: f = F_ring_generator + sage: from sage.modular.multiple_zeta import rho_inverse + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: f = A.custom_gen + sage: W = A.basis().keys() sage: rho_inverse(f(3)) ζ(3) sage: rho_inverse(f(9)) ζ(9) - sage: rho_inverse(f(5)*f(3)) + sage: rho_inverse(A("53")) -1/5*ζ(3,5) """ pa = elt.parent() @@ -2893,9 +2717,10 @@ def rho_inverse(elt): if elt == pa.zero(): return M_BR.zero() - a, b = next(iter(elt)) - N = sum(int(x[1:]) for x in a) + 2 * b.degree() + pw, _ = next(iter(elt)) + p, w = pw + N = 2 * p + sum(int(c) for c in w) - v = f_to_vector(elt) + v = elt.to_vector() w = v * rho_matrix_inverse(N) return sum(cf * b for cf, b in zip(w, M_BR.basis_data(BR, N))) diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py new file mode 100644 index 00000000000..d9e629ccd35 --- /dev/null +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -0,0 +1,747 @@ +# -*- coding: utf-8 -*- +r""" +F-algebra for motivic multiple zeta values. + +This is a commutative algebra, defined as the tensor product of the +polynomial algebra over one generator `f_2` by the shuffle algebra in +infinitely many generators indexed by odd integers and denoted by +`f_3`, `f_5`, ... It serves as an auxiliary algebra in the study of +the ring of motivic multiple zeta values. + +Here we provide a basic direct implementation, endowed with the +motivic coproduct. + +AUTHORS: + +- Frédéric Chapoton (2022-09): Initial version + +""" + +# **************************************************************************** +# Copyright (C) 2022 Frédéric Chapoton +# +# Distributed under the terms of the GNU General Public License (GPL) +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.arith.misc import bernoulli +from sage.categories.rings import Rings +from sage.categories.bialgebras_with_basis import BialgebrasWithBasis +from sage.combinat.free_module import CombinatorialFreeModule +from sage.combinat.words.words import Words +from sage.combinat.words.finite_word import FiniteWord_class +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute +from sage.sets.family import Family +from sage.sets.integer_range import IntegerRange +from sage.rings.integer_ring import ZZ +from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.rings.infinity import Infinity +from sage.modules.free_module_element import vector + + +# the indexing set: (integer power of f_2, word in 3, 5, 7,...) +W_Odds = Words(IntegerRange(3, Infinity, 2), infinite=False) +Indices = NN.cartesian_product(W_Odds) + + +def str_to_index(x: str): + """ + Convert a string to an index. + + Every letter "2" contributes to the power of `f_2`. Other letters + define a word in `f_3`, `f_5`, ... + + Usually the letters "2" form a prefix of the input. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import str_to_index + sage: str_to_index("22357") + (2, word: 357) + """ + p = NN(x.count("2")) + w = [NN(int(i)) for i in x if i != '2'] + return Indices((p, w)) + + +def basis_f_odd_iterator(n): + """ + Return an iterator over compositions of ``n`` with parts in ``(3,5,7,...)`` + + This is used to index a basis. + + INPUT: + + - ``n`` -- an integer + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import basis_f_odd_iterator + sage: [list(basis_f_odd_iterator(i)) for i in range(2,9)] + [[], [(3,)], [], [(5,)], [(3, 3)], [(7,)], [(5, 3), (3, 5)]] + sage: list(basis_f_odd_iterator(14)) + [(11, 3), + (5, 3, 3, 3), + (3, 5, 3, 3), + (3, 3, 5, 3), + (9, 5), + (3, 3, 3, 5), + (7, 7), + (5, 9), + (3, 11)] + """ + if n == 0: + yield tuple() + return + if n == 1: + return + if n % 2: + yield (n,) + for k in range(3, n, 2): + for start in basis_f_odd_iterator(n - k): + yield start + (k, ) + + +def basis_f_iterator(n): + """ + Return an iterator over decompositions of ``n`` using ``2,3,5,7,9,...``. + + The means that each term is made of a power of 2 and a composition + of the remaining integer with parts in ``(3,5,7,...)`` + + This set is indexing a basis of the homogeneous component of weight ``n``. + + INPUT: + + - ``n`` -- an integer + + Each term is returned as a pair (integer, word) where + the integer is the exponent of 2. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import basis_f_iterator + sage: [list(basis_f_iterator(i)) for i in range(2,9)] + [[(1, word: )], + [(0, word: 3)], + [(2, word: )], + [(0, word: 5), (1, word: 3)], + [(0, word: 33), (3, word: )], + [(0, word: 7), (1, word: 5), (2, word: 3)], + [(0, word: 53), (0, word: 35), (1, word: 33), (4, word: )]] + sage: list(basis_f_iterator(11)) + [(0, word: 11), + (0, word: 533), + (0, word: 353), + (0, word: 335), + (1, word: 9), + (1, word: 333), + (2, word: 7), + (3, word: 5), + (4, word: 3)] + + TESTS:: + + sage: list(basis_f_iterator(0)) + [(0, word: )] + """ + if n and n < 2: + return + for k in range(n // 2 + 1): + for start in basis_f_odd_iterator(n - 2 * k): + yield (k, W_Odds(start, check=False)) + + +def vector_to_f(vec, N): + """ + Convert back a vector to an element of the F-algebra. + + INPUT: + + - ``vec`` -- a vector with coefficients in some base ring + + - ``N`` -- integer, the homogeneous weight + + OUTPUT: + + an homogeneous element of :func:`F_ring` over this base ring + + .. SEEALSO:: :meth:`F_algebra.to_vector` + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import vector_to_f + sage: vector_to_f((4,5),6) + 4*f3f3 + 5*f2^3 + sage: _.to_vector() + (4, 5) + """ + if isinstance(vec, (list, tuple)): + vec = vector(vec) + F = F_algebra(vec.base_ring()) + return sum(cf * F.monomial(bi) + for cf, bi in zip(vec, basis_f_iterator(N))) + + +def morphism_constructor(data): + """ + Build a morphism from the F-algebra to some codomain. + + INPUT: + + a dictionary containing the images of `f_2`, `f_3`, `f_5`, `f_7`, ... + + OUTPUT: + + the unique morphism defined by the dictionary ``data`` + + The codomain must be a zinbiel algebra, namely have both a + commutative associative product ``*`` and a zinbiel product + available as ``half_product``. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra, morphism_constructor + sage: F = F_algebra(QQ) + sage: Z = Multizeta + sage: D = {2: Z(2), 3: Z(3)} + sage: rho = morphism_constructor(D) + sage: rho(F("2")) + ζ(2) + sage: rho(F("3")) + ζ(3) + sage: rho(F("33")) + 6*ζ(1,5) + 3*ζ(2,4) + ζ(3,3) + sage: rho(F("23")) + 6*ζ(1,4) + 3*ζ(2,3) + ζ(3,2) + """ + im_f2 = data[2] + codomain = im_f2.parent() + domain = F_algebra(codomain.base_ring()) + + def morphism_on_basis(pw): + p, w = pw + if not w: + return im_f2**p + v = im_f2**p * data[w[-1]] + for letter in w[-2::-1]: + v = codomain.half_product(data[letter], v) + return v + + morphism = domain._module_morphism(morphism_on_basis, codomain=codomain) + + return morphism + + +class F_algebra(CombinatorialFreeModule): + r""" + Auxiliary algebra for the study of motivic multiple zeta values. + + INPUT: + + - ``R`` -- ring + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ); F + F-ring over Rational Field + sage: F.base_ring() + Rational Field + sage: F.is_commutative() + True + sage: TestSuite(F).run() + + sage: f2 = F("2") + sage: f3 = F("3") + sage: f5 = F("5") + + sage: s = f2*f3+f5; s + f5 + f2*f3 + """ + def __init__(self, R): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ); F + F-ring over Rational Field + + TESTS:: + + sage: F_algebra(24) + Traceback (most recent call last): + ... + TypeError: argument R must be a ring + """ + if R not in Rings(): + raise TypeError("argument R must be a ring") + self.__ngens = Infinity + self._alphabet = Family({z: z for z in [3, 5, 7]}) + cat = BialgebrasWithBasis(R).Commutative().Graded() + CombinatorialFreeModule.__init__(self, R, Indices, + latex_prefix="", prefix='f', + category=cat) + + def _repr_term(self, pw): + """ + Return the custom representation of terms. + + Each monomial is written as a power of `f_2` times a word + in `f_3`, `f_5`, ... + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ) + sage: f2 = F.gen(0) + sage: f3 = F.gen(1) + sage: f5 = F.gen(2) + sage: f2*f3+f5+f2**2 + f5 + f2*f3 + f2^2 + """ + p, w = pw + if not p: + if not w: + return "1" + resu = "" + elif p == 1: + resu = "f2" + else: + resu = f"f2^{p}" + if p and w: + resu += "*" + return resu + "".join(f"f{i}" for i in w) + + def _repr_(self): + r""" + Text representation of this algebra. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(ZZ) + sage: F # indirect doctest + F-ring over Integer Ring + """ + return "F-ring over %s" % (self.base_ring()) + + @cached_method + def one_basis(self): + r""" + Return the pair (0, empty word), which index of `1` of this algebra. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: A.one_basis() + (0, word: ) + """ + return self.basis().keys()((0, [])) + + def product_on_basis(self, pw1, pw2): + r""" + Return the product of basis elements ``w1`` and ``w2``. + + INPUT: + + - ``w1``, ``w2`` -- basis elements + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: W = A.basis().keys() + sage: A.product(A("23"), A("25")) + f2^2*f3f5 + f2^2*f5f3 + """ + p1, w1 = pw1 + p2, w2 = pw2 + return sum(self.basis()[(p1 + p2, u)] for u in w1.shuffle(w2)) + + def half_product_on_basis(self, pw1, pw2): + r""" + Return the half product of basis elements ``w1`` and ``w2``. + + This is an extension of the zinbiel product of the shuffle algebra. + + INPUT: + + - ``w1``, ``w2`` -- Basis elements + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: W = A.basis().keys() + sage: t = A.half_product(A("23"), A("25")); t + f2^2*f3f5 + + TESTS:: + + sage: [list(pw[1]) for pw, cf in t] + [[3, 5]] + """ + p1, w1 = pw1 + p2, w2 = pw2 + if not w1: + return self.monomial((p1 + p2, w2)) + letter = W_Odds([w1[0]], check=False) + return self.sum_of_monomials((p1 + p2, letter + W_Odds(u, check=False)) + for u in w1[1:].shuffle(w2)) + + @lazy_attribute + def half_product(self): + r""" + Return the `<` product. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: W = A.basis().keys() + sage: A.half_product(A("235"), A("227")) + f2^3*f3f5f7 + f2^3*f3f7f5 + """ + half = self.half_product_on_basis + return self._module_morphism(self._module_morphism(half, position=0, + codomain=self), + position=1) + + def gen(self, i): + r""" + Return the ``i``-th generator of the algebra. + + INPUT: + + - ``i`` -- an integer, index in the enumeration `f_2,f_3,f_5,f_7,\ldots` + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(ZZ) + sage: F.gen(0) + f2 + sage: F.gen(4) + f9 + """ + if i == 0: + return self.monomial(Indices((1, []))) + return self.monomial(Indices((0, [2 * i + 1]))) + + def custom_gen(self, i): + r""" + Return the generator of the F ring over `\QQ`. + + INPUT: + + - ``i`` -- a nonnegative integer + + If ``i`` is odd, this returns a single generator `f_i` of the free + shuffle algebra. + + Otherwise, it returns an appropriate multiple of a power of `f_2`. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: [A.custom_gen(i) for i in range(2,8)] + [f2, f3, 2/5*f2^2, f5, 8/35*f2^3, f7] + """ + f2 = self("2") + if i == 2: + return f2 + # now i odd >= 3 + if i % 2: + return self.gen((i - 1) // 2) + # now powers of f2 + i = i // 2 + B = bernoulli(2 * i) * (-1)**(i - 1) + B *= ZZ(2)**(3 * i - 1) * ZZ(3)**i / ZZ(2 * i).factorial() + return B * f2**i + + def an_element(self): + """ + Return a typical element. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(ZZ) + sage: F.an_element() + 3*f2*f3f5 + f2*f5f3 + """ + return self("253") + 3 * self("235") + + def some_elements(self): + """ + Return some typical elements. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(ZZ) + sage: F.some_elements() + [0, 1, f2, f3 + f5] + """ + return [self.zero(), self.one(), self.gen(0), + self.gen(1) + self.gen(2)] + + def coproduct_on_basis(self, pw): + r""" + Return the coproduct of the basis element indexed by the word ``w``. + + The coproduct is given by deconcatenation on the shuffle part, + and extended by the value + + .. MATH:: + + \Delta(f_2) = 1 \otimes f_2. + + INPUT: + + - ``w`` -- a word + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ) + sage: W = F.basis().keys() + sage: F.coproduct_on_basis(W((1,[]))) + 1 # f2 + sage: F.coproduct_on_basis(W((0,[3]))) + 1 # f3 + f3 # 1 + sage: F.coproduct_on_basis(W((1,[3]))) + 1 # f2*f3 + f3 # f2 + sage: F.coproduct_on_basis(W((0,[3,5]))) + 1 # f3f5 + f3 # f5 + f3f5 # 1 + sage: F.coproduct_on_basis(W((0,[]))) + 1 # 1 + + TESTS:: + + sage: F = F_algebra(QQ) + sage: S = F.an_element(); S + 3*f2*f3f5 + f2*f5f3 + sage: F.coproduct(S) + 3*1 # f2*f3f5 + 1 # f2*f5f3 + 3*f3 # f2*f5 + 3*f3f5 # f2 + + f5 # f2*f3 + f5f3 # f2 + """ + p, w = pw + TS = self.tensor_square() + return TS.sum_of_monomials(((0, w[:i]), (p, w[i:])) + for i in range(len(w) + 1)) + + def degree_on_basis(self, pw): + """ + Return the degree of the element ``w``. + + This is the sum of the power of `f_2` and the indices in the word. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: [A.degree_on_basis(x.leading_support()) for x in A.some_elements() if x != 0] + [0, 1, 5] + """ + p, w = pw + return ZZ(p + sum(w)) + + def _element_constructor_(self, x): + r""" + Convert ``x`` into ``self``. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: R = F_algebra(QQ) + sage: R("3") + f3 + sage: R("2") + f2 + sage: R("2235") + f2^2*f3f5 + """ + if isinstance(x, (str, FiniteWord_class)): + return self.monomial(str_to_index(x)) + + P = x.parent() + if isinstance(P, F_algebra): + if P is self: + return x + if not (P is self.base_ring()): + return self.element_class(self, x.monomial_coefficients()) + + R = self.base_ring() + # coercion via base ring + x = R(x) + if x == 0: + return self.element_class(self, {}) + return self.from_base_ring_from_one_basis(x) + + def _coerce_map_from_(self, R): + r""" + Return ``True`` if there is a coercion from ``R`` into ``self`` + and ``False`` otherwise. + + The things that coerce into ``self`` are + + - an ``F_algebra`` over a base with a coercion + map into ``self.base_ring()``. + + - Anything with a coercion into ``self.base_ring()``. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(GF(7)); F + F-ring over Finite Field of size 7 + + Elements of the algebra itself canonically coerce in:: + + sage: F.coerce(F("2")*F("3")) # indirect doctest + f2*f3 + + Elements of the integers coerce in, since there is a coerce map + from `\ZZ` to GF(7):: + + sage: F.coerce(1) # indirect doctest + 1 + + There is no coerce map from `\QQ` to `\GF{7}`:: + + sage: F.coerce(2/3) # indirect doctest + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Rational Field + to F-ring over Finite Field of size 7 + + Elements of the base ring coerce in:: + + sage: F.coerce(GF(7)(5)) + 5 + + The algebra over `\ZZ` coerces in, since + `\ZZ` coerces to `\GF{7}`:: + + sage: G = F_algebra(ZZ) + sage: Gx,Gy = G.gen(0), G.gen(1) + sage: z = F.coerce(Gx**2 * Gy);z + f2^2*f3 + sage: z.parent() is F + True + + However, `\GF{7}` does not coerce to `\ZZ`, so the + algebra over `\GF{7}` does not coerce to the one over `\ZZ`:: + + sage: G.coerce(F("2")) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from F-ring over Finite Field + of size 7 to F-ring over Integer Ring + + TESTS:: + + sage: F = F_algebra(ZZ) + sage: G = F_algebra(QQ) + + sage: F._coerce_map_from_(G) + False + sage: G._coerce_map_from_(F) + True + + sage: F._coerce_map_from_(QQ) + False + sage: G._coerce_map_from_(QQ) + True + + sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z')) + False + """ + if isinstance(R, F_algebra): + return self.base_ring().has_coerce_map_from(R.base_ring()) + + return self.base_ring().has_coerce_map_from(R) + + class Element(CombinatorialFreeModule.Element): + def coefficient(self, w): + """ + Return the coefficient of the given index. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ) + sage: S = F.an_element(); S + 3*f2*f3f5 + f2*f5f3 + sage: S.coefficient("235") + 3 + sage: S.coefficient((1,[5,3])) + 1 + """ + if isinstance(w, str): + w = str_to_index(w) + w = Indices(w) + return super().coefficient(w) + + def to_vector(self): + """ + Convert an homogeneous element to a vector. + + This is using a fixed enumeration of the basis. + + INPUT: + + an homogeneous element of :func:`F_ring` over some base ring + + OUTPUT: + + a vector with coefficients in the base ring + + .. SEEALSO:: :func:`vector_to_f` + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra, Indices + sage: F = F_algebra(QQ) + sage: f2 = F("2") + sage: x = f2**4 + F("233") + sage: x.to_vector() + (0, 0, 1, 1) + + sage: x = F.monomial(Indices((0,[11]))); x + f11 + sage: x.to_vector() + (1, 0, 0, 0, 0, 0, 0, 0, 0) + """ + F = self.parent() + BR = F.base_ring() + if not self: + return vector(BR, []) + a, b = next(iter(self))[0] + N = 2 * a + sum(int(x) for x in b) + return vector(BR, [self.coefficient(b) + for b in basis_f_iterator(N)]) + + coefficients = to_vector + + def without_f2(self): + """ + Remove all terms containing a power of `f_2`. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra, Indices + sage: F = F_algebra(QQ) + sage: t = 4*F("35")+F("27") + sage: t.without_f2() + 4*f3f5 + """ + F = self.parent() + return F._from_dict({(0, w): cf for (p, w), cf in self if not p}) From 3b06406df5cf16582b125245f5adc03d221f9d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 20 Sep 2022 13:49:42 +0200 Subject: [PATCH 651/742] using NonNegativeIntegers instead of NN --- src/sage/modular/multiple_zeta_F_algebra.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index d9e629ccd35..a37b8170eb8 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -35,14 +35,14 @@ from sage.sets.family import Family from sage.sets.integer_range import IntegerRange from sage.rings.integer_ring import ZZ -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.sets.non_negative_integers import NonNegativeIntegers from sage.rings.infinity import Infinity from sage.modules.free_module_element import vector # the indexing set: (integer power of f_2, word in 3, 5, 7,...) W_Odds = Words(IntegerRange(3, Infinity, 2), infinite=False) -Indices = NN.cartesian_product(W_Odds) +Indices = NonNegativeIntegers().cartesian_product(W_Odds) def str_to_index(x: str): @@ -60,8 +60,8 @@ def str_to_index(x: str): sage: str_to_index("22357") (2, word: 357) """ - p = NN(x.count("2")) - w = [NN(int(i)) for i in x if i != '2'] + p = x.count("2") + w = [int(i) for i in x if i != '2'] return Indices((p, w)) From 9584bf16b9ddf4248f233d01c70184b5fa86e2e3 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Tue, 20 Sep 2022 23:07:45 +0200 Subject: [PATCH 652/742] Fix wrong link in the documentation of TopologicalSubmanifold.open_subset (Trac #34565) --- src/sage/manifolds/topological_submanifold.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/manifolds/topological_submanifold.py b/src/sage/manifolds/topological_submanifold.py index 828b97703f5..314a6a16a1b 100644 --- a/src/sage/manifolds/topological_submanifold.py +++ b/src/sage/manifolds/topological_submanifold.py @@ -294,8 +294,7 @@ def open_subset(self, name, latex_name=None, coord_def={}, supersets=None): OUTPUT: - - the open subset, as an instance of - :class:`~sage.manifolds.manifold.topological_submanifold.TopologicalSubmanifold` + - the open subset, as an instance of :class:`TopologicalSubmanifold` EXAMPLES:: From c7b3fee645b47b1236fd59eeb8f3f5ceffabc13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 21 Sep 2022 09:05:29 +0200 Subject: [PATCH 653/742] remove wrong alias for coefficients --- src/sage/modular/multiple_zeta_F_algebra.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index a37b8170eb8..852899f74a5 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -711,9 +711,11 @@ def to_vector(self): sage: from sage.modular.multiple_zeta_F_algebra import F_algebra, Indices sage: F = F_algebra(QQ) sage: f2 = F("2") - sage: x = f2**4 + F("233") + sage: x = f2**4 + 34 * F("233") sage: x.to_vector() - (0, 0, 1, 1) + (0, 0, 34, 1) + sage: x.coefficients() + [34, 1] sage: x = F.monomial(Indices((0,[11]))); x f11 @@ -729,8 +731,6 @@ def to_vector(self): return vector(BR, [self.coefficient(b) for b in basis_f_iterator(N)]) - coefficients = to_vector - def without_f2(self): """ Remove all terms containing a power of `f_2`. From 0a56256f45417f9047f05d14926c2dfc3e22b8b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 21 Sep 2022 09:22:05 +0200 Subject: [PATCH 654/742] implement and use attribute _indices in F-algebra --- src/sage/modular/multiple_zeta_F_algebra.py | 26 +++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index 852899f74a5..b8faf911afa 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -42,7 +42,6 @@ # the indexing set: (integer power of f_2, word in 3, 5, 7,...) W_Odds = Words(IntegerRange(3, Infinity, 2), infinite=False) -Indices = NonNegativeIntegers().cartesian_product(W_Odds) def str_to_index(x: str): @@ -58,11 +57,11 @@ def str_to_index(x: str): sage: from sage.modular.multiple_zeta_F_algebra import str_to_index sage: str_to_index("22357") - (2, word: 357) + (2, [3, 5, 7]) """ p = x.count("2") w = [int(i) for i in x if i != '2'] - return Indices((p, w)) + return (p, w) def basis_f_odd_iterator(n): @@ -280,7 +279,8 @@ def __init__(self, R): if R not in Rings(): raise TypeError("argument R must be a ring") self.__ngens = Infinity - self._alphabet = Family({z: z for z in [3, 5, 7]}) + Indices = NonNegativeIntegers().cartesian_product(W_Odds) + self._indices = Indices cat = BialgebrasWithBasis(R).Commutative().Graded() CombinatorialFreeModule.__init__(self, R, Indices, latex_prefix="", prefix='f', @@ -389,7 +389,7 @@ def half_product_on_basis(self, pw1, pw2): p1, w1 = pw1 p2, w2 = pw2 if not w1: - return self.monomial((p1 + p2, w2)) + return self.monomial(self._indices((p1 + p2, w2))) letter = W_Odds([w1[0]], check=False) return self.sum_of_monomials((p1 + p2, letter + W_Odds(u, check=False)) for u in w1[1:].shuffle(w2)) @@ -430,8 +430,8 @@ def gen(self, i): f9 """ if i == 0: - return self.monomial(Indices((1, []))) - return self.monomial(Indices((0, [2 * i + 1]))) + return self.monomial(self._indices((1, []))) + return self.monomial(self._indices((0, [2 * i + 1]))) def custom_gen(self, i): r""" @@ -569,7 +569,7 @@ def _element_constructor_(self, x): f2^2*f3f5 """ if isinstance(x, (str, FiniteWord_class)): - return self.monomial(str_to_index(x)) + return self.monomial(self._indices(str_to_index(x))) P = x.parent() if isinstance(P, F_algebra): @@ -687,7 +687,7 @@ def coefficient(self, w): """ if isinstance(w, str): w = str_to_index(w) - w = Indices(w) + w = self.parent()._indices(w) return super().coefficient(w) def to_vector(self): @@ -708,7 +708,7 @@ def to_vector(self): EXAMPLES:: - sage: from sage.modular.multiple_zeta_F_algebra import F_algebra, Indices + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra sage: F = F_algebra(QQ) sage: f2 = F("2") sage: x = f2**4 + 34 * F("233") @@ -717,7 +717,9 @@ def to_vector(self): sage: x.coefficients() [34, 1] - sage: x = F.monomial(Indices((0,[11]))); x + TESTS:: + + sage: x = F.monomial(F._indices((0,[11]))); x f11 sage: x.to_vector() (1, 0, 0, 0, 0, 0, 0, 0, 0) @@ -737,7 +739,7 @@ def without_f2(self): EXAMPLES:: - sage: from sage.modular.multiple_zeta_F_algebra import F_algebra, Indices + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra sage: F = F_algebra(QQ) sage: t = 4*F("35")+F("27") sage: t.without_f2() From 6f110595865af941c7b1afeba01ff0f536c1b556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 21 Sep 2022 09:37:23 +0200 Subject: [PATCH 655/742] using sum_of_monomials --- src/sage/modular/multiple_zeta_F_algebra.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index b8faf911afa..2891c5b3be5 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -361,7 +361,8 @@ def product_on_basis(self, pw1, pw2): """ p1, w1 = pw1 p2, w2 = pw2 - return sum(self.basis()[(p1 + p2, u)] for u in w1.shuffle(w2)) + return self.sum_of_monomials((p1 + p2, W_Odds(u, check=False)) + for u in w1.shuffle(w2)) def half_product_on_basis(self, pw1, pw2): r""" @@ -389,7 +390,7 @@ def half_product_on_basis(self, pw1, pw2): p1, w1 = pw1 p2, w2 = pw2 if not w1: - return self.monomial(self._indices((p1 + p2, w2))) + return self.basis()[(p1 + p2, w2)] letter = W_Odds([w1[0]], check=False) return self.sum_of_monomials((p1 + p2, letter + W_Odds(u, check=False)) for u in w1[1:].shuffle(w2)) From d5ee67d85985f1be9c3807db3622bfa9ac4bc4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 21 Sep 2022 13:17:51 +0200 Subject: [PATCH 656/742] using homogeneous_to_vector and homogeneous_from_vector --- src/sage/modular/multiple_zeta.py | 6 +- src/sage/modular/multiple_zeta_F_algebra.py | 86 ++++++++++----------- 2 files changed, 45 insertions(+), 47 deletions(-) diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index fd9fb808f9c..10c7008330a 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -1394,7 +1394,7 @@ def phi_as_vector(self): """ if not self.is_homogeneous(): raise ValueError('only defined for homogeneous elements') - return self.parent().phi(self).to_vector() + return self.parent().phi(self).homogeneous_to_vector() def _numerical_approx_pari(self): r""" @@ -2680,7 +2680,7 @@ def rho_matrix_inverse(n): resu = [] for b in base: phi_b = phi_on_basis(b) - resu.append(phi_b.to_vector()) + resu.append(phi_b.homogeneous_to_vector()) dN = len(resu) return ~matrix(QQ, dN, dN, resu) @@ -2721,6 +2721,6 @@ def rho_inverse(elt): p, w = pw N = 2 * p + sum(int(c) for c in w) - v = elt.to_vector() + v = elt.homogeneous_to_vector() w = v * rho_matrix_inverse(N) return sum(cf * b for cf, b in zip(w, M_BR.basis_data(BR, N))) diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index 2891c5b3be5..2ca60775d0a 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -16,13 +16,14 @@ - Frédéric Chapoton (2022-09): Initial version """ - # **************************************************************************** # Copyright (C) 2022 Frédéric Chapoton # # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # **************************************************************************** +from __future__ import annotations +from typing import Iterator from sage.arith.misc import bernoulli from sage.categories.rings import Rings @@ -32,7 +33,6 @@ from sage.combinat.words.finite_word import FiniteWord_class from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute -from sage.sets.family import Family from sage.sets.integer_range import IntegerRange from sage.rings.integer_ring import ZZ from sage.sets.non_negative_integers import NonNegativeIntegers @@ -44,7 +44,7 @@ W_Odds = Words(IntegerRange(3, Infinity, 2), infinite=False) -def str_to_index(x: str): +def str_to_index(x: str) -> tuple: """ Convert a string to an index. @@ -64,7 +64,7 @@ def str_to_index(x: str): return (p, w) -def basis_f_odd_iterator(n): +def basis_f_odd_iterator(n) -> Iterator[tuple]: """ Return an iterator over compositions of ``n`` with parts in ``(3,5,7,...)`` @@ -102,7 +102,7 @@ def basis_f_odd_iterator(n): yield start + (k, ) -def basis_f_iterator(n): +def basis_f_iterator(n) -> Iterator[tuple]: """ Return an iterator over decompositions of ``n`` using ``2,3,5,7,9,...``. @@ -152,38 +152,7 @@ def basis_f_iterator(n): yield (k, W_Odds(start, check=False)) -def vector_to_f(vec, N): - """ - Convert back a vector to an element of the F-algebra. - - INPUT: - - - ``vec`` -- a vector with coefficients in some base ring - - - ``N`` -- integer, the homogeneous weight - - OUTPUT: - - an homogeneous element of :func:`F_ring` over this base ring - - .. SEEALSO:: :meth:`F_algebra.to_vector` - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta_F_algebra import vector_to_f - sage: vector_to_f((4,5),6) - 4*f3f3 + 5*f2^3 - sage: _.to_vector() - (4, 5) - """ - if isinstance(vec, (list, tuple)): - vec = vector(vec) - F = F_algebra(vec.base_ring()) - return sum(cf * F.monomial(bi) - for cf, bi in zip(vec, basis_f_iterator(N))) - - -def morphism_constructor(data): +def morphism_constructor(data: dict): """ Build a morphism from the F-algebra to some codomain. @@ -280,13 +249,12 @@ def __init__(self, R): raise TypeError("argument R must be a ring") self.__ngens = Infinity Indices = NonNegativeIntegers().cartesian_product(W_Odds) - self._indices = Indices cat = BialgebrasWithBasis(R).Commutative().Graded() CombinatorialFreeModule.__init__(self, R, Indices, latex_prefix="", prefix='f', category=cat) - def _repr_term(self, pw): + def _repr_term(self, pw) -> str: """ Return the custom representation of terms. @@ -316,7 +284,7 @@ def _repr_term(self, pw): resu += "*" return resu + "".join(f"f{i}" for i in w) - def _repr_(self): + def _repr_(self) -> str: r""" Text representation of this algebra. @@ -554,6 +522,36 @@ def degree_on_basis(self, pw): p, w = pw return ZZ(p + sum(w)) + def homogeneous_from_vector(self, vec, N): + """ + Convert back a vector to an element of the F-algebra. + + INPUT: + + - ``vec`` -- a vector with coefficients in some base ring + + - ``N`` -- integer, the homogeneous weight + + OUTPUT: + + an homogeneous element of :func:`F_ring` over this base ring + + .. SEEALSO:: :meth:`F_algebra.homogeneous_to_vector` + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ) + sage: F.homogeneous_from_vector((4,5),6) + 4*f3f3 + 5*f2^3 + sage: _.homogeneous_to_vector() + (4, 5) + """ + if isinstance(vec, (list, tuple)): + vec = vector(vec) + return self.sum(cf * self.monomial(bi) + for cf, bi in zip(vec, basis_f_iterator(N))) + def _element_constructor_(self, x): r""" Convert ``x`` into ``self``. @@ -691,7 +689,7 @@ def coefficient(self, w): w = self.parent()._indices(w) return super().coefficient(w) - def to_vector(self): + def homogeneous_to_vector(self): """ Convert an homogeneous element to a vector. @@ -705,7 +703,7 @@ def to_vector(self): a vector with coefficients in the base ring - .. SEEALSO:: :func:`vector_to_f` + .. SEEALSO:: :meth:`F_algebra.homogeneous_from_vector` EXAMPLES:: @@ -713,7 +711,7 @@ def to_vector(self): sage: F = F_algebra(QQ) sage: f2 = F("2") sage: x = f2**4 + 34 * F("233") - sage: x.to_vector() + sage: x.homogeneous_to_vector() (0, 0, 34, 1) sage: x.coefficients() [34, 1] @@ -722,7 +720,7 @@ def to_vector(self): sage: x = F.monomial(F._indices((0,[11]))); x f11 - sage: x.to_vector() + sage: x.homogeneous_to_vector() (1, 0, 0, 0, 0, 0, 0, 0, 0) """ F = self.parent() From 1c9e6279f6f8d7a9d94de35f1d6a8494818c42f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 20 Sep 2022 18:57:19 +0200 Subject: [PATCH 657/742] Fix minor doc formatting issues in dancing links --- src/sage/combinat/matrices/dancing_links.pyx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/matrices/dancing_links.pyx b/src/sage/combinat/matrices/dancing_links.pyx index 953b5c4e680..9b5ee82aa81 100644 --- a/src/sage/combinat/matrices/dancing_links.pyx +++ b/src/sage/combinat/matrices/dancing_links.pyx @@ -193,8 +193,8 @@ cdef class dancing_linksWrapper: r""" Reinitialization of the search algorithm - This recreates an empty `dancing_links` object and adds the rows to - the instance of dancing_links. + This recreates an empty ``dancing_links`` object and adds the rows to + the instance of ``dancing_links.`` EXAMPLES:: @@ -805,7 +805,7 @@ cdef class dancing_linksWrapper: INPUT: - ``ncpus`` -- integer (default: ``None``), maximal number of - subprocesses to use at the same time. If `ncpus>1` the dancing + subprocesses to use at the same time. If ``ncpus>1`` the dancing links problem is split into independent subproblems to allow parallel computation. If ``None``, it detects the number of effective CPUs in the system using @@ -968,8 +968,8 @@ cdef class dancing_linksWrapper: .. NOTE:: - When comparing the time taken by method `one_solution`, - have in mind that `one_solution_using_sat_solver` first + When comparing the time taken by method ``one_solution``, + have in mind that ``one_solution_using_sat_solver`` first creates the SAT solver instance from the dancing links solver. This copy of data may take many seconds depending on the size of the problem. @@ -1096,8 +1096,8 @@ cdef class dancing_linksWrapper: .. NOTE:: - When comparing the time taken by method `one_solution`, have in - mind that `one_solution_using_milp_solver` first creates (and + When comparing the time taken by method ``one_solution``, have in + mind that ``one_solution_using_milp_solver`` first creates (and caches) the MILP solver instance from the dancing links solver. This copy of data may take many seconds depending on the size of the problem. From 9548409c9cd69ec52a3c5bca95331a5595d64727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 21 Sep 2022 15:42:44 +0200 Subject: [PATCH 658/742] change name of example in simplicial complexes --- src/doc/en/reference/references/index.rst | 4 ++++ src/sage/homology/examples.py | 2 +- src/sage/topology/simplicial_complex_catalog.py | 4 ++-- src/sage/topology/simplicial_complex_examples.py | 14 ++++++-------- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 1dbd6f036e7..dd3c36e2540 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -2662,6 +2662,10 @@ REFERENCES: .. [Gop1981] \V. D. Goppa, “Codes on algebraic curves,” Sov. Math. Dokl., vol. 24, no. 1, pp. 170–172, 1981. +.. [Gor2016] \D. Gorodkov, *A 15-vertex triangulation of the quaternionic + projective plane*, Discrete & Computational Geometry, vol. 62, + pp. 348-373 (2019). :doi:`10.1007/s00454-018-00055-w` + .. [Gos1972] Bill Gosper, "Continued Fraction Arithmetic" https://perl.plover.com/classes/cftalk/INFO/gosper.txt diff --git a/src/sage/homology/examples.py b/src/sage/homology/examples.py index 704b1219189..c469f9d6c54 100644 --- a/src/sage/homology/examples.py +++ b/src/sage/homology/examples.py @@ -21,7 +21,7 @@ 'SurfaceOfGenus', 'MooreSpace', 'ComplexProjectivePlane', - 'PseudoQuaternionicProjectivePlane', + 'QuaternionicProjectivePlane', 'PoincareHomologyThreeSphere', 'RealProjectiveSpace', 'K3Surface', diff --git a/src/sage/topology/simplicial_complex_catalog.py b/src/sage/topology/simplicial_complex_catalog.py index cbb84e0892e..07a0de43b4a 100644 --- a/src/sage/topology/simplicial_complex_catalog.py +++ b/src/sage/topology/simplicial_complex_catalog.py @@ -34,7 +34,7 @@ - :meth:`~sage.topology.examples.MooreSpace` - :meth:`~sage.topology.examples.NotIConnectedGraphs` - :meth:`~sage.topology.examples.PoincareHomologyThreeSphere` -- :meth:`~sage.topology.examples.PseudoQuaternionicProjectivePlane` +- :meth:`~sage.topology.examples.QuaternionicProjectivePlane` - :meth:`~sage.topology.examples.RandomComplex` - :meth:`~sage.topology.examples.RandomTwoSphere` - :meth:`~sage.topology.examples.RealProjectivePlane` @@ -69,7 +69,7 @@ ProjectivePlane, RealProjectivePlane, KleinBottle, FareyMap, GenusSix, SurfaceOfGenus, MooreSpace, - ComplexProjectivePlane, PseudoQuaternionicProjectivePlane, + ComplexProjectivePlane, QuaternionicProjectivePlane, PoincareHomologyThreeSphere, RealProjectiveSpace, K3Surface, BarnetteSphere, BrucknerGrunbaumSphere, NotIConnectedGraphs, MatchingComplex, ChessboardComplex, RandomComplex, SumComplex, diff --git a/src/sage/topology/simplicial_complex_examples.py b/src/sage/topology/simplicial_complex_examples.py index 27d74458a65..971b7d75d83 100644 --- a/src/sage/topology/simplicial_complex_examples.py +++ b/src/sage/topology/simplicial_complex_examples.py @@ -34,7 +34,7 @@ - :func:`MooreSpace` - :func:`NotIConnectedGraphs` - :func:`PoincareHomologyThreeSphere` -- :func:`PseudoQuaternionicProjectivePlane` +- :func:`QuaternionicProjectivePlane` - :func:`RandomComplex` - :func:`RandomTwoSphere` - :func:`RealProjectivePlane` @@ -544,15 +544,14 @@ def ComplexProjectivePlane(): name='Minimal triangulation of the complex projective plane') -def PseudoQuaternionicProjectivePlane(): +def QuaternionicProjectivePlane(): r""" Return a pure simplicial complex of dimension 8 with 490 facets. .. WARNING:: - This is expected to be a triangulation of the projective plane - `HP^2` over the ring of quaternions, but this has not been - proved yet. + This was proven to be a triangulation of the projective plane + `HP^2` over the ring of quaternions by Gorodkov in 2016 [Gor2016]_. This simplicial complex has the same homology as `HP^2`. Its automorphism group is isomorphic to the alternating group `A_5` @@ -560,12 +559,11 @@ def PseudoQuaternionicProjectivePlane(): This is defined here using the description in [BK1992]_. This article deals with three different triangulations. This procedure - returns the only one which has a transitive group of - automorphisms. + returns the only one which has a transitive group of automorphisms. EXAMPLES:: - sage: HP2 = simplicial_complexes.PseudoQuaternionicProjectivePlane() ; HP2 + sage: HP2 = simplicial_complexes.QuaternionicProjectivePlane() ; HP2 Simplicial complex with 15 vertices and 490 facets sage: HP2.f_vector() [1, 15, 105, 455, 1365, 3003, 4515, 4230, 2205, 490] From 7b55ef58e4f2c274165b5a8e277149f83705b52c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 15 Aug 2022 11:07:03 +0900 Subject: [PATCH 659/742] Speeding up powers of lazy series by using a different algorithm. --- src/sage/rings/lazy_series.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 9f4cd1b0f39..57e19c1bc0a 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -117,9 +117,11 @@ from sage.structure.element import Element, parent from sage.structure.richcmp import op_EQ, op_NE from sage.functions.other import factorial +from sage.misc.misc_c import prod from sage.arith.power import generic_power from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.data_structures.stream import ( @@ -2014,7 +2016,12 @@ def __pow__(self, n): from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - exp = P(lambda k: 1/factorial(ZZ(k)), valuation=0) + + if n in QQ or n in self.base_ring(): + f = P(lambda k: prod(n - i for i in range(k)) / ZZ(k).factorial(), valuation=0) + return f(self - 1) + + exp = P(lambda k: 1 / ZZ(k).factorial(), valuation=0) return exp(self.log() * n) def sqrt(self): @@ -2045,7 +2052,7 @@ def sqrt(self): sage: f*f - Z O(1/(8^s)) """ - return self ** (1/ZZ(2)) + return self ** QQ((1, 2)) # == 1/2 class LazyCauchyProductSeries(LazyModuleElement): From 7d395b55bc21c2ca30cb0a0e9dd1fabd3656255f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 21 Sep 2022 15:55:33 +0200 Subject: [PATCH 660/742] remove duplicate code --- src/sage/modular/multiple_zeta.py | 84 ------------------------------- 1 file changed, 84 deletions(-) diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 10c7008330a..ed104785883 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -547,90 +547,6 @@ def __call__(self, index, prec=None, reverse=True): Values = MultizetaValues() -def basis_f_odd_iterator(n): - """ - Return an iterator over compositions of ``n`` with parts in ``(3,5,7,...)`` - - INPUT: - - - ``n`` -- an integer - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import basis_f_odd_iterator - sage: [list(basis_f_odd_iterator(i)) for i in range(2,9)] - [[], [(3,)], [], [(5,)], [(3, 3)], [(7,)], [(5, 3), (3, 5)]] - sage: list(basis_f_odd_iterator(14)) - [(11, 3), - (5, 3, 3, 3), - (3, 5, 3, 3), - (3, 3, 5, 3), - (9, 5), - (3, 3, 3, 5), - (7, 7), - (5, 9), - (3, 11)] - """ - if n == 0: - yield tuple() - return - if n == 1: - return - if n % 2: - yield (n,) - for k in range(3, n, 2): - for start in basis_f_odd_iterator(n - k): - yield start + (k, ) - - -def basis_f_iterator(n): - """ - Return an iterator over decompositions of ``n`` using ``2,3,5,7,9,...``. - - The means that each term is made of a power of 2 and a composition - of the remaining integer with parts in ``(3,5,7,...)`` - - INPUT: - - - ``n`` -- an integer - - Each term is returned as a pair (integer, word) where - the integer is the exponent of 2. - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import basis_f_iterator - sage: [list(basis_f_iterator(i)) for i in range(2,9)] - [[(1, word: )], - [(0, word: f3)], - [(2, word: )], - [(0, word: f5), (1, word: f3)], - [(0, word: f3,f3), (3, word: )], - [(0, word: f7), (1, word: f5), (2, word: f3)], - [(0, word: f5,f3), (0, word: f3,f5), (1, word: f3,f3), (4, word: )]] - sage: list(basis_f_iterator(11)) - [(0, word: f11), - (0, word: f5,f3,f3), - (0, word: f3,f5,f3), - (0, word: f3,f3,f5), - (1, word: f9), - (1, word: f3,f3,f3), - (2, word: f7), - (3, word: f5), - (4, word: f3)] - - TESTS:: - - sage: list(basis_f_iterator(0)) - [(0, word: )] - """ - if n and n < 2: - return - for k in range(n // 2 + 1): - for start in basis_f_odd_iterator(n - 2 * k): - yield (k, Word(['f{}'.format(d) for d in start])) - - def extend_multiplicative_basis(B, n): """ Extend a multiplicative basis into a basis. From 5df08cb7dd7bffd732d6143a7d38244c30946e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 21 Sep 2022 15:58:28 +0200 Subject: [PATCH 661/742] simplify code a little bit in MZV --- src/sage/modular/multiple_zeta.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index ed104785883..5fb94f92229 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -494,8 +494,7 @@ def pari_eval(self, index): if weight <= self.max_weight: index = pari.zetamultconvert(index, 2) return self._data[index - 1] - else: - return pari.zetamult(index, precision=self.prec) + return pari.zetamult(index, precision=self.prec) def __call__(self, index, prec=None, reverse=True): r""" @@ -540,8 +539,7 @@ def __call__(self, index, prec=None, reverse=True): index = pari.zetamultconvert(index, 2) value = self._data[index - 1] return value.sage().n(prec=prec) - else: - return pari.zetamult(index, precision=prec).sage().n(prec=prec) + return pari.zetamult(index, precision=prec).sage().n(prec=prec) Values = MultizetaValues() @@ -937,7 +935,7 @@ def _element_constructor_(self, x): if isinstance(x, list): x = tuple(x) return self._monomial(W(x, check=False)) - elif isinstance(parent(x), Multizetas_iterated): + if isinstance(parent(x), Multizetas_iterated): return x.composition() raise TypeError('invalid input for building a multizeta value') @@ -1042,7 +1040,7 @@ def basis_filtration(self, d, reverse=False): raise ValueError('d must be a non-negative integer') if d == 0: return [self([])] - elif d == 1: + if d == 1: return [] Values.reset(max_weight=d) @@ -1376,8 +1374,7 @@ def numerical_approx(self, prec=None, digits=None, algorithm=None): if prec < Values.prec: s = sum(cf * Values(tuple(w)) for w, cf in self.monomial_coefficients().items()) return s.n(prec=prec) - else: - return sum(cf * Values(tuple(w), prec=prec) for w, cf in self.monomial_coefficients().items()) + return sum(cf * Values(tuple(w), prec=prec) for w, cf in self.monomial_coefficients().items()) class Multizetas_iterated(CombinatorialFreeModule): @@ -1885,8 +1882,7 @@ def _element_constructor_(self, x): x = R(x) if x == 0: return self.element_class(self, {}) - else: - return self.from_base_ring_from_one_basis(x) + return self.from_base_ring_from_one_basis(x) class Element(CombinatorialFreeModule.Element): def simplify(self): From d4450fb31c4d7331cafbad27bf45c4c3697df679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Wed, 21 Sep 2022 16:42:14 +0200 Subject: [PATCH 662/742] Update lazy_series' __pow__ docstring It used to only document the integer powers of a series whereas it can do much more. --- src/sage/rings/lazy_series.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 57e19c1bc0a..8aafe4fd4c6 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -1995,7 +1995,9 @@ def __pow__(self, n): INPUT: - - ``n`` -- integer; the power to which to raise the series + - ``n`` -- the power to which to raise the series. This may be an + integer, a rational number, an element of the base ring, or an other + series. EXAMPLES:: @@ -2010,6 +2012,20 @@ def __pow__(self, n): 1 + 2/3/2^s + 2/3/3^s + 5/9/4^s + 2/3/5^s + 4/9/6^s + 2/3/7^s + O(1/(8^s)) sage: f^3 - Z O(1/(8^s)) + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: f = 1 + z + sage: f ^ (1 / 2) + 1 + 1/2*z - 1/8*z^2 + 1/16*z^3 - 5/128*z^4 + 7/256*z^5 - 21/1024*z^6 + O(z^7) + + sage: f^f + 1 + z + z^2 + 1/2*z^3 + 1/3*z^4 + 1/12*z^5 + 3/40*z^6 + O(z^7) + + sage: q = ZZ['q'].fraction_field().gen() + sage: L. = LazyLaurentSeriesRing(q.parent()) + sage: f = (1 - z)^q + sage: f + 1 - q*z + ((q^2 - q)/2)*z^2 + ((-q^3 + 3*q^2 - 2*q)/6)*z^3 + ((q^4 - 6*q^3 + 11*q^2 - 6*q)/24)*z^4 + ((-q^5 + 10*q^4 - 35*q^3 + 50*q^2 - 24*q)/120)*z^5 + ((q^6 - 15*q^5 + 85*q^4 - 225*q^3 + 274*q^2 - 120*q)/720)*z^6 + O(z^7) """ if n in ZZ: return generic_power(self, n) From 92f1edab2ca281fd0fdb4e597388fb172a35a030 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Wed, 21 Sep 2022 10:46:40 -0700 Subject: [PATCH 663/742] trac 34528: remove m1/m2 warning from gfortran/SPKG.rst, and add one to gcc/SPKG.rst. --- build/pkgs/gcc/SPKG.rst | 5 +++++ build/pkgs/gfortran/SPKG.rst | 7 ------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/build/pkgs/gcc/SPKG.rst b/build/pkgs/gcc/SPKG.rst index 87a056f83d5..cc6c8153a8c 100644 --- a/build/pkgs/gcc/SPKG.rst +++ b/build/pkgs/gcc/SPKG.rst @@ -42,6 +42,11 @@ you need a recent version of Xcode. (Installing the ``gfortran`` SPKG becomes a no-op in this case.) +Building Sage from source on Apple Silicon (M1/M2) requires the use of +Apple's Command Line Tools, and those tools include a suitable +compiler. Sage's ``gcc`` SPKG is not suitable for M1/M2; building it +will likely fail. + License ------- diff --git a/build/pkgs/gfortran/SPKG.rst b/build/pkgs/gfortran/SPKG.rst index b6ba9b9bb4d..9559b98456d 100644 --- a/build/pkgs/gfortran/SPKG.rst +++ b/build/pkgs/gfortran/SPKG.rst @@ -20,13 +20,6 @@ need to run:: $ ./configure CC=clang CXX=clang++ FC=flang -Building Sage from source on Apple Silicon (M1/M2) requires the use of -​the `Homebrew package manager `_ (recommended) or -conda-forge, which package versions of GCC 12.x (including -``gfortran``) with the necessary changes for this platform. These -changes are not in a released upstream version of GCC, and hence -the ``gfortran`` SPKG is not suitable for the M1/M2. - License ------- From ec7d50c6189e2a24d72342cea676419110f6bb2e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 21 Sep 2022 17:05:37 -0700 Subject: [PATCH 664/742] build/pkgs/gcc/SPKG.rst: Add info from https://trac.sagemath.org/ticket/32074 --- build/pkgs/gcc/SPKG.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/build/pkgs/gcc/SPKG.rst b/build/pkgs/gcc/SPKG.rst index cc6c8153a8c..75feee2d6d8 100644 --- a/build/pkgs/gcc/SPKG.rst +++ b/build/pkgs/gcc/SPKG.rst @@ -24,6 +24,25 @@ need to run:: Vendor and versions of the C and C++ compilers should match. +Users of older Linux distributions (in particular, ``ubuntu-xenial`` +or older, ``debian-stretch`` or older, ``linuxmint-18`` or older) +should upgrade their systems before attempting to install Sage from +source. Users of ``ubuntu-bionic``, ``linuxmint-19.x``, and +``opensuse-15.x`` can install a versioned ``gcc`` system package +and then use:: + + $ ./configure CC=gcc-8 CXX=g++-8 FC=gfortran-8 + +or similar. Users on ``ubuntu`` can also install a modern compiler +toolchain `using the ubuntu-toolchain-r ppa +`_. +On ``ubuntu-trusty``, also the package ``binutils-2.26`` is required; +after installing it, make it available using ``export +PATH="/usr/lib/binutils-2.26/bin:$PATH"``. Instead of upgrading their +distribution, users of ``centos-7`` can install a modern compiler +toolchain `using Redhat's devtoolset +`_. + This package uses the non-standard default ``configure --with-system-gcc=force``, giving an error at ``configure`` time when no suitable system compilers are configured. From 5f3a23fc0b7d07d0eb928f4d9c612d3376ee83e2 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 22 Sep 2022 11:31:37 +0900 Subject: [PATCH 665/742] Recover the case for single pair --- src/sage/arith/misc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index eaded5d7532..f08b01afb50 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -3307,13 +3307,15 @@ def CRT_list(values, moduli): raise ValueError("arguments to CRT_list should be lists of the same length") if not values: return ZZ.zero() + if len(values) == 1: + return moduli[0].parent()(values[0]) # The result is computed using a binary tree. In typical cases, # this scales much better than folding the list from one side. from sage.arith.functions import lcm while len(values) > 1: vs, ms = values[::2], moduli[::2] - for i,(v,m) in enumerate(zip(values[1::2], moduli[1::2])): + for i, (v, m) in enumerate(zip(values[1::2], moduli[1::2])): vs[i] = CRT(vs[i], v, ms[i], m) ms[i] = lcm(ms[i], m) values, moduli = vs, ms From 97df3007235d8d654498f7179b96555ec98631a4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 22 Sep 2022 12:43:30 +0900 Subject: [PATCH 666/742] Updating sf/sfa.py doctest due to #34494. --- src/sage/combinat/sf/sfa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 1fb9d204e34..e9af98027f2 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -3137,7 +3137,7 @@ def plethysm(self, x, include=None, exclude=None): sage: T = tensor([X,Y]) sage: s = SymmetricFunctions(T).s() sage: s(2*T.one()) - (2*B[word:]#B[word:])*s[] + (2*B[]#B[])*s[] .. TODO:: From e64cb5fb155c2597abaf63ed21eddf17356aab4e Mon Sep 17 00:00:00 2001 From: Paul Fili Date: Mon, 25 Nov 2019 15:02:57 -0600 Subject: [PATCH 667/742] Added Arakelov Zhang pairing function to fresh copy of projective_ds.py --- .../arithmetic_dynamics/projective_ds.py | 231 ++++++++++++++++++ 1 file changed, 231 insertions(+) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index cdfc11a9e52..ac936e019ce 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1103,6 +1103,237 @@ def nth_iterate(self, P, n, **kwds): raise TypeError("must be a forward orbit") return self.orbit(P, [n,n+1], **kwds)[0] + def arakelov_zhang_pairing(self, g, n=5, f_starting_point=None, g_starting_point=None, check_primes_of_bad_reduction=False, prec=None, noise_multiplier=2): + r""" + Returns an estimate of the Arakelov-Zhang pairing of the rational maps ``self`` and ``g`` on `\mathbb{P}^1` over + a number field. + + The Arakelov-Zhang pairing was introduced by Petsche, Szpiro, and Tucker in 2012, and is a measure of dynamical closeness + of two rational maps. They prove inter alia that if one takes a sequence of small points for one map (for example, + preperiodic points for ``self``) and measure their dynamical height with respect to the other map (say, ``g``), then + the values of the height will tend to the value of the Arakelov-Zhang pairing. + + The Arakelov-Zhang pairing involves mutual energy integrals between dynamical measures, which are in the case of + polynomials the equilibrium measures of the associated Julia sets at each place. As a result these pairings are + very difficult to compute exactly via analytic methods. We use a discrete approximation to these energy integrals. + + ALGORITHM: + We select periodic points of order `n`, or ``n``-th preimages of a specified starting value given by + ``f_starting_point`` and ``g_starting_point``, and then, at the archimedean places and the places of bad + reduction of the two maps, we compute the discrete approximations to the energy integrals involved using these + points. + + INPUT: + + - ``g`` - a rational map of `\mathbb{P}^1` given as a ProjectiveMorphism. ``g`` and ``self`` should have the same field of definition. + + kwds: + + - ``n`` - positive integer + Order of periodic points to use or preimages to take if starting points are specified. + default: 5 + + - ``f_starting_point`` - value in the base number field or None. + If ``f_starting_point`` is None, we solve for points of period ``n`` for ``self``. Otherwise, we take + ``n``-th preimages of the point given by ``f_starting_point`` under ``f`` on the affine line. (optional) + default: None + + - ``g_starting_point`` - value in the base number field or None. + If ``g_starting_point`` is None, we solve for points of period ``n`` for ``g``. Otherwise, we take + ``n``-th preimages of the point given by ``g_starting_point`` under ``g`` on the affine line. (optional) + default: None + + - ``check_primes_of_bad_reduction`` - boolean + Passed to the ``primes_of_bad_reduction`` function for ``self`` and ``g``. (optional) + default: False + + - ``prec`` - default precision for RealField values which are returned. (optional) + default: RealField default + + - ``noise_multiplier`` - real value. + Discriminant terms involved in the computation at the archimedean places are often not needed, particularly + if the capacity of the Julia sets is 1, and introduce a lot of error. By a well-known result of Mahler + (see also M. Baker, ""A lower bound for averages of dynamical Green's functions") such error (for a set of + `N` points) is on the order of `\log(N)/N` after our normalization. We check if the value of the archimedean + discriminant terms is within ``2*noise_multiplier`` of `\log(N)/N`, and if so, we discard it. In practice this + greatly improves the accuracy of the estimate of the pairing. If desired, ``noise_multiplier`` can be set to 0, + and no terms will be ignored. + default: 2 + + OUTPUT: + + - a real number estimating the Arakelov-Zhang pairing of the two rational maps. + + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ,1) + sage: f = DynamicalSystem_projective([x^2+4*y^2, y^2]) + sage: g = DynamicalSystem_projective([x^2,y^2]) + sage: pairingval = f.arakelov_zhang_pairing(g, n=6); pairingval + 0.750178391443644 + sage: # Compare to the exact value: + sage: dynheight = f.canonical_height(P(0,1)); dynheight + 0.75017839144364417318023000563 + sage: dynheight - pairingval + 0.000000000000000 + + Notice that if we set the noise_multiplier to 0, the accuracy is diminished:: + + sage: P. = ProjectiveSpace(QQ,1) + sage: f = DynamicalSystem_projective([x^2+4*y^2, y^2]) + sage: g = DynamicalSystem_projective([x^2,y^2]) + sage: pairingval = f.arakelov_zhang_pairing(g, n=6, noise_multiplier=0) + sage: print pairingval + 0.650660018921632 + sage: dynheight = f.canonical_height(P(0,1)); dynheight + sage: print pairingval - dynheight + -0.0995183725220122 + + We compute the example of Prop. 18(d) from Petsche, Szpiro and Tucker:: + + sage: P. = ProjectiveSpace(QQ,1) + sage: f = DynamicalSystem_projective([y^2 - (y - x)^2, y^2]) + sage: g = DynamicalSystem_projective([x^2,y^2]) + sage: f.arakelov_zhang_pairing(g) + 0.326954667248466 + sage: # Correct value should be = 0.323067... + sage: f.arakelov_zhang_pairing(g, n=9) + 0.323091061918965 + sage: _ - 0.323067 + 0.0000240619189654789 + + Also from Prop. 18 of Petsche, Szpiro and Tucker, includes places of bad reduction:: + + sage: R. = PolynomialRing(ZZ) + sage: K. = NumberField(z^3 - 11) + sage: P. = ProjectiveSpace(K,1) + sage: a = 7/(b-1) + sage: f = DynamicalSystem_projective([a*y^2 - (a*y - x)^2, y^2]) + sage: g = DynamicalSystem_projective([x^2,y^2]) + sage: # If all archimedean absolute values of a have modulus > 2, then the pairing should be h(a). + sage: f.arakelov_zhang_pairing(g, n=6) + 1.93846423207664 + sage: _ - a.global_height() + -0.00744591697867270 + + """ + PS = self.domain() + n = Integer(n) + if PS != g.domain(): + raise TypeError("Implemented only for rational maps of the same projective line.") + if (n < 1): + raise ValueError("Period must be a positive integer.") + from sage.schemes.projective.projective_space import is_ProjectiveSpace + if not is_ProjectiveSpace(PS) or not is_ProjectiveSpace(g.domain()): + raise NotImplementedError("Not implemented for subschemes.") + if (PS.dimension_relative() > 1): + raise NotImplementedError("Only implemented for dimension 1.") + if not self.is_endomorphism(): + raise TypeError("Self must be an endomorphism.") + if not PS.base_ring() in NumberFields() and not PS.base_ring() is QQbar: + raise NotImplementedError("Not implemented for base fields other than number fields.") + + from sage.misc.misc import union + badprimes = union(self.primes_of_bad_reduction(check=check_primes_of_bad_reduction), g.primes_of_bad_reduction(check=check_primes_of_bad_reduction)) + + fiterate = self.nth_iterate_map(n) + giterate = g.nth_iterate_map(n) + if f_starting_point is None: + Fpolyhom = fiterate.defining_polynomials()[0]*self.domain().gens()[1]-fiterate.defining_polynomials()[1]*self.domain().gens()[0] + else: + Fpolyhom = fiterate.defining_polynomials()[0]-f_starting_point*fiterate.defining_polynomials()[1] + if g_starting_point is None: + Gpolyhom = giterate.defining_polynomials()[0]*g.domain().gens()[1]-giterate.defining_polynomials()[1]*g.domain().gens()[0] + else: + Gpolyhom = giterate.defining_polynomials()[0]-g_starting_point*giterate.defining_polynomials()[1] + + Fpoly = Fpolyhom([(self.domain().gens()[0]),1]).univariate_polynomial().monic() + Gpoly = Gpolyhom([(g.domain().gens()[0]),1]).univariate_polynomial().monic() + + # If Fpoly and Gpoly are not squarefree, make them squarefree. + if not Fpoly.is_squarefree(): + Fpoly = Fpoly.quo_rem(gcd(Fpoly, Fpoly.derivative()))[0] + if not Gpoly.is_squarefree(): + Gpoly = Gpoly.quo_rem(gcd(Gpoly, Gpoly.derivative()))[0] + + if Fpoly.degree() <= 2 or Gpoly.degree() <= 2: + # we are very unlucky and fpoint or gpoint is exceptional + raise ValueError("It appears that one of the starting points is exceptional. Please specify non-exceptional initial point.") + + if gcd(Fpoly,Gpoly).degree() > 0: + if Fpoly.degree() > Gpoly.degree(): + Fpoly = Fpoly.quo_rem(gcd(Fpoly,Gpoly))[0] + else: + Gpoly = Gpoly.quo_rem(gcd(Fpoly,Gpoly))[0] + if Fpoly.degree() <= 2 or Gpoly.degree() <= 2: + raise ValueError("It appears that after removing common factors, the n-th iterates of self and g had too many roots in common. Try another n or starting values.") + + Fdisc = Fpoly.discriminant() + Gdisc = Gpoly.discriminant() + + dF = Fpoly.degree() + dG = Gpoly.degree() + + res = Fpoly.resultant(Gpoly) + + oldprec = prec + if prec < 512: + # Want temporarily higher precision here since resultants are usually very, very large. + # This isn't to say the computation is so accurate, merely that we want to keep track + # of potentially very large height integers/rationals. + prec = 512 + R = RealField(prec) + AZpairing = R(0) + # The code below actually computes -( mu_f - mu_g, mu_f - mu_g ), so flip the sign at the end. + if PS.base_ring() is QQ: + for p in badprimes: + temp = (ZZ(1)/2)*(-Fdisc.ord(p))*R(p).log()/(dF**2) + if abs(temp) > noise_multiplier*R(dF).log()/(R(dF)): + AZpairing += temp + AZpairing -= (-res.ord(p))*R(p).log()/(dF*dG) + temp = (ZZ(1)/2)*(-Gdisc.ord(p))*R(p).log()/(dG**2) + if abs(temp) > noise_multiplier*R(dG).log()/(R(dG)): + AZpairing += temp + temp = (ZZ(1)/2)*(R(Fdisc).abs().log())/(dF**2) + if abs(temp) > noise_multiplier*R(dF).log()/(R(dF)): + AZpairing += temp + temp = (ZZ(1)/2)*(R(Gdisc).abs().log())/(dG**2) + if abs(temp) > noise_multiplier*R(dG).log()/(R(dG)): + AZpairing += temp + AZpairing -= R(res).abs().log()/(dF*dG) + else: # number field case + K = self.base_ring() + d = K.absolute_degree() + for v in badprimes: + Nv = v.absolute_ramification_index()*v.residue_class_degree()/d + AZpairing += Nv*((ZZ(1)/2)*K(Fdisc).abs_non_arch(v, prec=prec).log()/(dF**2) - K(res).abs_non_arch(v, prec=prec).log()/(dF*dG) + (ZZ(1)/2)*K(Gdisc).abs_non_arch(v, prec=prec).log()/(dG**2)) + if Fdisc.is_rational(): + Fdisc = QQ(Fdisc) + temp = (ZZ(1)/2)*(R(Fdisc).abs().log())/(dF**2) + if abs(temp) > noise_multiplier*R(dF).log()/R(dF): + AZpairing += temp + else: + temp = (ZZ(1)/d)*(ZZ(1)/2)*(R(K(Fdisc).abs().norm()).log())/(dF**2) + if abs(temp) > noise_multiplier*R(dF).log()/R(dF): + AZpairing += temp + if Gdisc.is_rational(): + temp = (ZZ(1)/2)*(R(Gdisc).abs().log())/(dG**2) + if abs(temp) > noise_multiplier*R(dG).log()/R(dG): + AZpairing += temp + else: + temp = (ZZ(1)/d)*(ZZ(1)/2)*(R(K(Gdisc).norm()).abs().log())/(dG**2) + if abs(temp) > noise_multiplier*R(dG).log()/R(dG): + AZpairing += temp + if res.is_rational(): + AZpairing -= (R(res).abs().log())/(dF*dG) + else: + AZpairing -= (ZZ(1)/d)*(R(K(res).norm()).abs().log())/(dF*dG) + if oldprec is None: + R = RealField() + else: + R = RealField(oldprec) + return R(-AZpairing) + def degree_sequence(self, iterates=2): r""" Return sequence of degrees of normalized iterates starting with From 580a8dcc75f29af8c950509ad124839cc990700c Mon Sep 17 00:00:00 2001 From: Paul Fili Date: Mon, 25 Nov 2019 15:30:59 -0600 Subject: [PATCH 668/742] Updated AZ pairing and checked tests --- .../arithmetic_dynamics/projective_ds.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index ac936e019ce..15021adccb3 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1183,10 +1183,11 @@ def arakelov_zhang_pairing(self, g, n=5, f_starting_point=None, g_starting_point sage: f = DynamicalSystem_projective([x^2+4*y^2, y^2]) sage: g = DynamicalSystem_projective([x^2,y^2]) sage: pairingval = f.arakelov_zhang_pairing(g, n=6, noise_multiplier=0) - sage: print pairingval + sage: pairingval 0.650660018921632 sage: dynheight = f.canonical_height(P(0,1)); dynheight - sage: print pairingval - dynheight + 0.75017839144364417318023000563 + sage: pairingval - dynheight -0.0995183725220122 We compute the example of Prop. 18(d) from Petsche, Szpiro and Tucker:: @@ -1214,7 +1215,7 @@ def arakelov_zhang_pairing(self, g, n=5, f_starting_point=None, g_starting_point sage: f.arakelov_zhang_pairing(g, n=6) 1.93846423207664 sage: _ - a.global_height() - -0.00744591697867270 + -0.00744591697867292 """ PS = self.domain() @@ -1277,12 +1278,15 @@ def arakelov_zhang_pairing(self, g, n=5, f_starting_point=None, g_starting_point res = Fpoly.resultant(Gpoly) oldprec = prec - if prec < 512: + if prec is None: + R = RealField(512) + else: + if prec < 512: # Want temporarily higher precision here since resultants are usually very, very large. # This isn't to say the computation is so accurate, merely that we want to keep track # of potentially very large height integers/rationals. - prec = 512 - R = RealField(prec) + prec = 512 + R = RealField(prec) AZpairing = R(0) # The code below actually computes -( mu_f - mu_g, mu_f - mu_g ), so flip the sign at the end. if PS.base_ring() is QQ: From 7dd124b111007d7f982529a279b775ad1fb16d1a Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Mon, 5 Sep 2022 11:55:37 +0800 Subject: [PATCH 669/742] 21129: Format doc; TODO: Turn args to kwds properly --- .../arithmetic_dynamics/projective_ds.py | 104 ++++++++++-------- 1 file changed, 58 insertions(+), 46 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 15021adccb3..cc819f2f343 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1103,62 +1103,75 @@ def nth_iterate(self, P, n, **kwds): raise TypeError("must be a forward orbit") return self.orbit(P, [n,n+1], **kwds)[0] - def arakelov_zhang_pairing(self, g, n=5, f_starting_point=None, g_starting_point=None, check_primes_of_bad_reduction=False, prec=None, noise_multiplier=2): + def arakelov_zhang_pairing( + self, g, n=5, + f_starting_point=None, g_starting_point=None, + check_primes_of_bad_reduction=False, + prec=None, + noise_multiplier=2 + ): r""" - Returns an estimate of the Arakelov-Zhang pairing of the rational maps ``self`` and ``g`` on `\mathbb{P}^1` over - a number field. - - The Arakelov-Zhang pairing was introduced by Petsche, Szpiro, and Tucker in 2012, and is a measure of dynamical closeness - of two rational maps. They prove inter alia that if one takes a sequence of small points for one map (for example, - preperiodic points for ``self``) and measure their dynamical height with respect to the other map (say, ``g``), then + Return an estimate of the Arakelov-Zhang pairing of the rational + maps ``self`` and ``g`` on `\mathbb{P}^1` over a number field. + + The Arakelov-Zhang pairing was introduced by Petsche, Szpiro, and + Tucker in 2012, which measures the dynamical closeness of two rational + maps. They prove inter alia that if one takes a sequence of small points + for one map (for example, preperiodic points for ``self``) and measure + their dynamical height with respect to the other map (say, ``g``), then the values of the height will tend to the value of the Arakelov-Zhang pairing. - The Arakelov-Zhang pairing involves mutual energy integrals between dynamical measures, which are in the case of - polynomials the equilibrium measures of the associated Julia sets at each place. As a result these pairings are - very difficult to compute exactly via analytic methods. We use a discrete approximation to these energy integrals. + The Arakelov-Zhang pairing involves mutual energy integrals between dynamical + measures, which are in the case of polynomials, the equilibrium measures + of the associated Julia sets at each place. As a result, these pairings + are very difficult to compute exactly via analytic methods. We use a + discrete approximation to these energy integrals. ALGORITHM: - We select periodic points of order `n`, or ``n``-th preimages of a specified starting value given by - ``f_starting_point`` and ``g_starting_point``, and then, at the archimedean places and the places of bad - reduction of the two maps, we compute the discrete approximations to the energy integrals involved using these - points. + + We select periodic points of order `n`, or ``n``-th preimages of a + specified starting value given by ``f_starting_point`` and ``g_starting_point``. + At the archimedean places and the places of bad reduction of the two maps, + we compute the discrete approximations to the energy integrals involved + using these points. INPUT: - - ``g`` - a rational map of `\mathbb{P}^1` given as a ProjectiveMorphism. ``g`` and ``self`` should have the same field of definition. + - ``g`` - a rational map of `\mathbb{P}^1` given as a projective morphism. + ``g`` and ``self`` should have the same field of definition. kwds: - - ``n`` - positive integer - Order of periodic points to use or preimages to take if starting points are specified. - default: 5 - - - ``f_starting_point`` - value in the base number field or None. - If ``f_starting_point`` is None, we solve for points of period ``n`` for ``self``. Otherwise, we take - ``n``-th preimages of the point given by ``f_starting_point`` under ``f`` on the affine line. (optional) - default: None - - - ``g_starting_point`` - value in the base number field or None. - If ``g_starting_point`` is None, we solve for points of period ``n`` for ``g``. Otherwise, we take - ``n``-th preimages of the point given by ``g_starting_point`` under ``g`` on the affine line. (optional) - default: None - - - ``check_primes_of_bad_reduction`` - boolean - Passed to the ``primes_of_bad_reduction`` function for ``self`` and ``g``. (optional) - default: False - - - ``prec`` - default precision for RealField values which are returned. (optional) - default: RealField default - - - ``noise_multiplier`` - real value. - Discriminant terms involved in the computation at the archimedean places are often not needed, particularly - if the capacity of the Julia sets is 1, and introduce a lot of error. By a well-known result of Mahler - (see also M. Baker, ""A lower bound for averages of dynamical Green's functions") such error (for a set of - `N` points) is on the order of `\log(N)/N` after our normalization. We check if the value of the archimedean - discriminant terms is within ``2*noise_multiplier`` of `\log(N)/N`, and if so, we discard it. In practice this - greatly improves the accuracy of the estimate of the pairing. If desired, ``noise_multiplier`` can be set to 0, - and no terms will be ignored. - default: 2 + - ``n`` - (default: 5) a positive integer + Order of periodic points to use or preimages to take if starting points are specified. + + - ``f_starting_point`` - (optional, default: ``None``) value in the base number field or None. + If ``f_starting_point`` is None, we solve for points of period ``n`` for ``self``. + Otherwise, we take ``n``-th preimages of the point given by ``f_starting_point`` + under ``f`` on the affine line. + + - ``g_starting_point`` - (optional, default: ``None``) value in the base number field or None. + If ``g_starting_point`` is None, we solve for points of period ``n`` for ``g``. + Otherwise, we take ``n``-th preimages of the point given by ``g_starting_point`` + under ``g`` on the affine line. + + - ``check_primes_of_bad_reduction`` - (optional, default: ``False``) boolean. + Passed to the ``primes_of_bad_reduction`` function for ``self`` and ``g``. + + - ``prec`` - (optional, default: ``RealField`` default) + default precision for RealField values which are returned. + + - ``noise_multiplier`` - (default: 2) a real number. + Discriminant terms involved in the computation at the archimedean places + are often not needed, particularly if the capacity of the Julia sets is 1, + and introduce a lot of error. By a well-known result of Mahler (see + also M. Baker, ""A lower bound for averages of dynamical Green's + functions") such error (for a set of `N` points) is on the order of + `\log(N)/N` after our normalization. We check if the value of the + archimedean discriminant terms is within ``2*noise_multiplier`` of + `\log(N)/N`. If so, we discard it. In practice this greatly improves + the accuracy of the estimate of the pairing. If desired, + ``noise_multiplier`` can be set to 0, and no terms will be ignored. OUTPUT: @@ -1216,7 +1229,6 @@ def arakelov_zhang_pairing(self, g, n=5, f_starting_point=None, g_starting_point 1.93846423207664 sage: _ - a.global_height() -0.00744591697867292 - """ PS = self.domain() n = Integer(n) From 6bf37d521d2f615c164816b6173ca232a4d2b39e Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Wed, 7 Sep 2022 16:17:03 +0800 Subject: [PATCH 670/742] 21129: Change args to kwds --- .../arithmetic_dynamics/projective_ds.py | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index cc819f2f343..693a1016453 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1103,13 +1103,7 @@ def nth_iterate(self, P, n, **kwds): raise TypeError("must be a forward orbit") return self.orbit(P, [n,n+1], **kwds)[0] - def arakelov_zhang_pairing( - self, g, n=5, - f_starting_point=None, g_starting_point=None, - check_primes_of_bad_reduction=False, - prec=None, - noise_multiplier=2 - ): + def arakelov_zhang_pairing(self, g, **kwds): r""" Return an estimate of the Arakelov-Zhang pairing of the rational maps ``self`` and ``g`` on `\mathbb{P}^1` over a number field. @@ -1230,21 +1224,34 @@ def arakelov_zhang_pairing( sage: _ - a.global_height() -0.00744591697867292 """ + n = kwds.pop('n', 5) + f_starting_point = kwds.pop('f_starting_point', None) + g_starting_point = kwds.pop('g_starting_point', None) + check_primes_of_bad_reduction = kwds.pop('check_primes_of_bad_reduction', False) + prec = kwds.pop('prec', None) + noise_multiplier = kwds.pop('noise_multiplier', 2) + PS = self.domain() - n = Integer(n) - if PS != g.domain(): + R = PS.base_ring() + g_domain = g.domain() + + if PS != g_domain: raise TypeError("Implemented only for rational maps of the same projective line.") - if (n < 1): + + if n <= 0: raise ValueError("Period must be a positive integer.") - from sage.schemes.projective.projective_space import is_ProjectiveSpace - if not is_ProjectiveSpace(PS) or not is_ProjectiveSpace(g.domain()): + + if not (is_ProjectiveSpace(PS) and is_ProjectiveSpace(g_domain)): raise NotImplementedError("Not implemented for subschemes.") - if (PS.dimension_relative() > 1): + + if PS.dimension_relative() > 1: raise NotImplementedError("Only implemented for dimension 1.") + if not self.is_endomorphism(): raise TypeError("Self must be an endomorphism.") - if not PS.base_ring() in NumberFields() and not PS.base_ring() is QQbar: - raise NotImplementedError("Not implemented for base fields other than number fields.") + + if R not in NumberFields() and R is not QQbar: + raise NotImplementedError("Only implemented for number fields.") from sage.misc.misc import union badprimes = union(self.primes_of_bad_reduction(check=check_primes_of_bad_reduction), g.primes_of_bad_reduction(check=check_primes_of_bad_reduction)) @@ -1256,12 +1263,12 @@ def arakelov_zhang_pairing( else: Fpolyhom = fiterate.defining_polynomials()[0]-f_starting_point*fiterate.defining_polynomials()[1] if g_starting_point is None: - Gpolyhom = giterate.defining_polynomials()[0]*g.domain().gens()[1]-giterate.defining_polynomials()[1]*g.domain().gens()[0] + Gpolyhom = giterate.defining_polynomials()[0]*g_domain.gens()[1]-giterate.defining_polynomials()[1]*g_domain.gens()[0] else: Gpolyhom = giterate.defining_polynomials()[0]-g_starting_point*giterate.defining_polynomials()[1] Fpoly = Fpolyhom([(self.domain().gens()[0]),1]).univariate_polynomial().monic() - Gpoly = Gpolyhom([(g.domain().gens()[0]),1]).univariate_polynomial().monic() + Gpoly = Gpolyhom([(g_domain.gens()[0]),1]).univariate_polynomial().monic() # If Fpoly and Gpoly are not squarefree, make them squarefree. if not Fpoly.is_squarefree(): @@ -1301,7 +1308,7 @@ def arakelov_zhang_pairing( R = RealField(prec) AZpairing = R(0) # The code below actually computes -( mu_f - mu_g, mu_f - mu_g ), so flip the sign at the end. - if PS.base_ring() is QQ: + if R is QQ: for p in badprimes: temp = (ZZ(1)/2)*(-Fdisc.ord(p))*R(p).log()/(dF**2) if abs(temp) > noise_multiplier*R(dF).log()/(R(dF)): From bbe618032b7c31e74b111e9dd14390044cd29350 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Wed, 7 Sep 2022 16:56:16 +0800 Subject: [PATCH 671/742] 21129: Complete `)` in misc.py --- src/sage/misc/misc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index c2c440daffb..bae968c42f3 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -548,7 +548,7 @@ def union(x, y=None): True """ from sage.misc.superseded import deprecation - deprecation(32096, "sage.misc.misc.union is deprecated, use 'list(set(x).union(y)' or a more suitable replacement") + deprecation(32096, "sage.misc.misc.union is deprecated, use 'list(set(x).union(y))' or a more suitable replacement") if y is None: return list(set(x)) return list(set(x).union(y)) From 67e3590d4a0fd63177fde6aba21db64d1f16672c Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Wed, 7 Sep 2022 18:27:24 +0800 Subject: [PATCH 672/742] 21129: Better format and doc --- .vscode/settings.json | 3 +- .../arithmetic_dynamics/projective_ds.py | 195 ++++++++++-------- 2 files changed, 109 insertions(+), 89 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 10822524b25..c2193d76a35 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -33,5 +33,6 @@ "Conda", "sagemath", "Cython" - ] + ], + "editor.formatOnType": true } diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 693a1016453..70a88fad632 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1231,131 +1231,150 @@ def arakelov_zhang_pairing(self, g, **kwds): prec = kwds.pop('prec', None) noise_multiplier = kwds.pop('noise_multiplier', 2) - PS = self.domain() - R = PS.base_ring() + f_domain = self.domain() + K = f_domain.base_ring() g_domain = g.domain() - if PS != g_domain: + if f_domain != g_domain: raise TypeError("Implemented only for rational maps of the same projective line.") if n <= 0: raise ValueError("Period must be a positive integer.") - if not (is_ProjectiveSpace(PS) and is_ProjectiveSpace(g_domain)): + if not (is_ProjectiveSpace(f_domain) and is_ProjectiveSpace(g_domain)): raise NotImplementedError("Not implemented for subschemes.") - if PS.dimension_relative() > 1: + if f_domain.dimension_relative() > 1: raise NotImplementedError("Only implemented for dimension 1.") if not self.is_endomorphism(): raise TypeError("Self must be an endomorphism.") - if R not in NumberFields() and R is not QQbar: + if K not in NumberFields() and K is not QQbar: raise NotImplementedError("Only implemented for number fields.") - from sage.misc.misc import union - badprimes = union(self.primes_of_bad_reduction(check=check_primes_of_bad_reduction), g.primes_of_bad_reduction(check=check_primes_of_bad_reduction)) - - fiterate = self.nth_iterate_map(n) - giterate = g.nth_iterate_map(n) + f_iterate_map = self.nth_iterate_map(n) + f_iter_map_poly = f_iterate_map.defining_polynomials() if f_starting_point is None: - Fpolyhom = fiterate.defining_polynomials()[0]*self.domain().gens()[1]-fiterate.defining_polynomials()[1]*self.domain().gens()[0] + f_poly_hom = f_iter_map_poly[0] * f_domain.gens()[1] - f_iter_map_poly[1] * f_domain.gens()[0] else: - Fpolyhom = fiterate.defining_polynomials()[0]-f_starting_point*fiterate.defining_polynomials()[1] + f_poly_hom = f_iter_map_poly[0] - f_starting_point * f_iter_map_poly[1] + + g_iterate_map = g.nth_iterate_map(n) + g_iter_map_poly = g_iterate_map.defining_polynomials() if g_starting_point is None: - Gpolyhom = giterate.defining_polynomials()[0]*g_domain.gens()[1]-giterate.defining_polynomials()[1]*g_domain.gens()[0] + g_poly_hom = g_iter_map_poly[0] * g_domain.gens()[1] - g_iter_map_poly[1] * g_domain.gens()[0] else: - Gpolyhom = giterate.defining_polynomials()[0]-g_starting_point*giterate.defining_polynomials()[1] + g_poly_hom = g_iter_map_poly[0] - g_starting_point * g_iter_map_poly[1] - Fpoly = Fpolyhom([(self.domain().gens()[0]),1]).univariate_polynomial().monic() - Gpoly = Gpolyhom([(g_domain.gens()[0]),1]).univariate_polynomial().monic() + f_poly = f_poly_hom([(f_domain.gens()[0]), 1]).univariate_polynomial().monic() + g_poly = g_poly_hom([(g_domain.gens()[0]), 1]).univariate_polynomial().monic() - # If Fpoly and Gpoly are not squarefree, make them squarefree. - if not Fpoly.is_squarefree(): - Fpoly = Fpoly.quo_rem(gcd(Fpoly, Fpoly.derivative()))[0] - if not Gpoly.is_squarefree(): - Gpoly = Gpoly.quo_rem(gcd(Gpoly, Gpoly.derivative()))[0] + # If f_poly and g_poly are not square-free, make them square-free. + if not f_poly.is_squarefree(): + f_poly = f_poly.quo_rem(gcd(f_poly, f_poly.derivative()))[0] + if not g_poly.is_squarefree(): + g_poly = g_poly.quo_rem(gcd(g_poly, g_poly.derivative()))[0] - if Fpoly.degree() <= 2 or Gpoly.degree() <= 2: - # we are very unlucky and fpoint or gpoint is exceptional - raise ValueError("It appears that one of the starting points is exceptional. Please specify non-exceptional initial point.") + if f_poly.degree() <= 2 or g_poly.degree() <= 2: + # f_point or g_point is exceptional + raise ValueError("One of the starting points is exceptional. Please specify a non-exceptional initial point.") - if gcd(Fpoly,Gpoly).degree() > 0: - if Fpoly.degree() > Gpoly.degree(): - Fpoly = Fpoly.quo_rem(gcd(Fpoly,Gpoly))[0] + if gcd(f_poly, g_poly).degree() > 0: + if f_poly.degree() > g_poly.degree(): + f_poly = f_poly.quo_rem(gcd(f_poly, g_poly))[0] else: - Gpoly = Gpoly.quo_rem(gcd(Fpoly,Gpoly))[0] - if Fpoly.degree() <= 2 or Gpoly.degree() <= 2: - raise ValueError("It appears that after removing common factors, the n-th iterates of self and g had too many roots in common. Try another n or starting values.") - - Fdisc = Fpoly.discriminant() - Gdisc = Gpoly.discriminant() + g_poly = g_poly.quo_rem(gcd(f_poly, g_poly))[0] - dF = Fpoly.degree() - dG = Gpoly.degree() + if f_poly.degree() <= 2 or g_poly.degree() <= 2: + raise ValueError("After removing common factors, the n-th iterates of 'self' and 'g' have too many roots in common. Try another 'n' or starting values.") - res = Fpoly.resultant(Gpoly) - - oldprec = prec + # We want higher precision here temporarily, since resultants are + # usually very large. This is not to say that the computation is + # very accurate, merely that we want to keep track of potentially + # very large height integers/rationals. + old_prec = prec if prec is None: R = RealField(512) + else if prec < 512: + prec = 512 + R = RealField(prec) + + bad_primes = list(set(self.primes_of_bad_reduction(check=check_primes_of_bad_reduction)).union(g.primes_of_bad_reduction(check=check_primes_of_bad_reduction))) + + f_deg = f_poly.degree() + g_deg = g_poly.degree() + + f_disc = f_poly.discriminant() + g_disc = g_poly.discriminant() + + res = f_poly.resultant(g_poly) + + # The code below actually computes -( mu_f - mu_g, mu_f - mu_g ), + # so flip the sign at the end. + AZ_pairing = R(0) + if K is QQ: + for p in bad_primes: + temp = (ZZ(1)/2) * (-f_disc.ord(p)) * R(p).log() / (f_deg**2) + if abs(temp) > noise_multiplier * R(f_deg).log() / (R(f_deg)): + AZ_pairing += temp + AZ_pairing -= (-res.ord(p)) * R(p).log() / (f_deg * g_deg) + + temp = (ZZ(1)/2) * (-g_disc.ord(p)) * R(p).log() / (g_deg**2) + if abs(temp) > noise_multiplier * R(g_deg).log() / (R(g_deg)): + AZ_pairing += temp + + temp = (ZZ(1)/2) * (R(f_disc).abs().log()) / (f_deg**2) + if abs(temp) > noise_multiplier * R(f_deg).log() / (R(f_deg)): + AZ_pairing += temp + + temp = (ZZ(1)/2) * (R(g_disc).abs().log()) / (g_deg**2) + if abs(temp) > noise_multiplier*R(g_deg).log() / (R(g_deg)): + AZ_pairing += temp + + AZ_pairing -= R(res).abs().log() / (f_deg * g_deg) + + # For number fields else: - if prec < 512: - # Want temporarily higher precision here since resultants are usually very, very large. - # This isn't to say the computation is so accurate, merely that we want to keep track - # of potentially very large height integers/rationals. - prec = 512 - R = RealField(prec) - AZpairing = R(0) - # The code below actually computes -( mu_f - mu_g, mu_f - mu_g ), so flip the sign at the end. - if R is QQ: - for p in badprimes: - temp = (ZZ(1)/2)*(-Fdisc.ord(p))*R(p).log()/(dF**2) - if abs(temp) > noise_multiplier*R(dF).log()/(R(dF)): - AZpairing += temp - AZpairing -= (-res.ord(p))*R(p).log()/(dF*dG) - temp = (ZZ(1)/2)*(-Gdisc.ord(p))*R(p).log()/(dG**2) - if abs(temp) > noise_multiplier*R(dG).log()/(R(dG)): - AZpairing += temp - temp = (ZZ(1)/2)*(R(Fdisc).abs().log())/(dF**2) - if abs(temp) > noise_multiplier*R(dF).log()/(R(dF)): - AZpairing += temp - temp = (ZZ(1)/2)*(R(Gdisc).abs().log())/(dG**2) - if abs(temp) > noise_multiplier*R(dG).log()/(R(dG)): - AZpairing += temp - AZpairing -= R(res).abs().log()/(dF*dG) - else: # number field case - K = self.base_ring() d = K.absolute_degree() - for v in badprimes: - Nv = v.absolute_ramification_index()*v.residue_class_degree()/d - AZpairing += Nv*((ZZ(1)/2)*K(Fdisc).abs_non_arch(v, prec=prec).log()/(dF**2) - K(res).abs_non_arch(v, prec=prec).log()/(dF*dG) + (ZZ(1)/2)*K(Gdisc).abs_non_arch(v, prec=prec).log()/(dG**2)) - if Fdisc.is_rational(): - Fdisc = QQ(Fdisc) - temp = (ZZ(1)/2)*(R(Fdisc).abs().log())/(dF**2) - if abs(temp) > noise_multiplier*R(dF).log()/R(dF): - AZpairing += temp + + for v in bad_primes: + Nv = v.absolute_ramification_index() * v.residue_class_degree() / d + AZ_pairing += Nv * ((ZZ(1)/2) * K(f_disc).abs_non_arch(v, prec=prec).log() / (f_deg**2) + + (ZZ(1)/2) * K(g_disc).abs_non_arch(v, prec=prec).log() / (g_deg**2)) + - K(res).abs_non_arch(v, prec=prec).log() / (f_deg * g_deg) + + if f_disc.is_rational(): + f_disc = QQ(f_disc) + temp = (ZZ(1)/2) * (R(f_disc).abs().log()) / (f_deg**2) + if abs(temp) > noise_multiplier * R(f_deg).log() / R(f_deg): + AZ_pairing += temp else: - temp = (ZZ(1)/d)*(ZZ(1)/2)*(R(K(Fdisc).abs().norm()).log())/(dF**2) - if abs(temp) > noise_multiplier*R(dF).log()/R(dF): - AZpairing += temp - if Gdisc.is_rational(): - temp = (ZZ(1)/2)*(R(Gdisc).abs().log())/(dG**2) - if abs(temp) > noise_multiplier*R(dG).log()/R(dG): - AZpairing += temp + temp = (ZZ(1)/d) * (ZZ(1)/2) * (R(K(f_disc).abs().norm()).log()) / (f_deg**2) + if abs(temp) > noise_multiplier*R(f_deg).log() / R(f_deg): + AZ_pairing += temp + + if g_disc.is_rational(): + g_disc = QQ(g_disc) # TODO newly add, maybe delete + temp = (ZZ(1)/2) * (R(g_disc).abs().log()) / (g_deg**2) + if abs(temp) > noise_multiplier * R(g_deg).log() / R(g_deg): + AZ_pairing += temp else: - temp = (ZZ(1)/d)*(ZZ(1)/2)*(R(K(Gdisc).norm()).abs().log())/(dG**2) - if abs(temp) > noise_multiplier*R(dG).log()/R(dG): - AZpairing += temp + temp = (ZZ(1)/d) * (ZZ(1)/2) * (R(K(g_disc).norm()).abs().log()) / (g_deg**2) + if abs(temp) > noise_multiplier*R(g_deg).log() / R(g_deg): + AZ_pairing += temp + if res.is_rational(): - AZpairing -= (R(res).abs().log())/(dF*dG) + AZ_pairing -= (R(res).abs().log()) / (f_deg * g_deg) else: - AZpairing -= (ZZ(1)/d)*(R(K(res).norm()).abs().log())/(dF*dG) - if oldprec is None: + AZ_pairing -= (ZZ(1)/d) * (R(K(res).norm()).abs().log()) / (f_deg * g_deg) + + if old_prec is None: R = RealField() else: - R = RealField(oldprec) - return R(-AZpairing) + R = RealField(old_prec) + + return R(-AZ_pairing) def degree_sequence(self, iterates=2): r""" From be6f236b9681c3c2f689db3a8469acc3d5ba25da Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Wed, 7 Sep 2022 18:42:38 +0800 Subject: [PATCH 673/742] 21129: Indent --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 70a88fad632..135d1077473 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1296,7 +1296,7 @@ def arakelov_zhang_pairing(self, g, **kwds): old_prec = prec if prec is None: R = RealField(512) - else if prec < 512: + elif prec < 512: prec = 512 R = RealField(prec) @@ -1340,9 +1340,7 @@ def arakelov_zhang_pairing(self, g, **kwds): for v in bad_primes: Nv = v.absolute_ramification_index() * v.residue_class_degree() / d - AZ_pairing += Nv * ((ZZ(1)/2) * K(f_disc).abs_non_arch(v, prec=prec).log() / (f_deg**2) - + (ZZ(1)/2) * K(g_disc).abs_non_arch(v, prec=prec).log() / (g_deg**2)) - - K(res).abs_non_arch(v, prec=prec).log() / (f_deg * g_deg) + AZ_pairing += Nv * ((ZZ(1)/2) * K(f_disc).abs_non_arch(v, prec=prec).log() / (f_deg**2) + (ZZ(1)/2) * K(g_disc).abs_non_arch(v, prec=prec).log() / (g_deg**2))- K(res).abs_non_arch(v, prec=prec).log() / (f_deg * g_deg) if f_disc.is_rational(): f_disc = QQ(f_disc) From 0fdcfd2d25098b71f191bf9cba9c455a1bda81d7 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Wed, 7 Sep 2022 22:24:07 +0800 Subject: [PATCH 674/742] 21129: Rename `RealField` and `f.domain.base_ring` vars to avoid confusion --- .../arithmetic_dynamics/projective_ds.py | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 135d1077473..4ec04c63b39 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1232,7 +1232,7 @@ def arakelov_zhang_pairing(self, g, **kwds): noise_multiplier = kwds.pop('noise_multiplier', 2) f_domain = self.domain() - K = f_domain.base_ring() + R = f_domain.base_ring() g_domain = g.domain() if f_domain != g_domain: @@ -1250,7 +1250,7 @@ def arakelov_zhang_pairing(self, g, **kwds): if not self.is_endomorphism(): raise TypeError("Self must be an endomorphism.") - if K not in NumberFields() and K is not QQbar: + if R not in NumberFields() and R is not QQbar: raise NotImplementedError("Only implemented for number fields.") f_iterate_map = self.nth_iterate_map(n) @@ -1295,10 +1295,10 @@ def arakelov_zhang_pairing(self, g, **kwds): # very large height integers/rationals. old_prec = prec if prec is None: - R = RealField(512) + Real = RealField(512) elif prec < 512: prec = 512 - R = RealField(prec) + Real = RealField(prec) bad_primes = list(set(self.primes_of_bad_reduction(check=check_primes_of_bad_reduction)).union(g.primes_of_bad_reduction(check=check_primes_of_bad_reduction))) @@ -1312,30 +1312,31 @@ def arakelov_zhang_pairing(self, g, **kwds): # The code below actually computes -( mu_f - mu_g, mu_f - mu_g ), # so flip the sign at the end. - AZ_pairing = R(0) - if K is QQ: + AZ_pairing = Real(0) + if R is QQ: for p in bad_primes: - temp = (ZZ(1)/2) * (-f_disc.ord(p)) * R(p).log() / (f_deg**2) - if abs(temp) > noise_multiplier * R(f_deg).log() / (R(f_deg)): + temp = (ZZ(1)/2) * (-f_disc.ord(p)) * Real(p).log() / (f_deg**2) + if abs(temp) > noise_multiplier * Real(f_deg).log() / (Real(f_deg)): AZ_pairing += temp - AZ_pairing -= (-res.ord(p)) * R(p).log() / (f_deg * g_deg) + AZ_pairing -= (-res.ord(p)) * Real(p).log() / (f_deg * g_deg) - temp = (ZZ(1)/2) * (-g_disc.ord(p)) * R(p).log() / (g_deg**2) - if abs(temp) > noise_multiplier * R(g_deg).log() / (R(g_deg)): + temp = (ZZ(1)/2) * (-g_disc.ord(p)) * Real(p).log() / (g_deg**2) + if abs(temp) > noise_multiplier * Real(g_deg).log() / (Real(g_deg)): AZ_pairing += temp - temp = (ZZ(1)/2) * (R(f_disc).abs().log()) / (f_deg**2) - if abs(temp) > noise_multiplier * R(f_deg).log() / (R(f_deg)): + temp = (ZZ(1)/2) * (Real(f_disc).abs().log()) / (f_deg**2) + if abs(temp) > noise_multiplier * Real(f_deg).log() / (Real(f_deg)): AZ_pairing += temp - temp = (ZZ(1)/2) * (R(g_disc).abs().log()) / (g_deg**2) - if abs(temp) > noise_multiplier*R(g_deg).log() / (R(g_deg)): + temp = (ZZ(1)/2) * (Real(g_disc).abs().log()) / (g_deg**2) + if abs(temp) > noise_multiplier*Real(g_deg).log() / (Real(g_deg)): AZ_pairing += temp - AZ_pairing -= R(res).abs().log() / (f_deg * g_deg) + AZ_pairing -= Real(res).abs().log() / (f_deg * g_deg) # For number fields else: + K = self.base_ring() d = K.absolute_degree() for v in bad_primes: @@ -1344,35 +1345,35 @@ def arakelov_zhang_pairing(self, g, **kwds): if f_disc.is_rational(): f_disc = QQ(f_disc) - temp = (ZZ(1)/2) * (R(f_disc).abs().log()) / (f_deg**2) - if abs(temp) > noise_multiplier * R(f_deg).log() / R(f_deg): + temp = (ZZ(1)/2) * (Real(f_disc).abs().log()) / (f_deg**2) + if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp else: - temp = (ZZ(1)/d) * (ZZ(1)/2) * (R(K(f_disc).abs().norm()).log()) / (f_deg**2) - if abs(temp) > noise_multiplier*R(f_deg).log() / R(f_deg): + temp = (ZZ(1)/d) * (ZZ(1)/2) * (Real(K(f_disc).abs().norm()).log()) / (f_deg**2) + if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp if g_disc.is_rational(): g_disc = QQ(g_disc) # TODO newly add, maybe delete - temp = (ZZ(1)/2) * (R(g_disc).abs().log()) / (g_deg**2) - if abs(temp) > noise_multiplier * R(g_deg).log() / R(g_deg): + temp = (ZZ(1)/2) * (Real(g_disc).abs().log()) / (g_deg**2) + if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): AZ_pairing += temp else: - temp = (ZZ(1)/d) * (ZZ(1)/2) * (R(K(g_disc).norm()).abs().log()) / (g_deg**2) - if abs(temp) > noise_multiplier*R(g_deg).log() / R(g_deg): + temp = (ZZ(1)/d) * (ZZ(1)/2) * (Real(K(g_disc).norm()).abs().log()) / (g_deg**2) + if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): AZ_pairing += temp if res.is_rational(): - AZ_pairing -= (R(res).abs().log()) / (f_deg * g_deg) + AZ_pairing -= (Real(res).abs().log()) / (f_deg * g_deg) else: - AZ_pairing -= (ZZ(1)/d) * (R(K(res).norm()).abs().log()) / (f_deg * g_deg) + AZ_pairing -= (ZZ(1)/d) * (Real(K(res).norm()).abs().log()) / (f_deg * g_deg) if old_prec is None: - R = RealField() + Real = RealField() else: - R = RealField(old_prec) + Real = RealField(old_prec) - return R(-AZ_pairing) + return Real(-AZ_pairing) def degree_sequence(self, iterates=2): r""" From f1f7fb1985ca5aa64dafdb052b6ce6d19e520301 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Thu, 22 Sep 2022 14:02:11 +0800 Subject: [PATCH 675/742] 21129: Fix docs and a bug when `f_disc` is not rational --- .../arithmetic_dynamics/projective_ds.py | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 4ec04c63b39..90eb5a25c48 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1173,35 +1173,44 @@ def arakelov_zhang_pairing(self, g, **kwds): EXAMPLES:: - sage: P. = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2+4*y^2, y^2]) - sage: g = DynamicalSystem_projective([x^2,y^2]) + sage: K. = CyclotomicField(3) + sage: P. = ProjectiveSpace(K, 1) + sage: f = DynamicalSystem_projective([x^2 + (2*k + 2)*y^2, y^2]) + sage: g = DynamicalSystem_projective([x^2, y^2]) + sage: pairingval = f.arakelov_zhang_pairing(g, n=5); pairingval + 0.409598197761958 + + :: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([x^2 + 4*y^2, y^2]) + sage: g = DynamicalSystem_projective([x^2, y^2]) sage: pairingval = f.arakelov_zhang_pairing(g, n=6); pairingval 0.750178391443644 sage: # Compare to the exact value: - sage: dynheight = f.canonical_height(P(0,1)); dynheight + sage: dynheight = f.canonical_height(P(0, 1)); dynheight 0.75017839144364417318023000563 sage: dynheight - pairingval 0.000000000000000 Notice that if we set the noise_multiplier to 0, the accuracy is diminished:: - sage: P. = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2+4*y^2, y^2]) - sage: g = DynamicalSystem_projective([x^2,y^2]) + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([x^2 + 4*y^2, y^2]) + sage: g = DynamicalSystem_projective([x^2, y^2]) sage: pairingval = f.arakelov_zhang_pairing(g, n=6, noise_multiplier=0) sage: pairingval 0.650660018921632 - sage: dynheight = f.canonical_height(P(0,1)); dynheight + sage: dynheight = f.canonical_height(P(0, 1)); dynheight 0.75017839144364417318023000563 sage: pairingval - dynheight -0.0995183725220122 We compute the example of Prop. 18(d) from Petsche, Szpiro and Tucker:: - sage: P. = ProjectiveSpace(QQ,1) + sage: P. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([y^2 - (y - x)^2, y^2]) - sage: g = DynamicalSystem_projective([x^2,y^2]) + sage: g = DynamicalSystem_projective([x^2, y^2]) sage: f.arakelov_zhang_pairing(g) 0.326954667248466 sage: # Correct value should be = 0.323067... @@ -1215,14 +1224,14 @@ def arakelov_zhang_pairing(self, g, **kwds): sage: R. = PolynomialRing(ZZ) sage: K. = NumberField(z^3 - 11) sage: P. = ProjectiveSpace(K,1) - sage: a = 7/(b-1) + sage: a = 7/(b - 1) sage: f = DynamicalSystem_projective([a*y^2 - (a*y - x)^2, y^2]) - sage: g = DynamicalSystem_projective([x^2,y^2]) + sage: g = DynamicalSystem_projective([x^2, y^2]) sage: # If all archimedean absolute values of a have modulus > 2, then the pairing should be h(a). sage: f.arakelov_zhang_pairing(g, n=6) - 1.93846423207664 + 3.46979800225000 sage: _ - a.global_height() - -0.00744591697867292 + 1.52388785319469 """ n = kwds.pop('n', 5) f_starting_point = kwds.pop('f_starting_point', None) @@ -1349,12 +1358,12 @@ def arakelov_zhang_pairing(self, g, **kwds): if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp else: - temp = (ZZ(1)/d) * (ZZ(1)/2) * (Real(K(f_disc).abs().norm()).log()) / (f_deg**2) + temp = (ZZ(1)/d) * (ZZ(1)/2) * (Real(K(f_disc).norm()).abs().log()) / (f_deg**2) if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp if g_disc.is_rational(): - g_disc = QQ(g_disc) # TODO newly add, maybe delete + g_disc = QQ(g_disc) temp = (ZZ(1)/2) * (Real(g_disc).abs().log()) / (g_deg**2) if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): AZ_pairing += temp From ecf50141497051ed31083820cbd11c9710c8e2fd Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Thu, 22 Sep 2022 14:25:10 +0800 Subject: [PATCH 676/742] 21129: Wrap long lines --- .../arithmetic_dynamics/projective_ds.py | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 90eb5a25c48..bd5b8fbf96d 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1227,7 +1227,8 @@ def arakelov_zhang_pairing(self, g, **kwds): sage: a = 7/(b - 1) sage: f = DynamicalSystem_projective([a*y^2 - (a*y - x)^2, y^2]) sage: g = DynamicalSystem_projective([x^2, y^2]) - sage: # If all archimedean absolute values of a have modulus > 2, then the pairing should be h(a). + sage: # If all archimedean absolute values of a have modulus > 2, + sage: # then the pairing should be h(a). sage: f.arakelov_zhang_pairing(g, n=6) 3.46979800225000 sage: _ - a.global_height() @@ -1287,7 +1288,8 @@ def arakelov_zhang_pairing(self, g, **kwds): if f_poly.degree() <= 2 or g_poly.degree() <= 2: # f_point or g_point is exceptional - raise ValueError("One of the starting points is exceptional. Please specify a non-exceptional initial point.") + raise ValueError("One of the starting points is exceptional. \ + Please specify a non-exceptional initial point.") if gcd(f_poly, g_poly).degree() > 0: if f_poly.degree() > g_poly.degree(): @@ -1296,7 +1298,10 @@ def arakelov_zhang_pairing(self, g, **kwds): g_poly = g_poly.quo_rem(gcd(f_poly, g_poly))[0] if f_poly.degree() <= 2 or g_poly.degree() <= 2: - raise ValueError("After removing common factors, the n-th iterates of 'self' and 'g' have too many roots in common. Try another 'n' or starting values.") + raise ValueError("After removing common factors, the n-th \ + iterates of 'self' and 'g' have too many \ + roots in common. Try another 'n' or starting \ + values.") # We want higher precision here temporarily, since resultants are # usually very large. This is not to say that the computation is @@ -1308,8 +1313,9 @@ def arakelov_zhang_pairing(self, g, **kwds): elif prec < 512: prec = 512 Real = RealField(prec) - - bad_primes = list(set(self.primes_of_bad_reduction(check=check_primes_of_bad_reduction)).union(g.primes_of_bad_reduction(check=check_primes_of_bad_reduction))) + + bad_primes = list(set(self.primes_of_bad_reduction(check=check_primes_of_bad_reduction)) + .union(g.primes_of_bad_reduction(check=check_primes_of_bad_reduction))) f_deg = f_poly.degree() g_deg = g_poly.degree() @@ -1350,7 +1356,9 @@ def arakelov_zhang_pairing(self, g, **kwds): for v in bad_primes: Nv = v.absolute_ramification_index() * v.residue_class_degree() / d - AZ_pairing += Nv * ((ZZ(1)/2) * K(f_disc).abs_non_arch(v, prec=prec).log() / (f_deg**2) + (ZZ(1)/2) * K(g_disc).abs_non_arch(v, prec=prec).log() / (g_deg**2))- K(res).abs_non_arch(v, prec=prec).log() / (f_deg * g_deg) + AZ_pairing += Nv * ((ZZ(1)/2) * K(f_disc).abs_non_arch(v, prec=prec).log() / + (f_deg**2) + (ZZ(1)/2) * K(g_disc).abs_non_arch(v, prec=prec).log() / + (g_deg**2))- K(res).abs_non_arch(v, prec=prec).log() / (f_deg * g_deg) if f_disc.is_rational(): f_disc = QQ(f_disc) From ae5676b4fdf9db1482c01e902a1e32a33eedacc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 22 Sep 2022 08:31:44 +0200 Subject: [PATCH 677/742] adding a deprecation --- src/sage/topology/simplicial_complex_examples.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/topology/simplicial_complex_examples.py b/src/sage/topology/simplicial_complex_examples.py index 971b7d75d83..a21391beab3 100644 --- a/src/sage/topology/simplicial_complex_examples.py +++ b/src/sage/topology/simplicial_complex_examples.py @@ -63,6 +63,14 @@ {0: 0, 1: C4, 2: 0} sage: simplicial_complexes.MatchingComplex(6).homology() {0: 0, 1: Z^16, 2: 0} + +TESTS:: + + sage: from sage.topology.simplicial_complex_examples import PseudoQuaternionicProjectivePlane + sage: H = PseudoQuaternionicProjectivePlane() + doctest:warning...: + DeprecationWarning: PseudoQuaternionicProjectivePlane is deprecated. Please use sage.topology.simplicial_complex_examples.QuaternionicProjectivePlane instead. + See https://trac.sagemath.org/34568 for details. """ from .simplicial_complex import SimplicialComplex @@ -75,6 +83,7 @@ from sage.misc.functional import is_even from sage.combinat.subset import Subsets import sage.misc.prandom as random +from sage.misc.superseded import deprecated_function_alias # Miscellaneous utility functions. @@ -596,6 +605,10 @@ def QuaternionicProjectivePlane(): for tuple in start_list for g in PermutationGroup([P, S])]) + +PseudoQuaternionicProjectivePlane = deprecated_function_alias(34568, QuaternionicProjectivePlane) + + def PoincareHomologyThreeSphere(): """ A triangulation of the Poincaré homology 3-sphere. From b23792105a2fbb3d8e7d529774f91eaa3831ac84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 22 Sep 2022 09:33:13 +0200 Subject: [PATCH 678/742] Formatting issues / docstring conventions --- src/sage/rings/lazy_series.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 8aafe4fd4c6..6bfb8730c39 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -1995,9 +1995,8 @@ def __pow__(self, n): INPUT: - - ``n`` -- the power to which to raise the series. This may be an - integer, a rational number, an element of the base ring, or an other - series. + - ``n`` -- the power to which to raise the series; this may be a + rational number, an element of the base ring, or an other series EXAMPLES:: @@ -2015,7 +2014,7 @@ def __pow__(self, n): sage: L. = LazyLaurentSeriesRing(QQ) sage: f = 1 + z - sage: f ^ (1 / 2) + sage: f^(1 / 2) 1 + 1/2*z - 1/8*z^2 + 1/16*z^3 - 5/128*z^4 + 7/256*z^5 - 21/1024*z^6 + O(z^7) sage: f^f @@ -2025,7 +2024,11 @@ def __pow__(self, n): sage: L. = LazyLaurentSeriesRing(q.parent()) sage: f = (1 - z)^q sage: f - 1 - q*z + ((q^2 - q)/2)*z^2 + ((-q^3 + 3*q^2 - 2*q)/6)*z^3 + ((q^4 - 6*q^3 + 11*q^2 - 6*q)/24)*z^4 + ((-q^5 + 10*q^4 - 35*q^3 + 50*q^2 - 24*q)/120)*z^5 + ((q^6 - 15*q^5 + 85*q^4 - 225*q^3 + 274*q^2 - 120*q)/720)*z^6 + O(z^7) + 1 - q*z + ((q^2 - q)/2)*z^2 + ((-q^3 + 3*q^2 - 2*q)/6)*z^3 + + ((q^4 - 6*q^3 + 11*q^2 - 6*q)/24)*z^4 + + ((-q^5 + 10*q^4 - 35*q^3 + 50*q^2 - 24*q)/120)*z^5 + + ((q^6 - 15*q^5 + 85*q^4 - 225*q^3 + 274*q^2 - 120*q)/720)*z^6 + + O(z^7) """ if n in ZZ: return generic_power(self, n) @@ -2068,7 +2071,7 @@ def sqrt(self): sage: f*f - Z O(1/(8^s)) """ - return self ** QQ((1, 2)) # == 1/2 + return self ** QQ((1, 2)) # == 1/2 class LazyCauchyProductSeries(LazyModuleElement): From 4bdced9c9f14129d69bd409db0660987d17221da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 22 Sep 2022 10:01:49 +0200 Subject: [PATCH 679/742] small detail in MZV --- src/sage/modular/multiple_zeta_F_algebra.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index 2ca60775d0a..44a5d93a382 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -329,8 +329,8 @@ def product_on_basis(self, pw1, pw2): """ p1, w1 = pw1 p2, w2 = pw2 - return self.sum_of_monomials((p1 + p2, W_Odds(u, check=False)) - for u in w1.shuffle(w2)) + p = p1 + p2 + return self.sum_of_monomials((p, u) for u in w1.shuffle(w2)) def half_product_on_basis(self, pw1, pw2): r""" @@ -357,10 +357,11 @@ def half_product_on_basis(self, pw1, pw2): """ p1, w1 = pw1 p2, w2 = pw2 + p = p1 + p2 if not w1: - return self.basis()[(p1 + p2, w2)] - letter = W_Odds([w1[0]], check=False) - return self.sum_of_monomials((p1 + p2, letter + W_Odds(u, check=False)) + return self.basis()[(p, w2)] + letter = w1[:1] + return self.sum_of_monomials((p, letter + u) for u in w1[1:].shuffle(w2)) @lazy_attribute From 7661288224be017f92be37698032eb89fccb0622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 22 Sep 2022 14:45:20 +0200 Subject: [PATCH 680/742] a few more details in MZV --- src/sage/modular/multiple_zeta.py | 27 ++++++++++----------- src/sage/modular/multiple_zeta_F_algebra.py | 5 ++-- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 5fb94f92229..f4f93ada0d7 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -187,7 +187,7 @@ from sage.misc.cachefunc import cached_function, cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod -from sage.modular.multiple_zeta_F_algebra import F_algebra, W_Odds +from sage.modular.multiple_zeta_F_algebra import F_algebra from sage.modules.free_module import VectorSpace from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -436,7 +436,7 @@ def __repr__(self): sage: MultizetaValues() Cached multiple zeta values at precision 1024 up to weight 8 """ - return "Cached multiple zeta values at precision %d up to weight %d" % (self.prec, self.max_weight) + return f"Cached multiple zeta values at precision {self.prec} up to weight {self.max_weight}" def reset(self, max_weight=8, prec=1024): r""" @@ -1062,9 +1062,8 @@ def basis_filtration(self, d, reverse=False): v = self(c).phi_as_vector() if v in U: continue - else: - U = V.subspace(U.basis() + [v]) - basis.append(c) + U = V.subspace(U.basis() + [v]) + basis.append(c) k += 1 return [self(c) for c in basis] @@ -1113,7 +1112,7 @@ def single_valued(self): phi_im = self.phi() zin = phi_im.parent() phi_no_f2 = phi_im.without_f2() - sv = zin.sum_of_terms(((0, W_Odds(w, check=False)), cf) + sv = zin.sum_of_terms(((0, w), cf) for (a, b), cf in phi_no_f2.coproduct() for w in shuffle(a[1], b[1].reversal(), False)) return rho_inverse(sv) @@ -1242,7 +1241,7 @@ def _richcmp_(self, other, op): sage: (0*M()) == 0 True """ - if op != op_EQ and op != op_NE: + if op not in [op_EQ, op_NE]: raise TypeError('invalid comparison for multizetas') return self.iterated()._richcmp_(other.iterated(), op) @@ -1424,9 +1423,10 @@ def _repr_(self): sage: from sage.modular.multiple_zeta import Multizetas_iterated sage: M = Multizetas_iterated(QQ); M - Algebra of motivic multiple zeta values as convergent iterated integrals over Rational Field + Algebra of motivic multiple zeta values + as convergent iterated integrals over Rational Field """ - return "Algebra of motivic multiple zeta values as convergent iterated integrals over {}".format(self.base_ring()) + return f"Algebra of motivic multiple zeta values as convergent iterated integrals over {self.base_ring()}" def _repr_term(self, m): """ @@ -1555,12 +1555,11 @@ def split_word(indices): w = Word(seq[indices[i]:indices[i + 1] + 1]) if len(w) == 2: # this factor is one continue - elif len(w) <= 4 or len(w) == 6 or w[0] == w[-1]: + if len(w) <= 4 or len(w) == 6 or w[0] == w[-1]: # vanishing factors return self.zero() - else: - value = M_all(w) - L *= value.regularise().simplify() + value = M_all(w) + L *= value.regularise().simplify() return L resu = self.tensor_square().zero() @@ -2028,7 +2027,7 @@ def _richcmp_(self, other, op): sage: a.iterated() == b.iterated() # not tested, long time 20s True """ - if op != op_EQ and op != op_NE: + if op not in [op_EQ, op_NE]: raise TypeError('invalid comparison for multizetas') return (self - other).is_zero() == (op == op_EQ) diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index 44a5d93a382..baa50c7d787 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -247,7 +247,6 @@ def __init__(self, R): """ if R not in Rings(): raise TypeError("argument R must be a ring") - self.__ngens = Infinity Indices = NonNegativeIntegers().cartesian_product(W_Odds) cat = BialgebrasWithBasis(R).Commutative().Graded() CombinatorialFreeModule.__init__(self, R, Indices, @@ -295,7 +294,7 @@ def _repr_(self) -> str: sage: F # indirect doctest F-ring over Integer Ring """ - return "F-ring over %s" % (self.base_ring()) + return f"F-ring over {self.base_ring()}" @cached_method def one_basis(self): @@ -575,7 +574,7 @@ def _element_constructor_(self, x): if isinstance(P, F_algebra): if P is self: return x - if not (P is self.base_ring()): + if P is not self.base_ring(): return self.element_class(self, x.monomial_coefficients()) R = self.base_ring() From 63695d79d12e7822f0539968fcac1ecb87f398a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 22 Sep 2022 14:55:05 +0200 Subject: [PATCH 681/742] more fine-tuning details in MZV --- src/sage/modular/multiple_zeta.py | 1 - src/sage/modular/multiple_zeta_F_algebra.py | 18 +++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index f4f93ada0d7..f22fb5b0d7c 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -2614,7 +2614,6 @@ def rho_inverse(elt): sage: from sage.modular.multiple_zeta_F_algebra import F_algebra sage: A = F_algebra(QQ) sage: f = A.custom_gen - sage: W = A.basis().keys() sage: rho_inverse(f(3)) ζ(3) sage: rho_inverse(f(9)) diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index baa50c7d787..430b0df890d 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -312,11 +312,11 @@ def one_basis(self): def product_on_basis(self, pw1, pw2): r""" - Return the product of basis elements ``w1`` and ``w2``. + Return the product of basis elements ``pw1`` and ``pw2``. INPUT: - - ``w1``, ``w2`` -- basis elements + - ``pw1``, ``pw2`` -- basis elements EXAMPLES:: @@ -333,13 +333,13 @@ def product_on_basis(self, pw1, pw2): def half_product_on_basis(self, pw1, pw2): r""" - Return the half product of basis elements ``w1`` and ``w2``. + Return the half product of basis elements ``pw1`` and ``pw2``. This is an extension of the zinbiel product of the shuffle algebra. INPUT: - - ``w1``, ``w2`` -- Basis elements + - ``pw1``, ``pw2`` -- Basis elements EXAMPLES:: @@ -408,7 +408,7 @@ def custom_gen(self, i): INPUT: - - ``i`` -- a nonnegative integer + - ``i`` -- a nonnegative integer (at least 2) If ``i`` is odd, this returns a single generator `f_i` of the free shuffle algebra. @@ -463,7 +463,7 @@ def some_elements(self): def coproduct_on_basis(self, pw): r""" - Return the coproduct of the basis element indexed by the word ``w``. + Return the coproduct of the basis element indexed by the pair ``pw``. The coproduct is given by deconcatenation on the shuffle part, and extended by the value @@ -474,7 +474,7 @@ def coproduct_on_basis(self, pw): INPUT: - - ``w`` -- a word + - ``pw`` -- an index EXAMPLES:: @@ -695,10 +695,6 @@ def homogeneous_to_vector(self): This is using a fixed enumeration of the basis. - INPUT: - - an homogeneous element of :func:`F_ring` over some base ring - OUTPUT: a vector with coefficients in the base ring From 7c0495988c7962163abf3c11ad200add7feb05cc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 22 Sep 2022 09:42:01 -0700 Subject: [PATCH 682/742] src/sage/manifolds/differentiable/diff_form_module.py: Fix typo in docstring --- src/sage/manifolds/differentiable/diff_form_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index cf69dd22c28..37feeaa7650 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -580,7 +580,7 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): is not parallelizable, the class :class:`DiffFormModule` must be used instead. - For the special case of `-forms, use the class :class:`VectorFieldDualFreeModule`. + For the special case of 1-forms, use the class :class:`VectorFieldDualFreeModule`. INPUT: From 2de6d46f0363a6a3f8b45ad37fe150bc472abf86 Mon Sep 17 00:00:00 2001 From: Jan Groenewald Date: Thu, 22 Sep 2022 09:45:08 -0700 Subject: [PATCH 683/742] build/pkgs/_develop/distros/debian.txt: Remove nonexistent package openssh --- build/pkgs/_develop/distros/debian.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/build/pkgs/_develop/distros/debian.txt b/build/pkgs/_develop/distros/debian.txt index 4598e83f3f5..5c3c17488e8 100644 --- a/build/pkgs/_develop/distros/debian.txt +++ b/build/pkgs/_develop/distros/debian.txt @@ -1,4 +1,3 @@ # Needed for devcontainer support in VS code gpgconf openssh-client -openssh From 20399901b09f6f7fbc49bc6d9856a5e6a56694c2 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 23 Sep 2022 07:39:31 +0900 Subject: [PATCH 684/742] Updating doctest due to changes from #34494. --- src/sage/combinat/sf/sfa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 1fb9d204e34..e9af98027f2 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -3137,7 +3137,7 @@ def plethysm(self, x, include=None, exclude=None): sage: T = tensor([X,Y]) sage: s = SymmetricFunctions(T).s() sage: s(2*T.one()) - (2*B[word:]#B[word:])*s[] + (2*B[]#B[])*s[] .. TODO:: From 6cb40430327f5e7ac5addd78841119abdedcb916 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 23 Sep 2022 01:18:01 +0200 Subject: [PATCH 685/742] curly braces for typesetting --- src/sage/arith/power.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/arith/power.pyx b/src/sage/arith/power.pyx index 3c9219a5f11..2900d9f2a45 100644 --- a/src/sage/arith/power.pyx +++ b/src/sage/arith/power.pyx @@ -24,7 +24,7 @@ cpdef generic_power(a, n): """ Return `a^n`. - If `n` is negative, return `(1/a)^(-n)`. + If `n` is negative, return `(1/a)^{-n}`. INPUT: From 0dc211bda2ce63861f3494a99f157ffea468baaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Fri, 23 Sep 2022 13:57:52 +1200 Subject: [PATCH 686/742] Removin binary_function from ginac code --- src/sage/symbolic/ginac/ex.h | 8 ++++---- src/sage/symbolic/ginac/expair.h | 6 +++--- src/sage/symbolic/ginac/order.h | 6 ++---- src/sage/symbolic/ginac/ptr.h | 3 +-- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/sage/symbolic/ginac/ex.h b/src/sage/symbolic/ginac/ex.h index 7d220d2d25d..6a164af270f 100644 --- a/src/sage/symbolic/ginac/ex.h +++ b/src/sage/symbolic/ginac/ex.h @@ -677,19 +677,19 @@ std::ostream & operator<<(std::ostream & os, const exset & e); std::ostream & operator<<(std::ostream & os, const exmap & e); /* Function objects for STL sort() etc. */ -struct ex_is_less : public std::binary_function { +struct ex_is_less { bool operator() (const ex &lh, const ex &rh) const { return lh.compare(rh) < 0; } }; -struct ex_is_equal : public std::binary_function { +struct ex_is_equal { bool operator() (const ex &lh, const ex &rh) const { return lh.is_equal(rh); } }; -struct op0_is_equal : public std::binary_function { +struct op0_is_equal { bool operator() (const ex &lh, const ex &rh) const { return lh.op(0).is_equal(rh.op(0)); } }; -struct ex_swap : public std::binary_function { +struct ex_swap { void operator() (ex &lh, ex &rh) const { lh.swap(rh); } }; diff --git a/src/sage/symbolic/ginac/expair.h b/src/sage/symbolic/ginac/expair.h index 75177f6e49a..38b34e18404 100644 --- a/src/sage/symbolic/ginac/expair.h +++ b/src/sage/symbolic/ginac/expair.h @@ -91,7 +91,7 @@ class expair }; /** Function object for insertion into third argument of STL's sort() etc. */ -struct expair_is_less : public std::binary_function { +struct expair_is_less { bool operator()(const expair &lh, const expair &rh) const { return lh.is_less(rh); } }; @@ -99,11 +99,11 @@ struct expair_is_less : public std::binary_function { * into third argument of STL's sort(). Note that this does not define a * strict weak ordering since for any symbol x we have neither 3*x<2*x or * 2*x<3*x. Handle with care! */ -struct expair_rest_is_less : public std::binary_function { +struct expair_rest_is_less { bool operator()(const expair &lh, const expair &rh) const { return (lh.rest.compare(rh.rest)<0); } }; -struct expair_swap : public std::binary_function { +struct expair_swap { void operator()(expair &lh, expair &rh) const { lh.swap(rh); } }; diff --git a/src/sage/symbolic/ginac/order.h b/src/sage/symbolic/ginac/order.h index 63d5373ae90..7c65d6a7d69 100644 --- a/src/sage/symbolic/ginac/order.h +++ b/src/sage/symbolic/ginac/order.h @@ -35,7 +35,7 @@ namespace GiNaC { -class print_order : public std::binary_function { +class print_order { private: const tinfo_t& function_id() const; const tinfo_t& fderivative_id() const; @@ -96,9 +96,7 @@ class print_order_mul : public print_order { // We have to define the following class to sort held expressions // E.g. 3*x+2*x which does not get simplified to 5*x. -class print_order_pair : - public std::binary_function -{ +class print_order_pair { public: bool operator() (const expair &lh, const expair &rh) const; bool compare_degrees(const expair &lhex, const expair &rhex) const; diff --git a/src/sage/symbolic/ginac/ptr.h b/src/sage/symbolic/ginac/ptr.h index 7f3061cfe43..531e30ca869 100644 --- a/src/sage/symbolic/ginac/ptr.h +++ b/src/sage/symbolic/ginac/ptr.h @@ -158,8 +158,7 @@ namespace std { /** Specialization of std::less for ptr to enable ordering of ptr * objects (e.g. for the use as std::map keys). */ -template struct less< GiNaC::ptr > - : public binary_function, GiNaC::ptr, bool> { +template struct less< GiNaC::ptr > { bool operator()(const GiNaC::ptr &lhs, const GiNaC::ptr &rhs) const { return less()(lhs.p, rhs.p); From 1e2736ff4a0a5d2080d91c4b3f16d87d9acadd0e Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 23 Sep 2022 11:15:22 +0900 Subject: [PATCH 687/742] Minor edits --- src/sage/arith/misc.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index b9767de58f6..7194bdf6e35 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -1,6 +1,10 @@ # -*- coding: utf-8 -*- r""" Miscellaneous arithmetic functions + +AUTHORS: + +- Kevin Stueve (2010-01-17): in ``is_prime(n)``, delegated calculation to ``n.is_prime()`` """ # **************************************************************************** @@ -473,6 +477,10 @@ def is_prime(n): r""" Determine whether `n` is a prime element of its parent ring. + INPUT: + + - ``n`` - the object for which to determine primality + Exceptional special cases: - For integers, determine whether `n` is a *positive* prime. @@ -485,20 +493,11 @@ def is_prime(n): or a strong pseudo-primality test depending on the global :mod:`arithmetic proof flag `. - INPUT: - - - ``n`` - the object for which to determine primality - .. SEEALSO:: - :meth:`is_pseudoprime` - :meth:`sage.rings.integer.Integer.is_prime` - AUTHORS: - - - Kevin Stueve kstueve@uw.edu (2010-01-17): - delegated calculation to ``n.is_prime()`` - EXAMPLES:: sage: is_prime(389) @@ -530,16 +529,18 @@ def is_prime(n): sage: is_prime(7/1) doctest:warning ... - UserWarning: Testing primality in Rational Field, which is a field, hence the result will always be False. To test whether n is a prime integer, use is_prime(ZZ(n)) or ZZ(n).is_prime(). Using n.is_prime() instead will silence this warning. + UserWarning: Testing primality in Rational Field, which is a field, + hence the result will always be False. To test whether n is a prime + integer, use is_prime(ZZ(n)) or ZZ(n).is_prime(). Using n.is_prime() + instead will silence this warning. False sage: ZZ(7/1).is_prime() True sage: QQ(7/1).is_prime() False - However, number fields redefine ``.is_prime()`` in an - incompatible fashion (cf. :trac:`32340`) and we should - not warn:: + However, number fields redefine ``.is_prime()`` in an incompatible fashion + (cf. :trac:`32340`) and we should not warn:: sage: K. = NumberField(x^2+1) sage: is_prime(1+i) From dc25d4de7f23fe54485eccd6a362df9d871ab30b Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 23 Sep 2022 14:30:05 +0900 Subject: [PATCH 688/742] Fix invalid escape sequence warning --- src/sage/functions/special.py | 44 ++++++++++++++++------------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 02596e49620..eb085823e0e 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -1,20 +1,5 @@ r""" -Miscellaneous Special Functions - -AUTHORS: - -- David Joyner (2006-13-06): initial version - -- David Joyner (2006-30-10): bug fixes to pari wrappers of Bessel - functions, hypergeometric_U - -- William Stein (2008-02): Impose some sanity checks. - -- David Joyner (2008-04-23): addition of elliptic integrals - -- Eviatar Bach (2013): making elliptic integrals symbolic - -- Eric Gourgoulhon (2022): add Condon-Shortley phase to spherical harmonics +Miscellaneous special functions This module provides easy access to many of Maxima and PARI's special functions. @@ -104,6 +89,11 @@ and the complete ones are obtained by taking `\phi =\pi/2`. +.. WARNING:: + + SciPy's versions are poorly documented and seem less + accurate than the Maxima and PARI versions; typically they are limited + by hardware floats precision. REFERENCES: @@ -118,16 +108,22 @@ AUTHORS: -- David Joyner and William Stein +- David Joyner (2006-13-06): initial version -Added 16-02-2008 (wdj): optional calls to scipy and replace all -'#random' by '...' (both at the request of William Stein) +- David Joyner (2006-30-10): bug fixes to pari wrappers of Bessel + functions, hypergeometric_U -.. warning:: +- William Stein (2008-02): Impose some sanity checks. + +- David Joyner (2008-02-16): optional calls to scipy and replace all ``#random`` by ``...`` + (both at the request of William Stein) + +- David Joyner (2008-04-23): addition of elliptic integrals + +- Eviatar Bach (2013): making elliptic integrals symbolic + +- Eric Gourgoulhon (2022): add Condon-Shortley phase to spherical harmonics - SciPy's versions are poorly documented and seem less - accurate than the Maxima and PARI versions; typically they are limited - by hardware floats precision. """ # **************************************************************************** @@ -849,7 +845,7 @@ class EllipticF(BuiltinFunction): - :wikipedia:`Elliptic_integral#Incomplete_elliptic_integral_of_the_first_kind` """ def __init__(self): - """ + r""" EXAMPLES:: sage: loads(dumps(elliptic_f)) From 22c177847d061cb6c183660cc07cf900a38026e2 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Fri, 23 Sep 2022 13:31:54 +0800 Subject: [PATCH 689/742] 21129: Better indentation --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index bd5b8fbf96d..5117fef866b 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1344,7 +1344,7 @@ def arakelov_zhang_pairing(self, g, **kwds): AZ_pairing += temp temp = (ZZ(1)/2) * (Real(g_disc).abs().log()) / (g_deg**2) - if abs(temp) > noise_multiplier*Real(g_deg).log() / (Real(g_deg)): + if abs(temp) > noise_multiplier * Real(g_deg).log() / (Real(g_deg)): AZ_pairing += temp AZ_pairing -= Real(res).abs().log() / (f_deg * g_deg) @@ -1356,9 +1356,9 @@ def arakelov_zhang_pairing(self, g, **kwds): for v in bad_primes: Nv = v.absolute_ramification_index() * v.residue_class_degree() / d - AZ_pairing += Nv * ((ZZ(1)/2) * K(f_disc).abs_non_arch(v, prec=prec).log() / - (f_deg**2) + (ZZ(1)/2) * K(g_disc).abs_non_arch(v, prec=prec).log() / - (g_deg**2))- K(res).abs_non_arch(v, prec=prec).log() / (f_deg * g_deg) + AZ_pairing += Nv * ((ZZ(1)/2) * K(f_disc).abs_non_arch(v, prec=prec).log() / (f_deg**2) + + (ZZ(1)/2) * K(g_disc).abs_non_arch(v, prec=prec).log() / (g_deg**2)) + - K(res).abs_non_arch(v, prec=prec).log() / (f_deg * g_deg) if f_disc.is_rational(): f_disc = QQ(f_disc) From 6b0cb1fd1b4223574a4283679d52fbdc1aacf506 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 23 Sep 2022 14:40:25 +0900 Subject: [PATCH 690/742] Uniformize headline: functions --- src/sage/functions/airy.py | 2 +- src/sage/functions/bessel.py | 2 +- src/sage/functions/error.py | 2 +- src/sage/functions/exp_integral.py | 2 +- src/sage/functions/generalized.py | 2 +- src/sage/functions/hyperbolic.py | 2 +- src/sage/functions/hypergeometric.py | 2 +- src/sage/functions/jacobi.py | 2 +- src/sage/functions/log.py | 2 +- src/sage/functions/min_max.py | 2 +- src/sage/functions/orthogonal_polys.py | 2 +- src/sage/functions/piecewise.py | 2 +- src/sage/functions/prime_pi.pyx | 18 +++++++++--------- src/sage/functions/special.py | 8 +++----- src/sage/functions/spike_function.py | 2 +- src/sage/functions/transcendental.py | 2 +- src/sage/functions/trig.py | 2 +- 17 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/sage/functions/airy.py b/src/sage/functions/airy.py index cf32fb8f1c8..eceb9e6eafc 100644 --- a/src/sage/functions/airy.py +++ b/src/sage/functions/airy.py @@ -1,5 +1,5 @@ r""" -Airy Functions +Airy functions This module implements Airy functions and their generalized derivatives. It supports symbolic functionality through Maxima and numeric evaluation through diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index de1401dde68..d6c5c4ed4bc 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -1,5 +1,5 @@ r""" -Bessel Functions +Bessel functions This module provides symbolic Bessel and Hankel functions, and their spherical versions. These functions use the `mpmath library`_ for numerical diff --git a/src/sage/functions/error.py b/src/sage/functions/error.py index 06f0b244736..ca665622f20 100644 --- a/src/sage/functions/error.py +++ b/src/sage/functions/error.py @@ -1,5 +1,5 @@ r""" -Error Functions +Error functions This module provides symbolic error functions. These functions use the `mpmath library` for numerical evaluation and Maxima, Pynac for diff --git a/src/sage/functions/exp_integral.py b/src/sage/functions/exp_integral.py index 7ef74d9ed49..3f193cf5f1b 100644 --- a/src/sage/functions/exp_integral.py +++ b/src/sage/functions/exp_integral.py @@ -1,5 +1,5 @@ r""" -Exponential Integrals +Exponential integrals AUTHORS: diff --git a/src/sage/functions/generalized.py b/src/sage/functions/generalized.py index a24268c9b6b..d912ea23719 100644 --- a/src/sage/functions/generalized.py +++ b/src/sage/functions/generalized.py @@ -1,5 +1,5 @@ r""" -Generalized Functions +Generalized functions Sage implements several generalized functions (also known as distributions) such as Dirac delta, Heaviside step functions. These diff --git a/src/sage/functions/hyperbolic.py b/src/sage/functions/hyperbolic.py index 4487a3b3641..9a362b8882f 100644 --- a/src/sage/functions/hyperbolic.py +++ b/src/sage/functions/hyperbolic.py @@ -1,5 +1,5 @@ r""" -Hyperbolic Functions +Hyperbolic functions The full set of hyperbolic and inverse hyperbolic functions is available: diff --git a/src/sage/functions/hypergeometric.py b/src/sage/functions/hypergeometric.py index 795a1ab7228..50c60b25638 100644 --- a/src/sage/functions/hypergeometric.py +++ b/src/sage/functions/hypergeometric.py @@ -1,5 +1,5 @@ r""" -Hypergeometric Functions +Hypergeometric functions This module implements manipulation of infinite hypergeometric series represented in standard parametric form (as `\,_pF_q` functions). diff --git a/src/sage/functions/jacobi.py b/src/sage/functions/jacobi.py index af67d857f27..6fe3b2ade89 100644 --- a/src/sage/functions/jacobi.py +++ b/src/sage/functions/jacobi.py @@ -1,5 +1,5 @@ r""" -Jacobi Elliptic Functions +Jacobi elliptic functions This module implements the 12 Jacobi elliptic functions, along with their inverses and the Jacobi amplitude function. diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index d322305b223..f4015efb784 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -1,5 +1,5 @@ """ -Logarithmic Functions +Logarithmic functions AUTHORS: diff --git a/src/sage/functions/min_max.py b/src/sage/functions/min_max.py index 9b7d6d99f62..f783de0ba96 100644 --- a/src/sage/functions/min_max.py +++ b/src/sage/functions/min_max.py @@ -1,5 +1,5 @@ r""" -Symbolic Minimum and Maximum +Symbolic minimum and maximum Sage provides a symbolic maximum and minimum due to the fact that the Python builtin max and min are not able to deal with variables as users might expect. diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index a61f84649e9..5dd38d1c0be 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -1,5 +1,5 @@ r""" -Orthogonal Polynomials +Orthogonal polynomials Chebyshev polynomials --------------------- diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index 688db13a3b8..10d82e3709a 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- r""" -Piecewise-defined Functions +Piecewise functions This module implement piecewise functions in a single variable. See :mod:`sage.sets.real_set` for more information about how to construct diff --git a/src/sage/functions/prime_pi.pyx b/src/sage/functions/prime_pi.pyx index 0a576734777..38c68a2d4b4 100644 --- a/src/sage/functions/prime_pi.pyx +++ b/src/sage/functions/prime_pi.pyx @@ -1,5 +1,13 @@ r""" -Counting Primes +Counting primes + +EXAMPLES:: + + sage: z = sage.functions.prime_pi.PrimePi() + sage: loads(dumps(z)) + prime_pi + sage: loads(dumps(z)) == z + True AUTHORS: @@ -12,14 +20,6 @@ AUTHORS: - Dima Pasechnik (2021): removed buggy cython code, replaced it with calls to primecount/primecountpy spkg - -EXAMPLES:: - - sage: z = sage.functions.prime_pi.PrimePi() - sage: loads(dumps(z)) - prime_pi - sage: loads(dumps(z)) == z - True """ # **************************************************************************** diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index eb085823e0e..56f96f2ef53 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -91,9 +91,9 @@ .. WARNING:: - SciPy's versions are poorly documented and seem less - accurate than the Maxima and PARI versions; typically they are limited - by hardware floats precision. + SciPy's versions are poorly documented and seem less accurate than the + Maxima and PARI versions. Typically they are limited by hardware floats + precision. REFERENCES: @@ -116,14 +116,12 @@ - William Stein (2008-02): Impose some sanity checks. - David Joyner (2008-02-16): optional calls to scipy and replace all ``#random`` by ``...`` - (both at the request of William Stein) - David Joyner (2008-04-23): addition of elliptic integrals - Eviatar Bach (2013): making elliptic integrals symbolic - Eric Gourgoulhon (2022): add Condon-Shortley phase to spherical harmonics - """ # **************************************************************************** diff --git a/src/sage/functions/spike_function.py b/src/sage/functions/spike_function.py index 2118c1b2dcc..83fde81b0ca 100644 --- a/src/sage/functions/spike_function.py +++ b/src/sage/functions/spike_function.py @@ -1,5 +1,5 @@ r""" -Spike Functions +Spike functions AUTHORS: diff --git a/src/sage/functions/transcendental.py b/src/sage/functions/transcendental.py index a470e9ed67d..b76e3a1bbbe 100644 --- a/src/sage/functions/transcendental.py +++ b/src/sage/functions/transcendental.py @@ -1,5 +1,5 @@ """ -Number-Theoretic Functions +Number-theoretic functions """ # **************************************************************************** # Copyright (C) 2005 William Stein diff --git a/src/sage/functions/trig.py b/src/sage/functions/trig.py index fb97a5e8c58..16aeeae43ab 100644 --- a/src/sage/functions/trig.py +++ b/src/sage/functions/trig.py @@ -1,5 +1,5 @@ r""" -Trigonometric Functions +Trigonometric functions """ from sage.symbolic.function import GinacFunction import math From 818403963bc01bec9ee5a9f38383009c8fcf4942 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 23 Sep 2022 15:09:10 +0900 Subject: [PATCH 691/742] Remove the fix from #34465 --- src/sage/functions/special.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 56f96f2ef53..38273aafb36 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -843,7 +843,7 @@ class EllipticF(BuiltinFunction): - :wikipedia:`Elliptic_integral#Incomplete_elliptic_integral_of_the_first_kind` """ def __init__(self): - r""" + """ EXAMPLES:: sage: loads(dumps(elliptic_f)) From 6b80c50d028c46ef48bc2cc9bac53446aa170958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 23 Sep 2022 10:12:16 +0200 Subject: [PATCH 692/742] get rid of custom_gen, now gen --- src/sage/modular/multiple_zeta.py | 8 ++--- src/sage/modular/multiple_zeta_F_algebra.py | 39 +++++---------------- 2 files changed, 13 insertions(+), 34 deletions(-) diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index f22fb5b0d7c..36a968fadf7 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -1790,7 +1790,7 @@ def phi_extended(self, w): # this is now hardcoded # prec = 1024 F = F_algebra(self.base_ring()) - f = F.custom_gen + f = F.gen if not w: return F.one() N = len(w) @@ -2413,7 +2413,7 @@ def phi_on_multiplicative_basis(compo): sage: phi_on_multiplicative_basis((3,)) f3 """ - f = F_algebra(QQ).custom_gen + f = F_algebra(QQ).gen if tuple(compo) == (2,): return f(2) @@ -2560,7 +2560,7 @@ def compute_u_on_basis(w): for k in range(3, N, 2): xi_dict[k] = F.sum(cf * coeff_phi(ww[0]) * M.phi_extended(tuple(ww[1])) for ww, cf in M.D_on_basis(k, w)) - return F.sum(F.half_product(F.custom_gen(k), xi_dict[k]) + return F.sum(F.half_product(F.gen(k), xi_dict[k]) for k in range(3, N, 2)) @@ -2613,7 +2613,7 @@ def rho_inverse(elt): sage: from sage.modular.multiple_zeta import rho_inverse sage: from sage.modular.multiple_zeta_F_algebra import F_algebra sage: A = F_algebra(QQ) - sage: f = A.custom_gen + sage: f = A.gen sage: rho_inverse(f(3)) ζ(3) sage: rho_inverse(f(9)) diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index 430b0df890d..39e7dcad4e7 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -264,9 +264,9 @@ def _repr_term(self, pw) -> str: sage: from sage.modular.multiple_zeta_F_algebra import F_algebra sage: F = F_algebra(QQ) - sage: f2 = F.gen(0) - sage: f3 = F.gen(1) - sage: f5 = F.gen(2) + sage: f2 = F.gen(2) + sage: f3 = F.gen(3) + sage: f5 = F.gen(5) sage: f2*f3+f5+f2**2 f5 + f2*f3 + f2^2 """ @@ -382,27 +382,6 @@ def half_product(self): position=1) def gen(self, i): - r""" - Return the ``i``-th generator of the algebra. - - INPUT: - - - ``i`` -- an integer, index in the enumeration `f_2,f_3,f_5,f_7,\ldots` - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta_F_algebra import F_algebra - sage: F = F_algebra(ZZ) - sage: F.gen(0) - f2 - sage: F.gen(4) - f9 - """ - if i == 0: - return self.monomial(self._indices((1, []))) - return self.monomial(self._indices((0, [2 * i + 1]))) - - def custom_gen(self, i): r""" Return the generator of the F ring over `\QQ`. @@ -419,15 +398,15 @@ def custom_gen(self, i): sage: from sage.modular.multiple_zeta_F_algebra import F_algebra sage: A = F_algebra(QQ) - sage: [A.custom_gen(i) for i in range(2,8)] + sage: [A.gen(i) for i in range(2,8)] [f2, f3, 2/5*f2^2, f5, 8/35*f2^3, f7] """ - f2 = self("2") + f2 = self.monomial(self._indices((1, []))) if i == 2: return f2 # now i odd >= 3 if i % 2: - return self.gen((i - 1) // 2) + return self.monomial(self._indices((0, [i]))) # now powers of f2 i = i // 2 B = bernoulli(2 * i) * (-1)**(i - 1) @@ -458,8 +437,8 @@ def some_elements(self): sage: F.some_elements() [0, 1, f2, f3 + f5] """ - return [self.zero(), self.one(), self.gen(0), - self.gen(1) + self.gen(2)] + return [self.zero(), self.one(), self.gen(2), + self.gen(3) + self.gen(5)] def coproduct_on_basis(self, pw): r""" @@ -630,7 +609,7 @@ def _coerce_map_from_(self, R): `\ZZ` coerces to `\GF{7}`:: sage: G = F_algebra(ZZ) - sage: Gx,Gy = G.gen(0), G.gen(1) + sage: Gx,Gy = G.gen(2), G.gen(3) sage: z = F.coerce(Gx**2 * Gy);z f2^2*f3 sage: z.parent() is F From cac22914d83cc3d4e1b0a69de0c309af0fd552c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 23 Sep 2022 12:14:37 +0200 Subject: [PATCH 693/742] using IntegerRange in MZV itself --- src/sage/modular/multiple_zeta.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 36a968fadf7..2af659e3ff9 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -191,7 +191,8 @@ from sage.modules.free_module import VectorSpace from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.sets.integer_range import IntegerRange +from sage.rings.infinity import Infinity # multiplicative generators for weight <= 17 # using the following convention @@ -660,7 +661,8 @@ def __init__(self, R): cat = GradedAlgebrasWithBasis(R).Commutative() if R in Domains(): cat = cat & Domains() - CombinatorialFreeModule.__init__(self, R, Words(NN, infinite=False), + NN1 = IntegerRange(1, Infinity) + CombinatorialFreeModule.__init__(self, R, Words(NN1, infinite=False), prefix="Z", category=cat) From 8a8cdf3fd2ee95dae4c1523b34e561a6cce8639f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 23 Sep 2022 14:24:32 +0200 Subject: [PATCH 694/742] using PositiveIntegers --- src/sage/modular/multiple_zeta.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 2af659e3ff9..6fd43f34560 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -191,8 +191,7 @@ from sage.modules.free_module import VectorSpace from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.sets.integer_range import IntegerRange -from sage.rings.infinity import Infinity +from sage.sets.positive_integers import PositiveIntegers # multiplicative generators for weight <= 17 # using the following convention @@ -661,10 +660,8 @@ def __init__(self, R): cat = GradedAlgebrasWithBasis(R).Commutative() if R in Domains(): cat = cat & Domains() - NN1 = IntegerRange(1, Infinity) - CombinatorialFreeModule.__init__(self, R, Words(NN1, infinite=False), - prefix="Z", - category=cat) + W = Words(PositiveIntegers(), infinite=False) + CombinatorialFreeModule.__init__(self, R, W, prefix="Z", category=cat) def _repr_(self): r""" From 5b9b5a0c1a595aeaafb082a3bd72e93938e93ae1 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 23 Sep 2022 12:35:37 -0700 Subject: [PATCH 695/742] trac 34528: fix a few links --- src/doc/en/installation/source.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index 89dbfb10be4..879c15f4847 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -63,9 +63,9 @@ However, there are minimal prerequisites for building Sage that already must be installed on your system: - `Fundamental system packages required for installing from source - <../reference/spkg/_prereq>`_ + <../reference/spkg/_prereq.html>`_ -- `C/C++ compilers <../reference/spkg/gcc>`_ +- `C/C++ compilers <../reference/spkg/gcc.html>`_ If you have sufficient privileges (for example, on Linux you can use ``sudo`` to become the ``root`` user), then you can install these packages @@ -76,12 +76,12 @@ do this for you. In addition to these minimal prerequisites, we strongly recommend to use system installations of the following: -- `Fortran compiler <../reference/spkg/gfortran>`_ +- `Fortran compiler <../reference/spkg/gfortran.html>`_ -- `Python <../reference/spkg/python3>`_ +- `Python <../reference/spkg/python3.html>`_ Sage developers will also need the `system packages required for -bootstrapping <../reference/spkg/_bootstrap>`_; they cannot be +bootstrapping <../reference/spkg/_bootstrap.html>`_; they cannot be installed by Sage. When the ``./configure`` script runs, it will check for the presence of many From fdf90994b1da29de8cadbe70ec35cc989bebe91a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 11 Aug 2022 12:18:03 -0700 Subject: [PATCH 696/742] build/bin/sage-dist-helpers (sdh_pip_editable_install), build/pkgs/sagelib/spkg-install: Do not use PEP 660 editable wheels --- build/bin/sage-dist-helpers | 2 ++ build/pkgs/sagelib/spkg-install | 2 ++ 2 files changed, 4 insertions(+) diff --git a/build/bin/sage-dist-helpers b/build/bin/sage-dist-helpers index 339d06ce493..1fc904c3f5b 100644 --- a/build/bin/sage-dist-helpers +++ b/build/bin/sage-dist-helpers @@ -290,6 +290,8 @@ sdh_pip_install() { sdh_pip_editable_install() { echo "Installing $PKG_NAME (editable mode)" + # Until https://trac.sagemath.org/ticket/34209 switches us to PEP 660 editable wheels + export SETUPTOOLS_ENABLE_FEATURE=legacy-editable python3 -m pip install --verbose --no-deps --no-index --no-build-isolation --isolated --editable "$@" || \ sdh_die "Error installing $PKG_NAME" } diff --git a/build/pkgs/sagelib/spkg-install b/build/pkgs/sagelib/spkg-install index 8d91b16b3f0..8d28a2d03dd 100755 --- a/build/pkgs/sagelib/spkg-install +++ b/build/pkgs/sagelib/spkg-install @@ -52,6 +52,8 @@ if [ "$SAGE_EDITABLE" = yes ]; then # and renamed the distribution to "sagemath-standard"). There is no clean way to uninstall # them, so we just use rm. (cd "$SITEPACKAGESDIR" && rm -rf sage sage_setup sage-[1-9]*.egg-info sage-[1-9]*.dist-info) + # Until https://trac.sagemath.org/ticket/34209 switches us to PEP 660 editable wheels + export SETUPTOOLS_ENABLE_FEATURE=legacy-editable time python3 -m pip install --verbose --no-deps --no-index --no-build-isolation --isolated --editable . || exit 1 else # Make sure that an installed old version of sagelib in which sage is an ordinary package From 94f0f76aab946dbf6a4f932a0c3ae2fbf0c9c79f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 11 Aug 2022 12:13:06 -0700 Subject: [PATCH 697/742] build/pkgs/setuptools[_wheel]: Update to 63.4.3, 65.3.0 --- build/bin/sage-dist-helpers | 2 +- build/pkgs/sagelib/spkg-install | 2 +- build/pkgs/setuptools/SPKG.rst | 24 +++++++++---------- build/pkgs/setuptools/checksums.ini | 6 ++--- build/pkgs/setuptools/package-version.txt | 2 +- build/pkgs/setuptools_wheel/SPKG.rst | 3 +++ build/pkgs/setuptools_wheel/checksums.ini | 6 ++++- .../pkgs/setuptools_wheel/package-version.txt | 2 +- 8 files changed, 26 insertions(+), 21 deletions(-) mode change 120000 => 100644 build/pkgs/setuptools_wheel/checksums.ini mode change 120000 => 100644 build/pkgs/setuptools_wheel/package-version.txt diff --git a/build/bin/sage-dist-helpers b/build/bin/sage-dist-helpers index 1fc904c3f5b..24769ebfffc 100644 --- a/build/bin/sage-dist-helpers +++ b/build/bin/sage-dist-helpers @@ -291,7 +291,7 @@ sdh_pip_install() { sdh_pip_editable_install() { echo "Installing $PKG_NAME (editable mode)" # Until https://trac.sagemath.org/ticket/34209 switches us to PEP 660 editable wheels - export SETUPTOOLS_ENABLE_FEATURE=legacy-editable + export SETUPTOOLS_ENABLE_FEATURES=legacy-editable python3 -m pip install --verbose --no-deps --no-index --no-build-isolation --isolated --editable "$@" || \ sdh_die "Error installing $PKG_NAME" } diff --git a/build/pkgs/sagelib/spkg-install b/build/pkgs/sagelib/spkg-install index 8d28a2d03dd..91e4d8c1869 100755 --- a/build/pkgs/sagelib/spkg-install +++ b/build/pkgs/sagelib/spkg-install @@ -53,7 +53,7 @@ if [ "$SAGE_EDITABLE" = yes ]; then # them, so we just use rm. (cd "$SITEPACKAGESDIR" && rm -rf sage sage_setup sage-[1-9]*.egg-info sage-[1-9]*.dist-info) # Until https://trac.sagemath.org/ticket/34209 switches us to PEP 660 editable wheels - export SETUPTOOLS_ENABLE_FEATURE=legacy-editable + export SETUPTOOLS_ENABLE_FEATURES=legacy-editable time python3 -m pip install --verbose --no-deps --no-index --no-build-isolation --isolated --editable . || exit 1 else # Make sure that an installed old version of sagelib in which sage is an ordinary package diff --git a/build/pkgs/setuptools/SPKG.rst b/build/pkgs/setuptools/SPKG.rst index 8d510960f1d..a50e171a98d 100644 --- a/build/pkgs/setuptools/SPKG.rst +++ b/build/pkgs/setuptools/SPKG.rst @@ -4,26 +4,24 @@ setuptools: Build system for Python packages Description ----------- -setuptools is a collection of enhancements to the Python distutils (for -Python 2.6 and up) that allow you to more easily build and distribute -Python packages, especially ones that have dependencies on other -packages. +setuptools is the classical build system for Python packages, +a collection of enhancements to the Python distutils. -Website: http://pypi.python.org/pypi/setuptools/ +This package represents version 63.x of ``setuptools``. +Sage installs this version to provide the build system +for non-PEP 517 packages. In particular, Sage uses it +for building ``numpy``, whose build system ``numpy.distutils`` +is not compatible with newer versions of ``setuptools``, +see https://github.com/numpy/numpy/pull/22154 License ------- -PSF or ZPL. i.e Python Software Foundation License or Zope Public -License - +MIT License Upstream Contact ---------------- -- Phillip J. Eby (distutils-sig@python org) - -Dependencies ------------- +http://pypi.python.org/pypi/setuptools/ -- python +https://github.com/pypa/setuptools diff --git a/build/pkgs/setuptools/checksums.ini b/build/pkgs/setuptools/checksums.ini index 8a9faad33ca..d47099a8019 100644 --- a/build/pkgs/setuptools/checksums.ini +++ b/build/pkgs/setuptools/checksums.ini @@ -1,5 +1,5 @@ tarball=setuptools-VERSION.tar.gz -sha1=2a5a4ac384ace22dd10e3dac0a1b6af49e03c596 -md5=d72acb93671bde8e4ca0971866f9cdda -cksum=2262493785 +sha1=b14b8e2cf965fdb6870ebfccee50c751c056f757 +md5=02a0e4dc4fa13168904e8769a077aa26 +cksum=2734084418 upstream_url=https://pypi.io/packages/source/s/setuptools/setuptools-VERSION.tar.gz diff --git a/build/pkgs/setuptools/package-version.txt b/build/pkgs/setuptools/package-version.txt index 61f1f83a084..fe3c6688881 100644 --- a/build/pkgs/setuptools/package-version.txt +++ b/build/pkgs/setuptools/package-version.txt @@ -1 +1 @@ -63.2.0 +63.4.3 diff --git a/build/pkgs/setuptools_wheel/SPKG.rst b/build/pkgs/setuptools_wheel/SPKG.rst index c78602a296a..b77a6679f8f 100644 --- a/build/pkgs/setuptools_wheel/SPKG.rst +++ b/build/pkgs/setuptools_wheel/SPKG.rst @@ -3,3 +3,6 @@ setuptools_wheel: Build the setuptools package as a wheel After installing setuptools and wheel, we build a wheel of setuptools to complete the set of wheels stored in our wheelhouse. + +This version of setuptools is suitable for PEP 517/518/660 builds, +but it is not suitable for building ``numpy``. diff --git a/build/pkgs/setuptools_wheel/checksums.ini b/build/pkgs/setuptools_wheel/checksums.ini deleted file mode 120000 index 4f64d3ce107..00000000000 --- a/build/pkgs/setuptools_wheel/checksums.ini +++ /dev/null @@ -1 +0,0 @@ -../setuptools/checksums.ini \ No newline at end of file diff --git a/build/pkgs/setuptools_wheel/checksums.ini b/build/pkgs/setuptools_wheel/checksums.ini new file mode 100644 index 00000000000..3850ab96795 --- /dev/null +++ b/build/pkgs/setuptools_wheel/checksums.ini @@ -0,0 +1,5 @@ +tarball=setuptools-VERSION.tar.gz +sha1=984db5daf7ecf07640c75fbd86b48935cd333c86 +md5=66c6b8819c5306c12c38d7fad41b7f99 +cksum=2256175575 +upstream_url=https://pypi.io/packages/source/s/setuptools/setuptools-VERSION.tar.gz diff --git a/build/pkgs/setuptools_wheel/package-version.txt b/build/pkgs/setuptools_wheel/package-version.txt deleted file mode 120000 index 5268dbec8f6..00000000000 --- a/build/pkgs/setuptools_wheel/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -../setuptools/package-version.txt \ No newline at end of file diff --git a/build/pkgs/setuptools_wheel/package-version.txt b/build/pkgs/setuptools_wheel/package-version.txt new file mode 100644 index 00000000000..8390dbf7231 --- /dev/null +++ b/build/pkgs/setuptools_wheel/package-version.txt @@ -0,0 +1 @@ +65.3.0 From 34dee19a191153c64f62f4bc84a8a898a4539334 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 23 Sep 2022 18:00:58 -0700 Subject: [PATCH 698/742] Revert "build/pkgs/setuptools/install-requires.txt: Set upper bound" This reverts commit 8ff38941aac3c72947934a2e06e2e930f67c673d. --- build/pkgs/setuptools/install-requires.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build/pkgs/setuptools/install-requires.txt b/build/pkgs/setuptools/install-requires.txt index 486c3c348ee..0810ca37277 100644 --- a/build/pkgs/setuptools/install-requires.txt +++ b/build/pkgs/setuptools/install-requires.txt @@ -1,2 +1 @@ -# Set this bound until https://trac.sagemath.org/ticket/34209 adds support for PEP660 editable builds -setuptools >=49.6.0,<64.0.0 +setuptools >=49.6.0 From 87f23005f42f0990e954d955ef9c12cb75ae40be Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 23 Sep 2022 18:06:47 -0700 Subject: [PATCH 699/742] build/pkgs/hatchling: Update to 1.10.0 --- build/pkgs/hatchling/checksums.ini | 6 +++--- build/pkgs/hatchling/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/hatchling/checksums.ini b/build/pkgs/hatchling/checksums.ini index ec1317175da..598cd79a2c7 100644 --- a/build/pkgs/hatchling/checksums.ini +++ b/build/pkgs/hatchling/checksums.ini @@ -1,5 +1,5 @@ tarball=hatchling-VERSION.tar.gz -sha1=63ae7f29657e4d069c716e098a9ac8114d2f29f9 -md5=e05f845d94f400c3085bbaab21adcdbe -cksum=3213522818 +sha1=8f102796a225fb18b0571a44308341c7211d5d94 +md5=c50eff4f711cee451037ec7eb780154a +cksum=3180958969 upstream_url=https://pypi.io/packages/source/h/hatchling/hatchling-VERSION.tar.gz diff --git a/build/pkgs/hatchling/package-version.txt b/build/pkgs/hatchling/package-version.txt index 3a3cd8cc8b0..81c871de46b 100644 --- a/build/pkgs/hatchling/package-version.txt +++ b/build/pkgs/hatchling/package-version.txt @@ -1 +1 @@ -1.3.1 +1.10.0 From 045ee7d6cc6846b8c7ac5d7f87053a29ba9bec77 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 23 Sep 2022 18:09:33 -0700 Subject: [PATCH 700/742] build/pkgs/distlib: Update to 0.3.6 --- build/pkgs/distlib/checksums.ini | 6 +++--- build/pkgs/distlib/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/distlib/checksums.ini b/build/pkgs/distlib/checksums.ini index 9c739a93823..e83721c68b5 100644 --- a/build/pkgs/distlib/checksums.ini +++ b/build/pkgs/distlib/checksums.ini @@ -1,5 +1,5 @@ tarball=distlib-VERSION.zip -sha1=e7927ebc964676c17d466ed6a345222c34167a85 -md5=c886b7d99b4085c5d960e7435dcbd397 -cksum=10374426 +sha1=3a86d49dc17320325004564d0dc86afa808624bc +md5=f60ba4e3f8e76c214d3d00b2227a16f7 +cksum=1543870863 upstream_url=https://pypi.io/packages/source/d/distlib/distlib-VERSION.zip diff --git a/build/pkgs/distlib/package-version.txt b/build/pkgs/distlib/package-version.txt index 42045acae20..449d7e73a96 100644 --- a/build/pkgs/distlib/package-version.txt +++ b/build/pkgs/distlib/package-version.txt @@ -1 +1 @@ -0.3.4 +0.3.6 From 7529bc48bc424634597bd7d463995ec0ee491095 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 23 Sep 2022 18:10:08 -0700 Subject: [PATCH 701/742] build/pkgs/importlib_metadata: Update to 4.12.0 --- build/pkgs/importlib_metadata/checksums.ini | 6 +++--- build/pkgs/importlib_metadata/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/importlib_metadata/checksums.ini b/build/pkgs/importlib_metadata/checksums.ini index d5a9b1a2668..ea39c54a4a3 100644 --- a/build/pkgs/importlib_metadata/checksums.ini +++ b/build/pkgs/importlib_metadata/checksums.ini @@ -1,5 +1,5 @@ tarball=importlib_metadata-VERSION.tar.gz -sha1=7d15d8e06299a8f24e076600899aceee75ce8b0b -md5=a605ba6ec315bc1324fd6b7210fe7c12 -cksum=448954927 +sha1=ec68de1ec1800048de8656b9d211e22b7fe7c53e +md5=cfcf29185e13439c76d09c94bc8d81f4 +cksum=2134804316 upstream_url=https://pypi.io/packages/source/i/importlib_metadata/importlib_metadata-VERSION.tar.gz diff --git a/build/pkgs/importlib_metadata/package-version.txt b/build/pkgs/importlib_metadata/package-version.txt index 326ec6355f3..815588ef140 100644 --- a/build/pkgs/importlib_metadata/package-version.txt +++ b/build/pkgs/importlib_metadata/package-version.txt @@ -1 +1 @@ -4.8.2 +4.12.0 From 2fa5306f872182846a112ce9c5522268a58537ec Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 23 Sep 2022 18:10:14 -0700 Subject: [PATCH 702/742] build/pkgs/importlib_resources: Update to 5.9.0 --- build/pkgs/importlib_resources/checksums.ini | 6 +++--- build/pkgs/importlib_resources/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/importlib_resources/checksums.ini b/build/pkgs/importlib_resources/checksums.ini index f769a9f43b4..99a4cdf7908 100644 --- a/build/pkgs/importlib_resources/checksums.ini +++ b/build/pkgs/importlib_resources/checksums.ini @@ -1,5 +1,5 @@ tarball=importlib_resources-VERSION.tar.gz -sha1=d1f2742895a68f3f8d19dd7285df1687877fb15a -md5=5db738106ca7c05340495c36357986a2 -cksum=1338307365 +sha1=3b4b20fa0399e2fa21c7506be27a4b943495d3ad +md5=3b6d98270d40b2ba7af1f8d09188f0c2 +cksum=2401793228 upstream_url=https://pypi.io/packages/source/i/importlib_resources/importlib_resources-VERSION.tar.gz diff --git a/build/pkgs/importlib_resources/package-version.txt b/build/pkgs/importlib_resources/package-version.txt index ce7f2b425b5..b3d91f9cfc0 100644 --- a/build/pkgs/importlib_resources/package-version.txt +++ b/build/pkgs/importlib_resources/package-version.txt @@ -1 +1 @@ -5.2.2 +5.9.0 From ab0e195764735aa99ff60f113229bd8721c485a6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 23 Sep 2022 18:12:14 -0700 Subject: [PATCH 703/742] build/pkgs/tomlkit: Update to 0.11.4 --- build/pkgs/tomlkit/checksums.ini | 6 +++--- build/pkgs/tomlkit/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/tomlkit/checksums.ini b/build/pkgs/tomlkit/checksums.ini index f2116d86933..f43c80b7196 100644 --- a/build/pkgs/tomlkit/checksums.ini +++ b/build/pkgs/tomlkit/checksums.ini @@ -1,5 +1,5 @@ tarball=tomlkit-VERSION.tar.gz -sha1=c618d9b0490fb626c053c691def29223dcfbd6cc -md5=c4edce886bc20ef8ecea49984cce2e69 -cksum=2455377393 +sha1=65f56e209410e4eee4b45d048e6b4dc0fcaad74a +md5=d0edd43143c7840deb88185685cea8dd +cksum=846256591 upstream_url=https://pypi.io/packages/source/t/tomlkit/tomlkit-VERSION.tar.gz diff --git a/build/pkgs/tomlkit/package-version.txt b/build/pkgs/tomlkit/package-version.txt index d9df1bbc0c7..35ad34429be 100644 --- a/build/pkgs/tomlkit/package-version.txt +++ b/build/pkgs/tomlkit/package-version.txt @@ -1 +1 @@ -0.11.0 +0.11.4 From a3eb4caef4d91a3f3490985b3409089d99f2ffc3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Jul 2022 19:10:17 -0700 Subject: [PATCH 704/742] build/pkgs/terminado: Update; do not remove pyproject.toml --- build/pkgs/terminado/checksums.ini | 6 +++--- build/pkgs/terminado/dependencies | 2 +- build/pkgs/terminado/package-version.txt | 2 +- build/pkgs/terminado/spkg-install.in | 5 ----- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/build/pkgs/terminado/checksums.ini b/build/pkgs/terminado/checksums.ini index f33efd4b5da..794b2cda764 100644 --- a/build/pkgs/terminado/checksums.ini +++ b/build/pkgs/terminado/checksums.ini @@ -1,5 +1,5 @@ tarball=terminado-VERSION.tar.gz -sha1=65f40480c1d8077b78dcffb7e0c909eae86998bf -md5=4871263f6aaed18e09603fa6785b4340 -cksum=2070178009 +sha1=b0ff75a4f024dc07c9a819c1a63d75908624a5d3 +md5=e3fe92b48b3885ffa19b9890ed41578f +cksum=1261401246 upstream_url=https://pypi.io/packages/source/t/terminado/terminado-VERSION.tar.gz diff --git a/build/pkgs/terminado/dependencies b/build/pkgs/terminado/dependencies index e44a0d91033..3f42e57c3a2 100644 --- a/build/pkgs/terminado/dependencies +++ b/build/pkgs/terminado/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) ptyprocess tornado +$(PYTHON) ptyprocess tornado | $(PYTHON_TOOLCHAIN) flit_core ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/terminado/package-version.txt b/build/pkgs/terminado/package-version.txt index 34a83616bb5..a5510516948 100644 --- a/build/pkgs/terminado/package-version.txt +++ b/build/pkgs/terminado/package-version.txt @@ -1 +1 @@ -0.12.1 +0.15.0 diff --git a/build/pkgs/terminado/spkg-install.in b/build/pkgs/terminado/spkg-install.in index cb4ba894442..058b1344dc2 100644 --- a/build/pkgs/terminado/spkg-install.in +++ b/build/pkgs/terminado/spkg-install.in @@ -1,8 +1,3 @@ cd src -# Make sure that modern pip uses the generated setup.py -# that is distributed with the PyPI tarball, -# so we do not have to have flit. Trac #29803. -rm -f pyproject.toml - sdh_pip_install . From 0624430113aafba3059b283c3d675b4da4c510d9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Jul 2022 19:21:44 -0700 Subject: [PATCH 705/742] build/pkgs/terminado: Fix dependencies --- build/pkgs/terminado/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/terminado/dependencies b/build/pkgs/terminado/dependencies index 3f42e57c3a2..54ec1c7c229 100644 --- a/build/pkgs/terminado/dependencies +++ b/build/pkgs/terminado/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) ptyprocess tornado | $(PYTHON_TOOLCHAIN) flit_core +$(PYTHON) ptyprocess tornado | $(PYTHON_TOOLCHAIN) hatchling ---------- All lines of this file are ignored except the first. From 1079cd40ceef8e7469434ca906a2ad7a1679dad5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Jul 2022 19:23:16 -0700 Subject: [PATCH 706/742] build/pkgs/pkgconfig: Do not remove pyproject.toml, add poetry_core as a dependency --- build/pkgs/pkgconfig/dependencies | 2 +- build/pkgs/pkgconfig/spkg-install.in | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/build/pkgs/pkgconfig/dependencies b/build/pkgs/pkgconfig/dependencies index 79554fc438d..6dfe046e55e 100644 --- a/build/pkgs/pkgconfig/dependencies +++ b/build/pkgs/pkgconfig/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) pkgconf +$(PYTHON) | $(PYTHON_TOOLCHAIN) pkgconf poetry_core ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pkgconfig/spkg-install.in b/build/pkgs/pkgconfig/spkg-install.in index 761190e309c..d14edc90bcd 100644 --- a/build/pkgs/pkgconfig/spkg-install.in +++ b/build/pkgs/pkgconfig/spkg-install.in @@ -1,10 +1,5 @@ cd src -# Make sure that modern pip uses the generated setup.py -# that is distributed with the PyPI tarball, -# so we do not have to have poetry. Trac #29803. -rm -f pyproject.toml - sdh_pip_install . if [ $? -ne 0 ]; then From c7d9032af08a3972d7a6a227acf620e7024a0cc5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 23 Sep 2022 19:42:47 -0700 Subject: [PATCH 707/742] build/pkgs/pathspec: Update to 0.10.1 --- build/pkgs/pathspec/checksums.ini | 6 +++--- build/pkgs/pathspec/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/pathspec/checksums.ini b/build/pkgs/pathspec/checksums.ini index cb80c60c623..2db40ded285 100644 --- a/build/pkgs/pathspec/checksums.ini +++ b/build/pkgs/pathspec/checksums.ini @@ -1,5 +1,5 @@ tarball=pathspec-VERSION.tar.gz -sha1=afe51c21951f457f82a5810016d0b6752ffc487b -md5=9b6b70fa5ffc31e6f5700522880140c0 -cksum=3501694416 +sha1=ef0f4b07097506575ca8052256b56f137a7b170d +md5=6f4fde5e701d328a2846d206edb63aa9 +cksum=2376511942 upstream_url=https://pypi.io/packages/source/p/pathspec/pathspec-VERSION.tar.gz diff --git a/build/pkgs/pathspec/package-version.txt b/build/pkgs/pathspec/package-version.txt index ac39a106c48..571215736a6 100644 --- a/build/pkgs/pathspec/package-version.txt +++ b/build/pkgs/pathspec/package-version.txt @@ -1 +1 @@ -0.9.0 +0.10.1 From 0f1e6a445e967e843d6a60c3a37a7a10c1aeaf67 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Sat, 24 Sep 2022 11:24:36 +0800 Subject: [PATCH 708/742] 21129: Add noise_multiplier check for bad reductions --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 5117fef866b..4568cca18e3 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1331,20 +1331,20 @@ def arakelov_zhang_pairing(self, g, **kwds): if R is QQ: for p in bad_primes: temp = (ZZ(1)/2) * (-f_disc.ord(p)) * Real(p).log() / (f_deg**2) - if abs(temp) > noise_multiplier * Real(f_deg).log() / (Real(f_deg)): + if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp AZ_pairing -= (-res.ord(p)) * Real(p).log() / (f_deg * g_deg) temp = (ZZ(1)/2) * (-g_disc.ord(p)) * Real(p).log() / (g_deg**2) - if abs(temp) > noise_multiplier * Real(g_deg).log() / (Real(g_deg)): + if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): AZ_pairing += temp temp = (ZZ(1)/2) * (Real(f_disc).abs().log()) / (f_deg**2) - if abs(temp) > noise_multiplier * Real(f_deg).log() / (Real(f_deg)): + if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp temp = (ZZ(1)/2) * (Real(g_disc).abs().log()) / (g_deg**2) - if abs(temp) > noise_multiplier * Real(g_deg).log() / (Real(g_deg)): + if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): AZ_pairing += temp AZ_pairing -= Real(res).abs().log() / (f_deg * g_deg) @@ -1356,6 +1356,8 @@ def arakelov_zhang_pairing(self, g, **kwds): for v in bad_primes: Nv = v.absolute_ramification_index() * v.residue_class_degree() / d + if abs(Nv) > noise_multiplier * Real(f_deg).log() / Real(f_deg): + AZ_pairing += Nv AZ_pairing += Nv * ((ZZ(1)/2) * K(f_disc).abs_non_arch(v, prec=prec).log() / (f_deg**2) + (ZZ(1)/2) * K(g_disc).abs_non_arch(v, prec=prec).log() / (g_deg**2)) - K(res).abs_non_arch(v, prec=prec).log() / (f_deg * g_deg) From 82bfeaaaf6b772d0c893b12e7945707c745f0c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 24 Sep 2022 08:49:49 +0200 Subject: [PATCH 709/742] standard error messages in pbori/ --- src/sage/rings/polynomial/pbori/pbori.pyx | 155 ++++++++++------------ 1 file changed, 71 insertions(+), 84 deletions(-) diff --git a/src/sage/rings/polynomial/pbori/pbori.pyx b/src/sage/rings/polynomial/pbori/pbori.pyx index e369473c3c4..41850904621 100644 --- a/src/sage/rings/polynomial/pbori/pbori.pyx +++ b/src/sage/rings/polynomial/pbori/pbori.pyx @@ -328,8 +328,6 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): sage: S. = BooleanPolynomialRing(2, order='deglex') sage: P == S False - - """ def __init__(self, n=None, names=None, order='lex'): """ @@ -348,7 +346,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): cdef Py_ssize_t i, j, bstart, bsize if names is None: - raise TypeError("You must specify the names of the variables.") + raise TypeError("you must specify the names of the variables") if n is None: if isinstance(names, (tuple, list)): @@ -357,10 +355,10 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): try: n = int(n) except TypeError as msg: - raise TypeError("Number of variables must be an integer") + raise TypeError("number of variables must be an integer") if n < 1: - raise ValueError("Number of variables must be greater than 1.") + raise ValueError("number of variables must be greater than 1") self.pbind = sig_malloc(n*sizeof(Py_ssize_t)) @@ -369,13 +367,13 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): try: pb_order_code = order_mapping[order[0].name()] except KeyError: - raise ValueError("Only order keys " + + raise ValueError("only order keys " + ', '.join(order_mapping.keys()) + - " are supported.") + " are supported") if order.is_block_order(): if pb_order_code is pblp: - raise ValueError("Only deglex and degneglex are supported for block orders.") + raise ValueError("only deglex and degneglex are supported for block orders") elif pb_order_code is pbdlex: pb_order_code = pbblock_dlex elif pb_order_code is pbdp_asc: @@ -384,8 +382,8 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): pb_order_code = pbblock_dp for i in range(1, len(order.blocks())): if order[0].name() != order[i].name(): - raise ValueError("Each block must have the same order type " - "(deglex and degneglex) for block orders.") + raise ValueError("each block must have the same order type " + "(deglex and degneglex) for block orders") if pb_order_code is pbdp: for i in range(n): @@ -506,8 +504,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): INPUT: - - ``i`` - an integer or a boolean monomial in one - variable + - ``i`` -- an integer or a boolean monomial in one variable EXAMPLES:: @@ -530,10 +527,10 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): if len(i) == 1: i = i.index() else: - raise TypeError("Boolean monomials must be in one variable only.") + raise TypeError("boolean monomials must be in one variable only") cdef idx = int(i) if idx < 0 or idx >= self._pbring.nVariables(): - raise ValueError("Generator not defined.") + raise ValueError("generator not defined") return new_BP_from_PBVar(self, self._pbring.variable(self.pbind[idx])) def gens(self): @@ -551,7 +548,6 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): sage: P = BooleanPolynomialRing(10,'x') sage: P.gens() (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) - """ return tuple(new_BP_from_PBVar(self, self._pbring.variable(self.pbind[i])) @@ -559,14 +555,12 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): def change_ring(self, base_ring=None, names=None, order=None): """ - Return a new multivariate polynomial ring with base ring - ``base_ring``, variable names set to ``names``, and term - ordering given by ``order``. + Return a new multivariate polynomial ring with base ring ``base_ring``, + variable names set to ``names``, and term ordering given by ``order``. When ``base_ring`` is not specified, this function returns a ``BooleanPolynomialRing`` isomorphic to ``self``. Otherwise, - this returns a ``MPolynomialRing``. Each argument above is - optional. + this returns a ``MPolynomialRing``. Each argument above is optional. INPUT: @@ -590,7 +584,6 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): sage: T.term_order() Lexicographic term order """ - if names is None: names = self.variable_names() if order is None: @@ -1082,10 +1075,9 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): sage: R.remove_var(x,y,z) Traceback (most recent call last): ... - ValueError: impossible to use the original term order (most likely because it was a block order). Please specify the term order for the subring + ValueError: impossible to use the original term order (most likely because it was a block order); please specify the term order for the subring sage: R.remove_var(x,y,z, order='deglex') Boolean PolynomialRing in u, v - """ vars = list(self.variable_names()) for v in var: @@ -1096,7 +1088,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): try: return BooleanPolynomialRing(names=vars, order=self.term_order()) except ValueError: - raise ValueError("impossible to use the original term order (most likely because it was a block order). Please specify the term order for the subring") + raise ValueError("impossible to use the original term order (most likely because it was a block order); please specify the term order for the subring") else: return BooleanPolynomialRing(names=vars, order=order) @@ -1205,7 +1197,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): sage: P.random_element(degree=4) Traceback (most recent call last): ... - ValueError: Given degree should be less than or equal to number of variables (3) + ValueError: given degree should be less than or equal to number of variables (3) sage: f = P.random_element(degree=1, terms=5) sage: f.degree() <= 1 @@ -1251,7 +1243,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): degree = Integer(degree) if degree > nvars: - raise ValueError("Given degree should be less than or equal to number of variables (%s)" % nvars) + raise ValueError("given degree should be less than or equal to number of variables (%s)" % nvars) tot_terms = 0 monom_counts = [] @@ -1638,10 +1630,10 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): if len(i) == 1: i = i.index() else: - raise TypeError("Boolean monomials must be in one variable only.") + raise TypeError("boolean monomials must be in one variable only") i = int(i) if i < 0 or i >= self._pbring.nVariables(): - raise ValueError("Generator not defined.") + raise ValueError("generator not defined") return new_BM_from_PBVar(self._monom_monoid, self, self._pbring.variable(self.pbind[i])) @@ -1998,7 +1990,7 @@ class BooleanMonomialMonoid(UniqueRepresentation, Monoid_class): x50 """ if i < 0 or i >= self.ngens(): - raise ValueError("Generator not defined.") + raise ValueError("generator not defined") cdef PBVar newvar newvar = PBBooleVariable(i, (self._ring)._pbring) @@ -2382,11 +2374,11 @@ cdef class BooleanMonomial(MonoidElement): """ P = self.parent() if args and kwds: - raise ValueError("Using keywords and regular arguments not supported.") + raise ValueError("using keywords and regular arguments not supported") if args: - d = {} if len(args) > self._parent.ngens(): - raise ValueError("Number of arguments is greater than the number of variables of parent ring.") + raise ValueError("number of arguments is greater than the number of variables of parent ring") + d = {} for i in range(len(args)): d[i] = args[i] elif kwds: @@ -2522,7 +2514,7 @@ cdef class BooleanMonomial(MonoidElement): return self._pbmonom.deg() if x not in self._parent.gens(): - raise ValueError("x must be one of the generators of the parent.") + raise ValueError("x must be one of the generators of the parent") if self.reducible_by(x.lm()): return 1 @@ -3004,7 +2996,7 @@ cdef class BooleanPolynomial(MPolynomial): sage: a._repr_with_changed_varnames([1,'y','z']) Traceback (most recent call last): ... - TypeError: varnames has entries with wrong type. + TypeError: varnames has entries with wrong type :: @@ -3016,7 +3008,7 @@ cdef class BooleanPolynomial(MPolynomial): cdef int N = P._pbring.nVariables() if len(varnames) != N: - raise TypeError("len(varnames) doesn't equal self.parent().ngens()") + raise TypeError("len(varnames) is not equal to self.parent().ngens()") orig_varnames = P.variable_names() try: @@ -3025,7 +3017,7 @@ cdef class BooleanPolynomial(MPolynomial): except TypeError: for i in range(N): P._pbring.setVariableName(i, str_to_bytes(orig_varnames[i])) - raise TypeError("varnames has entries with wrong type.") + raise TypeError("varnames has entries with wrong type") s = ccrepr(self._pbpoly) for i in range(N): P._pbring.setVariableName(i, str_to_bytes(orig_varnames[i])) @@ -3256,7 +3248,7 @@ cdef class BooleanPolynomial(MPolynomial): sage: p^-1 Traceback (most recent call last): ... - NotImplementedError: Negative exponents for non constant boolean polynomials not implemented. + NotImplementedError: negative exponents for non constant boolean polynomials not implemented :: @@ -3278,7 +3270,7 @@ cdef class BooleanPolynomial(MPolynomial): elif self._pbpoly.isZero(): raise ZeroDivisionError else: - raise NotImplementedError("Negative exponents for non constant boolean polynomials not implemented.") + raise NotImplementedError("negative exponents for non constant boolean polynomials not implemented") def __neg__(BooleanPolynomial self): r""" @@ -3953,11 +3945,11 @@ cdef class BooleanPolynomial(MPolynomial): P = self._parent cdef int N = P.ngens() if args and kwds: - raise ValueError("Using keywords and regular arguments not supported.") + raise ValueError("using keywords and regular arguments not supported") if args: d = {} if len(args) != N: - raise ValueError("Number of arguments is different from the number of variables of parent ring.") + raise ValueError("number of arguments is different from the number of variables of parent ring") for i in range(N): arg = args[i] try: @@ -4565,7 +4557,7 @@ cdef class BooleanPolynomial(MPolynomial): L.append(tuple(l)) return tuple(L) else: - raise TypeError("Type '%s' of s not supported." % type(s)) + raise TypeError("type '%s' of s not supported" % type(s)) def spoly(self, BooleanPolynomial rhs): r""" @@ -4665,7 +4657,7 @@ cdef class BooleanPolynomial(MPolynomial): sage: a.reduce([None,None]) Traceback (most recent call last): ... - TypeError: argument must be a BooleanPolynomial. + TypeError: argument must be a BooleanPolynomial """ from sage.rings.polynomial.pbori.pbori import red_tail if not I: @@ -4674,7 +4666,7 @@ cdef class BooleanPolynomial(MPolynomial): I = I.gens() first = I[0] if first is None: - raise TypeError("argument must be a BooleanPolynomial.") + raise TypeError("argument must be a BooleanPolynomial") g = ReductionStrategy(first.ring()) g.opt_red_tail = True for p in I: @@ -4729,7 +4721,7 @@ cdef class PolynomialConstruct: # So, it is just a conversion. [Simon King] return (ring)._element_constructor_(x) - raise TypeError("Cannot generate Boolean polynomial from %s , %s" % + raise TypeError("cannot generate Boolean polynomial from %s , %s" % (type(x), type(ring))) @@ -4768,7 +4760,7 @@ cdef class MonomialConstruct: return result.lm() return result except Exception: - raise TypeError("Cannot convert to Boolean Monomial %s" % + raise TypeError("cannot convert to Boolean Monomial %s" % type(x)) cdef class VariableConstruct: @@ -4790,11 +4782,10 @@ cdef class VariableConstruct: """ if isinstance(arg, BooleanPolynomialRing): return arg.variable(0) - elif isinstance(ring, BooleanPolynomialRing): + if isinstance(ring, BooleanPolynomialRing): return (ring).variable(arg) - else: - raise TypeError("todo polynomial factory %s%s" % - (str(type(arg)), str(type(ring)))) + raise TypeError("todo polynomial factory %s%s" % + (str(type(arg)), str(type(ring)))) cdef class BooleanPolynomialIterator: @@ -4932,7 +4923,7 @@ class BooleanPolynomialIdeal(MPolynomialIdeal): - ``lazy`` - (default: ``True``) - ``invert`` - setting ``invert=True`` input and output get a - transformation ``x+1`` for each variable ``x``, which shouldn't + transformation ``x+1`` for each variable ``x``, which should not effect the calculated GB, but the algorithm. - ``other_ordering_first`` - possible values are ``False`` or @@ -5526,7 +5517,7 @@ cdef class BooleSet: elif isinstance(rhs, BooleanPolynomial): s = (rhs)._pbpoly.set() else: - raise TypeError("Argument 'rhs' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(rhs)) + raise TypeError("argument 'rhs' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(rhs)) return new_BS_from_PBSet(self._pbset.diff(s), self._ring) def union(self, rhs): @@ -5560,7 +5551,7 @@ cdef class BooleSet: elif isinstance(rhs, BooleanPolynomial): s = (rhs)._pbpoly.set() else: - raise TypeError("Argument 'rhs' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(rhs)) + raise TypeError("argument 'rhs' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(rhs)) return new_BS_from_PBSet(self._pbset.unite(s), self._ring) def change(self, ind): @@ -6175,7 +6166,7 @@ cdef class BooleanPolynomialVector: elif isinstance(el, BooleanMonomial): p = PBBoolePolynomial((el)._pbmonom) else: - raise TypeError("Argument 'el' has incorrect type (expected BooleanPolynomial or BooleanMonomial, got %s)" % type(el)) + raise TypeError("argument 'el' has incorrect type (expected BooleanPolynomial or BooleanMonomial, got %s)" % type(el)) self._vec.push_back(p) cdef inline BooleanPolynomialVector new_BPV_from_PBPolyVector( @@ -6255,12 +6246,12 @@ cdef class ReductionStrategy: sage: red.add_generator(None) Traceback (most recent call last): ... - TypeError: argument must be a BooleanPolynomial. + TypeError: argument must be a BooleanPolynomial """ if p is None: - raise TypeError("argument must be a BooleanPolynomial.") + raise TypeError("argument must be a BooleanPolynomial") if p._pbpoly.isZero(): - raise ValueError("zero generators not allowed.") + raise ValueError("zero generators not allowed") deref(self._strat).addGenerator(p._pbpoly) def nf(self, BooleanPolynomial p): @@ -6525,7 +6516,6 @@ cdef class FGLMStrategy: Traceback (most recent call last): ... RuntimeError... - """ cdef BooleanPolynomialRing _from_ring, _to_ring @@ -6598,7 +6588,7 @@ cdef class GroebnerStrategy: self._strat = make_shared[PBGBStrategy]((param)._pbring) self._parent = param else: - raise ValueError("Cannot generate GroebnerStrategy from %s." % + raise ValueError("cannot generate GroebnerStrategy from %s" % type(param)) self.reduction_strategy = ReductionStrategy(self._parent) @@ -6629,7 +6619,7 @@ cdef class GroebnerStrategy: [a + b, a + c] """ if p._pbpoly.isZero(): - raise ValueError("zero generators not allowed.") + raise ValueError("zero generators not allowed") deref(self._strat).addGeneratorDelayed(p._pbpoly) def add_generator(self, BooleanPolynomial p): @@ -6654,7 +6644,7 @@ cdef class GroebnerStrategy: ValueError: strategy already contains a polynomial with same lead """ if p._pbpoly.isZero(): - raise ValueError("zero generators not allowed.") + raise ValueError("zero generators not allowed") if deref(self._strat).generators.leadingTerms.owns(p._pbpoly.lead()): raise ValueError("strategy already contains a polynomial with same lead") deref(self._strat).generators.addGenerator(p._pbpoly) @@ -6689,7 +6679,7 @@ cdef class GroebnerStrategy: [a + c, b + c] """ if p._pbpoly.isZero(): - raise ValueError("zero generators not allowed.") + raise ValueError("zero generators not allowed") deref(self._strat).addAsYouWish(p._pbpoly) def implications(self, i): @@ -7207,7 +7197,7 @@ def zeros(pol, BooleSet s): elif isinstance(pol, BooleanMonomial): p = PBBoolePolynomial((pol)._pbmonom) else: - raise TypeError("Argument 'p' has incorrect type (expected BooleanPolynomial or BooleanMonomial, got %s)" % type(pol)) + raise TypeError("argument 'p' has incorrect type (expected BooleanPolynomial or BooleanMonomial, got %s)" % type(pol)) return new_BS_from_PBSet(pb_zeros(p, s._pbset), s._ring) @@ -7256,13 +7246,13 @@ def interpolate(zero, one): z = (zero)._pbpoly.set() ring = (zero)._parent else: - raise TypeError("Argument 'zero' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(zero)) + raise TypeError("argument 'zero' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(zero)) if isinstance(one, BooleSet): o = (one)._pbset elif isinstance(one, BooleanPolynomial): o = (one)._pbpoly.set() else: - raise TypeError("Argument 'one' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(one)) + raise TypeError("argument 'one' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(one)) return new_BP_from_PBPoly(ring, pb_interpolate(z, o)) @@ -7333,13 +7323,13 @@ def interpolate_smallest_lex(zero, one): elif isinstance(zero, BooleanPolynomial): z = (zero)._pbpoly.set() else: - raise TypeError("Argument 'zero' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(zero)) + raise TypeError("argument 'zero' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(zero)) if isinstance(one, BooleSet): o = (one)._pbset elif isinstance(one, BooleanPolynomial): o = (one)._pbpoly.set() else: - raise TypeError("Argument 'one' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(one)) + raise TypeError("argument 'one' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(one)) return new_BP_from_PBPoly(zero.ring(), pb_interpolate_smallest_lex(z, o)) @@ -7400,7 +7390,7 @@ def ll_red_nf_redsb(p, BooleSet reductors): t = PBBoolePolynomial((p)._pbmonom) parent = (p)._ring else: - raise TypeError("Argument 'p' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(p)) + raise TypeError("argument 'p' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(p)) res = pb_ll_red_nf(t, reductors._pbset) @@ -7513,7 +7503,7 @@ def if_then_else(root, a, b): sage: if_then_else(x5, f0, f1) Traceback (most recent call last): ... - IndexError: index of root must be less than the values of roots of the branches. + IndexError: index of root must be less than the values of roots of the branches """ cdef PBSet a_set, b_set cdef PBSet res @@ -7525,14 +7515,14 @@ def if_then_else(root, a, b): b_set = (b)._pbpoly.set() ring = (b)._parent else: - raise TypeError("Argument 'b' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(b)) + raise TypeError("argument 'b' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(b)) if isinstance(a, BooleSet): a_set = (a)._pbset elif isinstance(a, BooleanPolynomial): a_set = (a)._pbpoly.set() else: - raise TypeError("Argument 'a' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(a)) + raise TypeError("argument 'a' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(a)) try: root = int(root) @@ -7541,22 +7531,22 @@ def if_then_else(root, a, b): if len(root) == 1: root = root.lm() else: - raise TypeError("Only variables are acceptable as root.") + raise TypeError("only variables are acceptable as root") if isinstance(root, BooleanMonomial): if len(root) == 1: root = root.index() else: - raise TypeError("Only variables are acceptable as root.") + raise TypeError("only variables are acceptable as root") if not isinstance(root, int): - raise TypeError("Only variables are acceptable as root.") + raise TypeError("only variables are acceptable as root") cdef Py_ssize_t* pbind = ring.pbind root = ring.pbind[root] if (root >= a_set.navigation().value()) or (root >= b_set.navigation().value()): raise IndexError("index of root must be less than " - "the values of roots of the branches.") + "the values of roots of the branches") res = PBBooleSet(root, a_set.navigation(), b_set.navigation(), ring._pbring) @@ -7590,7 +7580,7 @@ def top_index(s): elif isinstance(s, BooleanPolynomial): idx = (s)._pbpoly.navigation().value() else: - raise TypeError("Argument 's' has incorrect type (expected BooleSet, BooleanMonomial or BooleanPolynomial, got %s)" % type(s)) + raise TypeError("argument 's' has incorrect type (expected BooleSet, BooleanMonomial or BooleanPolynomial, got %s)" % type(s)) return (s.ring()).pbind[idx] @@ -8010,19 +8000,16 @@ cdef class VariableFactory: a sage: VariableFactory(B)(0) a - """ if ring is None and self._ring is not None: return new_BM_from_PBVar(self._ring._monom_monoid, self._ring, self._factory(arg)) - elif isinstance(arg, BooleanPolynomialRing): + if isinstance(arg, BooleanPolynomialRing): return arg.variable(0) - elif isinstance(ring, BooleanPolynomialRing): + if isinstance(ring, BooleanPolynomialRing): return (ring).variable(arg) - else: - raise TypeError( - "Cannot convert (%s, %s) to Boolean Variable" % - (type(arg), type(ring))) + raise TypeError("cannot convert (%s, %s) to Boolean Variable" % + (type(arg), type(ring))) cdef class MonomialFactory: @@ -8097,7 +8084,7 @@ cdef class MonomialFactory: return result except Exception: raise TypeError( - "Cannot %s convert to Boolean Monomial" % type(arg)) + "cannot %s convert to Boolean Monomial" % type(arg)) cdef class PolynomialFactory: @@ -8174,5 +8161,5 @@ cdef class PolynomialFactory: return new_BP_from_PBPoly(self._ring, self._factory((arg)._pbmonom)) - raise TypeError("Cannot convert %s to BooleanPolynomial" % + raise TypeError("cannot convert %s to BooleanPolynomial" % type(arg)) From 7235c9376163061759c812ceec99361a61694188 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Sat, 24 Sep 2022 10:20:21 +0200 Subject: [PATCH 710/742] typos --- src/sage/rings/polynomial/skew_polynomial_finite_order.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx index b21e2eb37db..951fcd22c97 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx @@ -266,7 +266,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): By default, the name of the central variable is usually ``z`` (see :meth:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_finite_order.center` for more details about this). - However, the user can speciify a different variable name if desired:: + However, the user can specify a different variable name if desired:: sage: a.reduced_norm(var='u') u^3 + 4*u^2 + 4 @@ -367,7 +367,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): The reduced characteristic polynomial has coefficients in the center of `S`, which is itself a univariate polynomial ring in the variable - `z = u^3` over `\GF{5}`. Hence it appears as a bivariate polynomial. + `z = u^3` over `\GF{5}`. Hence it appears as a bivariate polynomial:: sage: chi.parent() Univariate Polynomial Ring in x over Univariate Polynomial Ring in z over Finite Field of size 5 From bda724dc57e1389f4f36db54278fea7cb592a5f2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 24 Sep 2022 16:24:57 -0700 Subject: [PATCH 711/742] build/pkgs/setuptools_wheel: Update to 65.4.0 --- build/pkgs/setuptools_wheel/checksums.ini | 6 +++--- build/pkgs/setuptools_wheel/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/setuptools_wheel/checksums.ini b/build/pkgs/setuptools_wheel/checksums.ini index 3850ab96795..2da328e1726 100644 --- a/build/pkgs/setuptools_wheel/checksums.ini +++ b/build/pkgs/setuptools_wheel/checksums.ini @@ -1,5 +1,5 @@ tarball=setuptools-VERSION.tar.gz -sha1=984db5daf7ecf07640c75fbd86b48935cd333c86 -md5=66c6b8819c5306c12c38d7fad41b7f99 -cksum=2256175575 +sha1=e5f9797d85db9bb2ce39b401c1b7aca38de616b5 +md5=ec88a6545351e72ca73fcec7a6bff6ad +cksum=1981709060 upstream_url=https://pypi.io/packages/source/s/setuptools/setuptools-VERSION.tar.gz diff --git a/build/pkgs/setuptools_wheel/package-version.txt b/build/pkgs/setuptools_wheel/package-version.txt index 8390dbf7231..ba0d20023a1 100644 --- a/build/pkgs/setuptools_wheel/package-version.txt +++ b/build/pkgs/setuptools_wheel/package-version.txt @@ -1 +1 @@ -65.3.0 +65.4.0 From 996461a5e06cef4faa60b646446a62cff3041ede Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 24 Sep 2022 17:33:00 -0700 Subject: [PATCH 712/742] build/pkgs/sagemath_repl/dependencies: Update from pkgs/sagemath-repl/setup.cfg.m4 --- build/pkgs/sagemath_repl/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/sagemath_repl/dependencies b/build/pkgs/sagemath_repl/dependencies index 6c22cd39e91..ebc253dac5b 100644 --- a/build/pkgs/sagemath_repl/dependencies +++ b/build/pkgs/sagemath_repl/dependencies @@ -1 +1 @@ -$(PYTHON) sagemath_objects ipython | $(PYTHON_TOOLCHAIN) python_build +$(PYTHON) sagemath_objects sagemath_environment ipython ipywidgets | $(PYTHON_TOOLCHAIN) python_build From 0ffdd57a963b29ec2c681975fc5c7e8682c82b24 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 24 Sep 2022 17:33:20 -0700 Subject: [PATCH 713/742] pkgs/sagemath-repl/setup.cfg.m4: Update python-requires --- pkgs/sagemath-repl/setup.cfg.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/sagemath-repl/setup.cfg.m4 b/pkgs/sagemath-repl/setup.cfg.m4 index f8757ee66cb..96515e21499 100644 --- a/pkgs/sagemath-repl/setup.cfg.m4 +++ b/pkgs/sagemath-repl/setup.cfg.m4 @@ -18,14 +18,14 @@ classifiers = Operating System :: POSIX Operating System :: MacOS :: MacOS X Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering :: Mathematics [options] -python_requires = >=3.7, <3.11 +python_requires = >=3.8, <3.11 install_requires = esyscmd(`sage-get-system-packages install-requires \ sagemath_objects \ From 141318f276c07658845e2df41d3255c9c9bbbbc3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 24 Sep 2022 17:35:19 -0700 Subject: [PATCH 714/742] build/pkgs/sagemath_categories/dependencies: Remove dependencies implied by sagemath_objects dependencies --- build/pkgs/sagemath_categories/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/sagemath_categories/dependencies b/build/pkgs/sagemath_categories/dependencies index b8d566d84de..d8b6bdbd4a7 100644 --- a/build/pkgs/sagemath_categories/dependencies +++ b/build/pkgs/sagemath_categories/dependencies @@ -1 +1 @@ -$(PYTHON) cysignals gmpy2 sagemath_objects | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig python_build +$(PYTHON) sagemath_objects | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig python_build From 3da18116695c59d26f5243386a303ae04357e412 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 25 Sep 2022 10:42:08 +0900 Subject: [PATCH 715/742] Wrapping lines of README.rst --- pkgs/sagemath-categories/README.rst | 18 +++++++++++++++--- pkgs/sagemath-environment/README.rst | 17 ++++++++++++++--- pkgs/sagemath-objects/README.rst | 16 +++++++++++++--- pkgs/sagemath-repl/README.rst | 15 ++++++++++++--- 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/pkgs/sagemath-categories/README.rst b/pkgs/sagemath-categories/README.rst index 81311e5a217..d1f90fea966 100644 --- a/pkgs/sagemath-categories/README.rst +++ b/pkgs/sagemath-categories/README.rst @@ -12,15 +12,27 @@ About SageMath https://www.sagemath.org -SageMath fully supports all major Linux distributions, recent versions of macOS, and Windows (using Cygwin or Windows Subsystem for Linux). +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). -The traditional and recommended way to install SageMath is from source via Sage-the-distribution (https://www.sagemath.org/download-source.html). Sage-the-distribution first builds a large number of open source packages from source (unless it finds suitable versions installed in the system) and then installs the Sage Library (sagelib, implemented in Python and Cython). +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). About this experimental pip-installable source distribution ----------------------------------------------------------- -This pip-installable source distribution `sagemath-categories` is an experimental distribution of a small part of the Sage Library. Use at your own risk. It provides a small subset of the modules of the Sage library ("sagelib", `sagemath-standard`). It is a superset of the `sagemath-objects` (providing Sage objects, the element/parent framework, categories, the coercion system and the related metaclasses), making various additional categories available without introducing dependencies on additional mathematical libraries. +This pip-installable source distribution `sagemath-categories` is an +experimental distribution of a small part of the Sage Library. Use at your own +risk. It provides a small subset of the modules of the Sage library +("sagelib", `sagemath-standard`). It is a superset of the `sagemath-objects` +(providing Sage objects, the element/parent framework, categories, the coercion +system and the related metaclasses), making various additional categories +available without introducing dependencies on additional mathematical +libraries. Dependencies diff --git a/pkgs/sagemath-environment/README.rst b/pkgs/sagemath-environment/README.rst index 7c71698734a..ba5905777c0 100644 --- a/pkgs/sagemath-environment/README.rst +++ b/pkgs/sagemath-environment/README.rst @@ -12,12 +12,23 @@ About SageMath https://www.sagemath.org -SageMath fully supports all major Linux distributions, recent versions of macOS, and Windows (using Cygwin or Windows Subsystem for Linux). +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). -The traditional and recommended way to install SageMath is from source via Sage-the-distribution (https://www.sagemath.org/download-source.html). Sage-the-distribution first builds a large number of open source packages from source (unless it finds suitable versions installed in the system) and then installs the Sage Library (sagelib, implemented in Python and Cython). +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). About this experimental pip-installable source distribution ----------------------------------------------------------- -This pip-installable source distribution `sagemath-environment` is an experimental distribution of a small part of the Sage Library. Use at your own risk. It provides a small, fundamental subset of the modules of the Sage library ("sagelib", `sagemath-standard`), providing the connection to the system and software environment. It also includes the `sage` script for launching the Sage REPL and accessing various developer tools (see `sage --help`). +This pip-installable source distribution `sagemath-environment` is an +experimental distribution of a small part of the Sage Library. Use at your own +risk. It provides a small, fundamental subset of the modules of the Sage +library ("sagelib", `sagemath-standard`), providing the connection to the +system and software environment. It also includes the `sage` script for +launching the Sage REPL and accessing various developer tools (see `sage +--help`). diff --git a/pkgs/sagemath-objects/README.rst b/pkgs/sagemath-objects/README.rst index 8058f633654..9dc9cfd888f 100644 --- a/pkgs/sagemath-objects/README.rst +++ b/pkgs/sagemath-objects/README.rst @@ -12,15 +12,25 @@ About SageMath https://www.sagemath.org -SageMath fully supports all major Linux distributions, recent versions of macOS, and Windows (using Cygwin or Windows Subsystem for Linux). +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). -The traditional and recommended way to install SageMath is from source via Sage-the-distribution (https://www.sagemath.org/download-source.html). Sage-the-distribution first builds a large number of open source packages from source (unless it finds suitable versions installed in the system) and then installs the Sage Library (sagelib, implemented in Python and Cython). +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). About this experimental pip-installable source distribution ----------------------------------------------------------- -This pip-installable source distribution `sagemath-objects` is an experimental distribution of a small part of the Sage Library. Use at your own risk. It provides a small, fundamental subset of the modules of the Sage library ("sagelib", `sagemath-standard`), making Sage objects, the element/parent framework, categories, the coercion system and the related metaclasses available. +This pip-installable source distribution `sagemath-objects` is an experimental +distribution of a small part of the Sage Library. Use at your own risk. It +provides a small, fundamental subset of the modules of the Sage library +("sagelib", `sagemath-standard`), making Sage objects, the element/parent +framework, categories, the coercion system and the related metaclasses +available. Dependencies diff --git a/pkgs/sagemath-repl/README.rst b/pkgs/sagemath-repl/README.rst index 1e0af5c4e7e..3dde4aae5e5 100644 --- a/pkgs/sagemath-repl/README.rst +++ b/pkgs/sagemath-repl/README.rst @@ -12,12 +12,21 @@ About SageMath https://www.sagemath.org -SageMath fully supports all major Linux distributions, recent versions of macOS, and Windows (using Cygwin or Windows Subsystem for Linux). +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). -The traditional and recommended way to install SageMath is from source via Sage-the-distribution (https://www.sagemath.org/download-source.html). Sage-the-distribution first builds a large number of open source packages from source (unless it finds suitable versions installed in the system) and then installs the Sage Library (sagelib, implemented in Python and Cython). +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). About this experimental pip-installable source distribution ----------------------------------------------------------- -This pip-installable source distribution `sagemath-repl` is an experimental distribution of a small part of the Sage Library. Use at your own risk. It provides a small, fundamental subset of the modules of the Sage library ("sagelib", `sagemath-standard`), providing the IPython kernel, Sage preparser, and doctester. +This pip-installable source distribution `sagemath-repl` is an experimental +distribution of a small part of the Sage Library. Use at your own risk. It +provides a small, fundamental subset of the modules of the Sage library +("sagelib", `sagemath-standard`), providing the IPython kernel, Sage preparser, +and doctester. From 664e98ca7aa321327a3af7901f34c1c35936c745 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 24 Sep 2022 21:40:13 -0700 Subject: [PATCH 716/742] build/pkgs/distlib/checksums.ini: switch to tar.gz --- build/pkgs/distlib/checksums.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/distlib/checksums.ini b/build/pkgs/distlib/checksums.ini index e83721c68b5..1d749b2f9a7 100644 --- a/build/pkgs/distlib/checksums.ini +++ b/build/pkgs/distlib/checksums.ini @@ -1,5 +1,5 @@ -tarball=distlib-VERSION.zip +tarball=distlib-VERSION.tar.gz sha1=3a86d49dc17320325004564d0dc86afa808624bc md5=f60ba4e3f8e76c214d3d00b2227a16f7 cksum=1543870863 -upstream_url=https://pypi.io/packages/source/d/distlib/distlib-VERSION.zip +upstream_url=https://pypi.io/packages/source/d/distlib/distlib-VERSION.tar.gz From 805bf1194f1944855faa95dd155b711f811e5393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 25 Sep 2022 09:28:45 +0200 Subject: [PATCH 717/742] use .Display for character tables --- src/sage/groups/perm_gps/permgroup.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 3a0c780d677..1b3b174a6e6 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -3358,8 +3358,7 @@ def character_table(self): sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3)]]) sage: CT = gap(G).CharacterTable() - Type ``print(gap.eval("Display(%s)"%CT.name()))`` to display this - nicely. + Type ``CT.Display()`` to display this nicely. :: @@ -3374,8 +3373,7 @@ def character_table(self): [ 2 0 0 0 -2] sage: CT = gap(G).CharacterTable() - Again, type ``print(gap.eval("Display(%s)"%CT.name()))`` to display this - nicely. + Again, type ``CT.Display()`` to display this nicely. :: From 74eda63d6ed027e73c2e9bba9306f06611e91d41 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 5 May 2022 12:22:55 +0100 Subject: [PATCH 718/742] use Homebrew's primecount --- .homebrew-build-env | 4 ++-- build/pkgs/primecount/distros/homebrew.txt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 build/pkgs/primecount/distros/homebrew.txt diff --git a/.homebrew-build-env b/.homebrew-build-env index 84f5017a310..506055480f5 100644 --- a/.homebrew-build-env +++ b/.homebrew-build-env @@ -10,7 +10,7 @@ done export PATH PKG_CONFIG_PATH="$HOMEBREW/lib/pkgconfig:$PKG_CONFIG_PATH" # libpng.pc depends on zlib.pc -for l in openblas openssl readline sqlite zlib; do +for l in openblas openssl readline sqlite zlib primesieve primecount; do if [ -d "$HOMEBREW/opt/$l/lib/pkgconfig" ]; then PKG_CONFIG_PATH="$HOMEBREW/opt/$l/lib/pkgconfig:$PKG_CONFIG_PATH" fi @@ -23,7 +23,7 @@ export PKG_CONFIG_PATH LIBRARY_PATH="$HOMEBREW/lib$LIBRARY_PATH" [ -z "$CPATH" ] || CPATH=":${CPATH}" CPATH="$HOMEBREW/include$CPATH" -for l in readline bzip2 ntl polymake libpng bdw-gc primesieve; do +for l in readline bzip2 ntl polymake libpng bdw-gc primesieve primecount; do if [ -d "$HOMEBREW/opt/$l/lib" ]; then LIBRARY_PATH="$HOMEBREW/opt/$l/lib:$LIBRARY_PATH" fi diff --git a/build/pkgs/primecount/distros/homebrew.txt b/build/pkgs/primecount/distros/homebrew.txt new file mode 100644 index 00000000000..f67843baa2b --- /dev/null +++ b/build/pkgs/primecount/distros/homebrew.txt @@ -0,0 +1 @@ +primecount From 82c8e7a2787cdad2a9389460cf3468e08f25b4c9 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sun, 25 Sep 2022 15:36:08 +0100 Subject: [PATCH 719/742] Revert "use Homebrew's primecount" This reverts commit 74eda63d6ed027e73c2e9bba9306f06611e91d41. --- .homebrew-build-env | 4 ++-- build/pkgs/primecount/distros/homebrew.txt | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 build/pkgs/primecount/distros/homebrew.txt diff --git a/.homebrew-build-env b/.homebrew-build-env index 506055480f5..84f5017a310 100644 --- a/.homebrew-build-env +++ b/.homebrew-build-env @@ -10,7 +10,7 @@ done export PATH PKG_CONFIG_PATH="$HOMEBREW/lib/pkgconfig:$PKG_CONFIG_PATH" # libpng.pc depends on zlib.pc -for l in openblas openssl readline sqlite zlib primesieve primecount; do +for l in openblas openssl readline sqlite zlib; do if [ -d "$HOMEBREW/opt/$l/lib/pkgconfig" ]; then PKG_CONFIG_PATH="$HOMEBREW/opt/$l/lib/pkgconfig:$PKG_CONFIG_PATH" fi @@ -23,7 +23,7 @@ export PKG_CONFIG_PATH LIBRARY_PATH="$HOMEBREW/lib$LIBRARY_PATH" [ -z "$CPATH" ] || CPATH=":${CPATH}" CPATH="$HOMEBREW/include$CPATH" -for l in readline bzip2 ntl polymake libpng bdw-gc primesieve primecount; do +for l in readline bzip2 ntl polymake libpng bdw-gc primesieve; do if [ -d "$HOMEBREW/opt/$l/lib" ]; then LIBRARY_PATH="$HOMEBREW/opt/$l/lib:$LIBRARY_PATH" fi diff --git a/build/pkgs/primecount/distros/homebrew.txt b/build/pkgs/primecount/distros/homebrew.txt deleted file mode 100644 index f67843baa2b..00000000000 --- a/build/pkgs/primecount/distros/homebrew.txt +++ /dev/null @@ -1 +0,0 @@ -primecount From 7bd0541af0eec33e08190ad3833c017f215a214a Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sun, 25 Sep 2022 15:37:53 +0100 Subject: [PATCH 720/742] use Homebrew's primecount --- build/pkgs/primecount/distros/homebrew.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 build/pkgs/primecount/distros/homebrew.txt diff --git a/build/pkgs/primecount/distros/homebrew.txt b/build/pkgs/primecount/distros/homebrew.txt new file mode 100644 index 00000000000..f67843baa2b --- /dev/null +++ b/build/pkgs/primecount/distros/homebrew.txt @@ -0,0 +1 @@ +primecount From 499f10b1d865c1e4a5fc8080f9d9bea524659ec1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 25 Sep 2022 09:26:52 -0700 Subject: [PATCH 721/742] build/pkgs/numpy/spkg-install.in: Remove outdated workaround for numpy 1.20.x from Trac #32021 --- build/pkgs/numpy/spkg-install.in | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build/pkgs/numpy/spkg-install.in b/build/pkgs/numpy/spkg-install.in index f66c6f56426..68142b48aba 100644 --- a/build/pkgs/numpy/spkg-install.in +++ b/build/pkgs/numpy/spkg-install.in @@ -27,10 +27,6 @@ fi export FFLAGS="$FFLAGS -fPIC" export FCFLAGS="$FCFLAGS -fPIC" -# Numpy 1.20.3 enables some intrinsics on machines without support with `-march=native`. -# We disable it until this is fixed. -export CFLAGS="$CFLAGS_NON_NATIVE" - export NUMPY_FCONFIG="config_fc --noopt --noarch" if [ "$SAGE_FAT_BINARY" = "yes" ]; then export NUMPY_FCONFIG="--cpu-baseline=NONE" From 81a5e8ebea5a177c4ac0607df28729ecd5b520b9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 25 Sep 2022 09:50:46 -0700 Subject: [PATCH 722/742] build/pkgs/numpy/spkg-install.in: Remove unexplained 'config_fc --noopt --noarch' introduced in 908f93fedb12b48f5366c7a141837b82595ee1d1 (2010) --- build/pkgs/numpy/spkg-install.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build/pkgs/numpy/spkg-install.in b/build/pkgs/numpy/spkg-install.in index 68142b48aba..986a14255e1 100644 --- a/build/pkgs/numpy/spkg-install.in +++ b/build/pkgs/numpy/spkg-install.in @@ -27,11 +27,10 @@ fi export FFLAGS="$FFLAGS -fPIC" export FCFLAGS="$FCFLAGS -fPIC" -export NUMPY_FCONFIG="config_fc --noopt --noarch" if [ "$SAGE_FAT_BINARY" = "yes" ]; then export NUMPY_FCONFIG="--cpu-baseline=NONE" else - export NUMPY_FCONFIG + export NUMPY_FCONFIG="" fi # Trac #32423: Fix 32-bit builds on x86_64 From 03fad7d05a2739d44af7d5eb889885ab32b402e3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 25 Sep 2022 10:54:25 -0700 Subject: [PATCH 723/742] build/pkgs/numpy/spkg-install.in: Workaround for clang compiler bug affecting 'reciprocal' and incomplete numpy fix --- build/pkgs/numpy/spkg-install.in | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/build/pkgs/numpy/spkg-install.in b/build/pkgs/numpy/spkg-install.in index 986a14255e1..2b555d8b871 100644 --- a/build/pkgs/numpy/spkg-install.in +++ b/build/pkgs/numpy/spkg-install.in @@ -7,6 +7,14 @@ if [ `uname` = "Darwin" ]; then unset ATLAS unset BLAS unset LAPACK + # https://trac.sagemath.org/ticket/34110#comment:35 + # The fix for "reciprocal" (affected by a clang compiler bug) in + # https://github.com/numpy/numpy/pull/19926 relies on -ftrapping-math + # being used when Apple clang v12+ is used. + # But numpy.distutils.ccompiler only sets this flag when + # $CC contains the string "clang" -- missing the case CC=/usr/bin/gcc. + # So we set it here explicitly if the compiler supports the flag. + export CFLAGS="$(testcflags.sh $CFLAGS -ftrapping-math)" else export {ATLAS,PTATLAS,OPENBLAS,MKL,MKLROOT}=None export LDFLAGS="${LDFLAGS} -shared" From e5d1070e3b851da062e00ead6832ea30cd6e1a8e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 25 Sep 2022 11:11:44 -0700 Subject: [PATCH 724/742] src/sage/misc/lazy_import.pyx: Add comments --- src/sage/misc/lazy_import.pyx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index a835a401c88..2d4413cd1a3 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -68,11 +68,17 @@ from warnings import warn import inspect from . import sageinspect + +# LazyImport.__repr__ uses try... except FeatureNotPresentError. +# This is defined in sage.features, provided by the distribution sagemath-environment. try: from sage.features import FeatureNotPresentError except ImportError: + # If sage.features cannot be imported, then FeatureNotPresentError cannot + # be raised. In this case, use the empty tuple as the exception specification. FeatureNotPresentError = () + cdef inline obj(x): if type(x) is LazyImport: return (x).get_object() @@ -255,6 +261,7 @@ cdef class LazyImport(): self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name) except ImportError as e: if self._feature: + # Avoid warnings from static type checkers by explicitly importing FeatureNotPresentError. from sage.features import FeatureNotPresentError raise FeatureNotPresentError(self._feature, reason=f'Importing {self._name} failed: {e}') raise From 4541564cf151a5138810e9c2144349f59469d769 Mon Sep 17 00:00:00 2001 From: Release Manager Date: Sun, 25 Sep 2022 20:47:57 +0200 Subject: [PATCH 725/742] Updated SageMath version to 9.8.beta0 --- .zenodo.json | 8 ++++---- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/sage_conf/install-requires.txt | 2 +- build/pkgs/sage_docbuild/install-requires.txt | 2 +- build/pkgs/sage_setup/install-requires.txt | 2 +- build/pkgs/sage_sws2rst/install-requires.txt | 2 +- build/pkgs/sagelib/install-requires.txt | 2 +- build/pkgs/sagemath_categories/install-requires.txt | 2 +- build/pkgs/sagemath_environment/install-requires.txt | 2 +- build/pkgs/sagemath_objects/install-requires.txt | 2 +- pkgs/sage-conf/VERSION.txt | 2 +- pkgs/sage-conf_pypi/VERSION.txt | 2 +- pkgs/sage-docbuild/VERSION.txt | 2 +- pkgs/sage-setup/VERSION.txt | 2 +- pkgs/sage-sws2rst/VERSION.txt | 2 +- pkgs/sagemath-categories/VERSION.txt | 2 +- pkgs/sagemath-environment/VERSION.txt | 2 +- pkgs/sagemath-objects/VERSION.txt | 2 +- pkgs/sagemath-repl/VERSION.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 24 files changed, 33 insertions(+), 33 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index 91b74285b39..06bf86e4065 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,10 +1,10 @@ { "description": "Mirror of the Sage https://sagemath.org/ source tree", "license": "other-open", - "title": "sagemath/sage: 9.7", - "version": "9.7", + "title": "sagemath/sage: 9.8.beta0", + "version": "9.8.beta0", "upload_type": "software", - "publication_date": "2022-09-19", + "publication_date": "2022-09-25", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.7", + "identifier": "https://github.com/sagemath/sage/tree/9.8.beta0", "relation": "isSupplementTo" }, { diff --git a/VERSION.txt b/VERSION.txt index 6e6a77791e1..58778909bd8 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.7, Release Date: 2022-09-19 +SageMath version 9.8.beta0, Release Date: 2022-09-25 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 1506e268bde..d7e7fc0fcc1 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=5a1689117566cc63ea05f0aa9a2f125da7ba7dc6 -md5=37178d28e02f691476b4ba5b9e915026 -cksum=4153085574 +sha1=c2e1c4db6762c4d97d5127f5f056e46fe3d5a94d +md5=70dcc35964e4234443c4e77beb2245d7 +cksum=2271434645 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index dc10cfa4f97..abdbdc62467 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -1cee2c8b179b9fb913facf54b48dd710178bbffc +04fbc829e9850eedf555acc683666c55cb7052d7 diff --git a/build/pkgs/sage_conf/install-requires.txt b/build/pkgs/sage_conf/install-requires.txt index a0356056891..35a8993af20 100644 --- a/build/pkgs/sage_conf/install-requires.txt +++ b/build/pkgs/sage_conf/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 9.7 +sage-conf ~= 9.8b0 diff --git a/build/pkgs/sage_docbuild/install-requires.txt b/build/pkgs/sage_docbuild/install-requires.txt index 202df450687..002c6b79c65 100644 --- a/build/pkgs/sage_docbuild/install-requires.txt +++ b/build/pkgs/sage_docbuild/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 9.7 +sage-docbuild ~= 9.8b0 diff --git a/build/pkgs/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt index 1b631d955d2..5720bc8f2c5 100644 --- a/build/pkgs/sage_setup/install-requires.txt +++ b/build/pkgs/sage_setup/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 9.7 +sage-setup ~= 9.8b0 diff --git a/build/pkgs/sage_sws2rst/install-requires.txt b/build/pkgs/sage_sws2rst/install-requires.txt index 344cda711c9..70be4d731ee 100644 --- a/build/pkgs/sage_sws2rst/install-requires.txt +++ b/build/pkgs/sage_sws2rst/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 9.7 +sage-sws2rst ~= 9.8b0 diff --git a/build/pkgs/sagelib/install-requires.txt b/build/pkgs/sagelib/install-requires.txt index edd78431534..359dff35670 100644 --- a/build/pkgs/sagelib/install-requires.txt +++ b/build/pkgs/sagelib/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagelib ~= 9.7 +sagelib ~= 9.8b0 diff --git a/build/pkgs/sagemath_categories/install-requires.txt b/build/pkgs/sagemath_categories/install-requires.txt index 848ad97d3e1..070f8caa2ea 100644 --- a/build/pkgs/sagemath_categories/install-requires.txt +++ b/build/pkgs/sagemath_categories/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 9.7 +sagemath-categories ~= 9.8b0 diff --git a/build/pkgs/sagemath_environment/install-requires.txt b/build/pkgs/sagemath_environment/install-requires.txt index 92b35788acb..e9976c7146f 100644 --- a/build/pkgs/sagemath_environment/install-requires.txt +++ b/build/pkgs/sagemath_environment/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 9.7 +sagemath-environment ~= 9.8b0 diff --git a/build/pkgs/sagemath_objects/install-requires.txt b/build/pkgs/sagemath_objects/install-requires.txt index 17764575b14..0fb621f26f2 100644 --- a/build/pkgs/sagemath_objects/install-requires.txt +++ b/build/pkgs/sagemath_objects/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 9.7 +sagemath-objects ~= 9.8b0 diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index 9d5e716c055..aadd65deb15 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -9.7 +9.8.beta0 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index 9d5e716c055..aadd65deb15 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -9.7 +9.8.beta0 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index 9d5e716c055..aadd65deb15 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -9.7 +9.8.beta0 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index 9d5e716c055..aadd65deb15 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -9.7 +9.8.beta0 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index 9d5e716c055..aadd65deb15 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -9.7 +9.8.beta0 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index 9d5e716c055..aadd65deb15 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -9.7 +9.8.beta0 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index 9d5e716c055..aadd65deb15 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -9.7 +9.8.beta0 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index 9d5e716c055..aadd65deb15 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -9.7 +9.8.beta0 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index 9d5e716c055..aadd65deb15 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -9.7 +9.8.beta0 diff --git a/src/VERSION.txt b/src/VERSION.txt index 9d5e716c055..aadd65deb15 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.7 +9.8.beta0 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 7fc8e994958..802ca805250 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.7' -SAGE_RELEASE_DATE='2022-09-19' -SAGE_VERSION_BANNER='SageMath version 9.7, Release Date: 2022-09-19' +SAGE_VERSION='9.8.beta0' +SAGE_RELEASE_DATE='2022-09-25' +SAGE_VERSION_BANNER='SageMath version 9.8.beta0, Release Date: 2022-09-25' diff --git a/src/sage/version.py b/src/sage/version.py index 139e6f07404..94cf8afef07 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '9.7' -date = '2022-09-19' -banner = 'SageMath version 9.7, Release Date: 2022-09-19' +version = '9.8.beta0' +date = '2022-09-25' +banner = 'SageMath version 9.8.beta0, Release Date: 2022-09-25' From f0def924fea5ab8caaeccd0f89d21d455004a6aa Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 25 Sep 2022 16:42:30 -0700 Subject: [PATCH 726/742] src/sage/tensor/modules/tensor_free_module.py: Remove redundant method --- src/sage/tensor/modules/tensor_free_module.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 0a22d9cc5d1..b04e8581148 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -808,8 +808,3 @@ def _basis_sym(self): frame = tuple(self.base_module().irange()) tensor = self.ambient()() return tensor._new_comp(frame) - - # Until https://trac.sagemath.org/ticket/30373 is done, - # TensorProductFunctor._functor_name is "tensor" - def tensor(self, *others): - return self.tensor_product(*others) From 00d217122a30386b0205baecf01b65cd0b94b58a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 29 Aug 2022 19:02:55 -0700 Subject: [PATCH 727/742] sage --package create: Add option --source wheel --- build/sage_bootstrap/app.py | 10 +++++++++- build/sage_bootstrap/cmdline.py | 2 +- build/sage_bootstrap/creator.py | 3 +++ build/sage_bootstrap/pypi.py | 15 ++++++++++----- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py index d6094609d88..bdc32882a92 100644 --- a/build/sage_bootstrap/app.py +++ b/build/sage_bootstrap/app.py @@ -271,7 +271,7 @@ def create(self, package_name, version=None, tarball=None, pkg_type=None, upstre if '-' in package_name: raise ValueError('package names must not contain dashes, use underscore instead') if pypi: - pypi_version = PyPiVersion(package_name) + pypi_version = PyPiVersion(package_name, source=source) if source == 'normal': if not tarball: # Guess the general format of the tarball name. @@ -281,6 +281,14 @@ def create(self, package_name, version=None, tarball=None, pkg_type=None, upstre # Use a URL from pypi.io instead of the specific URL received from the PyPI query # because it follows a simple pattern. upstream_url = 'https://pypi.io/packages/source/{0:1.1}/{0}/{1}'.format(package_name, tarball) + elif source == 'wheel': + if not tarball: + tarball = pypi_version.tarball.replace(pypi_version.version, 'VERSION') + if not tarball.endswith('-none-any.whl'): + raise ValueError('Only platform-independent wheels can be used for wheel packages, got {0}'.format(tarball)) + if not version: + version = pypi_version.version + upstream_url = 'https://pypi.io/packages/py3/{0:1.1}/{0}/{1}'.format(package_name, tarball) if not description: description = pypi_version.summary if not license: diff --git a/build/sage_bootstrap/cmdline.py b/build/sage_bootstrap/cmdline.py index 780f3c5a8e3..aea51cb48f0 100644 --- a/build/sage_bootstrap/cmdline.py +++ b/build/sage_bootstrap/cmdline.py @@ -312,7 +312,7 @@ def make_parser(): 'package_name', default=None, type=str, help='Package name.') parser_create.add_argument( - '--source', type=str, default='normal', help='Package source (one of normal, script, pip)') + '--source', type=str, default='normal', help='Package source (one of normal, wheel, script, pip)') parser_create.add_argument( '--version', type=str, default=None, help='Package version') parser_create.add_argument( diff --git a/build/sage_bootstrap/creator.py b/build/sage_bootstrap/creator.py index 3779707de1f..a0756718316 100644 --- a/build/sage_bootstrap/creator.py +++ b/build/sage_bootstrap/creator.py @@ -99,6 +99,9 @@ def set_python_data_and_scripts(self, pypi_package_name=None, source='normal'): f.write('cd src\nsdh_pip_install .\n') with open(os.path.join(self.path, 'install-requires.txt'), 'w+') as f: f.write('{0}\n'.format(pypi_package_name)) + elif source == 'wheel': + with open(os.path.join(self.path, 'install-requires.txt'), 'w+') as f: + f.write('{0}\n'.format(pypi_package_name)) elif source == 'pip': with open(os.path.join(self.path, 'requirements.txt'), 'w+') as f: f.write('{0}\n'.format(pypi_package_name)) diff --git a/build/sage_bootstrap/pypi.py b/build/sage_bootstrap/pypi.py index 24b050045f9..5ade971682b 100644 --- a/build/sage_bootstrap/pypi.py +++ b/build/sage_bootstrap/pypi.py @@ -34,11 +34,15 @@ class PyPiError(Exception): class PyPiVersion(object): - def __init__(self, package_name): + def __init__(self, package_name, source='normal'): self.name = package_name self.json = self._get_json() # Replace provided name with the canonical name self.name = self.json['info']['name'] + if source == 'wheel': + self.python_version = 'py3' + else: + self.python_version = 'source' def _get_json(self): response = urllib.urlopen(self.json_url) @@ -64,10 +68,11 @@ def url(self): """ Return the source url """ + print(self.json['urls']) for download in self.json['urls']: - if download['python_version'] == 'source': + if download['python_version'] == self.python_version: return download['url'] - raise PyPiError('No source url for %s found', self.name) + raise PyPiError('No %s url for %s found', self.python_version, self.name) @property def tarball(self): @@ -75,9 +80,9 @@ def tarball(self): Return the source tarball name """ for download in self.json['urls']: - if download['python_version'] == 'source': + if download['python_version'] == self.python_version: return download['filename'] - raise PyPiError('No source url for %s found', self.name) + raise PyPiError('No %s url for %s found', self.python_version, self.name) @property def package_url(self): From 1a31a6a0f4fe563242e3ef7b04e737a6e0ec8945 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 25 Sep 2022 20:58:56 -0700 Subject: [PATCH 728/742] build/sage_bootstrap/pypi.py: Remove debugging code --- build/sage_bootstrap/pypi.py | 1 - 1 file changed, 1 deletion(-) diff --git a/build/sage_bootstrap/pypi.py b/build/sage_bootstrap/pypi.py index 5ade971682b..a11f3a95b46 100644 --- a/build/sage_bootstrap/pypi.py +++ b/build/sage_bootstrap/pypi.py @@ -68,7 +68,6 @@ def url(self): """ Return the source url """ - print(self.json['urls']) for download in self.json['urls']: if download['python_version'] == self.python_version: return download['url'] From 2efa3184692a6232eecfd5b7ab8347730246622b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 25 Sep 2022 21:01:06 -0700 Subject: [PATCH 729/742] build/sage_bootstrap/creator.py (set_python_data_and_scripts): Update docstring and exception message --- build/sage_bootstrap/creator.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/sage_bootstrap/creator.py b/build/sage_bootstrap/creator.py index a0756718316..f7a6ab203dc 100644 --- a/build/sage_bootstrap/creator.py +++ b/build/sage_bootstrap/creator.py @@ -87,6 +87,8 @@ def set_python_data_and_scripts(self, pypi_package_name=None, source='normal'): If ``source`` is ``"normal"``, write the files ``spkg-install.in`` and ``install-requires.txt``. + If ``source`` is ``"wheel"``, write the file ``install-requires.txt``. + If ``source`` is ``"pip"``, write the file ``requirements.txt``. """ if pypi_package_name is None: @@ -108,4 +110,4 @@ def set_python_data_and_scripts(self, pypi_package_name=None, source='normal'): elif source == 'script': pass else: - raise ValueError('package source must be one of normal, script, or pip') + raise ValueError('package source must be one of normal, script, pip, or wheel') From d18cfa4bcff599965396ead4537ab66f06048efd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 25 Sep 2022 21:10:34 -0700 Subject: [PATCH 730/742] build/sage_bootstrap/app.py, src/doc/en/developer/packaging.rst: Add doc --- build/sage_bootstrap/app.py | 10 +++++++++- src/doc/en/developer/packaging.rst | 8 ++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py index bdc32882a92..132ada17594 100644 --- a/build/sage_bootstrap/app.py +++ b/build/sage_bootstrap/app.py @@ -266,7 +266,15 @@ def fix_checksum(self, package_name): def create(self, package_name, version=None, tarball=None, pkg_type=None, upstream_url=None, description=None, license=None, upstream_contact=None, pypi=False, source='normal'): """ - Create a normal package + Create a package + + $ sage --package create foo --version 1.3 --tarball FoO-VERSION.tar.gz --type experimental + + $ sage --package create scikit_spatial --pypi --type optional + + $ sage --package create torch --pypi --source pip --type optional + + $ sage --package create jupyterlab_markup --pypi --source wheel --type optional """ if '-' in package_name: raise ValueError('package names must not contain dashes, use underscore instead') diff --git a/src/doc/en/developer/packaging.rst b/src/doc/en/developer/packaging.rst index 33ca56415f8..8f084b38ff6 100644 --- a/src/doc/en/developer/packaging.rst +++ b/src/doc/en/developer/packaging.rst @@ -1106,7 +1106,7 @@ set the ``upstream_url`` field in ``checksums.ini`` described above. For Python packages available from PyPI, you can use:: - [user@localhost]$ sage -package create scikit_spatial --pypi --type optional + [user@localhost]$ sage --package create scikit_spatial --pypi --type optional This automatically downloads the most recent version from PyPI and also obtains most of the necessary information by querying PyPI. @@ -1117,7 +1117,11 @@ in the file ``install-requires.txt``. To create a pip package rather than a normal package, you can use:: - [user@localhost]$ sage -package create scikit_spatial --pypi --source pip --type optional + [user@localhost]$ sage --package create scikit_spatial --pypi --source pip --type optional + +To create a wheel package rather than a normal package, you can use:: + + [user@localhost]$ sage --package create scikit_spatial --pypi --source wheel --type optional .. _section-manual-build: From 905a0eeb762a802538fea630460624c37bf42605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 26 Sep 2022 09:04:59 +0200 Subject: [PATCH 731/742] fix some E251 in modular/ --- src/sage/modular/abvar/cuspidal_subgroup.py | 8 ++-- src/sage/modular/abvar/finite_subgroup.py | 2 +- src/sage/modular/abvar/morphism.py | 2 +- .../modular/arithgroup/arithgroup_generic.py | 11 ++--- src/sage/modular/hecke/submodule.py | 5 +-- src/sage/modular/local_comp/type_space.py | 2 +- src/sage/modular/modform/ambient_eps.py | 10 ++--- src/sage/modular/modform/constructor.py | 40 +++++++++---------- .../modular/modform/cuspidal_submodule.py | 2 +- src/sage/modular/modform/eis_series.py | 21 +++++----- .../modular/modform/hecke_operator_on_qexp.py | 17 ++++---- src/sage/modular/modform/space.py | 2 +- src/sage/modular/modform/submodule.py | 3 +- .../hecke_triangle_groups.py | 2 +- .../series_constructor.py | 5 +-- src/sage/modular/modsym/ambient.py | 12 +++--- src/sage/modular/modsym/boundary.py | 12 +++--- src/sage/modular/modsym/modsym.py | 10 ++--- src/sage/modular/modsym/subspace.py | 7 ++-- src/sage/modular/overconvergent/genus0.py | 33 ++++++++------- src/sage/modular/pollack_stevens/manin_map.py | 2 +- src/sage/modular/pollack_stevens/space.py | 2 +- 22 files changed, 108 insertions(+), 102 deletions(-) diff --git a/src/sage/modular/abvar/cuspidal_subgroup.py b/src/sage/modular/abvar/cuspidal_subgroup.py index a2769d7eff7..136f6cf23e4 100644 --- a/src/sage/modular/abvar/cuspidal_subgroup.py +++ b/src/sage/modular/abvar/cuspidal_subgroup.py @@ -241,10 +241,11 @@ def lattice(self): try: return self.__lattice except AttributeError: - lattice = self._compute_lattice(rational_only = False) + lattice = self._compute_lattice(rational_only=False) self.__lattice = lattice return lattice + class RationalCuspSubgroup(CuspidalSubgroup_generic): """ EXAMPLES:: @@ -292,10 +293,11 @@ def lattice(self): try: return self.__lattice except AttributeError: - lattice = self._compute_lattice(rational_only = True) + lattice = self._compute_lattice(rational_only=True) self.__lattice = lattice return lattice + class RationalCuspidalSubgroup(CuspidalSubgroup_generic): """ EXAMPLES:: @@ -342,7 +344,7 @@ def lattice(self): try: return self.__lattice except AttributeError: - lattice = self._compute_lattice(rational_subgroup = True) + lattice = self._compute_lattice(rational_subgroup=True) self.__lattice = lattice return lattice diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index d2af5e29e00..3f4f0ffbd8f 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -461,7 +461,7 @@ def __mul__(self, right): """ lattice = self.lattice().scale(right) return FiniteSubgroup_lattice(self.abelian_variety(), lattice, - field_of_definition = self.field_of_definition()) + field_of_definition=self.field_of_definition()) def __rmul__(self, left): """ diff --git a/src/sage/modular/abvar/morphism.py b/src/sage/modular/abvar/morphism.py index d8676e7db00..bb31e19dbe0 100644 --- a/src/sage/modular/abvar/morphism.py +++ b/src/sage/modular/abvar/morphism.py @@ -546,7 +546,7 @@ def _image_of_finite_subgroup(self, G): B = G._relative_basis_matrix() * self.restrict_domain(G.abelian_variety()).matrix() * self.codomain().lattice().basis_matrix() lattice = B.row_module(ZZ) return self.codomain().finite_subgroup(lattice, - field_of_definition = G.field_of_definition()) + field_of_definition=G.field_of_definition()) def _image_of_abvar(self, A): """ diff --git a/src/sage/modular/arithgroup/arithgroup_generic.py b/src/sage/modular/arithgroup/arithgroup_generic.py index 7e07c33e551..b271e1b121f 100644 --- a/src/sage/modular/arithgroup/arithgroup_generic.py +++ b/src/sage/modular/arithgroup/arithgroup_generic.py @@ -744,7 +744,7 @@ def _find_cusps(self): so this should usually be overridden in subclasses; but it doesn't have to be. """ - i = Cusp([1,0]) + i = Cusp([1, 0]) L = [i] for a in self.coset_reps(): ai = i.apply([a.a(), a.b(), a.c(), a.d()]) @@ -757,11 +757,12 @@ def _find_cusps(self): L.append(ai) return L - def are_equivalent(self, x, y, trans = False): + def are_equivalent(self, x, y, trans=False): r""" - Test whether or not cusps x and y are equivalent modulo self. If self - has a reduce_cusp() method, use that; otherwise do a slow explicit - test. + Test whether or not cusps x and y are equivalent modulo self. + + If self has a reduce_cusp() method, use that; otherwise do a + slow explicit test. If trans = False, returns True or False. If trans = True, then return either False or an element of self mapping x onto y. diff --git a/src/sage/modular/hecke/submodule.py b/src/sage/modular/hecke/submodule.py index 572a8f73029..a6b5c96cbbc 100644 --- a/src/sage/modular/hecke/submodule.py +++ b/src/sage/modular/hecke/submodule.py @@ -27,7 +27,6 @@ from . import module - def is_HeckeSubmodule(x): r""" Return True if x is of type HeckeSubmodule. @@ -553,8 +552,8 @@ def dual_free_module(self, bound=None, anemic=True, use_star=True): # then we compute the dual on each eigenspace, then put them # together. if len(self.star_eigenvalues()) == 2: - V = self.plus_submodule(compute_dual = False).dual_free_module() + \ - self.minus_submodule(compute_dual = False).dual_free_module() + V = self.plus_submodule(compute_dual=False).dual_free_module() + \ + self.minus_submodule(compute_dual=False).dual_free_module() return V # At this point, we know that self is an eigenspace for star. diff --git a/src/sage/modular/local_comp/type_space.py b/src/sage/modular/local_comp/type_space.py index 87b3996dc04..2549e5519b0 100644 --- a/src/sage/modular/local_comp/type_space.py +++ b/src/sage/modular/local_comp/type_space.py @@ -33,7 +33,7 @@ @cached_function -def example_type_space(example_no = 0): +def example_type_space(example_no=0): r""" Quickly return an example of a type space. Used mainly to speed up doctesting. diff --git a/src/sage/modular/modform/ambient_eps.py b/src/sage/modular/modform/ambient_eps.py index 093f62daa0d..cf676af02ef 100644 --- a/src/sage/modular/modform/ambient_eps.py +++ b/src/sage/modular/modform/ambient_eps.py @@ -198,9 +198,9 @@ def change_ring(self, base_ring): """ if self.base_ring() == base_ring: return self - return ambient_R.ModularFormsAmbient_R(self, base_ring = base_ring) + return ambient_R.ModularFormsAmbient_R(self, base_ring=base_ring) - @cached_method(key=lambda self,sign: rings.Integer(sign)) # convert sign to an Integer before looking this up in the cache + @cached_method(key=lambda self, sign: rings.Integer(sign)) # convert sign to an Integer before looking this up in the cache def modular_symbols(self, sign=0): """ Return corresponding space of modular symbols with given sign. @@ -222,9 +222,9 @@ def modular_symbols(self, sign=0): """ sign = rings.Integer(sign) return modsym.ModularSymbols(self.character(), - weight = self.weight(), - sign = sign, - base_ring = self.base_ring()) + weight=self.weight(), + sign=sign, + base_ring=self.base_ring()) @cached_method def eisenstein_submodule(self): diff --git a/src/sage/modular/modform/constructor.py b/src/sage/modular/modform/constructor.py index e16b2e4f1df..dfb1dc1b53f 100644 --- a/src/sage/modular/modform/constructor.py +++ b/src/sage/modular/modform/constructor.py @@ -153,12 +153,13 @@ def ModularForms_clear_cache(): global _cache _cache = {} -def ModularForms(group = 1, - weight = 2, - base_ring = None, + +def ModularForms(group=1, + weight=2, + base_ring=None, eis_only=False, - use_cache = True, - prec = defaults.DEFAULT_PRECISION): + use_cache=True, + prec=defaults.DEFAULT_PRECISION): r""" Create an ambient space of modular forms. @@ -346,8 +347,8 @@ def ModularForms(group = 1, eps = eps.minimize_base_ring() if eps.is_trivial(): return ModularForms(eps.modulus(), weight, base_ring, - use_cache = use_cache, - prec = prec) + use_cache=use_cache, + prec=prec) M = ModularFormsAmbient_eps(eps, weight, eis_only=eis_only) if base_ring != eps.base_ring(): M = M.base_extend(base_ring) # ambient_R.ModularFormsAmbient_R(M, base_ring) @@ -360,11 +361,11 @@ def ModularForms(group = 1, return M -def CuspForms(group = 1, - weight = 2, - base_ring = None, - use_cache = True, - prec = defaults.DEFAULT_PRECISION): +def CuspForms(group=1, + weight=2, + base_ring=None, + use_cache=True, + prec=defaults.DEFAULT_PRECISION): """ Create a space of cuspidal modular forms. @@ -380,13 +381,13 @@ def CuspForms(group = 1, use_cache=use_cache, prec=prec).cuspidal_submodule() -def EisensteinForms(group = 1, - weight = 2, - base_ring = None, - use_cache = True, - prec = defaults.DEFAULT_PRECISION): +def EisensteinForms(group=1, + weight=2, + base_ring=None, + use_cache=True, + prec=defaults.DEFAULT_PRECISION): """ - Create a space of eisenstein modular forms. + Create a space of Eisenstein modular forms. See the documentation for the ModularForms command for a description of the input parameters. @@ -396,7 +397,7 @@ def EisensteinForms(group = 1, sage: EisensteinForms(11,2) Eisenstein subspace of dimension 1 of Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field """ - if weight==1: + if weight == 1: return ModularForms(group, weight, base_ring, use_cache=use_cache, eis_only=True, prec=prec).eisenstein_submodule() else: @@ -404,7 +405,6 @@ def EisensteinForms(group = 1, use_cache=use_cache, prec=prec).eisenstein_submodule() - def Newforms(group, weight=2, base_ring=None, names=None): r""" Returns a list of the newforms of the given weight and level (or weight, diff --git a/src/sage/modular/modform/cuspidal_submodule.py b/src/sage/modular/modform/cuspidal_submodule.py index d40af39c52e..e2e43a01f96 100644 --- a/src/sage/modular/modform/cuspidal_submodule.py +++ b/src/sage/modular/modform/cuspidal_submodule.py @@ -236,7 +236,7 @@ def _compute_q_expansion_basis(self, prec=None): prec = Integer(prec) if self.dimension() == 0: return [] - M = self.modular_symbols(sign = 1) + M = self.modular_symbols(sign=1) return M.q_expansion_basis(prec) def _compute_hecke_matrix_prime(self, p): diff --git a/src/sage/modular/modform/eis_series.py b/src/sage/modular/modform/eis_series.py index 65d43a39fda..88499df94c5 100644 --- a/src/sage/modular/modform/eis_series.py +++ b/src/sage/modular/modform/eis_series.py @@ -26,7 +26,7 @@ from .eis_series_cython import eisenstein_series_poly, Ek_ZZ -def eisenstein_series_qexp(k, prec = 10, K=QQ, var='q', normalization='linear'): +def eisenstein_series_qexp(k, prec=10, K=QQ, var='q', normalization='linear'): r""" Return the `q`-expansion of the normalized weight `k` Eisenstein series on `\SL_2(\ZZ)` to precision prec in the ring `K`. Three normalizations @@ -420,28 +420,29 @@ def eisenstein_series_lseries(weight, prec=53, sage: L(2) -5.0235535164599797471968418348135050804419155747868718371029 """ - f = eisenstein_series_qexp(weight,prec) + f = eisenstein_series_qexp(weight, prec) from sage.lfunctions.all import Dokchitser j = weight - L = Dokchitser(conductor = 1, - gammaV = [0,1], - weight = j, - eps = (-1)**Integer(j/2), - poles = [j], + L = Dokchitser(conductor=1, + gammaV=[0, 1], + weight=j, + eps=(-1)**Integer(j // 2), + poles=[j], # Using a string for residues is a hack but it works well # since this will make PARI/GP compute sqrt(pi) with the # right precision. - residues = '[sqrt(Pi)*(%s)]'%((-1)**Integer(j/2)*bernoulli(j)/j), - prec = prec) + residues='[sqrt(Pi)*(%s)]'%((-1)**Integer(j/2)*bernoulli(j)/j), + prec=prec) s = 'coeff = %s;'%f.list() - L.init_coeffs('coeff[k+1]',pari_precode = s, + L.init_coeffs('coeff[k+1]',pari_precode=s, max_imaginary_part=max_imaginary_part, max_asymp_coeffs=max_asymp_coeffs) L.check_functional_equation() L.rename('L-series associated to the weight %s Eisenstein series %s on SL_2(Z)'%(j,f)) return L + def compute_eisenstein_params(character, k): r""" Compute and return a list of all parameters `(\chi,\psi,t)` that diff --git a/src/sage/modular/modform/hecke_operator_on_qexp.py b/src/sage/modular/modform/hecke_operator_on_qexp.py index 6a61cbb46f2..89de388f27f 100644 --- a/src/sage/modular/modform/hecke_operator_on_qexp.py +++ b/src/sage/modular/modform/hecke_operator_on_qexp.py @@ -1,16 +1,15 @@ """ Hecke Operators on `q`-expansions """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004-2006 William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.arith.misc import divisors, gcd from sage.matrix.constructor import matrix @@ -24,7 +23,7 @@ from sage.modular.dirichlet import DirichletGroup, is_DirichletCharacter from .element import is_ModularFormElement -def hecke_operator_on_qexp(f, n, k, eps = None, +def hecke_operator_on_qexp(f, n, k, eps=None, prec=None, check=True, _return_list=False): r""" Given the `q`-expansion `f` of a modular form with character @@ -149,8 +148,8 @@ def _hecke_operator_on_basis(B, V, n, k, eps): TB = [V.coordinate_vector(w) for w in TB] return matrix(V.base_ring(), len(B), len(B), TB, sparse=False) -def hecke_operator_on_basis(B, n, k, eps=None, - already_echelonized = False): + +def hecke_operator_on_basis(B, n, k, eps=None, already_echelonized=False): r""" Given a basis `B` of `q`-expansions for a space of modular forms with character `\varepsilon` to precision at least `\#B\cdot n+1`, @@ -232,8 +231,8 @@ def hecke_operator_on_basis(B, n, k, eps=None, raise TypeError("each element of B must be a power series") n = Integer(n) k = Integer(k) - prec = (f.prec()-1)//n + prec = (f.prec() - 1) // n A = R**prec V = A.span_of_basis([g.padded_list(prec) for g in B], - already_echelonized = already_echelonized) + already_echelonized=already_echelonized) return _hecke_operator_on_basis(B, V, n, k, eps) diff --git a/src/sage/modular/modform/space.py b/src/sage/modular/modform/space.py index 5dfd3f568d8..69206f0e023 100644 --- a/src/sage/modular/modform/space.py +++ b/src/sage/modular/modform/space.py @@ -1309,7 +1309,7 @@ def _compute_hecke_matrix_prime(self, p, prec=None): self.weight(), eps, already_echelonized=False) except ValueError: # Double the precision. - return self._compute_hecke_matrix_prime(p, prec = 2*prec+1) + return self._compute_hecke_matrix_prime(p, prec=2 * prec + 1) def _compute_hecke_matrix(self, n): """ diff --git a/src/sage/modular/modform/submodule.py b/src/sage/modular/modform/submodule.py index b1da8a92105..49b6c12b493 100644 --- a/src/sage/modular/modform/submodule.py +++ b/src/sage/modular/modform/submodule.py @@ -104,7 +104,8 @@ def _compute_q_expansion_basis(self, prec): O(q^5)] """ A = self.ambient_module() - return [A._q_expansion(element = f.element(), prec=prec) for f in self.basis()] + return [A._q_expansion(element=f.element(), prec=prec) + for f in self.basis()] # TODO diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index c1fc60f724c..fdd7e38b552 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -834,7 +834,7 @@ def emb_key(emb): return L if len(L) > 1: - L.sort(key = emb_key) + L.sort(key=emb_key) return L[-1] def _elliptic_conj_reps(self): diff --git a/src/sage/modular/modform_hecketriangle/series_constructor.py b/src/sage/modular/modform_hecketriangle/series_constructor.py index 3b698833b2b..881270c5bfa 100644 --- a/src/sage/modular/modform_hecketriangle/series_constructor.py +++ b/src/sage/modular/modform_hecketriangle/series_constructor.py @@ -33,8 +33,7 @@ from .hecke_triangle_groups import HeckeTriangleGroup - -class MFSeriesConstructor(SageObject,UniqueRepresentation): +class MFSeriesConstructor(SageObject, UniqueRepresentation): r""" Constructor for the Fourier expansion of some (specific, basic) modular forms. @@ -44,7 +43,7 @@ class MFSeriesConstructor(SageObject,UniqueRepresentation): """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), prec=ZZ(10)): + def __classcall__(cls, group=HeckeTriangleGroup(3), prec=ZZ(10)): r""" Return a (cached) instance with canonical parameters. diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index 6408405d520..4f9b23bfc28 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -3014,7 +3014,7 @@ def _compute_hecke_matrix_prime(self, p, rows=None): P1 = self.p1list() mod2term = self._mod2term R = self.manin_gens_to_basis() - W = R.new_matrix(nrows=len(B), ncols = R.nrows()) # the 0 with given number of rows and cols. + W = R.new_matrix(nrows=len(B), ncols=R.nrows()) # the 0 with given number of rows and cols. j = 0 tm = verbose("Matrix non-reduced", tm) for i in B: @@ -3588,11 +3588,11 @@ def __init__(self, eps, weight, sign, base_ring, custom_init=None, category=None """ level = eps.modulus() ModularSymbolsAmbient.__init__(self, - weight = weight, - group = arithgroup.Gamma1(level), - sign = sign, - base_ring = base_ring, - character = eps.change_ring(base_ring), + weight=weight, + group=arithgroup.Gamma1(level), + sign=sign, + base_ring=base_ring, + character=eps.change_ring(base_ring), custom_init=custom_init, category=category) diff --git a/src/sage/modular/modsym/boundary.py b/src/sage/modular/modsym/boundary.py index f8550d0f05f..fa24249edc8 100644 --- a/src/sage/modular/modsym/boundary.py +++ b/src/sage/modular/modsym/boundary.py @@ -274,17 +274,17 @@ def __neg__(self): sage: -x + x # indirect doctest 0 """ - return self*(-1) + return self * (-1) @richcmp_method class BoundarySpace(hecke.HeckeModule_generic): def __init__(self, - group = arithgroup.Gamma0(1), - weight = 2, - sign = 0, - base_ring = rings.QQ, - character = None): + group=arithgroup.Gamma0(1), + weight=2, + sign=0, + base_ring=rings.QQ, + character=None): """ Space of boundary symbols for a congruence subgroup of SL_2(Z). diff --git a/src/sage/modular/modsym/modsym.py b/src/sage/modular/modsym/modsym.py index a30f53a8a9e..0a87eece1d7 100644 --- a/src/sage/modular/modsym/modsym.py +++ b/src/sage/modular/modsym/modsym.py @@ -180,11 +180,11 @@ def ModularSymbols_clear_cache(): _cache = {} -def ModularSymbols(group = 1, - weight = 2, - sign = 0, - base_ring = None, - use_cache = True, +def ModularSymbols(group=1, + weight=2, + sign=0, + base_ring=None, + use_cache=True, custom_init=None): r""" Create an ambient space of modular symbols. diff --git a/src/sage/modular/modsym/subspace.py b/src/sage/modular/modsym/subspace.py index e27467a3816..c1f70471c0f 100644 --- a/src/sage/modular/modsym/subspace.py +++ b/src/sage/modular/modsym/subspace.py @@ -72,9 +72,10 @@ def __init__(self, ambient_hecke_module, submodule, """ self.__ambient_hecke_module = ambient_hecke_module A = ambient_hecke_module - sage.modular.modsym.space.ModularSymbolsSpace.__init__(self, A.group(), A.weight(), \ - A.character(), A.sign(), A.base_ring()) - hecke.HeckeSubmodule.__init__(self, A, submodule, dual_free_module = dual_free_module, check=check) + sage.modular.modsym.space.ModularSymbolsSpace.__init__(self, A.group(), + A.weight(), + A.character(), A.sign(), A.base_ring()) + hecke.HeckeSubmodule.__init__(self, A, submodule, dual_free_module=dual_free_module, check=check) def _repr_(self): """ diff --git a/src/sage/modular/overconvergent/genus0.py b/src/sage/modular/overconvergent/genus0.py index 0e30f40d23b..8f903f76b7c 100644 --- a/src/sage/modular/overconvergent/genus0.py +++ b/src/sage/modular/overconvergent/genus0.py @@ -202,11 +202,12 @@ __ocmfdict = {} + #################### # Factory function # #################### -def OverconvergentModularForms(prime, weight, radius, base_ring=QQ, prec = 20, char = None): +def OverconvergentModularForms(prime, weight, radius, base_ring=QQ, prec=20, char=None): r""" Create a space of overconvergent `p`-adic modular forms of level `\Gamma_0(p)`, over the given base ring. The base ring need not be a @@ -316,7 +317,7 @@ def __init__(self, prime, weight, radius, base_ring, prec, char): if isinstance(weight, WeightCharacter): self._wtchar = weight else: - self._wtchar = WeightSpace(prime, base_ring = char.base_ring())(weight, char, algebraic=True) + self._wtchar = WeightSpace(prime, base_ring=char.base_ring())(weight, char, algebraic=True) if not self._wtchar.is_even(): raise ValueError("Weight-character must be even") @@ -951,7 +952,7 @@ def _convert_to_basis(self, qexp): x = x - self._basis_cache[i] * answer[i] return answer + O(g**n) - def hecke_matrix(self, m, n, use_recurrence = False, exact_arith = False): + def hecke_matrix(self, m, n, use_recurrence=False, exact_arith=False): r""" Calculate the matrix of the `T_m` operator in the basis of this space, truncated to an `n \times n` matrix. Conventions are that operators act @@ -1052,12 +1053,14 @@ def slopes(self, n, use_recurrence=False): print("slopes are only defined for base field QQ or a p-adic field") return [-i for i in slopelist] - def eigenfunctions(self, n, F = None, exact_arith=True): + def eigenfunctions(self, n, F=None, exact_arith=True): """ - Calculate approximations to eigenfunctions of self. These are the - eigenfunctions of self.hecke_matrix(p, n), which are approximations to - the true eigenfunctions. Returns a list of - OverconvergentModularFormElement objects, in increasing order of slope. + Calculate approximations to eigenfunctions of self. + + These are the eigenfunctions of self.hecke_matrix(p, n), which + are approximations to the true eigenfunctions. Returns a list + of OverconvergentModularFormElement objects, in increasing + order of slope. INPUT: @@ -1201,7 +1204,7 @@ def recurrence_matrix(self, use_smithline=True): return self._cached_recurrence_matrix MM = OverconvergentModularForms(self.prime(), 0, 0, base_ring=QQ) - m = MM._discover_recurrence_matrix(use_smithline = True).base_extend(self.base_ring()) + m = MM._discover_recurrence_matrix(use_smithline=True).base_extend(self.base_ring()) r = diagonal_matrix([self._const**i for i in range(self.prime())]) self._cached_recurrence_matrix = (r**(-1)) * m * r @@ -1339,7 +1342,7 @@ def _add_(self, other): sage: f + f # indirect doctest 2-adic overconvergent modular form of weight-character 12 with q-expansion 2 - 131040/1414477*q ... """ - return OverconvergentModularFormElement(self.parent(), gexp = self.gexp() + other.gexp()) + return OverconvergentModularFormElement(self.parent(), gexp=self.gexp() + other.gexp()) def _lmul_(self, x): r""" @@ -1353,7 +1356,7 @@ def _lmul_(self, x): 2-adic overconvergent modular form of weight-character 12 with q-expansion 2 - 131040/1414477*q ... """ - return OverconvergentModularFormElement(self.parent(), gexp = x * self.gexp()) + return OverconvergentModularFormElement(self.parent(), gexp=x * self.gexp()) def _rmul_(self, x): r""" @@ -1367,7 +1370,7 @@ def _rmul_(self, x): 2-adic overconvergent modular form of weight-character 12 with q-expansion 3 - 196560/1414477*q ... """ - return OverconvergentModularFormElement(self.parent(), gexp = x * self.gexp()) + return OverconvergentModularFormElement(self.parent(), gexp=x * self.gexp()) def prec(self): r""" @@ -1636,7 +1639,7 @@ def governing_term(self, r): return i raise RuntimeError("Can't get here") - def valuation_plot(self, rmax = None): + def valuation_plot(self, rmax=None): r""" Draw a graph depicting the growth of the norm of this overconvergent modular form as it approaches the boundary of the overconvergent @@ -1650,8 +1653,8 @@ def valuation_plot(self, rmax = None): Graphics object consisting of 1 graphics primitive """ if rmax is None: - rmax = ZZ(self.prime())/ZZ(1 + self.prime()) - return plot(self.r_ord, (0, rmax) ) + rmax = ZZ(self.prime()) / ZZ(1 + self.prime()) + return plot(self.r_ord, (0, rmax)) def weight(self): r""" diff --git a/src/sage/modular/pollack_stevens/manin_map.py b/src/sage/modular/pollack_stevens/manin_map.py index 74de1b039f3..70465dade8f 100644 --- a/src/sage/modular/pollack_stevens/manin_map.py +++ b/src/sage/modular/pollack_stevens/manin_map.py @@ -762,7 +762,7 @@ def specialize(self, *args): return self.__class__(self._codomain.specialize(*args), self._manin, D, check=False) - def hecke(self, ell, algorithm = 'prep'): + def hecke(self, ell, algorithm='prep'): r""" Return the image of this Manin map under the Hecke operator `T_{\ell}`. diff --git a/src/sage/modular/pollack_stevens/space.py b/src/sage/modular/pollack_stevens/space.py index 8bb41867770..99bff5e6890 100644 --- a/src/sage/modular/pollack_stevens/space.py +++ b/src/sage/modular/pollack_stevens/space.py @@ -851,7 +851,7 @@ def cusps_from_mat(g): return ac, bd -def ps_modsym_from_elliptic_curve(E, sign = 0, implementation='eclib'): +def ps_modsym_from_elliptic_curve(E, sign=0, implementation='eclib'): r""" Return the overconvergent modular symbol associated to an elliptic curve defined over the rationals. From 18478cae2dc614a1e53890b6dbaee7431f107a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 26 Sep 2022 09:06:25 +0200 Subject: [PATCH 732/742] fix E251 in Clifford too --- src/sage/algebras/clifford_algebra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 8fc5d750dd6..58d045db307 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -666,7 +666,7 @@ def _basis_index_function(self, x): # if the input is a tuple, assume that it has # entries in {0, ..., 2**Q.dim()-1} if isinstance(x, tuple): - return FrozenBitset(x, capacity = Q.dim()) + return FrozenBitset(x, capacity=Q.dim()) # slice the output of format in order to make conventions # of format and FrozenBitset agree. From c6a47f24d4faa5dbb6cdf25419a1419afb5a32bd Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 26 Sep 2022 18:02:35 +0900 Subject: [PATCH 733/742] Minor edits in INPUT block --- src/sage/arith/misc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 7194bdf6e35..a8ff6b7355d 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -479,7 +479,7 @@ def is_prime(n): INPUT: - - ``n`` - the object for which to determine primality + - ``n`` -- the object for which to determine primality Exceptional special cases: From e10f9cf17bd06784805914b63b7ae0adc4423c96 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 26 Sep 2022 10:18:43 -0700 Subject: [PATCH 734/742] src/sage/manifolds/differentiable/vectorfield_module.py: Revert change to VectorFieldModule.tensor (not needed yet) --- src/sage/manifolds/differentiable/vectorfield_module.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 67e3a40efd1..580eec814ab 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -731,7 +731,7 @@ def general_linear_group(self): self._general_linear_group = AutomorphismFieldGroup(self) return self._general_linear_group - def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, + def tensor(self, tensor_type, name=None, latex_name=None, sym=None, antisym=None, specific_type=None): r""" Construct a tensor on ``self``. @@ -824,8 +824,6 @@ def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, self, tensor_type, name=name, latex_name=latex_name, sym=sym, antisym=antisym) - tensor = FiniteRankFreeModule.tensor - def alternating_contravariant_tensor(self, degree, name=None, latex_name=None): r""" From 9ce8f81a254707d3c5504fef58b329e4ec153f2f Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Tue, 27 Sep 2022 16:02:40 +0800 Subject: [PATCH 735/742] 21129: Correct nosie mult bug --- .../arithmetic_dynamics/projective_ds.py | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 4568cca18e3..f47d5d36249 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1230,9 +1230,9 @@ def arakelov_zhang_pairing(self, g, **kwds): sage: # If all archimedean absolute values of a have modulus > 2, sage: # then the pairing should be h(a). sage: f.arakelov_zhang_pairing(g, n=6) - 3.46979800225000 + 1.93846423207664 sage: _ - a.global_height() - 1.52388785319469 + -0.00744591697867292 """ n = kwds.pop('n', 5) f_starting_point = kwds.pop('f_starting_point', None) @@ -1333,12 +1333,13 @@ def arakelov_zhang_pairing(self, g, **kwds): temp = (ZZ(1)/2) * (-f_disc.ord(p)) * Real(p).log() / (f_deg**2) if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp - AZ_pairing -= (-res.ord(p)) * Real(p).log() / (f_deg * g_deg) temp = (ZZ(1)/2) * (-g_disc.ord(p)) * Real(p).log() / (g_deg**2) if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): AZ_pairing += temp + AZ_pairing -= (-res.ord(p)) * Real(p).log() / (f_deg * g_deg) + temp = (ZZ(1)/2) * (Real(f_disc).abs().log()) / (f_deg**2) if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp @@ -1356,11 +1357,16 @@ def arakelov_zhang_pairing(self, g, **kwds): for v in bad_primes: Nv = v.absolute_ramification_index() * v.residue_class_degree() / d - if abs(Nv) > noise_multiplier * Real(f_deg).log() / Real(f_deg): - AZ_pairing += Nv - AZ_pairing += Nv * ((ZZ(1)/2) * K(f_disc).abs_non_arch(v, prec=prec).log() / (f_deg**2) - + (ZZ(1)/2) * K(g_disc).abs_non_arch(v, prec=prec).log() / (g_deg**2)) - - K(res).abs_non_arch(v, prec=prec).log() / (f_deg * g_deg) + + temp = Nv * ((ZZ(1)/2) * K(f_disc).abs_non_arch(v, prec=prec).log() / (f_deg**2)) + if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): + AZ_pairing += temp + + temp = Nv * ((ZZ(1)/2) * K(g_disc).abs_non_arch(v, prec=prec).log() / (g_deg**2)) + if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): + AZ_pairing += temp + + AZ_pairing -= Nv * (K(res).abs_non_arch(v, prec=prec).log() / (f_deg * g_deg)) if f_disc.is_rational(): f_disc = QQ(f_disc) From 8266146638d0a3596b89896132e7436d1b49581f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 27 Sep 2022 17:05:09 +0200 Subject: [PATCH 736/742] fix W605 in libs/ and rings/semirings/ --- src/sage/libs/eclib/mwrank.pyx | 37 +++++++++---------- src/sage/libs/eclib/newforms.pyx | 2 +- src/sage/libs/ntl/ntl_GF2E.pyx | 17 +++++---- src/sage/libs/ntl/ntl_ZZX.pyx | 27 ++++++++------ src/sage/libs/ntl/ntl_ZZ_pEX.pyx | 11 +++--- src/sage/libs/ntl/ntl_mat_GF2.pyx | 31 +++++++++------- src/sage/libs/ntl/ntl_mat_GF2E.pyx | 17 +++++---- src/sage/libs/ntl/ntl_mat_ZZ.pyx | 4 +- src/sage/libs/singular/polynomial.pyx | 9 ++--- .../rings/semirings/tropical_semiring.pyx | 8 ++-- 10 files changed, 86 insertions(+), 77 deletions(-) diff --git a/src/sage/libs/eclib/mwrank.pyx b/src/sage/libs/eclib/mwrank.pyx index 7df61a54f12..f17abe62e69 100644 --- a/src/sage/libs/eclib/mwrank.pyx +++ b/src/sage/libs/eclib/mwrank.pyx @@ -335,7 +335,7 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class return string_sigoff(Curvedata_repr(self.x))[:-1] def silverman_bound(self): - """ + r""" The Silverman height bound for this elliptic curve. OUTPUT: @@ -364,7 +364,7 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class return Curvedata_silverman_bound(self.x) def cps_bound(self): - """ + r""" The Cremona-Prickett-Siksek height bound for this elliptic curve. OUTPUT: @@ -376,10 +376,9 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class .. note:: - Since eclib can compute this to arbitrary precision, we + Since ``eclib`` can compute this to arbitrary precision, we could return a Sage real, but this is only a bound and in - the contexts in which it is used extra precision is - irrelevant. + the contexts in which it is used extra precision is irrelevant. EXAMPLES:: @@ -399,7 +398,7 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class return x def height_constant(self): - """ + r""" A height bound for this elliptic curve. OUTPUT: @@ -412,10 +411,9 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class .. note:: - Since eclib can compute this to arbitrary precision, we + Since ``eclib`` can compute this to arbitrary precision, we could return a Sage real, but this is only a bound and in - the contexts in which it is used extra precision is - irrelevant. + the contexts in which it is used extra precision is irrelevant. EXAMPLES:: @@ -542,7 +540,7 @@ cdef class _mw: cdef int verb def __init__(self, _Curvedata curve, verb=False, pp=1, maxr=999): - """ + r""" Constructor for mw class. INPUT: @@ -908,7 +906,7 @@ cdef class _mw: return ok, index, unsat def search(self, h_lim, int moduli_option=0, int verb=0): - """ + r""" Search for points in the mw group. INPUT: @@ -926,17 +924,16 @@ cdef class _mw: .. NOTE:: - The effect of the search is also governed by the class - options, notably whether the points found are processed: - meaning that linear relations are found and saturation is - carried out, with the result that the list of generators - will always contain a `\ZZ`-span of the saturation of the - points found, modulo torsion. + The effect of the search is also governed by the class + options, notably whether the points found are processed: + meaning that linear relations are found and saturation is + carried out, with the result that the list of generators + will always contain a `\ZZ`-span of the saturation of the + points found, modulo torsion. OUTPUT: - None. The effect of the search is to update the list of - generators. + None. The effect of the search is to update the list of generators. EXAMPLES:: @@ -1273,7 +1270,7 @@ cdef class _two_descent: sig_off() def getbasis(self): - """ + r""" Returns the basis of points found by doing a 2-descent. If the success and certain flags are 1, this will be a diff --git a/src/sage/libs/eclib/newforms.pyx b/src/sage/libs/eclib/newforms.pyx index d30ac0e3758..2d35716c4db 100644 --- a/src/sage/libs/eclib/newforms.pyx +++ b/src/sage/libs/eclib/newforms.pyx @@ -22,7 +22,7 @@ from sage.modular.all import Cusp cdef class ECModularSymbol: - """ + r""" Modular symbol associated with an elliptic curve, using John Cremona's newforms class. EXAMPLES:: diff --git a/src/sage/libs/ntl/ntl_GF2E.pyx b/src/sage/libs/ntl/ntl_GF2E.pyx index bc6a32ce0d3..b944dddf2d9 100644 --- a/src/sage/libs/ntl/ntl_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_GF2E.pyx @@ -439,17 +439,20 @@ cdef class ntl_GF2E(): return l def _sage_(ntl_GF2E self, k=None): - """ - Returns a \class{FiniteFieldElement} representation - of this element. If a \class{FiniteField} k is provided - it is constructed in this field if possible. A \class{FiniteField} - will be constructed if none is provided. + r""" + Returns a \class{FiniteFieldElement} representation of this element. + + If a \class{FiniteField} k is provided it is constructed in + this field if possible. A \class{FiniteField} will be + constructed if none is provided. INPUT: - k -- optional GF(2**deg) + + k -- optional GF(2**deg) OUTPUT: - FiniteFieldElement over k + + FiniteFieldElement over k EXAMPLES:: diff --git a/src/sage/libs/ntl/ntl_ZZX.pyx b/src/sage/libs/ntl/ntl_ZZX.pyx index 8d38fcb7f8f..bf51373e9eb 100644 --- a/src/sage/libs/ntl/ntl_ZZX.pyx +++ b/src/sage/libs/ntl/ntl_ZZX.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -17,8 +17,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off @@ -692,12 +692,14 @@ cdef class ntl_ZZX(): return (self*other).quo_rem(g)[0] def xgcd(self, ntl_ZZX other, proof=None): - """ - If self and other are coprime over the rationals, return r, s, - t such that r = s*self + t*other. Otherwise return 0. This - is \emph{not} the same as the \sage function on polynomials - over the integers, since here the return value r is always an - integer. + r""" + If ``self`` and ``other`` are coprime over the rationals, + return ``r, s, t`` such that ``r = s*self + t*other``. + Otherwise return 0. + + This is \emph{not} the same as the \sage function on + polynomials over the integers, since here the return value r + is always an integer. Here r is the resultant of a and b; if r != 0, then this function computes s and t such that: a*s + b*t = r; otherwise @@ -709,7 +711,6 @@ cdef class ntl_ZZX(): randomized strategy that errors with probability no more than `2^{-80}`. - EXAMPLES:: sage: f = ntl.ZZX([1,2,3]) * ntl.ZZX([4,5])**2 @@ -717,7 +718,8 @@ cdef class ntl_ZZX(): sage: f.xgcd(g) # nothing since they are not coprime (0, [], []) - In this example the input quadratic polynomials have a common root modulo 13. + In this example the input quadratic polynomials have a common root modulo 13:: + sage: f = ntl.ZZX([5,0,1]) sage: g = ntl.ZZX([18,0,1]) sage: f.xgcd(g) @@ -805,7 +807,8 @@ cdef class ntl_ZZX(): sage: f == g True - Though f and g are equal, they are not the same objects in memory: + Though f and g are equal, they are not the same objects in memory:: + sage: f is g False """ diff --git a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx index f9d2e982343..d5f10218a77 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx @@ -5,14 +5,15 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -""" +r""" Wrapper for NTL's polynomials over finite ring extensions of `\Z / p\Z.` AUTHORS: - -- David Roe (2007-10-10) + +- David Roe (2007-10-10) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 William Stein # David Roe # @@ -25,8 +26,8 @@ AUTHORS: # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off from sage.ext.cplusplus cimport ccrepr diff --git a/src/sage/libs/ntl/ntl_mat_GF2.pyx b/src/sage/libs/ntl/ntl_mat_GF2.pyx index 833b7b9ea8e..ee90bf17fce 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -""" +r""" Matrices over the `\GF{2}` via NTL This class is only provided to have a complete NTL interface and for @@ -13,11 +13,11 @@ comparison purposes. Sage's native matrices over `F_2` are much faster for many problems like matrix multiplication and Gaussian elimination. AUTHORS: - - Martin Albrecht - 2008-09: initial version + +- Martin Albrecht 2008-09: initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # Copyright (C) 2008 Martin Albrecht # @@ -30,8 +30,8 @@ AUTHORS: # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off from sage.ext.cplusplus cimport ccrepr @@ -131,6 +131,8 @@ cdef class ntl_mat_GF2(): def __reduce__(self): """ + EXAMPLES:: + sage: A = random_matrix(GF(2),4,4) sage: B = ntl.mat_GF2(A) sage: loads(dumps(B)) == B # indirect doctest @@ -375,17 +377,18 @@ cdef class ntl_mat_GF2(): sig_off() return r - def gauss(self,ncols=-1): - """ - Performs unitary row operations so as to bring this matrix - into row echelon form (not reduced!). If the optional - argument \code{ncols} is supplied, stops when first ncols - columns are in echelon form. The return value is the rank (or - the rank of the first ncols columns). + def gauss(self, ncols=-1): + r""" + Perform unitary row operations so as to bring this matrix + into row echelon form (not reduced!). + + If the optional argument ``ncols`` is supplied, stops when + first ``ncols`` columns are in echelon form. The return value is + the rank (or the rank of the first ``ncols`` columns). INPUT: - ncols -- number of columns to process (default: all) + - ``ncols`` -- number of columns to process (default: all) EXAMPLES:: diff --git a/src/sage/libs/ntl/ntl_mat_GF2E.pyx b/src/sage/libs/ntl/ntl_mat_GF2E.pyx index e18d150cbda..574ff43c213 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2E.pyx @@ -445,17 +445,18 @@ cdef class ntl_mat_GF2E(): sig_off() return r - def gauss(self,ncols=-1): - """ - Performs unitary row operations so as to bring this matrix - into row echelon form. If the optional argument \code{ncols} - is supplied, stops when first ncols columns are in echelon - form. The return value is the rank (or the rank of the first - ncols columns). + def gauss(self, ncols=-1): + r""" + Perform unitary row operations so as to bring this matrix + into row echelon form. + + If the optional argument ``ncols`` is supplied, stops when + first ``ncols`` columns are in echelon form. The return value + is the rank (or the rank of the first ``ncols`` columns). INPUT: - - ``ncols`` - number of columns to process (default: all) + - ``ncols`` -- number of columns to process (default: all) EXAMPLES:: diff --git a/src/sage/libs/ntl/ntl_mat_ZZ.pyx b/src/sage/libs/ntl/ntl_mat_ZZ.pyx index dac2ca79636..fb1769db352 100644 --- a/src/sage/libs/ntl/ntl_mat_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_mat_ZZ.pyx @@ -73,7 +73,7 @@ cdef class ntl_mat_ZZ(): The \class{mat_ZZ} class implements arithmetic with matrices over `\Z`. """ def __init__(self, nrows=0, ncols=0, v=None): - """ + r""" The \class{mat_ZZ} class implements arithmetic with matrices over `\Z`. EXAMPLES:: @@ -319,6 +319,8 @@ cdef class ntl_mat_ZZ(): def __getitem__(self, ij): """ + EXAMPLES:: + sage: m = ntl.mat_ZZ(3, 2, range(6)) sage: m[0,0] ## indirect doctest 0 diff --git a/src/sage/libs/singular/polynomial.pyx b/src/sage/libs/singular/polynomial.pyx index e012da4573c..b2efc7dfbcb 100644 --- a/src/sage/libs/singular/polynomial.pyx +++ b/src/sage/libs/singular/polynomial.pyx @@ -5,16 +5,15 @@ AUTHOR: - Martin Albrecht (2009-07): refactoring """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Martin Albrecht # # 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 cysignals.signals cimport sig_on, sig_off @@ -22,7 +21,7 @@ cdef extern from *: # hack to get at cython macro int unlikely(int) import re -plusminus_pattern = re.compile("([^\(^])([\+\-])") +plusminus_pattern = re.compile(r"([^\(^])([\+\-])") parenthvar_pattern = re.compile(r"\(([a-zA-Z][a-zA-Z0-9]*)\)") from sage.cpython.string cimport bytes_to_str, str_to_bytes diff --git a/src/sage/rings/semirings/tropical_semiring.pyx b/src/sage/rings/semirings/tropical_semiring.pyx index 5ae1ea93bf7..17e25091f39 100644 --- a/src/sage/rings/semirings/tropical_semiring.pyx +++ b/src/sage/rings/semirings/tropical_semiring.pyx @@ -99,7 +99,7 @@ cdef class TropicalSemiringElement(Element): return repr(self._val) def _latex_(self): - """ + r""" Return a latex representation of ``self``. EXAMPLES:: @@ -135,7 +135,7 @@ cdef class TropicalSemiringElement(Element): # Comparisons cpdef _richcmp_(left, right, int op): - """ + r""" Return the standard comparison of ``left`` and ``right``. EXAMPLES:: @@ -259,7 +259,7 @@ cdef class TropicalSemiringElement(Element): return x def __neg__(self): - """ + r""" Return the additive inverse, which only exists for `\infty`. EXAMPLES:: @@ -610,7 +610,7 @@ class TropicalSemiring(Parent, UniqueRepresentation): @cached_method def zero(self): - """ + r""" Return the (tropical) additive identity element `+\infty`. EXAMPLES:: From 307698f9426a6130b1af23c53e69baf8eb8a20c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 27 Sep 2022 17:50:12 +0200 Subject: [PATCH 737/742] more cleanup in libs/ --- src/sage/libs/ntl/ntl_GF2.pyx | 12 +++++++ src/sage/libs/ntl/ntl_GF2E.pyx | 2 ++ src/sage/libs/ntl/ntl_ZZ.pyx | 49 +++++++++++++++++--------- src/sage/libs/ntl/ntl_ZZX.pyx | 12 ++++--- src/sage/libs/ntl/ntl_ZZ_p.pyx | 8 +++-- src/sage/libs/ntl/ntl_ZZ_pE.pyx | 8 +++-- src/sage/libs/ntl/ntl_ZZ_pEContext.pyx | 14 +++++--- src/sage/libs/ntl/ntl_ZZ_pX.pyx | 12 ++++--- src/sage/libs/ntl/ntl_lzz_pContext.pyx | 8 +++-- 9 files changed, 86 insertions(+), 39 deletions(-) diff --git a/src/sage/libs/ntl/ntl_GF2.pyx b/src/sage/libs/ntl/ntl_GF2.pyx index c88034ff5c4..8af0d6caf9a 100644 --- a/src/sage/libs/ntl/ntl_GF2.pyx +++ b/src/sage/libs/ntl/ntl_GF2.pyx @@ -116,6 +116,8 @@ cdef class ntl_GF2(): def __mul__(self, other): """ + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: o*o @@ -137,6 +139,8 @@ cdef class ntl_GF2(): def __truediv__(self, other): """ + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: o/o @@ -159,6 +163,8 @@ cdef class ntl_GF2(): def __sub__(self, other): """ + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: o-o @@ -180,6 +186,8 @@ cdef class ntl_GF2(): def __add__(self, other): """ + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: o+o @@ -201,6 +209,8 @@ cdef class ntl_GF2(): def __neg__(ntl_GF2 self): """ + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: -z @@ -214,6 +224,8 @@ cdef class ntl_GF2(): def __pow__(ntl_GF2 self, long e, ignored): """ + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: z^2 diff --git a/src/sage/libs/ntl/ntl_GF2E.pyx b/src/sage/libs/ntl/ntl_GF2E.pyx index b944dddf2d9..2744de98c01 100644 --- a/src/sage/libs/ntl/ntl_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_GF2E.pyx @@ -164,6 +164,8 @@ cdef class ntl_GF2E(): def __reduce__(self): """ + EXAMPLES:: + sage: ctx = ntl.GF2EContext( ntl.GF2X([1,1,0,1,1,0,0,0,1]) ) sage: a = ntl.GF2E(ntl.ZZ_pX([1,1,3],2), ctx) sage: loads(dumps(a)) == a diff --git a/src/sage/libs/ntl/ntl_ZZ.pyx b/src/sage/libs/ntl/ntl_ZZ.pyx index 39a98da2101..6f9d15f780e 100644 --- a/src/sage/libs/ntl/ntl_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_ZZ.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -17,8 +17,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off from sage.ext.cplusplus cimport ccrepr, ccreadstr @@ -176,6 +176,8 @@ cdef class ntl_ZZ(): def __mul__(self, other): """ + EXAMPLES:: + sage: n=ntl.ZZ(2983)*ntl.ZZ(2) sage: n 5966 @@ -192,6 +194,8 @@ cdef class ntl_ZZ(): def __sub__(self, other): """ + EXAMPLES:: + sage: n=ntl.ZZ(2983)-ntl.ZZ(2) sage: n 2981 @@ -208,6 +212,8 @@ cdef class ntl_ZZ(): def __add__(self, other): """ + EXAMPLES:: + sage: n=ntl.ZZ(2983)+ntl.ZZ(2) sage: n 2985 @@ -224,6 +230,8 @@ cdef class ntl_ZZ(): def __neg__(ntl_ZZ self): """ + EXAMPLES:: + sage: x = ntl.ZZ(38) sage: -x -38 @@ -236,6 +244,8 @@ cdef class ntl_ZZ(): def __pow__(ntl_ZZ self, long e, ignored): """ + EXAMPLES:: + sage: ntl.ZZ(23)^50 122008981252869411022491112993141891091036959856659100591281395343249 """ @@ -266,6 +276,7 @@ cdef class ntl_ZZ(): cdef int get_as_int(ntl_ZZ self): r""" Returns value as C int. + Return value is only valid if the result fits into an int. AUTHOR: David Harvey (2006-08-05) @@ -278,12 +289,14 @@ cdef class ntl_ZZ(): r""" This method exists solely for automated testing of get_as_int(). - sage: x = ntl.ZZ(42) - sage: i = x.get_as_int_doctest() - sage: i - 42 - sage: type(i) - <... 'int'> + EXAMPLES:: + + sage: x = ntl.ZZ(42) + sage: i = x.get_as_int_doctest() + sage: i + 42 + sage: type(i) + <... 'int'> """ return self.get_as_int() @@ -291,9 +304,11 @@ cdef class ntl_ZZ(): r""" Gets the value as a sage int. - sage: n=ntl.ZZ(2983) - sage: type(n._integer_()) - + EXAMPLES:: + + sage: n=ntl.ZZ(2983) + sage: type(n._integer_()) + AUTHOR: Joel B. Mohler """ @@ -332,10 +347,12 @@ cdef class ntl_ZZ(): r""" This method exists solely for automated testing of set_from_int(). - sage: x = ntl.ZZ() - sage: x.set_from_int_doctest(42) - sage: x - 42 + EXAMPLES:: + + sage: x = ntl.ZZ() + sage: x.set_from_int_doctest(42) + sage: x + 42 """ self.set_from_int(int(value)) diff --git a/src/sage/libs/ntl/ntl_ZZX.pyx b/src/sage/libs/ntl/ntl_ZZX.pyx index bf51373e9eb..e369f7152e4 100644 --- a/src/sage/libs/ntl/ntl_ZZX.pyx +++ b/src/sage/libs/ntl/ntl_ZZX.pyx @@ -144,10 +144,12 @@ cdef class ntl_ZZX(): def __reduce__(self): """ - sage: from sage.libs.ntl.ntl_ZZX import ntl_ZZX - sage: f = ntl_ZZX([1,2,0,4]) - sage: loads(dumps(f)) == f - True + EXAMPLES:: + + sage: from sage.libs.ntl.ntl_ZZX import ntl_ZZX + sage: f = ntl_ZZX([1,2,0,4]) + sage: loads(dumps(f)) == f + True """ return unpickle_class_value, (ntl_ZZX, self.list()) @@ -183,6 +185,8 @@ cdef class ntl_ZZX(): def __setitem__(self, long i, a): """ + EXAMPLES:: + sage: n=ntl.ZZX([1,2,3]) sage: n [1 2 3] diff --git a/src/sage/libs/ntl/ntl_ZZ_p.pyx b/src/sage/libs/ntl/ntl_ZZ_p.pyx index 9b90383d50c..469d62f2812 100644 --- a/src/sage/libs/ntl/ntl_ZZ_p.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_p.pyx @@ -166,9 +166,11 @@ cdef class ntl_ZZ_p(): def __reduce__(self): """ - sage: a = ntl.ZZ_p(4,7) - sage: loads(dumps(a)) == a - True + EXAMPLES:: + + sage: a = ntl.ZZ_p(4,7) + sage: loads(dumps(a)) == a + True """ return unpickle_class_args, (ntl_ZZ_p, (self.lift(), self.modulus_context())) diff --git a/src/sage/libs/ntl/ntl_ZZ_pE.pyx b/src/sage/libs/ntl/ntl_ZZ_pE.pyx index 97c658dffb0..9e2d06bb58e 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pE.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pE.pyx @@ -166,9 +166,11 @@ cdef class ntl_ZZ_pE(): def __reduce__(self): """ - sage: a = ntl.ZZ_pE([4],ntl.ZZ_pX([1,1,1],ntl.ZZ(7))) - sage: loads(dumps(a)) == a - True + EXAMPLES:: + + sage: a = ntl.ZZ_pE([4],ntl.ZZ_pX([1,1,1],ntl.ZZ(7))) + sage: loads(dumps(a)) == a + True """ return make_ZZ_pE, (self.get_as_ZZ_pX(), self.get_modulus_context()) diff --git a/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx b/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx index bef581722bd..b6ff3c66b01 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx @@ -37,13 +37,15 @@ cdef class ntl_ZZ_pEContext_class(): """ EXAMPLES: - # You can construct contexts manually. + You can construct contexts manually:: + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([4,1,6],25)) sage: n1=c.ZZ_pE([10,17,12]) sage: n1 [2 15] - # or You can construct contexts implicitly. + Or you can construct contexts implicitly:: + sage: n2=ntl.ZZ_pE(12, ntl.ZZ_pX([1,1,1],7)) sage: n2 [5] @@ -65,9 +67,11 @@ cdef class ntl_ZZ_pEContext_class(): def __reduce__(self): """ - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1],7)) - sage: loads(dumps(c)) is c - True + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1],7)) + sage: loads(dumps(c)) is c + True """ return ntl_ZZ_pEContext, (self.f,) diff --git a/src/sage/libs/ntl/ntl_ZZ_pX.pyx b/src/sage/libs/ntl/ntl_ZZ_pX.pyx index 95d77f727fa..c2fff88cb0f 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pX.pyx @@ -207,11 +207,13 @@ cdef class ntl_ZZ_pX(): def __setitem__(self, long i, a): r""" - sage: c = ntl.ZZ_pContext(23) - sage: x = ntl.ZZ_pX([2, 3, 4], c) - sage: x[1] = 5 - sage: x - [2 5 4] + EXAMPLES:: + + sage: c = ntl.ZZ_pContext(23) + sage: x = ntl.ZZ_pX([2, 3, 4], c) + sage: x[1] = 5 + sage: x + [2 5 4] """ if i < 0: raise IndexError("index (i=%s) must be >= 0" % i) diff --git a/src/sage/libs/ntl/ntl_lzz_pContext.pyx b/src/sage/libs/ntl/ntl_lzz_pContext.pyx index 64301157702..80ff9ac51bc 100644 --- a/src/sage/libs/ntl/ntl_lzz_pContext.pyx +++ b/src/sage/libs/ntl/ntl_lzz_pContext.pyx @@ -60,9 +60,11 @@ cdef class ntl_zz_pContext_class(): def __reduce__(self): """ - sage: c=ntl.zz_pContext(13) - sage: loads(dumps(c)) is c - True + EXAMPLES:: + + sage: c=ntl.zz_pContext(13) + sage: loads(dumps(c)) is c + True """ return ntl_zz_pContext, (self.p,) From 9c4465943a0f0d4a8e6843e187cc15b82215302b Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Tue, 27 Sep 2022 15:52:41 -0700 Subject: [PATCH 738/742] trac 34595: fix internet doctests in findstat.py --- src/sage/databases/findstat.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index d21f1a250b3..70429a47ac0 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -4545,7 +4545,7 @@ def name(self, style="singular"): _SupportedFindStatCollection(lambda x: (lambda E, V: Graph([list(range(V)), lambda i,j: (i,j) in E or (j,i) in E], immutable=True))(*literal_eval(x)), - lambda X: str((sorted(X.edges(labels=False)), X.num_verts())), + lambda X: str((X.edges(labels=False, sort=True), X.num_verts())), lambda x: (g.copy(immutable=True) for g in graphs(x, copy=False)), lambda x: x.num_verts(), lambda x: isinstance(x, Graph)), @@ -4767,13 +4767,13 @@ def _element_constructor_(self, entry): sage: cc = FindStatCollection(graphs(3)); cc # optional -- internet a subset of Cc0020: Graphs - sage: cc.first_terms(lambda x: x.edges(labels=False)).list() # optional -- internet + sage: cc.first_terms(lambda x: x.edges(labels=False, sort=True)).list() # optional -- internet [(Graph on 3 vertices, []), (Graph on 3 vertices, [(0, 2)]), (Graph on 3 vertices, [(0, 2), (1, 2)]), (Graph on 3 vertices, [(0, 1), (0, 2), (1, 2)])] - sage: len(cc.first_terms(lambda x: x.edges(labels=False)).list()) # optional -- internet + sage: len(cc.first_terms(lambda x: x.edges(labels=False, sort=False)).list()) # optional -- internet 4 """ if isinstance(entry, self.Element): From 1205fc8770a71791be27a13553c4ad04b1a220f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 28 Sep 2022 09:53:56 +0200 Subject: [PATCH 739/742] details as suggested by the reviewer --- src/sage/libs/eclib/mwrank.pyx | 41 +++++++++++++++++----------------- src/sage/libs/ntl/ntl_GF2E.pyx | 18 +++++++-------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/sage/libs/eclib/mwrank.pyx b/src/sage/libs/eclib/mwrank.pyx index f17abe62e69..119d4d49dd4 100644 --- a/src/sage/libs/eclib/mwrank.pyx +++ b/src/sage/libs/eclib/mwrank.pyx @@ -83,7 +83,7 @@ mwrank_set_precision(150) def get_precision(): """ - Returns the working floating point bit precision of mwrank, which is + Return the working floating point bit precision of mwrank, which is equal to the global NTL real number precision. OUTPUT: @@ -119,7 +119,7 @@ def set_precision(n): This change is global and affects *all* future calls of eclib functions by Sage. - .. note:: + .. NOTE:: The minimal value to which the precision may be set is 53. Lower values will be increased to 53. @@ -345,7 +345,7 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class + B`, where `h(P)` is the naive height and `\hat{h}(P)` the canonical height. - .. note:: + .. NOTE:: Since eclib can compute this to arbitrary precision, we could return a Sage real, but this is only a bound and in @@ -374,7 +374,7 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class + B`, where `h(P)` is the naive height and `\hat{h}(P)` the canonical height. - .. note:: + .. NOTE:: Since ``eclib`` can compute this to arbitrary precision, we could return a Sage real, but this is only a bound and in @@ -409,7 +409,7 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class canonical height. This is the minimum of the Silverman and Cremona_Prickett-Siksek height bounds. - .. note:: + .. NOTE:: Since ``eclib`` can compute this to arbitrary precision, we could return a Sage real, but this is only a bound and in @@ -702,10 +702,10 @@ cdef class _mw: .. NOTE:: - The eclib function which implements this only carries out - any saturation if the rank of the points increases upon - adding the new point. This is because it is assumed that - one saturates as ones goes along. + The eclib function which implements this only carries out + any saturation if the rank of the points increases upon + adding the new point. This is because it is assumed that + one saturates as ones goes along. EXAMPLES:: @@ -751,7 +751,7 @@ cdef class _mw: def getbasis(self): """ - Returns the current basis of the mw structure. + Return the current basis of the mw structure. OUTPUT: @@ -776,7 +776,7 @@ cdef class _mw: def regulator(self): """ - Returns the regulator of the current basis of the mw group. + Return the regulator of the current basis of the mw group. OUTPUT: @@ -808,7 +808,7 @@ cdef class _mw: def rank(self): """ - Returns the rank of the current basis of the mw group. + Return the rank of the current basis of the mw group. OUTPUT: @@ -1066,7 +1066,7 @@ cdef class _two_descent: def getrank(self): """ - Returns the rank (after doing a 2-descent). + Return the rank (after doing a 2-descent). OUTPUT: @@ -1099,7 +1099,7 @@ cdef class _two_descent: def getrankbound(self): """ - Returns the rank upper bound (after doing a 2-descent). + Return the rank upper bound (after doing a 2-descent). OUTPUT: @@ -1132,7 +1132,7 @@ cdef class _two_descent: def getselmer(self): """ - Returns the 2-Selmer rank (after doing a 2-descent). + Return the 2-Selmer rank (after doing a 2-descent). OUTPUT: @@ -1164,7 +1164,7 @@ cdef class _two_descent: def ok(self): """ - Returns the success flag (after doing a 2-descent). + Return the success flag (after doing a 2-descent). OUTPUT: @@ -1193,7 +1193,7 @@ cdef class _two_descent: def getcertain(self): """ - Returns the certainty flag (after doing a 2-descent). + Return the certainty flag (after doing a 2-descent). OUTPUT: @@ -1271,7 +1271,7 @@ cdef class _two_descent: def getbasis(self): r""" - Returns the basis of points found by doing a 2-descent. + Return the basis of points found by doing a 2-descent. If the success and certain flags are 1, this will be a `\ZZ/2\ZZ`-basis for `E(\QQ)/2E(\QQ)` (modulo torsion), @@ -1279,7 +1279,8 @@ cdef class _two_descent: .. NOTE:: - You must call ``saturate()`` first, or a RunTimeError will be raised. + You must call ``saturate()`` first, or a ``RunTimeError`` + will be raised. OUTPUT: @@ -1317,7 +1318,7 @@ cdef class _two_descent: def regulator(self): """ - Returns the regulator of the points found by doing a 2-descent. + Return the regulator of the points found by doing a 2-descent. OUTPUT: diff --git a/src/sage/libs/ntl/ntl_GF2E.pyx b/src/sage/libs/ntl/ntl_GF2E.pyx index 2744de98c01..54c7eef492a 100644 --- a/src/sage/libs/ntl/ntl_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_GF2E.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # Copyright (C) 2007 Martin Albrecht # @@ -18,8 +18,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.ext.cplusplus cimport ccrepr @@ -73,7 +73,7 @@ def ntl_GF2E_random(ntl_GF2EContext_class ctx): cdef class ntl_GF2E(): r""" - The \\class{GF2E} represents a finite extension field over GF(2) + The :class:`GF2E` represents a finite extension field over GF(2) using NTL. Elements are represented as polynomials over GF(2) modulo a modulus. @@ -442,19 +442,19 @@ cdef class ntl_GF2E(): def _sage_(ntl_GF2E self, k=None): r""" - Returns a \class{FiniteFieldElement} representation of this element. + Return a :class:`FiniteFieldElement` representation of this element. - If a \class{FiniteField} k is provided it is constructed in - this field if possible. A \class{FiniteField} will be + If a :class:`FiniteField` `k` is provided, it is constructed + in this field if possible. A :class:`FiniteField` will be constructed if none is provided. INPUT: - k -- optional GF(2**deg) + - `k` -- (optional) a field `\GF{2^d}` OUTPUT: - FiniteFieldElement over k + :class:`FiniteFieldElement` over `k` EXAMPLES:: From 188910c1fe03a8147bd1a038ab5e0383571eb2e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 28 Sep 2022 09:16:01 +0200 Subject: [PATCH 740/742] some care for W391 (final empty lines) and a few other things --- src/sage/algebras/catalog.py | 3 +-- src/sage/algebras/clifford_algebra.py | 1 - src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py | 9 ++++----- .../algebras/hecke_algebras/cubic_hecke_base_ring.py | 3 +-- .../algebras/hecke_algebras/cubic_hecke_matrix_rep.py | 1 - src/sage/algebras/q_commuting_polynomials.py | 3 +-- src/sage/algebras/quantum_clifford.py | 5 ++--- src/sage/categories/commutative_algebras.py | 1 - src/sage/categories/integral_domains.py | 1 - src/sage/databases/cubic_hecke_db.py | 1 - src/sage/groups/cubic_braid.py | 8 +++----- src/sage/groups/raag.py | 1 - src/sage/homology/free_resolution.py | 1 - src/sage/homology/graded_resolution.py | 1 - src/sage/matrix/benchmark.py | 6 ++---- src/sage/matrix/matrix_integer_dense_saturation.py | 6 ++---- src/sage/misc/dev_tools.py | 8 ++++---- src/sage/monoids/free_abelian_monoid.py | 1 - src/sage/monoids/free_monoid_element.py | 5 ++--- src/sage/monoids/indexed_free_monoid.py | 7 +++---- src/sage/monoids/monoid.py | 1 - src/sage/numerical/linear_tensor.py | 5 +---- src/sage/numerical/linear_tensor_constraints.py | 3 +-- src/sage/sat/solvers/cryptominisat.py | 8 +++----- src/sage/sat/solvers/dimacs.py | 3 +-- src/sage/sat/solvers/picosat.py | 6 ++---- src/sage/schemes/elliptic_curves/hom.py | 3 +-- src/sage/schemes/elliptic_curves/hom_velusqrt.py | 1 - src/sage/schemes/elliptic_curves/weierstrass_morphism.py | 1 - src/sage/schemes/riemann_surfaces/riemann_surface.py | 2 +- src/sage/sets/disjoint_union_enumerated_sets.py | 4 +--- src/sage/sets/finite_set_maps.py | 1 - src/sage/structure/indexed_generators.py | 3 +-- src/sage/structure/proof/proof.py | 1 - src/sage/tests/combinatorial_hopf_algebras.py | 1 - src/sage/tests/functools_partial_src.py | 1 - src/sage/tests/gosper-sum.py | 1 - src/sage/typeset/unicode_characters.py | 2 -- 38 files changed, 37 insertions(+), 82 deletions(-) diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index cce33d64029..a3c8aa161ed 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -133,5 +133,4 @@ 'ACEQuantumOnsagerAlgebra', 'AlternatingCentralExtensionQuantumOnsager') lazy_import('sage.algebras.yangian', 'Yangian') -del lazy_import # We remove the object from here so it doesn't appear under tab completion - +del lazy_import # We remove the object from here so it doesn't appear under tab completion diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 8fc5d750dd6..a6ee368a61d 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2994,4 +2994,3 @@ def groebner_basis(self, term_order=None, reduced=True): self._groebner_strategy.compute_groebner(reduced=reduced) self._reduced = reduced return self._groebner_strategy.groebner_basis - diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 29ed81ff47d..f3cdb5a6af8 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -1757,11 +1757,11 @@ def _test_ring_constructions(self, **options): raise RuntimeError('fatal: base ring embedding %s does not work' % bri) test_eleBgenEmb = self._tester(**options) - test_eleBgenEmb.assertTrue(eleBgenEmb == eleB) + test_eleBgenEmb.assertEqual(eleBgenEmb, eleB) test_eleEgenEmb = self._tester(**options) - test_eleEgenEmb.assertTrue(eleEgenEmb == eleE) + test_eleEgenEmb.assertEqual(eleEgenEmb, eleE) test_eleBembE = self._tester(**options) - test_eleBembE.assertTrue(eleBembE == eleB) + test_eleBembE.assertEqual(eleBembE, eleB) # -------------------------------------------------------------------------- # _test_matrix_constructions @@ -1806,7 +1806,7 @@ def check_matrix(representation_type): m12mult = m1*m2 m12mat = b12.matrix(representation_type=representation_type) test_matrix = self._tester(**options) - test_matrix.assertTrue(m12mult == m12mat) + test_matrix.assertEqual(m12mult, m12mat) from sage.combinat.root_system.reflection_group_real import is_chevie_available @@ -3535,4 +3535,3 @@ def char_function(ele): return char_function irrs = [irr for irr in self.irred_repr if irr.number_gens() == self._nstrands - 1] return [self.characters(irrs[i], original=original) for i in range(len(irrs))] - diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py index d30633cad55..1a21f5dcb9f 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -1477,7 +1477,7 @@ def specialize_links_gould(self): L = LaurentPolynomialRing(ZZ, 't0, t1') t0, t1 = L.gens() lu = t0 + t1 - 1 - lv = t0*t1 - t0 - t1 + lv = t0 * t1 - t0 - t1 lw = -t0 * t1 LL = L.localization((lu, lv)) u = LL(lu) @@ -1486,4 +1486,3 @@ def specialize_links_gould(self): phi = self.hom((u, v, w, LL.one())) inc = L.convert_map_from(LL) return inc * phi - diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py index 01c72e26098..b2d68fb2f6f 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py @@ -1079,4 +1079,3 @@ def some_elements(self): True """ return tuple([self(x) for x in self._cubic_hecke_algebra.some_elements()]) - diff --git a/src/sage/algebras/q_commuting_polynomials.py b/src/sage/algebras/q_commuting_polynomials.py index b772f04a57e..d1aae987d61 100644 --- a/src/sage/algebras/q_commuting_polynomials.py +++ b/src/sage/algebras/q_commuting_polynomials.py @@ -346,6 +346,5 @@ def product_on_basis(self, x, y): Ly = y.list() # This could be made more efficient - qpow = sum(exp * sum(self._B[j,i] * val for j, val in enumerate(Ly[:i])) for i,exp in enumerate(Lx)) + qpow = sum(exp * sum(self._B[j, i] * val for j, val in enumerate(Ly[:i])) for i, exp in enumerate(Lx)) return self.term(x * y, self._q ** qpow) - diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index f646b0c2a52..1e57682f255 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -948,8 +948,7 @@ def inverse(self): if any(p[i] != 0 for i in range(Cl._n)): return super().__invert__() tk = 2 * Cl._k - w = tuple([tk-val if val else 0 for val in w]) - return Cl.element_class(Cl, {(p, w) : coeff.inverse_of_unit()}) + w = tuple([tk - val if val else 0 for val in w]) + return Cl.element_class(Cl, {(p, w): coeff.inverse_of_unit()}) __invert__ = inverse - diff --git a/src/sage/categories/commutative_algebras.py b/src/sage/categories/commutative_algebras.py index 0f24e90c524..cff24e1298a 100644 --- a/src/sage/categories/commutative_algebras.py +++ b/src/sage/categories/commutative_algebras.py @@ -89,4 +89,3 @@ def extra_super_categories(self): True """ return [CommutativeRings()] - diff --git a/src/sage/categories/integral_domains.py b/src/sage/categories/integral_domains.py index 8cf87ffe94f..2d5d7730693 100644 --- a/src/sage/categories/integral_domains.py +++ b/src/sage/categories/integral_domains.py @@ -144,4 +144,3 @@ def _test_fraction_field(self, **options): class ElementMethods: pass - diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index fd0068f8793..99e96a9b816 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -1514,4 +1514,3 @@ def read_markov(bas_ele, variables, num_strands=4): 0, 1]} return data[num_strands][bas_ele] - diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index 90f8e07ba2c..4866cdc4f85 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -2028,19 +2028,17 @@ def cubic_braid_subgroup(self, nstrands=None): True """ if nstrands is None: - nstrands = self.strands() -1 + nstrands = self.strands() - 1 n = self.strands() nstrands = Integer(nstrands) if nstrands >= n or nstrands <= 0: - raise ValueError("nstrands must be positive and less than %s" %(self.strands())) - + raise ValueError("nstrands must be positive and less than %s" % (self.strands())) names = self.variable_names() - names_red = names[:nstrands-1] + names_red = names[:nstrands - 1] subgrp = CubicBraidGroup(names=names_red, cbg_type=self._cbg_type) subgrp._ambient = self return subgrp - diff --git a/src/sage/groups/raag.py b/src/sage/groups/raag.py index 59b78c6d757..e8d626a32a4 100644 --- a/src/sage/groups/raag.py +++ b/src/sage/groups/raag.py @@ -857,4 +857,3 @@ class Element(CohomologyRAAGElement): """ An element in the cohomology ring of a right-angled Artin group. """ - diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 7d3ea29057e..424086d283e 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -891,4 +891,3 @@ def _maps(self): r = minres(res(std(mod), 0)) return si2sa_resolution(r) - diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index 97a3cb9624b..940d24d160d 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -572,4 +572,3 @@ def _maps(self): self._res_shifts = res_shifts return res_mats - diff --git a/src/sage/matrix/benchmark.py b/src/sage/matrix/benchmark.py index 86d09a63a49..811a1cbfc98 100644 --- a/src/sage/matrix/benchmark.py +++ b/src/sage/matrix/benchmark.py @@ -1229,12 +1229,10 @@ def nullspace_RDF(n=300, min=0, max=10, system='sage'): t := Cputime(); K := Kernel(A); s := Cputime(t); -"""%(n,min,max) +""" % (n, min, max) if verbose: print(code) magma.eval(code) return float(magma.eval('s')) else: - raise ValueError('unknown system "%s"'%system) - - + raise ValueError('unknown system "%s"' % system) diff --git a/src/sage/matrix/matrix_integer_dense_saturation.py b/src/sage/matrix/matrix_integer_dense_saturation.py index 9ac854ea2d1..01621f6844f 100644 --- a/src/sage/matrix/matrix_integer_dense_saturation.py +++ b/src/sage/matrix/matrix_integer_dense_saturation.py @@ -339,13 +339,11 @@ def index_in_saturation(A, proof=True): """ r = A.rank() if r == 0: - return ZZ(1) + return ZZ.one() if r < A.nrows(): A = A.hermite_form(proof=proof, include_zero_rows=False) if A.is_square(): return abs(A.determinant(proof=proof)) A = A.transpose() - A = A.hermite_form(proof=proof,include_zero_rows=False) + A = A.hermite_form(proof=proof, include_zero_rows=False) return abs(A.determinant(proof=proof)) - - diff --git a/src/sage/misc/dev_tools.py b/src/sage/misc/dev_tools.py index 5eed16a8565..8d2c2f080d5 100644 --- a/src/sage/misc/dev_tools.py +++ b/src/sage/misc/dev_tools.py @@ -525,12 +525,12 @@ def import_statements(*objects, **kwds): if kwds: raise TypeError("Unexpected '{}' argument".format(next(iter(kwds)))) - def expand_comma_separated_names(object): - if isinstance(object, str): - for w in object.strip('()').split(','): + def expand_comma_separated_names(obj): + if isinstance(obj, str): + for w in obj.strip('()').split(','): yield w.strip() else: - yield object + yield obj for obj in itertools.chain.from_iterable(expand_comma_separated_names(object) for object in objects): diff --git a/src/sage/monoids/free_abelian_monoid.py b/src/sage/monoids/free_abelian_monoid.py index d1a5dce30c1..54771b247e4 100644 --- a/src/sage/monoids/free_abelian_monoid.py +++ b/src/sage/monoids/free_abelian_monoid.py @@ -308,4 +308,3 @@ def cardinality(self): return ZZ.one() from sage.rings.infinity import infinity return infinity - diff --git a/src/sage/monoids/free_monoid_element.py b/src/sage/monoids/free_monoid_element.py index 23a6cc709c7..f23dba93b45 100644 --- a/src/sage/monoids/free_monoid_element.py +++ b/src/sage/monoids/free_monoid_element.py @@ -408,7 +408,6 @@ def to_list(self, indices=False): :meth:`to_word` """ if not indices: - return sum( ([i[0]] * i[1] for i in list(self)), []) + return sum(([i[0]] * i[1] for i in list(self)), []) gens = self.parent().gens() - return sum( ([gens.index(i[0])] * i[1] for i in list(self)), []) - + return sum(([gens.index(i[0])] * i[1] for i in list(self)), []) diff --git a/src/sage/monoids/indexed_free_monoid.py b/src/sage/monoids/indexed_free_monoid.py index cda2681c5be..58910533a9a 100644 --- a/src/sage/monoids/indexed_free_monoid.py +++ b/src/sage/monoids/indexed_free_monoid.py @@ -1002,7 +1002,6 @@ def gen(self, x): if x not in self._indices: raise IndexError("{} is not in the index set".format(x)) try: - return self.element_class(self, {self._indices(x):1}) - except (TypeError, NotImplementedError): # Backup (e.g., if it is a string) - return self.element_class(self, {x:1}) - + return self.element_class(self, {self._indices(x): 1}) + except (TypeError, NotImplementedError): # Backup (e.g., if it is a string) + return self.element_class(self, {x: 1}) diff --git a/src/sage/monoids/monoid.py b/src/sage/monoids/monoid.py index 4ba247e7d99..31e6c219f89 100644 --- a/src/sage/monoids/monoid.py +++ b/src/sage/monoids/monoid.py @@ -70,4 +70,3 @@ def monoid_generators(self): """ from sage.sets.family import Family return Family(self.gens()) - diff --git a/src/sage/numerical/linear_tensor.py b/src/sage/numerical/linear_tensor.py index bdf9529659a..a210ff52fd7 100644 --- a/src/sage/numerical/linear_tensor.py +++ b/src/sage/numerical/linear_tensor.py @@ -478,7 +478,4 @@ def _an_element_(self): (1.0, 0.0) + (5.0, 0.0)*x_2 + (7.0, 0.0)*x_5 """ m = self.free_module().an_element() - return self._element_constructor_({-1:m, 2:5*m, 5:7*m}) - - - + return self._element_constructor_({-1: m, 2: 5 * m, 5: 7 * m}) diff --git a/src/sage/numerical/linear_tensor_constraints.py b/src/sage/numerical/linear_tensor_constraints.py index ce09731cc6e..3da0cd4719a 100644 --- a/src/sage/numerical/linear_tensor_constraints.py +++ b/src/sage/numerical/linear_tensor_constraints.py @@ -446,7 +446,7 @@ def _element_constructor_(self, left, right, equality): def _an_element_(self): """ - Returns an element + Return an element. EXAMPLES:: @@ -457,4 +457,3 @@ def _an_element_(self): """ LT = self.linear_tensors() return LT.an_element() >= 0 - diff --git a/src/sage/sat/solvers/cryptominisat.py b/src/sage/sat/solvers/cryptominisat.py index 6a090604438..eb12e9fbbb3 100644 --- a/src/sage/sat/solvers/cryptominisat.py +++ b/src/sage/sat/solvers/cryptominisat.py @@ -276,11 +276,9 @@ def clauses(self, filename=None): 1 2 -4 0 x1 2 3 0 x1 2 -5 0 - + """ if filename is None: return self._clauses - else: - from sage.sat.solvers.dimacs import DIMACS - DIMACS.render_dimacs(self._clauses, filename, self.nvars()) - + from sage.sat.solvers.dimacs import DIMACS + DIMACS.render_dimacs(self._clauses, filename, self.nvars()) diff --git a/src/sage/sat/solvers/dimacs.py b/src/sage/sat/solvers/dimacs.py index ca40b2d6fe7..cff59ac8205 100644 --- a/src/sage/sat/solvers/dimacs.py +++ b/src/sage/sat/solvers/dimacs.py @@ -622,6 +622,5 @@ def __call__(self, **kwds): if line.startswith("v"): full_line += line[2:] + ' ' s = map(int, full_line[:-3].strip().split(" ")) - s = (None,) + tuple(e>0 for e in s) + s = (None,) + tuple(e > 0 for e in s) return s - diff --git a/src/sage/sat/solvers/picosat.py b/src/sage/sat/solvers/picosat.py index f27c70a92bf..daeef620669 100644 --- a/src/sage/sat/solvers/picosat.py +++ b/src/sage/sat/solvers/picosat.py @@ -220,7 +220,5 @@ def clauses(self, filename=None): """ if filename is None: return self._clauses - else: - from sage.sat.solvers.dimacs import DIMACS - DIMACS.render_dimacs(self._clauses, filename, self.nvars()) - + from sage.sat.solvers.dimacs import DIMACS + DIMACS.render_dimacs(self._clauses, filename, self.nvars()) diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index 8d707e8e6b7..f5391068e47 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -713,7 +713,7 @@ def compare_via_evaluation(left, right): q = F.cardinality() d = left.degree() e = integer_floor(1 + 2 * (2*d.sqrt() + 1).log(q)) # from Hasse bound - e = next(i for i,n in enumerate(E.count_points(e+1), 1) if n > 4*d) + e = next(i for i, n in enumerate(E.count_points(e+1), 1) if n > 4*d) EE = E.base_extend(F.extension(e)) Ps = EE.gens() return all(left._eval(P) == right._eval(P) for P in Ps) @@ -728,4 +728,3 @@ def compare_via_evaluation(left, right): else: raise NotImplementedError('not implemented for this base field') - diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 20688dbb4d0..043edcd7399 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -1247,4 +1247,3 @@ def _random_example_for_testing(): K = G(v).element() assert K.order() == deg return E, K - diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py index 33549debee1..a9ad45f6fb2 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py @@ -907,4 +907,3 @@ def scaling_factor(self): the tuple `(u,r,s,t)` defining the isomorphism. """ return self.u - diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index f85a7295dbc..87e02bc962b 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -478,7 +478,7 @@ def reparameterize_differential_minpoly(minpoly, z0): return mt -class RiemannSurface(object): +class RiemannSurface(): r""" Construct a Riemann Surface. This is specified by the zeroes of a bivariate polynomial with rational coefficients `f(z,w) = 0`. diff --git a/src/sage/sets/disjoint_union_enumerated_sets.py b/src/sage/sets/disjoint_union_enumerated_sets.py index 1820a79256f..7b95a9dc945 100644 --- a/src/sage/sets/disjoint_union_enumerated_sets.py +++ b/src/sage/sets/disjoint_union_enumerated_sets.py @@ -602,6 +602,4 @@ def Element(self): """ if not self._facade: return ElementWrapper - else: - return NotImplemented - + return NotImplemented diff --git a/src/sage/sets/finite_set_maps.py b/src/sage/sets/finite_set_maps.py index fd4a3ed08ba..ce5029d8032 100644 --- a/src/sage/sets/finite_set_maps.py +++ b/src/sage/sets/finite_set_maps.py @@ -585,4 +585,3 @@ def __init__(self, domain, action, category=None): self._action = action Element = FiniteSetEndoMap_Set - diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index da04658324f..4cf80c3522d 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -818,7 +818,7 @@ def standardize_names_index_set(names=None, index_set=None, ngens=None): index_set = tuple(names) from sage.sets.finite_enumerated_set import FiniteEnumeratedSet - if isinstance(index_set, dict): # dict of {name: index} -- not likely to be used + if isinstance(index_set, dict): # dict of {name: index} -- not likely to be used if names is not None: raise ValueError("cannot give index_set as a dict and names") names = normalize_names(-1, tuple(index_set.keys())) @@ -841,4 +841,3 @@ def standardize_names_index_set(names=None, index_set=None, ngens=None): " the number of generators") return (names, index_set) - diff --git a/src/sage/structure/proof/proof.py b/src/sage/structure/proof/proof.py index c667704db92..24532380e8a 100644 --- a/src/sage/structure/proof/proof.py +++ b/src/sage/structure/proof/proof.py @@ -253,4 +253,3 @@ def __exit__(self, *args): True """ _proof_prefs._require_proof[self._subsystem] = self._t_orig - diff --git a/src/sage/tests/combinatorial_hopf_algebras.py b/src/sage/tests/combinatorial_hopf_algebras.py index 83a732a170f..6ac40f7aad5 100644 --- a/src/sage/tests/combinatorial_hopf_algebras.py +++ b/src/sage/tests/combinatorial_hopf_algebras.py @@ -48,4 +48,3 @@ sage: all(go2(n) for n in range(6)) # not tested (needs more morphisms) True """ - diff --git a/src/sage/tests/functools_partial_src.py b/src/sage/tests/functools_partial_src.py index 01e4af0f574..1fb24e15b34 100644 --- a/src/sage/tests/functools_partial_src.py +++ b/src/sage/tests/functools_partial_src.py @@ -22,4 +22,3 @@ def base(x): return x test_func = partial(base, 6) - diff --git a/src/sage/tests/gosper-sum.py b/src/sage/tests/gosper-sum.py index 95266ac235c..abdb622b18c 100644 --- a/src/sage/tests/gosper-sum.py +++ b/src/sage/tests/gosper-sum.py @@ -214,4 +214,3 @@ sage: t.simplify_full().is_trivial_zero() False """ - diff --git a/src/sage/typeset/unicode_characters.py b/src/sage/typeset/unicode_characters.py index 4eacf326c43..c4aa7bdd5fb 100644 --- a/src/sage/typeset/unicode_characters.py +++ b/src/sage/typeset/unicode_characters.py @@ -99,5 +99,3 @@ unicode_mathbbR = '\u211D' # 'ℝ' unicode_mathbbC = '\u2102' # 'ℂ' - - From d4eddeceb082a2525d3dcacf09020ef444bf66c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 28 Sep 2022 20:34:34 +0200 Subject: [PATCH 741/742] fix W391 in tests, modules, rings --- src/sage/modules/free_module.py | 1 - src/sage/modules/module_functors.py | 3 +-- src/sage/modules/submodule.py | 1 - src/sage/modules/with_basis/cell_module.py | 1 - src/sage/modules/with_basis/morphism.py | 2 +- src/sage/rings/ideal.py | 6 +----- src/sage/rings/polynomial/msolve.py | 3 +-- src/sage/rings/polynomial/multi_polynomial_ideal.py | 1 - .../rings/polynomial/polynomial_quotient_ring_element.py | 1 - src/sage/rings/tate_algebra.py | 1 - .../calculus_doctest.py | 1 - .../combinat_doctest.py | 1 - .../domaines_doctest.py | 1 - .../float_doctest.py | 1 - .../graphique_doctest.py | 1 - .../graphtheory_doctest.py | 1 - .../integration_doctest.py | 1 - .../linalg_doctest.py | 1 - .../computational-mathematics-with-sagemath/lp_doctest.py | 1 - .../mpoly_doctest.py | 1 - .../nonlinear_doctest.py | 1 - .../numbertheory_doctest.py | 1 - .../polynomes_doctest.py | 1 - .../premierspas_doctest.py | 1 - .../programmation_doctest.py | 1 - .../recequadiff_doctest.py | 1 - .../sol/calculus_doctest.py | 1 - .../sol/combinat_doctest.py | 1 - .../sol/domaines_doctest.py | 1 - .../sol/float_doctest.py | 1 - .../sol/integration_doctest.py | 1 - .../sol/linalg_doctest.py | 1 - .../sol/linsolve_doctest.py | 1 - .../sol/lp_doctest.py | 1 - .../sol/mpoly_doctest.py | 1 - .../sol/nonlinear_doctest.py | 1 - .../sol/numbertheory_doctest.py | 1 - .../sol/polynomes_doctest.py | 1 - .../sol/recequadiff_doctest.py | 1 - 39 files changed, 4 insertions(+), 45 deletions(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index b849f1e86ee..47fb713d522 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -8243,4 +8243,3 @@ def __richcmp__(self, other, op): True """ return self.obj._echelon_matrix_richcmp(other.obj, op) - diff --git a/src/sage/modules/module_functors.py b/src/sage/modules/module_functors.py index 5e84c79008d..497120d02e8 100644 --- a/src/sage/modules/module_functors.py +++ b/src/sage/modules/module_functors.py @@ -75,7 +75,7 @@ class QuotientModuleFunctor(ConstructionFunctor): sage: Q2 = A2 / B2 sage: q3 = Q1.an_element() + Q2.an_element() """ - rank = 5 # ranking of functor, not rank of module + rank = 5 # ranking of functor, not rank of module def __init__(self, relations): """ @@ -187,4 +187,3 @@ def merge(self, other): """ if isinstance(other, QuotientModuleFunctor): return QuotientModuleFunctor(self._relations + other._relations) - diff --git a/src/sage/modules/submodule.py b/src/sage/modules/submodule.py index f8078c4066e..4e0d6994f02 100644 --- a/src/sage/modules/submodule.py +++ b/src/sage/modules/submodule.py @@ -243,4 +243,3 @@ def ambient_module(self): True """ return self._ambient - diff --git a/src/sage/modules/with_basis/cell_module.py b/src/sage/modules/with_basis/cell_module.py index 5c6145d167e..a17882b4e9e 100644 --- a/src/sage/modules/with_basis/cell_module.py +++ b/src/sage/modules/with_basis/cell_module.py @@ -473,4 +473,3 @@ def _acted_upon_(self, scalar, self_on_left=False): # For backward compatibility _lmul_ = _acted_upon_ _rmul_ = _acted_upon_ - diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index b8fe98111b2..3cd841629a9 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -1551,6 +1551,7 @@ def pointwise_inverse_function(f): return f.pointwise_inverse() return PointwiseInverseFunction(f) + from sage.structure.sage_object import SageObject class PointwiseInverseFunction(SageObject): r""" @@ -1630,4 +1631,3 @@ def pointwise_inverse(self): True """ return self._pointwise_inverse - diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 8e584ee0141..f1342415355 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -1847,12 +1847,8 @@ def FieldIdeal(R): Multivariate Polynomial Ring in x1, x2, x3, x4 over Finite Field in alpha of size 2^4 """ - q = R.base_ring().order() - import sage.rings.infinity if q is sage.rings.infinity.infinity: raise TypeError("Cannot construct field ideal for R.base_ring().order()==infinity") - - return R.ideal([x**q - x for x in R.gens() ]) - + return R.ideal([x**q - x for x in R.gens()]) diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index 65ae859f751..221eed660b0 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -290,7 +290,7 @@ def to_poly(p, d=1, *, upol=PolynomialRing(base, 't')): variety = [] for rt in elim_roots: den_of_rt = den(rt) - point = [-p(rt)/den_of_rt for p in param] + point = [-p(rt) / den_of_rt for p in param] if len(param) != len(vars): point.append(rt) assert len(point) == len(vars) @@ -313,4 +313,3 @@ def to_poly(p, d=1, *, upol=PolynomialRing(base, 't')): for point in l] return [KeyConvertingDict(out_ring, zip(vars, point)) for point in variety] - diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 4e1937a4645..e0f3e0686e8 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -5458,4 +5458,3 @@ def __richcmp__(self, other, op): return not (contained and contains) else: # remaining case < return contained and not contains - diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index 803e78f6e13..e397fffc6d8 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -737,4 +737,3 @@ def rational_reconstruction(self, *args, **kwargs): R = m.parent() f = R(self._polynomial) return f.rational_reconstruction(m, *args, **kwargs) - diff --git a/src/sage/rings/tate_algebra.py b/src/sage/rings/tate_algebra.py index 9097b2a4e07..701278b2eb1 100644 --- a/src/sage/rings/tate_algebra.py +++ b/src/sage/rings/tate_algebra.py @@ -1295,4 +1295,3 @@ def is_integral_domain(self, proof=True): True """ return True - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/calculus_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/calculus_doctest.py index 2e188829ed8..976b912de2a 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/calculus_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/calculus_doctest.py @@ -552,4 +552,3 @@ ) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/combinat_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/combinat_doctest.py index 9dc4f6e430a..d19ba51ec96 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/combinat_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/combinat_doctest.py @@ -1053,4 +1053,3 @@ 645490122795799841856164638490742749440 """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/domaines_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/domaines_doctest.py index e08cf0fb5bb..94c50977d79 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/domaines_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/domaines_doctest.py @@ -442,4 +442,3 @@ (4) * (x + 2)^2 * (x^2 + 3) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/float_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/float_doctest.py index abc31568dd3..aa3eed32f3b 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/float_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/float_doctest.py @@ -476,4 +476,3 @@ 1.73205080756887729352744634151? """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py index 472b7167ac9..0caad449666 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py @@ -260,4 +260,3 @@ Graphics3d Object """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/graphtheory_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/graphtheory_doctest.py index 35d367d8de7..c1d8fa977e5 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/graphtheory_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/graphtheory_doctest.py @@ -417,4 +417,3 @@ sage: g.show(edge_colors=edge_coloring(g, hex_colors=True)) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py index 518e958cad4..fcb293eb698 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py @@ -289,4 +289,3 @@ mpf('2.7135204235459511323824699502438') """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py index 902b3c1aec2..5b99bdfa6ac 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py @@ -458,4 +458,3 @@ True """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py index d4910d7b691..f3aa2201ac8 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py @@ -233,4 +233,3 @@ ....: if p.get_values(B(u,v), convert=ZZ, tolerance=1e-3) == 1] ) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/mpoly_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/mpoly_doctest.py index f36b207d7e3..bef4a2b6c62 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/mpoly_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/mpoly_doctest.py @@ -559,4 +559,3 @@ 45 """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/nonlinear_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/nonlinear_doctest.py index 909d7d3c746..3a7104637ec 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/nonlinear_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/nonlinear_doctest.py @@ -489,4 +489,3 @@ 1/2*pi - (e^(1/2*pi) - 10)*e^(-1/2*pi) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/numbertheory_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/numbertheory_doctest.py index 8a1bed213bc..46a4d4d2bec 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/numbertheory_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/numbertheory_doctest.py @@ -154,4 +154,3 @@ 17 """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py index 951bfb2b5c6..f2f9530e9f4 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py @@ -406,4 +406,3 @@ (x^562949953421312 + 1, 562949953421312*x^562949953421311) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py index 7b8218b4899..fae01daa748 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py @@ -179,4 +179,3 @@ bla """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/programmation_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/programmation_doctest.py index dd2db19fd8a..3f036d5d362 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/programmation_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/programmation_doctest.py @@ -661,4 +661,3 @@ ....: return len(D) == len (Set(D.values())) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py index f53f813d793..50f936f8cba 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py @@ -385,4 +385,3 @@ 2**n*C0 + 2**(n + 1)*n """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/calculus_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/calculus_doctest.py index ca748ba2059..947f9f53a22 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/calculus_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/calculus_doctest.py @@ -263,4 +263,3 @@ True """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/combinat_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/combinat_doctest.py index 4cd1f78259c..5f372f505b0 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/combinat_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/combinat_doctest.py @@ -216,4 +216,3 @@ [0, 1, 1, 2, 5, 14, 42, 132, 429] """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/domaines_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/domaines_doctest.py index 03b4731f545..df3eb03d8fe 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/domaines_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/domaines_doctest.py @@ -58,4 +58,3 @@ """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/float_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/float_doctest.py index 7e1d7f0c0e4..5d5d4686ec7 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/float_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/float_doctest.py @@ -140,4 +140,3 @@ [-1.0000000000000000 .. 1.0000000000000000] """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/integration_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/integration_doctest.py index e11b6bad8d9..bb9550918bf 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/integration_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/integration_doctest.py @@ -55,4 +55,3 @@ [-0.285398163397448, -0.00524656673640445, -0.00125482109302663] """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linalg_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linalg_doctest.py index 4e24775c753..7e164a3bffc 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linalg_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linalg_doctest.py @@ -55,4 +55,3 @@ False """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linsolve_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linsolve_doctest.py index 839ad0d7ec7..e89d7c06fb5 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linsolve_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linsolve_doctest.py @@ -24,4 +24,3 @@ True """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/lp_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/lp_doctest.py index 5219f6f6552..d60adc9dd8b 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/lp_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/lp_doctest.py @@ -46,4 +46,3 @@ True """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/mpoly_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/mpoly_doctest.py index f056b349b3e..d4b92c1dfd6 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/mpoly_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/mpoly_doctest.py @@ -114,4 +114,3 @@ 1/16*u^2*v^2 - 3/8*u^2*v + 7/16*u^2 + 1/8*v^2 - 1/8*v - 1/8 """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/nonlinear_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/nonlinear_doctest.py index afa1a637b7e..f99860f7b9c 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/nonlinear_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/nonlinear_doctest.py @@ -110,4 +110,3 @@ 1/2*pi - (e^(1/2*pi) - 10)*e^(-1/2*pi) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/numbertheory_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/numbertheory_doctest.py index ceae289f561..2dbd0b018e5 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/numbertheory_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/numbertheory_doctest.py @@ -166,4 +166,3 @@ + 4/5*s3^3*x3^15 - 9/32*s3^2*x3^16 + 1/17*s3*x3^17 """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py index 2908f38254d..f8cefd2f6e8 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py @@ -106,4 +106,3 @@ + 21844/6081075*x^13 + O(x^15) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/recequadiff_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/recequadiff_doctest.py index 2dfe2109434..01d0e1bc143 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/recequadiff_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/recequadiff_doctest.py @@ -57,4 +57,3 @@ -sqrt(2*_C + 2*log(x))*x """ - From 54cd6fe6de52aee5a433e0569e8c370618cb2047 Mon Sep 17 00:00:00 2001 From: Release Manager Date: Thu, 29 Sep 2022 23:43:26 +0200 Subject: [PATCH 742/742] Updated SageMath version to 9.8.beta1 --- .zenodo.json | 8 ++++---- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/sage_conf/install-requires.txt | 2 +- build/pkgs/sage_docbuild/install-requires.txt | 2 +- build/pkgs/sage_setup/install-requires.txt | 2 +- build/pkgs/sage_sws2rst/install-requires.txt | 2 +- build/pkgs/sagelib/install-requires.txt | 2 +- build/pkgs/sagemath_categories/install-requires.txt | 2 +- build/pkgs/sagemath_environment/install-requires.txt | 2 +- build/pkgs/sagemath_objects/install-requires.txt | 2 +- build/pkgs/sagemath_repl/install-requires.txt | 2 +- pkgs/sage-conf/VERSION.txt | 2 +- pkgs/sage-conf_pypi/VERSION.txt | 2 +- pkgs/sage-docbuild/VERSION.txt | 2 +- pkgs/sage-setup/VERSION.txt | 2 +- pkgs/sage-sws2rst/VERSION.txt | 2 +- pkgs/sagemath-categories/VERSION.txt | 2 +- pkgs/sagemath-environment/VERSION.txt | 2 +- pkgs/sagemath-objects/VERSION.txt | 2 +- pkgs/sagemath-repl/VERSION.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 25 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index 06bf86e4065..999a424d8d2 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,10 +1,10 @@ { "description": "Mirror of the Sage https://sagemath.org/ source tree", "license": "other-open", - "title": "sagemath/sage: 9.8.beta0", - "version": "9.8.beta0", + "title": "sagemath/sage: 9.8.beta1", + "version": "9.8.beta1", "upload_type": "software", - "publication_date": "2022-09-25", + "publication_date": "2022-09-29", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.8.beta0", + "identifier": "https://github.com/sagemath/sage/tree/9.8.beta1", "relation": "isSupplementTo" }, { diff --git a/VERSION.txt b/VERSION.txt index 58778909bd8..5a632a27b46 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.8.beta0, Release Date: 2022-09-25 +SageMath version 9.8.beta1, Release Date: 2022-09-29 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 321fc772b79..53ac5f0f4d1 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=ab44e3d0f184a755c459c0d8f53267dbaaa11f22 -md5=d697c1d0ec53797eb738c5887e42147a -cksum=510253933 +sha1=73f9fe2ad9e2cfe224c7667a784144a1c520b9d8 +md5=8be336b502a66c5a410183be1eca2ca9 +cksum=42655200 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index fedd179981d..ac53b0e4214 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -e955bf1426c87765849016445fccd304066533d3 +51d49e23f3d3014e301fefcf72bf7a2a3fe0c4e0 diff --git a/build/pkgs/sage_conf/install-requires.txt b/build/pkgs/sage_conf/install-requires.txt index 35a8993af20..8e33acc92e6 100644 --- a/build/pkgs/sage_conf/install-requires.txt +++ b/build/pkgs/sage_conf/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 9.8b0 +sage-conf ~= 9.8b1 diff --git a/build/pkgs/sage_docbuild/install-requires.txt b/build/pkgs/sage_docbuild/install-requires.txt index 002c6b79c65..a2cc79f66c9 100644 --- a/build/pkgs/sage_docbuild/install-requires.txt +++ b/build/pkgs/sage_docbuild/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 9.8b0 +sage-docbuild ~= 9.8b1 diff --git a/build/pkgs/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt index 5720bc8f2c5..050098266b7 100644 --- a/build/pkgs/sage_setup/install-requires.txt +++ b/build/pkgs/sage_setup/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 9.8b0 +sage-setup ~= 9.8b1 diff --git a/build/pkgs/sage_sws2rst/install-requires.txt b/build/pkgs/sage_sws2rst/install-requires.txt index 70be4d731ee..ca58fa64648 100644 --- a/build/pkgs/sage_sws2rst/install-requires.txt +++ b/build/pkgs/sage_sws2rst/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 9.8b0 +sage-sws2rst ~= 9.8b1 diff --git a/build/pkgs/sagelib/install-requires.txt b/build/pkgs/sagelib/install-requires.txt index 359dff35670..82d6db622ed 100644 --- a/build/pkgs/sagelib/install-requires.txt +++ b/build/pkgs/sagelib/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagelib ~= 9.8b0 +sagelib ~= 9.8b1 diff --git a/build/pkgs/sagemath_categories/install-requires.txt b/build/pkgs/sagemath_categories/install-requires.txt index 070f8caa2ea..f5c2a080bae 100644 --- a/build/pkgs/sagemath_categories/install-requires.txt +++ b/build/pkgs/sagemath_categories/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 9.8b0 +sagemath-categories ~= 9.8b1 diff --git a/build/pkgs/sagemath_environment/install-requires.txt b/build/pkgs/sagemath_environment/install-requires.txt index e9976c7146f..5ac02d56d50 100644 --- a/build/pkgs/sagemath_environment/install-requires.txt +++ b/build/pkgs/sagemath_environment/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 9.8b0 +sagemath-environment ~= 9.8b1 diff --git a/build/pkgs/sagemath_objects/install-requires.txt b/build/pkgs/sagemath_objects/install-requires.txt index 0fb621f26f2..24f5473ae33 100644 --- a/build/pkgs/sagemath_objects/install-requires.txt +++ b/build/pkgs/sagemath_objects/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 9.8b0 +sagemath-objects ~= 9.8b1 diff --git a/build/pkgs/sagemath_repl/install-requires.txt b/build/pkgs/sagemath_repl/install-requires.txt index 40b60fa7bd0..9d91ae25d19 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 ~= 9.7b6 +sagemath-repl ~= 9.8b1 diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/src/VERSION.txt b/src/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 802ca805250..4f92b35ee39 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.8.beta0' -SAGE_RELEASE_DATE='2022-09-25' -SAGE_VERSION_BANNER='SageMath version 9.8.beta0, Release Date: 2022-09-25' +SAGE_VERSION='9.8.beta1' +SAGE_RELEASE_DATE='2022-09-29' +SAGE_VERSION_BANNER='SageMath version 9.8.beta1, Release Date: 2022-09-29' diff --git a/src/sage/version.py b/src/sage/version.py index 94cf8afef07..96d65f23372 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '9.8.beta0' -date = '2022-09-25' -banner = 'SageMath version 9.8.beta0, Release Date: 2022-09-25' +version = '9.8.beta1' +date = '2022-09-29' +banner = 'SageMath version 9.8.beta1, Release Date: 2022-09-29'