From e17bf65cd77e6a97de8ccb087d49b5bb83ab0ce8 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Wed, 12 Jul 2023 21:22:43 +0300 Subject: [PATCH 001/187] Implement .coefficients for GradedModularFormElement The `.coefficients` methods was missing from `GradedModularFormElement`, whereas it was implemented for `ModularFormElements`. This PR also fixes several tiny problems. --- src/sage/modular/modform/element.py | 53 ++++++++++++++++++----------- src/sage/modular/modform/ring.py | 39 +++++++++++++++++++++ 2 files changed, 73 insertions(+), 19 deletions(-) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 4d2123abab1..749629cd5b8 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -362,7 +362,7 @@ def coefficients(self, X): self.__coefficients except AttributeError: self.__coefficients = {} - if isinstance(X, Integer): + if isinstance(X, (int, Integer)): X = list(range(1, X + 1)) Y = [n for n in X if n not in self.__coefficients] v = self._compute(Y) @@ -2783,7 +2783,7 @@ def _compute_element(self): """ M = self.parent() S = M.cuspidal_subspace() -# return S.find_in_space( self.__E.q_expansion( S.q_expansion_basis()[0].prec() ) ) + [0] * ( M.dimension() - S.dimension() ) + # return S.find_in_space( self.__E.q_expansion( S.q_expansion_basis()[0].prec() ) ) + [0] * ( M.dimension() - S.dimension() ) return vector(S.find_in_space(self.__E.q_expansion(S.sturm_bound())) + [0] * (M.dimension() - S.dimension())) def _compute_q_expansion(self, prec): @@ -3392,6 +3392,30 @@ def q_expansion(self, prec=None): qexp = q_expansion # alias + def coefficients(self, X): + r""" + The coefficients a_n of self, for integers n>=0 in the list of X. If + X is an Integer, return coefficients for indices from 1 to X. + + TESTS:: + + sage: M = ModularFormsRing(1) + sage: E4 = M.0; E6 = M.1 + sage: F = E4 + E6 + sage: F.coefficients([0,1,3,6]) + [2, -264, -116256, -3997728] + sage: F.coefficients(10) + [-264, -14472, -116256, -515208, -1545264, -3997728, -8388672, -16907400, -29701992, -51719472] + sage: M = ModularFormsRing(13) + sage: (M.0^3).coefficients(range(10, 20)) + [22812, 36552, 57680, 85686, 126744, 177408, 249246, 332172, 448926, 575736] + """ + if isinstance(X, (int, Integer)): + return list(self.q_expansion(X + 1))[1:X + 1] + prec = max(X) + v = self.q_expansion(prec + 1) + return [v[x] for x in X] + def _repr_(self): r""" The string representation of self. @@ -3734,7 +3758,7 @@ def _homogeneous_to_polynomial(self, names, gens): return poly_parent(self[k]) # create the set of "weighted exponents" and compute sturm bound - weights_of_generators = [gens[i].weight() for i in range(0, len(gens))] + weights_of_generators = [gen.weight() for gen in gens] W = WeightedIntegerVectors(k, weights_of_generators).list() sturm_bound = self.group().sturm_bound(k) @@ -3742,18 +3766,9 @@ def _homogeneous_to_polynomial(self, names, gens): matrix_datum = [] # form the matrix of coefficients and list the monomials of weight k - list_of_monomials = [] - for exponents in W: - monomial_form = M.one() - monomial_poly = poly_parent.one() - iter = 0 - for e, g in zip(exponents, gens): - monomial_form *= M(g) ** e - monomial_poly *= poly_parent.gen(iter) ** e - iter += 1 - matrix_datum.append(monomial_form[k].coefficients(range(0, sturm_bound + 1))) - list_of_monomials.append(monomial_poly) - + monomial_forms = [prod(M(gen) ** exp for exp, gen in zip(exps, gens)) for exps in W] + monomial_polys = [prod(poly_gen ** exp for exp, poly_gen in zip(exps, poly_parent.gens())) for exps in W] + matrix_datum = M._to_matrix(monomial_forms, prec=sturm_bound) mat = Matrix(matrix_datum).transpose() # initialize the column vector of the coefficients of self @@ -3764,8 +3779,8 @@ def _homogeneous_to_polynomial(self, names, gens): # initialize the polynomial associated to self poly = poly_parent.zero() - for iter, p in enumerate(list_of_monomials): - poly += soln[iter, 0] * p + for i, p in enumerate(monomial_polys): + poly += soln[i, 0] * p return poly def to_polynomial(self, names='x', gens=None): @@ -3778,7 +3793,7 @@ def to_polynomial(self, names='x', gens=None): - ``names`` -- a list or tuple of names (strings), or a comma separated string. Correspond to the names of the variables; - ``gens`` -- (default: None) a list of generator of the parent of ``self``. If set to ``None``, - the list returned by :meth:`~sage.modular.modform.find_generator.ModularFormsRing.gen_forms` + the list returned by :meth:`~sage.modular.modform.ring.ModularFormsRing.gen_forms` is used instead OUTPUT: A polynomial in the variables ``names`` @@ -3791,7 +3806,7 @@ def to_polynomial(self, names='x', gens=None): sage: (M.0^10 + M.0 * M.1).to_polynomial() x0^10 + x0*x1 - This method is not necessarily the inverse of :meth:`~sage.modular.modform.find_generator.ModularFormsRing.from_polynomial` + This method is not necessarily the inverse of :meth:`~sage.modular.modform.ring.ModularFormsRing.from_polynomial` since there may be some relations between the generators of the modular forms ring:: sage: M = ModularFormsRing(Gamma0(6)) diff --git a/src/sage/modular/modform/ring.py b/src/sage/modular/modform/ring.py index 90e149340e4..731ba91befd 100644 --- a/src/sage/modular/modform/ring.py +++ b/src/sage/modular/modform/ring.py @@ -23,6 +23,7 @@ from random import shuffle from sage.categories.graded_algebras import GradedAlgebras +from sage.matrix.constructor import Matrix from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod from sage.misc.superseded import deprecated_function_alias @@ -1185,6 +1186,44 @@ def cuspidal_submodule_q_expansion_basis(self, weight, prec=None): R = G[0][1].parent() return [R(list(x), prec=prec) for x in W.gens()] + def _to_matrix(self, gens=None, prec=None): + r""" + Returns a matrix corresponding to the q-expansion of the generators to precision. + + INPUT: + + - ``gens`` -- (default: None) a list of generators. If set to ``None``, + the list returned by :meth:`~sage.modular.modform.ring.ModularFormsRing.gen_forms` + is used instead + - ``prec`` -- (default: None) precision to compute up to, or the Sturm + bound if ``prec`` is None. + + OUTPUT: A matrix. + + TESTS:: + + sage: M = ModularFormsRing(1) + sage: E4 = M.0; E6 = M.1 + sage: gens = [E4^3, E6^2] + """ + + if gens is None: + gens = self.gen_forms() + + if prec is None: + # we don't default to prec=6 because this is an internal function + # and is usually used to write other forms as a linear combination + # of generators, in which case using the Sturm bound is more reasonable + prec = 0 + for gen in gens: + prec = max(prec, gen.group().sturm_bound(gen.weight())) + + matrix_datum = [] + for gen in gens: + matrix_datum.append(gen.coefficients(range(0, prec + 1))) + + return Matrix(matrix_datum) + # Deprecated functions find_generators = deprecated_function_alias(31559, ModularFormsRing.generators) From e86d063bf81014f52a8170a4e2cee0f53877e717 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Fri, 14 Jul 2023 01:07:32 +0300 Subject: [PATCH 002/187] Implement raising modular forms to integer powers --- src/sage/modular/modform/element.py | 42 +++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 749629cd5b8..b92c8d3212c 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -2568,6 +2568,45 @@ def __mul__(self, other): return newparent.base_extend(newqexp.base_ring())(newqexp) + def _pow_int(self, n): + """ + Raises ``self`` to integer powers. + + TESTS:: + + sage: F = ModularForms(1, 12).0 + sage: (F**5).qexp(20) + q^5 - 120*q^6 + 7020*q^7 + O(q^8) + + Exponentiation is a lot faster than chain multiplication: + + sage: F = ModularForms(DirichletGroup(6).0, 3).0 + sage: G = F**8 # long time -- around 3 seconds + """ + # shamelessly copied from above + try: + eps = self.character() + verbose(f"character of self is {eps}") + newchar = eps ** n + verbose(f"character of product is {newchar}") + except (NotImplementedError, ValueError): + newchar = None + verbose("character of product not determined") + + from .constructor import ModularForms + if newchar is not None: + verbose("creating a parent with char") + newparent = ModularForms(newchar, self.weight() * n, + base_ring=newchar.base_ring()) + verbose("parent is %s" % newparent) + else: + newparent = ModularForms(self.group(), self.weight() * n, + base_ring=ZZ) + m = newparent.sturm_bound() + newqexp = self.qexp(m) ** n + + return newparent.base_extend(newqexp.base_ring())(newqexp) + def atkin_lehner_eigenvalue(self, d=None, embedding=None): """ Return the result of the Atkin-Lehner operator `W_d` on @@ -3572,6 +3611,9 @@ def _mul_(self, other): sage: F4 = M(f4); F6 = M(f6); sage: F4*F6 # indirect doctest 1 - 264*q - 135432*q^2 - 5196576*q^3 - 69341448*q^4 - 515625264*q^5 + O(q^6) + sage: E4 = EisensteinForms(1, 4).0 + sage: E4^2 + 1 + 480*q + 61920*q^2 + 1050240*q^3 + 7926240*q^4 + 37500480*q^5 + O(q^6) """ GM = self.__class__ f_self = self._forms_dictionary From 310356c382dcc9559c1785c86665f035fd4a2786 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Wed, 14 Feb 2024 21:38:11 +0000 Subject: [PATCH 003/187] general refactoring --- src/sage/modular/modform/element.py | 21 +++++++++--------- src/sage/modular/modform/ring.py | 33 +++++++++++++++-------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 226bc623f44..ffda5f3e1b5 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -2578,7 +2578,7 @@ def _pow_int(self, n): TESTS:: sage: F = ModularForms(1, 12).0 - sage: (F**5).qexp(20) + sage: (F^5).qexp(20) q^5 - 120*q^6 + 7020*q^7 - 266560*q^8 + 7379190*q^9 - 158562144*q^10 + 2748847640*q^11 - 39443189760*q^12 + 476711357265*q^13 - 4910778324400*q^14 + 43440479153652*q^15 - 331129448133120*q^16 + 2173189785854230*q^17 - 12199334429782080*q^18 + @@ -2587,7 +2587,7 @@ def _pow_int(self, n): Exponentiation is a lot faster than chain multiplication: sage: F = ModularForms(DirichletGroup(6).0, 3).0 - sage: G = F**8 # long time -- around 3 seconds + sage: G = F**8 # long time -- around 3 seconds """ # shamelessly copied from above try: @@ -2604,7 +2604,7 @@ def _pow_int(self, n): verbose("creating a parent with char") newparent = ModularForms(newchar, self.weight() * n, base_ring=newchar.base_ring()) - verbose("parent is %s" % newparent) + verbose(f"parent is {newparent}") else: newparent = ModularForms(self.group(), self.weight() * n, base_ring=ZZ) @@ -3847,11 +3847,11 @@ def to_polynomial(self, names='x', gens=None): INPUT: - - ``names`` -- a list or tuple of names (strings), or a comma separated string. Correspond - to the names of the variables; - - ``gens`` -- (default: None) a list of generator of the parent of ``self``. If set to ``None``, - the list returned by :meth:`~sage.modular.modform.ring.ModularFormsRing.gen_forms` - is used instead + - ``names`` -- a list or tuple of names (strings), or a comma separated string, + corresponding to the names of the variables. + - ``gens`` -- (default: None) a list of generator of the parent of ``self``. If set to + ``None``, the list returned by + :meth:`~sage.modular.modform.ring.ModularFormsRing.gen_forms` is used instead. OUTPUT: A polynomial in the variables ``names`` @@ -3863,8 +3863,9 @@ def to_polynomial(self, names='x', gens=None): sage: (M.0^10 + M.0 * M.1).to_polynomial() x0^10 + x0*x1 - This method is not necessarily the inverse of :meth:`~sage.modular.modform.ring.ModularFormsRing.from_polynomial` - since there may be some relations between the generators of the modular forms ring:: + This method is not necessarily the inverse of + :meth:`~sage.modular.modform.ring.ModularFormsRing.from_polynomial` since there may be some + relations between the generators of the modular forms ring:: sage: M = ModularFormsRing(Gamma0(6)) sage: P. = M.polynomial_ring() diff --git a/src/sage/modular/modform/ring.py b/src/sage/modular/modform/ring.py index 41d8a29e1eb..2e88849cb80 100644 --- a/src/sage/modular/modform/ring.py +++ b/src/sage/modular/modform/ring.py @@ -1189,15 +1189,15 @@ def cuspidal_submodule_q_expansion_basis(self, weight, prec=None): def _to_matrix(self, gens=None, prec=None): r""" - Returns a matrix corresponding to the q-expansion of the generators to precision. + Return a matrix corresponding to the `q`-expansion of the generators to the given precision. INPUT: - - ``gens`` -- (default: None) a list of generators. If set to ``None``, - the list returned by :meth:`~sage.modular.modform.ring.ModularFormsRing.gen_forms` - is used instead - - ``prec`` -- (default: None) precision to compute up to, or the Sturm - bound if ``prec`` is None. + - ``gens`` -- (default: ``None``) a list of generators. If not provided, + the list returned by :meth:`ModularFormsRing.gen_forms` + is used instead. + - ``prec`` -- (default: ``None``) precision to compute up to, or the Sturm + bound if not provided. OUTPUT: A matrix. @@ -1205,9 +1205,16 @@ def _to_matrix(self, gens=None, prec=None): sage: M = ModularFormsRing(1) sage: E4 = M.0; E6 = M.1 - sage: gens = [E4^3, E6^2] + sage: gens = [E4^3, E6^2]; gens + [1 + 720*q + 179280*q^2 + 16954560*q^3 + 396974160*q^4 + 4632858720*q^5 + O(q^6), + 1 - 1008*q + 220752*q^2 + 16519104*q^3 + 399517776*q^4 + 4624512480*q^5 + O(q^6)] + sage: M._to_matrix(gens) + [ 1 720] + [ 1 -1008] + sage: M._to_matrix(gens, 6) + [ 1 720 179280 16954560 396974160 4632858720 34413301440] + [ 1 -1008 220752 16519104 399517776 4624512480 34423752384] """ - if gens is None: gens = self.gen_forms() @@ -1215,15 +1222,9 @@ def _to_matrix(self, gens=None, prec=None): # we don't default to prec=6 because this is an internal function # and is usually used to write other forms as a linear combination # of generators, in which case using the Sturm bound is more reasonable - prec = 0 - for gen in gens: - prec = max(prec, gen.group().sturm_bound(gen.weight())) - - matrix_datum = [] - for gen in gens: - matrix_datum.append(gen.coefficients(range(0, prec + 1))) + prec = max(gen.group().sturm_bound(gen.weight()) for gen in gens) - return Matrix(matrix_datum) + return Matrix(gen.coefficients(range(prec + 1)) for gen in gens) # Deprecated functions From 709a32eaba14874cff8d3b9d32190303804e6537 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Tue, 20 Aug 2024 16:56:32 +0100 Subject: [PATCH 004/187] add doctests for modular form exponentiation --- src/sage/modular/modform/element.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 0984f51edd2..5e43e081d23 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -2580,11 +2580,23 @@ def _pow_int(self, n): 39443189760*q^12 + 476711357265*q^13 - 4910778324400*q^14 + 43440479153652*q^15 - 331129448133120*q^16 + 2173189785854230*q^17 - 12199334429782080*q^18 + 57636170473930920*q^19 + O(q^20) + sage: _ == (F.qexp(20)**5) + True + + Testing modular forms of nontrivial character:: + + sage: F = ModularForms(DirichletGroup(17).0^2,2).2 + sage: F3 = F^3; F3 + q^3 + (-3*zeta8^2 + 6)*q^4 + (-12*zeta8^2 + 3*zeta8 + 18)*q^5 + O(q^6) + sage: F3.qexp(6) == F.qexp(6)^3 + True + sage: F3.character() == F.character()^3 + True - Exponentiation is a lot faster than chain multiplication: + Testing modular forms of level greater than 1:: - sage: F = ModularForms(DirichletGroup(6).0, 3).0 - sage: G = F**8 # long time -- around 3 seconds + sage: for F in ModularForms(Gamma0(4), 2).gens(): + ....: assert (F**5).qexp(10) == F.qexp(10)**5 """ # shamelessly copied from above try: From e1addeb50efecbdc03e499a564f438463c41fa4e Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Tue, 20 Aug 2024 17:17:52 +0100 Subject: [PATCH 005/187] rewrite documentations --- src/sage/modular/modform/element.py | 33 +++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 5e43e081d23..6bbc087ce49 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -337,13 +337,18 @@ def _compute(self, X): return [q_exp[i] for i in X] def coefficients(self, X): - """ - The coefficients a_n of self, for integers n>=0 in the list - X. If X is an Integer, return coefficients for indices from 1 - to X. + r""" + Return the coefficients `a_n` of the `q`-expansion of this modular form. This function caches the results of the compute function. + INPUT: + + - ``X`` -- an iterator or an integer. If ``X`` is an iterator, a list + containing all `a_{X_i}` is returned. If ``X`` is an integer, it must + be positive, in which case the coefficients `a_1` to `a_X` are + returned in a list. + TESTS:: sage: e = DirichletGroup(11).gen() @@ -3443,10 +3448,16 @@ def q_expansion(self, prec=None): def coefficients(self, X): r""" - The coefficients a_n of self, for integers n>=0 in the list of X. If - X is an Integer, return coefficients for indices from 1 to X. + Return the coefficients `a_n` of the `q`-expansion of this modular form. - TESTS:: + INPUT: + + - ``X`` -- an iterator or an integer. If ``X`` is an iterator, a list + containing all `a_{X_i}` is returned. If ``X`` is an integer, it must + be positive, in which case the coefficients `a_1` to `a_X` are + returned in a list. + + EXAMPLES:: sage: M = ModularFormsRing(1) sage: E4 = M.0; E6 = M.1 @@ -3455,8 +3466,12 @@ def coefficients(self, X): [2, -264, -116256, -3997728] sage: F.coefficients(10) [-264, -14472, -116256, -515208, -1545264, -3997728, -8388672, -16907400, -29701992, -51719472] - sage: M = ModularFormsRing(13) - sage: (M.0^3).coefficients(range(10, 20)) + sage: assert _ == F.coefficients(range(1, 11)) == list(F.qexp(11))[1:] + + :: + + sage: F = ModularFormsRing(13).0 + sage: (F^3).coefficients(range(10, 20)) [22812, 36552, 57680, 85686, 126744, 177408, 249246, 332172, 448926, 575736] """ if isinstance(X, (int, Integer)): From c7381d7cb1982059f272cd365df72acbf8b967e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 9 Oct 2024 21:23:49 +0200 Subject: [PATCH 006/187] convert magma power series rings --- src/sage/ext_data/magma/sage/basic.m | 38 +++++++++++++++++++++----- src/sage/interfaces/magma.py | 40 +++++++++++++++------------- 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/src/sage/ext_data/magma/sage/basic.m b/src/sage/ext_data/magma/sage/basic.m index 678174dfd49..9af9c3f4714 100644 --- a/src/sage/ext_data/magma/sage/basic.m +++ b/src/sage/ext_data/magma/sage/basic.m @@ -8,7 +8,7 @@ function PreparseElts(R) end function; intrinsic Sage(X::.) -> MonStgElt, BoolElt -{Default way to convert a Magma object to Sage if we haven't +{Default way to convert a Magma object to Sage if we have not written anything better.} return Sprintf("%o", X), true; end intrinsic; @@ -153,16 +153,19 @@ intrinsic SageNamesHelper(X::.) -> MonStgElt {} /* XXX */ i := NumberOfNames(X); - if i ge 2 then - return (&* [ Sprintf("%o, ", X.j) : j in [ 1..i-1 ] ]) * Sprintf("%o", X.i); + if "$" in Sprint(X.i) then + /* unnamed variables */ + return "(" * (&* [ Sprintf("'x%o', ", j) : j in [ 1..i ] ]) * ")" else - return Sprintf("%o", X.i); - end if; + /* named variables */ + return "(" * (&* [ Sprintf("'%o', ", X.j) : j in [ 1..i ] ]) * ")" + end if: end intrinsic; intrinsic Sage(X::RngUPol) -> MonStgElt, BoolElt {} - return Sprintf("%o['%o'.replace('$.', 'x').replace('.', '')]", Sage(BaseRing(X)), SageNamesHelper(X)), false; + txt := "PolynomialRing(%o, %o)"; + return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; end intrinsic; intrinsic Sage(X::RngUPolElt) -> MonStgElt, BoolElt @@ -173,7 +176,8 @@ intrinsic Sage(X::RngUPolElt) -> MonStgElt, BoolElt intrinsic Sage(X::RngMPol) -> MonStgElt, BoolElt {} - return Sprintf("%o['%o'.replace('$.', 'x').replace('.', '')]", Sage(BaseRing(X)), SageNamesHelper(X)), false; + txt := "PolynomialRing(%o, %o)"; + return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; end intrinsic; intrinsic Sage(X::RngMPolElt) -> MonStgElt, BoolElt @@ -264,3 +268,23 @@ intrinsic Sage(X::ModTupRngElt) -> MonStgElt, BoolElt {} return Sprintf("%o(%o)", Sage(Parent(X)), Sage(ElementToSequence(X))), true; end intrinsic; + +/* Power series rings */ + +intrinsic Sage(X::RngSerPow) -> MonStgElt, BoolElt +{} + txt := "PowerSeriesRing(%o, %o)"; + return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; +end intrinsic; + +intrinsic Sage(X::RngSerLaur) -> MonStgElt, BoolElt +{} + txt := "LaurentSeriesRing(%o, %o)"; + return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; +end intrinsic; + +intrinsic Sage(X::RngSerPuis) -> MonStgElt, BoolElt +{} + txt := "PuiseuxSeriesRing(%o, %o)"; + return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; +end intrinsic; diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index 3ec584931cc..3b633244f41 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -221,11 +221,6 @@ from sage.structure.parent import Parent from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement -PROMPT = ">>>" - -SAGE_REF = "_sage_ref" -SAGE_REF_RE = re.compile(r'%s\d+' % SAGE_REF) - from sage.env import SAGE_EXTCODE, DOT_SAGE import sage.misc.misc import sage.misc.sage_eval @@ -233,15 +228,21 @@ from sage.interfaces.tab_completion import ExtraTabCompletion from sage.misc.instancedoc import instancedoc +PROMPT = ">>>" + +SAGE_REF = "_sage_ref" +SAGE_REF_RE = re.compile(r'%s\d+' % SAGE_REF) + INTRINSIC_CACHE = '%s/magma_intrinsic_cache.sobj' % DOT_SAGE EXTCODE_DIR = None -def extcode_dir(iface=None): +def extcode_dir(iface=None) -> str: """ - Return directory that contains all the Magma extcode. This is put - in a writable directory owned by the user, since when attached, - Magma has to write sig and lck files. + Return directory that contains all the Magma extcode. + + This is put in a writable directory owned by the user, since when + attached, Magma has to write sig and lck files. EXAMPLES:: @@ -413,7 +414,7 @@ def __reduce__(self): """ return reduce_load_Magma, tuple([]) - def _read_in_file_command(self, filename): + def _read_in_file_command(self, filename) -> str: """ Return the command in Magma that reads in the contents of the given file. @@ -433,7 +434,7 @@ def _read_in_file_command(self, filename): """ return 'load "%s";' % filename - def _post_process_from_file(self, s): + def _post_process_from_file(self, s) -> str: r""" Used internally in the Magma interface to post-process the result of evaluating a string using a file. For Magma what this does is @@ -462,7 +463,7 @@ def _post_process_from_file(self, s): return '' return s[i + 1:] - def __getattr__(self, attrname): + def __getattr__(self, attrname) -> MagmaFunction: """ Return a formal wrapper around a Magma function, or raise an :exc:`AttributeError` if attrname starts with an underscore. @@ -494,7 +495,7 @@ def __getattr__(self, attrname): raise AttributeError return MagmaFunction(self, attrname) - def eval(self, x, strip=True, **kwds): + def eval(self, x, strip=True, **kwds) -> str: """ Evaluate the given block x of code in Magma and return the output as a string. @@ -553,7 +554,7 @@ def eval(self, x, strip=True, **kwds): raise RuntimeError("Error evaluating Magma code.\nIN:%s\nOUT:%s" % (x, ans)) return ans - def _preparse(self, s): + def _preparse(self, s) -> str: """ All input gets preparsed by calling this function before it gets evaluated. @@ -578,7 +579,7 @@ def _preparse(self, s): pass return s - def _start(self): + def _start(self) -> None: """ Initialize a Magma interface instance. This involves (1) setting up an obfuscated prompt, and (2) attaching the MAGMA_SPEC file (see @@ -619,7 +620,7 @@ def set(self, var, value): if out.lower().find("error") != -1: raise TypeError("Error executing Magma code:\n%s" % out) - def get(self, var): + def get(self, var) -> str: """ Get the value of the variable var. @@ -1880,10 +1881,11 @@ def __getattr__(self, attrname): def _sage_(self): """ - Return Sage version of this object. Use self.sage() to get the Sage - version. + Return Sage version of this object. + + Use self.sage() to get the Sage version. - Edit src/ext/magma/sage/basic.m to add functionality. + Edit ``src/sage/ext_data/magma/sage/basic.m`` to add functionality. EXAMPLES: Enumerated Sets:: From 686462f2e56021e925d3438053c30537493e03db Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Wed, 20 Nov 2024 17:53:29 +0800 Subject: [PATCH 007/187] Remove SAGE_DB --- src/sage/graphs/isgci.py | 3 +-- src/sage/misc/all.py | 3 +-- src/sage/misc/all__sagemath_objects.py | 2 +- src/sage/misc/misc.py | 5 ----- src/sage/misc/persist.pyx | 24 ------------------------ 5 files changed, 3 insertions(+), 34 deletions(-) diff --git a/src/sage/graphs/isgci.py b/src/sage/graphs/isgci.py index f8bcf801d7e..d7e4a5aec55 100644 --- a/src/sage/graphs/isgci.py +++ b/src/sage/graphs/isgci.py @@ -857,8 +857,7 @@ def update_db(self): Depending on the credentials of the user running Sage when this command is run, one attempt is made at saving the result in Sage's directory so that all users can benefit from it. If the credentials are not - sufficient, the XML file are saved instead in the user's directory (in - the SAGE_DB folder). + sufficient, the XML file are saved instead in the user's directory. EXAMPLES:: diff --git a/src/sage/misc/all.py b/src/sage/misc/all.py index fa14ec98696..41112d9203e 100644 --- a/src/sage/misc/all.py +++ b/src/sage/misc/all.py @@ -9,8 +9,7 @@ exists, forall, is_iterator, random_sublist, pad_zeros, - SAGE_DB, - newton_method_sizes, compose, + newton_method_sizes, compose, nest) from sage.misc.banner import version diff --git a/src/sage/misc/all__sagemath_objects.py b/src/sage/misc/all__sagemath_objects.py index 634584c5567..2a7dee3b0d4 100644 --- a/src/sage/misc/all__sagemath_objects.py +++ b/src/sage/misc/all__sagemath_objects.py @@ -20,7 +20,7 @@ from sage.misc.flatten import flatten -from sage.misc.persist import save, load, dumps, loads, db, db_save +from sage.misc.persist import save, load, dumps, loads from sage.misc.constant_function import ConstantFunction diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index e5b3aed1ace..aeadd7b71f1 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -168,17 +168,12 @@ def try_read(obj, splitlines=False): return data - -SAGE_DB = os.path.join(DOT_SAGE, 'db') -os.makedirs(SAGE_DB, exist_ok=True) - try: # Create the matplotlib config directory. os.makedirs(os.environ["MPLCONFIGDIR"], exist_ok=True) except KeyError: pass - def exactly_one_is_true(iterable): r""" Return whether exactly one element of ``iterable`` evaluates ``True``. diff --git a/src/sage/misc/persist.pyx b/src/sage/misc/persist.pyx index 7429388112e..85d99fe6f87 100644 --- a/src/sage/misc/persist.pyx +++ b/src/sage/misc/persist.pyx @@ -1222,27 +1222,3 @@ def load_sage_element(cls, parent, dic_pic): X._set_parent(parent) X.__dict__ = SageUnpickler.loads(dic_pic) return X - - -def db(name): - r""" - Load object with given name from the Sage database. Use x.db(name) - or db_save(x, name) to save objects to the database. - - The database directory is ``$HOME/.sage/db``. - """ - from sage.misc.misc import SAGE_DB - return load('%s/%s' % (SAGE_DB, name)) - - -def db_save(x, name=None): - r""" - Save x to the Sage database. - - The database directory is ``$HOME/.sage/db``. - """ - try: - x.db(name) - except AttributeError: - from sage.misc.misc import SAGE_DB - save(x, '%s/%s' % (SAGE_DB, name)) From 66e972491a8aca28f13755b1f735fc0436a239d9 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 1 Dec 2024 13:25:03 +0530 Subject: [PATCH 008/187] added is_brace() --- src/sage/graphs/matching_covered_graph.py | 356 +++++++++++++++++++++- 1 file changed, 355 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 2a9b8916c90..fb335d9139c 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -107,7 +107,6 @@ :delim: | ``bricks_and_braces()`` | Return the list of (underlying simple graph of) the bricks and braces of the (matching covered) graph. - ``is_brace()`` | Check if the (matching covered) graph is a brace. ``is_brick()`` | Check if the (matching covered) graph is a brick. ``number_of_braces()`` | Return the number of braces. ``number_of_bricks()`` | Return the number of bricks. @@ -2003,6 +2002,361 @@ def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, raise ValueError('algorithm must be set to \'Edmonds\', ' '\'LP_matching\' or \'LP\'') + @doc_index('Bricks, braces and tight cut decomposition') + def is_brace(self, coNP_certificate=False): + r""" + Check if the (matching covered) graph is a brace. + + A matching covered graph which is free of nontrivial tight cuts is + called a *brace* if it is bipartite. Let `G := (A \cup B, E)` be a + bipartite matching covered graph on six or more vertices. The + following statements are equivalent [LM2024]_: + + 1. `G` is a brace (aka free of nontrivial tight cuts). + 2. `G - a_1 - a_2 - b_1 - b_2` has a perfect matching for any two + distinct vertices `a_1` and `a_2` in `A` and any two distinct + vertices `b_1` and `b_2` in `B`. + 3. `G` is two extendable (any two nonadjacent distinct edges can be + extended to some perfect matching of `G`). + 4. `|N(X)| \geq |X| + 2`, for all `X ⊂ A` such that `0 < |X| < + |A| - 1`, where `N(S) := \{b | (a, b) \in E ^ a \in S\}` is called + the neighboring set of `S`. + 5. `G - a - b` is matching covered, for some perfect matching `M` of + `G` and for each edge `ab` in `M`. + + We shall be using the 5th characterization mentioned above in order + to determine whether the provided bipartite matching covered graph + is a brace or not using *M*-alternating tree search [LZ2001]_. + + INPUT: + + - ``coNP_certificate`` -- boolean (default: ``False``) + + OUTPUT: + + - If the input matching covered graph is not bipartite, a + :exc:`ValueError` is returned. + + - If the input bipartite matching covered graph is a brace, a boolean + ``True`` is returned if ``coNP_certificate`` is set to ``False`` + otherwise a pair ``(True, None, None)`` is returned. + + - If the input bipartite matching covered graph is not a brace, a + boolean ``False`` is returned if ``coNP_certificate`` is set to + ``False`` otherwise a tuple of boolean ``False``, a list of + edges constituting a nontrivial tight cut and a set of vertices of + one of the shores of the nontrivial tight cut is returned. + + EXAMPLES: + + The complete graph on two vertices `K_2` is the smallest brace:: + + sage: K = graphs.CompleteGraph(2) + sage: G = MatchingCoveredGraph(K) + sage: G.is_brace() + True + + The cycle graph on four vertices `C_4` is a brace:: + + sage: C = graphs.CycleGraph(4) + sage: G = MatchingCoveredGraph(C) + sage: G.is_brace() + True + + Each graph that is isomorphic to a biwheel is a brace:: + + sage: B = graphs.BiwheelGraph(15) + sage: G = MatchingCoveredGraph(B) + sage: G.is_brace() + True + + A circular ladder graph on `2n` vertices for `n \equiv 0 (\mod 2)` is + a brace:: + + sage: n = 10 + sage: CL = graphs.CircularLadderGraph(n) + sage: G = MatchingCoveredGraph(CL) + sage: G.is_brace() + True + + A moebius ladder graph on `2n` vertices for `n \equiv 1 (\mod 2)` is + a brace:: + + sage: n = 11 + sage: ML = graphs.MoebiusLadderGraph(n) + sage: G = MatchingCoveredGraph(ML) + sage: G.is_brace() + True + + Note that the union of the above mentioned four families of braces, + that are: + 1. the biwheel graph ``BiwheelGraph(n)``, + 2. the circular ladder graph ``CircularLadderGraph(n)`` for even ``n``, + 3. the moebius ladder graph ``MoebiusLadderGraph(n)`` for odd ``n``, + is referred to as the *McCuaig* *family* *of* *braces.* + + The only simple brace of order six is the complete graph of the same + order, that is `K_{3, 3}`:: + + sage: L = list(graphs(6, + ....: lambda G: G.size() <= 15 and + ....: G.is_bipartite()) + ....: ) + sage: L = list(G for G in L if G.is_connected() and + ....: G.is_matching_covered() + ....: ) + sage: M = list(MatchingCoveredGraph(G) for G in L) + sage: B = list(G for G in M if G.is_brace()) + sage: K = graphs.CompleteBipartiteGraph(3, 3) + sage: G = MatchingCoveredGraph(K) + sage: next(iter(B)).is_isomorphic(G) + True + + The nonplanar `K_{3, 3}`-free brace Heawood graph is the unique cubic + graph of girth six with the fewest number of vertices (that is 14). + Note that by `K_{3, 3}`-free, it shows that the Heawood graph does not + contain a subgraph that is isomophic to a graph obtained by + bisubdivision of `K_{3, 3}`:: + + sage: K = graphs.CompleteBipartiteGraph(3, 3) + sage: J = graphs.HeawoodGraph() + sage: H = MatchingCoveredGraph(J) + sage: H.is_brace() and not H.is_planar() and \ + ....: H.is_regular(k=3) and H.girth() == 6 + True + + Braces of order six or more are 3-connected:: + + sage: H = graphs.HexahedralGraph() + sage: G = MatchingCoveredGraph(H) + sage: G.is_brace() and G.is_triconnected() + True + + Braces of order four or more are 2-extendable:: + + sage: H = graphs.EllinghamHorton54Graph() + sage: G = MatchingCoveredGraph(H) + sage: G.is_brace() + True + sage: e = next(G.edge_iterator(labels=False)); f = None + sage: for f in G.edge_iterator(labels=False): + ....: if not (set(e) & set(f)): + ....: break + sage: S = [u for x in [e, f] for u in set(x)] + sage: J = H.copy(); J.delete_vertices(S) + sage: M = Graph(J.matching()) + sage: M.add_edges([e, f]) + sage: if all(d == 1 for d in M.degree()) and \ + ....: G.order() == M.order() and \ + ....: G.order() == 2*M.size(): + ....: print(f'graph {G} is 2-extendable') + graph Ellingham-Horton 54-graph is 2-extendable + + Every edge in a brace of order at least six is removable:: + + sage: H = graphs.CircularLadderGraph(8) + sage: G = MatchingCoveredGraph(H) + sage: # len(G.removble_edges()) == G.size() + # True + + Every brace of order eight has the hexahedral graph as a spanning + subgraph:: + + sage: H = graphs.HexahedralGraph() + sage: L = list(graphs(8, + ....: lambda G: G.size() <= 28 and + ....: G.is_bipartite()) + ....: ) + sage: L = list(G for G in L if G.is_connected() and + ....: G.is_matching_covered() + ....: ) + sage: M = list(MatchingCoveredGraph(G) for G in L) + sage: B = list(G for G in M if G.is_brace()) + sage: C = list(G for G in M if Graph(G).subgraph_search(H) is not None) + sage: B == C + True + + For every brace `G[A, B]` of order at least six, the graph + `G - a_1 - a_2 - b_1 - b_2` has a perfect matching for any two distinct + vertices `a_1` and `a_2` in `A` and any two distinct vertices `b_1` and + `b_2` in `B`:: + + sage: H = graphs.CompleteBipartiteGraph(10, 10) + sage: G = MatchingCoveredGraph(H) + sage: G.is_brace() + True + sage: S = [0, 1, 10, 12] + sage: G.delete_vertices(S) + sage: G.has_perfect_matching() + True + + For a brace `G[A, B]` of order six or more, `|N(X)| \geq |X| + 2`, for + all `X \subset A` such that `0 < |X| <|A| - 1`, where + `N(S) := \{b | (a, b) \in E ^ a \in S\}` is called the neighboring set + of `S`:: + + sage: H = graphs.MoebiusLadderGraph(15) + sage: G = MatchingCoveredGraph(H) + sage: G.is_brace() + True + sage: A, _ = G.bipartite_sets() + sage: # needs random + sage: X = random.sample(list(A), random.randint(1, len(A) - 1)) + sage: N = {v for u in X for v in G.neighbor_iterator(u)} + sage: len(N) >= len(X) + 2 + True + + For a brace `G` of order four or more with a perfect matching `M`, the + graph `G - a - b` is matching covered for each edge `(a, b)` in `M`:: + + sage: H = graphs.HeawoodGraph() + sage: G = MatchingCoveredGraph(H) + sage: G.is_brace() + True + sage: M = G.get_matching() + sage: L = [] + sage: for a, b, *_ in M: + ....: J = G.copy(); J.delete_vertices([a, b]) + ....: if J.is_matching_covered(): + ....: L.append(J) + sage: len(L) == len(M) + True + + A cycle graph of order six of more is a bipartite matching covered + graph, but is not a brace:: + + sage: C = graphs.CycleGraph(10) + sage: G = MatchingCoveredGraph(C) + sage: G.is_brace() + False + + One may set the ``coNP_certificate`` to be ``True``:: + + sage: H = graphs.HexahedralGraph() + sage: G = MatchingCoveredGraph(H) + sage: G.is_brace(coNP_certificate=True) + (True, None, None) + sage: C = graphs.CycleGraph(6) + sage: D = MatchingCoveredGraph(C) + sage: D.is_brace(coNP_certificate=True) + (False, [(0, 5, None), (2, 3, None)], {0, 1, 2}) + + If the input matching covered graph is nonbipartite, a + :exc:`ValueError` is thrown:: + + sage: K4 = graphs.CompleteGraph(4) + sage: G = MatchingCoveredGraph(K4) + sage: G.is_brace() + Traceback (most recent call last): + ... + ValueError: the input graph is not bipartite + sage: P = graphs.PetersenGraph() + sage: H = MatchingCoveredGraph(P) + sage: H.is_brace(coNP_certificate=True) + Traceback (most recent call last): + ... + ValueError: the input graph is not bipartite + """ + if not self.is_bipartite(): + raise ValueError('the input graph is not bipartite') + + if self.order() < 6: + return (True, None) if coNP_certificate else True + + color = {u: 0 if u in self.bipartite_sets()[0] else 1 for u in self} + matching = set(self.get_matching()) + matching_neighbor = {x: y for u, v, *_ in self.get_matching() for x, y in [(u, v), (v, u)]} + + for e in list(self.get_matching())[:]: + u, v, *_ = e + + # Let G denote the undirected graph self, and + # let the graph H(e) := G — u — v + H = Graph(self, multiedges=False) + H.delete_vertices([u, v]) + + if not H.is_matching_covered(list(matching - set([e]))): + if not coNP_certificate: + return False + + # Construct the digraph D(e)(A ∪ B, F) defined as follows: + from sage.graphs.digraph import DiGraph + D = DiGraph() + + # For each edge (a, b) in E(H(e)) ∩ M with a in A, b —> a in D(e). + # For each edge (a, b) in E(H(e)) with a in A, a —> b in D(e). + for a, b, *_ in H.edge_iterator(): + + if color[a]: + a, b = b, a + + D.add_edge((a, b)) + if matching_neighbor[a] == b: + D.add_edge((b, a)) + + D.show() + + # H(e) is matching covered iff D(e) is strongly connected. + # Check if D(e) is strongly connected using Kosaraju's algorithm + def dfs(J, v, visited, orientation): + stack = [v] # a stack of vertices + + while stack: + v = stack.pop() + + if v not in visited: + visited[v] = True + + if orientation == 'in': + for u in J.neighbors_out(v): + if u not in visited: + stack.append(u) + + elif orientation == 'out': + for u in J.neighbors_in(v): + if u not in visited: + stack.append(u) + else: + raise ValueError('Unknown orientation') + + root = next(D.vertex_iterator()) + + visited_in = {} + dfs(D, root, visited_in, 'in') + + visited_out = {} + dfs(D, root, visited_out, 'out') + + # Note that by definition of D(e), it follows that C ⊆ E(H(e)) — M. + # Thus, C is a cut of H(e), which has a shore X such that every edge of C is + # incident with a vertex in X ∩ B. + + # Moreover, M — e is a perfect matching of H(e), and thus, |X ∩ A| = |X ∩ B| + # Consequently, Y := X + v is a shore of a nontrivial tight cut T of G + + if not all(visited_in.values()): + X = {w for w in D if w in visited_in} + else: + X = {w for w in D if w in visited_out} + + # Compute the directed cut C of D(e) + C = [] + for a, b, *_ in H.edge_iterator(): + if (a in X) ^ (b in X): # Exclusive OR: one in X, the other not + x, y = (a, b) if color[a] == 0 else (b, a) + C.append([x, y]) + + # Obtain the color class Z ∈ {A, B} such that X ∩ Z is a vertex cover for C + color_class = 1 if C[0][0] not in X else 0 + X.add(u if (not color_class and color[v]) or (color_class and color[u]) else v) + + # Compute the nontrivial tight cut T := ∂(X) + T = [f for f in self.edge_iterator() if (f[0] in X) ^ (f[1] in X)] + + return False, T, X + + return (True, None, None) if coNP_certificate else True + @doc_index('Miscellaneous methods') def update_matching(self, matching): r""" From 86bd2e91c82568a38f1831540a2b0cd5c1bda0b5 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 1 Dec 2024 13:26:05 +0530 Subject: [PATCH 009/187] updated the to do list --- src/sage/graphs/matching_covered_graph.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index fb335d9139c..85209f81930 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -72,6 +72,7 @@ ``loop_edges()`` | Return a list of all loops in the matching covered graph. ``loop_vertices()`` | Return a list of vertices with loops. ``merge_vertices()`` | Merge vertices. + ``minor()`` | Return the vertices of a minor isomorphic to `H` in the current graph. ``number_of_loops()`` | Return the number of edges that are loops. ``random_subgraph()`` | Return a random matching covered subgraph containing each vertex with probability ``p``. ``remove_loops()`` | Remove loops on vertices in ``vertices``. @@ -85,6 +86,7 @@ ``subgraph_search_iterator()`` | Return an iterator over the labelled copies of (matching covered) ``G`` in ``self``. ``tensor_product()`` | Return the tensor product of ``self`` and ``other``. ``to_undirected()`` | Return an undirected Graph instance of the matching covered graph. + ``topological_minor()`` | Return a topological `H`-minor from ``self`` if one exists. ``transitive_closure()`` | Return the transitive closure of the matching covered graph. ``transitive_reduction()`` | Return a transitive reduction of the matching covered graph. ``union()`` | Return the union of ``self`` and ``other``. From dc47497c7a8aa35229a2f2692b558e829b63a192 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 1 Dec 2024 13:27:04 +0530 Subject: [PATCH 010/187] updated the digraph H --- src/sage/graphs/matching.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/matching.py b/src/sage/graphs/matching.py index c8eea2bb005..79dd5eeb19a 100644 --- a/src/sage/graphs/matching.py +++ b/src/sage/graphs/matching.py @@ -1019,10 +1019,9 @@ def is_matching_covered(G, matching=None, algorithm='Edmonds', coNP_certificate= if color[u]: u, v = v, u - if M.has_edge(u, v): - H.add_edge(u, v) - else: - H.add_edge(v, u) + H.add_edge((u, v)) + if next(M.neighbor_iterator(u)) == v: + H.add_edge((v, u)) # Check if H is strongly connected using Kosaraju's algorithm def dfs(J, v, visited, orientation): From e5d74e288f5b0997235ca6d3e274c3f4ba33c3c5 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 1 Dec 2024 13:28:30 +0530 Subject: [PATCH 011/187] updated the doctest --- src/sage/graphs/matching.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/matching.py b/src/sage/graphs/matching.py index 79dd5eeb19a..df1b8e8d979 100644 --- a/src/sage/graphs/matching.py +++ b/src/sage/graphs/matching.py @@ -877,7 +877,7 @@ def is_matching_covered(G, matching=None, algorithm='Edmonds', coNP_certificate= sage: H = graphs.PathGraph(20) sage: M = H.matching() sage: H.is_matching_covered(matching=M, coNP_certificate=True) - (False, (1, 2, None)) + (False, (2, 1, None)) TESTS: From 4b438976d2a8602d3225fbe0ced7d9b7ec43a493 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 1 Dec 2024 17:08:58 +0530 Subject: [PATCH 012/187] updated is_matching_covered() --- src/sage/graphs/matching.py | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/sage/graphs/matching.py b/src/sage/graphs/matching.py index df1b8e8d979..66e87683be8 100644 --- a/src/sage/graphs/matching.py +++ b/src/sage/graphs/matching.py @@ -1024,38 +1024,28 @@ def is_matching_covered(G, matching=None, algorithm='Edmonds', coNP_certificate= H.add_edge((v, u)) # Check if H is strongly connected using Kosaraju's algorithm - def dfs(J, v, visited, orientation): + def dfs(v, visited, neighbor_iterator): stack = [v] # a stack of vertices while stack: v = stack.pop() + visited.add(v) - if v not in visited: - visited[v] = True - - if orientation == 'in': - for u in J.neighbors_out(v): - if u not in visited: - stack.append(u) - - elif orientation == 'out': - for u in J.neighbors_in(v): - if u not in visited: - stack.append(u) - else: - raise ValueError('Unknown orientation') + for u in neighbor_iterator(v): + if u not in visited: + stack.append(u) root = next(H.vertex_iterator()) - visited_in = {} - dfs(H, root, visited_in, 'in') + visited_in = set() + dfs(root, visited_in, H.neighbor_in_iterator) - visited_out = {} - dfs(H, root, visited_out, 'out') + visited_out = set() + dfs(root, visited_out, H.neighbor_out_iterator) for edge in H.edge_iterator(): u, v, _ = edge - if (u not in visited_in) or (v not in visited_out): + if (u not in visited_out) or (v not in visited_in): if not M.has_edge(edge): return (False, edge) if coNP_certificate else False From 0eb894d871b90af7f62b90a1e83f17b121231127 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 1 Dec 2024 17:09:23 +0530 Subject: [PATCH 013/187] updated is_brace() --- src/sage/graphs/matching_covered_graph.py | 42 ++++++++--------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 85209f81930..b398a672abe 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2263,9 +2263,9 @@ def is_brace(self, coNP_certificate=False): raise ValueError('the input graph is not bipartite') if self.order() < 6: - return (True, None) if coNP_certificate else True + return (True, None, None) if coNP_certificate else True - color = {u: 0 if u in self.bipartite_sets()[0] else 1 for u in self} + A, B = self.bipartite_sets() matching = set(self.get_matching()) matching_neighbor = {x: y for u, v, *_ in self.get_matching() for x, y in [(u, v), (v, u)]} @@ -2289,45 +2289,33 @@ def is_brace(self, coNP_certificate=False): # For each edge (a, b) in E(H(e)) with a in A, a —> b in D(e). for a, b, *_ in H.edge_iterator(): - if color[a]: + if a in B: a, b = b, a D.add_edge((a, b)) if matching_neighbor[a] == b: D.add_edge((b, a)) - D.show() - # H(e) is matching covered iff D(e) is strongly connected. # Check if D(e) is strongly connected using Kosaraju's algorithm - def dfs(J, v, visited, orientation): + def dfs(v, visited, neighbor_iterator): stack = [v] # a stack of vertices while stack: v = stack.pop() + visited.add(v) - if v not in visited: - visited[v] = True - - if orientation == 'in': - for u in J.neighbors_out(v): - if u not in visited: - stack.append(u) - - elif orientation == 'out': - for u in J.neighbors_in(v): - if u not in visited: - stack.append(u) - else: - raise ValueError('Unknown orientation') + for u in neighbor_iterator(v): + if u not in visited: + stack.append(u) root = next(D.vertex_iterator()) - visited_in = {} - dfs(D, root, visited_in, 'in') + visited_in = set() + dfs(root, visited_in, D.neighbor_in_iterator) - visited_out = {} - dfs(D, root, visited_out, 'out') + visited_out = set() + dfs(root, visited_out, D.neighbor_out_iterator) # Note that by definition of D(e), it follows that C ⊆ E(H(e)) — M. # Thus, C is a cut of H(e), which has a shore X such that every edge of C is @@ -2336,7 +2324,7 @@ def dfs(J, v, visited, orientation): # Moreover, M — e is a perfect matching of H(e), and thus, |X ∩ A| = |X ∩ B| # Consequently, Y := X + v is a shore of a nontrivial tight cut T of G - if not all(visited_in.values()): + if len(visited_in) != D.order(): X = {w for w in D if w in visited_in} else: X = {w for w in D if w in visited_out} @@ -2345,12 +2333,12 @@ def dfs(J, v, visited, orientation): C = [] for a, b, *_ in H.edge_iterator(): if (a in X) ^ (b in X): # Exclusive OR: one in X, the other not - x, y = (a, b) if color[a] == 0 else (b, a) + x, y = (a, b) if a in A else (b, a) C.append([x, y]) # Obtain the color class Z ∈ {A, B} such that X ∩ Z is a vertex cover for C color_class = 1 if C[0][0] not in X else 0 - X.add(u if (not color_class and color[v]) or (color_class and color[u]) else v) + X.add(u if (not color_class and u in A) or (color_class and u in B) else v) # Compute the nontrivial tight cut T := ∂(X) T = [f for f in self.edge_iterator() if (f[0] in X) ^ (f[1] in X)] From 451f1643382898e52d25fbc7040f783fc04a429c Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 1 Dec 2024 17:16:18 +0530 Subject: [PATCH 014/187] removed an unnecessary space --- src/sage/graphs/matching_covered_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index b398a672abe..f148784d264 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2265,7 +2265,7 @@ def is_brace(self, coNP_certificate=False): if self.order() < 6: return (True, None, None) if coNP_certificate else True - A, B = self.bipartite_sets() + A, B = self.bipartite_sets() matching = set(self.get_matching()) matching_neighbor = {x: y for u, v, *_ in self.get_matching() for x, y in [(u, v), (v, u)]} From 74ea0275aa41c7dda1e87817c44ac8c846d71a1d Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 1 Dec 2024 17:23:29 +0530 Subject: [PATCH 015/187] updated the documentation --- src/sage/graphs/matching_covered_graph.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index f148784d264..d96181a5d7d 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2021,7 +2021,7 @@ def is_brace(self, coNP_certificate=False): 3. `G` is two extendable (any two nonadjacent distinct edges can be extended to some perfect matching of `G`). 4. `|N(X)| \geq |X| + 2`, for all `X ⊂ A` such that `0 < |X| < - |A| - 1`, where `N(S) := \{b | (a, b) \in E ^ a \in S\}` is called + |A| - 1`, where `N(S) := \{b | (a, b) \in E \^ a \in S\}` is called the neighboring set of `S`. 5. `G - a - b` is matching covered, for some perfect matching `M` of `G` and for each edge `ab` in `M`. @@ -2092,9 +2092,11 @@ def is_brace(self, coNP_certificate=False): Note that the union of the above mentioned four families of braces, that are: + 1. the biwheel graph ``BiwheelGraph(n)``, 2. the circular ladder graph ``CircularLadderGraph(n)`` for even ``n``, 3. the moebius ladder graph ``MoebiusLadderGraph(n)`` for odd ``n``, + is referred to as the *McCuaig* *family* *of* *braces.* The only simple brace of order six is the complete graph of the same @@ -2194,7 +2196,7 @@ def is_brace(self, coNP_certificate=False): For a brace `G[A, B]` of order six or more, `|N(X)| \geq |X| + 2`, for all `X \subset A` such that `0 < |X| <|A| - 1`, where - `N(S) := \{b | (a, b) \in E ^ a \in S\}` is called the neighboring set + `N(S) := \{b | (a, b) \in E \^ a \in S\}` is called the neighboring set of `S`:: sage: H = graphs.MoebiusLadderGraph(15) From 9c3936becb79511807236c72320e5b8ebfda1783 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 1 Dec 2024 19:55:09 +0530 Subject: [PATCH 016/187] updated is_brace() --- src/sage/graphs/matching_covered_graph.py | 36 +++++++++++------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index d96181a5d7d..b53b52cabeb 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2271,7 +2271,7 @@ def is_brace(self, coNP_certificate=False): matching = set(self.get_matching()) matching_neighbor = {x: y for u, v, *_ in self.get_matching() for x, y in [(u, v), (v, u)]} - for e in list(self.get_matching())[:]: + for e in matching: u, v, *_ = e # Let G denote the undirected graph self, and @@ -2316,36 +2316,34 @@ def dfs(v, visited, neighbor_iterator): visited_in = set() dfs(root, visited_in, D.neighbor_in_iterator) - visited_out = set() - dfs(root, visited_out, D.neighbor_out_iterator) - - # Note that by definition of D(e), it follows that C ⊆ E(H(e)) — M. - # Thus, C is a cut of H(e), which has a shore X such that every edge of C is + # Since D(e) is not strongly connected, it has a directed cut T(e). + # Note that by definition of D(e), it follows that T(e) ⊆ E(H(e)) — M. + # Thus, T(e) is a cut of H(e), which has a shore X such that every edge of T(e) is # incident with a vertex in X ∩ B. # Moreover, M — e is a perfect matching of H(e), and thus, |X ∩ A| = |X ∩ B| # Consequently, Y := X + v is a shore of a nontrivial tight cut T of G if len(visited_in) != D.order(): - X = {w for w in D if w in visited_in} + X = visited_in else: - X = {w for w in D if w in visited_out} + X = set() + dfs(root, X, D.neighbor_out_iterator) - # Compute the directed cut C of D(e) - C = [] - for a, b, *_ in H.edge_iterator(): - if (a in X) ^ (b in X): # Exclusive OR: one in X, the other not - x, y = (a, b) if a in A else (b, a) - C.append([x, y]) + for a, b in H.edge_iterator(labels=False): + if (a in X) ^ (b in X): + x = a if a in A else b + color_class = x not in X + break - # Obtain the color class Z ∈ {A, B} such that X ∩ Z is a vertex cover for C - color_class = 1 if C[0][0] not in X else 0 + # Obtain the color class Z ∈ {A, B} such that X ∩ Z is a vertex cover for T(e) + # Thus, obtain Y := X + v X.add(u if (not color_class and u in A) or (color_class and u in B) else v) - # Compute the nontrivial tight cut T := ∂(X) - T = [f for f in self.edge_iterator() if (f[0] in X) ^ (f[1] in X)] + # Compute the nontrivial tight cut C := ∂(Y) + C = [f for f in self.edge_iterator() if (f[0] in X) ^ (f[1] in X)] - return False, T, X + return False, C, X return (True, None, None) if coNP_certificate else True From 430b837d76d9f6132988e6bbe096438612932230 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Mon, 2 Dec 2024 08:20:22 +0530 Subject: [PATCH 017/187] updated is_brace() --- src/sage/graphs/matching_covered_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index b53b52cabeb..f702074d1c8 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2269,7 +2269,7 @@ def is_brace(self, coNP_certificate=False): A, B = self.bipartite_sets() matching = set(self.get_matching()) - matching_neighbor = {x: y for u, v, *_ in self.get_matching() for x, y in [(u, v), (v, u)]} + matching_neighbor = {x: y for u, v, *_ in matching for x, y in [(u, v), (v, u)]} for e in matching: u, v, *_ = e From b1b8b8b2955e2cc089b51ee0b0edea50addab58d Mon Sep 17 00:00:00 2001 From: Janmenjaya Panda <83154020+janmenjayap@users.noreply.github.com> Date: Thu, 5 Dec 2024 22:17:06 +0530 Subject: [PATCH 018/187] Updated math expression formatting Co-authored-by: user202729 <25191436+user202729@users.noreply.github.com> --- src/sage/graphs/matching_covered_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index f702074d1c8..71aabbbc0e0 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2021,7 +2021,7 @@ def is_brace(self, coNP_certificate=False): 3. `G` is two extendable (any two nonadjacent distinct edges can be extended to some perfect matching of `G`). 4. `|N(X)| \geq |X| + 2`, for all `X ⊂ A` such that `0 < |X| < - |A| - 1`, where `N(S) := \{b | (a, b) \in E \^ a \in S\}` is called + |A| - 1`, where `N(S) := \{b \mid (a, b) \in E ∧ a \in S\}` is called the neighboring set of `S`. 5. `G - a - b` is matching covered, for some perfect matching `M` of `G` and for each edge `ab` in `M`. From 9f29ad96e7359998e06179e9d4051028c9edc450 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 9 Dec 2024 21:01:14 +0800 Subject: [PATCH 019/187] Readd db/db_save as deprecated methods --- src/sage/misc/all__sagemath_objects.py | 2 +- src/sage/misc/persist.pyx | 30 +++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/all__sagemath_objects.py b/src/sage/misc/all__sagemath_objects.py index 2a7dee3b0d4..634584c5567 100644 --- a/src/sage/misc/all__sagemath_objects.py +++ b/src/sage/misc/all__sagemath_objects.py @@ -20,7 +20,7 @@ from sage.misc.flatten import flatten -from sage.misc.persist import save, load, dumps, loads +from sage.misc.persist import save, load, dumps, loads, db, db_save from sage.misc.constant_function import ConstantFunction diff --git a/src/sage/misc/persist.pyx b/src/sage/misc/persist.pyx index 02a12469ed2..d9a460c4c6e 100644 --- a/src/sage/misc/persist.pyx +++ b/src/sage/misc/persist.pyx @@ -44,7 +44,7 @@ comp = zlib comp_other = bz2 from sage.misc.sage_unittest import TestSuite - +from sage.misc.superseded import deprecation # We define two global dictionaries `already_pickled` and # `already_unpickled`, which are intended to help you to implement @@ -1222,3 +1222,31 @@ def load_sage_element(cls, parent, dic_pic): X._set_parent(parent) X.__dict__ = SageUnpickler.loads(dic_pic) return X + + +def db(name): + r""" + Load object with given name from the Sage database. Use x.db(name) + or db_save(x, name) to save objects to the database. + + The database directory is ``$HOME/.sage/db``. + """ + deprecation(39012, "Directly use pickle/unpickle instead of db/db_save.") + + from sage.misc.misc import SAGE_DB + return load('%s/%s' % (SAGE_DB, name)) + + +def db_save(x, name=None): + r""" + Save x to the Sage database. + + The database directory is ``$HOME/.sage/db``. + """ + deprecation(39012, "Directly use pickle/unpickle instead of db/db_save.") + + try: + x.db(name) + except AttributeError: + from sage.misc.misc import SAGE_DB + save(x, '%s/%s' % (SAGE_DB, name)) From 3ae8d63177a38982973e2cfaad5f6abe1e3cdd5e Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 9 Dec 2024 21:01:34 +0800 Subject: [PATCH 020/187] Improve comment about isgci database location --- src/sage/graphs/isgci.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/isgci.py b/src/sage/graphs/isgci.py index d7e4a5aec55..a0cea704e32 100644 --- a/src/sage/graphs/isgci.py +++ b/src/sage/graphs/isgci.py @@ -852,12 +852,8 @@ def update_db(self): This method downloads the ISGCI database from the website `GraphClasses.org `_. It then extracts the - zip file and parses its XML content. - - Depending on the credentials of the user running Sage when this command - is run, one attempt is made at saving the result in Sage's directory so - that all users can benefit from it. If the credentials are not - sufficient, the XML file are saved instead in the user's directory. + zip file and parses its XML content. The XML file is saved in the directory + controlled by the :class:`DatabaseGraphs` class (usually, ``$HOME/.sage/db``). EXAMPLES:: From c9902bea46a2b753ae7d256874de52edb6518132 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 9 Dec 2024 21:58:56 +0800 Subject: [PATCH 021/187] fix linter --- src/sage/misc/misc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index aeadd7b71f1..f7119920be2 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -174,6 +174,7 @@ def try_read(obj, splitlines=False): except KeyError: pass + def exactly_one_is_true(iterable): r""" Return whether exactly one element of ``iterable`` evaluates ``True``. From d319860597025df02396423c7c18e941471d0de8 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Fri, 13 Dec 2024 15:41:12 +0530 Subject: [PATCH 022/187] added is_brick() --- src/sage/graphs/matching_covered_graph.py | 99 ++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index a7d1904df9f..21374d90f20 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -94,7 +94,6 @@ :delim: | ``bricks_and_braces()`` | Return the list of (underlying simple graph of) the bricks and braces of the (matching covered) graph. - ``is_brick()`` | Check if the (matching covered) graph is a brick. ``number_of_braces()`` | Return the number of braces. ``number_of_bricks()`` | Return the number of bricks. ``number_of_petersen_bricks()`` | Return the number of Petersen bricks. @@ -2690,6 +2689,104 @@ def dfs(v, visited, neighbor_iterator): return (True, None, None) if coNP_certificate else True + + @doc_index('Bricks, braces and tight cut decomposition') + def is_brick(self, coNP_certificate=False): + r""" + Check if the (matching covered) graph is a brick. + + A matching covered graph which is free of nontrivial tight cuts is + called a *brick* if it is nonbipartite. A nonbipartite matching covered + graph is a brick if and only if it is 3-connected and bicritical + [LM2024]_. + + .. SEEALSO:: + + :meth:`~sage.graphs.graph.Graph.is_bicritical` + """ + if self.is_bipartite(): + raise ValueError('the input graph is bipartite') + + # Check if G is bicritical + bicritical, certificate = self.is_bicritical(coNP_certificate=True) + + if not bicritical: + if not coNP_certificate: + return False + + # G has a pair of vertices u, v such that G - u - v is not matching + # covered, thus has a nontrivial barrier B containing both u and v. + u, _ = certificate + B = self.maximal_barrier(u) + + H = Graph(self) + H.delete_vertices(B) + + # Let K be a nontrivial odd component of H := G - B. Note that + # there exists at least one such K since G is nonbipartite + nontrivial_odd_component = next( + (component for component in H.connected_components() + if len(component) % 2 and len(component) > 1), None + ) + + # Find a nontrivial barrier cut + C = [(u, v, w) if u in nontrivial_odd_component else (v, u, w) + for u, v, w in self.edge_iterator() + if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] + + return False, C, nontrivial_odd_component + + # Check if G is 3-connected + if self.is_triconnected(): + return (True, None, None) if coNP_certificate else True + + # G has a 2-vertex cut + # Compute the SPQR-tree decomposition + spqr_tree = self.spqr_tree() + two_vertex_cut = [] + + # Check for 2-vertex cuts in P and S nodes + for u in spqr_tree: + if u[0] == 'P': + two_vertex_cut.extend(u[1].vertices()) + break + elif u[0] == 'S' and u[1].order() > 3: + s_vertex_set = set(u[1].vertices()) + for v in u[1].vertices(): + s_vertex_set -= {v} | set(u[1].neighbors(v)) + two_vertex_cut.extend([v, next(iter(s_vertex_set))]) + break + + # If no 2-vertex cut found, look for R nodes + if not two_vertex_cut: + R_frequency = {u: 0 for u in self} + for u in spqr_tree.vertices(): + if u[0] == 'R': + for v in u[1].vertices(): + R_frequency[v] += 1 + two_vertex_cut = [u for u in self if R_frequency[u] >= 2][:2] + + # We obtain a 2-vertex cut (u, v) + H = Graph(self) + H.delete_vertices(two_vertex_cut) + + # Check if all components of H are odd + components = H.connected_components() + are_all_odd_components = all(len(c) % 2 for c in components) + + # Find a nontrivial odd component + if are_all_odd_components: + nontrivial_odd_component = next((c for c in components if len(c) > 1), None) + else: + nontrivial_odd_component = components[0] + [two_vertex_cut[0]] + + C = [(u, v, w) if u in nontrivial_odd_component else (v, u, w) + for u, v, w in self.edge_iterator() + if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] + + # Edge (u, v, w) in C are formatted so that u is in a nontrivial odd component + return (False, C, nontrivial_odd_component) if coNP_certificate else False + @doc_index('Overwritten methods') def loop_edges(self, labels=True): r""" From 564cbbbc71f7f3e3e1a73778bca2c993c89539bd Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Fri, 13 Dec 2024 15:41:48 +0530 Subject: [PATCH 023/187] updated is_brace() --- src/sage/graphs/matching_covered_graph.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 21374d90f20..58d39a8b938 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2683,7 +2683,9 @@ def dfs(v, visited, neighbor_iterator): X.add(u if (not color_class and u in A) or (color_class and u in B) else v) # Compute the nontrivial tight cut C := ∂(Y) - C = [f for f in self.edge_iterator() if (f[0] in X) ^ (f[1] in X)] + C = [(u, v, w) if u in X else (v, u, w) + for u, v, w in self.edge_iterator() + if (u in X) ^ (v in X)] return False, C, X From e23375ff081dc3a179317cf5c4ac5b63c0dfd8e7 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:19:05 +0700 Subject: [PATCH 024/187] Minor refactor for is_exact --- src/sage/matrix/matrix_space.py | 18 ++++++++++++++++++ src/sage/modules/free_module.py | 18 ++++++++++++++++++ src/sage/rings/ring.pyx | 23 ----------------------- src/sage/structure/parent.pyx | 6 +++--- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 2ba59292d54..ae116fb0b66 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -955,6 +955,24 @@ def characteristic(self): """ return self.base_ring().characteristic() + def is_exact(self): + """ + Test whether elements of this matrix space is exact. + + OUTPUT: + + Return ``True`` if elements of this matrix space are represented exactly, i.e., + there is no precision loss when doing arithmetic. + + EXAMPLES:: + + sage: MatrixSpace(ZZ, 3).is_exact() + True + sage: MatrixSpace(RR, 3).is_exact() + False + """ + return self._base.is_exact() + def _has_default_implementation(self): r""" EXAMPLES:: diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 097db985ede..45c1434fa89 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -1008,6 +1008,24 @@ def is_sparse(self): """ return self.__is_sparse + def is_exact(self): + """ + Test whether elements of this module is exact. + + OUTPUT: + + Return ``True`` if elements of this module are represented exactly, i.e., + there is no precision loss when doing arithmetic. + + EXAMPLES:: + + sage: (ZZ^2).is_exact() + True + sage: (RR^2).is_exact() + False + """ + return self._base.is_exact() + def _an_element_(self): """ Return an arbitrary element of a free module. diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 36b84c399fe..16f8f8c856c 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -520,29 +520,6 @@ cdef class Ring(ParentWithGens): else: return False - cpdef bint is_exact(self) except -2: - """ - Return ``True`` if elements of this ring are represented exactly, i.e., - there is no precision loss when doing arithmetic. - - .. NOTE:: - - This defaults to ``True``, so even if it does return ``True`` you - have no guarantee (unless the ring has properly overloaded this). - - EXAMPLES:: - - sage: QQ.is_exact() # indirect doctest - True - sage: ZZ.is_exact() - True - sage: Qp(7).is_exact() # needs sage.rings.padics - False - sage: Zp(7, type='capped-abs').is_exact() # needs sage.rings.padics - False - """ - return True - def order(self): """ The number of elements of ``self``. diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 1dd2ae070ca..508d2931c81 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -2863,17 +2863,17 @@ cdef class Parent(sage.structure.category_object.CategoryObject): cpdef bint is_exact(self) except -2: """ - Test whether the ring is exact. + Test whether elements of this parent is exact. .. NOTE:: This defaults to true, so even if it does return ``True`` - you have no guarantee (unless the ring has properly + you have no guarantee (unless the parent has properly overloaded this). OUTPUT: - Return ``True`` if elements of this ring are represented exactly, i.e., + Return ``True`` if elements of this parent are represented exactly, i.e., there is no precision loss when doing arithmetic. EXAMPLES:: From abb8d018a38822e126357ee343a7d692692f94c2 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Mon, 16 Dec 2024 13:31:45 +0700 Subject: [PATCH 025/187] Fix alarm tests --- src/sage/coding/linear_code.py | 6 +- .../bounded_integer_sequences.pyx | 6 +- src/sage/doctest/util.py | 103 ++++++++++++++++++ src/sage/geometry/integral_points.pxi | 6 +- src/sage/libs/flint/nmod_poly_linkage.pxi | 6 +- src/sage/libs/gap/element.pyx | 6 +- src/sage/libs/libecm.pyx | 6 +- src/sage/matrix/matrix_integer_dense.pyx | 20 +--- src/sage/matrix/matrix_mod2_dense.pyx | 6 +- src/sage/rings/complex_arb.pyx | 11 +- src/sage/rings/factorint_pari.pyx | 7 +- src/sage/rings/integer.pyx | 11 +- .../rings/polynomial/polynomial_element.pyx | 6 +- .../polynomial/polynomial_zmod_flint.pyx | 6 +- src/sage/rings/qqbar.py | 15 ++- .../elliptic_curves/descent_two_isogeny.pyx | 6 +- src/sage/sets/recursively_enumerated_set.pyx | 21 +--- src/sage/structure/coerce_actions.pyx | 6 +- 18 files changed, 153 insertions(+), 101 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 3e9d388c434..5d61dbfba37 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -789,10 +789,8 @@ def canonical_representative(self, equivalence='semilinear'): (see :issue:`21651`):: sage: C = LinearCode(random_matrix(GF(47), 25, 35)) - sage: alarm(0.5); C.canonical_representative() # needs sage.libs.gap - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.5): C.canonical_representative() # needs sage.libs.gap """ aut_group_can_label = self._canonize(equivalence) return aut_group_can_label.get_canonical_form(), \ diff --git a/src/sage/data_structures/bounded_integer_sequences.pyx b/src/sage/data_structures/bounded_integer_sequences.pyx index 96dd83b4f8e..a96a55e5b50 100644 --- a/src/sage/data_structures/bounded_integer_sequences.pyx +++ b/src/sage/data_structures/bounded_integer_sequences.pyx @@ -1372,10 +1372,8 @@ def _biseq_stresstest(): TESTS:: sage: from sage.data_structures.bounded_integer_sequences import _biseq_stresstest - sage: alarm(1); _biseq_stresstest() # long time - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(1): _biseq_stresstest() # long time """ cdef int branch cdef Py_ssize_t x, y, z diff --git a/src/sage/doctest/util.py b/src/sage/doctest/util.py index e17df277c1f..34c99a4827e 100644 --- a/src/sage/doctest/util.py +++ b/src/sage/doctest/util.py @@ -25,6 +25,8 @@ from time import time as walltime from os import sysconf, times +from contextlib import contextmanager +from cysignals.alarm import alarm, cancel_alarm, AlarmInterrupt def count_noun(number, noun, plural=None, pad_number=False, pad_noun=False): @@ -749,3 +751,104 @@ def __ne__(self, other): True """ return not (self == other) + + +@contextmanager +def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = 0.2, inaccuracy_tolerance: float = 0.1): + """ + Helper function for doctesting to ensure that the code is interruptible after a certain amount of time. + This should only be used for internal doctesting purposes. + + EXAMPLES:: + + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(1) as data: sleep(3) + + ``as data`` is optional, but if it is used, it will contain a few useful values:: + + sage: data # abs tol 0.2 + {'alarm_raised': True, 'elapsed': 1.0} + + ``max_wait_after_interrupt`` can be passed if the function may take longer than usual to be interrupted:: + + sage: cython(''' + ....: from libc.time cimport clock_t, clock, CLOCKS_PER_SEC + ....: from cysignals.signals cimport sig_check + ....: cpdef void uninterruptible_sleep(double seconds): + ....: cdef clock_t target = clock() + (CLOCKS_PER_SEC * seconds) + ....: while clock() < target: + ....: pass + ....: cpdef void check_interrupt_only_occasionally(): + ....: for i in range(10): + ....: uninterruptible_sleep(0.8) + ....: sig_check() + ....: ''') + sage: with ensure_interruptible_after(1) as data: # not passing max_wait_after_interrupt will raise an error + ....: check_interrupt_only_occasionally() + Traceback (most recent call last): + ... + RuntimeError: Function is not interruptible within 1.0000 seconds, only after 1... seconds + sage: with ensure_interruptible_after(1, max_wait_after_interrupt=0.9): + ....: check_interrupt_only_occasionally() + + TESTS:: + + sage: data['elapsed'] # abs tol 0.3 # 1.6 = 0.8 * 2 + 1.6 + + :: + + sage: with ensure_interruptible_after(2) as data: sleep(1) + Traceback (most recent call last): + ... + RuntimeError: Function terminates early after 1... < 2.0000 seconds + sage: data # abs tol 0.2 + {'alarm_raised': False, 'elapsed': 1.0} + sage: with ensure_interruptible_after(1) as data: raise ValueError + Traceback (most recent call last): + ... + ValueError + sage: data # abs tol 0.2 + {'alarm_raised': False, 'elapsed': 0.0} + + :: + + sage: # needs sage.misc.cython + sage: with ensure_interruptible_after(1) as data: uninterruptible_sleep(2) + Traceback (most recent call last): + ... + RuntimeError: Function is not interruptible within 1.0000 seconds, only after 2... seconds + sage: data # abs tol 0.2 + {'alarm_raised': True, 'elapsed': 2.0} + sage: with ensure_interruptible_after(1): uninterruptible_sleep(2); raise RuntimeError + Traceback (most recent call last): + ... + RuntimeError: Function is not interruptible within 1.0000 seconds, only after 2... seconds + sage: data # abs tol 0.2 + {'alarm_raised': True, 'elapsed': 2.0} + """ + data = {} + start_time = walltime() + alarm(seconds) + alarm_raised = False + + try: + yield data + except AlarmInterrupt: + alarm_raised = True + finally: + cancel_alarm() + elapsed = walltime() - start_time + data["elapsed"] = elapsed + data["alarm_raised"] = alarm_raised + + if elapsed > seconds + max_wait_after_interrupt: + raise RuntimeError( + f"Function is not interruptible within {seconds:.4f} seconds, only after {elapsed:.4f} seconds" + + ("" if alarm_raised else " (__exit__ called before interrupt check)")) + + if alarm_raised: + if elapsed < seconds - inaccuracy_tolerance: + raise RuntimeError(f"Interrupted too early: {elapsed:.4f} < {seconds:.4f}, this should not happen") + else: + raise RuntimeError(f"Function terminates early after {elapsed:.4f} < {seconds:.4f} seconds") diff --git a/src/sage/geometry/integral_points.pxi b/src/sage/geometry/integral_points.pxi index a67535b450b..f351e63f5aa 100644 --- a/src/sage/geometry/integral_points.pxi +++ b/src/sage/geometry/integral_points.pxi @@ -531,10 +531,8 @@ cpdef rectangular_box_points(list box_min, list box_max, ....: (0, 0, 0, 0, 0, -1, 2, -1, 0), ....: (0, 0, 0, 0, 0, 0, -1, 2, -1)] sage: P = Polyhedron(ieqs=ieqs) - sage: alarm(0.5); P.integral_points() - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.5): P.integral_points() """ assert len(box_min) == len(box_max) assert not (count_only and return_saturated) diff --git a/src/sage/libs/flint/nmod_poly_linkage.pxi b/src/sage/libs/flint/nmod_poly_linkage.pxi index b1be0216a2e..2bd2ae1205f 100644 --- a/src/sage/libs/flint/nmod_poly_linkage.pxi +++ b/src/sage/libs/flint/nmod_poly_linkage.pxi @@ -536,10 +536,8 @@ cdef inline int celement_pow(nmod_poly_t res, nmod_poly_t x, long e, nmod_poly_t Make sure that exponentiation can be interrupted, see :issue:`17470`:: sage: n = 2^23 - sage: alarm(0.2); x^n; cancel_alarm() - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.2): (x^n).degree() """ if modulus != NULL: sig_on() diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index b35626b29e1..3faa39c5329 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -1135,10 +1135,8 @@ cdef class GapElement(RingElement): Check that this can be interrupted gracefully:: sage: a, b = libgap.GL(1000, 3).GeneratorsOfGroup(); g = a * b - sage: alarm(0.5); g ^ (2 ^ 10000) - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.5): g ^ (2 ^ 10000) sage: libgap.CyclicGroup(2) ^ 2 Traceback (most recent call last): diff --git a/src/sage/libs/libecm.pyx b/src/sage/libs/libecm.pyx index 6e0fc8668a5..86492a5e232 100644 --- a/src/sage/libs/libecm.pyx +++ b/src/sage/libs/libecm.pyx @@ -143,10 +143,8 @@ def ecmfactor(number, double B1, verbose=False, sigma=0): Check that ``ecmfactor`` can be interrupted (factoring a large prime number):: - sage: alarm(0.5); ecmfactor(2^521-1, 1e7) - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.5): ecmfactor(2^521-1, 1e7) Some special cases:: diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index 9ea2335b297..5e1c83dac50 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -4385,14 +4385,8 @@ cdef class Matrix_integer_dense(Matrix_dense): sage: A = random_matrix(ZZ, 2000, 2000) sage: B = random_matrix(ZZ, 2000, 2000) - sage: t0 = walltime() - sage: alarm(2); A._solve_iml(B) # long time - Traceback (most recent call last): - ... - AlarmInterrupt - sage: t = walltime(t0) - sage: t < 10 or t - True + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(2, max_wait_after_interrupt=8): A._solve_iml(B) ALGORITHM: Uses IML. @@ -4549,14 +4543,8 @@ cdef class Matrix_integer_dense(Matrix_dense): sage: A = random_matrix(ZZ, 2000, 2000) sage: B = random_matrix(ZZ, 2000, 2000) - sage: t0 = walltime() - sage: alarm(2); A._solve_flint(B) # long time - Traceback (most recent call last): - ... - AlarmInterrupt - sage: t = walltime(t0) - sage: t < 10 or t - True + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(2, max_wait_after_interrupt=8): A._solve_flint(B) AUTHORS: diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 55f39acf67f..3ee7e0f10f9 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -1975,10 +1975,8 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse sage: A = random_matrix(GF(2), n, m) sage: x = random_vector(GF(2), m) sage: B = A*x - sage: alarm(0.5); sol = A.solve_right(B) - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.5): sol = A.solve_right(B) """ cdef mzd_t *B_entries = (B)._entries diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index fb9d821a413..400bd4dc387 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -1184,13 +1184,10 @@ class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): sage: ComplexBallField(100).integral(lambda x, _: sin(x), RBF(0), RBF(1)) [0.4596976941318602825990633926 +/- ...e-29] - sage: from cysignals.alarm import alarm - sage: alarm(0.1r) - sage: C = ComplexBallField(1000000) - sage: C.integral(lambda x, _: x.cos() * x.sin(), 0, 1) - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.1): + ....: C = ComplexBallField(1000000) + ....: C.integral(lambda x, _: x.cos() * x.sin(), 0, 1) """ cdef IntegrationContext ctx = IntegrationContext() cdef acb_calc_integrate_opt_t arb_opts diff --git a/src/sage/rings/factorint_pari.pyx b/src/sage/rings/factorint_pari.pyx index a8d748c5845..620453a65d4 100644 --- a/src/sage/rings/factorint_pari.pyx +++ b/src/sage/rings/factorint_pari.pyx @@ -50,10 +50,11 @@ def factor_using_pari(n, int_=False, debug_level=0, proof=None): Check that PARI's debug level is properly reset (:issue:`18792`):: - sage: alarm(0.5); factor(2^1000 - 1, verbose=5) - Traceback (most recent call last): + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.5): factor(2^1000 - 1, verbose=5) ... - AlarmInterrupt + doctest:warning... + RuntimeWarning: cypari2 leaked ... bytes on the PARI stack sage: pari.get_debug_level() 0 """ diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index c9d1ff65bc6..d5d72f2ade9 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -7108,21 +7108,16 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): Check that it can be interrupted (:issue:`17852`):: - sage: alarm(0.5); (2^100).binomial(2^22, algorithm='mpir') - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.5): (2^100).binomial(2^22, algorithm='mpir') For PARI, we try 10 interrupts with increasing intervals to check for reliable interrupting, see :issue:`18919`:: sage: from cysignals import AlarmInterrupt sage: for i in [1..10]: # long time (5s) # needs sage.libs.pari - ....: try: - ....: alarm(i/11) + ....: with ensure_interruptible_after(i/11): ....: (2^100).binomial(2^22, algorithm='pari') - ....: except AlarmInterrupt: - ....: pass doctest:...: RuntimeWarning: cypari2 leaked ... bytes on the PARI stack... """ cdef Integer x diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 389e538f83e..624bcf3ee6e 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -2533,10 +2533,8 @@ cdef class Polynomial(CommutativePolynomial): sage: K. = GF(2^8) sage: x = polygen(K) sage: pol = x^1000000 + x + a - sage: alarm(0.5); pol.any_root() - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.5): pol.any_root() Check root computation over large finite fields:: diff --git a/src/sage/rings/polynomial/polynomial_zmod_flint.pyx b/src/sage/rings/polynomial/polynomial_zmod_flint.pyx index 5b3539d6b70..2bde0865f72 100644 --- a/src/sage/rings/polynomial/polynomial_zmod_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_zmod_flint.pyx @@ -811,10 +811,8 @@ cdef class Polynomial_zmod_flint(Polynomial_template): sage: R. = PolynomialRing(GF(65537), implementation="FLINT") sage: f = R.random_element(9973) * R.random_element(10007) - sage: alarm(0.5); f.factor() - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.5): f.factor() Test zero polynomial:: diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 3806663eaf0..a52694cf82b 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -7106,14 +7106,13 @@ def exactify(self): sage: x = polygen(AA) sage: p = AA(2)^(1/100) * x + AA(3)^(1/100) sage: cp = AA.common_polynomial(p) - sage: alarm(0.5); cp.generator() - Traceback (most recent call last): - ... - AlarmInterrupt - sage: alarm(0.5); cp.generator() - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.5): cp.generator() + doctest:warning... + RuntimeWarning: cypari2 leaked ... bytes on the PARI stack + sage: with ensure_interruptible_after(0.5): cp.generator() + doctest:warning... + RuntimeWarning: cypari2 leaked ... bytes on the PARI stack """ if self._exact: return diff --git a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx index 16bad60ba56..f83568c2af2 100755 --- a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx +++ b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx @@ -1208,10 +1208,8 @@ def two_descent_by_two_isogeny(E, Elliptic Curve defined by y^2 = x^3 - x^2 - 900*x - 10098 over Rational Field sage: E.sha().an() 4 - sage: alarm(0.5); two_descent_by_two_isogeny(E, global_limit_large=10^8) - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.5): two_descent_by_two_isogeny(E, global_limit_large=10^8) """ cdef Integer a1, a2, a3, a4, a6, s2, s4, s6 cdef Integer c, d, x0 diff --git a/src/sage/sets/recursively_enumerated_set.pyx b/src/sage/sets/recursively_enumerated_set.pyx index b20fa8cbe8a..098074b1649 100644 --- a/src/sage/sets/recursively_enumerated_set.pyx +++ b/src/sage/sets/recursively_enumerated_set.pyx @@ -1122,11 +1122,8 @@ cdef class RecursivelyEnumeratedSet_symmetric(RecursivelyEnumeratedSet_generic): {0} sage: next(it) {-1, 1} - sage: from cysignals.alarm import alarm - sage: alarm(0.02); next(it) - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.02): next(it) sage: next(it) Traceback (most recent call last): ... @@ -1175,11 +1172,8 @@ cdef class RecursivelyEnumeratedSet_symmetric(RecursivelyEnumeratedSet_generic): ....: sleep(0.1r) ....: return [a - 1, a + 1] sage: C = RecursivelyEnumeratedSet([0], f, structure='symmetric') - sage: from cysignals.alarm import alarm - sage: alarm(0.45); C.graded_component(10) - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.45): C.graded_component(10) sage: C.graded_component(1) {-1, 1} sage: C.graded_component(2) @@ -1394,11 +1388,8 @@ cdef class RecursivelyEnumeratedSet_graded(RecursivelyEnumeratedSet_generic): ....: sleep(0.1r) ....: return [a + 1, a + I] sage: C = RecursivelyEnumeratedSet([0], f, structure='graded') - sage: from cysignals.alarm import alarm - sage: alarm(0.45); C.graded_component(10) - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.45): C.graded_component(10) sage: C.graded_component(2) {2*I, I + 1, 2} sage: C.graded_component(3) diff --git a/src/sage/structure/coerce_actions.pyx b/src/sage/structure/coerce_actions.pyx index 17bbd397c98..f146a332368 100644 --- a/src/sage/structure/coerce_actions.pyx +++ b/src/sage/structure/coerce_actions.pyx @@ -801,10 +801,8 @@ cdef class IntegerMulAction(IntegerAction): sage: # needs sage.schemes sage: P = E([2,1,1]) - sage: alarm(0.001); 2^(10^8) * P - Traceback (most recent call last): - ... - AlarmInterrupt + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(0.001): 2^(10^8) * P Verify that cysignals correctly detects that the above exception has been handled:: From 40dfc5f36afa8dd5f6a9e19977328cd7cb12e0f1 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Thu, 19 Dec 2024 09:21:53 +0700 Subject: [PATCH 026/187] Fix test fail by suppress warning --- src/sage/rings/qqbar.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index a52694cf82b..eedd9bd5dc5 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -7083,7 +7083,7 @@ def complex_roots(self, prec, multiplicity): return roots def exactify(self): - """ + r""" Compute a common field that holds all of the algebraic coefficients of this polynomial, then factor the polynomial over that field. Store the factors for later use (ignoring multiplicity). @@ -7107,12 +7107,13 @@ def exactify(self): sage: p = AA(2)^(1/100) * x + AA(3)^(1/100) sage: cp = AA.common_polynomial(p) sage: from sage.doctest.util import ensure_interruptible_after - sage: with ensure_interruptible_after(0.5): cp.generator() - doctest:warning... - RuntimeWarning: cypari2 leaked ... bytes on the PARI stack - sage: with ensure_interruptible_after(0.5): cp.generator() - doctest:warning... - RuntimeWarning: cypari2 leaked ... bytes on the PARI stack + sage: from warnings import catch_warnings, filterwarnings + sage: with ensure_interruptible_after(0.5), catch_warnings(): + ....: filterwarnings("ignore", r"cypari2 leaked \d+ bytes on the PARI stack") + ....: cp.generator() + sage: with ensure_interruptible_after(0.5), catch_warnings(): + ....: filterwarnings("ignore", r"cypari2 leaked \d+ bytes on the PARI stack") + ....: cp.generator() """ if self._exact: return From 63d482a32feed9d7886ca35bb7a7fa49932bed5a Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Thu, 19 Dec 2024 12:15:18 +0700 Subject: [PATCH 027/187] Wait by realtime, avoid unexplained slowdown --- src/sage/doctest/util.py | 55 +++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/sage/doctest/util.py b/src/sage/doctest/util.py index 34c99a4827e..6bb2967ae73 100644 --- a/src/sage/doctest/util.py +++ b/src/sage/doctest/util.py @@ -766,49 +766,59 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = ``as data`` is optional, but if it is used, it will contain a few useful values:: - sage: data # abs tol 0.2 + sage: data # abs tol 0.01 {'alarm_raised': True, 'elapsed': 1.0} ``max_wait_after_interrupt`` can be passed if the function may take longer than usual to be interrupted:: - sage: cython(''' - ....: from libc.time cimport clock_t, clock, CLOCKS_PER_SEC + sage: cython(r''' + ....: from posix.time cimport clock_gettime, CLOCK_REALTIME, timespec ....: from cysignals.signals cimport sig_check + ....: from time import time as walltime + ....: ....: cpdef void uninterruptible_sleep(double seconds): - ....: cdef clock_t target = clock() + (CLOCKS_PER_SEC * seconds) - ....: while clock() < target: - ....: pass + ....: cdef timespec start_time, target_time + ....: start_walltime = walltime() + ....: clock_gettime(CLOCK_REALTIME, &start_time) + ....: + ....: cdef int floor_seconds = seconds + ....: target_time.tv_sec = start_time.tv_sec + floor_seconds + ....: target_time.tv_nsec = start_time.tv_nsec + ((seconds - floor_seconds) * 1e9) + ....: if target_time.tv_nsec >= 1000000000: + ....: target_time.tv_nsec -= 1000000000 + ....: target_time.tv_sec += 1 + ....: + ....: while True: + ....: clock_gettime(CLOCK_REALTIME, &start_time) + ....: if start_time.tv_sec > target_time.tv_sec or (start_time.tv_sec == target_time.tv_sec and start_time.tv_nsec >= target_time.tv_nsec): + ....: break + ....: ....: cpdef void check_interrupt_only_occasionally(): ....: for i in range(10): ....: uninterruptible_sleep(0.8) ....: sig_check() ....: ''') - sage: with ensure_interruptible_after(1) as data: # not passing max_wait_after_interrupt will raise an error + sage: with ensure_interruptible_after(1): # not passing max_wait_after_interrupt will raise an error ....: check_interrupt_only_occasionally() Traceback (most recent call last): ... - RuntimeError: Function is not interruptible within 1.0000 seconds, only after 1... seconds + RuntimeError: Function is not interruptible within 1.0000 seconds, only after 1.60... seconds sage: with ensure_interruptible_after(1, max_wait_after_interrupt=0.9): ....: check_interrupt_only_occasionally() TESTS:: - sage: data['elapsed'] # abs tol 0.3 # 1.6 = 0.8 * 2 - 1.6 - - :: - sage: with ensure_interruptible_after(2) as data: sleep(1) Traceback (most recent call last): ... - RuntimeError: Function terminates early after 1... < 2.0000 seconds - sage: data # abs tol 0.2 + RuntimeError: Function terminates early after 1.00... < 2.0000 seconds + sage: data # abs tol 0.01 {'alarm_raised': False, 'elapsed': 1.0} sage: with ensure_interruptible_after(1) as data: raise ValueError Traceback (most recent call last): ... ValueError - sage: data # abs tol 0.2 + sage: data # abs tol 0.01 {'alarm_raised': False, 'elapsed': 0.0} :: @@ -817,16 +827,20 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = sage: with ensure_interruptible_after(1) as data: uninterruptible_sleep(2) Traceback (most recent call last): ... - RuntimeError: Function is not interruptible within 1.0000 seconds, only after 2... seconds - sage: data # abs tol 0.2 + RuntimeError: Function is not interruptible within 1.0000 seconds, only after 2.00... seconds + sage: data # abs tol 0.01 {'alarm_raised': True, 'elapsed': 2.0} sage: with ensure_interruptible_after(1): uninterruptible_sleep(2); raise RuntimeError Traceback (most recent call last): ... - RuntimeError: Function is not interruptible within 1.0000 seconds, only after 2... seconds - sage: data # abs tol 0.2 + RuntimeError: Function is not interruptible within 1.0000 seconds, only after 2.00... seconds + sage: data # abs tol 0.01 {'alarm_raised': True, 'elapsed': 2.0} """ + seconds = float(seconds) + max_wait_after_interrupt = float(max_wait_after_interrupt) + inaccuracy_tolerance = float(inaccuracy_tolerance) + # use Python float to avoid unexplained slowdown with Sage objects data = {} start_time = walltime() alarm(seconds) @@ -837,6 +851,7 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = except AlarmInterrupt: alarm_raised = True finally: + before_cancel_alarm_elapsed = walltime() - start_time cancel_alarm() elapsed = walltime() - start_time data["elapsed"] = elapsed From a3233d87a6646974b132cefd35c5c826bdc86d1b Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:48:25 +0700 Subject: [PATCH 028/187] Change some sleep() call to use Python float --- src/sage/doctest/util.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/doctest/util.py b/src/sage/doctest/util.py index 6bb2967ae73..4e36a541d3f 100644 --- a/src/sage/doctest/util.py +++ b/src/sage/doctest/util.py @@ -762,7 +762,7 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = EXAMPLES:: sage: from sage.doctest.util import ensure_interruptible_after - sage: with ensure_interruptible_after(1) as data: sleep(3) + sage: with ensure_interruptible_after(1) as data: sleep(3r) ``as data`` is optional, but if it is used, it will contain a few useful values:: @@ -808,7 +808,8 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = TESTS:: - sage: with ensure_interruptible_after(2) as data: sleep(1) + sage: # we use 1r instead of 1 to avoid unexplained slowdown + sage: with ensure_interruptible_after(2) as data: sleep(1r) Traceback (most recent call last): ... RuntimeError: Function terminates early after 1.00... < 2.0000 seconds From cdba9cdd60d51c56bd0d2f8d1cabcb1235a2dd08 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Fri, 20 Dec 2024 09:28:52 +0700 Subject: [PATCH 029/187] Fix tests on Mac --- src/sage/doctest/util.py | 65 +++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/src/sage/doctest/util.py b/src/sage/doctest/util.py index 4e36a541d3f..47ed4e767ee 100644 --- a/src/sage/doctest/util.py +++ b/src/sage/doctest/util.py @@ -762,28 +762,27 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = EXAMPLES:: sage: from sage.doctest.util import ensure_interruptible_after - sage: with ensure_interruptible_after(1) as data: sleep(3r) + sage: with ensure_interruptible_after(1) as data: sleep(3) ``as data`` is optional, but if it is used, it will contain a few useful values:: - sage: data # abs tol 0.01 + sage: data # abs tol 1 {'alarm_raised': True, 'elapsed': 1.0} ``max_wait_after_interrupt`` can be passed if the function may take longer than usual to be interrupted:: + sage: # needs sage.misc.cython sage: cython(r''' - ....: from posix.time cimport clock_gettime, CLOCK_REALTIME, timespec + ....: from posix.time cimport clock_gettime, CLOCK_REALTIME, timespec, time_t ....: from cysignals.signals cimport sig_check - ....: from time import time as walltime ....: ....: cpdef void uninterruptible_sleep(double seconds): ....: cdef timespec start_time, target_time - ....: start_walltime = walltime() ....: clock_gettime(CLOCK_REALTIME, &start_time) ....: - ....: cdef int floor_seconds = seconds + ....: cdef time_t floor_seconds = seconds ....: target_time.tv_sec = start_time.tv_sec + floor_seconds - ....: target_time.tv_nsec = start_time.tv_nsec + ((seconds - floor_seconds) * 1e9) + ....: target_time.tv_nsec = start_time.tv_nsec + ((seconds - floor_seconds) * 1e9) ....: if target_time.tv_nsec >= 1000000000: ....: target_time.tv_nsec -= 1000000000 ....: target_time.tv_sec += 1 @@ -808,23 +807,44 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = TESTS:: - sage: # we use 1r instead of 1 to avoid unexplained slowdown - sage: with ensure_interruptible_after(2) as data: sleep(1r) + sage: with ensure_interruptible_after(2) as data: sleep(1) Traceback (most recent call last): ... - RuntimeError: Function terminates early after 1.00... < 2.0000 seconds - sage: data # abs tol 0.01 + RuntimeError: Function terminates early after 1... < 2.0000 seconds + sage: data # abs tol 1 {'alarm_raised': False, 'elapsed': 1.0} - sage: with ensure_interruptible_after(1) as data: raise ValueError - Traceback (most recent call last): - ... - ValueError - sage: data # abs tol 0.01 - {'alarm_raised': False, 'elapsed': 0.0} - :: + The test above requires a large tolerance, because both ``time.sleep`` and + ``from posix.unistd cimport usleep`` may have slowdown on the order of 0.1s on Mac, + likely because the system is idle and GitHub CI switches the program out, + and context switch back takes time. So we use busy wait instead:: sage: # needs sage.misc.cython + sage: cython(r''' + ....: from posix.time cimport clock_gettime, CLOCK_REALTIME, timespec, time_t + ....: from cysignals.signals cimport sig_check + ....: + ....: cpdef void interruptible_sleep(double seconds): + ....: cdef timespec start_time, target_time + ....: clock_gettime(CLOCK_REALTIME, &start_time) + ....: + ....: cdef time_t floor_seconds = seconds + ....: target_time.tv_sec = start_time.tv_sec + floor_seconds + ....: target_time.tv_nsec = start_time.tv_nsec + ((seconds - floor_seconds) * 1e9) + ....: if target_time.tv_nsec >= 1000000000: + ....: target_time.tv_nsec -= 1000000000 + ....: target_time.tv_sec += 1 + ....: + ....: while True: + ....: sig_check() + ....: clock_gettime(CLOCK_REALTIME, &start_time) + ....: if start_time.tv_sec > target_time.tv_sec or (start_time.tv_sec == target_time.tv_sec and start_time.tv_nsec >= target_time.tv_nsec): + ....: break + ....: ''') + sage: with ensure_interruptible_after(2) as data: interruptible_sleep(1) + Traceback (most recent call last): + ... + RuntimeError: Function terminates early after 1.00... < 2.0000 seconds sage: with ensure_interruptible_after(1) as data: uninterruptible_sleep(2) Traceback (most recent call last): ... @@ -837,6 +857,15 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = RuntimeError: Function is not interruptible within 1.0000 seconds, only after 2.00... seconds sage: data # abs tol 0.01 {'alarm_raised': True, 'elapsed': 2.0} + + :: + + sage: with ensure_interruptible_after(1) as data: raise ValueError + Traceback (most recent call last): + ... + ValueError + sage: data # abs tol 0.01 + {'alarm_raised': False, 'elapsed': 0.0} """ seconds = float(seconds) max_wait_after_interrupt = float(max_wait_after_interrupt) From 0f6ca22d8047677f39eb9aa751cfddaa00f32efe Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 21 Dec 2024 11:26:41 +0530 Subject: [PATCH 030/187] updated is_brick() --- src/sage/graphs/matching_covered_graph.py | 167 +++++++++++++++++++--- 1 file changed, 151 insertions(+), 16 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 58d39a8b938..e9f90686b22 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2691,7 +2691,6 @@ def dfs(v, visited, neighbor_iterator): return (True, None, None) if coNP_certificate else True - @doc_index('Bricks, braces and tight cut decomposition') def is_brick(self, coNP_certificate=False): r""" @@ -2702,9 +2701,148 @@ def is_brick(self, coNP_certificate=False): graph is a brick if and only if it is 3-connected and bicritical [LM2024]_. + INPUT: + + - ``coNP_certificate`` -- boolean (default: ``False``) + + OUTPUT: + + - If the input matching covered graph is bipartite, a :exc:`ValueError` + is returned. + + - If the input nonbipartite matching covered graph is a brick, a + boolean ``True`` is returned if ``coNP_certificate`` is set to + ``False`` otherwise a tuple ``(True, None, None)`` is returned. + + - If the input nonbipartite matching covered graph is not a brick, a + boolean ``False`` is returned if ``coNP_certificate`` is set to + ``False`` otherwise a tuple of boolean ``False``, a list of + edges constituting a nontrivial tight cut and a set of vertices of + one of the shores of the nontrivial tight cut is returned. + + EXAMPLES: + + The complete graph on four vertices `K_4` is the smallest brick:: + + sage: K = graphs.CompleteGraph(4) + sage: G = MatchingCoveredGraph(K) + sage: G.is_brick() + True + + The triangular cicular ladder (a graph on six vertices), aka + `\overline{C_6}` is a brick:: + + sage: C6Bar = graphs.CircularLadderGraph(3) + sage: G = MatchingCoveredGraph(C6Bar) + sage: G.is_brick() + True + + Each of Petersen graph, Bicorn graph, Tricorn graph, Cubeplex graph, + Twinplex graph, Wagner graph is a brick:: + + sage: MatchingCoveredGraph(graphs.PetersenGraph()).is_brick() and \ + ....: MatchingCoveredGraph(graphs.StaircaseGraph(4)).is_brick() and \ + ....: MatchingCoveredGraph(graphs.TricornGraph()).is_brick() and \ + ....: MatchingCoveredGraph(graphs.CubeplexGraph()).is_brick() and \ + ....: MatchingCoveredGraph(graphs.TwinplexGraph()).is_brick() and \ + ....: MatchingCoveredGraph(graphs.WagnerGraph()).is_brick() + True + + The Murty graph is the smallest simple brick that is not odd-intercyclic:: + + sage: M = graphs.MurtyGraph() + sage: G = MatchingCoveredGraph(M) + sage: G.is_brick() + True + + A circular ladder graph of order six or more on `2n` vertices for an + odd `n` is a brick:: + + sage: n = 11 + sage: CL = graphs.CircularLadderGraph(n) + sage: G = MatchingCoveredGraph(CL) + sage: G.is_brick() + True + + A moebius ladder graph of order eight or more on `2n` vertices for an + even `n` is a brick:: + + sage: n = 10 + sage: ML = graphs.MoebiusLadderGraph(n) + sage: G = MatchingCoveredGraph(ML) + sage: G.is_brick() + True + + A wheel graph of an even order is a brick:: + + sage: W = graphs.WheelGraph(10) + sage: G = MatchingCoveredGraph(W) + sage: G.is_brick() + True + + A graph that is isomorphic to a truncated biwheel graph is a brick:: + + sage: TB = graphs.TruncatedBiwheelGraph(15) + sage: G = MatchingCoveredGraph(TB) + sage: G.is_brick() + True + + Each of the graphs in the staircase graph family with order eight or + more is a brick:: + + sage: ST = graphs.StaircaseGraph(9) + sage: G = MatchingCoveredGraph(ST) + sage: G.is_brick() + True + + Bricks are 3-connected:: + + sage: P = graphs.PetersenGraph() + sage: G = MatchingCoveredGraph(P) + sage: G.is_brick() + True + sage: G.is_triconnected() + True + + Bricks are bicritical:: + + sage: P = graphs.PetersenGraph() + sage: G = MatchingCoveredGraph(P) + sage: G.is_brick() + True + sage: G.is_bicritical() + True + + One may set the ``coNP_certificate`` to be ``True``:: + + sage: K4 = graphs.CompleteGraph(4) + sage: G = MatchingCoveredGraph(K4) + sage: G.is_brick(coNP_certificate=True) + sage: # K(4) + + If the input matching covered graph is bipartite, a + :exc:`ValueError` is thrown:: + + sage: H = graphs.HexahedralGraph() + sage: G = MatchingCoveredGraph(H) + sage: G.is_brick() + Traceback (most recent call last): + ... + ValueError: the input graph is bipartite + sage: J = graphs.HeawoodGraph() + sage: G = MatchingCoveredGraph(J) + sage: G.is_brick(coNP_certificate=True) + Traceback (most recent call last): + ... + ValueError: the input graph is bipartite + .. SEEALSO:: - :meth:`~sage.graphs.graph.Graph.is_bicritical` + - :meth:`~sage.graphs.graph.Graph.is_bicritical` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.is_brace` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.bricks_and_braces` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_bricks` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_petersen_bricks` """ if self.is_bipartite(): raise ValueError('the input graph is bipartite') @@ -2750,23 +2888,21 @@ def is_brick(self, coNP_certificate=False): # Check for 2-vertex cuts in P and S nodes for u in spqr_tree: if u[0] == 'P': - two_vertex_cut.extend(u[1].vertices()) + two_vertex_cut.extend(u[1]) break elif u[0] == 'S' and u[1].order() > 3: - s_vertex_set = set(u[1].vertices()) - for v in u[1].vertices(): - s_vertex_set -= {v} | set(u[1].neighbors(v)) - two_vertex_cut.extend([v, next(iter(s_vertex_set))]) - break + s_vertex_set = set(u[1]) + s_vertex_set -= {next(u[1].vertex_iterator())} | set(u[1].neighbors(next(u[1].vertex_iterator()))) + two_vertex_cut.extend([next(u[1].vertex_iterator()), next(iter(s_vertex_set))]) # If no 2-vertex cut found, look for R nodes if not two_vertex_cut: - R_frequency = {u: 0 for u in self} - for u in spqr_tree.vertices(): - if u[0] == 'R': - for v in u[1].vertices(): - R_frequency[v] += 1 - two_vertex_cut = [u for u in self if R_frequency[u] >= 2][:2] + from collections import Counter + R_frequency = Counter() + for t, g in spqr_tree: + if t == 'R': + R_frequency.update(g) + two_vertex_cut = [u for u, f in R_frequency.items() if f >= 2][:2] # We obtain a 2-vertex cut (u, v) H = Graph(self) @@ -2774,10 +2910,9 @@ def is_brick(self, coNP_certificate=False): # Check if all components of H are odd components = H.connected_components() - are_all_odd_components = all(len(c) % 2 for c in components) # Find a nontrivial odd component - if are_all_odd_components: + if all(len(c) % 2 for c in components): nontrivial_odd_component = next((c for c in components if len(c) > 1), None) else: nontrivial_odd_component = components[0] + [two_vertex_cut[0]] From adb95be3d242e4024cc1166b90a56c3a6604098a Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 21 Dec 2024 11:28:27 +0530 Subject: [PATCH 031/187] updated is_brace() --- src/sage/graphs/matching_covered_graph.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index e9f90686b22..7f3e249c128 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2383,7 +2383,7 @@ def is_brace(self, coNP_certificate=False): - If the input bipartite matching covered graph is a brace, a boolean ``True`` is returned if ``coNP_certificate`` is set to ``False`` - otherwise a pair ``(True, None, None)`` is returned. + otherwise a tuple ``(True, None, None)`` is returned. - If the input bipartite matching covered graph is not a brace, a boolean ``False`` is returned if ``coNP_certificate`` is set to @@ -2414,8 +2414,8 @@ def is_brace(self, coNP_certificate=False): sage: G.is_brace() True - A circular ladder graph on `2n` vertices for `n \equiv 0 (\mod 2)` is - a brace:: + A circular ladder graph of order eight or more on `2n` vertices for + an even `n` is a brace:: sage: n = 10 sage: CL = graphs.CircularLadderGraph(n) @@ -2423,8 +2423,8 @@ def is_brace(self, coNP_certificate=False): sage: G.is_brace() True - A moebius ladder graph on `2n` vertices for `n \equiv 1 (\mod 2)` is - a brace:: + A moebius ladder graph of order six or more on `2n` vertices for an odd + `n` is a brace:: sage: n = 11 sage: ML = graphs.MoebiusLadderGraph(n) @@ -2602,6 +2602,13 @@ def is_brace(self, coNP_certificate=False): Traceback (most recent call last): ... ValueError: the input graph is not bipartite + + .. SEEALSO:: + + - :meth:`~sage.graphs.graph.Graph.is_bicritical` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.is_brick` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.bricks_and_braces` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_braces` """ if not self.is_bipartite(): raise ValueError('the input graph is not bipartite') From e101d33ff0880461202244feafd404717be90d04 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 21 Dec 2024 11:29:29 +0530 Subject: [PATCH 032/187] updated see also --- src/sage/graphs/matching_covered_graph.py | 98 +++++++++++------------ 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 7f3e249c128..788ccb88467 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -1616,13 +1616,13 @@ def allow_loops(self, new, check=True): .. SEEALSO:: - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` """ if new: raise ValueError('loops are not allowed in ' @@ -1657,13 +1657,13 @@ def allows_loops(self): .. SEEALSO:: - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` """ return False @@ -2251,13 +2251,13 @@ def has_loops(self): .. SEEALSO:: - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` """ return False @@ -3001,13 +3001,13 @@ def loop_edges(self, labels=True): .. SEEALSO:: - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` """ return [] @@ -3068,13 +3068,13 @@ def loop_vertices(self): .. SEEALSO:: - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` """ return [] @@ -3140,13 +3140,13 @@ def number_of_loops(self): .. SEEALSO:: - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` """ return 0 @@ -3232,13 +3232,13 @@ def remove_loops(self, vertices=None): .. SEEALSO:: - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops` """ from collections.abc import Iterable From b7c274e8fba1719b202d31b189948c4000630a81 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 21 Dec 2024 12:35:20 +0530 Subject: [PATCH 033/187] updated the doctests --- src/sage/graphs/matching_covered_graph.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 788ccb88467..37c291edd97 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2057,8 +2057,7 @@ def maximal_barrier(self, vertex): sage: J = G.copy() sage: J.delete_vertices(B) - sage: all(len(K)%2 != 0 for K in J.connected_components()) - ... + sage: all(len(K)%2 != 0 for K in J.connected_components(sort=True)) True Let `B` be a maximal barrier in a matching covered graph `G` and let @@ -2585,7 +2584,7 @@ def is_brace(self, coNP_certificate=False): sage: C = graphs.CycleGraph(6) sage: D = MatchingCoveredGraph(C) sage: D.is_brace(coNP_certificate=True) - (False, [(0, 5, None), (2, 3, None)], {0, 1, 2}) + (False, [(1, 2, None), (5, 4, None)], {0, 1, 5}) If the input matching covered graph is nonbipartite, a :exc:`ValueError` is thrown:: @@ -2825,7 +2824,12 @@ def is_brick(self, coNP_certificate=False): sage: K4 = graphs.CompleteGraph(4) sage: G = MatchingCoveredGraph(K4) sage: G.is_brick(coNP_certificate=True) - sage: # K(4) + (True, None, None) + sage: # K(4) ⊙ K(3, 3) is nonbipartite but not a brick + sage: H = graphs.MurtyGraph(); H.delete_edge(0, 1) + sage: G = MatchingCoveredGraph(H) + sage: G.is_brick(coNP_certificate=True) + (False, [(5, 2, None), (6, 3, None), (7, 4, None)], {5, 6, 7}) If the input matching covered graph is bipartite, a :exc:`ValueError` is thrown:: From b8fdab8619b38f1eb9791efd45205f99b07ef5fc Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 21 Dec 2024 12:40:32 +0530 Subject: [PATCH 034/187] updated connected components parameter --- src/sage/graphs/matching_covered_graph.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 37c291edd97..37a31b72bca 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2066,7 +2066,7 @@ def maximal_barrier(self, vertex): `v` is the end of that edge in `V(K)`, then `M \cap E(K)` is a perfect matching of `K - v`:: - sage: K = J.subgraph(vertices=(J.connected_components())[0]) + sage: K = J.subgraph(vertices=(J.connected_components(sort=True))[0]) sage: # Let F := \partial_G(K) and T := M \cap F sage: F = [edge for edge in G.edge_iterator() ....: if (edge[0] in K and edge[1] not in K) @@ -2090,7 +2090,7 @@ def maximal_barrier(self, vertex): `G - B` is factor critical:: sage: all((K.subgraph(vertices=connected_component)).is_factor_critical() - ....: for connected_component in K.connected_components() + ....: for connected_component in K.connected_components(sort=True) ....: ) True @@ -2876,7 +2876,7 @@ def is_brick(self, coNP_certificate=False): # Let K be a nontrivial odd component of H := G - B. Note that # there exists at least one such K since G is nonbipartite nontrivial_odd_component = next( - (component for component in H.connected_components() + (component for component in H.connected_components(sort=True) if len(component) % 2 and len(component) > 1), None ) @@ -2920,7 +2920,7 @@ def is_brick(self, coNP_certificate=False): H.delete_vertices(two_vertex_cut) # Check if all components of H are odd - components = H.connected_components() + components = H.connected_components(sort=True) # Find a nontrivial odd component if all(len(c) % 2 for c in components): From cb4d3d133aeced010a99131f8221a7c9fb7b6ecc Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 21 Dec 2024 12:43:24 +0530 Subject: [PATCH 035/187] updated the return statement of is_brick() --- src/sage/graphs/matching_covered_graph.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 37a31b72bca..328db2950e7 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2885,7 +2885,7 @@ def is_brick(self, coNP_certificate=False): for u, v, w in self.edge_iterator() if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] - return False, C, nontrivial_odd_component + return (False, C, set(nontrivial_odd_component)) # Check if G is 3-connected if self.is_triconnected(): @@ -2933,7 +2933,7 @@ def is_brick(self, coNP_certificate=False): if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] # Edge (u, v, w) in C are formatted so that u is in a nontrivial odd component - return (False, C, nontrivial_odd_component) if coNP_certificate else False + return (False, C, set(nontrivial_odd_component)) if coNP_certificate else False @doc_index('Overwritten methods') def loop_edges(self, labels=True): From d6701686e1ab15f010ac825ec3a019ec5c922743 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 21 Dec 2024 12:43:50 +0530 Subject: [PATCH 036/187] updated the return statement of is_brace() --- src/sage/graphs/matching_covered_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 328db2950e7..76c5cc2dc37 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2693,7 +2693,7 @@ def dfs(v, visited, neighbor_iterator): for u, v, w in self.edge_iterator() if (u in X) ^ (v in X)] - return False, C, X + return (False, C, set(X)) return (True, None, None) if coNP_certificate else True From 03771eea4f41b77ff77635873b28856fd36ed0b5 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 21 Dec 2024 19:32:59 +0530 Subject: [PATCH 037/187] updated is_brace() --- src/sage/graphs/matching_covered_graph.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 76c5cc2dc37..fce968cb1dd 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2584,7 +2584,7 @@ def is_brace(self, coNP_certificate=False): sage: C = graphs.CycleGraph(6) sage: D = MatchingCoveredGraph(C) sage: D.is_brace(coNP_certificate=True) - (False, [(1, 2, None), (5, 4, None)], {0, 1, 5}) + (False, [(0, 5, None), (2, 3, None)], {0, 1, 2}) If the input matching covered graph is nonbipartite, a :exc:`ValueError` is thrown:: @@ -2637,7 +2637,7 @@ def is_brace(self, coNP_certificate=False): # For each edge (a, b) in E(H(e)) ∩ M with a in A, b —> a in D(e). # For each edge (a, b) in E(H(e)) with a in A, a —> b in D(e). - for a, b, *_ in H.edge_iterator(): + for a, b in H.edge_iterator(labels=False, sort_vertices=True): if a in B: a, b = b, a @@ -2678,7 +2678,7 @@ def dfs(v, visited, neighbor_iterator): X = set() dfs(root, X, D.neighbor_out_iterator) - for a, b in H.edge_iterator(labels=False): + for a, b in H.edge_iterator(labels=False, sort_vertices=True): if (a in X) ^ (b in X): x = a if a in A else b color_class = x not in X @@ -2690,7 +2690,7 @@ def dfs(v, visited, neighbor_iterator): # Compute the nontrivial tight cut C := ∂(Y) C = [(u, v, w) if u in X else (v, u, w) - for u, v, w in self.edge_iterator() + for u, v, w in self.edge_iterator(sort_vertices=True) if (u in X) ^ (v in X)] return (False, C, set(X)) From 8a14b4c10bf11724ed3ccd1130e1ea4c604b7968 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 21 Dec 2024 19:33:42 +0530 Subject: [PATCH 038/187] updated is_brick() --- src/sage/graphs/matching_covered_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index fce968cb1dd..cf5feff8752 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2924,7 +2924,7 @@ def is_brick(self, coNP_certificate=False): # Find a nontrivial odd component if all(len(c) % 2 for c in components): - nontrivial_odd_component = next((c for c in components if len(c) > 1), None) + nontrivial_odd_component = next(c for c in components if len(c) > 1) else: nontrivial_odd_component = components[0] + [two_vertex_cut[0]] From d295290b1cd230b2780237355c5d60b1ffab8adc Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 21 Dec 2024 22:52:35 +0530 Subject: [PATCH 039/187] updated doctests --- src/sage/graphs/matching_covered_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index cf5feff8752..125289de79f 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2584,7 +2584,7 @@ def is_brace(self, coNP_certificate=False): sage: C = graphs.CycleGraph(6) sage: D = MatchingCoveredGraph(C) sage: D.is_brace(coNP_certificate=True) - (False, [(0, 5, None), (2, 3, None)], {0, 1, 2}) + (False, [(0, 1, None), (4, 3, None)], {0, 4, 5}) If the input matching covered graph is nonbipartite, a :exc:`ValueError` is thrown:: From b619b575e1d7b95c5c1520fb986b6a4b0ac310ce Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 22 Dec 2024 08:35:34 +0530 Subject: [PATCH 040/187] updated the doctests --- src/sage/graphs/matching_covered_graph.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 125289de79f..d0910aef5c6 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2583,8 +2583,17 @@ def is_brace(self, coNP_certificate=False): (True, None, None) sage: C = graphs.CycleGraph(6) sage: D = MatchingCoveredGraph(C) - sage: D.is_brace(coNP_certificate=True) - (False, [(0, 1, None), (4, 3, None)], {0, 4, 5}) + sage: is_brace, nontrivial_tight_cut, nontrivial_odd_component = \ + ....: D.is_brace(coNP_certificate=True) + sage: is_brace is False + True + sage: J = C.subgraph(vertices=nontrivial_odd_component) + sage: J.is_isomorphic(graphs.PathGraph(3)) + True + sage: len(nontrivial_tight_cut) == 2 + True + sage: for u, v, *_ in nontrivial_tight_cut: + ....: assert (u in nontrivial_odd_component and v not in nontrivial_odd_component) If the input matching covered graph is nonbipartite, a :exc:`ValueError` is thrown:: From 62e79228314934c5a7d96abe2041269b4047ff88 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sun, 22 Dec 2024 17:36:12 +0700 Subject: [PATCH 041/187] Remove backslash hack in doctest --- src/sage/doctest/parsing.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 79a92835b26..cd5337a88d2 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -1016,20 +1016,10 @@ def parse(self, string, *args): find_sage_continuation = re.compile(r"^(\s*)\.\.\.\.:", re.M) find_python_continuation = re.compile(r"^(\s*)\.\.\.([^\.])", re.M) python_prompt = re.compile(r"^(\s*)>>>", re.M) - backslash_replacer = re.compile(r"""(\s*)sage:(.*)\\\ * -\ *((\.){4}:)?\ *""") # The following are used to allow ... at the beginning of output ellipsis_tag = "" - # Hack for non-standard backslash line escapes accepted by the current - # doctest system. - m = backslash_replacer.search(string) - while m is not None: - g = m.groups() - string = string[:m.start()] + g[0] + "sage:" + g[1] + string[m.end():] - m = backslash_replacer.search(string, m.start()) - replace_ellipsis = not python_prompt.search(string) if replace_ellipsis: # There are no >>> prompts, so we can allow ... to begin the output From 2a8963147b76244ffe6c2042d83e119e8b68d29c Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sun, 22 Dec 2024 19:40:34 +0700 Subject: [PATCH 042/187] Update documentation --- src/doc/en/developer/coding_basics.rst | 8 +++----- src/sage/doctest/parsing.py | 20 -------------------- 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index 9b56de46ad0..47511e31111 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -1093,12 +1093,10 @@ written. The :ref:`doctest fixer ` uses tab stops at columns 48, 56, 64, ... for these tags. -- **Split long lines:** You may want to split long lines of code with a - backslash. Note: this syntax is non-standard and may be removed in the - future:: +- **Split long lines:** Standard Python rules apply. For example:: - sage: n = 123456789123456789123456789\ - ....: 123456789123456789123456789 + sage: n = (123456789123456789123456789 + + ....: 123456789123456789123456789) sage: n.is_prime() False diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index cd5337a88d2..6b268719abb 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -880,26 +880,6 @@ def parse(self, string, *args): sage: ex.source 'for i in range(Integer(4)):\n print(i)\n' - Sage currently accepts backslashes as indicating that the end - of the current line should be joined to the next line. This - feature allows for breaking large integers over multiple lines - but is not standard for Python doctesting. It's not - guaranteed to persist:: - - sage: n = 1234\ - ....: 5678 - sage: print(n) - 12345678 - sage: type(n) - - - It also works without the line continuation:: - - sage: m = 8765\ - 4321 - sage: print(m) - 87654321 - Optional tags at the start of an example block persist to the end of the block (delimited by a blank line):: From 1ac874fa9fbc58a32e7cb8fe728b3c0c8e93efd3 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sun, 22 Dec 2024 20:02:02 +0700 Subject: [PATCH 043/187] Easy changes --- .../lie/branching_rules.rst | 2 +- .../en/thematic_tutorials/lie/crystals.rst | 4 +- src/doc/en/thematic_tutorials/sandpile.rst | 4 +- src/sage/coding/delsarte_bounds.py | 6 +- src/sage/coding/extended_code.py | 8 +- src/sage/coding/information_set_decoder.py | 24 +-- src/sage/coding/linear_code.py | 4 +- src/sage/coding/linear_code_no_metric.py | 46 ++-- .../designs/gen_quadrangles_with_spread.pyx | 2 +- src/sage/doctest/forker.py | 4 +- .../dynamics/arithmetic_dynamics/affine_ds.py | 2 +- .../dynamics/arithmetic_dynamics/wehlerK3.py | 202 +++++++++--------- src/sage/features/__init__.py | 4 +- src/sage/geometry/polyhedron/base4.py | 8 +- src/sage/graphs/graph.py | 4 +- src/sage/groups/conjugacy_classes.py | 12 +- src/sage/groups/group.pyx | 22 +- src/sage/interfaces/qepcad.py | 6 +- src/sage/knots/knotinfo.py | 2 +- src/sage/libs/ntl/ntl_mat_GF2.pyx | 6 +- .../differentiable/affine_connection.py | 2 +- src/sage/matrix/matrix_polynomial_dense.pyx | 44 ++-- src/sage/numerical/backends/glpk_backend.pyx | 8 +- .../backends/interactivelp_backend.pyx | 12 +- src/sage/rings/multi_power_series_ring.py | 10 +- .../rings/multi_power_series_ring_element.py | 6 +- .../rings/polynomial/multi_polynomial.pyx | 2 +- .../polynomial/multi_polynomial_ideal.py | 18 +- src/sage/rings/polynomial/pbori/gbcore.py | 2 +- .../schemes/jacobians/abstract_jacobian.py | 16 +- .../product_projective/rational_point.py | 14 +- .../schemes/product_projective/subscheme.py | 2 +- .../schemes/projective/projective_space.py | 6 +- src/sage/symbolic/expression.pyx | 90 ++++---- .../tensor/modules/tensor_with_indices.py | 4 +- .../float_doctest.py | 2 +- .../integration_doctest.py | 6 +- src/sage/topology/simplicial_complex.py | 2 +- 38 files changed, 309 insertions(+), 309 deletions(-) diff --git a/src/doc/en/thematic_tutorials/lie/branching_rules.rst b/src/doc/en/thematic_tutorials/lie/branching_rules.rst index f2c24f0e8be..422c08edba2 100644 --- a/src/doc/en/thematic_tutorials/lie/branching_rules.rst +++ b/src/doc/en/thematic_tutorials/lie/branching_rules.rst @@ -344,7 +344,7 @@ we could accomplish the branching in two steps, thus:: sage: A1xA1 = WeylCharacterRing("A1xA1", style="coroots") sage: reps = [A3(fw) for fw in A3.fundamental_weights()] sage: [pi.branch(C2, rule="symmetric").branch(B2, rule="isomorphic"). \ - branch(D2, rule="extended").branch(A1xA1, rule="isomorphic") for pi in reps] + ....: branch(D2, rule="extended").branch(A1xA1, rule="isomorphic") for pi in reps] [A1xA1(1,0) + A1xA1(0,1), 2*A1xA1(0,0) + A1xA1(1,1), A1xA1(1,0) + A1xA1(0,1)] As you can see, we've redone the branching rather circuitously this diff --git a/src/doc/en/thematic_tutorials/lie/crystals.rst b/src/doc/en/thematic_tutorials/lie/crystals.rst index fc3d867e532..ae64b3b5278 100644 --- a/src/doc/en/thematic_tutorials/lie/crystals.rst +++ b/src/doc/en/thematic_tutorials/lie/crystals.rst @@ -741,7 +741,7 @@ irreducible crystal. We can make four such crystals:: sage: C = crystals.Letters("A2") sage: T = crystals.TensorProduct(C,C,C) sage: [T1,T2,T3,T4] = \ - [crystals.TensorProduct(C,C,C,generators=[v]) for v in T.highest_weight_vectors()] + ....: [crystals.TensorProduct(C,C,C,generators=[v]) for v in T.highest_weight_vectors()] sage: [B.cardinality() for B in [T1,T2,T3,T4]] [10, 8, 8, 1] sage: [B.character(A2) for B in [T1,T2,T3,T4]] @@ -754,7 +754,7 @@ We see that two of these crystals are isomorphic, with character sage: C = crystals.Letters("A2") sage: T = crystals.TensorProduct(C,C,C) sage: [T1,T2,T3,T4] = \ - [crystals.TensorProduct(C,C,C,generators=[v]) for v in T.highest_weight_vectors()] + ....: [crystals.TensorProduct(C,C,C,generators=[v]) for v in T.highest_weight_vectors()] sage: T1.plot() Graphics object consisting of 35 graphics primitives sage: T2.plot() diff --git a/src/doc/en/thematic_tutorials/sandpile.rst b/src/doc/en/thematic_tutorials/sandpile.rst index 417f10e4dbd..0c7b2b05a18 100644 --- a/src/doc/en/thematic_tutorials/sandpile.rst +++ b/src/doc/en/thematic_tutorials/sandpile.rst @@ -1174,7 +1174,7 @@ dict (configuration) EXAMPLES:: sage: g = {0:{},1:{0:1,3:1,4:1},2:{0:1,3:1,5:1}, \ - 3:{2:1,5:1},4:{1:1,3:1},5:{2:1,3:1}} + ....: 3:{2:1,5:1},4:{1:1,3:1},5:{2:1,3:1}} sage: S = Sandpile(g,0) sage: S.burning_config() {1: 2, 2: 0, 3: 1, 4: 1, 5: 0} @@ -1226,7 +1226,7 @@ OUTPUT: dict EXAMPLES:: sage: g = {0:{},1:{0:1,3:1,4:1},2:{0:1,3:1,5:1},\ - 3:{2:1,5:1},4:{1:1,3:1},5:{2:1,3:1}} + ....: 3:{2:1,5:1},4:{1:1,3:1},5:{2:1,3:1}} sage: S = Sandpile(g,0) sage: S.burning_config() {1: 2, 2: 0, 3: 1, 4: 1, 5: 0} diff --git a/src/sage/coding/delsarte_bounds.py b/src/sage/coding/delsarte_bounds.py index f3dedb7a720..a34099fd548 100644 --- a/src/sage/coding/delsarte_bounds.py +++ b/src/sage/coding/delsarte_bounds.py @@ -490,7 +490,7 @@ def delsarte_bound_additive_hamming_space(n, d, q, d_star=1, q_base=0, return_da sage: codes.bounds.delsarte_bound_additive_hamming_space(11, 6, 2) 3 sage: a,p,val = codes.bounds.delsarte_bound_additive_hamming_space(\ - 11, 6, 2, return_data=True) + ....: 11, 6, 2, return_data=True) sage: [j for i,j in p.get_values(a).items()] [1, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0] @@ -514,13 +514,13 @@ def delsarte_bound_additive_hamming_space(n, d, q, d_star=1, q_base=0, return_da TESTS:: sage: a,p,x = codes.bounds.delsarte_bound_additive_hamming_space(\ - 19,15,7,return_data=True,isinteger=True) + ....: 19,15,7,return_data=True,isinteger=True) sage: [j for i,j in p.get_values(a).items()] [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 307, 0, 0, 1, 34] sage: codes.bounds.delsarte_bound_additive_hamming_space(19,15,7,solver='glpk') 3 sage: codes.bounds.delsarte_bound_additive_hamming_space(\ - 19,15,7, isinteger=True, solver='glpk') + ....: 19,15,7, isinteger=True, solver='glpk') 3 """ from sage.numerical.mip import MIPSolverException diff --git a/src/sage/coding/extended_code.py b/src/sage/coding/extended_code.py index 46335b19bdc..87288902820 100644 --- a/src/sage/coding/extended_code.py +++ b/src/sage/coding/extended_code.py @@ -134,8 +134,8 @@ def parity_check_matrix(self): EXAMPLES:: sage: C = LinearCode(matrix(GF(2),[[1,0,0,1,1],\ - [0,1,0,1,0],\ - [0,0,1,1,1]])) + ....: [0,1,0,1,0],\ + ....: [0,0,1,1,1]])) sage: C.parity_check_matrix() [1 0 1 0 1] [0 1 0 1 1] @@ -259,8 +259,8 @@ def generator_matrix(self): EXAMPLES:: sage: C = LinearCode(matrix(GF(2),[[1,0,0,1,1],\ - [0,1,0,1,0],\ - [0,0,1,1,1]])) + ....: [0,1,0,1,0],\ + ....: [0,0,1,1,1]])) sage: Ce = codes.ExtendedCode(C) sage: E = codes.encoders.ExtendedCodeExtendedMatrixEncoder(Ce) sage: E.generator_matrix() diff --git a/src/sage/coding/information_set_decoder.py b/src/sage/coding/information_set_decoder.py index c059b185816..99f54cdfbfc 100644 --- a/src/sage/coding/information_set_decoder.py +++ b/src/sage/coding/information_set_decoder.py @@ -157,10 +157,10 @@ def decode(self, r): EXAMPLES:: sage: M = matrix(GF(2), [[1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0],\ - [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1],\ - [0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0],\ - [0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1],\ - [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1]]) + ....: [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1],\ + ....: [0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0],\ + ....: [0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1],\ + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1]]) sage: C = codes.LinearCode(M) sage: from sage.coding.information_set_decoder import LeeBrickellISDAlgorithm sage: A = LeeBrickellISDAlgorithm(C, (2,2)) @@ -448,10 +448,10 @@ def decode(self, r): EXAMPLES:: sage: M = matrix(GF(2), [[1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0],\ - [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1],\ - [0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0],\ - [0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1],\ - [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1]]) + ....: [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1],\ + ....: [0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0],\ + ....: [0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1],\ + ....: [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1]]) sage: C = codes.LinearCode(M) sage: from sage.coding.information_set_decoder import LeeBrickellISDAlgorithm sage: A = LeeBrickellISDAlgorithm(C, (2,2)) @@ -929,10 +929,10 @@ def decode_to_code(self, r): EXAMPLES:: sage: M = matrix(GF(2), [[1,0,0,0,0,0,1,0,1,0,1,1,0,0,1],\ - [0,1,0,0,0,1,1,1,1,0,0,0,0,1,1],\ - [0,0,1,0,0,0,0,1,0,1,1,1,1,1,0],\ - [0,0,0,1,0,0,1,0,1,0,0,0,1,1,0],\ - [0,0,0,0,1,0,0,0,1,0,1,1,0,1,0]]) + ....: [0,1,0,0,0,1,1,1,1,0,0,0,0,1,1],\ + ....: [0,0,1,0,0,0,0,1,0,1,1,1,1,1,0],\ + ....: [0,0,0,1,0,0,1,0,1,0,0,0,1,1,0],\ + ....: [0,0,0,0,1,0,0,0,1,0,1,1,0,1,0]]) sage: C = LinearCode(M) sage: c = C.random_element() sage: Chan = channels.StaticErrorRateChannel(C.ambient_space(), 2) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 3e9d388c434..690a52b5fa8 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -66,8 +66,8 @@ class should inherit from this class. Also ``AbstractLinearCode`` should never A ``LinearCode`` is instantiated by providing a generator matrix:: sage: M = matrix(GF(2), [[1, 0, 0, 1, 0],\ - [0, 1, 0, 1, 1],\ - [0, 0, 1, 1, 1]]) + ....: [0, 1, 0, 1, 1],\ + ....: [0, 0, 1, 1, 1]]) sage: C = codes.LinearCode(M) sage: C [5, 3] linear code over GF(2) diff --git a/src/sage/coding/linear_code_no_metric.py b/src/sage/coding/linear_code_no_metric.py index 49c30a415c8..c509da57a89 100644 --- a/src/sage/coding/linear_code_no_metric.py +++ b/src/sage/coding/linear_code_no_metric.py @@ -527,7 +527,7 @@ def systematic_generator_matrix(self, systematic_positions=None): EXAMPLES:: sage: G = matrix(GF(3), [[ 1, 2, 1, 0],\ - [ 2, 1, 1, 1]]) + ....: [ 2, 1, 1, 1]]) sage: C = LinearCode(G) sage: C.generator_matrix() [1 2 1 0] @@ -579,8 +579,8 @@ def standard_form(self, return_permutation=True): sage: Cs is C True sage: C = LinearCode(matrix(GF(2), [[1,0,0,0,1,1,0],\ - [0,1,0,1,0,1,0],\ - [0,0,0,0,0,0,1]])) + ....: [0,1,0,1,0,1,0],\ + ....: [0,0,0,0,0,0,1]])) sage: Cs, p = C.standard_form() sage: p [1, 2, 7, 3, 4, 5, 6] @@ -629,7 +629,7 @@ def redundancy_matrix(self): [1 1 0] [1 1 1] sage: C = LinearCode(matrix(GF(3),2,[1,2,0,\ - 2,1,1])) + ....: 2,1,1])) sage: C.systematic_generator_matrix() [1 2 0] [0 0 1] @@ -1055,9 +1055,9 @@ class LinearCodeSystematicEncoder(Encoder): sage: LCSE = codes.encoders.LinearCodeSystematicEncoder sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0,0],\ - [1,0,0,1,1,0,0,0],\ - [0,1,0,1,0,1,0,0],\ - [1,1,0,1,0,0,1,1]]) + ....: [1,0,0,1,1,0,0,0],\ + ....: [0,1,0,1,0,1,0,0],\ + ....: [1,1,0,1,0,0,1,1]]) sage: C = LinearCode(G) sage: E = LCSE(C) sage: E.generator_matrix() @@ -1209,9 +1209,9 @@ def generator_matrix(self): sage: LCSE = codes.encoders.LinearCodeSystematicEncoder sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],\ - [1,0,0,1,1,0,0],\ - [0,1,0,1,0,1,0],\ - [1,1,0,1,0,0,1]]) + ....: [1,0,0,1,1,0,0],\ + ....: [0,1,0,1,0,1,0],\ + ....: [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: E = LCSE(C) sage: E.generator_matrix() @@ -1232,9 +1232,9 @@ def generator_matrix(self): Another example where there is no generator matrix of the form `[I \vert H]`:: sage: G = Matrix(GF(2), [[1,1,0,0,1,0,1],\ - [1,1,0,0,1,0,0],\ - [0,0,1,0,0,1,0],\ - [0,0,1,0,1,0,1]]) + ....: [1,1,0,0,1,0,0],\ + ....: [0,0,1,0,0,1,0],\ + ....: [0,0,1,0,1,0,1]]) sage: C = LinearCode(G) sage: E = LCSE(C) sage: E.generator_matrix() @@ -1279,8 +1279,8 @@ def systematic_permutation(self): EXAMPLES:: sage: C = LinearCode(matrix(GF(2), [[1,0,0,0,1,1,0],\ - [0,1,0,1,0,1,0],\ - [0,0,0,0,0,0,1]])) + ....: [0,1,0,1,0,1,0],\ + ....: [0,0,0,0,0,0,1]])) sage: E = codes.encoders.LinearCodeSystematicEncoder(C) sage: E.systematic_positions() (0, 1, 6) @@ -1311,9 +1311,9 @@ def systematic_positions(self): sage: LCSE = codes.encoders.LinearCodeSystematicEncoder sage: G = Matrix(GF(2), [[1,1,1,0,0,0,0],\ - [1,0,0,1,1,0,0],\ - [0,1,0,1,0,1,0],\ - [1,1,0,1,0,0,1]]) + ....: [1,0,0,1,1,0,0],\ + ....: [0,1,0,1,0,1,0],\ + ....: [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: E = LCSE(C) sage: E.systematic_positions() @@ -1322,9 +1322,9 @@ def systematic_positions(self): We take another matrix with a less nice shape:: sage: G = Matrix(GF(2), [[1,1,0,0,1,0,1],\ - [1,1,0,0,1,0,0],\ - [0,0,1,0,0,1,0],\ - [0,0,1,0,1,0,1]]) + ....: [1,1,0,0,1,0,0],\ + ....: [0,0,1,0,0,1,0],\ + ....: [0,0,1,0,1,0,1]]) sage: C = LinearCode(G) sage: E = LCSE(C) sage: E.systematic_positions() @@ -1345,8 +1345,8 @@ def systematic_positions(self): positions (even if another choice might also be systematic):: sage: G = Matrix(GF(2), [[1,0,0,0],\ - [0,1,0,0],\ - [0,0,1,1]]) + ....: [0,1,0,0],\ + ....: [0,0,1,1]]) sage: C = LinearCode(G) sage: E = LCSE(C, systematic_positions=[0,1,3]) sage: E.systematic_positions() diff --git a/src/sage/combinat/designs/gen_quadrangles_with_spread.pyx b/src/sage/combinat/designs/gen_quadrangles_with_spread.pyx index f5912e83690..43eeecf4c0c 100644 --- a/src/sage/combinat/designs/gen_quadrangles_with_spread.pyx +++ b/src/sage/combinat/designs/gen_quadrangles_with_spread.pyx @@ -267,7 +267,7 @@ def generalised_quadrangle_hermitian_with_ovoid(const int q): TESTS:: sage: from sage.combinat.designs.gen_quadrangles_with_spread import \ - is_GQ_with_spread, dual_GQ_ovoid + ....: is_GQ_with_spread, dual_GQ_ovoid sage: t = designs.generalised_quadrangle_hermitian_with_ovoid(3) sage: t = dual_GQ_ovoid(*t) sage: is_GQ_with_spread(*t, s=3, t=9) diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index bf6d49906de..f728d1e2a99 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -1806,8 +1806,8 @@ def parallel_dispatch(self): canceled:: sage: from tempfile import NamedTemporaryFile as NTF - sage: with NTF(suffix='.py', mode='w+t') as f1, \ - ....: NTF(suffix='.py', mode='w+t') as f2: + sage: with (NTF(suffix='.py', mode='w+t') as f1, + ....: NTF(suffix='.py', mode='w+t') as f2): ....: _ = f1.write("'''\nsage: import time; time.sleep(60)\n'''") ....: f1.flush() ....: _ = f2.write("'''\nsage: True\nFalse\n'''") diff --git a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py index ecf61822ba9..77daa006bf4 100644 --- a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py @@ -519,7 +519,7 @@ def dynatomic_polynomial(self, period): sage: R. = QQ[] sage: Pc. = ProjectiveSpace(R, 1) sage: G = DynamicalSystem_projective([(1/2*c + 1/2)*x^2 + (-2*c)*x*y + 2*c*y^2 , \ - (1/4*c + 1/2)*x^2 + (-c - 1)*x*y + (c + 1)*y^2]) + ....: (1/4*c + 1/2)*x^2 + (-c - 1)*x*y + (c + 1)*y^2]) sage: G.dehomogenize(1).dynatomic_polynomial(2) (1/4*c + 1/4)*x^2 + (-c - 1/2)*x + c + 1 """ diff --git a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py index 766dff990e0..f0a4ee8a173 100644 --- a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py +++ b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py @@ -205,11 +205,11 @@ def _check_satisfies_equations(self, P): sage: P. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 \ - + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 - \ - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ - - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - \ - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ - + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 - \ + ....: 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ + ....: - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - \ + ....: 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ + ....: + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0 * y0 + x1 * y1 + x2 * y2 sage: X = WehlerK3Surface([Z, Y]) sage: X._check_satisfies_equations([0, 0, 1, 1, 0, 0]) @@ -219,11 +219,11 @@ def _check_satisfies_equations(self, P): sage: P. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 \ - + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 - \ - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ - - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - \ - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ - + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 - \ + ....: 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ + ....: - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - \ + ....: 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ + ....: + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: X._check_satisfies_equations([0, 1, 1, 1, 0, 0]) @@ -262,7 +262,7 @@ def _Lcoeff(self, component, i): sage: R. = PolynomialRing(ZZ, 6) sage: Y = x0*y0 + x1*y1 - x2*y2 sage: Z = x0^2*y0*y1 + x0^2*y2^2 - x0*x1*y1*y2 + x1^2*y2*y1 \ - + x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 + ....: + x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 sage: X = WehlerK3Surface([Z, Y]) sage: X._Lcoeff(0, 0) y0 @@ -272,7 +272,7 @@ def _Lcoeff(self, component, i): sage: R. = PolynomialRing(ZZ, 6) sage: Y = x0*y0 + x1*y1 - x2*y2 sage: Z =x0^2*y0*y1 + x0^2*y2^2 - x0*x1*y1*y2 + x1^2*y2*y1 \ - + x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 + ....: + x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 sage: X = WehlerK3Surface([Z, Y]) sage: X._Lcoeff(1, 0) x0 @@ -312,7 +312,7 @@ def _Qcoeff(self, component, i, j): sage: R. = PolynomialRing(ZZ, 6) sage: Y = x0*y0 + x1*y1 - x2*y2 sage: Z = x0^2*y0*y1 + x0^2*y2^2 - x0*x1*y1*y2 + x1^2*y2*y1 \ - + x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 + ....: + x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 sage: X = WehlerK3Surface([Z, Y]) sage: X._Qcoeff(0, 0, 0) y0*y1 + y2^2 @@ -322,7 +322,7 @@ def _Qcoeff(self, component, i, j): sage: R. = PolynomialRing(ZZ, 6) sage: Y = x0*y0 + x1*y1 - x2*y2 sage: Z = x0^2*y0*y1 + x0^2*y2^2 - x0*x1*y1*y2 + x1^2*y2*y1 \ - + x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 + ....: + x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 sage: X = WehlerK3Surface([Z, Y]) sage: X._Qcoeff(1, 1, 0) x0^2 @@ -360,7 +360,7 @@ def Gpoly(self, component, k): sage: R. = PolynomialRing(ZZ, 6) sage: Y = x0*y0 + x1*y1 - x2*y2 sage: Z = x0^2*y0*y1 + x0^2*y2^2 - x0*x1*y1*y2 + x1^2*y2*y1 \ - + x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 + ....: + x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 sage: X = WehlerK3Surface([Z, Y]) sage: X.Gpoly(1, 0) x0^2*x1^2 + x1^4 - x0*x1^2*x2 + x1^3*x2 + x1^2*x2^2 + x2^4 @@ -406,7 +406,7 @@ def Hpoly(self, component, i, j): sage: R. = PolynomialRing(ZZ, 6) sage: Y = x0*y0 + x1*y1 - x2*y2 sage: Z = x0^2*y0*y1 + x0^2*y2^2 - x0*x1*y1*y2 + x1^2*y2*y1 \ - + x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 + ....: + x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 sage: X = WehlerK3Surface([Z, Y]) sage: X.Hpoly(0, 1, 0) 2*y0*y1^3 + 2*y0*y1*y2^2 - y1*y2^3 @@ -449,10 +449,10 @@ def Lxa(self, a): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 \ - + 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - \ - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - 4*x1*x2*y1^2 \ - + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 \ - + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: + 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - \ + ....: x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - 4*x1*x2*y1^2 \ + ....: + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 \ + ....: + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = PP(1, 1, 0, 1, 0, 0) @@ -489,9 +489,9 @@ def Qxa(self, a): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 \ - - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - 4*x1*x2*y1^2 \ - + 5*x0*x2*y0*y2 \ - - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - 4*x1*x2*y1^2 \ + ....: + 5*x0*x2*y0*y2 \ + ....: - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = PP(1, 1, 0, 1, 0, 0) @@ -528,10 +528,10 @@ def Sxa(self, a): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 \ - + 3*x0*x1*y0*y1 \ - - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - 4*x1*x2*y1^2 \ - + 5*x0*x2*y0*y2 \ - - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: + 3*x0*x1*y0*y1 \ + ....: - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - 4*x1*x2*y1^2 \ + ....: + 5*x0*x2*y0*y2 \ + ....: - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) @@ -566,10 +566,10 @@ def Lyb(self, b): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z =x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 \ - + 3*x0*x1*y0*y1 \ - - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - 4*x1*x2*y1^2 \ - + 5*x0*x2*y0*y2 \ - - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: + 3*x0*x1*y0*y1 \ + ....: - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - 4*x1*x2*y1^2 \ + ....: + 5*x0*x2*y0*y2 \ + ....: - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) @@ -607,9 +607,9 @@ def Qyb(self, b): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 \ - + 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ - - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 \ - + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: + 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ + ....: - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 \ + ....: + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = PP(1, 1, 0, 1, 0, 0) @@ -645,9 +645,9 @@ def Syb(self, b): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + \ - 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ - - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 \ - + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ + ....: - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 \ + ....: + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0 * y0 + x1 * y1 + x2 * y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = PP(1, 1, 0, 1, 0, 0) @@ -721,7 +721,7 @@ def is_degenerate(self): sage: R. = PolynomialRing(ZZ, 6) sage: Y = x0*y0 + x1*y1 - x2*y2 sage: Z = x0^2*y0*y1 + x0^2*y2^2 - x0*x1*y1*y2 + x1^2*y2*y1 + x2^2*y2^2 + \ - x2^2*y1^2 + x1^2*y2^2 + ....: x2^2*y1^2 + x1^2*y2^2 sage: X = WehlerK3Surface([Z, Y]) sage: X.is_degenerate() True @@ -730,8 +730,8 @@ def is_degenerate(self): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 - \ - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - \ - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - \ + ....: 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: X.is_degenerate() @@ -741,8 +741,8 @@ def is_degenerate(self): sage: PP. = ProductProjectiveSpaces([2, 2], GF(3)) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 - \ - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - \ - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - \ + ....: 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: X.is_degenerate() @@ -801,7 +801,7 @@ def degenerate_fibers(self): sage: R. = PolynomialRing(ZZ, 6) sage: Y = x0*y0 + x1*y1 - x2*y2 sage: Z = x0^2*y0*y1 + x0^2*y2^2 - x0*x1*y1*y2 + x1^2*y2*y1 + x2^2*y2^2\ - + x2^2*y1^2 + x1^2*y2^2 + ....: + x2^2*y1^2 + x1^2*y2^2 sage: X = WehlerK3Surface([Z, Y]) sage: X.degenerate_fibers() [[], [(1 : 0 : 0)]] @@ -824,7 +824,7 @@ def degenerate_fibers(self): sage: R = PP.coordinate_ring() sage: l = y0*x0 + y1*x1 + (y0 - y1)*x2 sage: q = (y1*y0 + y2^2)*x0^2 + ((y0^2 - y2*y1)*x1 + (y0^2 + (y1^2 - y2^2))*x2)*x0 \ - + (y2*y0 + y1^2)*x1^2 + (y0^2 + (-y1^2 + y2^2))*x2*x1 + ....: + (y2*y0 + y1^2)*x1^2 + (y0^2 + (-y1^2 + y2^2))*x2*x1 sage: X = WehlerK3Surface([l,q]) sage: X.degenerate_fibers() [[(-1 : 1 : 1), (0 : 0 : 1)], [(-1 : -1 : 1), (0 : 0 : 1)]] @@ -928,9 +928,9 @@ def degenerate_primes(self, check=True): sage: R. = PolynomialRing(QQ, 6) sage: L = y0*x0 + (y1*x1 + y2*x2) sage: Q = (2*y0^2 + y2*y0 + (2*y1^2 + y2^2))*x0^2 + ((y0^2 + y1*y0 + \ - (y1^2 + 2*y2*y1 + y2^2))*x1 + (2*y1^2 + y2*y1 + y2^2)*x2)*x0 + ((2*y0^2\ - + (y1 + 2*y2)*y0 + (2*y1^2 + y2*y1))*x1^2 + ((2*y1 + 2*y2)*y0 + (y1^2 + \ - y2*y1 + 2*y2^2))*x2*x1 + (2*y0^2 + y1*y0 + (2*y1^2 + y2^2))*x2^2) + ....: (y1^2 + 2*y2*y1 + y2^2))*x1 + (2*y1^2 + y2*y1 + y2^2)*x2)*x0 + ((2*y0^2\ + ....: + (y1 + 2*y2)*y0 + (2*y1^2 + y2*y1))*x1^2 + ((2*y1 + 2*y2)*y0 + (y1^2 + \ + ....: y2*y1 + 2*y2^2))*x2*x1 + (2*y0^2 + y1*y0 + (2*y1^2 + y2^2))*x2^2) sage: X = WehlerK3Surface([L, Q]) sage: X.degenerate_primes() [2, 3, 5, 11, 23, 47, 48747691, 111301831] @@ -1019,7 +1019,7 @@ def is_smooth(self): sage: R. = PolynomialRing(ZZ, 6) sage: Y = x0*y0 + x1*y1 - x2*y2 sage: Z = x0^2*y0*y1 + x0^2*y2^2 - x0*x1*y1*y2 + x1^2*y2*y1 +\ - x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 + ....: x2^2*y2^2 + x2^2*y1^2 + x1^2*y2^2 sage: X = WehlerK3Surface([Z, Y]) sage: X.is_smooth() False @@ -1028,9 +1028,9 @@ def is_smooth(self): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + \ - 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ - - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ - + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ + ....: - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ + ....: + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: X.is_smooth() @@ -1083,9 +1083,9 @@ def sigmaX(self, P, **kwds): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 +\ - 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -\ - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 +\ - 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -\ + ....: 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 +\ + ....: 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = PP(0, 0, 1, 1, 0, 0) @@ -1097,7 +1097,7 @@ def sigmaX(self, P, **kwds): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: l = y0*x0 + y1*x1 + (y0 - y1)*x2 sage: q = (y1*y0)*x0^2 + ((y0^2)*x1 + (y0^2 + (y1^2 - y2^2))*x2)*x0\ - + (y2*y0 + y1^2)*x1^2 + (y0^2 + (-y1^2 + y2^2))*x2*x1 + ....: + (y2*y0 + y1^2)*x1^2 + (y0^2 + (-y1^2 + y2^2))*x2*x1 sage: X = WehlerK3Surface([l, q]) sage: X.sigmaX(X([1, 0, 0, 0, 1, -2])) (1 : 0 : 0 , 0 : 1/2 : 1) @@ -1330,9 +1330,9 @@ def sigmaY(self, P, **kwds): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + \ - 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ - - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ - + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ + ....: - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ + ....: + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = PP(0, 0, 1, 1, 0, 0) @@ -1344,7 +1344,7 @@ def sigmaY(self, P, **kwds): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: l = y0*x0 + y1*x1 + (y0 - y1)*x2 sage: q = (y1*y0)*x0^2 + ((y0^2)*x1 + (y0^2 + (y1^2 - y2^2))*x2)*x0 +\ - (y2*y0 + y1^2)*x1^2 + (y0^2 + (-y1^2 + y2^2))*x2*x1 + ....: (y2*y0 + y1^2)*x1^2 + (y0^2 + (-y1^2 + y2^2))*x2*x1 sage: X = WehlerK3Surface([l, q]) sage: X.sigmaY(X([1, -1, 0 ,-1, -1, 1])) (1/10 : -1/10 : 1 , -1 : -1 : 1) @@ -1566,9 +1566,9 @@ def phi(self, a, **kwds): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + \ - 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ - - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ - + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ + ....: - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ + ....: + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = PP([0, 0, 1, 1 ,0, 0]) @@ -1606,9 +1606,9 @@ def psi(self, a, **kwds): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + \ - 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ - - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ - + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ + ....: - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ + ....: + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = PP([0, 0, 1, 1, 0, 0]) @@ -1651,8 +1651,8 @@ def lambda_plus(self, P, v, N, m, n, prec=100): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1\ - - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -4*x1*x2*y1^2 + 5*x0*x2*y0*y2\ - - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -4*x1*x2*y1^2 + 5*x0*x2*y0*y2\ + ....: - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: P = X([0, 0, 1, 1, 0, 0]) @@ -1751,8 +1751,8 @@ def lambda_minus(self, P, v, N, m, n, prec=100): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 \ - - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -4*x1*x2*y1^2 + 5*x0*x2*y0*y2\ - - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -4*x1*x2*y1^2 + 5*x0*x2*y0*y2\ + ....: - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: P = X([0, 0, 1, 1, 0, 0]) @@ -1844,8 +1844,8 @@ def canonical_height_plus(self, P, N, badprimes=None, prec=100): sage: R. = PolynomialRing(QQ, 6) sage: L = (-y0 - y1)*x0 + (-y0*x1 - y2*x2) sage: Q = (-y2*y0 - y1^2)*x0^2 + ((-y0^2 - y2*y0 + (-y2*y1 - y2^2))*x1 + \ - (-y0^2 - y2*y1)*x2)*x0 + ((-y0^2 - y2*y0 - y2^2)*x1^2 + (-y2*y0 - y1^2)*x2*x1 \ - + (-y0^2 + (-y1 - y2)*y0)*x2^2) + ....: (-y0^2 - y2*y1)*x2)*x0 + ((-y0^2 - y2*y0 - y2^2)*x1^2 + (-y2*y0 - y1^2)*x2*x1 \ + ....: + (-y0^2 + (-y1 - y2)*y0)*x2^2) sage: X = WehlerK3Surface([L, Q]) sage: P = X([1, 0, -1, 1, -1, 0]) #order 16 sage: X.canonical_height_plus(P, 5) # long time @@ -1856,9 +1856,9 @@ def canonical_height_plus(self, P, N, badprimes=None, prec=100): sage: set_verbose(None) sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + \ - 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ - - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ - + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ + ....: - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ + ....: + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: P = X([0, 1, 0, 0, 0, 1]) @@ -1908,8 +1908,8 @@ def canonical_height_minus(self, P, N, badprimes=None, prec=100): sage: R. = PolynomialRing(QQ, 6) sage: L = (-y0 - y1)*x0 + (-y0*x1 - y2*x2) sage: Q = (-y2*y0 - y1^2)*x0^2 + ((-y0^2 - y2*y0 + (-y2*y1 - y2^2))*x1\ - + (-y0^2 - y2*y1)*x2)*x0 + ((-y0^2 - y2*y0 - y2^2)*x1^2 + (-y2*y0 - y1^2)*x2*x1\ - + (-y0^2 + (-y1 - y2)*y0)*x2^2) + ....: + (-y0^2 - y2*y1)*x2)*x0 + ((-y0^2 - y2*y0 - y2^2)*x1^2 + (-y2*y0 - y1^2)*x2*x1\ + ....: + (-y0^2 + (-y1 - y2)*y0)*x2^2) sage: X = WehlerK3Surface([L, Q]) sage: P = X([1, 0, -1, 1, -1, 0]) #order 16 sage: X.canonical_height_minus(P, 5) # long time @@ -1920,9 +1920,9 @@ def canonical_height_minus(self, P, N, badprimes=None, prec=100): sage: set_verbose(None) sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 +\ - 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - \ - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + \ - x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - \ + ....: 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + \ + ....: x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: P = X([0, 1, 0, 0, 0, 1]) @@ -1970,8 +1970,8 @@ def canonical_height(self, P, N, badprimes=None, prec=100): sage: R. = PolynomialRing(QQ, 6) sage: L = (-y0 - y1)*x0 + (-y0*x1 - y2*x2) sage: Q = (-y2*y0 - y1^2)*x0^2 + ((-y0^2 - y2*y0 + (-y2*y1 - y2^2))*x1 + \ - (-y0^2 - y2*y1)*x2)*x0 + ((-y0^2 - y2*y0 - y2^2)*x1^2 + (-y2*y0 - y1^2)*x2*x1 \ - + (-y0^2 + (-y1 - y2)*y0)*x2^2) + ....: (-y0^2 - y2*y1)*x2)*x0 + ((-y0^2 - y2*y0 - y2^2)*x1^2 + (-y2*y0 - y1^2)*x2*x1 \ + ....: + (-y0^2 + (-y1 - y2)*y0)*x2^2) sage: X = WehlerK3Surface([L, Q]) sage: P = X([1, 0, -1, 1,- 1, 0]) #order 16 sage: X.canonical_height(P, 5) # long time @@ -1982,8 +1982,8 @@ def canonical_height(self, P, N, badprimes=None, prec=100): sage: set_verbose(None) sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 - \ - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 \ - -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 \ + ....: -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: P = X(0, 1, 0, 0, 0, 1) @@ -2015,7 +2015,7 @@ def fiber(self, p, component): sage: R. = PolynomialRing(ZZ, 6) sage: Y = x0*y0 + x1*y1 - x2*y2 sage: Z = y0^2*x0*x1 + y0^2*x2^2 - y0*y1*x1*x2 + y1^2*x2*x1 + y2^2*x2^2 +\ - y2^2*x1^2 + y1^2*x2^2 + ....: y2^2*x1^2 + y1^2*x2^2 sage: X = WehlerK3Surface([Z, Y]) sage: Proj = ProjectiveSpace(QQ, 2) sage: P = Proj([1, 0, 0]) @@ -2028,8 +2028,8 @@ def fiber(self, p, component): sage: P. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 - \ - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - \ - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - \ + ....: 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: Proj = P[0] @@ -2219,7 +2219,7 @@ def nth_iterate_phi(self, P, n, **kwds): sage: R.=PolynomialRing(QQ, 6) sage: L = (-y0 - y1)*x0 + (-y0*x1 - y2*x2) sage: Q = (-y2*y0 - y1^2)*x0^2 + ((-y0^2 - y2*y0 + (-y2*y1 - y2^2))*x1 + (-y0^2 - y2*y1)*x2)*x0 \ - + ((-y0^2 - y2*y0 - y2^2)*x1^2 + (-y2*y0 - y1^2)*x2*x1 + (-y0^2 + (-y1 - y2)*y0)*x2^2) + ....: + ((-y0^2 - y2*y0 - y2^2)*x1^2 + (-y2*y0 - y1^2)*x2*x1 + (-y0^2 + (-y1 - y2)*y0)*x2^2) sage: X = WehlerK3Surface([L, Q]) sage: P = X([1, 0, -1, 1, -1, 0]) sage: X.nth_iterate_phi(P, 8) == X.nth_iterate_psi(P, 8) @@ -2319,9 +2319,9 @@ def orbit_phi(self, P, N, **kwds): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + \ - 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - \ - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + \ - x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - \ + ....: 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + \ + ....: x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = PP(0, 0, 1, 1, 0, 0) @@ -2378,9 +2378,9 @@ def orbit_psi(self, P, N, **kwds): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + \ - 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - \ - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + \ - x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 - \ + ....: 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + \ + ....: x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = X(0, 0, 1, 1, 0, 0) @@ -2424,9 +2424,9 @@ def is_isomorphic(self, right): sage: PP. = ProductProjectiveSpaces([2, 2], QQ) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + \ - 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ - -4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ - + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 3*x0*x1*y0*y1 -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ + ....: -4*x1*x2*y1^2 + 5*x0*x2*y0*y2 - 4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ + ....: + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: W = WehlerK3Surface([Z + Y^2, Y]) @@ -2463,8 +2463,8 @@ def is_symmetric_orbit(self, orbit): sage: PP. = ProductProjectiveSpaces([2, 2], GF(7)) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + 3*x0*x1*y0*y1 \ - -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -4*x1*x2*y1^2 + 5*x0*x2*y0*y2 \ - -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: -2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 -4*x1*x2*y1^2 + 5*x0*x2*y0*y2 \ + ....: -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: T = PP([0, 0, 1, 1, 0, 0]) @@ -2517,9 +2517,9 @@ def cardinality( self): sage: PP. = ProductProjectiveSpaces([2, 2], GF(7)) sage: Z = x0^2*y0^2 + 3*x0*x1*y0^2 + x1^2*y0^2 + 4*x0^2*y0*y1 + \ - 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ - - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ - + x0*x1*y2^2 + 3*x2^2*y2^2 + ....: 3*x0*x1*y0*y1 - 2*x2^2*y0*y1 - x0^2*y1^2 + 2*x1^2*y1^2 - x0*x2*y1^2 \ + ....: - 4*x1*x2*y1^2 + 5*x0*x2*y0*y2 -4*x1*x2*y0*y2 + 7*x0^2*y1*y2 + 4*x1^2*y1*y2 \ + ....: + x0*x1*y2^2 + 3*x2^2*y2^2 sage: Y = x0*y0 + x1*y1 + x2*y2 sage: X = WehlerK3Surface([Z, Y]) sage: X.cardinality() diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index ac4a0bcd97f..62de2b8e0c5 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -821,8 +821,8 @@ def absolute_filename(self) -> str: sage: from sage.features import StaticFile sage: StaticFile(name='no_such_file', filename='KaT1aihu',\ - search_path=(), spkg='some_spkg',\ - url='http://rand.om').absolute_filename() # optional - sage_spkg + ....: search_path=(), spkg='some_spkg',\ + ....: url='http://rand.om').absolute_filename() # optional - sage_spkg Traceback (most recent call last): ... FeatureNotPresentError: no_such_file is not available. diff --git a/src/sage/geometry/polyhedron/base4.py b/src/sage/geometry/polyhedron/base4.py index ea0423c60fe..55a20537607 100644 --- a/src/sage/geometry/polyhedron/base4.py +++ b/src/sage/geometry/polyhedron/base4.py @@ -1126,10 +1126,10 @@ def is_combinatorially_isomorphic(self, other, algorithm='bipartite_graph'): Two polytopes with the same `f`-vector, but different combinatorial types:: sage: P = Polyhedron([[-605520/1525633, -605520/1525633, -1261500/1525633, -52200/1525633, 11833/1525633],\ - [-720/1769, -600/1769, 1500/1769, 0, -31/1769], [-216/749, 240/749, -240/749, -432/749, 461/749], \ - [-50/181, 50/181, 60/181, -100/181, -119/181], [-32/51, -16/51, -4/51, 12/17, 1/17],\ - [1, 0, 0, 0, 0], [16/129, 128/129, 0, 0, 1/129], [64/267, -128/267, 24/89, -128/267, 57/89],\ - [1200/3953, -1200/3953, -1440/3953, -360/3953, -3247/3953], [1512/5597, 1512/5597, 588/5597, 4704/5597, 2069/5597]]) + ....: [-720/1769, -600/1769, 1500/1769, 0, -31/1769], [-216/749, 240/749, -240/749, -432/749, 461/749], \ + ....: [-50/181, 50/181, 60/181, -100/181, -119/181], [-32/51, -16/51, -4/51, 12/17, 1/17],\ + ....: [1, 0, 0, 0, 0], [16/129, 128/129, 0, 0, 1/129], [64/267, -128/267, 24/89, -128/267, 57/89],\ + ....: [1200/3953, -1200/3953, -1440/3953, -360/3953, -3247/3953], [1512/5597, 1512/5597, 588/5597, 4704/5597, 2069/5597]]) sage: C = polytopes.cyclic_polytope(5,10) sage: C.f_vector() == P.f_vector(); C.f_vector() True diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 1e3025117df..de24b6f2cb1 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -104,7 +104,7 @@ :: sage: d = {0: [1,4,5], 1: [2,6], 2: [3,7], 3: [4,8], 4: [9], \ - 5: [7, 8], 6: [8,9], 7: [9]} + ....: 5: [7, 8], 6: [8,9], 7: [9]} sage: G = Graph(d); G Graph on 10 vertices sage: G.plot().show() # or G.show() # needs sage.plot @@ -308,7 +308,7 @@ objects for entries, one can make that association:: sage: d = {0 : graphs.DodecahedralGraph(), 1 : graphs.FlowerSnark(), \ - 2 : graphs.MoebiusKantorGraph(), 3 : graphs.PetersenGraph() } + ....: 2 : graphs.MoebiusKantorGraph(), 3 : graphs.PetersenGraph() } sage: d[2] Moebius-Kantor Graph: Graph on 16 vertices sage: T = graphs.TetrahedralGraph() diff --git a/src/sage/groups/conjugacy_classes.py b/src/sage/groups/conjugacy_classes.py index 2208389e17d..2bb655c926d 100644 --- a/src/sage/groups/conjugacy_classes.py +++ b/src/sage/groups/conjugacy_classes.py @@ -249,12 +249,12 @@ def set(self): sage: h = H(matrix(F,2,[1,2, -1, 1])) sage: C = ConjugacyClass(H,h) sage: S = [[[3, 2], [2, 4]], [[0, 1], [2, 2]], [[3, 4], [1, 4]],\ - [[0, 3], [4, 2]], [[1, 2], [4, 1]], [[2, 1], [2, 0]],\ - [[4, 1], [4, 3]], [[4, 4], [1, 3]], [[2, 4], [3, 0]],\ - [[1, 4], [2, 1]], [[3, 3], [3, 4]], [[2, 3], [4, 0]],\ - [[0, 2], [1, 2]], [[1, 3], [1, 1]], [[4, 3], [3, 3]],\ - [[4, 2], [2, 3]], [[0, 4], [3, 2]], [[1, 1], [3, 1]],\ - [[2, 2], [1, 0]], [[3, 1], [4, 4]]] + ....: [[0, 3], [4, 2]], [[1, 2], [4, 1]], [[2, 1], [2, 0]],\ + ....: [[4, 1], [4, 3]], [[4, 4], [1, 3]], [[2, 4], [3, 0]],\ + ....: [[1, 4], [2, 1]], [[3, 3], [3, 4]], [[2, 3], [4, 0]],\ + ....: [[0, 2], [1, 2]], [[1, 3], [1, 1]], [[4, 3], [3, 3]],\ + ....: [[4, 2], [2, 3]], [[0, 4], [3, 2]], [[1, 1], [3, 1]],\ + ....: [[2, 2], [1, 0]], [[3, 1], [4, 4]]] sage: C.set() == Set(H(x) for x in S) True diff --git a/src/sage/groups/group.pyx b/src/sage/groups/group.pyx index d004cdf98e2..64e9d27ea27 100644 --- a/src/sage/groups/group.pyx +++ b/src/sage/groups/group.pyx @@ -55,17 +55,17 @@ cdef class Group(Parent): sage: from sage.groups.group import Group sage: G = Group() sage: TestSuite(G).run(skip = ["_test_an_element",\ - "_test_associativity",\ - "_test_elements",\ - "_test_elements_eq_reflexive",\ - "_test_elements_eq_symmetric",\ - "_test_elements_eq_transitive",\ - "_test_elements_neq",\ - "_test_inverse",\ - "_test_one",\ - "_test_pickling",\ - "_test_prod",\ - "_test_some_elements"]) + ....: "_test_associativity",\ + ....: "_test_elements",\ + ....: "_test_elements_eq_reflexive",\ + ....: "_test_elements_eq_symmetric",\ + ....: "_test_elements_eq_transitive",\ + ....: "_test_elements_neq",\ + ....: "_test_inverse",\ + ....: "_test_one",\ + ....: "_test_pickling",\ + ....: "_test_prod",\ + ....: "_test_some_elements"]) Generic groups have very little functionality:: diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index df9f1583c86..2afac1b01c5 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -830,9 +830,9 @@ def __init__(self, formula, sage: (x, y, z) = var('x, y, z') sage: conds = [-z < 0, -y + z < 0, x^2 + x*y + 2*x*z + 2*y*z - x < 0, \ - x^2 + x*y + 3*x*z + 2*y*z + 2*z^2 - x - z < 0, \ - -2*x + 1 < 0, -x*y - x*z - 2*y*z - 2*z^2 + z < 0, \ - x + 3*y + 3*z - 1 < 0] + ....: x^2 + x*y + 3*x*z + 2*y*z + 2*z^2 - x - z < 0, \ + ....: -2*x + 1 < 0, -x*y - x*z - 2*y*z - 2*z^2 + z < 0, \ + ....: x + 3*y + 3*z - 1 < 0] sage: qepcad(conds, memcells=3000000) # optional - qepcad 2 x - 1 > 0 /\ z > 0 /\ z - y < 0 /\ 3 z + 3 y + x - 1 < 0 """ diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index 8c246ba8097..61d66602e9f 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -1427,7 +1427,7 @@ def homfly_polynomial(self, var1='v', var2='z', original=False): sage: H = KnotInfo.L11n459_1_1_1.homfly_polynomial() # optional - database_knotinfo sage: all(L.homfly_polynomial() == L.link().homfly_polynomial(normalization='vz')\ - for L in KnotInfo if L.crossing_number() < 7) + ....: for L in KnotInfo if L.crossing_number() < 7) True REFERENCES: diff --git a/src/sage/libs/ntl/ntl_mat_GF2.pyx b/src/sage/libs/ntl/ntl_mat_GF2.pyx index 479f4505b71..0a00672380a 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2.pyx @@ -506,9 +506,9 @@ cdef class ntl_mat_GF2(): EXAMPLES:: sage: l = [0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, \ - 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, \ - 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, \ - 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0] + ....: 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, \ + ....: 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, \ + ....: 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0] sage: A = ntl.mat_GF2(8,8,l) sage: E = ~A*A sage: E.IsIdent() diff --git a/src/sage/manifolds/differentiable/affine_connection.py b/src/sage/manifolds/differentiable/affine_connection.py index a52c82ee1cc..f2944602f40 100644 --- a/src/sage/manifolds/differentiable/affine_connection.py +++ b/src/sage/manifolds/differentiable/affine_connection.py @@ -372,7 +372,7 @@ def __init__(self, domain, name, latex_name=None): sage: M = Manifold(3, 'M') sage: from sage.manifolds.differentiable.affine_connection import \ - AffineConnection + ....: AffineConnection sage: nab = AffineConnection(M, 'nabla', latex_name=r'\nabla') sage: nab Affine connection nabla on the 3-dimensional differentiable diff --git a/src/sage/matrix/matrix_polynomial_dense.pyx b/src/sage/matrix/matrix_polynomial_dense.pyx index 99979a37ed8..81cfe8163ce 100644 --- a/src/sage/matrix/matrix_polynomial_dense.pyx +++ b/src/sage/matrix/matrix_polynomial_dense.pyx @@ -4116,8 +4116,8 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): completed row-wise into a `3 \times 3` unimodular matrix:: sage: mat = matrix(ring, 2, 3, \ - [[x^2 + 5*x + 5, 3*x^2 + x + 3, 4*x^2 + 5*x + 4], \ - [5*x^2 + 4*x, 3*x^2 + 4*x + 5, 5*x^2 + 5*x + 3]]) + ....: [[x^2 + 5*x + 5, 3*x^2 + x + 3, 4*x^2 + 5*x + 4], \ + ....: [5*x^2 + 4*x, 3*x^2 + 4*x + 5, 5*x^2 + 5*x + 3]]) sage: rcomp = mat._basis_completion_via_reversed_approx(); rcomp [ 2*x^2 + 1 4*x^2 + 3*x 2*x^2 + 3*x] sage: mat.stack(rcomp).determinant() @@ -4128,9 +4128,9 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): completion has two columns; in both cases, the Smith form is preserved:: sage: mat = matrix(ring, 3, 2, \ - [[ x^3 + x^2 + 5*x + 5, 2*x^3 + 2*x + 4], \ - [ 3*x^3 + 2*x^2 + x + 3, 6*x^3 + 5*x^2 + x + 1], \ - [2*x^3 + 5*x^2 + 3*x + 4, 4*x^3 + 6*x^2 + 5*x + 6]]) + ....: [[ x^3 + x^2 + 5*x + 5, 2*x^3 + 2*x + 4], \ + ....: [ 3*x^3 + 2*x^2 + x + 3, 6*x^3 + 5*x^2 + x + 1], \ + ....: [2*x^3 + 5*x^2 + 3*x + 4, 4*x^3 + 6*x^2 + 5*x + 6]]) sage: mat.smith_form(transformation=False) [x + 3 0] [ 0 0] @@ -4327,8 +4327,8 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): there is nothing to complete):: sage: mat = matrix(ring, 2, 3, \ - [[x^2 + 5*x + 5, 3*x^2 + x + 3, 4*x^2 + 5*x + 4], \ - [5*x^2 + 4*x, 3*x^2 + 4*x + 5, 5*x^2 + 5*x + 3]]) + ....: [[x^2 + 5*x + 5, 3*x^2 + x + 3, 4*x^2 + 5*x + 4], \ + ....: [5*x^2 + 4*x, 3*x^2 + 4*x + 5, 5*x^2 + 5*x + 3]]) sage: rcomp = mat.basis_completion(); rcomp [ 2*x^2 + 1 4*x^2 + 3*x 2*x^2 + 3*x] sage: mat.stack(rcomp).determinant() @@ -4341,9 +4341,9 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): completion has two columns; in both cases, the Smith form is preserved:: sage: mat = matrix(ring, 3, 2, \ - [[ x^3 + x^2 + 5*x + 5, 2*x^3 + 2*x + 4], \ - [ 3*x^3 + 2*x^2 + x + 3, 6*x^3 + 5*x^2 + x + 1], \ - [2*x^3 + 5*x^2 + 3*x + 4, 4*x^3 + 6*x^2 + 5*x + 6]]) + ....: [[ x^3 + x^2 + 5*x + 5, 2*x^3 + 2*x + 4], \ + ....: [ 3*x^3 + 2*x^2 + x + 3, 6*x^3 + 5*x^2 + x + 1], \ + ....: [2*x^3 + 5*x^2 + 3*x + 4, 4*x^3 + 6*x^2 + 5*x + 6]]) sage: mat.smith_form(transformation=False) [x + 3 0] [ 0 0] @@ -4378,8 +4378,8 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): 1 sage: mat = matrix([[x*(x-1), x*(x-2)], \ - [x*(x-2), x*(x-3)], \ - [(x-1)*(x-2), (x-1)*(x-3)]]) + ....: [x*(x-2), x*(x-3)], \ + ....: [(x-1)*(x-2), (x-1)*(x-3)]]) sage: mat.smith_form(transformation=False) [1 0] [0 x] @@ -4496,14 +4496,14 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): sage: ring. = GF(7)[] sage: mat1 = matrix([[x*(x-1)*(x-2), (x-2)*(x-3)*(x-4), (x-4)*(x-5)*(x-6)]]) sage: rcomp1 = matrix(ring, 2, 3, \ - [[5*x^2 + 4*x + 1, 5*x^2 + 2*x, 5*x^2], \ - [2*x^3 + 4*x^2, 2*x^3 + 6*x^2 + 2*x + 1, 2*x^3 + x^2 + 3*x]]) + ....: [[5*x^2 + 4*x + 1, 5*x^2 + 2*x, 5*x^2], \ + ....: [2*x^3 + 4*x^2, 2*x^3 + 6*x^2 + 2*x + 1, 2*x^3 + x^2 + 3*x]]) sage: rcomp1._is_basis_completion(mat1) True sage: mat2 = matrix(ring, 2, 3, \ - [[x^2 + 5*x + 5, 3*x^2 + x + 3, 4*x^2 + 5*x + 4], \ - [5*x^2 + 4*x, 3*x^2 + 4*x + 5, 5*x^2 + 5*x + 3]]) + ....: [[x^2 + 5*x + 5, 3*x^2 + x + 3, 4*x^2 + 5*x + 4], \ + ....: [5*x^2 + 4*x, 3*x^2 + 4*x + 5, 5*x^2 + 5*x + 3]]) sage: rcomp2 = matrix(ring, 1, 3, [[2*x^2 + 1, 4*x^2 + 3*x, 2*x^2 + 3*x]]) sage: rcomp2._is_basis_completion(mat2) True @@ -4512,16 +4512,16 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): True sage: mat3 = matrix(ring, 3, 2, \ - [[ x^3 + x^2 + 5*x + 5, 2*x^3 + 2*x + 4], \ - [ 3*x^3 + 2*x^2 + x + 3, 6*x^3 + 5*x^2 + x + 1], \ - [2*x^3 + 5*x^2 + 3*x + 4, 4*x^3 + 6*x^2 + 5*x + 6]]) + ....: [[ x^3 + x^2 + 5*x + 5, 2*x^3 + 2*x + 4], \ + ....: [ 3*x^3 + 2*x^2 + x + 3, 6*x^3 + 5*x^2 + x + 1], \ + ....: [2*x^3 + 5*x^2 + 3*x + 4, 4*x^3 + 6*x^2 + 5*x + 6]]) sage: rcomp3 = matrix(ring, 1, 2, [[x + 1, 2*x]]) sage: rcomp3._is_basis_completion(mat3) True sage: ccomp3 = matrix(ring, 3, 2, \ - [[3*x + 1, 4*x + 4], \ - [ 2*x, 5*x + 1], \ - [ 6*x, x]]) + ....: [[3*x + 1, 4*x + 4], \ + ....: [ 2*x, 5*x + 1], \ + ....: [ 6*x, x]]) sage: ccomp3._is_basis_completion(mat3, row_wise=False) True diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index 5e1f0dcdf82..adc1b573974 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -2322,7 +2322,7 @@ cdef class GLPKBackend(GenericBackend): EXAMPLES:: sage: p = MixedIntegerLinearProgram(maximization=True,\ - solver='GLPK') + ....: solver='GLPK') sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) @@ -2352,7 +2352,7 @@ cdef class GLPKBackend(GenericBackend): EXAMPLES:: sage: p = MixedIntegerLinearProgram(maximization=True,\ - solver='GLPK') + ....: solver='GLPK') sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) @@ -2383,7 +2383,7 @@ cdef class GLPKBackend(GenericBackend): EXAMPLES:: sage: p = MixedIntegerLinearProgram(maximization=True,\ - solver='GLPK') + ....: solver='GLPK') sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) @@ -2414,7 +2414,7 @@ cdef class GLPKBackend(GenericBackend): EXAMPLES:: sage: p = MixedIntegerLinearProgram(maximization=True,\ - solver='GLPK') + ....: solver='GLPK') sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) diff --git a/src/sage/numerical/backends/interactivelp_backend.pyx b/src/sage/numerical/backends/interactivelp_backend.pyx index 3519303a817..231e04a3e2c 100644 --- a/src/sage/numerical/backends/interactivelp_backend.pyx +++ b/src/sage/numerical/backends/interactivelp_backend.pyx @@ -1070,7 +1070,7 @@ cdef class InteractiveLPBackend: EXAMPLES:: sage: p = MixedIntegerLinearProgram(maximization=True,\ - solver='InteractiveLP') + ....: solver='InteractiveLP') sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) @@ -1100,7 +1100,7 @@ cdef class InteractiveLPBackend: EXAMPLES:: sage: p = MixedIntegerLinearProgram(maximization=True,\ - solver='InteractiveLP') + ....: solver='InteractiveLP') sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) @@ -1130,7 +1130,7 @@ cdef class InteractiveLPBackend: EXAMPLES:: sage: p = MixedIntegerLinearProgram(maximization=True,\ - solver='InteractiveLP') + ....: solver='InteractiveLP') sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) @@ -1160,7 +1160,7 @@ cdef class InteractiveLPBackend: EXAMPLES:: sage: p = MixedIntegerLinearProgram(maximization=True,\ - solver='InteractiveLP') + ....: solver='InteractiveLP') sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) @@ -1185,7 +1185,7 @@ cdef class InteractiveLPBackend: EXAMPLES:: sage: p = MixedIntegerLinearProgram(maximization=True,\ - solver='InteractiveLP') + ....: solver='InteractiveLP') sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) @@ -1218,7 +1218,7 @@ cdef class InteractiveLPBackend: EXAMPLES:: sage: p = MixedIntegerLinearProgram(maximization=True,\ - solver='InteractiveLP') + ....: solver='InteractiveLP') sage: x = p.new_variable(nonnegative=True) sage: p.add_constraint(-x[0] + x[1] <= 2) sage: p.add_constraint(8 * x[0] + 2 * x[1] <= 17) diff --git a/src/sage/rings/multi_power_series_ring.py b/src/sage/rings/multi_power_series_ring.py index 3a30b89b9e9..b7b45b0410e 100644 --- a/src/sage/rings/multi_power_series_ring.py +++ b/src/sage/rings/multi_power_series_ring.py @@ -59,11 +59,11 @@ sage: z = H.base_ring().gens() sage: f = H.gens() sage: h = 4*z[1]^2 + 2*z[0]*z[2] + z[1]*z[2] + z[2]^2 \ - + (-z[2]^2 - 2*z[0] + z[2])*f[0]*f[2] \ - + (-22*z[0]^2 + 2*z[1]^2 - z[0]*z[2] + z[2]^2 - 1955*z[2])*f[1]*f[2] \ - + (-z[0]*z[1] - 2*z[1]^2)*f[2]*f[3] \ - + (2*z[0]*z[1] + z[1]*z[2] - z[2]^2 - z[1] + 3*z[2])*f[3]^2 \ - + H.O(3) + ....: + (-z[2]^2 - 2*z[0] + z[2])*f[0]*f[2] \ + ....: + (-22*z[0]^2 + 2*z[1]^2 - z[0]*z[2] + z[2]^2 - 1955*z[2])*f[1]*f[2] \ + ....: + (-z[0]*z[1] - 2*z[1]^2)*f[2]*f[3] \ + ....: + (2*z[0]*z[1] + z[1]*z[2] - z[2]^2 - z[1] + 3*z[2])*f[3]^2 \ + ....: + H.O(3) sage: h in H True sage: h diff --git a/src/sage/rings/multi_power_series_ring_element.py b/src/sage/rings/multi_power_series_ring_element.py index 046f8338e05..fc08422371a 100644 --- a/src/sage/rings/multi_power_series_ring_element.py +++ b/src/sage/rings/multi_power_series_ring_element.py @@ -1150,7 +1150,7 @@ def polynomial(self): Field sage: t = M.gens() sage: f = 1/2*t[0]^3*t[1]^3*t[2]^2 + 2/3*t[0]*t[2]^6*t[3] \ - - t[0]^3*t[1]^3*t[3]^3 - 1/4*t[0]*t[1]*t[2]^7 + M.O(10) + ....: - t[0]^3*t[1]^3*t[3]^3 - 1/4*t[0]*t[1]*t[2]^7 + M.O(10) sage: f 1/2*t0^3*t1^3*t2^2 + 2/3*t0*t2^6*t3 - t0^3*t1^3*t3^3 - 1/4*t0*t1*t2^7 + O(t0, t1, t2, t3)^10 @@ -1299,7 +1299,7 @@ def V(self, n): sage: H = QQ[['x,y,z']] sage: (x,y,z) = H.gens() sage: h = -x*y^4*z^7 - 1/4*y*z^12 + 1/2*x^7*y^5*z^2 \ - + 2/3*y^6*z^8 + H.O(15) + ....: + 2/3*y^6*z^8 + H.O(15) sage: h.V(3) -x^3*y^12*z^21 - 1/4*y^3*z^36 + 1/2*x^21*y^15*z^6 + 2/3*y^18*z^24 + O(x, y, z)^45 """ @@ -1382,7 +1382,7 @@ def truncate(self, prec=infinity): Multivariate Power Series Ring in t0, t1, t2, t3 over Rational Field sage: t = M.gens() sage: f = 1/2*t[0]^3*t[1]^3*t[2]^2 + 2/3*t[0]*t[2]^6*t[3] \ - - t[0]^3*t[1]^3*t[3]^3 - 1/4*t[0]*t[1]*t[2]^7 + M.O(10) + ....: - t[0]^3*t[1]^3*t[3]^3 - 1/4*t[0]*t[1]*t[2]^7 + M.O(10) sage: f 1/2*t0^3*t1^3*t2^2 + 2/3*t0*t2^6*t3 - t0^3*t1^3*t3^3 - 1/4*t0*t1*t2^7 + O(t0, t1, t2, t3)^10 diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 0e25b72dbb9..c37225d09bc 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -2422,7 +2422,7 @@ cdef class MPolynomial(CommutativePolynomial): sage: R. = PolynomialRing(QQ) sage: f = 19*x^8 - 262*x^7*h + 1507*x^6*h^2 - 4784*x^5*h^3 + 9202*x^4*h^4\ - -10962*x^3*h^5 + 7844*x^2*h^6 - 3040*x*h^7 + 475*h^8 + ....: -10962*x^3*h^5 + 7844*x^2*h^6 - 3040*x*h^7 + 475*h^8 sage: f.reduced_form(prec=200, smallest_coeffs=False) # needs sage.modules sage.rings.complex_interval_field ( -x^8 - 2*x^7*h + 7*x^6*h^2 + 16*x^5*h^3 + 2*x^4*h^4 - 2*x^3*h^5 + 4*x^2*h^6 - 5*h^8, diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 8db6eb03ea6..c4bee3728f3 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2737,15 +2737,15 @@ def _variety_triangular_decomposition(self, ring): sage: R.inject_variables() Defining... sage: I = Ideal([x1 + 1, x2, x3 + 1, x5*x10 + x10 + x18, x5*x11 + x11, \ - x5*x18, x6, x7 + 1, x9, x10*x11 + x10 + x18, x10*x18 + x18, \ - x11*x18, x12, x13, x14, x15, x16 + 1, x17 + x18 + 1, x19, x20, \ - x21 + 1, x22, x23, x24, x25 + 1, x28 + 1, x29 + 1, x30, x8, \ - x26, x1^2 + x1, x2^2 + x2, x3^2 + x3, x4^2 + x4, x5^2 + x5, \ - x6^2 + x6, x7^2 + x7, x8^2 + x8, x9^2 + x9, x10^2 + x10, \ - x11^2 + x11, x12^2 + x12, x13^2 + x13, x14^2 + x14, x15^2 + x15, \ - x16^2 + x16, x17^2 + x17, x18^2 + x18, x19^2 + x19, x20^2 + x20, \ - x21^2 + x21, x22^2 + x22, x23^2 + x23, x24^2 + x24, x25^2 + x25, \ - x26^2 + x26, x27^2 + x27, x28^2 + x28, x29^2 + x29, x30^2 + x30]) + ....: x5*x18, x6, x7 + 1, x9, x10*x11 + x10 + x18, x10*x18 + x18, \ + ....: x11*x18, x12, x13, x14, x15, x16 + 1, x17 + x18 + 1, x19, x20, \ + ....: x21 + 1, x22, x23, x24, x25 + 1, x28 + 1, x29 + 1, x30, x8, \ + ....: x26, x1^2 + x1, x2^2 + x2, x3^2 + x3, x4^2 + x4, x5^2 + x5, \ + ....: x6^2 + x6, x7^2 + x7, x8^2 + x8, x9^2 + x9, x10^2 + x10, \ + ....: x11^2 + x11, x12^2 + x12, x13^2 + x13, x14^2 + x14, x15^2 + x15, \ + ....: x16^2 + x16, x17^2 + x17, x18^2 + x18, x19^2 + x19, x20^2 + x20, \ + ....: x21^2 + x21, x22^2 + x22, x23^2 + x23, x24^2 + x24, x25^2 + x25, \ + ....: x26^2 + x26, x27^2 + x27, x28^2 + x28, x29^2 + x29, x30^2 + x30]) sage: I.basis_is_groebner() True sage: sorted("".join(str(V[g]) for g in R.gens()) for V in I.variety()) # long time (6s on sage.math, 2011) diff --git a/src/sage/rings/polynomial/pbori/gbcore.py b/src/sage/rings/polynomial/pbori/gbcore.py index 8371577157d..cdf5a0bd324 100644 --- a/src/sage/rings/polynomial/pbori/gbcore.py +++ b/src/sage/rings/polynomial/pbori/gbcore.py @@ -319,7 +319,7 @@ def variety_size_from_gb(I): sage: variety_size_from_gb([x(1)*x(2), x(2)*x(3)]) 5.0 sage: mons = [Monomial([r.variable(i) for i in range(100) if i!=j])\ - for j in range(100)] + ....: for j in range(100)] sage: variety_size_from_gb(mons) 1.2676506002282294e+30 """ diff --git a/src/sage/schemes/jacobians/abstract_jacobian.py b/src/sage/schemes/jacobians/abstract_jacobian.py index 6ec2880a627..f1e060f77b1 100755 --- a/src/sage/schemes/jacobians/abstract_jacobian.py +++ b/src/sage/schemes/jacobians/abstract_jacobian.py @@ -101,14 +101,14 @@ def __init__(self, C, category=None): Note: this is an abstract parent, so we skip element tests:: sage: TestSuite(J).run(skip =["_test_an_element", \ - "_test_zero", \ - "_test_elements", \ - "_test_elements_eq_reflexive", \ - "_test_elements_eq_symmetric", \ - "_test_elements_eq_transitive", \ - "_test_additive_associativity", \ - "_test_elements_neq", \ - "_test_some_elements"]) + ....: "_test_zero", \ + ....: "_test_elements", \ + ....: "_test_elements_eq_reflexive", \ + ....: "_test_elements_eq_symmetric", \ + ....: "_test_elements_eq_transitive", \ + ....: "_test_additive_associativity", \ + ....: "_test_elements_neq", \ + ....: "_test_some_elements"]) :: diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index 1f29206dfd1..0173fdee72c 100755 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -16,7 +16,7 @@ sage: PP. = ProductProjectiveSpaces([1,0], QQ) sage: from sage.schemes.product_projective.rational_point import \ - enum_product_projective_rational_field + ....: enum_product_projective_rational_field sage: enum_product_projective_rational_field(PP, 3) [(-3 : 1 , 1), (-2 : 1 , 1), (-3/2 : 1 , 1), (-1 : 1 , 1), (-2/3 : 1 , 1), (-1/2 : 1 , 1), @@ -30,7 +30,7 @@ sage: P1. = ProductProjectiveSpaces([1, 1], GF(7)) sage: X = P1.subscheme([2*x + 3*y]) sage: from sage.schemes.product_projective.rational_point import \ - enum_product_projective_finite_field + ....: enum_product_projective_finite_field sage: enum_product_projective_finite_field(X) [(2 : 1 , 0 : 1), (2 : 1 , 1 : 0), (2 : 1 , 1 : 1), (2 : 1 , 2 : 1), (2 : 1 , 3 : 1), (2 : 1 , 4 : 1), @@ -89,7 +89,7 @@ def enum_product_projective_rational_field(X, B): sage: PP. = ProductProjectiveSpaces([1, 2], QQ) sage: from sage.schemes.product_projective.rational_point import \ - enum_product_projective_rational_field + ....: enum_product_projective_rational_field sage: enum_product_projective_rational_field(PP, 1) [(-1 : 1 , -1 : -1 : 1), (-1 : 1 , -1 : 0 : 1), (-1 : 1 , -1 : 1 : 0), (-1 : 1 , -1 : 1 : 1), (-1 : 1 , 0 : -1 : 1), (-1 : 1 , 0 : 0 : 1), @@ -115,7 +115,7 @@ def enum_product_projective_rational_field(X, B): sage: PP. = ProductProjectiveSpaces([2, 1], QQ) sage: X = PP.subscheme([x^2 + x*y + y*z, u*u - v*u]) sage: from sage.schemes.product_projective.rational_point import \ - enum_product_projective_rational_field + ....: enum_product_projective_rational_field sage: enum_product_projective_rational_field(X, 4) [(-2 : 4 : 1 , 0 : 1), (-2 : 4 : 1 , 1 : 1), (-1 : 1 : 0 , 0 : 1), (-1 : 1 : 0 , 1 : 1), (-2/3 : -4/3 : 1 , 0 : 1), (-2/3 : -4/3 : 1 , 1 : 1), @@ -215,7 +215,7 @@ def enum_product_projective_number_field(X, **kwds): sage: PP. = ProductProjectiveSpaces([1, 1], K) sage: X = PP.subscheme([x^2 + 2*y^2]) sage: from sage.schemes.product_projective.rational_point import \ - enum_product_projective_number_field + ....: enum_product_projective_number_field sage: enum_product_projective_number_field(X, bound=1.5) [(-v : 1 , -1 : 1), (-v : 1 , -v : 1), (-v : 1 , -1/2*v : 1), (-v : 1 , 0 : 1), (-v : 1 , 1/2*v : 1), (-v : 1 , v : 1), @@ -267,7 +267,7 @@ def enum_product_projective_finite_field(X): sage: PP. = ProductProjectiveSpaces([1, 1], GF(3)) sage: from sage.schemes.product_projective.rational_point import \ - enum_product_projective_finite_field + ....: enum_product_projective_finite_field sage: enum_product_projective_finite_field(PP) [(0 : 1 , 0 : 1), (0 : 1 , 1 : 0), (0 : 1 , 1 : 1), (0 : 1 , 2 : 1), (1 : 0 , 0 : 1), (1 : 0 , 1 : 0), @@ -281,7 +281,7 @@ def enum_product_projective_finite_field(X): sage: PP. = ProductProjectiveSpaces([1, 1], GF(17)) sage: X = PP.subscheme([x0^2 + 2*x1^2]) sage: from sage.schemes.product_projective.rational_point import \ - enum_product_projective_finite_field + ....: enum_product_projective_finite_field sage: len(enum_product_projective_finite_field(X)) 36 """ diff --git a/src/sage/schemes/product_projective/subscheme.py b/src/sage/schemes/product_projective/subscheme.py index 511f10a973e..3ee7f770551 100755 --- a/src/sage/schemes/product_projective/subscheme.py +++ b/src/sage/schemes/product_projective/subscheme.py @@ -55,7 +55,7 @@ class AlgebraicScheme_subscheme_product_projective(AlgebraicScheme_subscheme_pro TESTS:: sage: from sage.schemes.product_projective.subscheme \ - import AlgebraicScheme_subscheme_product_projective + ....: import AlgebraicScheme_subscheme_product_projective sage: AlgebraicScheme_subscheme_product_projective(P, [u*x^2 - v*y*x]) Closed subscheme of Product of projective spaces P^1 x P^1 over Rational Field defined by: diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 89d4f28f48b..ebc0df4b929 100755 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -982,9 +982,9 @@ def subscheme(self, X): TESTS:: sage: TestSuite(X).run(skip=["_test_an_element", "_test_elements",\ - "_test_elements_eq", "_test_some_elements", "_test_elements_eq_reflexive",\ - "_test_elements_eq_symmetric", "_test_elements_eq_transitive",\ - "_test_elements_neq"]) + ....: "_test_elements_eq", "_test_some_elements", "_test_elements_eq_reflexive",\ + ....: "_test_elements_eq_symmetric", "_test_elements_eq_transitive",\ + ....: "_test_elements_neq"]) """ R = self.base_ring() if R.is_field() and R.is_exact(): diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index da4d5db908f..054576e6da6 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -191,10 +191,10 @@ Check that :issue:`9880` is fixed:: sage: b = [var('b_%s'%i) for i in range(4)] sage: precomp = (2^b_2 + 2)*(2^b_1 + 2^(-b_1) + 2^b_1*2^b_0 - \ - 2^b_1*2^(-b_0) - 2^(-b_1)*2^b_0 - 2^(-b_1)*2^(-b_0) + \ - 2^b_0 + 2^(-b_0) - 9) + (2^b_1 + 2^(-b_1) + \ - 2^b_1*2^b_0 - 2^b_1*2^(-b_0) - 2^(-b_1)*2^b_0 - \ - 2^(-b_1)*2^(-b_0) + 2^b_0 + 2^(-b_0) - 9)/2^b_2 + ....: 2^b_1*2^(-b_0) - 2^(-b_1)*2^b_0 - 2^(-b_1)*2^(-b_0) + \ + ....: 2^b_0 + 2^(-b_0) - 9) + (2^b_1 + 2^(-b_1) + \ + ....: 2^b_1*2^b_0 - 2^b_1*2^(-b_0) - 2^(-b_1)*2^b_0 - \ + ....: 2^(-b_1)*2^(-b_0) + 2^b_0 + 2^(-b_0) - 9)/2^b_2 sage: repl_dict = {b_0: b_0, b_3: b_1, b_2: b_3, b_1: b_2} sage: P = precomp.substitute(repl_dict) sage: P.expand() @@ -209,35 +209,35 @@ Check that :issue:`9880` is fixed:: sage: _0,b_1,b_2=var('b_0,b_1,b_2') sage: f = 1/27*b_2^2/(2^b_2)^2 + 1/27*b_1^2/(2^b_1)^2 + \ - 1/27*b_0^2/(2^b_0)^2 + 1/27*b_2/(2^b_2)^2 - 2/81/(2^b_2)^2 + \ - 1/27*b_1/(2^b_1)^2 + 8/243/(2^b_2)^2 - 1/81*b_0/(2^b_0)^2 - \ - 1/27*b_1^2/((2^b_2)^2*(2^b_1)^2) - \ - 1/27*b_0^2/((2^b_2)^2*(2^b_0)^2) - 20/243/(2^b_1)^2 + 1/9/2^b_0 \ - + 4/81*b_0/(2^b_0)^2 - 8/243/(2^b_2)^2 - 2/9/(2^b_2*2^b_1) - \ - 2/9/(2^b_2*2^b_0) + 8/243/(2^b_1)^2 - 1/9/2^b_0 + \ - 2/9/(2^b_2*2^b_1) + 2/9/(2^b_2*2^b_0) - \ - 2/27*b_1*b_2/((2^b_2)^2*(2^b_1)^2) - \ - 1/27*b_2^2/((2^b_2)^2*(2^b_1)^2) - \ - 2/27*b_0*b_2/((2^b_2)^2*(2^b_0)^2) - \ - 1/27*b_2^2/((2^b_2)^2*(2^b_0)^2) + 2/81/(2^b_1)^2 - \ - 1/27*b_0^2/((2^b_1)^2*(2^b_0)^2) - \ - 2/27*b_0*b_1/((2^b_1)^2*(2^b_0)^2) - \ - 1/27*b_1^2/((2^b_1)^2*(2^b_0)^2) - 2/81/(2^b_0)^2 + \ - 5/27*b_1/((2^b_2)^2*(2^b_1)^2) + 5/27*b_2/((2^b_2)^2*(2^b_1)^2) \ - + 5/27*b_0/((2^b_2)^2*(2^b_0)^2) + \ - 5/27*b_2/((2^b_2)^2*(2^b_0)^2) + 5/27*b_0/((2^b_1)^2*(2^b_0)^2) \ - + 5/27*b_1/((2^b_1)^2*(2^b_0)^2) - 4/81/((2^b_2)^2*(2^b_1)^2) + \ - 1/27*b_0^2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ - 2/27*b_0*b_1/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ - 2/27*b_0*b_2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ - 1/27*b_1^2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ - 2/27*b_1*b_2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ - 1/27*b_2^2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) - \ - 4/81/((2^b_2)^2*(2^b_0)^2) - 4/81/((2^b_1)^2*(2^b_0)^2) - \ - 11/27*b_0/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) - \ - 11/27*b_1/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) - \ - 11/27*b_2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ - 64/81/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + 35/81 + ....: 1/27*b_0^2/(2^b_0)^2 + 1/27*b_2/(2^b_2)^2 - 2/81/(2^b_2)^2 + \ + ....: 1/27*b_1/(2^b_1)^2 + 8/243/(2^b_2)^2 - 1/81*b_0/(2^b_0)^2 - \ + ....: 1/27*b_1^2/((2^b_2)^2*(2^b_1)^2) - \ + ....: 1/27*b_0^2/((2^b_2)^2*(2^b_0)^2) - 20/243/(2^b_1)^2 + 1/9/2^b_0 \ + ....: + 4/81*b_0/(2^b_0)^2 - 8/243/(2^b_2)^2 - 2/9/(2^b_2*2^b_1) - \ + ....: 2/9/(2^b_2*2^b_0) + 8/243/(2^b_1)^2 - 1/9/2^b_0 + \ + ....: 2/9/(2^b_2*2^b_1) + 2/9/(2^b_2*2^b_0) - \ + ....: 2/27*b_1*b_2/((2^b_2)^2*(2^b_1)^2) - \ + ....: 1/27*b_2^2/((2^b_2)^2*(2^b_1)^2) - \ + ....: 2/27*b_0*b_2/((2^b_2)^2*(2^b_0)^2) - \ + ....: 1/27*b_2^2/((2^b_2)^2*(2^b_0)^2) + 2/81/(2^b_1)^2 - \ + ....: 1/27*b_0^2/((2^b_1)^2*(2^b_0)^2) - \ + ....: 2/27*b_0*b_1/((2^b_1)^2*(2^b_0)^2) - \ + ....: 1/27*b_1^2/((2^b_1)^2*(2^b_0)^2) - 2/81/(2^b_0)^2 + \ + ....: 5/27*b_1/((2^b_2)^2*(2^b_1)^2) + 5/27*b_2/((2^b_2)^2*(2^b_1)^2) \ + ....: + 5/27*b_0/((2^b_2)^2*(2^b_0)^2) + \ + ....: 5/27*b_2/((2^b_2)^2*(2^b_0)^2) + 5/27*b_0/((2^b_1)^2*(2^b_0)^2) \ + ....: + 5/27*b_1/((2^b_1)^2*(2^b_0)^2) - 4/81/((2^b_2)^2*(2^b_1)^2) + \ + ....: 1/27*b_0^2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ + ....: 2/27*b_0*b_1/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ + ....: 2/27*b_0*b_2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ + ....: 1/27*b_1^2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ + ....: 2/27*b_1*b_2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ + ....: 1/27*b_2^2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) - \ + ....: 4/81/((2^b_2)^2*(2^b_0)^2) - 4/81/((2^b_1)^2*(2^b_0)^2) - \ + ....: 11/27*b_0/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) - \ + ....: 11/27*b_1/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) - \ + ....: 11/27*b_2/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + \ + ....: 64/81/((2^b_2)^2*(2^b_1)^2*(2^b_0)^2) + 35/81 sage: f.nops() 38 @@ -7828,18 +7828,18 @@ cdef class Expression(Expression_abc): sage: y = var('y') sage: z = var('z') sage: e = 792*z^8*w^4*x^3*y^4*u^7 + 24*z^4*w^4*x^2*y^3*u^4 + \ - 264*z^8*w^3*x^2*y^7*u^5 + 198*z^4*w^5*x^5*y*u^6 + 110*z^2*w^3*x^5*y^4*u^6 \ - - 120*z^8*w*x^4*u^6 - 480*z^5*w*x^4*y^6*u^8 - 720*z^7*x^3*y^3*u^7 + \ - 165*z^4*w^2*x^4*y*u^5 + 450*z^8*w^6*x^2*y*u^8 + 40*z^2*w^3*x^3*y^3*u^6 - \ - 288*z^7*w^2*x^3*y^6*u^6 + 250*z^6*w^4*x^2*y^4*u^8 + \ - 576*z^7*w^7*x^2*y^4*u^8 - 80*z^6*w^2*x^5*y^3*u^7 - 144*z^8*w^4*x^5*u^7 + \ - 120*z^4*w*x^2*y^6*u^6 + 320*z^5*w^5*x^2*y^7*u^8 + 192*z^7*w^6*x*y^7*u^6 - \ - 12*z^4*w^3*x^3*y^5*u^6 - 36*z^4*w^4*x^4*y^2*u^8 + 72*z^4*w^5*x^3*u^6 - \ - 20*z^2*w^2*x^4*y^5*u^8 + 660*z^8*w*x^2*y^4*u^6 + 66*z^4*w^4*x^4*y^4*u^4 + \ - 440*z^6*w^2*x^3*y^7*u^7 - 30*z^4*w*x^3*y^2*u^7 - 48*z^8*w^3*x^4*y^3*u^5 + \ - 72*z^6*w^2*x*y^6*u^4 - 864*z^7*w^3*x^4*y^3*u^8 + 480*z^7*w^4*x*y^4*u^7 + \ - 60*z^4*w^2*x^2*u^5 + 375*z^8*w^3*x*y*u^7 + 150*z^8*w^5*x*y^4*u^6 + \ - 180*z^6*x*y^3*u^5 + 216*z^6*w^3*x^2*y^3*u^6; + ....: 264*z^8*w^3*x^2*y^7*u^5 + 198*z^4*w^5*x^5*y*u^6 + 110*z^2*w^3*x^5*y^4*u^6 \ + ....: - 120*z^8*w*x^4*u^6 - 480*z^5*w*x^4*y^6*u^8 - 720*z^7*x^3*y^3*u^7 + \ + ....: 165*z^4*w^2*x^4*y*u^5 + 450*z^8*w^6*x^2*y*u^8 + 40*z^2*w^3*x^3*y^3*u^6 - \ + ....: 288*z^7*w^2*x^3*y^6*u^6 + 250*z^6*w^4*x^2*y^4*u^8 + \ + ....: 576*z^7*w^7*x^2*y^4*u^8 - 80*z^6*w^2*x^5*y^3*u^7 - 144*z^8*w^4*x^5*u^7 + \ + ....: 120*z^4*w*x^2*y^6*u^6 + 320*z^5*w^5*x^2*y^7*u^8 + 192*z^7*w^6*x*y^7*u^6 - \ + ....: 12*z^4*w^3*x^3*y^5*u^6 - 36*z^4*w^4*x^4*y^2*u^8 + 72*z^4*w^5*x^3*u^6 - \ + ....: 20*z^2*w^2*x^4*y^5*u^8 + 660*z^8*w*x^2*y^4*u^6 + 66*z^4*w^4*x^4*y^4*u^4 + \ + ....: 440*z^6*w^2*x^3*y^7*u^7 - 30*z^4*w*x^3*y^2*u^7 - 48*z^8*w^3*x^4*y^3*u^5 + \ + ....: 72*z^6*w^2*x*y^6*u^4 - 864*z^7*w^3*x^4*y^3*u^8 + 480*z^7*w^4*x*y^4*u^7 + \ + ....: 60*z^4*w^2*x^2*u^5 + 375*z^8*w^3*x*y*u^7 + 150*z^8*w^5*x*y^4*u^6 + \ + ....: 180*z^6*x*y^3*u^5 + 216*z^6*w^3*x^2*y^3*u^6; sage: d = e.diff(x) sage: gcd(d,e) / (u^4*z^2) in QQ True diff --git a/src/sage/tensor/modules/tensor_with_indices.py b/src/sage/tensor/modules/tensor_with_indices.py index be7c88a859c..bd3edbb81d0 100644 --- a/src/sage/tensor/modules/tensor_with_indices.py +++ b/src/sage/tensor/modules/tensor_with_indices.py @@ -692,7 +692,7 @@ def __add__(self, other): sage: b[:] = [[-1,2,-3], [-4,5,6], [7,-8,9]] sage: T = a*a*b*b sage: 1/4*(T["ijkl_abcd"] + T["jikl_abcd"] + T["ijkl_abdc"]\ - + T["jikl_abdc"]) == T["(..).._..(..)"]["ijkl_abcd"] + ....: + T["jikl_abdc"]) == T["(..).._..(..)"]["ijkl_abcd"] True """ # Check tensor types are compatible @@ -770,7 +770,7 @@ def __sub__(self, other): sage: b[:] = [[-1,2,-3], [-4,5,6], [7,-8,9]] sage: T = a*a*b*b sage: 1/4*(T["ijkl_abcd"]-T["jikl_abcd"] - T["ijkl_abdc"]\ - + T["jikl_abdc"] ) == T["[..].._..[..]"]["ijkl_abcd"] + ....: + T["jikl_abdc"] ) == T["[..].._..[..]"]["ijkl_abcd"] True """ return self + (-other) 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 e283c56c74b..524783b5bf3 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 @@ -222,7 +222,7 @@ sage: c = sumcomp(y0,delta0,RDF(0.0),n,a) sage: print("exact - compensated summation: %.5f" \ - % RDF(s-RR(c).exact_rational())) + ....: % RDF(s-RR(c).exact_rational())) exact - compensated summation: -0.00042 Sage example in ./float.tex, line 1242:: 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 5bcd8aa9de6..f8b5ca511b2 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 @@ -181,7 +181,7 @@ Sage example in ./integration.tex, line 990:: sage: f = lambda y: numerical_integral(lambda x: exp(y*sin(x)), \ - 0, sqrt(y))[0] + ....: 0, sqrt(y))[0] sage: f(0.0), f(0.5), f(1.0) # abs tol 2e-15 (0.0, 0.8414895067661431, 1.6318696084180513) @@ -193,14 +193,14 @@ Sage example in ./integration.tex, line 1008:: sage: f = lambda y: sage.calculus.calculus.nintegral(exp(y*sin(x)), \ - x, 0, sqrt(y))[0] + ....: x, 0, sqrt(y))[0] sage: numerical_integral(f, 0, 1) # abs tol 2e-16 (0.8606791942204567, 6.301207560882096e-07) Sage example in ./integration.tex, line 1016:: sage: f = lambda y: RDF(mpmath.quad(lambda x: mpmath.exp(y*mpmath.sin(x)), \ - [0, sqrt(y)])) + ....: [0, sqrt(y)])) sage: numerical_integral(f, 0, 1) # abs tol 2e-16 (0.8606791942204567, 6.301207561187562e-07) diff --git a/src/sage/topology/simplicial_complex.py b/src/sage/topology/simplicial_complex.py index 54166cf4f1f..8b9eca04424 100644 --- a/src/sage/topology/simplicial_complex.py +++ b/src/sage/topology/simplicial_complex.py @@ -3465,7 +3465,7 @@ def minimal_nonfaces(self): TESTS:: sage: SC = SimplicialComplex([(0,1,2),(0,2,3),(2,3,4),(1,2,4), \ - (1,4,5),(0,3,6),(3,6,7),(4,5,7)]) + ....: (1,4,5),(0,3,6),(3,6,7),(4,5,7)]) This was taking a long time before :issue:`20078`:: From 8e7f1315ea3d7769cfb778d02ea6d50bf089af9c Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sun, 22 Dec 2024 20:02:19 +0700 Subject: [PATCH 044/187] Integer linebreak --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 8 ++++---- src/sage/tests/book_stein_ent.py | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index f395214b516..1cd0187a946 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2259,10 +2259,10 @@ def canonical_height(self, P, **kwds): :: - sage: RSA768 = 123018668453011775513049495838496272077285356959533479219732245215\ - ....: 1726400507263657518745202199786469389956474942774063845925192557326303453731548\ - ....: 2685079170261221429134616704292143116022212404792747377940806653514195974598569\ - ....: 02143413 + sage: RSA768 = Integer('123018668453011775513049495838496272077285356959533479219732245215' + ....: '1726400507263657518745202199786469389956474942774063845925192557326303453731548' + ....: '2685079170261221429134616704292143116022212404792747377940806653514195974598569' + ....: '02143413') sage: P. = ProjectiveSpace(QQ,1) sage: f = DynamicalSystem_projective([RSA768*x^2 + y^2, x*y]) sage: Q = P(RSA768,1) diff --git a/src/sage/tests/book_stein_ent.py b/src/sage/tests/book_stein_ent.py index 970b377e962..2e942934b9f 100644 --- a/src/sage/tests/book_stein_ent.py +++ b/src/sage/tests/book_stein_ent.py @@ -20,11 +20,11 @@ 3^2 * 223 sage: factor(31415926535898) 2 * 3 * 53 * 73 * 2531 * 534697 -sage: n = 7403756347956171282804679609742957314259318888\ -....: 9231289084936232638972765034028266276891996419625117\ -....: 8439958943305021275853701189680982867331732731089309\ -....: 0055250511687706329907239638078671008609696253793465\ -....: 0563796359 +sage: n = Integer('7403756347956171282804679609742957314259318888' +....: '9231289084936232638972765034028266276891996419625117' +....: '8439958943305021275853701189680982867331732731089309' +....: '0055250511687706329907239638078671008609696253793465' +....: '0563796359') sage: len(n.str(2)) 704 sage: len(n.str(10)) From ee716c670025740c83c2354b1ce9f30bca6b7394 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sun, 22 Dec 2024 20:05:42 +0700 Subject: [PATCH 045/187] More integer linebreak --- src/sage/symbolic/expression.pyx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 054576e6da6..ee31dae4e74 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -3596,10 +3596,9 @@ cdef class Expression(Expression_abc): sage: k = 26 sage: bool(2/(2*pi)^(2*k) <= abs(bernoulli(2*k)/factorial(2*k))) True - sage: t = log(17179815199/17179869184) + 727717503781781876485802\ - ....: 752874818120860129694543334299450155913077668355/2315841784\ - ....: 74632390847141970017375815706539969331281128078915168015826\ - ....: 259279872 + sage: t = (log(17179815199/17179869184) + + ....: 727717503781781876485802752874818120860129694543334299450155913077668355 / + ....: 231584178474632390847141970017375815706539969331281128078915168015826259279872) sage: v = -53985/17179869184 sage: bool(abs(t) < 1.213*2^-56*v^4) True From fcd783a95a36cd3f535e5f0658b3fead0d7ca951 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sun, 22 Dec 2024 20:06:34 +0700 Subject: [PATCH 046/187] Modify test accordingly --- src/sage/doctest/parsing.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 6b268719abb..05662691d16 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -973,15 +973,15 @@ def parse(self, string, *args): sage: parse("::\n\n sage: # needs sage.combinat\n sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \\\n ....: import incidence_matrix_to_bit_rep_of_Vrep\n sage: P = polytopes.associahedron(['A',3])\n\n") ['::\n\n', - '', - (None, - 'from sage.geometry.polyhedron.combinatorial_polyhedron.conversions import incidence_matrix_to_bit_rep_of_Vrep\n', - 'from sage.geometry.polyhedron.combinatorial_polyhedron.conversions import incidence_matrix_to_bit_rep_of_Vrep\n'), - '', - (None, - "P = polytopes.associahedron(['A',3])\n", - "P = polytopes.associahedron(['A',Integer(3)])\n"), - '\n'] + '', + (None, + 'from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \\\n import incidence_matrix_to_bit_rep_of_Vrep\n', + 'from sage.geometry.polyhedron.combinatorial_polyhedron.conversions import incidence_matrix_to_bit_rep_of_Vrep\n'), + '', + (None, + "P = polytopes.associahedron(['A',3])\n", + "P = polytopes.associahedron(['A',Integer(3)])\n"), + '\n'] sage: example4 = '::\n\n sage: C.minimum_distance(algorithm="guava") # optional - guava\n ...\n 24\n\n' sage: parsed4 = DTP.parse(example4) From 46d085e8b4684b8e5c323b21e850f333bf4361ed Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sun, 22 Dec 2024 21:37:18 +0700 Subject: [PATCH 047/187] Move optional tags to correct place --- src/sage/features/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 62de2b8e0c5..8d3f67efae7 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -820,9 +820,9 @@ def absolute_filename(self) -> str: A :exc:`FeatureNotPresentError` is raised if the file cannot be found:: sage: from sage.features import StaticFile - sage: StaticFile(name='no_such_file', filename='KaT1aihu',\ - ....: search_path=(), spkg='some_spkg',\ - ....: url='http://rand.om').absolute_filename() # optional - sage_spkg + sage: StaticFile(name='no_such_file', filename='KaT1aihu', # optional - sage_spkg + ....: search_path=(), spkg='some_spkg', + ....: url='http://rand.om').absolute_filename() Traceback (most recent call last): ... FeatureNotPresentError: no_such_file is not available. From e431b2f9ec9fe55dcda4cea6c8bd300cdf4c69ef Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Mon, 23 Dec 2024 12:59:21 +0700 Subject: [PATCH 048/187] Add remark in developer coding convention --- src/doc/en/developer/coding_basics.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index 9b56de46ad0..b80ac4b958f 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -966,6 +966,14 @@ written. checked, as they are the most likely to be broken, now or in the future. This probably belongs to the TESTS block (see :ref:`section-docstring-function`). +- **Interruption:** if the function might take a very long time, use + :func:`~sage.doctest.util.ensure_interruptible_after` to check that the user + can interrupt it. For example, the following tests ``sleep(3)`` can be + interrupted after 1 second:: + + sage: from sage.doctest.util import ensure_interruptible_after + sage: with ensure_interruptible_after(1) as data: sleep(3) + - **Systematic tests** of all small-sized inputs, or tests of **random** instances if possible. From 97db4bf7508b443e7be80fdc8941a08632d58efd Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Mon, 23 Dec 2024 16:11:37 +0700 Subject: [PATCH 049/187] Several fixes and documentation improvements for categories --- src/sage/categories/category.py | 115 +++++++++++++++++++- src/sage/categories/filtered_modules.py | 51 ++++++++- src/sage/categories/homset.py | 2 +- src/sage/categories/homsets.py | 15 ++- src/sage/groups/perm_gps/permgroup_named.py | 2 +- 5 files changed, 175 insertions(+), 10 deletions(-) diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index feb1b2cb393..1a2e2733cf4 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -943,6 +943,22 @@ def all_super_categories(self, proper=False): appropriate. Simply because lazy attributes are much faster than any method. + .. NOTE:: + + This is not the same as the concept of super category in mathematics. + In fact, this is not even the opposite relation of :meth:`is_subcategory`:: + + sage: A = VectorSpaces(QQ); A + Category of vector spaces over Rational Field + sage: B = VectorSpaces(QQ.category()); B + Category of vector spaces over (number fields and quotient fields and metric spaces) + sage: A.is_subcategory(B) + True + sage: B in A.all_super_categories() + False + + .. SEEALSO:: :meth:`_test_category_graph` + EXAMPLES:: sage: C = Rings(); C @@ -1379,7 +1395,16 @@ def _test_category_graph(self, **options): method resolution order of the parent and element classes. This method checks this. - .. TODO:: currently, this won't work for hom categories. + Note that if + :meth:`~sage.structure.category_object.CategoryObject._refine_category_` + is called at unexpected times, the invariant might be false. Most + commonly, this happens with rings like ``Zmod(n)`` or ``SR``, where + a check like ``Zmod(n) in Fields()`` is needed (which checks the primality + of `n`) to refine their category to be a subcategory of fields. + + .. SEEALSO:: + + :meth:`CategoryWithParameters._make_named_class_key` EXAMPLES:: @@ -1615,6 +1640,11 @@ def subcategory_class(self): sage: isinstance(AlgebrasWithBasis(QQ), cls) True + .. NOTE:: + + See the note about :meth:`_test_category_graph` regarding Python + class hierarchy. + TESTS:: sage: cls = Algebras(QQ).subcategory_class; cls @@ -1667,6 +1697,11 @@ def parent_class(self): :class:`~sage.categories.bimodules.Bimodules`, :class:`~sage.categories.category_types.Category_over_base` and :class:`sage.categories.category.JoinCategory`. + + .. NOTE:: + + See the note about :meth:`_test_category_graph` regarding Python + class hierarchy. """ return self._make_named_class('parent_class', 'ParentMethods') @@ -1713,6 +1748,11 @@ def element_class(self): 0 .. SEEALSO:: :meth:`parent_class` + + .. NOTE:: + + See the note about :meth:`_test_category_graph` regarding Python + class hierarchy. """ return self._make_named_class('element_class', 'ElementMethods') @@ -1757,7 +1797,7 @@ def required_methods(self): # Operations on the lattice of categories def is_subcategory(self, c): """ - Return ``True`` if ``self`` is naturally embedded as a subcategory of `c`. + Return ``True`` if there is a natural forgetful functor from ``self`` to `c`. EXAMPLES:: @@ -2046,13 +2086,18 @@ def _with_axiom(self, axiom): Return the subcategory of the objects of ``self`` satisfying the given ``axiom``. + Note that this is a private method thus should not be directly + used, see below. + INPUT: - ``axiom`` -- string, the name of an axiom EXAMPLES:: - sage: Sets()._with_axiom("Finite") + sage: Sets()._with_axiom("Finite") # not idiomatic + Category of finite sets + sage: Sets().Finite() # recommended Category of finite sets sage: type(Magmas().Finite().Commutative()) @@ -2068,7 +2113,7 @@ def _with_axiom(self, axiom): sage: Sets()._with_axiom("Associative") Category of sets - .. WARNING:: This may be changed in the future to raising an error. + .. WARNING:: This may be changed in the future to raise an error. """ return Category.join(self._with_axiom_as_tuple(axiom)) @@ -2718,6 +2763,10 @@ def _make_named_class(self, name, method_provider, cache=False, **options): It is assumed that this method is only called from a lazy attribute whose name coincides with the given ``name``. + Currently, this means :meth:`Category.subcategory_class`, + :meth:`Category.parent_class` or :meth:`element_class`. + + Subclasses need to implement :meth:`_make_named_class_key`. OUTPUT: @@ -2810,6 +2859,10 @@ def _make_named_class(self, name, method_provider, cache=False, **options): pass result = Category._make_named_class(self, name, method_provider, cache=cache, **options) + if key[2] != self._make_named_class_key(name): + # the object in the parameter may have had its category refined, which might modify the key + # throw result away and recompute + return self._make_named_class(name, method_provider, cache=cache, **options) self._make_named_class_cache[key] = result return result @@ -2818,6 +2871,50 @@ def _make_named_class_key(self, name): r""" Return what the element/parent/... class depend on. + This method starts as an optimization to allow different related + categories to share the Python types, see :issue:`11935`. + However, because of the guarantees stated in :meth:`Category._test_category_graph`, + the following rules must be followed:: + + - If two categories have different lists of supercategories, they must return + different keys:: + + sage: Zmod(5) in Fields() + True + sage: Algebras(Zmod(5)).all_super_categories() + [..., Category of vector spaces over Ring of integers modulo 5, ...] + sage: Zmod(6) in Fields() + False + sage: Algebras(Zmod(6)).all_super_categories() # of course don't have category of vector spaces + [..., Category of modules over Ring of integers modulo 6, ...] + sage: # therefore: + sage: Algebras(Zmod(5))._make_named_class_key("parent_class") != Algebras(Zmod(6))._make_named_class_key("parent_class") + True + sage: Algebras(Zmod(5)).parent_class != Algebras(Zmod(6)).parent_class + True + + - If category ``A`` is a supercategory of category ``B``, + and category ``B`` uses the optimization, then so must ``A``. + + For example, ``Modules(ZZ)`` is a supercategory of ``Algebras(ZZ)``, + and ``Algebras(ZZ)`` implements the optimization:: + + sage: from sage.categories.category import CategoryWithParameters + sage: isinstance(Algebras(ZZ), CategoryWithParameters) + True + sage: Algebras(ZZ).parent_class is Algebras(ZZ.category()).parent_class + True + sage: Modules(ZZ) in Algebras(ZZ).all_super_categories() + True + + This forces ``Modules(ZZ)`` to also implement the optimization:: + + sage: Modules(ZZ).parent_class is Modules(ZZ.category()).parent_class + True + + As a complication, computing the exact category might require some potentially + expensive test. See :meth:`Category._test_category_graph` for more details. + INPUT: - ``name`` -- string; the name of the class as an attribute @@ -2826,6 +2923,9 @@ def _make_named_class_key(self, name): .. SEEALSO:: - :meth:`_make_named_class` + + The following can be read for typical implementations of this method. + - :meth:`sage.categories.category_types.Category_over_base._make_named_class_key` - :meth:`sage.categories.bimodules.Bimodules._make_named_class_key` - :meth:`JoinCategory._make_named_class_key` @@ -3064,6 +3164,9 @@ def _with_axiom(self, axiom): """ Return the category obtained by adding an axiom to ``self``. + As mentioned in :meth:`Category._with_axiom`, this method should not be used directly + except in internal code. + .. NOTE:: This is just an optimization of @@ -3073,7 +3176,9 @@ def _with_axiom(self, axiom): EXAMPLES:: sage: C = Category.join([Monoids(), Posets()]) - sage: C._with_axioms(["Finite"]) + sage: C._with_axioms(["Finite"]) # not idiomatic + Join of Category of finite monoids and Category of finite posets + sage: C.Finite() # recommended Join of Category of finite monoids and Category of finite posets TESTS: diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index c4ca2db0028..17dcf1fbdca 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -67,6 +67,54 @@ def _repr_object_names(self): """ return "filtered {}".format(self.base_category()._repr_object_names()) + def _make_named_class_key(self, name): + r""" + Return what the element/parent/... classes depend on. + + .. SEEALSO:: + + - :meth:`.CategoryWithParameters._make_named_class_key` + + EXAMPLES:: + + sage: Modules(ZZ).Filtered()._make_named_class_key('element_class') + + + Note that we cannot simply return the base as in + :meth:`.Category_over_base._make_named_class_key` because of the following + (see :issue:`39154`):: + + sage: VectorSpacesQQ = VectorSpaces(QQ); VectorSpacesQQ + Category of vector spaces over Rational Field + sage: # ModulesQQ = Modules(QQ) # doesn't work because... + sage: Modules(QQ) is VectorSpacesQQ + True + sage: ModulesQQ = VectorSpacesQQ.super_categories()[0]; ModulesQQ + Category of modules over Rational Field + sage: VectorSpacesQQ.Filtered() + Category of filtered vector spaces over Rational Field + sage: ModulesQQ.Filtered() + Category of filtered modules over Rational Field + sage: VectorSpacesQQ.Filtered()._make_named_class_key('parent_class') + + sage: ModulesQQ.Filtered()._make_named_class_key('parent_class') + + sage: assert (VectorSpacesQQ.Filtered()._make_named_class_key('parent_class') != + ....: ModulesQQ.Filtered()._make_named_class_key('parent_class')) + sage: VectorSpacesQQ.Filtered().parent_class + + sage: ModulesQQ.Filtered().parent_class + + + Nevertheless, as explained in :meth:`.Category_over_base._make_named_class_key`, + ``Modules(QQ).Filtered()`` and ``Modules(QQ.category()).Filtered()`` must have + the same parent class:: + + sage: Modules(QQ).Filtered().parent_class == Modules(QQ.category()).Filtered().parent_class + True + """ + return getattr(self._base_category, name) + class FilteredModules(FilteredModulesCategory): r""" @@ -122,8 +170,9 @@ def extra_super_categories(self): """ from sage.categories.modules import Modules from sage.categories.fields import Fields + from sage.categories.category import Category base_ring = self.base_ring() - if base_ring in Fields(): + if base_ring in Fields() or (isinstance(base_ring, Category) and base_ring.is_subcategory(Fields())): return [Modules(base_ring)] else: return [] diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 1b05cca4a52..4cc58966bd3 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -396,7 +396,7 @@ def Hom(X, Y, category=None, check=True): """ # This should use cache_function instead # However some special handling is currently needed for - # domains/docomains that break the unique parent condition. Also, + # domains/codomains that break the unique parent condition. Also, # at some point, it somehow broke the coercion (see e.g. sage -t # sage.rings.real_mpfr). To be investigated. global _cache diff --git a/src/sage/categories/homsets.py b/src/sage/categories/homsets.py index d930e5a3fd2..73dc6be120c 100644 --- a/src/sage/categories/homsets.py +++ b/src/sage/categories/homsets.py @@ -10,13 +10,13 @@ # ***************************************************************************** from sage.misc.cachefunc import cached_method -from sage.categories.category import Category, JoinCategory +from sage.categories.category import Category, JoinCategory, CategoryWithParameters from sage.categories.category_singleton import Category_singleton from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.covariant_functorial_construction import FunctorialConstructionCategory -class HomsetsCategory(FunctorialConstructionCategory): +class HomsetsCategory(FunctorialConstructionCategory, CategoryWithParameters): _functor_category = "Homsets" @@ -155,6 +155,17 @@ def base(self): return C.base() raise AttributeError("This hom category has no base") + def _make_named_class_key(self, name): + r""" + Return what the element/parent/... classes depend on. + + .. SEEALSO:: + + - :meth:`CategoryWithParameters` + - :meth:`CategoryWithParameters._make_named_class_key` + """ + return getattr(self.base_category(), name) + class HomsetsOf(HomsetsCategory): """ diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index d7dd1bdb2c4..bd57a0f32c6 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -3514,7 +3514,7 @@ class SmallPermutationGroup(PermutationGroup_generic): [ 2 0 -1 2 0 -1] sage: def numgps(n): return ZZ(libgap.NumberSmallGroups(n)) sage: all(SmallPermutationGroup(n,k).id() == [n,k] - ....: for n in [1..64] for k in [1..numgps(n)]) + ....: for n in [1..64] for k in [1..numgps(n)]) # long time (180s) True sage: H = SmallPermutationGroup(6,1) sage: H.is_abelian() From fdaca893962ebefb39509ce36e3a7ddb3dedd241 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Mon, 23 Dec 2024 20:41:32 +0700 Subject: [PATCH 050/187] Fix incorrect markup --- src/sage/categories/category.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index 1a2e2733cf4..07383a84f68 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -2874,7 +2874,7 @@ def _make_named_class_key(self, name): This method starts as an optimization to allow different related categories to share the Python types, see :issue:`11935`. However, because of the guarantees stated in :meth:`Category._test_category_graph`, - the following rules must be followed:: + the following rules must be followed. - If two categories have different lists of supercategories, they must return different keys:: From babb6bba75d5618cb3975390dd29081198574b2e Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Mon, 23 Dec 2024 19:33:01 +0530 Subject: [PATCH 051/187] introduced tight_cut_decomposition() --- src/sage/graphs/matching_covered_graph.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index d0910aef5c6..9c80721e0dd 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -97,7 +97,6 @@ ``number_of_braces()`` | Return the number of braces. ``number_of_bricks()`` | Return the number of bricks. ``number_of_petersen_bricks()`` | Return the number of Petersen bricks. - ``tight_cut_decomposition()`` | Return a tight cut decomposition. **Removability and ear decomposition** @@ -3261,6 +3260,14 @@ def remove_loops(self, vertices=None): return + @doc_index('Bricks, braces and tight cut decomposition') + def tight_cut_decomposition(self): + r""" + Return a maximal set of laminar nontrivial tight cuts and a + corresponding vertex set partition. + """ + raise NotImplementedError() + @doc_index('Miscellaneous methods') def update_matching(self, matching): r""" From 7455ac043fdf58072bca87f5a3d3cee751cce619 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Mon, 23 Dec 2024 19:48:14 +0530 Subject: [PATCH 052/187] removed a whitespace --- src/sage/graphs/matching_covered_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 9c80721e0dd..3cf282b1f09 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -3267,7 +3267,7 @@ def tight_cut_decomposition(self): corresponding vertex set partition. """ raise NotImplementedError() - + @doc_index('Miscellaneous methods') def update_matching(self, matching): r""" From 274f78f8b5b93e18f5d591fad5b5111c2a1119b0 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Fri, 27 Dec 2024 20:30:06 +0700 Subject: [PATCH 053/187] Also handle elliptic curve, fix some grammar error --- src/sage/matrix/matrix_space.py | 2 +- src/sage/modules/free_module.py | 2 +- src/sage/schemes/elliptic_curves/ell_generic.py | 13 +++++++++++++ src/sage/structure/parent.pyx | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index acbb82c5a74..647efed20ca 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -957,7 +957,7 @@ def characteristic(self): def is_exact(self): """ - Test whether elements of this matrix space is exact. + Test whether elements of this matrix space are represented exactly. OUTPUT: diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 45c1434fa89..5686078ed31 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -1010,7 +1010,7 @@ def is_sparse(self): def is_exact(self): """ - Test whether elements of this module is exact. + Test whether elements of this module are represented exactly. OUTPUT: diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index 44f552ae4af..94c69fa3be0 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -1076,6 +1076,19 @@ def is_on_curve(self, x, y): a = self.ainvs() return y**2 + a[0]*x*y + a[2]*y == x**3 + a[1]*x**2 + a[3]*x + a[4] + def is_exact(self): + """ + Test whether elements of this elliptic curve are represented exactly. + + EXAMPLES:: + + sage: EllipticCurve(QQ, [1, 2]).is_exact() + True + sage: EllipticCurve(RR, [1, 2]).is_exact() + False + """ + return self.__base_ring.is_exact() + def a_invariants(self): r""" The `a`-invariants of this elliptic curve, as a tuple. diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 508d2931c81..e9aa7d0ec3e 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -2863,7 +2863,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): cpdef bint is_exact(self) except -2: """ - Test whether elements of this parent is exact. + Test whether elements of this parent are represented exactly. .. NOTE:: From 4af9d0e236996d35cc57f7d7a98661245ca92e17 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 29 Dec 2024 22:42:03 +0800 Subject: [PATCH 054/187] fix linter --- src/sage/misc/misc.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index f7119920be2..8005a14ee5a 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -50,11 +50,11 @@ from sage.env import DOT_SAGE, HOSTNAME from sage.misc.lazy_import import lazy_import -lazy_import("sage.combinat.subset", ["powerset", "subsets", "uniq"], - deprecation=35564) +lazy_import("sage.combinat.subset", ["powerset", "subsets", "uniq"], deprecation=35564) -lazy_import("sage.misc.timing", ["cputime", "GlobalCputime", "walltime"], - deprecation=35816) +lazy_import( + "sage.misc.timing", ["cputime", "GlobalCputime", "walltime"], deprecation=35816 +) LOCAL_IDENTIFIER = '%s.%s' % (HOSTNAME, os.getpid()) @@ -168,6 +168,7 @@ def try_read(obj, splitlines=False): return data + try: # Create the matplotlib config directory. os.makedirs(os.environ["MPLCONFIGDIR"], exist_ok=True) @@ -347,6 +348,7 @@ def nest(f, n, x): x """ from sage.rings.integer import Integer + n = Integer(n) if n < 0: @@ -361,6 +363,7 @@ def nest(f, n, x): # The A \ b operator ################################################################# + class BackslashOperator: r""" Implement Matlab-style backslash operator for solving systems:: @@ -385,6 +388,7 @@ class BackslashOperator: sage: preparse("A^3 \\ b") 'A**Integer(3) * BackslashOperator() * b' """ + def __rmul__(self, left): """ EXAMPLES:: @@ -408,6 +412,7 @@ def __rmul__(self, left): True """ from sage.misc.superseded import deprecation + deprecation(36394, 'the backslash operator has been deprecated') self.left = left return self @@ -439,6 +444,7 @@ def __mul__(self, right): (0.0, 0.5, 1.0, 1.5, 2.0) """ from sage.misc.superseded import deprecation + deprecation(36394, 'the backslash operator has been deprecated') return self.left._backslash_(right) @@ -527,6 +533,7 @@ def random_sublist(X, s): True """ import sage.misc.prandom as random + return [a for a in X if random.random() <= s] @@ -599,6 +606,7 @@ def some_tuples(elements, repeat, bound, max_samples=None): """ if max_samples is None: from itertools import islice, product + P = elements if repeat is None else product(elements, repeat=repeat) return islice(P, int(bound)) else: @@ -608,6 +616,7 @@ def some_tuples(elements, repeat, bound, max_samples=None): N = n if repeat is None else n**repeat if N <= max_samples: from itertools import product + return elements if repeat is None else product(elements, repeat=repeat) return _some_tuples_sampling(elements, repeat, max_samples, n) @@ -634,6 +643,7 @@ def _some_tuples_sampling(elements, repeat, max_samples, n): """ from sage.rings.integer import Integer import sage.misc.prandom as random + N = n if repeat is None else n**repeat # We sample on range(N) and create tuples manually since we don't want to create the list of all possible tuples in memory for a in random.sample(range(N), max_samples): @@ -647,6 +657,7 @@ def _some_tuples_sampling(elements, repeat, max_samples, n): # Misc. ################################################################# + def exists(S, P): """ If S contains an element x such that P(x) is ``True``, this function @@ -832,8 +843,8 @@ def in_quote(): # which is the case if the previous character isn't # a backslash, or it is but both previous characters # are backslashes. - if line[i - 1: i] != '\\' or line[i - 2: i] == '\\\\': - if line[i: i + 3] in ['"""', "'''"]: + if line[i - 1 : i] != '\\' or line[i - 2 : i] == '\\\\': + if line[i : i + 3] in ['"""', "'''"]: if not in_quote(): in_triple_quote = True elif in_triple_quote: @@ -895,6 +906,7 @@ def get_main_globals(): module. """ import sys + depth = 0 while True: G = sys._getframe(depth).f_globals @@ -953,8 +965,9 @@ def inject_variable(name, value, warn=True): # also from functions in various modules. G = get_main_globals() if name in G and warn: - warnings.warn("redefining global value `%s`" % name, - RuntimeWarning, stacklevel=2) + warnings.warn( + "redefining global value `%s`" % name, RuntimeWarning, stacklevel=2 + ) G[name] = value @@ -1009,12 +1022,14 @@ def run_once(func): sage: foo(False) sage: foo(True) """ + @functools.wraps(func) def wrapper(*args, **kwargs): if not wrapper.has_run: result = func(*args, **kwargs) wrapper.has_run = True return result + wrapper.has_run = False return wrapper From e1208c89e8ebb7491458951b30d1eb10ef4b3c17 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Wed, 1 Jan 2025 20:09:07 +0530 Subject: [PATCH 055/187] updated is_brace() --- src/sage/graphs/matching_covered_graph.py | 33 ++++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 3cf282b1f09..103e9975084 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2566,7 +2566,7 @@ def is_brace(self, coNP_certificate=False): sage: len(L) == len(M) True - A cycle graph of order six of more is a bipartite matching covered + A cycle graph of order six or more is a bipartite matching covered graph, but is not a brace:: sage: C = graphs.CycleGraph(10) @@ -2574,6 +2574,16 @@ def is_brace(self, coNP_certificate=False): sage: G.is_brace() False + A ladder graph of order six or more is a bipartite matching covered + graph, that is not a brace. The tight cut decomposition of a ladder + graph produces a list graphs the underlying graph of each of which + is isomorphic to a 4-cycle:: + + sage: L = graphs.LadderGraph(10) + sage: G = MatchingCoveredGraph(L) + sage: G.is_brace() + False + One may set the ``coNP_certificate`` to be ``True``:: sage: H = graphs.HexahedralGraph() @@ -2593,6 +2603,19 @@ def is_brace(self, coNP_certificate=False): True sage: for u, v, *_ in nontrivial_tight_cut: ....: assert (u in nontrivial_odd_component and v not in nontrivial_odd_component) + sage: L = graphs.LadderGraph(3) # A ladder graph with two constituent braces + sage: G = MatchingCoveredGraph(L) + sage: is_brace, nontrivial_tight_cut, nontrivial_odd_component = G.is_brace(coNP_certificate=True) + sage: is_brace is False + True + sage: G1 = L.copy() + sage: G1.merge_vertices(list(nontrivial_odd_component)) + sage: G1.to_simple().is_isomorphic(graphs.CycleGraph(4)) + True + sage: G2 = L.copy() + sage: G2.merge_vertices([v for v in G if v not in nontrivial_odd_component]) + sage: G2.to_simple().is_isomorphic(graphs.CycleGraph(4)) + True If the input matching covered graph is nonbipartite, a :exc:`ValueError` is thrown:: @@ -2612,7 +2635,6 @@ def is_brace(self, coNP_certificate=False): .. SEEALSO:: - - :meth:`~sage.graphs.graph.Graph.is_bicritical` - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.is_brick` - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.bricks_and_braces` - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_braces` @@ -2635,7 +2657,7 @@ def is_brace(self, coNP_certificate=False): H = Graph(self, multiedges=False) H.delete_vertices([u, v]) - if not H.is_matching_covered(list(matching - set([e]))): + if not H.is_connected()or not H.is_matching_covered(list(matching - set([e]))): if not coNP_certificate: return False @@ -2686,6 +2708,8 @@ def dfs(v, visited, neighbor_iterator): X = set() dfs(root, X, D.neighbor_out_iterator) + color_class = None + for a, b in H.edge_iterator(labels=False, sort_vertices=True): if (a in X) ^ (b in X): x = a if a in A else b @@ -2694,7 +2718,7 @@ def dfs(v, visited, neighbor_iterator): # Obtain the color class Z ∈ {A, B} such that X ∩ Z is a vertex cover for T(e) # Thus, obtain Y := X + v - X.add(u if (not color_class and u in A) or (color_class and u in B) else v) + X.add(u if (not color_class and u in A) or (color_class and u in B) or (color_class is None) else v) # Compute the nontrivial tight cut C := ∂(Y) C = [(u, v, w) if u in X else (v, u, w) @@ -2862,6 +2886,7 @@ def is_brick(self, coNP_certificate=False): - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.bricks_and_braces` - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_bricks` - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_petersen_bricks` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.tight_cut_decomposition` """ if self.is_bipartite(): raise ValueError('the input graph is bipartite') From 97e61051d2a444798e5a58e681b8acb95916b931 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Wed, 1 Jan 2025 23:23:46 +0700 Subject: [PATCH 056/187] Make tests compatible with numpy 2.1 --- .../Quickstarts/Statistics-and-Distributions.rst | 2 +- .../en/thematic_tutorials/numerical_sage/numpy.rst | 2 +- src/sage/combinat/fully_packed_loop.py | 2 +- src/sage/functions/special.py | 2 +- src/sage/numerical/optimize.py | 12 ++++++------ src/sage/plot/arrow.py | 2 +- src/sage/plot/multigraphics.py | 4 ++-- src/sage/plot/streamline_plot.py | 2 +- src/sage/rings/integer.pyx | 2 +- src/sage/rings/real_mpfi.pyx | 2 +- .../elliptic_curves/period_lattice_region.pyx | 10 +++++----- src/sage/stats/basic_stats.py | 4 ++-- src/sage/structure/coerce.pyx | 2 +- src/sage/symbolic/function.pyx | 2 +- src/sage/symbolic/ring.pyx | 2 +- 15 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/doc/en/prep/Quickstarts/Statistics-and-Distributions.rst b/src/doc/en/prep/Quickstarts/Statistics-and-Distributions.rst index 958a378f945..5870df3d88a 100644 --- a/src/doc/en/prep/Quickstarts/Statistics-and-Distributions.rst +++ b/src/doc/en/prep/Quickstarts/Statistics-and-Distributions.rst @@ -25,7 +25,7 @@ the standard deviation:: sage: import numpy as np sage: if int(np.version.short_version[0]) > 1: - ....: np.set_printoptions(legacy="1.25") + ....: _ = np.set_printoptions(legacy="1.25") sage: np.mean([1, 2, 3, 5]) 2.75 diff --git a/src/doc/en/thematic_tutorials/numerical_sage/numpy.rst b/src/doc/en/thematic_tutorials/numerical_sage/numpy.rst index 925e5312882..ab774ca8fd1 100644 --- a/src/doc/en/thematic_tutorials/numerical_sage/numpy.rst +++ b/src/doc/en/thematic_tutorials/numerical_sage/numpy.rst @@ -8,7 +8,7 @@ import it. sage: import numpy sage: if int(numpy.version.short_version[0]) > 1: - ....: numpy.set_printoptions(legacy="1.25") # to ensure numpy 2.0 compatibility + ....: _ = numpy.set_printoptions(legacy="1.25") # to ensure numpy 2.0 compatibility The basic object of computation in NumPy is an array. It is simple to create an array. diff --git a/src/sage/combinat/fully_packed_loop.py b/src/sage/combinat/fully_packed_loop.py index 81e3a30508f..e6c89ec3c3c 100644 --- a/src/sage/combinat/fully_packed_loop.py +++ b/src/sage/combinat/fully_packed_loop.py @@ -68,7 +68,7 @@ def _make_color_list(n, colors=None, color_map=None, randomize=False): sage: import numpy as np sage: if int(np.version.short_version[0]) > 1: - ....: np.set_printoptions(legacy="1.25") + ....: _ = np.set_printoptions(legacy="1.25") sage: from sage.combinat.fully_packed_loop import _make_color_list sage: _make_color_list(5) sage: _make_color_list(5, ['blue', 'red']) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 308171af3cd..4363d332291 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -219,7 +219,7 @@ class SphericalHarmonic(BuiltinFunction): sage: from scipy.special import sph_harm # NB: arguments x and y are swapped # needs scipy sage: import numpy as np # needs scipy sage: if int(np.version.short_version[0]) > 1: # needs scipy - ....: np.set_printoptions(legacy="1.25") # needs scipy + ....: _ = np.set_printoptions(legacy="1.25") # needs scipy sage: sph_harm(1, 1, pi.n(), (pi/2).n()) # abs tol 1e-14 # needs scipy sage.symbolic (0.3454941494713355-4.231083042742082e-17j) diff --git a/src/sage/numerical/optimize.py b/src/sage/numerical/optimize.py index cdcd3a524b3..742de62d5de 100644 --- a/src/sage/numerical/optimize.py +++ b/src/sage/numerical/optimize.py @@ -155,7 +155,7 @@ def find_root(f, a, b, xtol=10e-13, rtol=2.0**-50, maxiter=100, full_output=Fals import scipy.optimize import numpy if int(numpy.version.short_version[0]) > 1: - numpy.set_printoptions(legacy="1.25") + _ = numpy.set_printoptions(legacy="1.25") g = lambda x: float(f(x)) brentqRes = scipy.optimize.brentq(g, a, b, @@ -290,7 +290,7 @@ def find_local_minimum(f, a, b, tol=1.48e-08, maxfun=500): import scipy.optimize import numpy if int(numpy.version.short_version[0]) > 1: - numpy.set_printoptions(legacy="1.25") + _ = numpy.set_printoptions(legacy="1.25") xmin, fval, iter, funcalls = scipy.optimize.fminbound(f, a, b, full_output=1, xtol=tol, maxfun=maxfun) return fval, xmin @@ -381,7 +381,7 @@ def minimize(func, x0, gradient=None, hessian=None, algorithm='default', ....: return sum(100.0r*(x[1r:]-x[:-1r]**2.0r)**2.0r + (1r-x[:-1r])**2.0r) sage: import numpy sage: if int(numpy.version.short_version[0]) > 1: - ....: numpy.set_printoptions(legacy="1.25") + ....: _ = numpy.set_printoptions(legacy="1.25") sage: from numpy import zeros sage: def rosen_der(x): ....: xm = x[1r:-1r] @@ -400,7 +400,7 @@ def minimize(func, x0, gradient=None, hessian=None, algorithm='default', from sage.ext.fast_callable import fast_callable import numpy if int(numpy.version.short_version[0]) > 1: - numpy.set_printoptions(legacy="1.25") + _ = numpy.set_printoptions(legacy="1.25") from scipy import optimize if isinstance(func, Expression): @@ -539,7 +539,7 @@ def minimize_constrained(func, cons, x0, gradient=None, algorithm='default', **a from sage.ext.fast_callable import fast_callable import numpy if int(numpy.version.short_version[0]) > 1: - numpy.set_printoptions(legacy="1.25") + _ = numpy.set_printoptions(legacy="1.25") from scipy import optimize function_type = type(lambda x,y: x+y) @@ -662,7 +662,7 @@ def find_fit(data, model, initial_guess=None, parameters=None, variables=None, s """ import numpy if int(numpy.version.short_version[0]) > 1: - numpy.set_printoptions(legacy="1.25") + _ = numpy.set_printoptions(legacy="1.25") if not isinstance(data, numpy.ndarray): try: diff --git a/src/sage/plot/arrow.py b/src/sage/plot/arrow.py index 02442f90ba4..c8a252cfcca 100644 --- a/src/sage/plot/arrow.py +++ b/src/sage/plot/arrow.py @@ -55,7 +55,7 @@ def get_minmax_data(self): sage: import numpy # to ensure numpy 2.0 compatibility sage: if int(numpy.version.short_version[0]) > 1: - ....: numpy.set_printoptions(legacy="1.25") + ....: _ = numpy.set_printoptions(legacy="1.25") sage: from sage.plot.arrow import CurveArrow sage: b = CurveArrow(path=[[(0,0),(.5,.5),(1,0)],[(.5,1),(0,0)]], ....: options={}) diff --git a/src/sage/plot/multigraphics.py b/src/sage/plot/multigraphics.py index 6ed26974c49..38ce09e9846 100644 --- a/src/sage/plot/multigraphics.py +++ b/src/sage/plot/multigraphics.py @@ -766,7 +766,7 @@ def _add_subplot(self, figure, index, **options): (0.2, 0.3, 0.4, 0.1) sage: import numpy # to ensure numpy 2.0 compatibility sage: if int(numpy.version.short_version[0]) > 1: - ....: numpy.set_printoptions(legacy="1.25") + ....: _ = numpy.set_printoptions(legacy="1.25") sage: ax1.get_position().bounds # tol 1.0e-13 (0.2, 0.3, 0.4000000000000001, 0.10000000000000003) """ @@ -1269,7 +1269,7 @@ def position(self, index): sage: G = graphics_array([g1, g2]) sage: import numpy # to ensure numpy 2.0 compatibility sage: if int(numpy.version.short_version[0]) > 1: - ....: numpy.set_printoptions(legacy="1.25") + ....: _ = numpy.set_printoptions(legacy="1.25") sage: G.position(0) # tol 5.0e-3 (0.025045451349937315, 0.03415488992713045, diff --git a/src/sage/plot/streamline_plot.py b/src/sage/plot/streamline_plot.py index 2801446433a..f995cd71f93 100644 --- a/src/sage/plot/streamline_plot.py +++ b/src/sage/plot/streamline_plot.py @@ -72,7 +72,7 @@ def get_minmax_data(self): sage: x, y = var('x y') sage: import numpy # to ensure numpy 2.0 compatibility sage: if int(numpy.version.short_version[0]) > 1: - ....: numpy.set_printoptions(legacy="1.25") + ....: _ = numpy.set_printoptions(legacy="1.25") sage: d = streamline_plot((.01*x, x+y), (x,10,20), (y,10,20))[0].get_minmax_data() sage: d['xmin'] 10.0 diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index c9d1ff65bc6..466893c1f03 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -595,7 +595,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: # needs numpy sage: import numpy sage: if int(numpy.version.short_version[0]) > 1: - ....: numpy.set_printoptions(legacy="1.25") + ....: _ = numpy.set_printoptions(legacy="1.25") sage: numpy.int8('12') == 12 True sage: 12 == numpy.int8('12') diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index ce9958ce7e7..bbe72c26ba2 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -252,7 +252,7 @@ TESTS:: sage: import numpy # needs numpy sage: if int(numpy.version.short_version[0]) > 1: # needs numpy - ....: numpy.set_printoptions(legacy="1.25") # needs numpy + ....: _ = numpy.set_printoptions(legacy="1.25") # needs numpy sage: RIF(2) == numpy.int8('2') # needs numpy True sage: numpy.int8('2') == RIF(2) # needs numpy diff --git a/src/sage/schemes/elliptic_curves/period_lattice_region.pyx b/src/sage/schemes/elliptic_curves/period_lattice_region.pyx index 40b92ab23eb..e4676810481 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice_region.pyx +++ b/src/sage/schemes/elliptic_curves/period_lattice_region.pyx @@ -78,7 +78,7 @@ cdef class PeriodicRegion: sage: import numpy as np sage: if int(np.version.short_version[0]) > 1: - ....: np.set_printoptions(legacy="1.25") + ....: _ = np.set_printoptions(legacy="1.25") sage: from sage.schemes.elliptic_curves.period_lattice_region import PeriodicRegion sage: data = np.zeros((4, 4)) sage: PeriodicRegion(CDF(2), CDF(2*I), data).is_empty() @@ -296,7 +296,7 @@ cdef class PeriodicRegion: sage: import numpy as np sage: if int(np.version.short_version[0]) > 1: - ....: np.set_printoptions(legacy="1.25") + ....: _ = np.set_printoptions(legacy="1.25") sage: from sage.schemes.elliptic_curves.period_lattice_region import PeriodicRegion sage: data = np.zeros((10, 10)) sage: data[1:4,1:4] = True @@ -320,7 +320,7 @@ cdef class PeriodicRegion: sage: import numpy as np sage: if int(np.version.short_version[0]) > 1: - ....: np.set_printoptions(legacy="1.25") + ....: _ = np.set_printoptions(legacy="1.25") sage: from sage.schemes.elliptic_curves.period_lattice_region import PeriodicRegion sage: data = np.zeros((4, 4)) sage: data[1,1] = True @@ -375,7 +375,7 @@ cdef class PeriodicRegion: sage: import numpy as np sage: if int(np.version.short_version[0]) > 1: - ....: np.set_printoptions(legacy="1.25") + ....: _ = np.set_printoptions(legacy="1.25") sage: from sage.schemes.elliptic_curves.period_lattice_region import PeriodicRegion sage: data = np.zeros((20, 20)) @@ -528,7 +528,7 @@ cdef class PeriodicRegion: sage: import numpy as np sage: if int(np.version.short_version[0]) > 1: - ....: np.set_printoptions(legacy="1.25") + ....: _ = np.set_printoptions(legacy="1.25") sage: from sage.schemes.elliptic_curves.period_lattice_region import PeriodicRegion sage: data = np.zeros((4, 4)) sage: data[1, 1] = True diff --git a/src/sage/stats/basic_stats.py b/src/sage/stats/basic_stats.py index 47d890cf0ab..887e4dfd89f 100644 --- a/src/sage/stats/basic_stats.py +++ b/src/sage/stats/basic_stats.py @@ -222,7 +222,7 @@ def std(v, bias=False): sage: # needs numpy sage: import numpy sage: if int(numpy.version.short_version[0]) > 1: - ....: numpy.set_printoptions(legacy="1.25") + ....: _ = numpy.set_printoptions(legacy="1.25") sage: x = numpy.array([1,2,3,4,5]) sage: std(x, bias=False) 1.5811388300841898 @@ -299,7 +299,7 @@ def variance(v, bias=False): 0.4897530450000000? sage: import numpy # needs numpy sage: if int(numpy.version.short_version[0]) > 1: # needs numpy - ....: numpy.set_printoptions(legacy="1.25") # needs numpy + ....: _ = numpy.set_printoptions(legacy="1.25") # needs numpy sage: x = numpy.array([1,2,3,4,5]) # needs numpy sage: variance(x, bias=False) # needs numpy 2.5 diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 6861cfb5be3..f481536f8aa 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -521,7 +521,7 @@ cdef class CoercionModel: sage: import numpy # needs numpy sage: if int(numpy.version.short_version[0]) > 1: # needs numpy - ....: numpy.set_printoptions(legacy="1.25") # needs numpy + ....: _ = numpy.set_printoptions(legacy="1.25") # needs numpy sage: # needs sage.rings.real_mpfr sage: x = polygen(RR) diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 86860237d5b..6b087c78609 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -962,7 +962,7 @@ cdef class BuiltinFunction(Function): sage: import numpy # needs numpy sage: if int(numpy.version.short_version[0]) > 1: # needs numpy - ....: numpy.set_printoptions(legacy="1.25") # needs numpy + ....: _ = numpy.set_printoptions(legacy="1.25") # needs numpy sage: sin(numpy.int32(0)) # needs numpy 0.0 diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index eaaa5cbdc15..ceaede5aa12 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -1154,7 +1154,7 @@ cdef class NumpyToSRMorphism(Morphism): sage: import numpy # needs numpy sage: if int(numpy.version.short_version[0]) > 1: # needs numpy - ....: numpy.set_printoptions(legacy="1.25") # needs numpy + ....: _ = numpy.set_printoptions(legacy="1.25") # needs numpy sage: f(x) = x^2 sage: f(numpy.int8('2')) # needs numpy 4 From 6ef81a73a6627e30d5439bb41b0b7170cdc2bd8d Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 4 Jan 2025 19:39:10 +0800 Subject: [PATCH 057/187] Replace `pari.all` imports by direct imports from pari and cypari --- src/sage/arith/misc.py | 20 +++++++++---------- src/sage/combinat/sloane_functions.py | 2 +- src/sage/databases/cremona.py | 4 ++-- .../arithmetic_dynamics/projective_ds.py | 2 +- src/sage/functions/special.py | 2 +- src/sage/groups/perm_gps/constructor.py | 2 +- src/sage/interfaces/genus2reduction.py | 2 +- src/sage/interfaces/gp.py | 2 +- src/sage/libs/pari/__init__.py | 6 ++++-- src/sage/libs/pari/all.py | 3 ++- src/sage/matrix/matrix1.pyx | 2 +- src/sage/matrix/matrix_rational_dense.pyx | 2 +- src/sage/misc/randstate.pyx | 2 +- src/sage/modular/cusps.py | 3 ++- src/sage/modules/free_module_element.pyx | 2 +- src/sage/quadratic_forms/binary_qf.py | 3 ++- .../quadratic_form__automorphisms.py | 2 +- .../quadratic_form__ternary_Tornaria.py | 2 +- src/sage/rings/complex_mpc.pyx | 4 +++- src/sage/rings/complex_mpfr.pyx | 2 +- src/sage/rings/factorint_pari.pyx | 2 +- .../rings/finite_rings/element_ntl_gf2e.pyx | 2 +- .../rings/finite_rings/finite_field_givaro.py | 2 +- .../finite_rings/finite_field_ntl_gf2e.py | 2 +- src/sage/rings/finite_rings/integer_mod.pyx | 3 ++- .../rings/finite_rings/integer_mod_ring.py | 3 ++- src/sage/rings/fraction_field.py | 2 +- src/sage/rings/infinity.py | 3 ++- src/sage/rings/laurent_series_ring.py | 2 +- src/sage/rings/number_field/galois_group.py | 2 +- src/sage/rings/number_field/maps.py | 2 +- src/sage/rings/number_field/number_field.py | 3 ++- .../rings/number_field/number_field_ideal.py | 4 ++-- .../rings/number_field/number_field_rel.py | 4 ++-- src/sage/rings/number_field/order.py | 2 +- .../small_primes_of_degree_one.py | 2 +- .../rings/number_field/splitting_field.py | 3 ++- src/sage/rings/number_field/totallyreal.pyx | 2 +- .../rings/number_field/totallyreal_rel.py | 2 +- src/sage/rings/number_field/unit_group.py | 2 +- .../rings/padics/padic_ZZ_pX_CA_element.pyx | 2 +- .../rings/padics/padic_ZZ_pX_CR_element.pyx | 2 +- .../rings/padics/padic_ZZ_pX_FM_element.pyx | 2 +- .../padics/padic_floating_point_element.pyx | 2 +- .../rings/padics/padic_generic_element.pyx | 2 +- src/sage/rings/polynomial/cyclotomic.pyx | 2 +- .../rings/polynomial/multi_polynomial_ring.py | 2 +- .../polynomial_padic_capped_relative_dense.py | 3 ++- .../padics/polynomial_padic_flat.py | 2 +- .../rings/polynomial/polynomial_element.pyx | 4 +++- .../polynomial/polynomial_element_generic.py | 2 +- src/sage/rings/polynomial/polynomial_gf2x.pyx | 2 +- .../polynomial_integer_dense_flint.pyx | 3 ++- .../polynomial_integer_dense_ntl.pyx | 3 ++- .../polynomial/polynomial_modn_dense_ntl.pyx | 3 ++- .../polynomial/polynomial_real_mpfr_dense.pyx | 2 +- src/sage/rings/polynomial/polynomial_ring.py | 4 ++-- .../rings/polynomial/polynomial_template.pxi | 2 +- src/sage/rings/power_series_mpoly.pyx | 2 +- src/sage/rings/power_series_pari.pyx | 2 +- .../elliptic_curves/descent_two_isogeny.pyx | 2 +- src/sage/schemes/elliptic_curves/ell_point.py | 3 ++- .../schemes/elliptic_curves/isogeny_class.py | 2 +- src/sage/structure/factorization.py | 2 +- src/sage/structure/sage_object.pyx | 2 +- src/sage/symbolic/pynac_impl.pxi | 2 +- 66 files changed, 99 insertions(+), 80 deletions(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 637ed9192bd..0b03c450eb9 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -265,7 +265,7 @@ def norm(v): raise NotImplementedError("proof and height bound only implemented for real and complex numbers") else: - from sage.libs.pari.all import pari + from sage.libs.pari import pari y = pari(z) f = y.algdep(degree) @@ -378,7 +378,7 @@ def bernoulli(n, algorithm='default', num_threads=1): from sage.libs.flint.arith_sage import bernoulli_number as flint_bernoulli return flint_bernoulli(n) elif algorithm == 'pari' or algorithm == 'gp': - from sage.libs.pari.all import pari + from sage.libs.pari import pari x = pari(n).bernfrac() # Use the PARI C library return Rational(x) elif algorithm == 'gap': @@ -470,7 +470,7 @@ def factorial(n, algorithm='gmp'): if algorithm == 'gmp': return ZZ(n).factorial() elif algorithm == 'pari': - from sage.libs.pari.all import pari + from sage.libs.pari import pari return pari.factorial(n) else: raise ValueError('unknown algorithm') @@ -3164,7 +3164,7 @@ def __call__(self, n): return ZZ.zero() if n <= 2: return ZZ.one() - from sage.libs.pari.all import pari + from sage.libs.pari import pari return ZZ(pari(n).eulerphi()) def plot(self, xmin=1, xmax=50, pointsize=30, rgbcolor=(0, 0, 1), @@ -4425,7 +4425,7 @@ def primitive_root(n, check=True): sage: primitive_root(mpz(-46)) # needs sage.libs.pari 5 """ - from sage.libs.pari.all import pari + from sage.libs.pari import pari if not check: return ZZ(pari(n).znprimroot()) n = ZZ(n).abs() @@ -4482,7 +4482,7 @@ def nth_prime(n): """ if n <= 0: raise ValueError("nth prime meaningless for nonpositive n (=%s)" % n) - from sage.libs.pari.all import pari + from sage.libs.pari import pari return ZZ(pari.prime(n)) @@ -4600,7 +4600,7 @@ def __call__(self, n): # Use fast PARI algorithm if n == 0: return ZZ.zero() - from sage.libs.pari.all import pari + from sage.libs.pari import pari return ZZ(pari(n).moebius()) def __repr__(self): @@ -4685,7 +4685,7 @@ def range(self, start, stop=None, step=None): return self.range(start, 0, step) + [ZZ.zero()] +\ self.range(step, stop, step) - from sage.libs.pari.all import pari + from sage.libs.pari import pari if step == 1: v = pari('vector(%s, i, moebius(i-1+%s))' % (stop - start, start)) @@ -4815,7 +4815,7 @@ def number_of_divisors(n): m = ZZ(n) if m.is_zero(): raise ValueError("input must be nonzero") - from sage.libs.pari.all import pari + from sage.libs.pari import pari return ZZ(pari(m).numdiv()) @@ -4888,7 +4888,7 @@ def hilbert_symbol(a, b, p, algorithm='pari'): if algorithm == "pari": if p == -1: p = 0 - from sage.libs.pari.all import pari + from sage.libs.pari import pari return ZZ(pari(a).hilbert(b, p)) elif algorithm == 'direct': diff --git a/src/sage/combinat/sloane_functions.py b/src/sage/combinat/sloane_functions.py index b9651829109..12580cbb8ca 100644 --- a/src/sage/combinat/sloane_functions.py +++ b/src/sage/combinat/sloane_functions.py @@ -6796,7 +6796,7 @@ def _powerful_numbers_in_range(self, n, m): n = max(n, 4) # Use PARI directly -- much faster. - from sage.libs.pari.all import pari + from sage.libs.pari import pari L = pari('v=listcreate(); for(i=%s,%s,if(vecmin(factor(i)[,2])>1,listput(v,i))); v' % (n, m)) return [ZZ(x) for x in L] # not very many, so not much overhead diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index ca859214155..a476863ad15 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -559,7 +559,7 @@ def cremona_to_lmfdb(cremona_label, CDB=None): sage: for label in ['438.c2','306.b','462.f3']: ....: assert(cremona_to_lmfdb(lmfdb_to_cremona(label)) == label) """ - from sage.libs.pari.all import pari + from sage.libs.pari import pari m = cremona_label_regex.match(cremona_label) if m is None: raise ValueError("Invalid Cremona label") @@ -609,7 +609,7 @@ def lmfdb_to_cremona(lmfdb_label, CDB=None): sage: cremona_to_lmfdb('990j1') '990.h3' """ - from sage.libs.pari.all import pari + from sage.libs.pari import pari m = lmfdb_label_regex.match(lmfdb_label) if m is None: raise ValueError("Invalid LMFDB label") diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 591693e5af8..1d540a43657 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -116,7 +116,7 @@ class initialization directly. lazy_import('sage.rings.padics.factory', 'Qp') lazy_import('sage.rings.qqbar', 'number_field_elements_from_algebraics') -from sage.libs.pari.all import PariError +from cypari2.handle_error import PariError class DynamicalSystem_projective(SchemeMorphism_polynomial_projective_space, diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 308171af3cd..e3b9bf14702 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -453,7 +453,7 @@ def elliptic_j(z, prec=53): z = CC(z) except ValueError: raise ValueError("elliptic_j only defined for complex arguments.") - from sage.libs.pari.all import pari + from sage.libs.pari import pari return CC(pari(z).ellj()) diff --git a/src/sage/groups/perm_gps/constructor.py b/src/sage/groups/perm_gps/constructor.py index 63c9aecd5d3..fabc7a6c9d3 100644 --- a/src/sage/groups/perm_gps/constructor.py +++ b/src/sage/groups/perm_gps/constructor.py @@ -28,7 +28,7 @@ lazy_import('sage.combinat.permutation', ['Permutation', 'from_cycles']) try: - from sage.libs.pari.all import pari_gen + from cypari2.gen import Gen as pari_gen except ImportError: pari_gen = () diff --git a/src/sage/interfaces/genus2reduction.py b/src/sage/interfaces/genus2reduction.py index 913188f9182..487287386e6 100644 --- a/src/sage/interfaces/genus2reduction.py +++ b/src/sage/interfaces/genus2reduction.py @@ -36,7 +36,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.libs.pari.all import pari +from sage.libs.pari import pari roman_numeral = ["", "I", "II", "III", "IV", "V", "VI", "VII"] diff --git a/src/sage/interfaces/gp.py b/src/sage/interfaces/gp.py index b98c050d889..eeefad9cd44 100644 --- a/src/sage/interfaces/gp.py +++ b/src/sage/interfaces/gp.py @@ -145,7 +145,7 @@ from sage.env import DOT_SAGE from sage.interfaces.tab_completion import ExtraTabCompletion -from sage.libs.pari.all import pari +from sage.libs.pari import pari from sage.misc.instancedoc import instancedoc from sage.misc.lazy_import import lazy_import from sage.misc.verbose import verbose diff --git a/src/sage/libs/pari/__init__.py b/src/sage/libs/pari/__init__.py index b5bc281db4d..7d01109e276 100644 --- a/src/sage/libs/pari/__init__.py +++ b/src/sage/libs/pari/__init__.py @@ -173,6 +173,10 @@ 3.60546360143265208591582056420772677481026899659802474544 # 32-bit """ +from cypari2 import Pari + +from sage.ext.memory import init_memory_functions + def _get_pari_instance(): """ @@ -181,14 +185,12 @@ def _get_pari_instance(): sage: pari # indirect doctest Interface to the PARI C library """ - from cypari2 import Pari stack_initial = 1024 * 1024 stack_max = 1024 * stack_initial P = Pari(stack_initial, stack_max) # pari_init_opts() overrides MPIR's memory allocation functions, # so we need to reset them. - from sage.ext.memory import init_memory_functions init_memory_functions() # PARI sets debugmem=1 by default but we do not want those warning diff --git a/src/sage/libs/pari/all.py b/src/sage/libs/pari/all.py index 6cef5978cc1..e896e5b09ea 100644 --- a/src/sage/libs/pari/all.py +++ b/src/sage/libs/pari/all.py @@ -1,3 +1,4 @@ -from cypari2.gen import Gen as pari_gen from cypari2 import PariError +from cypari2.gen import Gen as pari_gen + from sage.libs.pari import pari diff --git a/src/sage/matrix/matrix1.pyx b/src/sage/matrix/matrix1.pyx index 96a175825b3..41b1786bd52 100644 --- a/src/sage/matrix/matrix1.pyx +++ b/src/sage/matrix/matrix1.pyx @@ -87,7 +87,7 @@ cdef class Matrix(Matrix0): [1.000000000, 2.000000000; 3.000000000, 1.000000000] # 32-bit [1.00000000000000, 2.00000000000000; 3.00000000000000, 1.00000000000000] # 64-bit """ - from sage.libs.pari.all import pari + from sage.libs.pari import pari return pari.matrix(self._nrows, self._ncols, self._list()) def _gap_init_(self): diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index 40c63470617..b9438883765 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -119,7 +119,7 @@ from sage.misc.verbose import verbose # ######################################################## # PARI C library -from sage.libs.pari.all import PariError +from cypari2.handle_error import PariError from sage.libs.pari.convert_gmp cimport INTFRAC_to_mpq from sage.libs.pari.convert_flint cimport rational_matrix, _new_GEN_from_fmpq_mat_t from cypari2.stack cimport clear_stack diff --git a/src/sage/misc/randstate.pyx b/src/sage/misc/randstate.pyx index fe3351d126b..db700897568 100644 --- a/src/sage/misc/randstate.pyx +++ b/src/sage/misc/randstate.pyx @@ -790,7 +790,7 @@ cdef class randstate: """ global _pari_seed_randstate if _pari_seed_randstate is not self: - from sage.libs.pari.all import pari + from sage.libs.pari import pari if self._pari_saved_seed is not None: seed = self._pari_saved_seed diff --git a/src/sage/modular/cusps.py b/src/sage/modular/cusps.py index 7a4a2628096..6d72d35ca49 100644 --- a/src/sage/modular/cusps.py +++ b/src/sage/modular/cusps.py @@ -40,7 +40,8 @@ from sage.structure.richcmp import richcmp try: - from sage.libs.pari.all import pari, pari_gen + from sage.libs.pari import pari + from cypari2.gen import Gen as pari_gen except ImportError: pari_gen = () diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index a9d074007f0..840ea71f68d 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -1055,7 +1055,7 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: pari(L) # needs sage.libs.pari [[0, 1, 2, 3], [0, 1, 8, 27], [0, 1, 32, 243]] """ - from sage.libs.pari.all import pari + from sage.libs.pari import pari return pari(self.list()) def _pari_init_(self): diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index 202da0652ff..a6707c242f5 100644 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -60,7 +60,8 @@ try: - from sage.libs.pari.all import pari_gen, pari + from sage.libs.pari import pari + from cypari2.gen import Gen as pari_gen except ImportError: pari_gen = () diff --git a/src/sage/quadratic_forms/quadratic_form__automorphisms.py b/src/sage/quadratic_forms/quadratic_form__automorphisms.py index 4fa4d4fe1ff..b19c7939252 100644 --- a/src/sage/quadratic_forms/quadratic_form__automorphisms.py +++ b/src/sage/quadratic_forms/quadratic_form__automorphisms.py @@ -181,7 +181,7 @@ def short_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False): raise ValueError("Quadratic form must be positive definite " "in order to enumerate short vectors") - from sage.libs.pari.all import pari + from sage.libs.pari import pari if len_bound <= 0: return [] diff --git a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py index 3922767e870..7e277d899ea 100644 --- a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +++ b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py @@ -537,7 +537,7 @@ def representation_number_list(self, B): sage: Q.representation_number_list(10) # needs sage.libs.pari [1, 16, 112, 448, 1136, 2016, 3136, 5504, 9328, 12112] """ - from sage.libs.pari.all import pari + from sage.libs.pari import pari ans = pari(1).concat(self.__pari__().qfrep(B - 1, 1) * 2) return ans.sage() diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index d6bcb664a49..28d521ec604 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -74,7 +74,9 @@ from sage.structure.richcmp cimport rich_to_bool from sage.categories.map cimport Map try: - from sage.libs.pari.all import pari, pari_gen, PariError + from sage.libs.pari import pari + from cypari2.handle_error import PariError + from cypari2.gen cimport Gen as pari_gen except ImportError: pari_gen = PariError = () diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index d24e61d2823..d3dee1b278e 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -56,7 +56,7 @@ cimport gmpy2 gmpy2.import_gmpy2() try: - from sage.libs.pari.all import pari_gen + from cypari2.gen cimport Gen as pari_gen except ImportError: pari_gen = () diff --git a/src/sage/rings/factorint_pari.pyx b/src/sage/rings/factorint_pari.pyx index a8d748c5845..4316dc2de01 100644 --- a/src/sage/rings/factorint_pari.pyx +++ b/src/sage/rings/factorint_pari.pyx @@ -16,7 +16,7 @@ AUTHORS: # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.libs.pari.all import pari +from sage.libs.pari import pari from sage.rings.integer cimport Integer diff --git a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx index 2c1c25254c4..7d7abe463e1 100644 --- a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx @@ -40,7 +40,7 @@ from sage.structure.element cimport Vector from sage.rings.finite_rings.finite_field_base cimport FiniteField -from sage.libs.pari.all import pari +from sage.libs.pari import pari from cypari2.gen cimport Gen from cypari2.stack cimport clear_stack diff --git a/src/sage/rings/finite_rings/finite_field_givaro.py b/src/sage/rings/finite_rings/finite_field_givaro.py index ea40970b276..b1dfe8be331 100644 --- a/src/sage/rings/finite_rings/finite_field_givaro.py +++ b/src/sage/rings/finite_rings/finite_field_givaro.py @@ -22,7 +22,7 @@ from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.integer import Integer from sage.rings.finite_rings.element_givaro import Cache_givaro -from sage.libs.pari.all import pari +from sage.libs.pari import pari class FiniteField_givaro(FiniteField): 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 92404849b4e..7e051bc8b74 100644 --- a/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py +++ b/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py @@ -16,7 +16,7 @@ #***************************************************************************** from sage.rings.finite_rings.finite_field_base import FiniteField -from sage.libs.pari.all import pari +from sage.libs.pari import pari from sage.rings.integer import Integer diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index 19525b40937..46a3c5c5d82 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -87,7 +87,8 @@ from sage.arith.long cimport ( import sage.rings.rational as rational try: - from sage.libs.pari.all import pari, PariError + from sage.libs.pari import pari + from cypari2.handle_error import PariError except ImportError: class PariError(Exception): pass diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index 893fde4e929..fe550a8f427 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -77,7 +77,8 @@ import sage.rings.quotient_ring as quotient_ring try: - from sage.libs.pari.all import pari, PariError + from sage.libs.pari import pari + from cypari2.handle_error import PariError except ImportError: class PariError(Exception): pass diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index 4e3e923c263..60ba0a5763f 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -692,7 +692,7 @@ def _element_constructor_(self, x, y=None, coerce=True): y = py_scalar_to_element(y) try: - from sage.libs.pari.all import pari_gen + from cypari2.gen import Gen as pari_gen except ImportError: pari_gen = () diff --git a/src/sage/rings/infinity.py b/src/sage/rings/infinity.py index 986b32cb5d5..70208389fa4 100644 --- a/src/sage/rings/infinity.py +++ b/src/sage/rings/infinity.py @@ -334,7 +334,8 @@ def __pari__(self): sage: pari(oo) # needs sage.libs.pari +oo """ - from sage.libs.pari.all import pari + from sage.libs.pari import pari + if self._sign >= 0: return pari('oo') else: diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index 1feba6e675b..ef3bbe00ba3 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -46,7 +46,7 @@ from sage.structure.unique_representation import UniqueRepresentation try: - from sage.libs.pari.all import pari_gen + from cypari2.gen import Gen as pari_gen except ImportError: pari_gen = () diff --git a/src/sage/rings/number_field/galois_group.py b/src/sage/rings/number_field/galois_group.py index c974c3df6ff..83c9d665d20 100644 --- a/src/sage/rings/number_field/galois_group.py +++ b/src/sage/rings/number_field/galois_group.py @@ -16,7 +16,7 @@ from sage.misc.superseded import deprecation from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute -from sage.libs.pari.all import pari +from sage.libs.pari import pari from sage.rings.infinity import infinity from sage.rings.number_field.number_field import refine_embedding from sage.rings.number_field.morphism import NumberFieldHomomorphism_im_gens diff --git a/src/sage/rings/number_field/maps.py b/src/sage/rings/number_field/maps.py index 8d8eb1b69ef..00422d022f3 100644 --- a/src/sage/rings/number_field/maps.py +++ b/src/sage/rings/number_field/maps.py @@ -45,7 +45,7 @@ import sage.rings.rational_field as rational_field -from sage.libs.pari.all import pari +from sage.libs.pari import pari QQ = rational_field.RationalField() diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index dbd8e7e2edf..37db309bbde 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -211,7 +211,8 @@ def proof_flag(t): from . import number_field_element from . import number_field_element_quadratic from .number_field_ideal import NumberFieldIdeal, NumberFieldFractionalIdeal -from sage.libs.pari.all import pari, pari_gen +from sage.libs.pari import pari +from cypari2.gen import Gen as pari_gen from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index 171fba9af6e..afdcd3267af 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -119,7 +119,7 @@ def __init__(self, field, gens, coerce=True): if len(gens) == 1 and isinstance(gens[0], (list, tuple)): gens = gens[0] - from sage.libs.pari.all import pari_gen + from cypari2.gen import Gen as pari_gen if len(gens) == 1 and isinstance(gens[0], pari_gen): # Init from PARI gens = gens[0] @@ -2641,7 +2641,7 @@ def _pari_bid_(self, flag=1): sage: bid.getattr('clgp') [2, [2]] """ - from sage.libs.pari.all import PariError + from cypari2.handle_error import PariError try: bid = self._bid if flag == 2: diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index 7ea070b113e..3021f3496b1 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -101,7 +101,7 @@ from sage.rings.number_field.order import (RelativeOrder, relative_order_from_ring_generators) from sage.rings.number_field.morphism import RelativeNumberFieldHomomorphism_from_abs -from sage.libs.pari.all import pari_gen +from cypari2.gen import Gen as pari_gen from sage.categories.homset import Hom from sage.categories.sets_cat import Sets @@ -1665,7 +1665,7 @@ def _pari_relative_structure(self): elif f.poldegree() == 1: # PARI's rnfpolredbest() does not always return a # polynomial with integral coefficients in this case. - from sage.libs.pari.all import pari + from sage.libs.pari import pari g = f.variable() alpha = -f[0]/f[1] beta = pari(0).Mod(f) diff --git a/src/sage/rings/number_field/order.py b/src/sage/rings/number_field/order.py index fd5662048df..fe33c456ead 100644 --- a/src/sage/rings/number_field/order.py +++ b/src/sage/rings/number_field/order.py @@ -91,7 +91,7 @@ from sage.rings.monomials import monomials -from sage.libs.pari.all import pari +from sage.libs.pari import pari def quadratic_order_class_number(disc): diff --git a/src/sage/rings/number_field/small_primes_of_degree_one.py b/src/sage/rings/number_field/small_primes_of_degree_one.py index ff30a006bba..541130e8a71 100644 --- a/src/sage/rings/number_field/small_primes_of_degree_one.py +++ b/src/sage/rings/number_field/small_primes_of_degree_one.py @@ -134,7 +134,7 @@ def __init__(self, field, num_integer_primes=10000, max_iterations=100): self._lc = self._poly.leading_coefficient() # this uses that [ O_K : Z[a] ]^2 = | disc(f(x)) / disc(O_K) | - from sage.libs.pari.all import pari + from sage.libs.pari import pari self._prod_of_small_primes = ZZ(pari('TEMPn = %s; TEMPps = primes(TEMPn); prod(X = 1, TEMPn, TEMPps[X])' % num_integer_primes)) self._prod_of_small_primes //= self._prod_of_small_primes.gcd(self._poly.discriminant() * self._lc) diff --git a/src/sage/rings/number_field/splitting_field.py b/src/sage/rings/number_field/splitting_field.py index 28c5486f171..aa8e5cb1ed4 100644 --- a/src/sage/rings/number_field/splitting_field.py +++ b/src/sage/rings/number_field/splitting_field.py @@ -22,7 +22,8 @@ from sage.rings.number_field.number_field import NumberField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import RationalField -from sage.libs.pari.all import pari, PariError +from sage.libs.pari import pari +from cypari2.handle_error import PariError class SplittingFieldAbort(Exception): diff --git a/src/sage/rings/number_field/totallyreal.pyx b/src/sage/rings/number_field/totallyreal.pyx index 14e55237dd1..928f65f1e1c 100644 --- a/src/sage/rings/number_field/totallyreal.pyx +++ b/src/sage/rings/number_field/totallyreal.pyx @@ -89,7 +89,7 @@ import math import sys from sage.libs.gmp.mpz cimport * -from sage.libs.pari.all import pari +from sage.libs.pari import pari from cypari2.gen cimport Gen as pari_gen from sage.libs.pari.misc cimport new_t_POL_from_int_star diff --git a/src/sage/rings/number_field/totallyreal_rel.py b/src/sage/rings/number_field/totallyreal_rel.py index ac3f52a544c..e7b2829e7a4 100644 --- a/src/sage/rings/number_field/totallyreal_rel.py +++ b/src/sage/rings/number_field/totallyreal_rel.py @@ -100,7 +100,7 @@ from sage.rings.number_field.number_field import NumberField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.number_field.totallyreal import weed_fields, odlyzko_bound_totallyreal, enumerate_totallyreal_fields_prim -from sage.libs.pari.all import pari +from sage.libs.pari import pari from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ diff --git a/src/sage/rings/number_field/unit_group.py b/src/sage/rings/number_field/unit_group.py index eb6b46ed82e..d6ee8be1e94 100644 --- a/src/sage/rings/number_field/unit_group.py +++ b/src/sage/rings/number_field/unit_group.py @@ -167,7 +167,7 @@ from sage.groups.abelian_gps.values import AbelianGroupWithValues_class from sage.structure.proof.proof import get_flag -from sage.libs.pari.all import pari +from sage.libs.pari import pari from sage.misc.misc_c import prod from sage.rings.integer_ring import ZZ diff --git a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx index 0e826c40db8..3373413adda 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx @@ -183,7 +183,7 @@ from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ from sage.libs.ntl.ntl_ZZ_p cimport ntl_ZZ_p from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class from sage.rings.padics.padic_generic_element cimport pAdicGenericElement -from sage.libs.pari.all import pari_gen +from cypari2.gen cimport Gen as pari_gen from sage.interfaces.abc import GpElement from sage.rings.finite_rings.integer_mod import IntegerMod_abstract from sage.rings.finite_rings.integer_mod_ring import IntegerModRing diff --git a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx index 5db54020fb2..e8c8e870e0c 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx @@ -201,7 +201,7 @@ from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ from sage.libs.ntl.ntl_ZZ_p cimport ntl_ZZ_p from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class from sage.rings.padics.padic_generic_element cimport pAdicGenericElement -from sage.libs.pari.all import pari_gen +from cypari2.gen cimport Gen as pari_gen from sage.interfaces.abc import GpElement from sage.rings.finite_rings.integer_mod import IntegerMod_abstract from sage.rings.padics.padic_ext_element cimport pAdicExtElement diff --git a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx index de3df469423..9ed7b653450 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx @@ -143,7 +143,7 @@ from sage.libs.ntl.ntl_ZZ cimport ntl_ZZ from sage.libs.ntl.ntl_ZZ_p cimport ntl_ZZ_p from sage.libs.ntl.ntl_ZZ_pContext cimport ntl_ZZ_pContext_class from sage.rings.rational cimport Rational -from sage.libs.pari.all import pari_gen +from cypari2.gen cimport Gen as pari_gen from sage.interfaces.abc import GpElement from sage.rings.finite_rings.integer_mod import IntegerMod_abstract from sage.rings.finite_rings.integer_mod_ring import IntegerModRing diff --git a/src/sage/rings/padics/padic_floating_point_element.pyx b/src/sage/rings/padics/padic_floating_point_element.pyx index ceae683a62c..e7c0976c6f9 100644 --- a/src/sage/rings/padics/padic_floating_point_element.pyx +++ b/src/sage/rings/padics/padic_floating_point_element.pyx @@ -21,7 +21,7 @@ AUTHORS: include "sage/libs/linkages/padics/mpz.pxi" include "FP_template.pxi" -from sage.libs.pari.all import pari +from sage.libs.pari import pari from sage.libs.pari.convert_gmp cimport new_gen_from_padic from sage.rings.finite_rings.integer_mod import Mod diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 81b164a03f9..4fd31a65d90 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -3514,7 +3514,7 @@ cdef class pAdicGenericElement(LocalGenericElement): ans = None if algorithm == "pari": - from sage.libs.pari.all import PariError + from cypari2.handle_error import PariError try: # use pari ans = parent(self.__pari__().sqrt()) diff --git a/src/sage/rings/polynomial/cyclotomic.pyx b/src/sage/rings/polynomial/cyclotomic.pyx index e9eb5675b90..f9e09ce4fd3 100644 --- a/src/sage/rings/polynomial/cyclotomic.pyx +++ b/src/sage/rings/polynomial/cyclotomic.pyx @@ -36,7 +36,7 @@ from sage.rings.integer_ring import ZZ from sage.structure.element cimport parent try: - from sage.libs.pari.all import pari + from sage.libs.pari import pari except ImportError: pass diff --git a/src/sage/rings/polynomial/multi_polynomial_ring.py b/src/sage/rings/polynomial/multi_polynomial_ring.py index 26c32fe036c..ddf3d3f614a 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring.py +++ b/src/sage/rings/polynomial/multi_polynomial_ring.py @@ -69,7 +69,7 @@ import sage.interfaces.abc try: - from sage.libs.pari.all import pari_gen + from cypari2.gen import Gen as pari_gen except ImportError: pari_gen = () diff --git a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py index 668f66fe574..51239d3d9db 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py @@ -21,7 +21,8 @@ from sage.rings.fraction_field_element import FractionFieldElement import copy -from sage.libs.pari.all import pari, pari_gen +from sage.libs.pari import pari +from cypari2.gen import Gen as pari_gen from sage.misc.lazy_import import lazy_import from sage.rings.infinity import infinity diff --git a/src/sage/rings/polynomial/padics/polynomial_padic_flat.py b/src/sage/rings/polynomial/padics/polynomial_padic_flat.py index 4db824cd0cc..d26f7e10e71 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic_flat.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic_flat.py @@ -11,7 +11,7 @@ from sage.rings.polynomial.polynomial_element import Polynomial_generic_dense, Polynomial from sage.rings.polynomial.padics.polynomial_padic import Polynomial_padic from sage.rings.infinity import infinity -from sage.libs.pari.all import pari_gen +from cypari2.gen import Gen as pari_gen import sage.rings.padics.misc diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 05de5dfe104..b0149fdb7c0 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -81,7 +81,9 @@ from sage.structure.richcmp cimport (richcmp, richcmp_item, rich_to_bool, rich_to_bool_sgn) try: - from sage.libs.pari.all import pari, pari_gen, PariError + from sage.libs.pari import pari + from cypari2.handle_error import PariError + from cypari2.gen cimport Gen as pari_gen except ImportError: pari_gen = () pari = None diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index db8139bddad..677c542ed20 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -35,7 +35,7 @@ from sage.rings.polynomial.polynomial_singular_interface import Polynomial_singular_repr try: - from sage.libs.pari.all import pari_gen + from cypari2.gen import Gen as pari_gen except ImportError: pari_gen = () diff --git a/src/sage/rings/polynomial/polynomial_gf2x.pyx b/src/sage/rings/polynomial/polynomial_gf2x.pyx index cf4a224dda9..7a5eeb7ffae 100644 --- a/src/sage/rings/polynomial/polynomial_gf2x.pyx +++ b/src/sage/rings/polynomial/polynomial_gf2x.pyx @@ -26,7 +26,7 @@ include "sage/libs/ntl/ntl_GF2X_linkage.pxi" # and then the interface include "polynomial_template.pxi" -from sage.libs.pari.all import pari +from sage.libs.pari import pari from sage.libs.m4ri cimport mzd_write_bit, mzd_read_bit from sage.matrix.matrix_mod2_dense cimport Matrix_mod2_dense diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx index fc2ab9b584e..8070c07b9d1 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx @@ -55,7 +55,8 @@ from sage.libs.ntl.ntl_ZZX cimport ntl_ZZX from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.libs.pari.all import pari, pari_gen +from sage.libs.pari import pari +from cypari2.gen cimport Gen as pari_gen from sage.structure.factorization import Factorization from sage.rings.fraction_field_element import FractionFieldElement diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx index 142c7b324ad..696357327e1 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx @@ -58,7 +58,8 @@ from sage.rings.integer cimport Integer from sage.rings.real_mpfr cimport RealNumber from sage.rings.real_mpfi cimport RealIntervalFieldElement -from sage.libs.pari.all import pari, pari_gen +from sage.libs.pari import pari +from cypari2.gen cimport Gen as pari_gen from sage.structure.factorization import Factorization from sage.structure.element import coerce_binop diff --git a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx index 68605382f1f..9261fdcc206 100644 --- a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx @@ -36,7 +36,8 @@ from cysignals.signals cimport sig_on, sig_off from sage.rings.polynomial.polynomial_element cimport Polynomial, _dict_to_list -from sage.libs.pari.all import pari, pari_gen +from sage.libs.pari import pari +from cypari2.gen cimport Gen as pari_gen from sage.rings.integer cimport smallInteger diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index cfcdcabdcb5..e2c401ebaca 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -41,7 +41,7 @@ from sage.structure.element import coerce_binop from sage.libs.mpfr cimport * try: - from sage.libs.pari.all import pari_gen + from cypari2.gen cimport Gen as pari_gen except ImportError: pari_gen = () diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 6be288de70f..9e1aef5dea5 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -159,7 +159,7 @@ from sage.rings.number_field.number_field_base import NumberField try: - from sage.libs.pari.all import pari_gen + from cypari2.gen import Gen as pari_gen except ImportError: pari_gen = () @@ -3608,7 +3608,7 @@ def irreducible_element(self, n, algorithm=None): - Jeroen Demeyer (September 2014): add "ffprimroot" algorithm, see :issue:`8373`. """ - from sage.libs.pari.all import pari + from sage.libs.pari import pari from sage.rings.finite_rings.conway_polynomials import (conway_polynomial, exists_conway_polynomial) diff --git a/src/sage/rings/polynomial/polynomial_template.pxi b/src/sage/rings/polynomial/polynomial_template.pxi index b76d62a9e92..c65eefee383 100644 --- a/src/sage/rings/polynomial/polynomial_template.pxi +++ b/src/sage/rings/polynomial/polynomial_template.pxi @@ -20,7 +20,7 @@ from sage.structure.element import coerce_binop from sage.structure.richcmp cimport rich_to_bool from sage.rings.fraction_field_element import FractionFieldElement from sage.rings.integer cimport Integer -from sage.libs.pari.all import pari_gen +from cypari2.gen cimport Gen as pari_gen import operator diff --git a/src/sage/rings/power_series_mpoly.pyx b/src/sage/rings/power_series_mpoly.pyx index 741b0ad94e7..255c9d0ee03 100644 --- a/src/sage/rings/power_series_mpoly.pyx +++ b/src/sage/rings/power_series_mpoly.pyx @@ -8,7 +8,7 @@ from sage.rings import power_series_poly try: - from sage.libs.pari.all import PariError + from cypari2.handle_error import PariError except ImportError: PariError = () diff --git a/src/sage/rings/power_series_pari.pyx b/src/sage/rings/power_series_pari.pyx index 350362cadb7..bd76579346e 100644 --- a/src/sage/rings/power_series_pari.pyx +++ b/src/sage/rings/power_series_pari.pyx @@ -71,7 +71,7 @@ AUTHORS: from cypari2.gen cimport Gen as pari_gen from cypari2.pari_instance cimport get_var from cypari2.paridecl cimport gel, typ, lg, valp, varn, t_POL, t_SER, t_RFRAC, t_VEC -from sage.libs.pari.all import pari +from sage.libs.pari import pari from sage.rings.polynomial.polynomial_element cimport Polynomial from sage.rings.power_series_ring_element cimport PowerSeries diff --git a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx index 16bad60ba56..91e870a8780 100644 --- a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx +++ b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx @@ -1318,7 +1318,7 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, p_list_len += 1 else: # Factor more slowly using Pari via Python. - from sage.libs.pari.all import pari + from sage.libs.pari import pari d = Integer(0) mpz_set(d.value, d_mpz) primes = list(pari(d).factor()[0]) diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index d05196240a1..50f0c609437 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -160,7 +160,8 @@ lazy_import('sage.schemes.generic.morphism', 'SchemeMorphism') try: - from sage.libs.pari.all import pari, PariError + from sage.libs.pari import pari + from cypari2.handle_error import PariError except ImportError: PariError = () diff --git a/src/sage/schemes/elliptic_curves/isogeny_class.py b/src/sage/schemes/elliptic_curves/isogeny_class.py index 13edc68a022..bffdbbdfc01 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_class.py +++ b/src/sage/schemes/elliptic_curves/isogeny_class.py @@ -1207,7 +1207,7 @@ def isogeny_degrees_cm(E, verbose=False): if verbose: print("CM case, discriminant = %s" % d) - from sage.libs.pari.all import pari + from sage.libs.pari import pari from sage.sets.set import Set from sage.arith.misc import kronecker as kronecker_symbol diff --git a/src/sage/structure/factorization.py b/src/sage/structure/factorization.py index ab3fa717031..e1279fec42f 100644 --- a/src/sage/structure/factorization.py +++ b/src/sage/structure/factorization.py @@ -918,7 +918,7 @@ def __pari__(self): sage: pari(g) # needs sage.libs.pari [x - 1, 1; x + 1, 1; x^4 - x^3 + x^2 - x + 1, 1; x^4 + x^3 + x^2 + x + 1, 1] """ - from sage.libs.pari.all import pari + from sage.libs.pari import pari from itertools import chain n = len(self) diff --git a/src/sage/structure/sage_object.pyx b/src/sage/structure/sage_object.pyx index 7102316be70..8605cc2c729 100644 --- a/src/sage/structure/sage_object.pyx +++ b/src/sage/structure/sage_object.pyx @@ -972,7 +972,7 @@ cdef class SageObject: return self.__pari except AttributeError: pass - from sage.libs.pari.all import pari + from sage.libs.pari import pari x = pari(self._pari_init_()) if self._interface_is_cached_(): try: diff --git a/src/sage/symbolic/pynac_impl.pxi b/src/sage/symbolic/pynac_impl.pxi index fcd084cea81..6b2d45499df 100644 --- a/src/sage/symbolic/pynac_impl.pxi +++ b/src/sage/symbolic/pynac_impl.pxi @@ -43,7 +43,7 @@ from sage.libs.gmp.all cimport * from sage.libs.gsl.complex cimport * from sage.libs.gsl.gamma cimport gsl_sf_lngamma_complex_e from sage.libs.mpmath import utils as mpmath_utils -from sage.libs.pari.all import pari +from sage.libs.pari import pari from sage.misc.persist import loads, dumps from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer, smallInteger From e8463079e84ec807fd6231b0b0d15197837563c7 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 4 Jan 2025 20:10:55 +0800 Subject: [PATCH 058/187] More replacements of `pari.all` --- src/sage/combinat/combinat.py | 2 +- src/sage/combinat/partition.py | 2 +- src/sage/combinat/partition_tuple.py | 2 +- src/sage/modular/btquotients/btquotient.py | 2 +- src/sage/modular/multiple_zeta.py | 2 +- src/sage/modular/ssmod/ssmod.py | 2 +- src/sage/rings/complex_mpc.pyx | 2 +- src/sage/rings/complex_mpfr.pyx | 11 ++++++----- src/sage/rings/pari_ring.py | 8 ++++---- src/sage/rings/polynomial/polynomial_element.pyx | 2 +- .../rings/polynomial/polynomial_rational_flint.pyx | 2 +- .../rings/polynomial/polynomial_real_mpfr_dense.pyx | 2 +- src/sage/rings/power_series_poly.pyx | 3 ++- .../schemes/elliptic_curves/ell_rational_field.py | 2 +- src/sage/schemes/elliptic_curves/gal_reps.py | 2 +- src/sage/schemes/elliptic_curves/period_lattice.py | 2 +- .../hyperelliptic_finite_field.py | 2 +- src/sage/schemes/projective/proj_bdd_height.py | 2 +- 18 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 03c1797abfb..e0217176636 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -184,7 +184,7 @@ from sage.structure.element import Element lazy_import('sage.interfaces.maxima_lib', 'maxima') -lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.libs.pari', 'pari') lazy_import('sage.misc.prandom', 'randint') diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 6b6a7edfa4c..ddd9db89bcc 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -317,7 +317,7 @@ lazy_import('sage.combinat.skew_partition', 'SkewPartition') lazy_import('sage.combinat.partition_tuple', 'PartitionTuple') lazy_import('sage.combinat.root_system.weyl_group', 'WeylGroup') -lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.libs.pari', 'pari') lazy_import('sage.groups.perm_gps.permgroup', 'PermutationGroup') lazy_import("sage.symbolic.ring", "var") diff --git a/src/sage/combinat/partition_tuple.py b/src/sage/combinat/partition_tuple.py index 527df5a2728..1e72c26ca29 100644 --- a/src/sage/combinat/partition_tuple.py +++ b/src/sage/combinat/partition_tuple.py @@ -275,7 +275,7 @@ class of modules for the algebras, which are generalisations of the Specht from sage.structure.unique_representation import UniqueRepresentation lazy_import('sage.groups.perm_gps.permgroup', 'PermutationGroup') -lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.libs.pari', 'pari') # ------------------------------------------------- # Partition tuple - element class diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index 280acec8874..19d4bde3e36 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -66,7 +66,7 @@ lazy_import('sage.algebras.quatalg.quaternion_algebra', 'QuaternionAlgebra') lazy_import('sage.graphs.graph', 'Graph') -lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.libs.pari', 'pari') lazy_import('sage.plot.colors', 'rainbow') lazy_import('sage.rings.number_field.number_field', 'NumberField') lazy_import('sage.rings.padics.factory', ['Qp', 'Zp']) diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 8bcbb1101de..77597d2ec17 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -195,7 +195,7 @@ from sage.rings.rational_field import QQ from sage.sets.positive_integers import PositiveIntegers -lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.libs.pari', 'pari') # multiplicative generators for weight <= 17 diff --git a/src/sage/modular/ssmod/ssmod.py b/src/sage/modular/ssmod/ssmod.py index 9913e554a02..ce475e0f10f 100644 --- a/src/sage/modular/ssmod/ssmod.py +++ b/src/sage/modular/ssmod/ssmod.py @@ -79,7 +79,7 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.richcmp import richcmp_method, richcmp -lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.libs.pari', 'pari') ZZy = PolynomialRing(ZZ, 'y') diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index 28d521ec604..8bd4e04f948 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -76,7 +76,7 @@ from sage.categories.map cimport Map try: from sage.libs.pari import pari from cypari2.handle_error import PariError - from cypari2.gen cimport Gen as pari_gen + from cypari2.gen import Gen as pari_gen except ImportError: pari_gen = PariError = () diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index d3dee1b278e..720ec37b969 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -56,9 +56,10 @@ cimport gmpy2 gmpy2.import_gmpy2() try: - from cypari2.gen cimport Gen as pari_gen + from cypari2.gen import Gen as pari_gen + from cypari2.handle_error import PariError except ImportError: - pari_gen = () + pari_gen = PariError = () # Some objects that are not imported at startup in order to break # circular imports @@ -1434,7 +1435,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): """ if self.is_real(): return self.real().__pari__() - return sage.libs.pari.all.pari.complex(self.real() or 0, self.imag()) + return sage.libs.pari.pari.complex(self.real() or 0, self.imag()) def __mpc__(self): """ @@ -2401,7 +2402,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): """ try: return self._parent(self.__pari__().eta(not omit_frac)) - except sage.libs.pari.all.PariError: + except PariError: raise ValueError("value must be in the upper half plane") def sin(self): @@ -2878,7 +2879,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): """ try: return self._parent(self.__pari__().gamma()) - except sage.libs.pari.all.PariError: + except PariError: from sage.rings.infinity import UnsignedInfinityRing return UnsignedInfinityRing.gen() diff --git a/src/sage/rings/pari_ring.py b/src/sage/rings/pari_ring.py index b8f2b62d5a7..b27e22e06e6 100644 --- a/src/sage/rings/pari_ring.py +++ b/src/sage/rings/pari_ring.py @@ -16,12 +16,12 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -import sage.libs.pari.all as pari from sage.categories.rings import Rings -from sage.structure.parent import Parent +from sage.libs.pari import pari +from sage.misc.fast_methods import Singleton from sage.structure.element import RingElement +from sage.structure.parent import Parent from sage.structure.richcmp import richcmp -from sage.misc.fast_methods import Singleton class Pari(RingElement): @@ -44,7 +44,7 @@ def __init__(self, x, parent=None) -> None: if parent is None: parent = _inst RingElement.__init__(self, parent) - self.__x = pari.pari(x) + self.__x = pari(x) def __repr__(self) -> str: """ diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index b0149fdb7c0..cb99e202f7c 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -83,7 +83,7 @@ from sage.structure.richcmp cimport (richcmp, richcmp_item, try: from sage.libs.pari import pari from cypari2.handle_error import PariError - from cypari2.gen cimport Gen as pari_gen + from cypari2.gen import Gen as pari_gen except ImportError: pari_gen = () pari = None diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pyx b/src/sage/rings/polynomial/polynomial_rational_flint.pyx index c11592cf2d6..98bfbbd3ffa 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pyx @@ -38,7 +38,7 @@ from sage.libs.flint.fmpq_poly_sage cimport * from sage.libs.gmp.mpz cimport * from sage.libs.gmp.mpq cimport * -from cypari2.gen import Gen as pari_gen +from cypari2.gen cimport Gen as pari_gen from sage.rings.complex_arb cimport ComplexBall from sage.rings.integer cimport Integer, smallInteger diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index e2c401ebaca..44faac21762 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -41,7 +41,7 @@ from sage.structure.element import coerce_binop from sage.libs.mpfr cimport * try: - from cypari2.gen cimport Gen as pari_gen + from cypari2.gen import Gen as pari_gen except ImportError: pari_gen = () diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index c284b06a5e4..9acde829d4a 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -8,7 +8,8 @@ from sage.structure.element cimport Element from sage.rings.infinity import infinity try: - from sage.libs.pari.all import pari_gen, PariError + from cypari2.handle_error import PariError + from cypari2.gen import Gen as pari_gen except ImportError: pari_gen = () PariError = () diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 134531ad1a5..96a9cca752a 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -80,7 +80,7 @@ from sage.structure.element import Element, RingElement lazy_import("sage.functions.log", "log") -lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.libs.pari', 'pari') lazy_import("sage.functions.gamma", "gamma_inc") lazy_import('sage.interfaces.gp', 'gp') diff --git a/src/sage/schemes/elliptic_curves/gal_reps.py b/src/sage/schemes/elliptic_curves/gal_reps.py index 8f0e0ed9a60..428bf4bebf6 100644 --- a/src/sage/schemes/elliptic_curves/gal_reps.py +++ b/src/sage/schemes/elliptic_curves/gal_reps.py @@ -125,7 +125,7 @@ from sage.rings.real_mpfr import RealField from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.libs.pari', 'pari') def _ex_set(p): diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 54cd135dea9..a4a44405671 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -120,7 +120,7 @@ from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.structure.richcmp import richcmp_method, richcmp, richcmp_not_equal -lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.libs.pari', 'pari') lazy_import('sage.rings.number_field.number_field', 'refine_embedding') diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py index 469e3eaa2f8..d2981b4fbd8 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py @@ -61,7 +61,7 @@ from sage.misc.functional import rank from sage.misc.lazy_import import lazy_import -lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.libs.pari', 'pari') lazy_import('sage.schemes.hyperelliptic_curves.hypellfrob', 'hypellfrob') from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_finite_field diff --git a/src/sage/schemes/projective/proj_bdd_height.py b/src/sage/schemes/projective/proj_bdd_height.py index 232f51188b4..b8fbb265b8d 100644 --- a/src/sage/schemes/projective/proj_bdd_height.py +++ b/src/sage/schemes/projective/proj_bdd_height.py @@ -28,7 +28,7 @@ from sage.schemes.projective.projective_space import ProjectiveSpace lazy_import('sage.geometry.polyhedron.constructor', 'Polyhedron') -lazy_import('sage.libs.pari.all', 'pari') +lazy_import('sage.libs.pari', 'pari') lazy_import('sage.matrix.constructor', ['matrix', 'column_matrix']) lazy_import('sage.modules.free_module_element', 'vector') lazy_import('sage.rings.number_field.unit_group', 'UnitGroup') From 36ae1d995ef3ff66bd28b1b678b362cf56edac2a Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sat, 4 Jan 2025 20:38:34 +0700 Subject: [PATCH 059/187] Use __ to avoid overwrite shell magic variables --- src/sage/structure/coerce.pyx | 2 +- src/sage/symbolic/function.pyx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index f481536f8aa..35c76cebc67 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -521,7 +521,7 @@ cdef class CoercionModel: sage: import numpy # needs numpy sage: if int(numpy.version.short_version[0]) > 1: # needs numpy - ....: _ = numpy.set_printoptions(legacy="1.25") # needs numpy + ....: __ = numpy.set_printoptions(legacy="1.25") # needs numpy sage: # needs sage.rings.real_mpfr sage: x = polygen(RR) diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 6b087c78609..132bed222a9 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -962,7 +962,7 @@ cdef class BuiltinFunction(Function): sage: import numpy # needs numpy sage: if int(numpy.version.short_version[0]) > 1: # needs numpy - ....: _ = numpy.set_printoptions(legacy="1.25") # needs numpy + ....: __ = numpy.set_printoptions(legacy="1.25") # needs numpy sage: sin(numpy.int32(0)) # needs numpy 0.0 From e4ceffe1d63440668fdbd4801dd472567751313e Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 4 Jan 2025 19:12:29 +0530 Subject: [PATCH 060/187] updated is_brick() --- src/sage/graphs/matching_covered_graph.py | 160 +++++++++++++++++++--- 1 file changed, 138 insertions(+), 22 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 103e9975084..b4849ef4e23 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2750,13 +2750,38 @@ def is_brick(self, coNP_certificate=False): - If the input nonbipartite matching covered graph is a brick, a boolean ``True`` is returned if ``coNP_certificate`` is set to - ``False`` otherwise a tuple ``(True, None, None)`` is returned. + ``False`` otherwise a 4-tuple ``(True, None, None, None)`` is + returned. - If the input nonbipartite matching covered graph is not a brick, a boolean ``False`` is returned if ``coNP_certificate`` is set to - ``False`` otherwise a tuple of boolean ``False``, a list of - edges constituting a nontrivial tight cut and a set of vertices of - one of the shores of the nontrivial tight cut is returned. + ``False``. + + - If ``coNP_certificate`` is set to ``True`` and the input nonbipartite + graph is not a brick, a 4-tuple of + + 1. a boolean ``False``, + + 2. a list of list of edges each list constituting a nontrivial tight + cut collectively representing a laminar tight cut, + + 3. a list of set of vertices of one of the shores of those respective + nontrivial tight cuts. + + i. In case of nontrivial barrier cuts, each of the shores is a + nontrivial odd component wrt a nontrivial barrier, thus the + returned list forms mutually exclusive collection of (odd) + sets. + + ii. Otherwise each of the nontrivial tight cuts is a 2-separation + cut, each of the shores form a subset sequence, with the `i`th + shore being a proper subset of the `i + 1`th shore. + + 4. a string showing whether the nontrivial tight cuts are barrier + cuts (if the string is 'nontrivial barrier cuts'), or 2-separation + cuts (if the string is 'nontrivial 2-separation cuts') + + is returned. EXAMPLES: @@ -2856,12 +2881,84 @@ def is_brick(self, coNP_certificate=False): sage: K4 = graphs.CompleteGraph(4) sage: G = MatchingCoveredGraph(K4) sage: G.is_brick(coNP_certificate=True) - (True, None, None) + (True, None, None, None) sage: # K(4) ⊙ K(3, 3) is nonbipartite but not a brick sage: H = graphs.MurtyGraph(); H.delete_edge(0, 1) sage: G = MatchingCoveredGraph(H) sage: G.is_brick(coNP_certificate=True) - (False, [(5, 2, None), (6, 3, None), (7, 4, None)], {5, 6, 7}) + (False, [[(5, 2, None), (6, 3, None), (7, 4, None)]], [{5, 6, 7}], + 'nontrivial barrier cuts') + sage: H = Graph([ + ....: (0, 12), (0, 13), (0, 15), (1, 4), (1, 13), (1, 14), + ....: (1, 19), (2, 4), (2, 13), (2, 14), (2, 17), (3, 9), + ....: (3, 13), (3, 16), (3, 21), (4, 6), (4, 7), (5, 7), + ....: (5, 8), (5, 12), (6, 8), (6, 11), (7, 10), (8, 9), + ....: (9, 10), (10, 11), (11, 12), (14, 15), (14, 16), (15, 16), + ....: (17, 18), (17, 21), (18, 19), (18, 20), (19, 20), (20, 21) + ....: ]) + sage: G = MatchingCoveredGraph(H) + sage: G.is_brick(coNP_certificate=True) + (False, + [[(12, 0, None), (4, 1, None), (4, 2, None), (9, 3, None)], + [(19, 1, None), (17, 2, None), (21, 3, None)], + [(15, 0, None), (14, 1, None), (14, 2, None), (16, 3, None)]], + [{4, 5, 6, 7, 8, 9, 10, 11, 12}, {17, 18, 19, 20, 21}, {14, 15, 16}], + 'nontrivial barrier cuts') + sage: J = Graph([ + ....: (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), + ....: (0, 6), (0, 7), (0, 8), (0, 9), (0, 10), + ....: (1, 2), (1, 11), (2, 11), (3, 4), (3, 11), + ....: (4, 11), (5, 6), (5, 11), (6, 11), (7, 8), + ....: (7, 11), (8, 11), (9, 10), (9, 11), (10, 11) + ....: ]) + sage: G = MatchingCoveredGraph(J) + sage: G.is_brick(coNP_certificate=True) + (False, + [[(0, 3, None), + (0, 4, None), + (0, 5, None), + (0, 6, None), + (0, 7, None), + (0, 8, None), + (0, 9, None), + (0, 10, None), + (1, 11, None), + (2, 11, None)], + [(0, 5, None), + (0, 6, None), + (0, 7, None), + (0, 8, None), + (0, 9, None), + (0, 10, None), + (1, 11, None), + (2, 11, None), + (3, 11, None), + (4, 11, None)], + [(0, 7, None), + (0, 8, None), + (0, 9, None), + (0, 10, None), + (1, 11, None), + (2, 11, None), + (3, 11, None), + (4, 11, None), + (5, 11, None), + (6, 11, None)], + [(0, 9, None), + (0, 10, None), + (1, 11, None), + (2, 11, None), + (3, 11, None), + (4, 11, None), + (5, 11, None), + (6, 11, None), + (7, 11, None), + (8, 11, None)]], + [{0, 1, 2}, + {0, 1, 2, 3, 4}, + {0, 1, 2, 3, 4, 5, 6}, + {0, 1, 2, 3, 4, 5, 6, 7, 8}], + 'nontrivial 2-separation cuts') If the input matching covered graph is bipartite, a :exc:`ValueError` is thrown:: @@ -2908,21 +3005,22 @@ def is_brick(self, coNP_certificate=False): # Let K be a nontrivial odd component of H := G - B. Note that # there exists at least one such K since G is nonbipartite - nontrivial_odd_component = next( - (component for component in H.connected_components(sort=True) - if len(component) % 2 and len(component) > 1), None - ) + nontrivial_odd_components = [ + set(component) for component in H.connected_components(sort=True) + if len(component) % 2 and len(component) > 1 + ] - # Find a nontrivial barrier cut - C = [(u, v, w) if u in nontrivial_odd_component else (v, u, w) - for u, v, w in self.edge_iterator() - if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] + # Find a laminar set of nontrivial barrier cuts + C = [[(u, v, w) if u in nontrivial_odd_component else (v, u, w) + for u, v, w in self.edge_iterator() + if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] + for nontrivial_odd_component in nontrivial_odd_components] - return (False, C, set(nontrivial_odd_component)) + return (False, C, nontrivial_odd_components, 'nontrivial barrier cuts') # Check if G is 3-connected if self.is_triconnected(): - return (True, None, None) if coNP_certificate else True + return (True, None, None, None) if coNP_certificate else True # G has a 2-vertex cut # Compute the SPQR-tree decomposition @@ -2934,6 +3032,7 @@ def is_brick(self, coNP_certificate=False): if u[0] == 'P': two_vertex_cut.extend(u[1]) break + elif u[0] == 'S' and u[1].order() > 3: s_vertex_set = set(u[1]) s_vertex_set -= {next(u[1].vertex_iterator())} | set(u[1].neighbors(next(u[1].vertex_iterator()))) @@ -2943,6 +3042,7 @@ def is_brick(self, coNP_certificate=False): if not two_vertex_cut: from collections import Counter R_frequency = Counter() + for t, g in spqr_tree: if t == 'R': R_frequency.update(g) @@ -2956,17 +3056,33 @@ def is_brick(self, coNP_certificate=False): components = H.connected_components(sort=True) # Find a nontrivial odd component + nontrivial_tight_cut_variation = None + if all(len(c) % 2 for c in components): - nontrivial_odd_component = next(c for c in components if len(c) > 1) + nontrivial_tight_cut_variation = 'nontrivial barrier cuts' + nontrivial_odd_components = [set(component) for component in components if len(component) > 1] + else: - nontrivial_odd_component = components[0] + [two_vertex_cut[0]] + nontrivial_tight_cut_variation = 'nontrivial 2-separation cuts' + nontrivial_odd_components = [] + + for index, component in enumerate(components): + if index == len(components) - 1: + continue + elif not index: + nontrivial_odd_components.append(set(components[0] + [two_vertex_cut[0]])) + else: + nontrivial_odd_component = nontrivial_odd_components[-1].copy() + nontrivial_odd_component.update(component) + nontrivial_odd_components.append(nontrivial_odd_component) - C = [(u, v, w) if u in nontrivial_odd_component else (v, u, w) - for u, v, w in self.edge_iterator() - if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] + C = [[(u, v, w) if u in nontrivial_odd_component else (v, u, w) + for u, v, w in self.edge_iterator() + if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] + for nontrivial_odd_component in nontrivial_odd_components] # Edge (u, v, w) in C are formatted so that u is in a nontrivial odd component - return (False, C, set(nontrivial_odd_component)) if coNP_certificate else False + return (False, C, nontrivial_odd_components, nontrivial_tight_cut_variation) if coNP_certificate else False @doc_index('Overwritten methods') def loop_edges(self, labels=True): From 5133db5da3bad28b5d4b0a4153a4a443c8004862 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 4 Jan 2025 19:53:13 +0530 Subject: [PATCH 061/187] added tight_cut_decomposition() to todo list --- src/sage/graphs/matching_covered_graph.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index b4849ef4e23..6b81cc2b9dd 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -97,6 +97,7 @@ ``number_of_braces()`` | Return the number of braces. ``number_of_bricks()`` | Return the number of bricks. ``number_of_petersen_bricks()`` | Return the number of Petersen bricks. + ``tight_cut_decomposition()`` | Return a maximal set of laminar nontrivial tight cuts and a corresponding vertex set partition. **Removability and ear decomposition** @@ -2983,7 +2984,6 @@ def is_brick(self, coNP_certificate=False): - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.bricks_and_braces` - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_bricks` - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_petersen_bricks` - - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.tight_cut_decomposition` """ if self.is_bipartite(): raise ValueError('the input graph is bipartite') @@ -3401,14 +3401,6 @@ def remove_loops(self, vertices=None): return - @doc_index('Bricks, braces and tight cut decomposition') - def tight_cut_decomposition(self): - r""" - Return a maximal set of laminar nontrivial tight cuts and a - corresponding vertex set partition. - """ - raise NotImplementedError() - @doc_index('Miscellaneous methods') def update_matching(self, matching): r""" From f2a5abe0fedc286fae9394a5a4582d3f55775ce9 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 4 Jan 2025 20:27:38 +0530 Subject: [PATCH 062/187] added a missing whitespace --- src/sage/graphs/matching_covered_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 6b81cc2b9dd..deefe46eeee 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2658,7 +2658,7 @@ def is_brace(self, coNP_certificate=False): H = Graph(self, multiedges=False) H.delete_vertices([u, v]) - if not H.is_connected()or not H.is_matching_covered(list(matching - set([e]))): + if not H.is_connected() or not H.is_matching_covered(list(matching - set([e]))): if not coNP_certificate: return False From f32ef0f083b8fcc5f0d816a8209ce94a7e3a1b3a Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 4 Jan 2025 20:38:19 +0530 Subject: [PATCH 063/187] fixed RST215 error --- src/sage/graphs/matching_covered_graph.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index deefe46eeee..c4545d964ad 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2769,14 +2769,14 @@ def is_brick(self, coNP_certificate=False): 3. a list of set of vertices of one of the shores of those respective nontrivial tight cuts. - i. In case of nontrivial barrier cuts, each of the shores is a - nontrivial odd component wrt a nontrivial barrier, thus the - returned list forms mutually exclusive collection of (odd) - sets. - - ii. Otherwise each of the nontrivial tight cuts is a 2-separation - cut, each of the shores form a subset sequence, with the `i`th - shore being a proper subset of the `i + 1`th shore. + - In case of nontrivial barrier cuts, each of the shores is a + nontrivial odd component wrt a nontrivial barrier, thus the + returned list forms mutually exclusive collection of (odd) + sets. + + - Otherwise each of the nontrivial tight cuts is a 2-separation + cut, each of the shores form a subset sequence, with the `i`th + shore being a proper subset of the `i + 1`th shore. 4. a string showing whether the nontrivial tight cuts are barrier cuts (if the string is 'nontrivial barrier cuts'), or 2-separation From f8c24e05a64a303baff8da1bc742d7d6a013f240 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 4 Jan 2025 18:05:30 +0100 Subject: [PATCH 064/187] add parameter immutable to method complement --- src/sage/graphs/generic_graph.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 101952109c3..bbeb1397ccf 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -19379,7 +19379,7 @@ def add_path(self, vertices): self.add_vertices(vertices) self.add_edges(zip(vertices[:-1], vertices[1:])) - def complement(self): + def complement(self, immutable=None): """ Return the complement of the (di)graph. @@ -19387,6 +19387,12 @@ def complement(self): that are not in the original graph. This is not well defined for graphs with multiple edges. + INPUT: + + - ``immutable`` -- boolean (default: ``None``); whether to return a + mutable or an immutable version of ``self``. By default (``None``), + the graph and its complement behave the same. + EXAMPLES:: sage: P = graphs.PetersenGraph() @@ -19436,8 +19442,9 @@ def complement(self): if self.name(): G.name("complement({})".format(self.name())) - - if self.is_immutable(): + if immutable is None: + immutable = self.is_immutable() + if immutable: return G.copy(immutable=True) return G From eb0781f5c0dcb2efb858cc95975aabbc0429ca03 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 4 Jan 2025 18:07:37 +0100 Subject: [PATCH 065/187] add doctests to method complement --- src/sage/graphs/generic_graph.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index bbeb1397ccf..c02e2209d97 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -19434,6 +19434,17 @@ def complement(self, immutable=None): Graph on 10 vertices sage: g.complement() Graph on 10 vertices + + Check the behovior of parameter `ìmmutable``:: + + sage: type(Graph().complement()._backend) + + sage: type(Graph().complement(immutable=True)._backend) + + sage: type(Graph(immutable=True).complement()._backend) + + sage: type(Graph(immutable=True).complement(immutable=False)._backend) + """ self._scream_if_not_simple() From 624b94c90bdaf15e22c87b164955dedbc15b4514 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sun, 5 Jan 2025 00:19:12 +0700 Subject: [PATCH 066/187] Specify use_sources=True in cython compilation --- src/sage/misc/cython.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index adf2d8a10ef..ace2e6b6544 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -58,7 +58,7 @@ def _standard_libs_libdirs_incdirs_aliases(): if SAGE_LOCAL: standard_libdirs.append(os.path.join(SAGE_LOCAL, "lib")) standard_libdirs.extend(aliases["CBLAS_LIBDIR"] + aliases["NTL_LIBDIR"]) - standard_incdirs = sage_include_directories() + aliases["CBLAS_INCDIR"] + aliases["NTL_INCDIR"] + standard_incdirs = sage_include_directories(use_sources=True) + aliases["CBLAS_INCDIR"] + aliases["NTL_INCDIR"] return standard_libs, standard_libdirs, standard_incdirs, aliases ################################################################ From df92cd547cd8d904ecabf1fb0af7a97ffa30f4af Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 4 Jan 2025 18:23:09 +0100 Subject: [PATCH 067/187] fix the behavior of method to_simple --- src/sage/graphs/generic_graph.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index c02e2209d97..e61029ff988 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -19509,12 +19509,31 @@ def to_simple(self, to_undirected=True, keep_label='any', immutable=None): [(2, 3, 1), (3, 2, None)] sage: G.to_simple(to_undirected=False, keep_label='max').edges(sort=True) [(2, 3, 2), (3, 2, None)] + + TESTS: + + Check the behavior of parameter `ìmmutable``:: + + sage: G = Graph([(0, 0), (0, 1)] * 2, loops=True, multiedges=True, immutable=True) + sage: H = G.to_simple() + sage: H.is_immutable() + True + sage: H.edges(labels=False) + [(0, 1)] + sage: H = G.to_simple(immutable=False) + sage: H.is_immutable() + False + sage: G = Graph([(0, 0), (0, 1)] * 2, loops=True, multiedges=True, immutable=False) + sage: G.to_simple().is_immutable() + False + sage: G.to_simple(immutable=True).is_immutable() + True """ if to_undirected: from sage.graphs.graph import Graph - g = Graph(self) + g = Graph(self, immutable=False) else: - g = copy(self) + g = self.copy(immutable=False) g.allow_loops(False) g.allow_multiple_edges(False, keep_label=keep_label) if immutable is None: From 7ae68620c92f86e983d105ef7a8361274eb46667 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 4 Jan 2025 18:30:27 +0100 Subject: [PATCH 068/187] add tests to add_clique, add_cycle, add_path --- src/sage/graphs/generic_graph.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index e61029ff988..c44dab69b67 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -19271,7 +19271,16 @@ def add_clique(self, vertices, loops=False): sage: D.add_clique(range(4), loops=True) sage: D.is_clique(directed_clique=True, loops=True) True + + Immutable graph:: + + sage: Graph(immutable=True).add_clique([1, 2, 3]) + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) """ + if self.is_immutable(): + raise ValueError("graph is immutable; please change a copy instead (use function copy())") import itertools if loops: if self.is_directed(): @@ -19337,6 +19346,13 @@ def add_cycle(self, vertices): sage: G.add_cycle(['a', 'b', 'c']) sage: G.order(), G.size() (3, 3) + + Immutable graph:: + + sage: Graph(immutable=True).add_cycle([1, 2, 3]) + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) """ if vertices: self.add_path(vertices) @@ -19373,6 +19389,16 @@ def add_path(self, vertices): sage: D.add_path(list(range(4))) sage: D.edges(sort=True) [(0, 1, None), (1, 2, None), (2, 3, None)] + + TESTS: + + Immutable graph:: + + sage: Graph(immutable=True).add_path([]) + sage: Graph(immutable=True).add_path([1, 2, 3]) + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) """ if not vertices: return From 597ffad4be4a72a1f8f6d64b6e7afc3e99f52c56 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 4 Jan 2025 18:39:49 +0100 Subject: [PATCH 069/187] improve method union to avoid copy --- src/sage/graphs/generic_graph.py | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index c44dab69b67..ab2cc5b8e51 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -19715,30 +19715,25 @@ def union(self, other, immutable=None): sage: D1.union(D2).weighted() or D2.union(D1).weighted() False """ - if (self._directed and not other._directed) or (not self._directed and other._directed): + if self._directed != other._directed: raise TypeError('both arguments must be of the same class') multiedges = self.allows_multiple_edges() or other.allows_multiple_edges() loops = self.allows_loops() or other.allows_loops() weighted = self.weighted() and other.weighted() + if immutable is None: + immutable = self.is_immutable() and other.is_immutable() if self._directed: - from sage.graphs.digraph import DiGraph - G = DiGraph(multiedges=multiedges, loops=loops, weighted=weighted) + from sage.graphs.digraph import DiGraph as GT else: - from sage.graphs.graph import Graph - G = Graph(multiedges=multiedges, loops=loops, weighted=weighted) - G.add_vertices(self) - G.add_vertices(other) - G.add_edges(self.edge_iterator()) - G.add_edges(other.edge_iterator()) - - if immutable is None: - immutable = self.is_immutable() and other.is_immutable() - if immutable: - G = G.copy(immutable=True) + from sage.graphs.graph import Graph as GT - return G + from itertools import chain + return GT([chain(self, other), + chain(self.edge_iterator(), other.edge_iterator())], + format='vertices_and_edges', weighted=weighted, loops=loops, + multiedges=multiedges, immutable=immutable) def cartesian_product(self, other): r""" From 7e4375005c59a2edb2a2fda63300bb3f9af6ad2b Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 4 Jan 2025 19:10:23 +0100 Subject: [PATCH 070/187] improve method disjoint_union --- src/sage/graphs/generic_graph.py | 45 +++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index ab2cc5b8e51..942b49f0a9c 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -19616,8 +19616,27 @@ def disjoint_union(self, other, labels='pairs', immutable=None): Custom path disjoint_union Cycle graph: Graph on 5 vertices sage: J.vertices(sort=True) [(0, 'a'), (0, 'b'), (1, 0), (1, 1), (1, 2)] + + TESTS: + + Check the behavior of parameter `ìmmutable``:: + + sage: G = Graph([(0, 1)]) + sage: G.disjoint_union(G).is_immutable() + False + sage: G.disjoint_union(G, immutable=True).is_immutable() + True + sage: H = G.copy(immutable=True) + sage: H.disjoint_union(H).is_immutable() + True + sage: G.disjoint_union(G, immutable=False).is_immutable() + False + sage: H.disjoint_union(G).is_immutable() + False + sage: G.disjoint_union(G, immutable=True).is_immutable() + True """ - if (self._directed and not other._directed) or (not self._directed and other._directed): + if self._directed != other._directed: raise TypeError('both arguments must be of the same class') if labels not in ['pairs', 'integers']: @@ -19629,7 +19648,11 @@ def disjoint_union(self, other, labels='pairs', immutable=None): else: r_self = {v: (0, v) for v in self} r_other = {v: (1, v) for v in other} - G = self.relabel(r_self, inplace=False).union(other.relabel(r_other, inplace=False), immutable=immutable) + + from itertools import chain + vertices = chain(r_self.values(), r_other.values()) + edges = chain(((r_self[u], r_self[v], w) for u, v, w in self.edge_iterator()), + ((r_other[u], r_other[v], w) for u, v, w in other.edge_iterator())) a = self.name() if not a: @@ -19637,8 +19660,22 @@ def disjoint_union(self, other, labels='pairs', immutable=None): b = other.name() if not b: b = other._repr_() - G._name = '{} disjoint_union {}'.format(a, b) - return G + name = f"{a} disjoint_union {b}" + + multiedges = self.allows_multiple_edges() or other.allows_multiple_edges() + loops = self.allows_loops() or other.allows_loops() + weighted = self.weighted() and other.weighted() + if immutable is None: + immutable = self.is_immutable() and other.is_immutable() + + if self._directed: + from sage.graphs.digraph import DiGraph as GT + else: + from sage.graphs.graph import Graph as GT + + return GT([vertices, edges], format='vertices_and_edges', + weighted=weighted, loops=loops, multiedges=multiedges, + name=name, immutable=immutable) def union(self, other, immutable=None): """ From 61d9b90113f4eb07027be48c52e9a04c8349acdc Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 4 Jan 2025 19:20:51 +0100 Subject: [PATCH 071/187] #39280: typo --- 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 942b49f0a9c..5f5ba9b69e2 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -19461,7 +19461,7 @@ def complement(self, immutable=None): sage: g.complement() Graph on 10 vertices - Check the behovior of parameter `ìmmutable``:: + Check the behavior of parameter `ìmmutable``:: sage: type(Graph().complement()._backend) From eba365c629631710b256d9d263ae50134c09657d Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 5 Jan 2025 13:16:37 +0100 Subject: [PATCH 072/187] add parameter immutable to some graph products --- src/sage/graphs/generic_graph.py | 301 +++++++++++++++++++++++-------- 1 file changed, 230 insertions(+), 71 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index badd28f4fb8..58efe9cd990 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -19689,7 +19689,7 @@ def union(self, other, immutable=None): return G - def cartesian_product(self, other): + def cartesian_product(self, other, immutable=None): r""" Return the Cartesian product of ``self`` and ``other``. @@ -19698,6 +19698,15 @@ def cartesian_product(self, other): and `((u,v), (w,x))` is an edge iff either - `(u, w)` is an edge of self and `v = x`, or - `(v, x)` is an edge of other and `u = w`. + INPUT: + + - ``other`` -- a graph or a digraph + + - ``immutable`` -- boolean (default: ``None``); whether to create a + mutable/immutable product. ``immutable=None`` (default) means that the + graphs and their product will behave the same way. If only one of them + is immutable, the product will be mutable. + .. SEEALSO:: - :meth:`~sage.graphs.graph_decompositions.graph_products.is_cartesian_product` @@ -19750,27 +19759,48 @@ def cartesian_product(self, other): sage: V = Q.strongly_connected_component_containing_vertex((0, 'aa')) # needs sage.combinat sage: B.is_isomorphic(Q.subgraph(V)) # needs sage.combinat True + + Check the behavior of parameter `ìmmutable``:: + + sage: A = Graph([(0, 1)]) + sage: B = Graph([('a', 'b')], immutable=True) + sage: A.cartesian_product(A).is_immutable() + False + sage: A.cartesian_product(A, immutable=True).is_immutable() + True + sage: A.cartesian_product(B).is_immutable() + False + sage: A.cartesian_product(B, immutable=True).is_immutable() + True + sage: B.cartesian_product(B).is_immutable() + True + sage: B.cartesian_product(B, immutable=False).is_immutable() + False """ self._scream_if_not_simple(allow_loops=True) if self._directed and other._directed: - from sage.graphs.digraph import DiGraph - G = DiGraph(loops=(self.has_loops() or other.has_loops())) + from sage.graphs.digraph import DiGraph as GT elif (not self._directed) and (not other._directed): - from sage.graphs.graph import Graph - G = Graph(loops=(self.has_loops() or other.has_loops())) + from sage.graphs.graph import Graph as GT else: raise TypeError('the graphs should be both directed or both undirected') - G.add_vertices((u, v) for u in self for v in other) - for u, w in self.edge_iterator(labels=None): - for v in other: - G.add_edge((u, v), (w, v)) - for v, x in other.edge_iterator(labels=None): - for u in self: - G.add_edge((u, v), (u, x)) - return G + if immutable is None: + immutable = self.is_immutable() and other.is_immutable() + loops = self.has_loops() or other.has_loops() + vertices = ((u, v) for u in self for v in other) + from itertools import chain + edges = chain((((u, v), (w, v)) + for u, w in self.edge_iterator(labels=False) + for v in other), + (((u, v), (u, x)) + for v, x in other.edge_iterator(labels=False) + for u in self)) - def tensor_product(self, other): + return GT([vertices, edges], format='vertices_and_edges', + loops=loops, immutable=immutable) + + def tensor_product(self, other, immutable=None): r""" Return the tensor product of ``self`` and ``other``. @@ -19783,6 +19813,15 @@ def tensor_product(self, other): Kronecker product (referring to the Kronecker matrix product). See the :wikipedia:`Kronecker_product`. + INPUT: + + - ``other`` -- a graph or a digraph + + - ``immutable`` -- boolean (default: ``None``); whether to create a + mutable/immutable product. ``immutable=None`` (default) means that the + graphs and their product will behave the same way. If only one of them + is immutable, the product will be mutable. + EXAMPLES:: sage: Z = graphs.CompleteGraph(2) @@ -19835,28 +19874,53 @@ def tensor_product(self, other): sage: T = B1.tensor_product(B2) sage: T.is_isomorphic(digraphs.DeBruijn(2 * 3, 3)) True + + Check the behavior of parameter `ìmmutable``:: + + sage: A = Graph([(0, 1)]) + sage: B = Graph([('a', 'b')], immutable=True) + sage: A.tensor_product(A).is_immutable() + False + sage: A.tensor_product(A, immutable=True).is_immutable() + True + sage: A.tensor_product(B).is_immutable() + False + sage: A.tensor_product(B, immutable=True).is_immutable() + True + sage: B.tensor_product(B).is_immutable() + True + sage: B.tensor_product(B, immutable=False).is_immutable() + False """ self._scream_if_not_simple(allow_loops=True) if self._directed and other._directed: - from sage.graphs.digraph import DiGraph - G = DiGraph(loops=(self.has_loops() or other.has_loops())) + from sage.graphs.digraph import DiGraph as GT + edges = (((u, v), (w, x)) + for u, w in self.edge_iterator(labels=False) + for v, x in other.edge_iterator(labels=False)) elif (not self._directed) and (not other._directed): - from sage.graphs.graph import Graph - G = Graph(loops=(self.has_loops() or other.has_loops())) + from sage.graphs.graph import Graph as GT + from itertools import chain + edges = chain((((u, v), (w, x)) + for u, w in self.edge_iterator(labels=False) + for v, x in other.edge_iterator(labels=False)), + (((u, x), (w, v)) + for u, w in self.edge_iterator(labels=False) + for v, x in other.edge_iterator(labels=False))) else: raise TypeError('the graphs should be both directed or both undirected') - G.add_vertices((u, v) for u in self for v in other) - for u, w in self.edge_iterator(labels=None): - for v, x in other.edge_iterator(labels=None): - G.add_edge((u, v), (w, x)) - if not G._directed: - G.add_edge((u, x), (w, v)) - return G + + if immutable is None: + immutable = self.is_immutable() and other.is_immutable() + loops = self.has_loops() or other.has_loops() + vertices = ((u, v) for u in self for v in other) + return GT([vertices, edges], format='vertices_and_edges', + loops=loops, immutable=immutable) categorical_product = tensor_product kronecker_product = tensor_product - def lexicographic_product(self, other): + def lexicographic_product(self, other, immutable=None): r""" Return the lexicographic product of ``self`` and ``other``. @@ -19866,6 +19930,15 @@ def lexicographic_product(self, other): * `(u, w)` is an edge of `G`, or * `u = w` and `(v, x)` is an edge of `H`. + INPUT: + + - ``other`` -- a graph or a digraph + + - ``immutable`` -- boolean (default: ``None``); whether to create a + mutable/immutable product. ``immutable=None`` (default) means that the + graphs and their product will behave the same way. If only one of them + is immutable, the product will be mutable. + EXAMPLES:: sage: Z = graphs.CompleteGraph(2) @@ -19911,27 +19984,48 @@ def lexicographic_product(self, other): ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] sage: T.is_isomorphic(J.lexicographic_product(I)) False + + Check the behavior of parameter `ìmmutable``:: + + sage: A = Graph([(0, 1)]) + sage: B = Graph([('a', 'b')], immutable=True) + sage: A.lexicographic_product(A).is_immutable() + False + sage: A.lexicographic_product(A, immutable=True).is_immutable() + True + sage: A.lexicographic_product(B).is_immutable() + False + sage: A.lexicographic_product(B, immutable=True).is_immutable() + True + sage: B.lexicographic_product(B).is_immutable() + True + sage: B.lexicographic_product(B, immutable=False).is_immutable() + False """ self._scream_if_not_simple(allow_loops=True) if self._directed and other._directed: - from sage.graphs.digraph import DiGraph - G = DiGraph(loops=(self.has_loops() or other.has_loops())) + from sage.graphs.digraph import DiGraph as GT elif (not self._directed) and (not other._directed): - from sage.graphs.graph import Graph - G = Graph(loops=(self.has_loops() or other.has_loops())) + from sage.graphs.graph import Graph as GT else: raise TypeError('the graphs should be both directed or both undirected') - G.add_vertices((u, v) for u in self for v in other) - for u, w in self.edge_iterator(labels=None): - for v in other: - for x in other: - G.add_edge((u, v), (w, x)) - for u in self: - for v, x in other.edge_iterator(labels=None): - G.add_edge((u, v), (u, x)) - return G - def strong_product(self, other): + if immutable is None: + immutable = self.is_immutable() and other.is_immutable() + loops = self.has_loops() or other.has_loops() + vertices = ((u, v) for u in self for v in other) + from itertools import chain + edges = chain((((u, v), (w, x)) + for u, w in self.edge_iterator(labels=False) + for v in other + for x in other), + (((u, v), (u, x)) + for u in self + for v, x in other.edge_iterator(labels=False))) + return GT([vertices, edges], format='vertices_and_edges', + loops=loops, immutable=immutable) + + def strong_product(self, other, immutable=None): r""" Return the strong product of ``self`` and ``other``. @@ -19946,6 +20040,15 @@ def strong_product(self, other): In other words, the edges of the strong product is the union of the edges of the tensor and Cartesian products. + INPUT: + + - ``other`` -- a graph or a digraph + + - ``immutable`` -- boolean (default: ``None``); whether to create a + mutable/immutable product. ``immutable=None`` (default) means that the + graphs and their product will behave the same way. If only one of them + is immutable, the product will be mutable. + EXAMPLES:: sage: Z = graphs.CompleteGraph(2) @@ -19993,31 +20096,57 @@ def strong_product(self, other): sage: expected = gm * hn + hm * gn + 2 * gm * hm sage: product_size == expected True + + Check the behavior of parameter `ìmmutable``:: + + sage: A = Graph([(0, 1)]) + sage: B = Graph([('a', 'b')], immutable=True) + sage: A.strong_product(A).is_immutable() + False + sage: A.strong_product(A, immutable=True).is_immutable() + True + sage: A.strong_product(B).is_immutable() + False + sage: A.strong_product(B, immutable=True).is_immutable() + True + sage: B.strong_product(B).is_immutable() + True + sage: B.strong_product(B, immutable=False).is_immutable() + False """ self._scream_if_not_simple(allow_loops=True) if self._directed and other._directed: - from sage.graphs.digraph import DiGraph - G = DiGraph(loops=(self.has_loops() or other.has_loops())) + from sage.graphs.digraph import DiGraph as GT elif (not self._directed) and (not other._directed): - from sage.graphs.graph import Graph - G = Graph(loops=(self.has_loops() or other.has_loops())) + from sage.graphs.graph import Graph as GT else: raise TypeError('the graphs should be both directed or both undirected') - G.add_vertices((u, v) for u in self for v in other) - for u, w in self.edge_iterator(labels=None): - for v in other: - G.add_edge((u, v), (w, v)) - for v, x in other.edge_iterator(labels=None): - G.add_edge((u, v), (w, x)) - if not self._directed: - G.add_edge((w, v), (u, x)) - for v, x in other.edge_iterator(labels=None): - for u in self: - G.add_edge((u, v), (u, x)) - return G + if immutable is None: + immutable = self.is_immutable() and other.is_immutable() + loops = self.has_loops() or other.has_loops() + vertices = ((u, v) for u in self for v in other) + + edges_1 = (((u, v), (w, v)) + for u, w in self.edge_iterator(labels=False) for v in other) + edges_2 = (((u, v), (u, x)) + for v, x in other.edge_iterator(labels=False) for u in self) + edges_3 = (((u, v), (w, x)) + for u, w in self.edge_iterator(labels=False) + for v, x in other.edge_iterator(labels=False)) + if self._directed: + edges_4 = () + else: + edges_4 = (((w, v), (u, x)) + for u, w in self.edge_iterator(labels=False) + for v, x in other.edge_iterator(labels=False)) - def disjunctive_product(self, other): + from itertools import chain + edges = chain(edges_1, edges_2, edges_3, edges_4) + return GT([vertices, edges], format='vertices_and_edges', + loops=loops, immutable=immutable) + + def disjunctive_product(self, other, immutable=None): r""" Return the disjunctive product of ``self`` and ``other``. @@ -20027,6 +20156,15 @@ def disjunctive_product(self, other): * `(u, w)` is an edge of `G`, or * `(v, x)` is an edge of `H`. + INPUT: + + - ``other`` -- a graph or a digraph + + - ``immutable`` -- boolean (default: ``None``); whether to create a + mutable/immutable product. ``immutable=None`` (default) means that the + graphs and their product will behave the same way. If only one of them + is immutable, the product will be mutable. + EXAMPLES:: sage: Z = graphs.CompleteGraph(2) @@ -20072,27 +20210,48 @@ def disjunctive_product(self, other): ((2, 'a'), (0, 'b')), ((2, 'a'), (1, 'b')), ((2, 'a'), (2, 'b'))] sage: T.is_isomorphic(J.disjunctive_product(I)) True + + Check the behavior of parameter `ìmmutable``:: + + sage: A = Graph([(0, 1)]) + sage: B = Graph([('a', 'b')], immutable=True) + sage: A.disjunctive_product(A).is_immutable() + False + sage: A.disjunctive_product(A, immutable=True).is_immutable() + True + sage: A.disjunctive_product(B).is_immutable() + False + sage: A.disjunctive_product(B, immutable=True).is_immutable() + True + sage: B.disjunctive_product(B).is_immutable() + True + sage: B.disjunctive_product(B, immutable=False).is_immutable() + False """ self._scream_if_not_simple(allow_loops=True) if self._directed and other._directed: - from sage.graphs.digraph import DiGraph - G = DiGraph(loops=(self.has_loops() or other.has_loops())) + from sage.graphs.digraph import DiGraph as GT elif (not self._directed) and (not other._directed): - from sage.graphs.graph import Graph - G = Graph(loops=(self.has_loops() or other.has_loops())) + from sage.graphs.graph import Graph as GT else: raise TypeError('the graphs should be both directed or both undirected') - G.add_vertices((u, v) for u in self for v in other) - for u, w in self.edge_iterator(labels=None): - for v in other: - for x in other: - G.add_edge((u, v), (w, x)) - for v, x in other.edge_iterator(labels=None): - for u in self: - for w in self: - G.add_edge((u, v), (w, x)) - return G + if immutable is None: + immutable = self.is_immutable() and other.is_immutable() + loops = self.has_loops() or other.has_loops() + vertices = ((u, v) for u in self for v in other) + edges_1 = (((u, v), (w, x)) + for u, w in self.edge_iterator(labels=False) + for v in other + for x in other) + edges_2 = (((u, v), (w, x)) + for v, x in other.edge_iterator(labels=False) + for u in self + for w in self) + from itertools import chain + edges = chain(edges_1, edges_2) + return GT([vertices, edges], format='vertices_and_edges', + loops=loops, immutable=immutable) def transitive_closure(self, loops=True): r""" From c3a9f9169fccae06067bbca29d1a23c5d6556e35 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 7 Jan 2025 16:33:31 +0100 Subject: [PATCH 073/187] more care about parameter immutable in generic_graph.py --- src/sage/graphs/generic_graph.py | 141 +++++++++++++++++++++++++------ 1 file changed, 117 insertions(+), 24 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index badd28f4fb8..fc709ea8f57 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -5468,6 +5468,17 @@ def cycle_basis(self, output='vertex'): [[(2, 3, 'c'), (3, 2, 'b')], [(3, 4, 'd'), (4, 1, 'f'), (1, 2, 'a'), (2, 3, 'b')], [(3, 4, 'e'), (4, 1, 'f'), (1, 2, 'a'), (2, 3, 'b')]] + + Check that the method is valid for immutable graphs:: + + sage: G = Graph(graphs.CycleGraph(3), immutable=True) + sage: G.cycle_basis() + [[0, 1, 2]] + sage: G = Graph([(1, 2, 'a'), (2, 3, 'b'), (2, 3, 'c'), + ....: (3, 4, 'd'), (3, 4, 'e'), (4, 1, 'f')], + ....: multiedges=True, immutable=True) + sage: G.cycle_basis() + [[3, 2], [4, 1, 2, 3], [4, 1, 2, 3]] """ if output not in ['vertex', 'edge']: raise ValueError('output must be either vertex or edge') @@ -5483,7 +5494,7 @@ def cycle_basis(self, output='vertex'): from sage.graphs.graph import Graph T = Graph(self.min_spanning_tree(), multiedges=True, format='list_of_edges') - H = self.copy() + H = self.copy(immutable=False) H.delete_edges(T.edge_iterator()) root = next(T.vertex_iterator()) rank = dict(T.breadth_first_search(root, report_distance=True)) @@ -7024,7 +7035,7 @@ def planar_dual(self, embedding=None): if e: e = e.pop() # just one edge since self and its dual are simple edges.append([v1, v2, self.edge_label(e[0], e[1])]) - return Graph([verts, edges]) + return Graph([verts, edges], format='vertices_and_edges') # Connectivity @@ -8156,6 +8167,7 @@ def good_edge(e): return val def longest_cycle(self, induced=False, use_edge_labels=False, + immutable=None, solver=None, verbose=0, *, integrality_tolerance=0.001): r""" Return the longest (induced) cycle of ``self``. @@ -8187,6 +8199,10 @@ def longest_cycle(self, induced=False, use_edge_labels=False, considered as a weight of `1`), or to compute a cycle with the largest possible number of edges (i.e., edge weights are set to 1) + - ``immutable`` -- boolean (default: ``None``); whether to create a + mutable/immutable (di)graph. ``immutable=None`` (default) means that + the (di)graph and its longest cycle will behave the same way. + - ``solver`` -- string (default: ``None``); specifies a Mixed Integer Linear Programming (MILP) solver to be used. If set to ``None``, the default one is used. For more information on MILP solvers and which @@ -8297,6 +8313,32 @@ def longest_cycle(self, induced=False, use_edge_labels=False, longest cycle from Subgraph of (Circuit disjoint_union Circuit): Digraph on 5 vertices sage: D.longest_cycle(induced=True) longest induced cycle from Subgraph of (Circuit disjoint_union Circuit): Digraph on 5 vertices + + Check the behavior of parameter ``immutable``:: + + sage: G = Graph([(0, 1), (1, 2), (0, 2)], immutable=True) + sage: G.longest_cycle().is_immutable() + True + sage: G = graphs.Grid2dGraph(3, 4) + sage: G.longest_cycle(induced=False, immutable=True).is_immutable() + True + sage: G.longest_cycle(induced=True, immutable=True).is_immutable() + True + sage: D = digraphs.Circuit(15) + sage: for u, v in D.edges(labels=False): + ....: D.set_edge_label(u, v, 1) + sage: D.add_edge(0, 10, 50) + sage: D.add_edge(11, 1, 1) + sage: D.add_edge(13, 0, 1) + sage: D.longest_cycle(induced=False, use_edge_labels=False, immutable=True).is_immutable() + True + sage: D.longest_cycle(induced=False, use_edge_labels=True, immutable=True)[1].is_immutable() + True + sage: D = DiGraph(D, immutable=True) + sage: D.longest_cycle(induced=False, use_edge_labels=True)[1].is_immutable() + True + sage: D.longest_cycle(induced=False, use_edge_labels=True, immutable=False)[1].is_immutable() + False """ self._scream_if_not_simple() G = self @@ -8318,7 +8360,8 @@ def total_weight(gg): return gg.order() directed = G.is_directed() - immutable = G.is_immutable() + if immutable is None: + immutable = G.is_immutable() if directed: from sage.graphs.digraph import DiGraph as MyGraph blocks = G.strongly_connected_components() @@ -8336,6 +8379,7 @@ def total_weight(gg): h = G.subgraph(vertices=block) C = h.longest_cycle(induced=induced, use_edge_labels=use_edge_labels, + immutable=immutable, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if total_weight(C) > best_w: @@ -8354,8 +8398,7 @@ def total_weight(gg): return MyGraph(name=name, immutable=immutable) if (not induced and ((directed and G.order() == 2) or (not directed and G.order() == 3))): - answer = G.copy() - answer.name(name) + answer = MyGraph(G, immutable=immutable, name=name) if use_edge_labels: return total_weight(answer), answer return answer @@ -8474,7 +8517,8 @@ def F(e): best.set_pos({u: pp for u, pp in G.get_pos().items() if u in best}) return (best_w, best) if use_edge_labels else best - def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm='MILP', + def longest_path(self, s=None, t=None, use_edge_labels=False, + algorithm='MILP', immutable=None, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a longest path of ``self``. @@ -8515,6 +8559,10 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm='MILP', parameters ``s``, ``t`` and ``use_edge_labels``. An error is raised if these parameters are set. + - ``immutable`` -- boolean (default: ``None``); whether to create a + mutable/immutable (di)graph. ``immutable=None`` (default) means that + the (di)graph and its longest path will behave the same way. + - ``solver`` -- string (default: ``None``); specifies a Mixed Integer Linear Programming (MILP) solver to be used. If set to ``None``, the default one is used. For more information on MILP solvers and which @@ -8682,6 +8730,24 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm='MILP', ... ValueError: parameters s, t, and use_edge_labels can not be used in combination with algorithm 'heuristic' + + Check the behavior of parameter ``immutable``:: + + sage: # needs sage.numerical.mip + sage: g1 = digraphs.RandomDirectedGNP(15, 0.2) + sage: for u,v in g.edge_iterator(labels=False): + ....: g.set_edge_label(u, v, random()) + sage: g2 = DiGraph(2 * g1, immutable=True) + sage: lp1 = g1.longest_path(use_edge_labels=True) + sage: lp2 = g2.longest_path(use_edge_labels=True) + sage: lp1[0] == lp2[0] + True + sage: not lp1.is_immutable() and lp2.is_immutable() + True + sage: lp1 = g1.longest_path(use_edge_labels=True, immutable=True) + sage: lp2 = g2.longest_path(use_edge_labels=True, immutable=False) + sage: lp1.is_immutable() and not lp2.is_immutable() + True """ self._scream_if_not_simple() @@ -8697,16 +8763,19 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm='MILP', raise ValueError("parameters s, t, and use_edge_labels can not " "be used in combination with algorithm 'heuristic'") + if immutable is None: + immutable = self.is_immutable() + # Quick improvement if not self.is_connected(): if use_edge_labels: - return max((g.longest_path(s=s, t=t, + return max((g.longest_path(s=s, t=t, immutable=immutable, use_edge_labels=use_edge_labels, algorithm=algorithm) for g in self.connected_components_subgraphs()), key=lambda x: x[0]) - return max((g.longest_path(s=s, t=t, + return max((g.longest_path(s=s, t=t, immutable=immutable, use_edge_labels=use_edge_labels, algorithm=algorithm) for g in self.connected_components_subgraphs()), @@ -8735,16 +8804,18 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm='MILP', (self._directed and (s is not None) and (t is not None) and not self.shortest_path(s, t))): if self._directed: - from sage.graphs.digraph import DiGraph - return [0, DiGraph()] if use_edge_labels else DiGraph() - from sage.graphs.graph import Graph - return [0, Graph()] if use_edge_labels else Graph() + from sage.graphs.digraph import DiGraph as MyGraph + else: + from sage.graphs.graph import Graph as MyGraph + GG = MyGraph(immutable=immutable) + return [0, GG] if use_edge_labels else GG # Calling the heuristic if asked if algorithm == "heuristic": from sage.graphs.generic_graph_pyx import find_hamiltonian as fh x = fh(self, find_path=True)[1] - return self.subgraph(vertices=x, edges=list(zip(x[:-1], x[1:]))) + return self.subgraph(vertices=x, edges=list(zip(x[:-1], x[1:])), + immutable=immutable) ################## # LP Formulation # @@ -8874,21 +8945,20 @@ def weight(x): edge_used = p.get_values(edge_used, convert=bool, tolerance=integrality_tolerance) vertex_used = p.get_values(vertex_used, convert=bool, tolerance=integrality_tolerance) if self._directed: - g = self.subgraph(vertices=(v for v in self if vertex_used[v]), - edges=((u, v, l) for u, v, l in self.edge_iterator() - if edge_used[u, v])) + edges = ((u, v, l) for u, v, l in self.edge_iterator() + if edge_used[u, v]) else: - g = self.subgraph( - vertices=(v for v in self if vertex_used[v]), - edges=((u, v, l) for u, v, l in self.edge_iterator() - if edge_used[frozenset((u, v))])) + edges = ((u, v, l) for u, v, l in self.edge_iterator() + if edge_used[frozenset((u, v))]) + g = self.subgraph(vertices=(v for v in self if vertex_used[v]), + edges=edges, immutable=immutable) if use_edge_labels: return sum(map(weight, g.edge_labels())), g return g def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, - maximize=False, algorithm='MILP', solver=None, verbose=0, - *, integrality_tolerance=1e-3): + maximize=False, algorithm='MILP', immutable=None, + solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a Hamiltonian path of the current graph/digraph. @@ -8934,6 +9004,10 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, * The backtrack algorithm does not support edge weighting, so setting ``use_edge_labels=True`` will force the use of the MILP algorithm. + - ``immutable`` -- boolean (default: ``None``); whether to create a + mutable/immutable (di)graph. ``immutable=None`` (default) means that + the (di)graph and its hamiltonian path will behave the same way. + - ``solver`` -- string (default: ``None``); specifies a Mixed Integer Linear Programming (MILP) solver to be used. If set to ``None``, the default one is used. For more information on MILP solvers and which @@ -9019,6 +9093,20 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, Traceback (most recent call last): ... ValueError: algorithm must be either 'backtrack' or 'MILP' + + Check the behavior of parameter ``immutable``:: + + sage: # needs sage.numerical.mip + sage: g = graphs.Grid2dGraph(3, 3) + sage: g.hamiltonian_path().is_immutable() + False + sage: g.hamiltonian_path(immutable=True).is_immutable() + True + sage: g = Graph(g, immutable=True) + sage: g.hamiltonian_path().is_immutable() + True + sage: g.hamiltonian_path(, use_edge_labels=True).is_immutable() + True """ if use_edge_labels or algorithm is None: # We force the algorithm to 'MILP' @@ -9033,6 +9121,8 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, if not self.is_connected(): return (0, None) if use_edge_labels else None + if immutable is None: + immutable = self.is_immutable() # # Deal with loops and multiple edges # @@ -9096,7 +9186,8 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, new_t = ones.pop() if not use_edge_labels and algorithm == "backtrack": - path = g.longest_path(s=new_s, t=new_t, algorithm='backtrack') + path = g.longest_path(s=new_s, t=new_t, algorithm='backtrack', + immutable=immutable) return path if path.order() == g.order() else None # @@ -9143,6 +9234,8 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, tsp.delete_vertices(extra_vertices) tsp.name("Hamiltonian path from {}".format(self.name())) + if immutable: + tst = tsp.copy(immutable=True) def weight(label): return 1 if label is None else label @@ -10779,7 +10872,7 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, solvers over an inexact base ring; see :meth:`MixedIntegerLinearProgram.get_values`. - Only useful when parameter ``ìnteger`` is ``True``. + Only useful when parameter ``integer`` is ``True``. ALGORITHM: From 57ff81d25971ff26a4dbe1eb88d3df877cfc402d Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 7 Jan 2025 17:18:37 +0100 Subject: [PATCH 074/187] 39297: fix small issues --- src/sage/graphs/generic_graph.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index fc709ea8f57..b983be0728b 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -8742,11 +8742,11 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, sage: lp2 = g2.longest_path(use_edge_labels=True) sage: lp1[0] == lp2[0] True - sage: not lp1.is_immutable() and lp2.is_immutable() + sage: not lp1[1].is_immutable() and lp2[1].is_immutable() True sage: lp1 = g1.longest_path(use_edge_labels=True, immutable=True) sage: lp2 = g2.longest_path(use_edge_labels=True, immutable=False) - sage: lp1.is_immutable() and not lp2.is_immutable() + sage: lp1[1].is_immutable() and not lp2[1].is_immutable() True """ self._scream_if_not_simple() @@ -9105,7 +9105,7 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, sage: g = Graph(g, immutable=True) sage: g.hamiltonian_path().is_immutable() True - sage: g.hamiltonian_path(, use_edge_labels=True).is_immutable() + sage: g.hamiltonian_path(use_edge_labels=True)[1].is_immutable() True """ if use_edge_labels or algorithm is None: @@ -9235,7 +9235,7 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, tsp.delete_vertices(extra_vertices) tsp.name("Hamiltonian path from {}".format(self.name())) if immutable: - tst = tsp.copy(immutable=True) + tsp = tsp.copy(immutable=True) def weight(label): return 1 if label is None else label From f75189b2cfe70aa9852461bed026ee7a0a47ae28 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Wed, 8 Jan 2025 11:50:36 +0100 Subject: [PATCH 075/187] #39280: add missing backticks --- src/sage/graphs/generic_graph.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index fb14afc6e0b..9375f9418b3 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -19473,7 +19473,7 @@ def complement(self, immutable=None): sage: g.complement() Graph on 10 vertices - Check the behavior of parameter `ìmmutable``:: + Check the behavior of parameter ``immutable``:: sage: type(Graph().complement()._backend) @@ -19550,7 +19550,7 @@ def to_simple(self, to_undirected=True, keep_label='any', immutable=None): TESTS: - Check the behavior of parameter `ìmmutable``:: + Check the behavior of parameter ``immutable``:: sage: G = Graph([(0, 0), (0, 1)] * 2, loops=True, multiedges=True, immutable=True) sage: H = G.to_simple() @@ -19631,7 +19631,7 @@ def disjoint_union(self, other, labels='pairs', immutable=None): TESTS: - Check the behavior of parameter `ìmmutable``:: + Check the behavior of parameter ``immutable``:: sage: G = Graph([(0, 1)]) sage: G.disjoint_union(G).is_immutable() From fa42cd3943c2e3c462cb4681d6a7fcdece9287b8 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Mon, 13 Jan 2025 17:27:58 +0530 Subject: [PATCH 076/187] updated is_brick() --- src/sage/graphs/matching_covered_graph.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index c4545d964ad..d85845a667d 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2751,7 +2751,7 @@ def is_brick(self, coNP_certificate=False): - If the input nonbipartite matching covered graph is a brick, a boolean ``True`` is returned if ``coNP_certificate`` is set to - ``False`` otherwise a 4-tuple ``(True, None, None, None)`` is + ``False``, otherwise a 4-tuple ``(True, None, None, None)`` is returned. - If the input nonbipartite matching covered graph is not a brick, a @@ -2763,20 +2763,20 @@ def is_brick(self, coNP_certificate=False): 1. a boolean ``False``, - 2. a list of list of edges each list constituting a nontrivial tight - cut collectively representing a laminar tight cut, + 2. a list of lists of edges, each list constituting a nontrivial + tight cut collectively representing a laminar tight cut, 3. a list of set of vertices of one of the shores of those respective - nontrivial tight cuts. + nontrivial tight cuts: - - In case of nontrivial barrier cuts, each of the shores is a - nontrivial odd component wrt a nontrivial barrier, thus the - returned list forms mutually exclusive collection of (odd) - sets. + #. In case of nontrivial barrier cuts, each of the shores is a + nontrivial odd component with respect to a nontrivial barrier, + thus the returned list forms mutually exclusive collection of + (odd) sets. - - Otherwise each of the nontrivial tight cuts is a 2-separation - cut, each of the shores form a subset sequence, with the `i`th - shore being a proper subset of the `i + 1`th shore. + #. Otherwise each of the nontrivial tight cuts is a 2-separation + cut, each of the shores form a subset sequence, with the + `i` th shore being a proper subset of the `i + 1` th shore. 4. a string showing whether the nontrivial tight cuts are barrier cuts (if the string is 'nontrivial barrier cuts'), or 2-separation From cdaf8e780b9193faf9001dcee37751f8a4400caf Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Tue, 14 Jan 2025 18:28:09 +0530 Subject: [PATCH 077/187] updated is_brace() --- src/sage/graphs/matching_covered_graph.py | 72 ++++++++++++++++------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 6b4ac097b42..f54840f81ff 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2382,13 +2382,24 @@ def is_brace(self, coNP_certificate=False): - If the input bipartite matching covered graph is a brace, a boolean ``True`` is returned if ``coNP_certificate`` is set to ``False`` - otherwise a tuple ``(True, None, None)`` is returned. + otherwise a 5-tuple ``(True, None, None, None, None)`` is returned. - If the input bipartite matching covered graph is not a brace, a boolean ``False`` is returned if ``coNP_certificate`` is set to - ``False`` otherwise a tuple of boolean ``False``, a list of - edges constituting a nontrivial tight cut and a set of vertices of - one of the shores of the nontrivial tight cut is returned. + ``False`` otherwise a 5-tuple of + + 1. a boolean ``False``, + + 2. a list of edges constituting a nontrivial tight cut (which is a + nontrivial barrier cut) + + 3. a set of vertices of one of the shores of the nontrivial tight cut + + 4. a string 'nontrivial tight cut' + + 5. a set of vertices showing the respective barrier + + is returned. EXAMPLES: @@ -2590,10 +2601,11 @@ def is_brace(self, coNP_certificate=False): sage: H = graphs.HexahedralGraph() sage: G = MatchingCoveredGraph(H) sage: G.is_brace(coNP_certificate=True) - (True, None, None) + (True, None, None, None, None) sage: C = graphs.CycleGraph(6) sage: D = MatchingCoveredGraph(C) - sage: is_brace, nontrivial_tight_cut, nontrivial_odd_component = \ + sage: is_brace, nontrivial_tight_cut, nontrivial_odd_component, \ + ....: nontrivial_tight_cut_variant, cut_identifier = \ ....: D.is_brace(coNP_certificate=True) sage: is_brace is False True @@ -2602,11 +2614,18 @@ def is_brace(self, coNP_certificate=False): True sage: len(nontrivial_tight_cut) == 2 True + sage: nontrivial_tight_cut_variant + 'nontrivial barrier cut' + sage: # Corresponding barrier + sage: cut_identifier == {a for u, v, *_ in nontrivial_tight_cut for a in [u, v] \ + ....: if a not in nontrivial_odd_component} + True sage: for u, v, *_ in nontrivial_tight_cut: ....: assert (u in nontrivial_odd_component and v not in nontrivial_odd_component) sage: L = graphs.LadderGraph(3) # A ladder graph with two constituent braces sage: G = MatchingCoveredGraph(L) - sage: is_brace, nontrivial_tight_cut, nontrivial_odd_component = G.is_brace(coNP_certificate=True) + sage: is_brace, nontrivial_tight_cut, nontrivial_odd_component, cut_variant, cut_identifier = \ + ....: G.is_brace(coNP_certificate=True) sage: is_brace is False True sage: G1 = L.copy() @@ -2617,6 +2636,11 @@ def is_brace(self, coNP_certificate=False): sage: G2.merge_vertices([v for v in G if v not in nontrivial_odd_component]) sage: G2.to_simple().is_isomorphic(graphs.CycleGraph(4)) True + sage: cut_variant + 'nontrivial barrier cut' + sage: cut_identifier == {a for u, v, *_ in nontrivial_tight_cut for a in [u, v] \ + ....: if a not in nontrivial_odd_component} + True If the input matching covered graph is nonbipartite, a :exc:`ValueError` is thrown:: @@ -2644,7 +2668,7 @@ def is_brace(self, coNP_certificate=False): raise ValueError('the input graph is not bipartite') if self.order() < 6: - return (True, None, None) if coNP_certificate else True + return (True, None, None, None, None) if coNP_certificate else True A, B = self.bipartite_sets() matching = set(self.get_matching()) @@ -2679,16 +2703,16 @@ def is_brace(self, coNP_certificate=False): # H(e) is matching covered iff D(e) is strongly connected. # Check if D(e) is strongly connected using Kosaraju's algorithm - def dfs(v, visited, neighbor_iterator): - stack = [v] # a stack of vertices + def dfs(x, visited, neighbor_iterator): + stack = [x] # a stack of xertices while stack: - v = stack.pop() - visited.add(v) + x = stack.pop() + visited.add(x) - for u in neighbor_iterator(v): - if u not in visited: - stack.append(u) + for y in neighbor_iterator(x): + if y not in visited: + stack.append(y) root = next(D.vertex_iterator()) @@ -2722,13 +2746,21 @@ def dfs(v, visited, neighbor_iterator): X.add(u if (not color_class and u in A) or (color_class and u in B) or (color_class is None) else v) # Compute the nontrivial tight cut C := ∂(Y) - C = [(u, v, w) if u in X else (v, u, w) - for u, v, w in self.edge_iterator(sort_vertices=True) - if (u in X) ^ (v in X)] + C = [(x, y, w) if x in X else (y, x, w) + for x, y, w in self.edge_iterator(sort_vertices=True) + if (x in X) ^ (y in X)] + + # Obtain the barrier Z + Z = None + + if (u in X and u in A) or (v in X and v in A): + Z = {b for b in B if b not in X} + else: + Z = {a for a in A if a not in X} - return (False, C, set(X)) + return (False, C, set(X), 'nontrivial barrier cut', Z) - return (True, None, None) if coNP_certificate else True + return (True, None, None, None, None) if coNP_certificate else True @doc_index('Bricks, braces and tight cut decomposition') def is_brick(self, coNP_certificate=False): From 2b765b3d2a7be78dbc7537fdc0da15da073c72b7 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Tue, 14 Jan 2025 18:30:10 +0530 Subject: [PATCH 078/187] updated is_brick() --- src/sage/graphs/matching_covered_graph.py | 33 ++++++++++++++--------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index f54840f81ff..3ef6579e987 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2783,7 +2783,7 @@ def is_brick(self, coNP_certificate=False): - If the input nonbipartite matching covered graph is a brick, a boolean ``True`` is returned if ``coNP_certificate`` is set to - ``False``, otherwise a 4-tuple ``(True, None, None, None)`` is + ``False``, otherwise a 5-tuple ``(True, None, None, None, None)`` is returned. - If the input nonbipartite matching covered graph is not a brick, a @@ -2791,7 +2791,7 @@ def is_brick(self, coNP_certificate=False): ``False``. - If ``coNP_certificate`` is set to ``True`` and the input nonbipartite - graph is not a brick, a 4-tuple of + graph is not a brick, a 5-tuple of 1. a boolean ``False``, @@ -2811,8 +2811,14 @@ def is_brick(self, coNP_certificate=False): `i` th shore being a proper subset of the `i + 1` th shore. 4. a string showing whether the nontrivial tight cuts are barrier - cuts (if the string is 'nontrivial barrier cuts'), or 2-separation - cuts (if the string is 'nontrivial 2-separation cuts') + cuts (if the string is 'nontrivial barrier cut'), or 2-separation + cuts (if the string is 'nontrivial 2-separation cut') + + 5. a set of vertices showing the respective barrier if the + nontrivial tight cuts are barrier cuts, or otherwise + a set of two vertices constituting the corresponding + two vertex cut (in this case the nontrivial tight cuts are + 2-separation cuts) is returned. @@ -2914,13 +2920,13 @@ def is_brick(self, coNP_certificate=False): sage: K4 = graphs.CompleteGraph(4) sage: G = MatchingCoveredGraph(K4) sage: G.is_brick(coNP_certificate=True) - (True, None, None, None) + (True, None, None, None, None) sage: # K(4) ⊙ K(3, 3) is nonbipartite but not a brick sage: H = graphs.MurtyGraph(); H.delete_edge(0, 1) sage: G = MatchingCoveredGraph(H) sage: G.is_brick(coNP_certificate=True) (False, [[(5, 2, None), (6, 3, None), (7, 4, None)]], [{5, 6, 7}], - 'nontrivial barrier cuts') + 'nontrivial barrier cut', {2, 3, 4}) sage: H = Graph([ ....: (0, 12), (0, 13), (0, 15), (1, 4), (1, 13), (1, 14), ....: (1, 19), (2, 4), (2, 13), (2, 14), (2, 17), (3, 9), @@ -2936,7 +2942,7 @@ def is_brick(self, coNP_certificate=False): [(19, 1, None), (17, 2, None), (21, 3, None)], [(15, 0, None), (14, 1, None), (14, 2, None), (16, 3, None)]], [{4, 5, 6, 7, 8, 9, 10, 11, 12}, {17, 18, 19, 20, 21}, {14, 15, 16}], - 'nontrivial barrier cuts') + 'nontrivial barrier cut', {0, 1, 2, 3}) sage: J = Graph([ ....: (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), ....: (0, 6), (0, 7), (0, 8), (0, 9), (0, 10), @@ -2991,7 +2997,8 @@ def is_brick(self, coNP_certificate=False): {0, 1, 2, 3, 4}, {0, 1, 2, 3, 4, 5, 6}, {0, 1, 2, 3, 4, 5, 6, 7, 8}], - 'nontrivial 2-separation cuts') + 'nontrivial 2-separation cut', + {0, 11}) If the input matching covered graph is bipartite, a :exc:`ValueError` is thrown:: @@ -3048,11 +3055,11 @@ def is_brick(self, coNP_certificate=False): if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] for nontrivial_odd_component in nontrivial_odd_components] - return (False, C, nontrivial_odd_components, 'nontrivial barrier cuts') + return (False, C, nontrivial_odd_components, 'nontrivial barrier cut', B) # Check if G is 3-connected if self.is_triconnected(): - return (True, None, None, None) if coNP_certificate else True + return (True, None, None, None, None) if coNP_certificate else True # G has a 2-vertex cut # Compute the SPQR-tree decomposition @@ -3091,11 +3098,11 @@ def is_brick(self, coNP_certificate=False): nontrivial_tight_cut_variation = None if all(len(c) % 2 for c in components): - nontrivial_tight_cut_variation = 'nontrivial barrier cuts' + nontrivial_tight_cut_variation = 'nontrivial barrier cut' nontrivial_odd_components = [set(component) for component in components if len(component) > 1] else: - nontrivial_tight_cut_variation = 'nontrivial 2-separation cuts' + nontrivial_tight_cut_variation = 'nontrivial 2-separation cut' nontrivial_odd_components = [] for index, component in enumerate(components): @@ -3114,7 +3121,7 @@ def is_brick(self, coNP_certificate=False): for nontrivial_odd_component in nontrivial_odd_components] # Edge (u, v, w) in C are formatted so that u is in a nontrivial odd component - return (False, C, nontrivial_odd_components, nontrivial_tight_cut_variation) if coNP_certificate else False + return (False, C, nontrivial_odd_components, nontrivial_tight_cut_variation, set(two_vertex_cut)) if coNP_certificate else False @doc_index('Overwritten methods') def loop_edges(self, labels=True): From 9a952219669192e080eeabc4c3bb16fe806fe350 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Tue, 14 Jan 2025 23:17:37 +0530 Subject: [PATCH 079/187] updated is_brick() --- src/sage/graphs/matching_covered_graph.py | 31 +++++++++-------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 3ef6579e987..c06d9a30aec 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -3095,25 +3095,18 @@ def is_brick(self, coNP_certificate=False): components = H.connected_components(sort=True) # Find a nontrivial odd component - nontrivial_tight_cut_variation = None - - if all(len(c) % 2 for c in components): - nontrivial_tight_cut_variation = 'nontrivial barrier cut' - nontrivial_odd_components = [set(component) for component in components if len(component) > 1] - - else: - nontrivial_tight_cut_variation = 'nontrivial 2-separation cut' - nontrivial_odd_components = [] - - for index, component in enumerate(components): - if index == len(components) - 1: - continue - elif not index: - nontrivial_odd_components.append(set(components[0] + [two_vertex_cut[0]])) - else: - nontrivial_odd_component = nontrivial_odd_components[-1].copy() - nontrivial_odd_component.update(component) - nontrivial_odd_components.append(nontrivial_odd_component) + nontrivial_tight_cut_variation = 'nontrivial 2-separation cut' + nontrivial_odd_components = [] + + for index, component in enumerate(components): + if index == len(components) - 1: + continue + elif not index: + nontrivial_odd_components.append(set(components[0] + [two_vertex_cut[0]])) + else: + nontrivial_odd_component = nontrivial_odd_components[-1].copy() + nontrivial_odd_component.update(component) + nontrivial_odd_components.append(nontrivial_odd_component) C = [[(u, v, w) if u in nontrivial_odd_component else (v, u, w) for u, v, w in self.edge_iterator() From 80e0b4ddd78381bd18c279add81793fc81a8bf0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 18 Jan 2025 20:41:10 +0100 Subject: [PATCH 080/187] activate check for ruff PLW0127 --- .../combinat/designs/orthogonal_arrays_build_recursive.py | 6 +++--- src/sage/combinat/skew_tableau.py | 4 ++-- src/sage/interacts/library.py | 8 ++++---- src/tox.ini | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py index 2bfd385492c..2609f69f2e7 100644 --- a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py +++ b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py @@ -837,14 +837,14 @@ def thwart_lemma_4_1(k, n, m, explain_construction=False): # - (1+t,t,1+t), (1,1,1), (1+t,t,t), (1,1,2), (0,0,1), (1,0,1), (0,1,1+t), # (0,1,1), (1,0,-t) points = [(1+t,t,1+t), (1,1,1), (1+t,t,t), (1,1,2), (0,0,1), (1,0,1), (0,1,1+t), (0,1,1), (1,0,-t)] - points = [[K(_) for _ in t] for t in points] # triples of K^3 + points = [[K(c) for c in t] for t in points] # triples of K^3 AG_2_3 = [] for x,y,z in points: if z != 0: - x,y,z = x/z,y/z,z/z + x, y, z = x / z, y / z, K.one() AG_2_3.append(relabel[x]+n*relabel[y]) elif y != 0: - x,y,z = x/y,y/y,z + x, y = x / y, K.one() AG_2_3.append(q**2+relabel[x]) else: AG_2_3.append(q**2+q) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 44189013d5c..6997cd396f9 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -1042,10 +1042,10 @@ def backward_slide(self, corner=None): # -1, which doesn't trigger the conditional if P_left > P_up: new_st[i][j] = P_left - i, j = (i, j - 1) + j = j - 1 else: # if they are equal, we slide up new_st[i][j] = P_up - i, j = (i - 1, j) + i = i - 1 # We don't need to reset the intermediate cells inside the loop # because the conditional above will continue to overwrite it until # the while loop terminates. We do need to reset it at the end. diff --git a/src/sage/interacts/library.py b/src/sage/interacts/library.py index a58a0748477..3ce16952a74 100644 --- a/src/sage/interacts/library.py +++ b/src/sage/interacts/library.py @@ -925,7 +925,7 @@ def bisection_method(title, f, interval, d, maxn): maxn: IntSlider(value=10, description='max iterations', max=15) """ def _bisection_method(f, a, b, maxn, eps): - intervals = [(a,b)] + intervals = [(a, b)] round = 1 two = float(2) while True: @@ -938,12 +938,12 @@ def _bisection_method(f, a, b, maxn, eps): if abs(fc) < eps: return c, intervals if fa*fc < 0: - a, b = a, c + b = c elif fc*fb < 0: - a, b = c, b + a = c else: raise ValueError("f must have a sign change in the interval (%s,%s)" % (a,b)) - intervals.append((a,b)) + intervals.append((a, b)) round += 1 return c, intervals diff --git a/src/tox.ini b/src/tox.ini index 29dd3fcaa15..a33f0f9b5a6 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -311,7 +311,7 @@ passenv = RUFF_OUTPUT_FORMAT # 1 F402 [ ] Import `factor` from line 259 shadowed by loop variable # 1 PLC0208 [*] Use a sequence type instead of a `set` when iterating over values # -commands = ruff check --ignore E402,E721,E731,E741,E742,E743,F401,F402,F403,F405,F821,F841,I001,PLC0206,PLC0208,PLC2401,PLC3002,PLE0302,PLR0124,PLR0402,PLR0911,PLR0912,PLR0913,PLR0915,PLR1704,PLR1711,PLR1714,PLR1736,PLR2004,PLR5501,PLW0120,PLW0127,PLW0211,PLW0602,PLW0603,PLW0642,PLW1508,PLW1510,PLW2901,PLW3301 {posargs:{toxinidir}/sage/} +commands = ruff check --ignore E402,E721,E731,E741,E742,E743,F401,F402,F403,F405,F821,F841,I001,PLC0206,PLC0208,PLC2401,PLC3002,PLE0302,PLR0124,PLR0402,PLR0911,PLR0912,PLR0913,PLR0915,PLR1704,PLR1711,PLR1714,PLR1736,PLR2004,PLR5501,PLW0120,PLW0211,PLW0602,PLW0603,PLW0642,PLW1508,PLW1510,PLW2901,PLW3301 {posargs:{toxinidir}/sage/} [flake8] rst-roles = From 83449baa95e11b340695e85173516d5fb15df346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 9 Oct 2024 21:23:49 +0200 Subject: [PATCH 081/187] convert magma power series rings --- src/sage/ext_data/magma/sage/basic.m | 38 +++++++++++++++++++++----- src/sage/interfaces/magma.py | 40 +++++++++++++++------------- 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/src/sage/ext_data/magma/sage/basic.m b/src/sage/ext_data/magma/sage/basic.m index 678174dfd49..9af9c3f4714 100644 --- a/src/sage/ext_data/magma/sage/basic.m +++ b/src/sage/ext_data/magma/sage/basic.m @@ -8,7 +8,7 @@ function PreparseElts(R) end function; intrinsic Sage(X::.) -> MonStgElt, BoolElt -{Default way to convert a Magma object to Sage if we haven't +{Default way to convert a Magma object to Sage if we have not written anything better.} return Sprintf("%o", X), true; end intrinsic; @@ -153,16 +153,19 @@ intrinsic SageNamesHelper(X::.) -> MonStgElt {} /* XXX */ i := NumberOfNames(X); - if i ge 2 then - return (&* [ Sprintf("%o, ", X.j) : j in [ 1..i-1 ] ]) * Sprintf("%o", X.i); + if "$" in Sprint(X.i) then + /* unnamed variables */ + return "(" * (&* [ Sprintf("'x%o', ", j) : j in [ 1..i ] ]) * ")" else - return Sprintf("%o", X.i); - end if; + /* named variables */ + return "(" * (&* [ Sprintf("'%o', ", X.j) : j in [ 1..i ] ]) * ")" + end if: end intrinsic; intrinsic Sage(X::RngUPol) -> MonStgElt, BoolElt {} - return Sprintf("%o['%o'.replace('$.', 'x').replace('.', '')]", Sage(BaseRing(X)), SageNamesHelper(X)), false; + txt := "PolynomialRing(%o, %o)"; + return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; end intrinsic; intrinsic Sage(X::RngUPolElt) -> MonStgElt, BoolElt @@ -173,7 +176,8 @@ intrinsic Sage(X::RngUPolElt) -> MonStgElt, BoolElt intrinsic Sage(X::RngMPol) -> MonStgElt, BoolElt {} - return Sprintf("%o['%o'.replace('$.', 'x').replace('.', '')]", Sage(BaseRing(X)), SageNamesHelper(X)), false; + txt := "PolynomialRing(%o, %o)"; + return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; end intrinsic; intrinsic Sage(X::RngMPolElt) -> MonStgElt, BoolElt @@ -264,3 +268,23 @@ intrinsic Sage(X::ModTupRngElt) -> MonStgElt, BoolElt {} return Sprintf("%o(%o)", Sage(Parent(X)), Sage(ElementToSequence(X))), true; end intrinsic; + +/* Power series rings */ + +intrinsic Sage(X::RngSerPow) -> MonStgElt, BoolElt +{} + txt := "PowerSeriesRing(%o, %o)"; + return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; +end intrinsic; + +intrinsic Sage(X::RngSerLaur) -> MonStgElt, BoolElt +{} + txt := "LaurentSeriesRing(%o, %o)"; + return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; +end intrinsic; + +intrinsic Sage(X::RngSerPuis) -> MonStgElt, BoolElt +{} + txt := "PuiseuxSeriesRing(%o, %o)"; + return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; +end intrinsic; diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index 3ec584931cc..3b633244f41 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -221,11 +221,6 @@ from sage.structure.parent import Parent from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement -PROMPT = ">>>" - -SAGE_REF = "_sage_ref" -SAGE_REF_RE = re.compile(r'%s\d+' % SAGE_REF) - from sage.env import SAGE_EXTCODE, DOT_SAGE import sage.misc.misc import sage.misc.sage_eval @@ -233,15 +228,21 @@ from sage.interfaces.tab_completion import ExtraTabCompletion from sage.misc.instancedoc import instancedoc +PROMPT = ">>>" + +SAGE_REF = "_sage_ref" +SAGE_REF_RE = re.compile(r'%s\d+' % SAGE_REF) + INTRINSIC_CACHE = '%s/magma_intrinsic_cache.sobj' % DOT_SAGE EXTCODE_DIR = None -def extcode_dir(iface=None): +def extcode_dir(iface=None) -> str: """ - Return directory that contains all the Magma extcode. This is put - in a writable directory owned by the user, since when attached, - Magma has to write sig and lck files. + Return directory that contains all the Magma extcode. + + This is put in a writable directory owned by the user, since when + attached, Magma has to write sig and lck files. EXAMPLES:: @@ -413,7 +414,7 @@ def __reduce__(self): """ return reduce_load_Magma, tuple([]) - def _read_in_file_command(self, filename): + def _read_in_file_command(self, filename) -> str: """ Return the command in Magma that reads in the contents of the given file. @@ -433,7 +434,7 @@ def _read_in_file_command(self, filename): """ return 'load "%s";' % filename - def _post_process_from_file(self, s): + def _post_process_from_file(self, s) -> str: r""" Used internally in the Magma interface to post-process the result of evaluating a string using a file. For Magma what this does is @@ -462,7 +463,7 @@ def _post_process_from_file(self, s): return '' return s[i + 1:] - def __getattr__(self, attrname): + def __getattr__(self, attrname) -> MagmaFunction: """ Return a formal wrapper around a Magma function, or raise an :exc:`AttributeError` if attrname starts with an underscore. @@ -494,7 +495,7 @@ def __getattr__(self, attrname): raise AttributeError return MagmaFunction(self, attrname) - def eval(self, x, strip=True, **kwds): + def eval(self, x, strip=True, **kwds) -> str: """ Evaluate the given block x of code in Magma and return the output as a string. @@ -553,7 +554,7 @@ def eval(self, x, strip=True, **kwds): raise RuntimeError("Error evaluating Magma code.\nIN:%s\nOUT:%s" % (x, ans)) return ans - def _preparse(self, s): + def _preparse(self, s) -> str: """ All input gets preparsed by calling this function before it gets evaluated. @@ -578,7 +579,7 @@ def _preparse(self, s): pass return s - def _start(self): + def _start(self) -> None: """ Initialize a Magma interface instance. This involves (1) setting up an obfuscated prompt, and (2) attaching the MAGMA_SPEC file (see @@ -619,7 +620,7 @@ def set(self, var, value): if out.lower().find("error") != -1: raise TypeError("Error executing Magma code:\n%s" % out) - def get(self, var): + def get(self, var) -> str: """ Get the value of the variable var. @@ -1880,10 +1881,11 @@ def __getattr__(self, attrname): def _sage_(self): """ - Return Sage version of this object. Use self.sage() to get the Sage - version. + Return Sage version of this object. + + Use self.sage() to get the Sage version. - Edit src/ext/magma/sage/basic.m to add functionality. + Edit ``src/sage/ext_data/magma/sage/basic.m`` to add functionality. EXAMPLES: Enumerated Sets:: From ce9db0fda02ff1b0169d992d5adb8ccb02b36718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 21 Jan 2025 12:02:01 -0500 Subject: [PATCH 082/187] some fixes --- src/sage/ext_data/magma/sage/basic.m | 6 ++--- src/sage/interfaces/magma.py | 37 ++++++++++++++-------------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/sage/ext_data/magma/sage/basic.m b/src/sage/ext_data/magma/sage/basic.m index 9af9c3f4714..a88ab8bf022 100644 --- a/src/sage/ext_data/magma/sage/basic.m +++ b/src/sage/ext_data/magma/sage/basic.m @@ -155,11 +155,11 @@ intrinsic SageNamesHelper(X::.) -> MonStgElt i := NumberOfNames(X); if "$" in Sprint(X.i) then /* unnamed variables */ - return "(" * (&* [ Sprintf("'x%o', ", j) : j in [ 1..i ] ]) * ")" + return "(" * (&* [ Sprintf("'x%o', ", j) : j in [ 1..i ] ]) * ")"; else /* named variables */ - return "(" * (&* [ Sprintf("'%o', ", X.j) : j in [ 1..i ] ]) * ")" - end if: + return "(" * (&* [ Sprintf("'%o', ", X.j) : j in [ 1..i ] ]) * ")"; + end if; end intrinsic; intrinsic Sage(X::RngUPol) -> MonStgElt, BoolElt diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index 3b633244f41..7496b061538 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -214,7 +214,7 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from __future__ import annotations +from pathlib import Path import re import sys import os @@ -463,7 +463,7 @@ def _post_process_from_file(self, s) -> str: return '' return s[i + 1:] - def __getattr__(self, attrname) -> MagmaFunction: + def __getattr__(self, attrname): """ Return a formal wrapper around a Magma function, or raise an :exc:`AttributeError` if attrname starts with an underscore. @@ -656,7 +656,7 @@ def objgens(self, value, gens): sage: R = magma.objgens('PolynomialRing(Rationals(),2)', 'alpha,beta') # optional - magma sage: R.gens() # optional - magma - [alpha, beta] + (alpha, beta) Because of how Magma works you can use this to change the variable names of the generators of an object:: @@ -912,16 +912,15 @@ def cputime(self, t=None): sage: # optional - magma sage: type(magma.cputime()) <... 'float'> - sage: magma.cputime() + sage: magma.cputime() # random 1.9399999999999999 sage: t = magma.cputime() - sage: magma.cputime(t) + sage: magma.cputime(t) # random 0.02 """ if t: return float(self.eval('Cputime(%s)' % t)) - else: - return float(self.eval('Cputime()')) + return float(self.eval('Cputime()')) def chdir(self, dir): """ @@ -1004,7 +1003,7 @@ def load(self, filename): Loading a file in Magma makes all the functions and procedures in the file available. The file should not contain any intrinsics (or - you'll get errors). It also runs code in the file, which can + you will get errors). It also runs code in the file, which can produce output. INPUT: @@ -1019,14 +1018,15 @@ def load(self, filename): sage: with NTF(mode='w+t', suffix='.m') as f: # optional - magma ....: _ = f.write('function f(n) return n^2; end function;\nprint "hi";') ....: print(magma.load(f.name)) - Loading ".../a.m" + Loading "....m" hi sage: magma('f(12)') # optional - magma 144 """ - return self.eval('load "%s"' % filename) + p = Path(filename) + return self.eval('load "%s"' % p.absolute()) - def _next_var_name(self): + def _next_var_name(self) -> str: """ Return the next available variable name in Magma. @@ -2072,14 +2072,14 @@ def AssignNames(self, names): def gen(self, n): """ - Return the `n`-th generator of this Magma element. Note that - generators are 1-based in Magma rather than 0-based! + Return the `n`-th generator of this Magma element. + + Note that generators are 1-based in Magma rather than 0-based! INPUT: - ``n`` -- *positive* integer - OUTPUT: :class:`MagmaElement` EXAMPLES:: @@ -2102,7 +2102,7 @@ def gen(self, n): sage: m.gen(4) # optional -- magma Traceback (most recent call last): ... - IndexError: list index out of range + IndexError: tuple index out of range """ if n <= 0: raise IndexError("index must be positive since Magma indexes are 1-based") @@ -2114,7 +2114,7 @@ def gens(self) -> tuple: 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 tuple - of the resulting X.i. Note - I don't think there is a Magma command + of the resulting X.i. Note - I do not 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 gets around that problem. Again, this is something that should @@ -2296,7 +2296,7 @@ def _polynomial_(self, R): sage: R. = QQ[] sage: f = magma(x^2 + 2/3*x + 5) # optional - magma sage: f # optional - magma - t^2 + 2/3*t + 5 + x^2 + 2/3*x + 5 sage: f.Type() # optional - magma RngUPolElt sage: f._polynomial_(R) # optional - magma @@ -2304,7 +2304,7 @@ def _polynomial_(self, R): """ return R(list(self.Eltseq())) - def _latex_(self): + def _latex_(self) -> str: r""" Return latex representation of ``self``. @@ -2856,6 +2856,7 @@ def write(self, s): sage: P. = GF(32003)[] sage: I = sage.rings.ideal.Katsura(P) sage: _ = I.groebner_basis('magma',prot=True) # indirect doctest, optional - magma + ... ******************** FAUGERE F4 ALGORITHM ******************** From dffb2735425df31441eef5e2dda47421d691b28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 21 Jan 2025 12:05:28 -0500 Subject: [PATCH 083/187] another fix --- src/sage/interfaces/magma.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index d8a5a944f6e..7496b061538 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -463,7 +463,7 @@ def _post_process_from_file(self, s) -> str: return '' return s[i + 1:] - def __getattr__(self, attrname) -> MagmaFunction: + def __getattr__(self, attrname): """ Return a formal wrapper around a Magma function, or raise an :exc:`AttributeError` if attrname starts with an underscore. From 48ead58ce10027e8491641c138e9bb4c74f08de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 21 Jan 2025 13:06:23 -0500 Subject: [PATCH 084/187] adding conversions towards magma --- src/sage/interfaces/magma.py | 2 +- src/sage/rings/laurent_series_ring.py | 23 +++++++++++++++++++++++ src/sage/rings/power_series_ring.py | 23 +++++++++++++++++++++++ src/sage/rings/puiseux_series_ring.py | 23 +++++++++++++++++++++++ 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index 7496b061538..c34db3f4573 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -10,7 +10,7 @@ You must have Magma installed on your computer for this interface to work. Magma is not free, so it is not included with Sage, but you can obtain it from - http://magma.maths.usyd.edu.au/. + https://magma.maths.usyd.edu.au/. The Magma interface offers three pieces of functionality: diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index 1feba6e675b..831d4a71db2 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -407,6 +407,29 @@ def _repr_(self): s = 'Sparse ' + s return s + def _magma_init_(self, magma): + """ + Used in converting this ring to the corresponding ring in MAGMA. + + EXAMPLES:: + + sage: # optional - magma + sage: R = LaurentSeriesRing(QQ, 'y') + sage: R._magma_init_(magma) + 'SageCreateWithNames(LaurentSeriesRing(_sage_ref...),["y"])' + sage: S = magma(R) + sage: S + Laurent series field in y over Rational Field + sage: S.1 + y + sage: magma(LaurentSeriesRing(GF(7), 'x')) # needs sage.rings.finite_rings + Laurent series field in x over GF(7) + """ + B = magma(self.base_ring()) + Bref = B._ref() + s = 'LaurentSeriesRing(%s)' % (Bref) + return magma._with_names(s, self.variable_names()) + def _element_constructor_(self, x, n=0, prec=infinity): r""" Construct a Laurent series from `x`. diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index 42ca735e671..8e7d7bfa22a 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -722,6 +722,29 @@ def _coerce_map_from_(self, S): and self.variable_names() == S.variable_names()): return True + def _magma_init_(self, magma): + """ + Used in converting this ring to the corresponding ring in MAGMA. + + EXAMPLES:: + + sage: # optional - magma + sage: R = QQ[['y']] + sage: R._magma_init_(magma) + 'SageCreateWithNames(PowerSeriesRing(_sage_ref...),["y"])' + sage: S = magma(R) + sage: S + Power series ring in y over Rational Field + sage: S.1 + y + sage: magma(PowerSeriesRing(GF(7), 'x')) # needs sage.rings.finite_rings + Power series ring in x over GF(7) + """ + B = magma(self.base_ring()) + Bref = B._ref() + s = 'PowerSeriesRing(%s)' % (Bref) + return magma._with_names(s, self.variable_names()) + def _element_constructor_(self, f, prec=infinity, check=True): """ Coerce object to this power series ring. diff --git a/src/sage/rings/puiseux_series_ring.py b/src/sage/rings/puiseux_series_ring.py index 06b752f92df..891f5b104dc 100644 --- a/src/sage/rings/puiseux_series_ring.py +++ b/src/sage/rings/puiseux_series_ring.py @@ -277,6 +277,29 @@ def uniformizer(self): Element = PuiseuxSeries + def _magma_init_(self, magma): + """ + Used in converting this ring to the corresponding ring in MAGMA. + + EXAMPLES:: + + sage: # optional - magma + sage: R = PuiseuxSeriesRing(QQ, 'y') + sage: R._magma_init_(magma) + 'SageCreateWithNames(PuiseuxSeriesRing(_sage_ref...),["y"])' + sage: S = magma(R) + sage: S + Puiseux series field in y over Rational Field + sage: S.1 + y + sage: magma(PuiseuxSeriesRing(GF(7), 'x')) # needs sage.rings.finite_rings + Puiseux series field in x over GF(7) + """ + B = magma(self.base_ring()) + Bref = B._ref() + s = 'PuiseuxSeriesRing(%s)' % (Bref) + return magma._with_names(s, self.variable_names()) + def _element_constructor_(self, x, e=1, prec=infinity): r""" Construct a Puiseux series from ``x``. From 8f536598f81c790a6d5d1d49e30e2f963dab88b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 21 Jan 2025 13:39:36 -0500 Subject: [PATCH 085/187] conversion now works --- src/sage/ext_data/magma/sage/basic.m | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/ext_data/magma/sage/basic.m b/src/sage/ext_data/magma/sage/basic.m index a88ab8bf022..373e1b225bb 100644 --- a/src/sage/ext_data/magma/sage/basic.m +++ b/src/sage/ext_data/magma/sage/basic.m @@ -274,17 +274,20 @@ intrinsic Sage(X::ModTupRngElt) -> MonStgElt, BoolElt intrinsic Sage(X::RngSerPow) -> MonStgElt, BoolElt {} txt := "PowerSeriesRing(%o, %o)"; - return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; + var := Sprintf("['%o']", X.1); + return Sprintf(txt, Sage(BaseRing(X)), var), false; end intrinsic; intrinsic Sage(X::RngSerLaur) -> MonStgElt, BoolElt {} txt := "LaurentSeriesRing(%o, %o)"; - return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; + var := Sprintf("['%o']", X.1); + return Sprintf(txt, Sage(BaseRing(X)), var), false; end intrinsic; intrinsic Sage(X::RngSerPuis) -> MonStgElt, BoolElt {} txt := "PuiseuxSeriesRing(%o, %o)"; - return Sprintf(txt, Sage(BaseRing(X)), SageNamesHelper(X)), false; + var := Sprintf("['%o']", X.1); + return Sprintf(txt, Sage(BaseRing(X)), var), false; end intrinsic; From 76bfff834799086483277bdee3db9e0f1f1bc336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 21 Jan 2025 14:15:28 -0500 Subject: [PATCH 086/187] fixing the interface (almost) --- src/sage/interfaces/magma.py | 2 +- src/sage/rings/laurent_series_ring.py | 3 +++ src/sage/rings/power_series_ring.py | 3 +++ src/sage/rings/puiseux_series_ring.py | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index c34db3f4573..563a9865272 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -1235,7 +1235,7 @@ def bar_call(self, left, name, gens, nvals=1): magma = self # coerce each arg to be a Magma element if isinstance(gens, (list, tuple)): - gens = (magma(z) for z in gens) + gens = [magma(z) for z in gens] # make comma separated list of names (in Magma) of each of the gens v = ', '.join(w.name() for w in gens) else: diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index 831d4a71db2..ef417093ae2 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -422,6 +422,9 @@ def _magma_init_(self, magma): Laurent series field in y over Rational Field sage: S.1 y + sage: S.sage() == R + True + sage: magma(LaurentSeriesRing(GF(7), 'x')) # needs sage.rings.finite_rings Laurent series field in x over GF(7) """ diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index 8e7d7bfa22a..29d2574dcac 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -737,6 +737,9 @@ def _magma_init_(self, magma): Power series ring in y over Rational Field sage: S.1 y + sage: S.sage() == R + True + sage: magma(PowerSeriesRing(GF(7), 'x')) # needs sage.rings.finite_rings Power series ring in x over GF(7) """ diff --git a/src/sage/rings/puiseux_series_ring.py b/src/sage/rings/puiseux_series_ring.py index 891f5b104dc..dd5ec0d9249 100644 --- a/src/sage/rings/puiseux_series_ring.py +++ b/src/sage/rings/puiseux_series_ring.py @@ -292,6 +292,9 @@ def _magma_init_(self, magma): Puiseux series field in y over Rational Field sage: S.1 y + sage: S.sage() == R + True + sage: magma(PuiseuxSeriesRing(GF(7), 'x')) # needs sage.rings.finite_rings Puiseux series field in x over GF(7) """ From e1e4071ab63674641c9c3fe319451e694f8b4c17 Mon Sep 17 00:00:00 2001 From: Dave Witte Morris Date: Tue, 21 Jan 2025 12:51:00 -0700 Subject: [PATCH 087/187] #33034 add doctest that integral is 0 --- src/sage/misc/functional.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index 4399007c91d..e8b0dc7e1dd 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -776,6 +776,13 @@ def integral(x, *args, **kwds): ... sage: result # needs sage.symbolic -1/4 + + Verify that :issue:`33034` is fixed:: + + sage: f(x) = (x + sin(3*x)) * exp(-3*x*I) + sage: h(x) = f(x) - f(x).expand() + sage: integral(h(x), (x, 0, 2*pi)) + 0 """ if hasattr(x, 'integral'): return x.integral(*args, **kwds) From af669930cc0e2c41be3ad5a63313994d1c4cab1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 22 Jan 2025 03:13:34 -0500 Subject: [PATCH 088/187] add missing optional tags, fix linter --- src/sage/rings/laurent_series_ring.py | 1 + src/sage/rings/power_series_ring.py | 3 ++- src/sage/rings/puiseux_series_ring.py | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index ef417093ae2..7b81e74d338 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -425,6 +425,7 @@ def _magma_init_(self, magma): sage: S.sage() == R True + sage: # optional - magma sage: magma(LaurentSeriesRing(GF(7), 'x')) # needs sage.rings.finite_rings Laurent series field in x over GF(7) """ diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index 29d2574dcac..6d290188760 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -739,7 +739,8 @@ def _magma_init_(self, magma): y sage: S.sage() == R True - + + sage: # optional - magma sage: magma(PowerSeriesRing(GF(7), 'x')) # needs sage.rings.finite_rings Power series ring in x over GF(7) """ diff --git a/src/sage/rings/puiseux_series_ring.py b/src/sage/rings/puiseux_series_ring.py index dd5ec0d9249..52b2279c1c7 100644 --- a/src/sage/rings/puiseux_series_ring.py +++ b/src/sage/rings/puiseux_series_ring.py @@ -295,6 +295,7 @@ def _magma_init_(self, magma): sage: S.sage() == R True + sage: # optional - magma sage: magma(PuiseuxSeriesRing(GF(7), 'x')) # needs sage.rings.finite_rings Puiseux series field in x over GF(7) """ From bac8f3c6f0fa1f95c448c97cbe41574c4a28958f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 22 Jan 2025 04:40:02 -0500 Subject: [PATCH 089/187] fixing some optional-magma doctests --- src/sage/matrix/matrix_mod2_dense.pyx | 7 ++++--- src/sage/modular/btquotients/btquotient.py | 5 +++-- src/sage/rings/polynomial/multi_polynomial_ideal.py | 2 +- src/sage/rings/polynomial/pbori/pbori.pyx | 9 ++------- src/sage/rings/polynomial/polynomial_rational_flint.pyx | 2 +- .../hyperelliptic_curves/hyperelliptic_generic.py | 2 +- 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 676a2fc7f49..19859149186 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -1393,14 +1393,15 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse def _magma_init_(self, magma): """ - Return a string of ``self`` in ``Magma`` form. Does not return - ``Magma`` object but string. + Return a string of ``self`` in ``Magma`` form. + + This does not return a ``Magma`` object but a string. EXAMPLES:: sage: A = random_matrix(GF(2),3,3) sage: A._magma_init_(magma) # optional - magma - 'Matrix(GF(2),3,3,StringToIntegerSequence("0 1 0 0 1 1 0 0 0"))' + 'Matrix(GF(2),3,3,StringToIntegerSequence("..."))' sage: A = random_matrix(GF(2),100,100) sage: B = random_matrix(GF(2),100,100) sage: magma(A*B) == magma(A) * magma(B) # optional - magma diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index 280acec8874..67b8eb410f5 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -42,6 +42,7 @@ from collections import deque from sage.arith.misc import gcd, xgcd, kronecker_symbol, fundamental_discriminant +from sage.interfaces.magma import magma from sage.matrix.constructor import Matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method @@ -2307,7 +2308,7 @@ def get_extra_embedding_matrices(self): [1 0 2 0] [0 0 2 0] [0 0 0 0] - [1 0 2 2] + [1 2 2 0] ] """ if not self._use_magma or len(self._extra_level) == 0: @@ -2700,7 +2701,7 @@ def get_splitting_field(self): sage: X = BruhatTitsQuotient(5,11,use_magma=True) # optional - magma sage: X.get_splitting_field() # optional - magma - Number Field in a with defining polynomial X1^2 + 11 + Number Field in a with defining polynomial x^2 + 11 """ if not self._use_magma: raise NotImplementedError('Sage does not know yet how to work with the kind of orders that you are trying to use. Try installing Magma first and set it up so that Sage can use it.') diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 24239660dec..38582141f4b 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -408,7 +408,7 @@ def _groebner_basis_magma(self, deg_bound=None, prot=False, magma=magma_default) sage: I = sage.rings.ideal.Cyclic(R, 6) sage: gb = I.groebner_basis('magma:GroebnerBasis', deg_bound=4) sage: len(gb) - 5 + 7 """ R = self.ring() if not deg_bound: diff --git a/src/sage/rings/polynomial/pbori/pbori.pyx b/src/sage/rings/polynomial/pbori/pbori.pyx index 14a929c3238..aea86d0cad0 100644 --- a/src/sage/rings/polynomial/pbori/pbori.pyx +++ b/src/sage/rings/polynomial/pbori/pbori.pyx @@ -4927,14 +4927,9 @@ class BooleanPolynomialIdeal(MPolynomialIdeal): sage: I = F.ideal() sage: I.groebner_basis(algorithm='magma', prot='sage') # optional - magma Leading term degree: 1. Critical pairs: 148. - Leading term degree: 2. Critical pairs: 144. - Leading term degree: 3. Critical pairs: 462. - Leading term degree: 1. Critical pairs: 167. - Leading term degree: 2. Critical pairs: 147. - Leading term degree: 3. Critical pairs: 101 (all pairs of current degree eliminated by criteria). - + ... Highest degree reached during computation: 3. - Polynomial Sequence with 35 Polynomials in 36 Variables + Polynomial Sequence with ... Polynomials in 36 Variables TESTS: diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pyx b/src/sage/rings/polynomial/polynomial_rational_flint.pyx index 979877606a7..e1b9e3c5a04 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pyx @@ -2162,7 +2162,7 @@ cdef class Polynomial_rational_flint(Polynomial): Transitive group number 183 of degree 12 sage: f.galois_group(algorithm='magma') # optional - magma - Transitive group number 5 of degree 4 + Transitive group number 183 of degree 12 TESTS: diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py index 61cd934c0a0..c8279e47391 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py @@ -669,7 +669,7 @@ def _magma_init_(self, magma): Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 + x^10*y = x^3 + x + 2 sage: D = magma(C); D # needs sage.rings.finite_rings - Hyperelliptic Curve defined by y^2 + (x^10)*y = x^3 + x + 2 over GF(3^2) + Hyperelliptic Curve defined by y^2 + x^10*y = x^3 + x + 2 over GF(3^2) sage: D.sage() # needs sage.rings.finite_rings Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 + x^10*y = x^3 + x + 2 From 6f957f19bcfd7a0b54e1ad49c21d7972a610f1f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 22 Jan 2025 05:27:06 -0500 Subject: [PATCH 090/187] fixing one issue --- src/sage/ext_data/magma/sage/basic.m | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/sage/ext_data/magma/sage/basic.m b/src/sage/ext_data/magma/sage/basic.m index 373e1b225bb..71ebea4fa84 100644 --- a/src/sage/ext_data/magma/sage/basic.m +++ b/src/sage/ext_data/magma/sage/basic.m @@ -158,8 +158,9 @@ intrinsic SageNamesHelper(X::.) -> MonStgElt return "(" * (&* [ Sprintf("'x%o', ", j) : j in [ 1..i ] ]) * ")"; else /* named variables */ - return "(" * (&* [ Sprintf("'%o', ", X.j) : j in [ 1..i ] ]) * ")"; - end if; + return "(" * (&* [ Sprintf("'%o'.replace('.', ''), ", X.j) : j in [ 1..i ] ]) * ")"; + +end if; end intrinsic; intrinsic Sage(X::RngUPol) -> MonStgElt, BoolElt @@ -191,9 +192,16 @@ intrinsic Sage(X::RngMPolElt) -> MonStgElt, BoolElt intrinsic Sage(K::FldNum) -> MonStgElt, BoolElt {} - names := [Sprintf("'%o'.replace('$.', 'a').replace('.', '')", a) : a in GeneratorsSequence(K)]; - polynomials := DefiningPolynomial(K); - return Sprintf("NumberField(%o, %o)", Sage(polynomials), names), false; + gens := GeneratorsSequence(K); + if "$" in Sprint(gens[1]) then + /* unnamed variables */ + names := "(" * (&* [ Sprintf("'a%o', ", j) : j in [ 1..#gens ] ]) * ")"; + else + /* named variables */ + names := "(" * (&* [ Sprintf("'%o'.replace('.', ''), ", a) : a in gens]) * ")"; + end if; + polynomials := DefiningPolynomial(K); + return Sprintf("NumberField(%o, %o)", Sage(polynomials), names), false; end intrinsic; intrinsic Sage(A::FldNumElt) -> MonStgElt, BoolElt From b1ae7383d87ac72364ae75bb32a18c3a662dbc7f Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Wed, 22 Jan 2025 23:09:34 +0700 Subject: [PATCH 091/187] Test pip editable install with meson --- .github/workflows/ci-meson.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-meson.yml b/.github/workflows/ci-meson.yml index ab073aae87c..56d01aaffbb 100644 --- a/.github/workflows/ci-meson.yml +++ b/.github/workflows/ci-meson.yml @@ -16,7 +16,7 @@ concurrency: jobs: test: - name: Conda (${{ matrix.os }}, Python ${{ matrix.python }}) + name: Conda (${{ matrix.os }}, Python ${{ matrix.python }}${{ matrix.editable && ', editable' || '' }}) runs-on: ${{ matrix.os }}-latest strategy: @@ -24,6 +24,7 @@ jobs: matrix: os: [ubuntu] python: ['3.11', '3.12'] + editable: [false, true] steps: - uses: actions/checkout@v4 @@ -70,7 +71,7 @@ jobs: export CC="ccache $CC" export CXX="ccache $CXX" # Use --no-deps and pip check below to verify that all necessary dependencies are installed via conda - pip install --no-build-isolation --no-deps --config-settings=builddir=builddir . -v + pip install --no-build-isolation --no-deps --config-settings=builddir=builddir ${{ matrix.editable && '--editable' || '' }} . -v - name: Verify dependencies shell: bash -l {0} @@ -80,7 +81,9 @@ jobs: shell: bash -l {0} run: | # We don't install sage_setup, so don't try to test it - rm -R ./src/sage_setup/ + # If editable then deleting the directory will cause sage to detect rebuild, which will cause ninja to fail + # so we don't delete the directory in this case + ${{ matrix.editable && 'true' || 'rm -R ./src/sage_setup/' }} ./sage -t --all -p4 - name: Upload log From 47ffe4449b5e6a514818854eae67850bf81213f8 Mon Sep 17 00:00:00 2001 From: Noel Roemmele Date: Fri, 24 Jan 2025 00:30:01 -0700 Subject: [PATCH 092/187] 24801 Fixed error causing the function random_diagonalizable_matrix to only return a matrix over the rational field. --- src/sage/matrix/special.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/sage/matrix/special.py b/src/sage/matrix/special.py index dbb0214994e..f9ff9be8b0c 100644 --- a/src/sage/matrix/special.py +++ b/src/sage/matrix/special.py @@ -3126,7 +3126,7 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): ....: eigenvalues=[2+I, 2-I, 2], dimensions=[1,1,1]) Traceback (most recent call last): ... - TypeError: eigenvalues must be integers. + TypeError: eigenvalues must be elements of the corresponding ring. Diagonal matrices must be square. :: @@ -3177,6 +3177,11 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): ... ValueError: each eigenvalue must have a corresponding dimension and each dimension a corresponding eigenvalue. + The elements of the random matrix must be a member of the correct corresponding ring. :: + sage: K = GF(3) + sage: random_matrix(K, 3,3,algorithm="diagonalizable").parent() + Full MatrixSpace of 3 by 3 dense matrices over Finite Field of size 3 + .. TODO:: Modify the routine to allow for complex eigenvalues. @@ -3189,6 +3194,9 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): from sage.misc.prandom import randint size = parent.nrows() + ring = parent.base_ring() + if ring == QQ: + ring = ZZ if parent.nrows() != parent.ncols(): raise TypeError("a diagonalizable matrix must be square.") if eigenvalues is not None and dimensions is None: @@ -3199,7 +3207,7 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): values = [] # create a list with "size" number of entries for eigen_index in range(size): - eigenvalue = randint(-10, 10) + eigenvalue = ring(randint(-10, 10)) values.append(eigenvalue) values.sort() dimensions = [] @@ -3214,8 +3222,8 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): size_check = 0 for check in range(len(dimensions)): size_check = size_check + dimensions[check] - if not all(x in ZZ for x in eigenvalues): - raise TypeError("eigenvalues must be integers.") + if not all(x in ring for x in eigenvalues): + raise TypeError("eigenvalues must be elements of the corresponding ring.") if size != size_check: raise ValueError("the size of the matrix must equal the sum of the dimensions.") if min(dimensions) < 1: @@ -3227,7 +3235,7 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): dimensions = [x[0] for x in dimensions_sort] eigenvalues = [x[1] for x in dimensions_sort] # Create the matrix of eigenvalues on the diagonal. Use a lower limit and upper limit determined by the eigenvalue dimensions. - diagonal_matrix = matrix(QQ, size) + diagonal_matrix = matrix(ring, size) up_bound = 0 low_bound = 0 for row_index in range(len(dimensions)): @@ -3237,7 +3245,7 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): low_bound = low_bound+dimensions[row_index] # Create a matrix to hold each of the eigenvectors as its columns, begin with an identity matrix so that after row and column # operations the resulting matrix will be unimodular. - eigenvector_matrix = matrix(QQ, size, size, 1) + eigenvector_matrix = matrix(ring, size, size, 1) upper_limit = 0 lower_limit = 0 # run the routine over the necessary number of columns corresponding eigenvalue dimension. From 13d74a31b13471ceacc3a16b7206ca25e83339c5 Mon Sep 17 00:00:00 2001 From: Noel Roemmele Date: Fri, 24 Jan 2025 01:14:40 -0700 Subject: [PATCH 093/187] 24801 Updated documentation of random_diagonalizable_matrix. --- src/sage/matrix/special.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sage/matrix/special.py b/src/sage/matrix/special.py index f9ff9be8b0c..8a486772bdb 100644 --- a/src/sage/matrix/special.py +++ b/src/sage/matrix/special.py @@ -3054,15 +3054,15 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): """ Create a random matrix that diagonalizes nicely. - To be used as a teaching tool. Return matrices have only real - eigenvalues. + To be used as a teaching tool. If the ring used is QQ then return matrices + have real eigenvalues. Otherwise eignevalues are elements of the ring. INPUT: If eigenvalues and dimensions are not specified in a list, they will be assigned randomly. - - ``parent`` -- the desired size of the square matrix + - ``parent`` -- the matrix space required - ``eigenvalues`` -- the list of desired eigenvalues (default=None) @@ -3071,9 +3071,10 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): OUTPUT: - A square, diagonalizable, matrix with only integer entries. The - eigenspaces of this matrix, if computed by hand, give basis - vectors with only integer entries. + A square, diagonalizable, matrix. If the ring used is QQ then we have + integer entries. Otherwise entries are elements of the ring. If the + ring used is QQ the eigenspaces of this matrix, if computed by hand, + give basis vectors with only integer entries. .. NOTE:: @@ -3120,7 +3121,7 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): TESTS: - Eigenvalues must all be integers. :: + Eigenvalues must all be elements of the ring. :: sage: random_matrix(QQ, 3, algorithm='diagonalizable', # needs sage.symbolic ....: eigenvalues=[2+I, 2-I, 2], dimensions=[1,1,1]) From 44ad9b4e3645be7ff48df728e18b5c582bee4729 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Fri, 24 Jan 2025 19:10:45 +0700 Subject: [PATCH 094/187] Try to use Python integers --- src/sage/doctest/util.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/doctest/util.py b/src/sage/doctest/util.py index 47ed4e767ee..9fec38f486d 100644 --- a/src/sage/doctest/util.py +++ b/src/sage/doctest/util.py @@ -817,7 +817,9 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = The test above requires a large tolerance, because both ``time.sleep`` and ``from posix.unistd cimport usleep`` may have slowdown on the order of 0.1s on Mac, likely because the system is idle and GitHub CI switches the program out, - and context switch back takes time. So we use busy wait instead:: + and context switch back takes time. Besides, there is an issue with ``Integer`` + destructor, see ``_ + So we use busy wait and Python integers:: sage: # needs sage.misc.cython sage: cython(r''' @@ -841,17 +843,17 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = ....: if start_time.tv_sec > target_time.tv_sec or (start_time.tv_sec == target_time.tv_sec and start_time.tv_nsec >= target_time.tv_nsec): ....: break ....: ''') - sage: with ensure_interruptible_after(2) as data: interruptible_sleep(1) + sage: with ensure_interruptible_after(2) as data: interruptible_sleep(1r) Traceback (most recent call last): ... RuntimeError: Function terminates early after 1.00... < 2.0000 seconds - sage: with ensure_interruptible_after(1) as data: uninterruptible_sleep(2) + sage: with ensure_interruptible_after(1) as data: uninterruptible_sleep(2r) Traceback (most recent call last): ... RuntimeError: Function is not interruptible within 1.0000 seconds, only after 2.00... seconds sage: data # abs tol 0.01 {'alarm_raised': True, 'elapsed': 2.0} - sage: with ensure_interruptible_after(1): uninterruptible_sleep(2); raise RuntimeError + sage: with ensure_interruptible_after(1): uninterruptible_sleep(2r); raise RuntimeError Traceback (most recent call last): ... RuntimeError: Function is not interruptible within 1.0000 seconds, only after 2.00... seconds @@ -870,7 +872,7 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = seconds = float(seconds) max_wait_after_interrupt = float(max_wait_after_interrupt) inaccuracy_tolerance = float(inaccuracy_tolerance) - # use Python float to avoid unexplained slowdown with Sage objects + # use Python float to avoid slowdown with Sage Integer (see https://github.com/sagemath/cysignals/issues/215) data = {} start_time = walltime() alarm(seconds) From 59756a1b17ea9b9fc7e3f1efb1feb24383e632bd Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sun, 5 Jan 2025 00:19:12 +0700 Subject: [PATCH 095/187] Specify use_sources=True in cython compilation --- src/sage/misc/cython.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 29c013eab19..c85be325c3d 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -60,7 +60,7 @@ def _standard_libs_libdirs_incdirs_aliases(): if SAGE_LOCAL: standard_libdirs.append(os.path.join(SAGE_LOCAL, "lib")) standard_libdirs.extend(aliases["CBLAS_LIBDIR"] + aliases["NTL_LIBDIR"]) - standard_incdirs = sage_include_directories() + aliases["CBLAS_INCDIR"] + aliases["NTL_INCDIR"] + standard_incdirs = sage_include_directories(use_sources=True) + aliases["CBLAS_INCDIR"] + aliases["NTL_INCDIR"] return standard_libs, standard_libdirs, standard_incdirs, aliases ################################################################ From 3709ec8f6a4c8b36e882531242c09042de41d8d1 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sat, 25 Jan 2025 09:03:37 +0700 Subject: [PATCH 096/187] Fix build with meson documentation --- src/doc/en/installation/meson.rst | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/doc/en/installation/meson.rst b/src/doc/en/installation/meson.rst index e0051dbbf68..45ba64c4100 100644 --- a/src/doc/en/installation/meson.rst +++ b/src/doc/en/installation/meson.rst @@ -88,12 +88,11 @@ To configure the project, we need to run the following command: $ meson setup builddir --prefix=$PWD/build-install This will create a build directory ``builddir`` that will hold the build artifacts. -The ``--prefix`` option specifies the directory where the Sage will be installed. +The ``--prefix`` option specifies the directory where the Sage will be installed, +and can be omitted when ``pip`` is used to install as explained below. -If pip is used as above, ``builddir`` is set to be +If pip is used as above with ``--editable``, ``builddir`` is set to be ``build/cp[Python major version][Python minor version]``, such as ``build/cp311``. -``--prefix=`` can be left unspecified, when conda is used then meson will -install to the conda environment e.g. ``$HOME/miniforge3/envs/sage-dev/``. To compile the project, run the following command: @@ -117,7 +116,8 @@ Usually, this directory is not on your Python path, so you have to use: When editable install is used, it is not necessary to reinstall after each compilation. -Alternatively, we can still use pip to install: +Alternatively, we can still use pip to install (which does not require specifying +``--prefix`` in advance and automatically works with conda environment): .. CODE-BLOCK:: shell-session @@ -134,7 +134,11 @@ Alternatively, we can still use pip to install: $ meson setup builddir --prefix=/usr --libdir=... -Dcpp_args=... $ meson compile -C builddir $ DESTDIR=/path/to/staging/root meson install -C builddir - + + With the `default `_ prefix + being ``/usr/local``, it may then install to + ``$DESTDIR/usr/local/lib/python3.12/site-packages/sage``. + See `Meson's quick guide `_ and `Meson's install guide `_ for more information. @@ -144,6 +148,7 @@ Miscellaneous tips The environment variable ``MESONPY_EDITABLE_VERBOSE=1`` can be set while running ``./sage``, so that when Cython files are recompiled a message is printed out. +See ``_. If a new ``.pyx`` file is added, it need to be added to ``meson.build`` file in the containing directory. From 7eca8049f238cb3f367ed6c773513d6eed3645f7 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sat, 25 Jan 2025 10:16:37 +0700 Subject: [PATCH 097/187] Add workaround to make tests work on Python 3.12 --- src/sage/doctest/util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/doctest/util.py b/src/sage/doctest/util.py index 9fec38f486d..a62d48cfa19 100644 --- a/src/sage/doctest/util.py +++ b/src/sage/doctest/util.py @@ -880,7 +880,8 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = try: yield data - except AlarmInterrupt: + except AlarmInterrupt as e: + e.__traceback__ = None # workaround for https://github.com/python/cpython/pull/129276 alarm_raised = True finally: before_cancel_alarm_elapsed = walltime() - start_time From 9259991bb6945664163f99b2043d3ce11933e554 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sat, 25 Jan 2025 12:11:23 +0700 Subject: [PATCH 098/187] Retrigger CI From 5f3eafa8d256f31a762c6ac75141e90c4b969440 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sat, 25 Jan 2025 15:04:20 +0700 Subject: [PATCH 099/187] Revert "Specify use_sources=True in cython compilation" This reverts commit 59756a1b17ea9b9fc7e3f1efb1feb24383e632bd. --- src/sage/misc/cython.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index c85be325c3d..29c013eab19 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -60,7 +60,7 @@ def _standard_libs_libdirs_incdirs_aliases(): if SAGE_LOCAL: standard_libdirs.append(os.path.join(SAGE_LOCAL, "lib")) standard_libdirs.extend(aliases["CBLAS_LIBDIR"] + aliases["NTL_LIBDIR"]) - standard_incdirs = sage_include_directories(use_sources=True) + aliases["CBLAS_INCDIR"] + aliases["NTL_INCDIR"] + standard_incdirs = sage_include_directories() + aliases["CBLAS_INCDIR"] + aliases["NTL_INCDIR"] return standard_libs, standard_libdirs, standard_incdirs, aliases ################################################################ From e6a2aa118465177c7f069c3fe03c523cef20ec5b Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 26 Jan 2025 13:32:29 +0100 Subject: [PATCH 100/187] #39285: suggested changes --- src/sage/graphs/generic_graph.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 7cf9e31a711..64df23dee75 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -19815,7 +19815,7 @@ def cartesian_product(self, other, immutable=None): sage: B.is_isomorphic(Q.subgraph(V)) # needs sage.combinat True - Check the behavior of parameter `ìmmutable``:: + Check the behavior of parameter ``immutable``:: sage: A = Graph([(0, 1)]) sage: B = Graph([('a', 'b')], immutable=True) @@ -19930,7 +19930,7 @@ def tensor_product(self, other, immutable=None): sage: T.is_isomorphic(digraphs.DeBruijn(2 * 3, 3)) True - Check the behavior of parameter `ìmmutable``:: + Check the behavior of parameter ``immutable``:: sage: A = Graph([(0, 1)]) sage: B = Graph([('a', 'b')], immutable=True) @@ -20040,7 +20040,7 @@ def lexicographic_product(self, other, immutable=None): sage: T.is_isomorphic(J.lexicographic_product(I)) False - Check the behavior of parameter `ìmmutable``:: + Check the behavior of parameter ``immutable``:: sage: A = Graph([(0, 1)]) sage: B = Graph([('a', 'b')], immutable=True) @@ -20152,7 +20152,7 @@ def strong_product(self, other, immutable=None): sage: product_size == expected True - Check the behavior of parameter `ìmmutable``:: + Check the behavior of parameter ``immutable``:: sage: A = Graph([(0, 1)]) sage: B = Graph([('a', 'b')], immutable=True) @@ -20266,7 +20266,7 @@ def disjunctive_product(self, other, immutable=None): sage: T.is_isomorphic(J.disjunctive_product(I)) True - Check the behavior of parameter `ìmmutable``:: + Check the behavior of parameter ``immutable``:: sage: A = Graph([(0, 1)]) sage: B = Graph([('a', 'b')], immutable=True) From 35df246b90ddede5d4ad1ed3e15a5203ae14e89a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 26 Jan 2025 13:41:36 +0100 Subject: [PATCH 101/187] inline an inner function in random two-sphere (for speed) --- src/sage/graphs/generators/random.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 821068763b3..76bd7bc50c4 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -2320,21 +2320,16 @@ def RandomTriangulation(n, set_position=False, k=3, seed=None): pattern = ['in', 'in', 'in', 'lf', 'in'] # 'partial closures' - def rotate_word_to_next_occurrence(word): - """ - Rotate ``word`` so that the given pattern occurs at the beginning. - - If the given pattern is not found, return the empty list. - """ + # We greedily perform the replacements 'in1,in2,in3,lf,in3'->'in1,in3'. + while True: + # first we rotate the word to it starts with pattern + word2 = [] N = len(word) for i in range(N): if all(word[(i + j) % N][0] == pattern[j] for j in range(5)): - return word[i:] + word[:i] - return [] + word2 = word[i:] + word[:i] + break - # We greedily perform the replacements 'in1,in2,in3,lf,in3'->'in1,in3'. - while True: - word2 = rotate_word_to_next_occurrence(word) if len(word2) >= 5: word = [word2[0]] + word2[4:] in1, in2, in3 = (u[1] for u in word2[:3]) From 8395396406de76ac3e19dc07c29b95ec636c46dc Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 26 Jan 2025 19:11:52 +0530 Subject: [PATCH 102/187] added doctests for is_brick() --- src/sage/graphs/matching_covered_graph.py | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index c06d9a30aec..ddf4def727b 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2915,6 +2915,38 @@ def is_brick(self, coNP_certificate=False): sage: G.is_bicritical() True + Examples of nonbipartite matching covered graphs that are not + bricks:: + + sage: H = Graph([ + ....: (0, 3), (0, 4), (0, 7), + ....: (1, 3), (1, 5), (1, 7), + ....: (2, 3), (2, 6), (2, 7), + ....: (4, 5), (4, 6), (5, 6) + ....: ]) + sage: G = MatchingCoveredGraph(H) + sage: G.is_bipartite() + False + sage: G.is_bicritical() + False + sage: G.is_triconnected() + True + sage: G.is_brick() + False + sage: H = Graph([ + ....: (0, 1), (0, 2), (0, 3), (0, 4), (1, 2), + ....: (1, 5), (2, 5), (3, 4), (3, 5), (4, 5) + ....: ]) + sage: G = MatchingCoveredGraph(H) + sage: G.is_bipartite() + False + sage: G.is_bicritical() + True + sage: G.is_triconnected() + False + sage: G.is_brick() + False + One may set the ``coNP_certificate`` to be ``True``:: sage: K4 = graphs.CompleteGraph(4) From fa51817c5b7551a5bcc009780fea8ab301b65de8 Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Mon, 27 Jan 2025 04:06:29 +0200 Subject: [PATCH 103/187] Correct method sparse_paving --- src/sage/matroids/matroid.pyx | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index cee2b831e5b..208a8544311 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -6212,33 +6212,45 @@ cdef class Matroid(SageObject): False """ if self.rank() >= 2: - for X in combinations(self.groundset(), self.rank() - 1): - if not self._is_independent(frozenset(X)): - return False + for _ in self.dependent_sets_iterator(self.rank() - 1): + return False return True cpdef bint is_sparse_paving(self) noexcept: """ Return if ``self`` is sparse-paving. - A matroid is sparse-paving if the symmetric difference of every pair - of circuits is greater than 2. + A matroid is sparse-paving if it is paving and its dual is paving. OUTPUT: boolean + ALGORITHM: + + First, check that the matroid is paving. Then, verify that the + symmetric difference of every pair of distinct `r`-circuits is greater + than 2. + EXAMPLES:: sage: M = matroids.catalog.Vamos() sage: M.is_sparse_paving() + True + sage: M = matroids.catalog.N1() + sage: M.is_sparse_paving() False - sage: M = matroids.catalog.Fano() + + TESTS:: + + sage: M = matroids.Uniform(4, 50) # fast because we don't check M.dual().is_paving() sage: M.is_sparse_paving() True + sage: for M in matroids.AllMatroids(8): + ....: assert M.is_sparse_paving() == (M.is_paving() and M.dual().is_paving()) """ if not self.is_paving(): return False from itertools import combinations - for (C1, C2) in combinations(self.circuits_iterator(), 2): + for (C1, C2) in combinations(self.nonbases_iterator(), 2): if len(C1 ^ C2) <= 2: return False return True From b046f8d308066fbc268551f12343b25c97abe0b7 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sun, 19 Jan 2025 12:09:58 -0600 Subject: [PATCH 104/187] bump fpylll to 0.6.3 --- build/pkgs/fpylll/checksums.ini | 4 ++-- build/pkgs/fpylll/package-version.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/fpylll/checksums.ini b/build/pkgs/fpylll/checksums.ini index 188e768b787..b02fd91bedc 100644 --- a/build/pkgs/fpylll/checksums.ini +++ b/build/pkgs/fpylll/checksums.ini @@ -1,4 +1,4 @@ tarball=fpylll-VERSION.tar.gz -sha1=c0bcf8c5583ebf614da9b26710a2c835d498bf34 -sha256=dfd9529a26c50993a2a716177debd7994312219070574cad31b35b4f0c040a19 +sha1=9399eea85c3f4cbd0dc33893532a324adc905d4e +sha256=a3f4049e1c27b52136f71f722312c4265e3a2dcb5722536ec8247d708dd4248a upstream_url=https://files.pythonhosted.org/packages/source/f/fpylll/fpylll-VERSION.tar.gz diff --git a/build/pkgs/fpylll/package-version.txt b/build/pkgs/fpylll/package-version.txt index ee6cdce3c29..844f6a91acb 100644 --- a/build/pkgs/fpylll/package-version.txt +++ b/build/pkgs/fpylll/package-version.txt @@ -1 +1 @@ -0.6.1 +0.6.3 From a7318b0bc7055320738c2653760e21a4a3420a71 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sun, 26 Jan 2025 12:11:48 -0600 Subject: [PATCH 105/187] also bump fplll to 5.5.0 --- build/pkgs/fplll/checksums.ini | 4 ++-- build/pkgs/fplll/package-version.txt | 2 +- build/pkgs/fplll/spkg-configure.m4 | 2 +- build/pkgs/fpylll/dependencies | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/pkgs/fplll/checksums.ini b/build/pkgs/fplll/checksums.ini index 7ad5ac91a3b..952e43611c3 100644 --- a/build/pkgs/fplll/checksums.ini +++ b/build/pkgs/fplll/checksums.ini @@ -1,4 +1,4 @@ tarball=fplll-VERSION.tar.gz -sha1=607f5922109d93ddd5a05419682511e26579f9d6 -sha256=76d3778f0326597ed7505bab19493a9bf6b73a5c5ca614e8fb82f42105c57d00 +sha1=b40beea04697cccb26c9e6140935039ef87371df +sha256=f0af6bdd0ebd5871e87ff3ef7737cb5360b1e38181a4e5a8c1236f3476fec3b2 upstream_url=https://github.com/fplll/fplll/releases/download/VERSION/fplll-VERSION.tar.gz diff --git a/build/pkgs/fplll/package-version.txt b/build/pkgs/fplll/package-version.txt index 8ce222e90f7..d50359de185 100644 --- a/build/pkgs/fplll/package-version.txt +++ b/build/pkgs/fplll/package-version.txt @@ -1 +1 @@ -5.4.5 +5.5.0 diff --git a/build/pkgs/fplll/spkg-configure.m4 b/build/pkgs/fplll/spkg-configure.m4 index 053c9c74daf..468db6c3f29 100644 --- a/build/pkgs/fplll/spkg-configure.m4 +++ b/build/pkgs/fplll/spkg-configure.m4 @@ -8,7 +8,7 @@ SAGE_SPKG_CONFIGURE([fplll], [ dnl Issue #31025: FPLLL/FPyLLL make no guarantee regarding compatibility dnl other than "whatever versions were released at the same time should work together" PKG_CHECK_MODULES([FPLLL], - [fplll >= 5.4.5 fplll <= 5.4.5], + [fplll >= 5.5.0], [ AC_MSG_CHECKING([whether BKZ default strategy JSON is installed]) AC_LANG_PUSH([C++]) diff --git a/build/pkgs/fpylll/dependencies b/build/pkgs/fpylll/dependencies index 03eb318a449..8faa54d6781 100644 --- a/build/pkgs/fpylll/dependencies +++ b/build/pkgs/fpylll/dependencies @@ -1,4 +1,4 @@ - cython cysignals numpy fplll | $(PYTHON_TOOLCHAIN) $(PYTHON) +cython cysignals numpy fplll | $(PYTHON_TOOLCHAIN) $(PYTHON) ---------- All lines of this file are ignored except the first. From 0a94fbba21f5b0f1950413439b6ae5b8e622ac7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 27 Jan 2025 10:32:56 +0100 Subject: [PATCH 106/187] fixing PLW0120 --- src/sage/combinat/diagram_algebras.py | 3 +-- src/sage/combinat/regular_sequence.py | 3 +-- src/sage/combinat/words/finite_word.py | 9 +++------ src/sage/combinat/words/morphic.py | 5 ++--- src/sage/combinat/words/morphism.py | 3 +-- src/sage/combinat/words/word_generators.py | 9 +++------ src/sage/modular/modform/element.py | 5 ++--- src/sage/rings/polynomial/binary_form_reduce.py | 7 +++---- src/sage/schemes/elliptic_curves/hom.py | 3 +-- src/sage/schemes/elliptic_curves/hom_velusqrt.py | 3 +-- 10 files changed, 18 insertions(+), 32 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 841c9efe9d3..758a1f1432d 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -4802,8 +4802,7 @@ def insert_pairing(cur, intervals): else: level.append(cur) return # We have stopped - else: - intervals.append([cur]) + intervals.append([cur]) # Build a set of intervals that defines where to draw the diagram intervals = [[]] propogating = [] diff --git a/src/sage/combinat/regular_sequence.py b/src/sage/combinat/regular_sequence.py index 6ad1c12c088..5ce785d6a42 100644 --- a/src/sage/combinat/regular_sequence.py +++ b/src/sage/combinat/regular_sequence.py @@ -1882,8 +1882,7 @@ def some_inverse_U_matrix(lines): return U.inverse(), m_indices except ZeroDivisionError: pass - else: - raise RuntimeError('no invertible submatrix found') + raise RuntimeError('no invertible submatrix found') def linear_combination_candidate(t_L, r_L, lines): r""" diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index ba9bf3f2157..a47c8006767 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -2367,8 +2367,7 @@ def longest_common_suffix(self, other): for i, (b, c) in iter: if b != c: return self[-i:] - else: - return self[-i-1:] + return self[-i-1:] def is_palindrome(self, f=None): r""" @@ -3739,8 +3738,7 @@ def is_subword_of(self, other): for e in other: if s == e: s = next(its) - else: - return False + return False except StopIteration: return True @@ -3881,8 +3879,7 @@ def is_lyndon(self) -> bool: else: # we found the first word in the lyndon factorization; return False - else: - return i == 0 + return i == 0 def lyndon_factorization(self): r""" diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 160f4e2243a..1d79d9dd1fc 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -344,8 +344,7 @@ def __iter__(self): try: for a in self._morphism.image(next(w)): yield self._coding[a] - else: - next_w = next(w) - w = chain([next_w], w, self._morphism.image(next_w)) + next_w = next(w) + w = chain([next_w], w, self._morphism.image(next_w)) except StopIteration: return diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 343fe8af9eb..3939e450b99 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -1550,8 +1550,7 @@ def _check_primitive(self): for image in self.images(): if not dom_alphabet <= set(image): return False - else: - return True + return True def is_primitive(self): r""" diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index 05ccb242508..a0150f8ed31 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -612,8 +612,7 @@ def _FibonacciWord_RecursiveConstructionIterator(self, alphabet=(0, 1)): for i in it: n += 1 yield alphabet[i] - else: - Fib1, Fib0 = Fib1 + Fib0, Fib1 + Fib1, Fib0 = Fib1 + Fib0, Fib1 def FixedPointOfMorphism(self, morphism, first_letter): r""" @@ -962,8 +961,7 @@ def _CharacteristicSturmianWord_LetterIterator(self, cf, alphabet=(0, 1)): for i in s1[n:]: n += 1 yield alphabet[i] - else: - s1, s0 = s1*next(cf) + s0, s1 + s1, s0 = s1*next(cf) + s0, s1 except StopIteration: return @@ -1306,8 +1304,7 @@ def _StandardEpisturmianWord_LetterIterator(self, directive_word): for x in w[n:]: n += 1 yield x - else: - w = W(w * W(next(d))).palindromic_closure() + w = W(w * W(next(d))).palindromic_closure() def MinimalSmoothPrefix(self, n): r""" diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 3fdabbfed7b..7b8a7e0e13f 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -2502,9 +2502,8 @@ def minimal_twist(self, p=None): h, tau = g.minimal_twist(p=None) M = chi.modulus().lcm(tau.modulus()) return (h, chi.extend(M)*tau.extend(M)) - else: - # f locally minimal at all p, hence globally minimal - return (self, DirichletGroup(1, self.base_ring())(1)) + # f locally minimal at all p, hence globally minimal + return (self, DirichletGroup(1, self.base_ring())(1)) p = ZZ(p) N = self.level() diff --git a/src/sage/rings/polynomial/binary_form_reduce.py b/src/sage/rings/polynomial/binary_form_reduce.py index 8d4c770072d..f56dfe459ac 100644 --- a/src/sage/rings/polynomial/binary_form_reduce.py +++ b/src/sage/rings/polynomial/binary_form_reduce.py @@ -232,10 +232,9 @@ def covariant_z0(F, z0_cov=False, prec=53, emb=None, error_limit=0.000001): z = v0[1].constant_coefficient() + v0[0].constant_coefficient()*CF.gen(0) err = z.diameter() # precision zz = (w - z).abs().lower() # difference in w and z - else: - # despite there is no break, this happens - if err > error_limit or err.is_NaN(): - raise ValueError("accuracy of Newton's root not within tolerance(%s > %s), increase precision" % (err, error_limit)) + # despite there is no break, this happens + if err > error_limit or err.is_NaN(): + raise ValueError("accuracy of Newton's root not within tolerance(%s > %s), increase precision" % (err, error_limit)) if z.imag().upper() <= z.diameter(): raise ArithmeticError("Newton's method converged to z not in the upper half plane") z = z.center() diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index 96700fa254d..aef794ed8f9 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -1199,8 +1199,7 @@ def compare_via_evaluation(left, right): if P._has_order_at_least(4*d + 1, attempts=50): # if P.height(precision=250) == 0: # slow sometimes return left._eval(P) == right._eval(P) - else: - assert False, "couldn't find a point of large enough order" + assert False, "couldn't find a point of large enough order" 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 d8cf1971f45..31968d8578f 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -581,8 +581,7 @@ def _point_outside_subgroup(P): Q = E.random_point() if n*Q or not P.weil_pairing(Q,n).is_one(): return Q - else: - raise NotImplementedError('could not find a point outside the kernel') + raise NotImplementedError('could not find a point outside the kernel') class EllipticCurveHom_velusqrt(EllipticCurveHom): From bb8b6460994660a84e2dd79e9d98370cc6e6b94b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 27 Jan 2025 11:18:02 +0100 Subject: [PATCH 107/187] use the faster binomial in combinat --- src/sage/combinat/affine_permutation.py | 40 +++++++++---------- src/sage/combinat/baxter_permutations.py | 19 ++++----- src/sage/combinat/blob_algebra.py | 29 ++++++-------- .../cluster_algebra_quiver/cluster_seed.py | 20 +++++----- src/sage/combinat/dyck_word.py | 7 ++-- src/sage/combinat/interval_posets.py | 6 +-- src/sage/combinat/posets/posets.py | 9 ++--- .../combinat/root_system/pieri_factors.py | 22 +++++----- src/sage/combinat/words/shuffle_product.py | 8 ++-- 9 files changed, 74 insertions(+), 86 deletions(-) diff --git a/src/sage/combinat/affine_permutation.py b/src/sage/combinat/affine_permutation.py index 74113055d13..536ccae8291 100644 --- a/src/sage/combinat/affine_permutation.py +++ b/src/sage/combinat/affine_permutation.py @@ -13,7 +13,6 @@ # **************************************************************************** from itertools import repeat -from sage.arith.misc import binomial from sage.categories.affine_weyl_groups import AffineWeylGroups from sage.combinat.composition import Composition from sage.combinat.partition import Partition @@ -77,13 +76,13 @@ def __init__(self, parent, lst, check=True): """ if check: lst = [ZZ(val) for val in lst] - self.k = parent.k + self.k = ZZ(parent.k) self.n = self.k + 1 - #This N doesn't matter for type A, but comes up in all other types. + # This N doesn't matter for type A, but comes up in all other types. if parent.cartan_type()[0] == 'A': self.N = self.n elif parent.cartan_type()[0] in ['B', 'C', 'D']: - self.N = 2*self.k + 1 + self.N = 2 * self.k + 1 elif parent.cartan_type()[0] == 'G': self.N = 6 else: @@ -245,7 +244,7 @@ def is_i_grassmannian(self, i=0, side='right') -> bool: """ return self == self.parent().one() or self.descents(side) == [i] - def index_set(self): + def index_set(self) -> tuple: r""" Index set of the affine permutation group. @@ -255,7 +254,7 @@ def index_set(self): sage: A.index_set() (0, 1, 2, 3, 4, 5, 6, 7) """ - return tuple(range(self.k+1)) + return tuple(range(self.k + 1)) def lower_covers(self, side='right'): r""" @@ -440,13 +439,14 @@ def check(self): if not self: return k = self.parent().k - #Type A. + # Type A if len(self) != k + 1: - raise ValueError("length of list must be k+1="+str(k+1)) - if binomial(k+2,2) != sum(self): - raise ValueError("window does not sum to " + str(binomial((k+2),2))) - l = sorted([i % (k+1) for i in self]) - if l != list(range(k+1)): + raise ValueError(f"length of list must be k+1={k + 1}") + sigma = (k + 2).binomial(2) + if sigma != sum(self): + raise ValueError(f"window does not sum to {sigma}") + l = sorted(i % (k + 1) for i in self) + if any(i != j for i, j in enumerate(l)): raise ValueError("entries must have distinct residues") def value(self, i, base_window=False): @@ -2001,9 +2001,9 @@ class AffinePermutationGroupGeneric(UniqueRepresentation, Parent): methods for the specific affine permutation groups. """ - #---------------------- - #Type-free methods. - #---------------------- + # ---------------------- + # Type-free methods. + # ---------------------- def __init__(self, cartan_type): r""" @@ -2014,13 +2014,13 @@ def __init__(self, cartan_type): """ Parent.__init__(self, category=AffineWeylGroups()) ct = CartanType(cartan_type) - self.k = ct.n + self.k = ZZ(ct.n) self.n = ct.rank() - #This N doesn't matter for type A, but comes up in all other types. + # This N doesn't matter for type A, but comes up in all other types. if ct.letter == 'A': self.N = self.k + 1 elif ct.letter == 'B' or ct.letter == 'C' or ct.letter == 'D': - self.N = 2*self.k + 1 + self.N = 2 * self.k + 1 elif ct.letter == 'G': self.N = 6 self._cartan_type = ct @@ -2034,14 +2034,14 @@ def _element_constructor_(self, *args, **keywords): """ return self.element_class(self, *args, **keywords) - def _repr_(self): + def _repr_(self) -> str: r""" TESTS:: sage: AffinePermutationGroup(['A',7,1]) The group of affine permutations of type ['A', 7, 1] """ - return "The group of affine permutations of type "+str(self.cartan_type()) + return "The group of affine permutations of type " + str(self.cartan_type()) def _test_enumeration(self, n=4, **options): r""" diff --git a/src/sage/combinat/baxter_permutations.py b/src/sage/combinat/baxter_permutations.py index 08b67b96540..6717dc59076 100644 --- a/src/sage/combinat/baxter_permutations.py +++ b/src/sage/combinat/baxter_permutations.py @@ -1,13 +1,11 @@ """ Baxter permutations """ - -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent -from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.combinat.permutation import Permutations - from sage.rings.integer_ring import ZZ +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation class BaxterPermutations(UniqueRepresentation, Parent): @@ -228,12 +226,11 @@ def cardinality(self): Integer Ring """ if self._n == 0: - return 1 - from sage.arith.misc import binomial - return sum((binomial(self._n + 1, k) * - binomial(self._n + 1, k + 1) * - binomial(self._n + 1, k + 2)) // - ((self._n + 1) * binomial(self._n + 1, 2)) + return ZZ.one() + n = self._n + 1 + return sum((n.binomial(k) * + n.binomial(k + 1) * + n.binomial(k + 2)) // (n * n.binomial(2)) for k in range(self._n)) diff --git a/src/sage/combinat/blob_algebra.py b/src/sage/combinat/blob_algebra.py index 595063a69fd..7477d6a8822 100644 --- a/src/sage/combinat/blob_algebra.py +++ b/src/sage/combinat/blob_algebra.py @@ -17,22 +17,19 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.element import Element, get_coercion_model -from sage.structure.richcmp import richcmp -#from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.misc.cachefunc import cached_method -from sage.combinat.subset import powerset -from sage.arith.misc import binomial -from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.algebras import Algebras +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.combinat.diagram_algebras import (TemperleyLiebDiagrams, diagram_latex, TL_diagram_ascii_art) -from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.dyck_word import DyckWords - -#@add_metaclass(InheritComparisonClasscallMetaclass) +from sage.combinat.free_module import CombinatorialFreeModule +from sage.combinat.subset import powerset +from sage.misc.cachefunc import cached_method +from sage.rings.integer_ring import ZZ +from sage.structure.element import Element, get_coercion_model +from sage.structure.parent import Parent +from sage.structure.richcmp import richcmp +from sage.structure.unique_representation import UniqueRepresentation class BlobDiagram(Element): @@ -167,7 +164,7 @@ def __init__(self, n): sage: BD4 = BlobDiagrams(4) sage: TestSuite(BD4).run() """ - self._n = n + self._n = ZZ(n) self._TL_diagrams = TemperleyLiebDiagrams(n) Parent.__init__(self, category=FiniteEnumeratedSets()) @@ -181,7 +178,7 @@ def _repr_(self): sage: BlobDiagrams(4) Blob diagrams of order 4 """ - return "Blob diagrams of order {}".format(self._n) + return f"Blob diagrams of order {self._n}" def cardinality(self): r""" @@ -194,7 +191,7 @@ def cardinality(self): sage: BD4.cardinality() 70 """ - return binomial(2*self._n, self._n) + return (2 * self._n).binomial(self._n) def order(self): r""" @@ -221,7 +218,7 @@ def base_set(self): sage: sorted(BD4.base_set()) [-4, -3, -2, -1, 1, 2, 3, 4] """ - return frozenset(range(1,self._n+1)).union(range(-self._n,0)) + return frozenset(range(1, self._n + 1)).union(range(-self._n, 0)) def _element_constructor_(self, marked, unmarked=None): r""" diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index 5ab85f84208..7860f4e0d87 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -332,7 +332,7 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user else: labelset = set(user_labels) # Sanitizes our ``user_labels`` to use Integers instead of ints - user_labels = [ZZ(x) if x in ZZ else x for x in user_labels] + user_labels = [Integer(x) if x in ZZ else x for x in user_labels] if labelset != set(self._nlist + self._mlist) and labelset != set(range(self._n + self._m)): raise ValueError('user_labels conflict with both the given' ' vertex labels and the default labels') @@ -3593,7 +3593,7 @@ def mutation_class_iter(self, depth=infinity, show_depth=False, else: orbits = [index for index in range(n) if index > i or sd2._M[index, i] != 0] - clusters[cl2] = [sd2, orbits, clusters[key][2]+[i]] + clusters[cl2] = [sd2, orbits, clusters[key][2] + [i]] if return_paths: yield (sd2, clusters[cl2][2]) else: @@ -3602,10 +3602,10 @@ def mutation_class_iter(self, depth=infinity, show_depth=False, if show_depth and gets_bigger: timer2 = time.time() dc = str(depth_counter) - dc += ' ' * (5-len(dc)) + dc += ' ' * (5 - len(dc)) nr = str(len(clusters)) - nr += ' ' * (10-len(nr)) - print(f"Depth: {dc} found: {nr} Time: {timer2-timer:.2f} s") + nr += ' ' * (10 - len(nr)) + print(f"Depth: {dc} found: {nr} Time: {timer2 - timer:.2f} s") def mutation_class(self, depth=infinity, show_depth=False, return_paths=False, up_to_equivalence=True, only_sink_source=False): @@ -4718,7 +4718,7 @@ def _produce_upper_cluster_algebra_element(self, vd, cList): for l in range(num_cols): denominator = denominator * (R.gen(l))**vd[i][0][l] # Each copy of a vector in vd contributes a factor of the Laurent polynomial calculated from it. - final = (numerator/denominator)**vd[i][1] + final = (numerator / denominator)**vd[i][1] finalP.append(final) laurentP = 1 # The UCA element for the vector a is the product of the elements produced from the vectors in its decomposition. @@ -4740,10 +4740,8 @@ def _bino(n, k): 0 """ if n >= 0: - from sage.arith.misc import binomial - return binomial(n, k) - else: - return 0 + return Integer(n).binomial(k) + return 0 def coeff_recurs(p, q, a1, a2, b, c): @@ -5192,7 +5190,7 @@ def almost_positive_root(self): mt = self._mutation_type._repr_() # mt is a string of the shape "['A', 15]" # where A is a single letter and 15 is an integer - Phi = RootSystem([mt[2: 3], ZZ(mt[6: -1])]) + Phi = RootSystem([mt[2: 3], Integer(mt[6: -1])]) Phiplus = Phi.root_lattice().simple_roots() if self.denominator() == 1: diff --git a/src/sage/combinat/dyck_word.py b/src/sage/combinat/dyck_word.py index df841984f31..e29c70dec78 100644 --- a/src/sage/combinat/dyck_word.py +++ b/src/sage/combinat/dyck_word.py @@ -544,13 +544,13 @@ def _repr_lattice(self, type=None, labelling=None, underpath=True) -> str: row = " " * (n - alst[-1] - 1) + final_fall + "\n" for i in range(n - 1): c = 0 - row = row + " "*(n-i-2-alst[-i-2]) + row = row + " " * (n-i-2-alst[-i-2]) c += n-i-2-alst[-i-2] if alst[-i-2]+1 != alst[-i-1]: row += " _" c += alst[-i-2] - alst[-i-1] if underpath: - row += "__"*(alst[-i-2]-alst[-i-1])+"|" + labels[-1] + "x "*(n-c-2-i) + " ."*i + "\n" + row += "__" * (alst[-i-2]-alst[-i-1]) + "|" + labels[-1] + "x "*(n-c-2-i) + " ." * i + "\n" else: row += "__"*(alst[-i-2]-alst[-i-1])+"| " + "x "*(n-c-2-i) + " ."*i + labels[-1] + "\n" labels.pop() @@ -3780,8 +3780,7 @@ def cardinality(self) -> int: ....: for p in range(7)) True """ - from sage.arith.misc import binomial - return (self.k1 - self.k2 + 1) * binomial(self.k1 + self.k2, self.k2) // (self.k1 + 1) + return (self.k1 - self.k2 + 1) * (self.k1 + self.k2).binomial(self.k2) // (self.k1 + 1) ################################################################ # Complete Dyck words diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index afdae758dfc..9fa34fd3986 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -47,6 +47,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer +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.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets @@ -3757,11 +3758,10 @@ def cardinality(self) -> Integer: sage: [TamariIntervalPosets(i).cardinality() for i in range(6)] [1, 1, 3, 13, 68, 399] """ - from sage.arith.misc import binomial n = self._size if n == 0: - return Integer(1) - return (2 * binomial(4 * n + 1, n - 1)) // (n * (n + 1)) + return ZZ.one() + return (2 * Integer(4 * n + 1).binomial(n - 1)) // (n * (n + 1)) # return Integer(2 * factorial(4*n+1)/(factorial(n+1)*factorial(3*n+2))) def __iter__(self) -> Iterator[TIP]: diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index a2039494ce4..0ab3588261a 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -292,7 +292,6 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod -from sage.arith.misc import binomial from sage.categories.category import Category from sage.categories.sets_cat import Sets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -1815,7 +1814,7 @@ def atkinson(self, a): for r in range(1, n + 1): new_a_spec.append(0) for i in range(max(1, r - n + k), min(r, k) + 1): - k_val = binomial(r - 1, i - 1) * binomial(n - r, k - i) + k_val = Integer(r - 1).binomial(i - 1) * Integer(n - r).binomial(k - i) new_a_spec[-1] += k_val * a_spec[i - 1] * n_lin_exts return new_a_spec @@ -5295,7 +5294,7 @@ def factor(self): dg = self._hasse_diagram if not dg.is_connected(): raise NotImplementedError('the poset is not connected') - if ZZ(dg.num_verts()).is_prime(): + if Integer(dg.num_verts()).is_prime(): return [self] G = dg.to_undirected() is_product, dic = G.is_cartesian_product(relabeling=True) @@ -6492,7 +6491,7 @@ def random_order_ideal(self, direction='down'): with seed(currseed): for _ in range(count): for element in range(n): - if random() % 2 == 1: + if random() % 2: # should use one random bit s = [state[i] for i in lower_covers[element]] if 1 not in s: if 2 not in s: @@ -8141,7 +8140,7 @@ def is_eulerian(self, k=None, certificate=False): n = self.cardinality() if n == 1: return True - if k is None and not certificate and n % 2 == 1: + if k is None and not certificate and n % 2: return False H = self._hasse_diagram diff --git a/src/sage/combinat/root_system/pieri_factors.py b/src/sage/combinat/root_system/pieri_factors.py index fa97defb73e..c1f2ba8afd3 100644 --- a/src/sage/combinat/root_system/pieri_factors.py +++ b/src/sage/combinat/root_system/pieri_factors.py @@ -11,22 +11,21 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +import sage.combinat.ranker +from sage.combinat.root_system.root_system import RootSystem +from sage.combinat.root_system.weyl_group import WeylGroup from sage.misc.cachefunc import cached_method -from sage.misc.constant_function import ConstantFunction from sage.misc.call import attrcall +from sage.misc.constant_function import ConstantFunction from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod -from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation +from sage.rings.infinity import infinity from sage.rings.integer import Integer from sage.rings.rational_field import QQ -from sage.rings.infinity import infinity -from sage.arith.misc import binomial -import sage.combinat.ranker from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet -from sage.combinat.root_system.root_system import RootSystem -from sage.combinat.root_system.weyl_group import WeylGroup +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation lazy_import('sage.graphs.digraph', 'DiGraph') lazy_import('sage.combinat.root_system.dynkin_diagram', 'DynkinDiagram') @@ -755,8 +754,7 @@ def cardinality(self): """ if self._min_length == len(self._min_support) and self._max_length == len(self._max_support) - 1: return Integer(2**(len(self._extra_support)) - 1) - else: - return self.generating_series(weight=ConstantFunction(1)) + return self.generating_series(weight=ConstantFunction(1)) def generating_series(self, weight=None): r""" @@ -774,7 +772,7 @@ def generating_series(self, weight=None): weight = self.default_weight() l_min = len(self._min_support) l_max = len(self._max_support) - return sum(binomial(l_max - l_min, l - l_min) * weight(l) + return sum(Integer(l_max - l_min).binomial(l - l_min) * weight(l) for l in range(self._min_length, self._max_length + 1)) def __iter__(self): diff --git a/src/sage/combinat/words/shuffle_product.py b/src/sage/combinat/words/shuffle_product.py index 5aea554b6b6..9d5c43dd73b 100644 --- a/src/sage/combinat/words/shuffle_product.py +++ b/src/sage/combinat/words/shuffle_product.py @@ -21,11 +21,11 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.combinat.words.word import Word_class, Word -from sage.arith.misc import binomial from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.combinat.integer_vector import IntegerVectors from sage.combinat.composition import Composition +from sage.combinat.integer_vector import IntegerVectors +from sage.combinat.words.word import Word_class, Word +from sage.rings.integer import Integer from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -174,7 +174,7 @@ def cardinality(self): """ len_w1 = self._w1.length() len_w2 = self._w2.length() - return binomial(len_w1 + len_w2, len_w1) + return Integer(len_w1 + len_w2).binomial(len_w1) def __iter__(self): """ From bf358eec7b61584724bb7aa0ae7cb3bebd1df233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 27 Jan 2025 11:53:57 +0100 Subject: [PATCH 108/187] using binomial method in modular --- src/sage/modular/dirichlet.py | 4 ++-- src/sage/modular/pollack_stevens/dist.pyx | 6 +++--- src/sage/modular/pollack_stevens/padic_lseries.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index f93984335bd..3d2ee75a7e7 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -62,7 +62,7 @@ import sage.rings.abc from sage.arith.functions import lcm -from sage.arith.misc import bernoulli, binomial, factorial, kronecker, factor, gcd, fundamental_discriminant, euler_phi, valuation +from sage.arith.misc import bernoulli, factorial, kronecker, factor, gcd, fundamental_discriminant, euler_phi, valuation from sage.categories.map import Map from sage.categories.objects import Objects from sage.categories.rings import Rings @@ -724,7 +724,7 @@ def bernoulli(self, k, algorithm='recurrence', cache=True, **opts): def S(n): return sum(v[r] * r**n for r in range(1, N)) - ber = sum(binomial(k, j) * bernoulli(j, **opts) * + ber = sum(ZZ(k).binomial(j) * bernoulli(j, **opts) * N**(j - 1) * S(k - j) for j in range(k + 1)) elif algorithm == "definition": # This is better since it computes the same thing, but requires diff --git a/src/sage/modular/pollack_stevens/dist.pyx b/src/sage/modular/pollack_stevens/dist.pyx index 9ed53a955c9..893b1dbf602 100644 --- a/src/sage/modular/pollack_stevens/dist.pyx +++ b/src/sage/modular/pollack_stevens/dist.pyx @@ -27,7 +27,7 @@ REFERENCES: # **************************************************************************** import operator -from sage.arith.misc import binomial, bernoulli +from sage.arith.misc import bernoulli from sage.categories.fields import Fields from sage.matrix.constructor import matrix from sage.matrix.matrix cimport Matrix @@ -1129,7 +1129,7 @@ cdef class Dist_vector(Dist): """ # assert self._moments[0][0]==0, "not total measure zero" # print("result accurate modulo p^",self.moment(0).valuation(self.p) ) - # v=[0 for j in range(0,i)]+[binomial(j,i)*bernoulli(j-i) for j in range(i,M)] + # v=[0 for j in range(i)]+[binomial(j,i)*bernoulli(j-i) for j in range(i,M)] M = self.precision_relative() R = self.parent().base_ring() K = R.fraction_field() @@ -1142,7 +1142,7 @@ cdef class Dist_vector(Dist): # bernoulli(1) = -1/2; the only nonzero odd Bernoulli number v[m] += m * minhalf * scalar for j in range(m - 1, M, 2): - v[j] += binomial(j, m - 1) * bern[(j - m + 1) // 2] * scalar + v[j] += ZZ(j).binomial(m - 1) * bern[(j - m + 1) // 2] * scalar p = self.parent().prime() cdef Dist_vector ans if p == 0: diff --git a/src/sage/modular/pollack_stevens/padic_lseries.py b/src/sage/modular/pollack_stevens/padic_lseries.py index 613ceef65b8..defacb1b357 100644 --- a/src/sage/modular/pollack_stevens/padic_lseries.py +++ b/src/sage/modular/pollack_stevens/padic_lseries.py @@ -121,7 +121,7 @@ def __init__(self, symb, gamma=None, quadratic_twist=1, precision=None): self._gamma = gamma self._quadratic_twist = quadratic_twist self._precision = precision - self._cinf = ZZ(1) # is set when called for an elliptic curve + self._cinf = ZZ.one() # is set when called for an elliptic curve def __getitem__(self, n): r""" @@ -373,7 +373,7 @@ def _basic_integral(self, a, j): ap = ap * kronecker(D, p) K = pAdicField(p, M) symb_twisted = symb.evaluate_twisted(a, D) - return sum(binomial(j, r) * + return sum(ZZ(j).binomial(r) * ((a - ZZ(K.teichmuller(a))) ** (j - r)) * (p ** r) * symb_twisted.moment(r) for r in range(j + 1)) / ap From b01e2a216dd11df8e01850247659316bcee4dd01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 27 Jan 2025 11:54:40 +0100 Subject: [PATCH 109/187] using the binomial method in categories + cleanup --- ...aded_connected_hopf_algebras_with_basis.py | 6 +- ...ite_dimensional_lie_algebras_with_basis.py | 87 +++++++++---------- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/src/sage/categories/examples/graded_connected_hopf_algebras_with_basis.py b/src/sage/categories/examples/graded_connected_hopf_algebras_with_basis.py index ae91a374489..d5235909b5f 100644 --- a/src/sage/categories/examples/graded_connected_hopf_algebras_with_basis.py +++ b/src/sage/categories/examples/graded_connected_hopf_algebras_with_basis.py @@ -12,7 +12,7 @@ from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis from sage.combinat.free_module import CombinatorialFreeModule -from sage.arith.misc import binomial +from sage.rings.integer import Integer from sage.misc.cachefunc import cached_method from sage.sets.non_negative_integers import NonNegativeIntegers @@ -144,8 +144,8 @@ def coproduct_on_basis(self, i): P0 # P3 + 3*P1 # P2 + 3*P2 # P1 + P3 # P0 """ return self.sum_of_terms( - ((i-j, j), binomial(i, j)) - for j in range(i+1) + ((i - j, j), Integer(i).binomial(j)) + for j in range(i + 1) ) diff --git a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py index 4e5212885ce..686d748e8d8 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -17,14 +17,14 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring +from sage.categories.lie_algebras import LieAlgebras +from sage.categories.subobjects import SubobjectsCategory from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import LazyImport -from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring -from sage.categories.lie_algebras import LieAlgebras -from sage.categories.subobjects import SubobjectsCategory +from sage.rings.integer import Integer from sage.sets.family import Family @@ -147,7 +147,7 @@ def names_map(x): F = FreeAlgebra(self.base_ring(), names) except ValueError: names = ['b{}'.format(i) for i in range(self.dimension())] - self._UEA_names_map = {g: names[i] for i,g in enumerate(I)} + self._UEA_names_map = {g: names[i] for i, g in enumerate(I)} names_map = self._UEA_names_map.__getitem__ F = FreeAlgebra(self.base_ring(), names) # ``F`` is the free algebra over the basis of ``self``. The @@ -207,7 +207,7 @@ def _basis_key_inverse(self): sage: [L._basis_key_inverse[k] for k in L._basis_ordering] [0, 1, 2, 3, 4, 5] """ - return {k: i for i,k in enumerate(self._basis_ordering)} + return {k: i for i, k in enumerate(self._basis_ordering)} def _basis_key(self, x): """ @@ -288,7 +288,7 @@ def from_vector(self, v, order=None): if order is None: order = self._basis_ordering B = self.basis() - return self.sum(v[i] * B[k] for i,k in enumerate(order) if v[i] != 0) + return self.sum(v[i] * B[k] for i, k in enumerate(order) if v[i] != 0) def killing_matrix(self, x, y): r""" @@ -424,9 +424,9 @@ def structure_coefficients(self, include_zeros=False): if not include_zeros and val == zero: continue if self._basis_key(x) > self._basis_key(y): - d[y,x] = -val + d[y, x] = -val else: - d[x,y] = val + d[x, y] = val return Family(d) def centralizer_basis(self, S): @@ -478,8 +478,8 @@ def centralizer_basis(self, S): """ from sage.matrix.constructor import matrix - #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra - #if isinstance(S, LieSubalgebra) or S is self: + # from sage.algebras.lie_algebras.subalgebra import LieSubalgebra + # if isinstance(S, LieSubalgebra) or S is self: if S is self: from sage.matrix.special import identity_matrix m = identity_matrix(self.base_ring(), self.dimension()) @@ -493,11 +493,11 @@ def centralizer_basis(self, S): for k in S.keys(): v = S[k].to_vector() sc[k] = v - sc[k[1],k[0]] = -v + sc[k[1], k[0]] = -v X = self.basis().keys() d = len(X) c_mat = matrix(self.base_ring(), - [[sum(m[i,j] * sc[x,xp][k] for j,xp in enumerate(X) + [[sum(m[i, j] * sc[x, xp][k] for j, xp in enumerate(X) if (x, xp) in sc) for x in X] for i in range(m.nrows()) for k in range(d)]) @@ -702,24 +702,24 @@ def derivations_basis(self): R = self.base_ring() B = self.basis() keys = list(B.keys()) - scoeffs = {(j,y,i): c for y in keys for i in keys - for j,c in self.bracket(B[y], B[i]) - } + scoeffs = {(j, y, i): c for y in keys for i in keys + for j, c in self.bracket(B[y], B[i]) + } zero = R.zero() data = {} N = len(keys) - for ii,i in enumerate(keys): - for ij,j in enumerate(keys[ii+1:]): + for ii, i in enumerate(keys): + for ij, j in enumerate(keys[ii+1:]): ijp = ij + ii + 1 - for il,l in enumerate(keys): + for il, l in enumerate(keys): row = ii + N * il + N**2 * ij - for ik,k in enumerate(keys): - data[row,ik+N*il] = (data.get((row,ik+N*il), zero) - + scoeffs.get((k, i, j), zero)) - data[row,ii+N*ik] = (data.get((row,ii+N*ik), zero) - - scoeffs.get((l, k, j), zero)) - data[row,ijp+N*ik] = (data.get((row,ijp+N*ik), zero) - - scoeffs.get((l, i, k), zero)) + for ik, k in enumerate(keys): + data[row, ik+N*il] = (data.get((row, ik+N*il), zero) + + scoeffs.get((k, i, j), zero)) + data[row, ii+N*ik] = (data.get((row, ii+N*ik), zero) + - scoeffs.get((l, k, j), zero)) + data[row, ijp+N*ik] = (data.get((row, ijp+N*ik), zero) + - scoeffs.get((l, i, k), zero)) mat = matrix(R, data, sparse=True) return tuple([matrix(R, N, N, list(b)) for b in mat.right_kernel().basis()]) @@ -1524,7 +1524,7 @@ def is_abelian(self): """ return len(self.structure_coefficients()) == 0 # TODO: boolean handling of empty family - #return not self.structure_coefficients() + # return not self.structure_coefficients() def is_solvable(self): r""" @@ -1699,9 +1699,7 @@ def chevalley_eilenberg_complex(self, M=None, dual=False, sparse=True, ncpus=Non sparse=sparse, ncpus=ncpus).dual() - import itertools from itertools import combinations, product - from sage.arith.misc import binomial from sage.matrix.matrix_space import MatrixSpace from sage.algebras.lie_algebras.representation import Representation_abstract R = self.base_ring() @@ -1776,8 +1774,8 @@ def compute_diff(k): Y.pop(i) # This is where we would do the action on # the coefficients module - #ret[indices[tuple(Y)]] += mone**i * zero - for j in range(i+1,k): + # ret[indices[tuple(Y)]] += mone**i * zero + for j in range(i + 1, k): # We shift j by 1 because we already removed # an earlier element from X. Z = tuple(Y[:j-1] + Y[j:]) @@ -1807,8 +1805,9 @@ def compute_diff(k): else: p2_data.append(ret) - nrows = binomial(len(LI), k) - ncols = binomial(len(LI), k-1) + lenLI = Integer(len(LI)) + nrows = lenLI.binomial(k) + ncols = lenLI.binomial(k - 1) MS = MatrixSpace(R, nrows, ncols, sparse=sparse) if M is None: p2 = MS(p2_data).transpose() @@ -1852,7 +1851,7 @@ def compute_diff(k): else: p1_data.append(ret) - nrows = len(MI) * binomial(len(LI), k) + nrows = len(MI) * Integer(len(LI)).binomial(k) ncols = len(ten_ind) MS = MatrixSpace(R, nrows, ncols, sparse=sparse) ret = MS(p1_data).transpose() + p2 @@ -1862,8 +1861,7 @@ def compute_diff(k): from sage.homology.chain_complex import ChainComplex ind = list(range(1, len(LI) + 1)) chain_data = {X[0][0]: M for X, M in compute_diff(ind)} - C = ChainComplex(chain_data, degree_of_differential=-1) - return C + return ChainComplex(chain_data, degree_of_differential=-1) def homology(self, deg=None, M=None, sparse=True, ncpus=None): r""" @@ -2019,11 +2017,11 @@ def as_finite_dimensional_algebra(self): M = [] for kp in K: if (k, kp) in S: - M.append( -S[k,kp].to_vector() ) + M.append(-S[k, kp].to_vector()) elif (kp, k) in S: - M.append( S[kp,k].to_vector() ) + M.append(S[kp, k].to_vector()) else: - M.append( zero_vec ) + M.append(zero_vec) mats.append(matrix(R, M)) from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra return FiniteDimensionalAlgebra(R, mats, names=self._names) @@ -2172,7 +2170,7 @@ def sc(i, j): vs = 'X{}_{}' else: vs = 'X{}{}' - R = PolynomialRing(self.base_ring(), ','.join(vs.format(i,j) + R = PolynomialRing(self.base_ring(), ','.join(vs.format(i, j) for i in range(n) for j in range(n))) X = [[R.gen(i+n*j) for i in range(n)] for j in range(n)] @@ -2184,10 +2182,10 @@ def sc(i, j): if i != j: s = sc(i, j) d[k] = (R.sum(s[I[u]] * X[a][u] for u in range(n)) - - R.sum(sc(s,t)[I[a]] * X[s][i] * X[t][j] + - R.sum(sc(s, t)[I[a]] * X[s][i] * X[t][j] for s in range(n) for t in range(n) if s != t)) else: - d[k] = -R.sum(sc(s,t)[I[a]] * X[s][i] * X[t][j] + d[k] = -R.sum(sc(s, t)[I[a]] * X[s][i] * X[t][j] for s in range(n) for t in range(n) if s != t) return Family(keys, d.__getitem__) @@ -2494,7 +2492,8 @@ def faithful_representation(self, algorithm=None): raise ValueError("invalid algorithm '{}'".format(algorithm)) class ElementMethods: - def adjoint_matrix(self, sparse=False): # In #11111 (more or less) by using matrix of a morphism + def adjoint_matrix(self, sparse=False): + # In #11111 (more or less) by using matrix of a morphism """ Return the matrix of the adjoint action of ``self``. @@ -2598,7 +2597,7 @@ def to_vector(self, sparse=False, order=None): from sage.modules.free_module import FreeModule M = FreeModule(self.parent().base_ring(), self.dimension(), sparse=True) if order is None: - order = {b: i for i,b in enumerate(self.parent()._basis_ordering)} + order = {b: i for i, b in enumerate(self.parent()._basis_ordering)} return M({order[k]: c for k, c in mc.items()}) else: M = self.parent().module() From d894970b9dd3cde0a817338ed0eeb82aa9539cb7 Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Mon, 27 Jan 2025 15:25:38 +0200 Subject: [PATCH 110/187] Add references for paving matroids --- src/doc/en/reference/references/index.rst | 7 +++++++ src/sage/matroids/matroid.pyx | 11 ++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 31cb3ec8074..9b04e70f030 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -3689,6 +3689,9 @@ REFERENCES: .. [Ja1971] \N. Jacobson. *Exceptional Lie Algebras*. Marcel Dekker, Inc. New York. 1971. IBSN No. 0-8247-1326-5. +.. [Jer2006] Mark Jerrum. *Two remarks concerning balanced matroids*. + Combinatorica 26, no. 6 (2006): 733-742. + .. [Jet2008] \D. Jetchev. Global divisibility of Heegner points and Tamagawa numbers. Compos. Math. 144 (2008), no. 4, 811--826. @@ -4991,6 +4994,10 @@ REFERENCES: *Yangians and classical Lie algebras*. (1994) :arxiv:`hep-th/9409025` +.. [MNWW2011] Dillon Mayhew, Mike Newman, Dominic Welsh, and Geoff Whittle. + *On the asymptotic proportion of connected matroids*. + European Journal of Combinatorics. 2011 Aug 1;32(6):882-90. + .. [Mol2007] Alexander Ivanovich Molev. *Yangians and Classical Lie Algebras*. Mathematical Surveys and Monographs. diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 208a8544311..d4a71e8a38e 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -6210,6 +6210,10 @@ cdef class Matroid(SageObject): sage: M = matroids.Theta(4) sage: M.is_paving() False + + REFERENCES: + + [Oxl2011]_, p. 24. """ if self.rank() >= 2: for _ in self.dependent_sets_iterator(self.rank() - 1): @@ -6239,12 +6243,17 @@ cdef class Matroid(SageObject): sage: M.is_sparse_paving() False + REFERENCES: + + The definition of sparse-paving matroids can be found in [MNWW2011]_. + The algorithm uses an alternative characterization from [Jer2006]_. + TESTS:: sage: M = matroids.Uniform(4, 50) # fast because we don't check M.dual().is_paving() sage: M.is_sparse_paving() True - sage: for M in matroids.AllMatroids(8): + sage: for M in matroids.AllMatroids(8): # optional - matroid_database ....: assert M.is_sparse_paving() == (M.is_paving() and M.dual().is_paving()) """ if not self.is_paving(): From c67f73dee25132490b0c84db9fb92689649e31df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 27 Jan 2025 14:37:28 +0100 Subject: [PATCH 111/187] minor detail in combin. polyhedron --- .../combinatorial_polyhedron/base.pyx | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 4db4eb54171..cc150ba8e8d 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -1943,15 +1943,14 @@ cdef class CombinatorialPolyhedron(SageObject): """ if self.is_simplex(): return self.dim() + 1 - else: - from sage.arith.misc import binomial - k = 1 - while self.f_vector()[k+1] == binomial(self.n_vertices(), k + 1): - k += 1 - return k + cdef int k = 2 + f = self.f_vector() + while f[k] == self.n_vertices().binomial(k): + k += 1 + return k - 1 @cached_method - def is_neighborly(self, k=None): + def is_neighborly(self, k=None) -> bool: r""" Return whether the polyhedron is neighborly. @@ -2000,7 +1999,7 @@ cdef class CombinatorialPolyhedron(SageObject): return all(self.f_vector()[i+1] == binomial(self.n_vertices(), i + 1) for i in range(1, k)) - def is_simplex(self): + def is_simplex(self) -> bool: r""" Return whether the polyhedron is a simplex. @@ -2014,10 +2013,10 @@ cdef class CombinatorialPolyhedron(SageObject): sage: CombinatorialPolyhedron([[0,1],[0,2],[1,2]]).is_simplex() True """ - return self.is_bounded() and (self.dim()+1 == self.n_vertices()) + return self.is_bounded() and (self.dim() + 1 == self.n_vertices()) @cached_method - def is_simplicial(self): + def is_simplicial(self) -> bool: r""" Test whether the polytope is simplicial. From dac13708ad065902c345bddbfdc3b28475308431 Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Mon, 27 Jan 2025 15:43:24 +0200 Subject: [PATCH 112/187] `matroids/database_collections.py`: Single quotes Use single quotes consistently. Resolves some failures of `# optional - matroid_database` tests. --- src/sage/matroids/database_collections.py | 60 +++++++++++------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/sage/matroids/database_collections.py b/src/sage/matroids/database_collections.py index b5175e0b3d7..3485e305cc1 100644 --- a/src/sage/matroids/database_collections.py +++ b/src/sage/matroids/database_collections.py @@ -85,7 +85,7 @@ def AllMatroids(n, r=None, type='all'): Traceback (most recent call last): ... ValueError: (n=10, r=4, type='all') is not available in the database - sage: for M in matroids.AllMatroids(12, 3, "unorientable"): + sage: for M in matroids.AllMatroids(12, 3, 'unorientable'): ....: M Traceback (most recent call last): ... @@ -94,12 +94,12 @@ def AllMatroids(n, r=None, type='all'): ....: M Traceback (most recent call last): ... - ValueError: The rank needs to be specified for type "unorientable" + ValueError: The rank needs to be specified for type 'unorientable' sage: for M in matroids.AllMatroids(6, type='nice'): ....: M Traceback (most recent call last): ... - AttributeError: The type "nice" is not available. There needs to be an "is_nice()" + AttributeError: The type 'nice' is not available. There needs to be an 'is_nice()' attribute for the type to be supported. REFERENCES: @@ -130,7 +130,7 @@ def AllMatroids(n, r=None, type='all'): ....: [ None, None, None, None, None, None, None, None, None, None, None, 1, 12], ....: [ None, None, None, None, None, None, None, None, None, None, None, None, 1] ....: ] - sage: for r in range(0, 12 + 1): # long time + sage: for r in range(0, 12 + 1): # long time ....: for n in range(r, 12 + 1): ....: if all[r][n] and all[r][n] < 1000: ....: assert len(list(matroids.AllMatroids(n, r))) == all[r][n] @@ -143,21 +143,21 @@ def AllMatroids(n, r=None, type='all'): ....: [ None, None, None, 1, 2, 4, 9, 23, 68, 383, 5249, 232928, None], ....: [ None, None, None, None, 1, 3, 11, 49, 617, 185981, None, None, None] ....: ] - sage: for r in range(0, 4 + 1): # long time + sage: for r in range(0, 4 + 1): # long time ....: for n in range(r, 12 + 1): ....: if simple[r][n] and simple[r][n] < 1000: - ....: assert len(list(matroids.AllMatroids(n, r, "simple"))) == simple[r][n] - ....: for M in matroids.AllMatroids(n, r, "simple"): + ....: assert len(list(matroids.AllMatroids(n, r, 'simple'))) == simple[r][n] + ....: for M in matroids.AllMatroids(n, r, 'simple'): ....: assert M.is_valid() and M.is_simple() sage: unorientable = [ ....: [1, 3, 18, 201, 9413], ....: [1, 34, 12284, None, None] ....: ] - sage: for r in range(0, 1 + 1): # long time + sage: for r in range(0, 1 + 1): # long time ....: for n in range(0, 4 + 1): ....: if unorientable[r][n] and unorientable[r][n] < 1000: - ....: assert len(list(matroids.AllMatroids(n+7, r+3, "unorientable"))) == unorientable[r][n] - ....: for M in matroids.AllMatroids(n+7, r+3, "unorientable"): + ....: assert len(list(matroids.AllMatroids(n+7, r+3, 'unorientable'))) == unorientable[r][n] + ....: for M in matroids.AllMatroids(n+7, r+3, 'unorientable'): ....: assert M.is_valid() """ from sage.matroids.constructor import Matroid @@ -165,44 +165,44 @@ def AllMatroids(n, r=None, type='all'): DatabaseMatroids().require() import matroid_database - if type != "all" and type != "unorientable": + if type != 'all' and type != 'unorientable': try: - getattr(Matroid(bases=[[1, 2], [1, 3]]), "is_" + type) + getattr(Matroid(bases=[[1, 2], [1, 3]]), 'is_' + type) except AttributeError: raise AttributeError( - "The type \"%s\" is not available. " % type + - "There needs to be an \"is_%s()\" attribute for the " % type + + "The type '%s' is not available. " % type + + "There needs to be an 'is_%s()' attribute for the " % type + "type to be supported." ) - if r is None and type == "unorientable": - raise ValueError("The rank needs to be specified for type \"%s\"" % type) + if r is None and type == 'unorientable': + raise ValueError("The rank needs to be specified for type '%s'" % type) if r is None: - rng = range(0, n+1) + rng = range(0, n + 1) else: - rng = range(r, r+1) + rng = range(r, r + 1) for r in rng: - if (r == 0 or r == n) and type != "unorientable": + if (r == 0 or r == n) and type != 'unorientable': M = Matroid(groundset=range(n), bases=[range(r)]) - M.rename(type + "_n" + str(n).zfill(2) + "_r" + str(r).zfill(2) + "_#" + "0" + ": " + repr(M)) - if type == "all": + M.rename(type + '_n' + str(n).zfill(2) + '_r' + str(r).zfill(2) + '_#' + '0' + ': ' + repr(M)) + if type == 'all': yield M else: - f = getattr(M, "is_" + type) + f = getattr(M, 'is_' + type) if f(): yield M else: - rp = min(r, n - r) if (type != "unorientable") else r - type_db = "all" if (type != "unorientable") else "unorientable" + rp = min(r, n - r) if (type != 'unorientable') else r + type_db = 'all' if (type != 'unorientable') else 'unorientable' - matroids_bases = getattr(matroid_database, type_db + "_matroids_bases") + matroids_bases = getattr(matroid_database, type_db + '_matroids_bases') try: matroids_bases(n, rp).__next__() except ValueError: raise ValueError( - "(n=%s, r=%s, type=\"%s\")" % (n, r, type) + "(n=%s, r=%s, type='%s')" % (n, r, type) + " is not available in the database" ) @@ -210,14 +210,14 @@ def AllMatroids(n, r=None, type='all'): for B in matroids_bases(n, rp): M = Matroid(groundset=range(n), bases=B) - if type != "unorientable" and n - r < r: + if type != 'unorientable' and n - r < r: M = M.dual() - M.rename(type + "_n" + str(n).zfill(2) + "_r" + str(r).zfill(2) + "_#" + str(cnt) + ": " + repr(M)) - if type == "all" or type == "unorientable": + M.rename(type + '_n' + str(n).zfill(2) + '_r' + str(r).zfill(2) + '_#' + str(cnt) + ': ' + repr(M)) + if type == 'all' or type == 'unorientable': yield M cnt += 1 else: - f = getattr(M, "is_" + type) + f = getattr(M, 'is_' + type) if f(): yield M cnt += 1 From 57c55ae17ba55c236d8ab5755773f86ab54c786f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 27 Jan 2025 20:00:32 +0100 Subject: [PATCH 113/187] breaking lines after else: in pyx files --- src/sage/coding/binary_code.pyx | 25 +- src/sage/libs/mpmath/ext_impl.pyx | 12 +- src/sage/libs/mpmath/utils.pyx | 12 +- src/sage/libs/singular/singular.pyx | 22 +- src/sage/numerical/backends/glpk_backend.pyx | 231 ++++++++++++------ src/sage/rings/finite_rings/element_base.pyx | 36 +-- src/sage/rings/finite_rings/integer_mod.pyx | 73 ++++-- .../rings/polynomial/polynomial_element.pyx | 15 +- 8 files changed, 277 insertions(+), 149 deletions(-) diff --git a/src/sage/coding/binary_code.pyx b/src/sage/coding/binary_code.pyx index 83dbefdfaf3..58f6572b2c9 100644 --- a/src/sage/coding/binary_code.pyx +++ b/src/sage/coding/binary_code.pyx @@ -617,7 +617,7 @@ cdef codeword *expand_to_ortho_basis(BinaryCode B, int n) noexcept: i = k word = 1 << k k += 1 - else: # NOTE THIS WILL NEVER HAPPEN AS CURRENTLY SET UP! + else: # NOTE THIS WILL NEVER HAPPEN AS CURRENTLY SET UP! temp = (1 << k) - 1 i = k word = 1 << k @@ -813,7 +813,7 @@ cdef class BinaryCode: combination ^= (1 << j) word ^= self_basis[j] - else: # isinstance(arg1, BinaryCode) + else: # isinstance(arg1, BinaryCode) other_basis = other.basis for i from 0 <= i < nrows-1: self_basis[i] = other_basis[i] @@ -2423,9 +2423,12 @@ cdef class PartitionStack: cdef int *self_wd_lvls = self.wd_lvls cdef int *self_wd_ents = self.wd_ents while True: - if CG.is_one(self_wd_ents[wd_ptr], col): i += 1 - if self_wd_lvls[wd_ptr] > k: wd_ptr += 1 - else: break + if CG.is_one(self_wd_ents[wd_ptr], col): + i += 1 + if self_wd_lvls[wd_ptr] > k: + wd_ptr += 1 + else: + break return i def _wd_degree(self, C, wd, col_ptr, k): @@ -3347,15 +3350,17 @@ cdef class BinaryCodeClassifier: if qzb > 0: zb__Lambda_rho[k] = Lambda[k] state = 3 - elif state == 3: # attempt to rule out automorphisms while moving down the tree + elif state == 3: # attempt to rule out automorphisms while moving down the tree # if k > hzf, then we know that nu currently does not look like zeta, the first # terminal node encountered, thus there is no automorphism to discover. If qzb < 0, # i.e. Lambda[k] < zb[k], then the indicator is not maximal, and we can't reach a # canonical leaf. If neither of these is the case, then proceed to state 4. - if hzf__h_zeta <= k or qzb >= 0: state = 4 - else: state = 6 + if hzf__h_zeta <= k or qzb >= 0: + state = 4 + else: + state = 6 - elif state == 4: # at this point we have -not- ruled out the presence of automorphisms + elif state == 4: # at this point we have -not- ruled out the presence of automorphisms if nu.is_discrete(k): state = 7 continue # we have a terminal node, so process it @@ -3368,7 +3373,7 @@ cdef class BinaryCodeClassifier: e[k] = 0 # see state 12 and 17 state = 2 # continue down the tree - elif state == 5: # same as state 3, but in the case where we haven't yet defined zeta + elif state == 5: # same as state 3, but in the case where we haven't yet defined zeta # i.e. this is our first time down the tree. Once we get to the bottom, # we will have zeta = nu = rho, so we do: zf__Lambda_zeta[k] = Lambda[k] diff --git a/src/sage/libs/mpmath/ext_impl.pyx b/src/sage/libs/mpmath/ext_impl.pyx index 8996d6296cf..477b6a09b09 100644 --- a/src/sage/libs/mpmath/ext_impl.pyx +++ b/src/sage/libs/mpmath/ext_impl.pyx @@ -1183,10 +1183,14 @@ cdef MPF_exp(MPF *y, MPF *x, MPopts opts): cdef mpz_t t, u cdef tuple w if x.special: - if x.special == S_ZERO: MPF_set_si(y, 1) - elif x.special == S_NINF: MPF_set_zero(y) - elif x.special == S_INF: MPF_set_inf(y) - else: MPF_set_nan(y) + if x.special == S_ZERO: + MPF_set_si(y, 1) + elif x.special == S_NINF: + MPF_set_zero(y) + elif x.special == S_INF: + MPF_set_inf(y) + else: + MPF_set_nan(y) return wp = opts.prec + 14 sign = mpz_sgn(x.man) < 0 diff --git a/src/sage/libs/mpmath/utils.pyx b/src/sage/libs/mpmath/utils.pyx index 5f681852c68..47061a6bfa4 100644 --- a/src/sage/libs/mpmath/utils.pyx +++ b/src/sage/libs/mpmath/utils.pyx @@ -134,11 +134,15 @@ cpdef normalize(long sign, Integer man, exp, long bc, long prec, str rnd): elif rnd == 'd': mpz_fdiv_q_2exp(res.value, man.value, shift) elif rnd == 'f': - if sign: mpz_cdiv_q_2exp(res.value, man.value, shift) - else: mpz_fdiv_q_2exp(res.value, man.value, shift) + if sign: + mpz_cdiv_q_2exp(res.value, man.value, shift) + else: + mpz_fdiv_q_2exp(res.value, man.value, shift) elif rnd == 'c': - if sign: mpz_fdiv_q_2exp(res.value, man.value, shift) - else: mpz_cdiv_q_2exp(res.value, man.value, shift) + if sign: + mpz_fdiv_q_2exp(res.value, man.value, shift) + else: + mpz_cdiv_q_2exp(res.value, man.value, shift) elif rnd == 'u': mpz_cdiv_q_2exp(res.value, man.value, shift) exp += shift diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index d4ed0e3b064..8e19f883b60 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -96,16 +96,18 @@ cdef Rational si2sa_QQ(number *n, number **nn, ring *_ring): mpq_init(_z) - ## Immediate integers handles carry the tag 'SR_INT', i.e. the last bit is 1. - ## This distinguishes immediate integers from other handles which point to - ## structures aligned on 4 byte boundaries and therefore have last bit zero. - ## (The second bit is reserved as tag to allow extensions of this scheme.) - ## Using immediates as pointers and dereferencing them gives address errors. + # Immediate integers handles carry the tag 'SR_INT', i.e. the last bit is 1. + # This distinguishes immediate integers from other handles which point to + # structures aligned on 4 byte boundaries and therefore have last bit zero. + # (The second bit is reserved as tag to allow extensions of this scheme.) + # Using immediates as pointers and dereferencing them gives address errors. nom = nlGetNumerator(n, _ring.cf) mpz_init(nom_z) - if (SR_HDL(nom) & SR_INT): mpz_set_si(nom_z, SR_TO_INT(nom)) - else: mpz_set(nom_z,nom.z) + if (SR_HDL(nom) & SR_INT): + mpz_set_si(nom_z, SR_TO_INT(nom)) + else: + mpz_set(nom_z,nom.z) mpq_set_num(_z,nom_z) nlDelete(&nom,_ring.cf) @@ -114,8 +116,10 @@ cdef Rational si2sa_QQ(number *n, number **nn, ring *_ring): denom = nlGetDenom(n, _ring.cf) mpz_init(denom_z) - if (SR_HDL(denom) & SR_INT): mpz_set_si(denom_z, SR_TO_INT(denom)) - else: mpz_set(denom_z,denom.z) + if (SR_HDL(denom) & SR_INT): + mpz_set_si(denom_z, SR_TO_INT(denom)) + else: + mpz_set(denom_z,denom.z) mpq_set_den(_z, denom_z) nlDelete(&denom,_ring.cf) diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index c70ac0bb0e0..750c72d9766 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -2134,18 +2134,23 @@ cdef class GLPKBackend(GenericBackend): value = solver_parameter_values[value] if name == timelimit_intopt: - if value is None: return self.iocp.tm_lim - else: self.iocp.tm_lim = value + if value is None: + return self.iocp.tm_lim + else: + self.iocp.tm_lim = value if name == timelimit_seconds: - if value is None: return self.iocp.tm_lim / 1000.0 + if value is None: + return self.iocp.tm_lim / 1000.0 else: self.iocp.tm_lim = value * 1000.0 self.smcp.tm_lim = value * 1000.0 elif name == timelimit_simplex: - if value is None: return self.smcp.tm_lim - else: self.smcp.tm_lim = value + if value is None: + return self.smcp.tm_lim + else: + self.smcp.tm_lim = value elif name == simplex_or_intopt: if value is None: @@ -2155,155 +2160,227 @@ cdef class GLPKBackend(GenericBackend): self.simplex_or_intopt = value elif name == msg_lev_simplex: - if value is None: return self.smcp.msg_lev - else: self.smcp.msg_lev = value + if value is None: + return self.smcp.msg_lev + else: + self.smcp.msg_lev = value elif name == msg_lev_intopt: - if value is None: return self.iocp.msg_lev - else: self.iocp.msg_lev = value + if value is None: + return self.iocp.msg_lev + else: + self.iocp.msg_lev = value elif name == br_tech: - if value is None: return self.iocp.br_tech - else: self.iocp.br_tech = value + if value is None: + return self.iocp.br_tech + else: + self.iocp.br_tech = value elif name == bt_tech: - if value is None: return self.iocp.bt_tech - else: self.iocp.bt_tech = value + if value is None: + return self.iocp.bt_tech + else: + self.iocp.bt_tech = value elif name == pp_tech: - if value is None: return self.iocp.pp_tech - else: self.iocp.pp_tech = value + if value is None: + return self.iocp.pp_tech + else: + self.iocp.pp_tech = value elif name == fp_heur: - if value is None: return self.iocp.fp_heur + if value is None: + return self.iocp.fp_heur else: - if value: value = GLP_ON - else: value = GLP_OFF + if value: + value = GLP_ON + else: + value = GLP_OFF self.iocp.fp_heur = value elif name == gmi_cuts: - if value is None: return self.iocp.gmi_cuts + if value is None: + return self.iocp.gmi_cuts else: - if value: value = GLP_ON - else: value = GLP_OFF + if value: + value = GLP_ON + else: + value = GLP_OFF self.iocp.gmi_cuts = value elif name == mir_cuts: - if value is None: return self.iocp.mir_cuts + if value is None: + return self.iocp.mir_cuts else: - if value: value = GLP_ON - else: value = GLP_OFF + if value: + value = GLP_ON + else: + value = GLP_OFF self.iocp.mir_cuts = value elif name == cov_cuts: - if value is None: return self.iocp.cov_cuts + if value is None: + return self.iocp.cov_cuts else: - if value: value = GLP_ON - else: value = GLP_OFF + if value: + value = GLP_ON + else: + value = GLP_OFF self.iocp.cov_cuts = value elif name == clq_cuts: - if value is None: return self.iocp.clq_cuts + if value is None: + return self.iocp.clq_cuts else: - if value: value = GLP_ON - else: value = GLP_OFF + if value: + value = GLP_ON + else: + value = GLP_OFF self.iocp.clq_cuts = value elif name == tol_int: - if value is None: return self.iocp.tol_int - else: self.iocp.tol_int = value + if value is None: + return self.iocp.tol_int + else: + self.iocp.tol_int = value elif name == tol_obj: - if value is None: return self.iocp.tol_obj - else: self.iocp.tol_obj = value + if value is None: + return self.iocp.tol_obj + else: + self.iocp.tol_obj = value elif name == mip_gap: - if value is None: return self.iocp.mip_gap - else: self.iocp.mip_gap = value + if value is None: + return self.iocp.mip_gap + else: + self.iocp.mip_gap = value elif name == tm_lim_intopt: - if value is None: return self.iocp.tm_lim - else: self.iocp.tm_lim = value + if value is None: + return self.iocp.tm_lim + else: + self.iocp.tm_lim = value elif name == out_frq_intopt: - if value is None: return self.iocp.out_frq - else: self.iocp.out_frq = value + if value is None: + return self.iocp.out_frq + else: + self.iocp.out_frq = value elif name == out_dly_intopt: - if value is None: return self.iocp.out_dly - else: self.iocp.out_dly = value + if value is None: + return self.iocp.out_dly + else: + self.iocp.out_dly = value elif name == presolve_intopt: - if value is None: return self.iocp.presolve + if value is None: + return self.iocp.presolve else: - if value: value = GLP_ON - else: value = GLP_OFF + if value: + value = GLP_ON + else: + value = GLP_OFF self.iocp.presolve = value elif name == binarize: - if value is None: return self.iocp.binarize + if value is None: + return self.iocp.binarize else: - if value: value = GLP_ON - else: value = GLP_OFF + if value: + value = GLP_ON + else: + value = GLP_OFF self.iocp.binarize = value elif name == msg_lev_simplex: - if value is None: return self.smcp.msg_lev - else: self.smcp.msg_lev = value + if value is None: + return self.smcp.msg_lev + else: + self.smcp.msg_lev = value elif name == meth: - if value is None: return self.smcp.meth - else: self.smcp.meth = value + if value is None: + return self.smcp.meth + else: + self.smcp.meth = value elif name == pricing: - if value is None: return self.smcp.pricing - else: self.smcp.pricing = value + if value is None: + return self.smcp.pricing + else: + self.smcp.pricing = value elif name == r_test: - if value is None: return self.smcp.r_test - else: self.smcp.r_test = value + if value is None: + return self.smcp.r_test + else: + self.smcp.r_test = value elif name == tol_bnd: - if value is None: return self.smcp.tol_bnd - else: self.smcp.tol_bnd = value + if value is None: + return self.smcp.tol_bnd + else: + self.smcp.tol_bnd = value elif name == tol_dj: - if value is None: return self.smcp.tol_dj - else: self.smcp.tol_dj = value + if value is None: + return self.smcp.tol_dj + else: + self.smcp.tol_dj = value elif name == tol_piv: - if value is None: return self.smcp.tol_piv - else: self.smcp.tol_piv = value + if value is None: + return self.smcp.tol_piv + else: + self.smcp.tol_piv = value elif name == obj_ll: - if value is None: return self.smcp.obj_ll - else: self.smcp.obj_ll = value + if value is None: + return self.smcp.obj_ll + else: + self.smcp.obj_ll = value elif name == obj_ul: - if value is None: return self.smcp.obj_ul - else: self.smcp.obj_ul = value + if value is None: + return self.smcp.obj_ul + else: + self.smcp.obj_ul = value elif name == it_lim: - if value is None: return self.smcp.it_lim - else: self.smcp.it_lim = value + if value is None: + return self.smcp.it_lim + else: + self.smcp.it_lim = value elif name == tm_lim_simplex: - if value is None: return self.smcp.tm_lim - else: self.smcp.tm_lim = value + if value is None: + return self.smcp.tm_lim + else: + self.smcp.tm_lim = value elif name == out_frq_simplex: - if value is None: return self.smcp.out_frq - else: self.smcp.out_frq = value + if value is None: + return self.smcp.out_frq + else: + self.smcp.out_frq = value elif name == out_dly_simplex: - if value is None: return self.smcp.out_dly - else: self.smcp.out_dly = value + if value is None: + return self.smcp.out_dly + else: + self.smcp.out_dly = value elif name == presolve_simplex: - if value is None: return self.smcp.presolve + if value is None: + return self.smcp.presolve else: - if value: value = GLP_ON - else: value = GLP_OFF + if value: + value = GLP_ON + else: + value = GLP_OFF self.smcp.presolve = value else: raise ValueError("This parameter is not available.") diff --git a/src/sage/rings/finite_rings/element_base.pyx b/src/sage/rings/finite_rings/element_base.pyx index 6ac8470d4c9..7f6cfd9fee3 100644 --- a/src/sage/rings/finite_rings/element_base.pyx +++ b/src/sage/rings/finite_rings/element_base.pyx @@ -87,14 +87,15 @@ cdef class FiniteRingElement(CommutativeRingElement): gcd = n.gcd(q-1) if self.is_one(): if gcd == 1: - if all: return [self] - else: return self + return [self] if all else self else: nthroot = K.zeta(gcd) return [nthroot**a for a in range(gcd)] if all else nthroot if gcd == q-1: - if all: return [] - else: raise ValueError("no nth root") + if all: + return [] + else: + raise ValueError("no nth root") gcd, alpha, _ = n.xgcd(q-1) # gcd = alpha*n + beta*(q-1), so 1/n = alpha/gcd (mod q-1) if gcd == 1: return [self**alpha] if all else self**alpha @@ -102,8 +103,10 @@ cdef class FiniteRingElement(CommutativeRingElement): n = gcd q1overn = (q-1)//n if self**q1overn != 1: - if all: return [] - else: raise ValueError("no nth root") + if all: + return [] + else: + raise ValueError("no nth root") self = self**alpha if cunningham: from sage.rings.factorint import factor_cunningham @@ -921,20 +924,25 @@ cdef class FinitePolyExtElement(FiniteRingElement): """ if self.is_zero(): if n <= 0: - if all: return [] - else: raise ValueError - if all: return [self] - else: return self + if all: + return [] + else: + raise ValueError + return [self] if all else self if n < 0: self = ~self n = -n elif n == 0: if self == 1: - if all: return [a for a in self.parent().list() if a != 0] - else: return self + if all: + return [a for a in self.parent().list() if a != 0] + else: + return self else: - if all: return [] - else: raise ValueError + if all: + return [] + else: + raise ValueError if extend: raise NotImplementedError n = Integer(n) diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index 19525b40937..0e2fd9b9f0f 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -1505,11 +1505,15 @@ cdef class IntegerMod_abstract(FiniteRingElement): n = Integer(n) if n == 0: if self == 1: - if all: return [K(a) for a in range(1,K.order())] - else: return self + if all: + return [K(a) for a in range(1, K.order())] + else: + return self else: - if all: return [] - else: raise ValueError + if all: + return [] + else: + raise ValueError F = K.factored_order() if len(F) == 0: if all: @@ -1533,8 +1537,10 @@ cdef class IntegerMod_abstract(FiniteRingElement): p, k = F[0] if self.is_zero(): if n < 0: - if all: return [] - else: raise ValueError + if all: + return [] + else: + raise ValueError if all: if k == 1: return [self] @@ -1547,12 +1553,13 @@ cdef class IntegerMod_abstract(FiniteRingElement): try: self = ~self except ZeroDivisionError: - if all: return [] - else: raise ValueError + if all: + return [] + else: + raise ValueError n = -n if p == 2 and k == 1: - if all: return [self] - else: return self + return [self] if all else self if k > 1: pval, upart = self.lift().val_unit(p) if not n.divides(pval): @@ -1571,21 +1578,29 @@ cdef class IntegerMod_abstract(FiniteRingElement): sign = [1] if self % 4 == 3: if n % 2 == 0: - if all: return [] - else: raise ValueError("no nth root") + if all: + return [] + else: + raise ValueError("no nth root") else: sign = [-1] self = -self elif n % 2 == 0: if k > 2 and self % 8 == 5: - if all: return [] - else: raise ValueError("no nth root") + if all: + return [] + else: + raise ValueError("no nth root") sign = [1, -1] if k == 2: - if all: return [K(s) for s in sign[:2]] - else: return K(sign[0]) - if all: modp = [mod(self,8)] - else: modp = mod(self,8) + if all: + return [K(s) for s in sign[:2]] + else: + return K(sign[0]) + if all: + modp = [mod(self,8)] + else: + modp = mod(self,8) else: sign = [1] modp = self % p @@ -1602,8 +1617,10 @@ cdef class IntegerMod_abstract(FiniteRingElement): else: return K(modp.lift()) else: - if all: return [] - else: raise ValueError("no nth root") + if all: + return [] + else: + raise ValueError("no nth root") if all: ans = [plog // n + p**(k - nval) * i for i in range(p**nval)] ans = [s*K(R.teichmuller(m) * a.exp()) for a in ans for m in modp for s in sign] @@ -3193,10 +3210,12 @@ cdef int_fast32_t mod_pow_int(int_fast32_t base, int_fast32_t exp, int_fast32_t if exp == 4: return (prod * prod) % n pow2 = base - if exp % 2: prod = base - else: prod = 1 + if exp % 2: + prod = base + else: + prod = 1 exp = exp >> 1 - while(exp != 0): + while exp != 0: pow2 = pow2 * pow2 if pow2 >= INTEGER_MOD_INT32_LIMIT: pow2 = pow2 % n if exp % 2: @@ -3855,10 +3874,12 @@ cdef int_fast64_t mod_pow_int64(int_fast64_t base, int_fast64_t exp, int_fast64_ if exp == 4: return (prod * prod) % n pow2 = base - if exp % 2: prod = base - else: prod = 1 + if exp % 2: + prod = base + else: + prod = 1 exp = exp >> 1 - while(exp != 0): + while exp != 0: pow2 = pow2 * pow2 if pow2 >= INTEGER_MOD_INT64_LIMIT: pow2 = pow2 % n if exp % 2: diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 4d2e607b37d..dff684e0467 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -6809,13 +6809,18 @@ cdef class Polynomial(CommutativePolynomial): e = self.exponents() c = self.coefficients() - if len(e) == 0: return [] + if len(e) == 0: + return [] if len(e) == 1: - if e[0] == 0: return [] - else: return [(infinity.infinity, e[0])] + if e[0] == 0: + return [] + else: + return [(infinity.infinity, e[0])] - if e[0] == 0: slopes = [] - else: slopes = [(infinity.infinity, e[0])] + if e[0] == 0: + slopes = [] + else: + slopes = [(infinity.infinity, e[0])] points = [(e[0], c[0].valuation(p)), (e[1], c[1].valuation(p))] slopes.append((-(c[1].valuation(p)-c[0].valuation(p))/(e[1] - e[0]), e[1]-e[0])) From 2b7b7d18adeb69a4b4963a00104dcb469c7a67e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 27 Jan 2025 21:13:29 +0100 Subject: [PATCH 114/187] move methods into category of fields --- src/sage/categories/fields.py | 55 +++++++++++++++++++++++++++++++++++ src/sage/rings/ring.pyx | 51 -------------------------------- 2 files changed, 55 insertions(+), 51 deletions(-) diff --git a/src/sage/categories/fields.py b/src/sage/categories/fields.py index 2868cd29d3e..9c7eca5c82c 100644 --- a/src/sage/categories/fields.py +++ b/src/sage/categories/fields.py @@ -240,6 +240,61 @@ def is_integrally_closed(self) -> bool: """ return True + def integral_closure(self): + """ + Return this field, since fields are integrally closed in their + fraction field. + + EXAMPLES:: + + sage: QQ.integral_closure() + Rational Field + sage: Frac(ZZ['x,y']).integral_closure() + Fraction Field of Multivariate Polynomial Ring in x, y + over Integer Ring + """ + return self + + def prime_subfield(self): + """ + Return the prime subfield of ``self``. + + EXAMPLES:: + + sage: k = GF(9, 'a') # needs sage.rings.finite_rings + sage: k.prime_subfield() # needs sage.rings.finite_rings + Finite Field of size 3 + """ + if self.characteristic() == 0: + import sage.rings.rational_field + return sage.rings.rational_field.RationalField() + + from sage.rings.finite_rings.finite_field_constructor import GF + return GF(self.characteristic()) + + def divides(self, x, y, coerce=True): + """ + Return ``True`` if ``x`` divides ``y`` in this field. + + This is usually ``True`` in a field!. + + If ``coerce`` is ``True`` (the default), first coerce + ``x`` and ``y`` into ``self``. + + EXAMPLES:: + + sage: QQ.divides(2, 3/4) + True + sage: QQ.divides(0, 5) + False + """ + if coerce: + x = self(x) + y = self(y) + if x.is_zero(): + return y.is_zero() + return True + def _gcd_univariate_polynomial(self, a, b): """ Return the gcd of ``a`` and ``b`` as a monic polynomial. diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index db62e4844e2..8c7c8703b24 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -1002,40 +1002,6 @@ cdef class Field(CommutativeRing): """ return self - def divides(self, x, y, coerce=True): - """ - Return ``True`` if ``x`` divides ``y`` in this field (usually ``True`` - in a field!). If ``coerce`` is ``True`` (the default), first coerce - ``x`` and ``y`` into ``self``. - - EXAMPLES:: - - sage: QQ.divides(2, 3/4) - True - sage: QQ.divides(0, 5) - False - """ - if coerce: - x = self(x) - y = self(y) - if x.is_zero(): - return y.is_zero() - return True - - def integral_closure(self): - """ - Return this field, since fields are integrally closed in their - fraction field. - - EXAMPLES:: - - sage: QQ.integral_closure() - Rational Field - sage: Frac(ZZ['x,y']).integral_closure() - Fraction Field of Multivariate Polynomial Ring in x, y over Integer Ring - """ - return self - def is_field(self, proof=True): """ Return ``True`` since this is a field. @@ -1047,23 +1013,6 @@ cdef class Field(CommutativeRing): """ return True - def prime_subfield(self): - """ - Return the prime subfield of ``self``. - - EXAMPLES:: - - sage: k = GF(9, 'a') # needs sage.rings.finite_rings - sage: k.prime_subfield() # needs sage.rings.finite_rings - Finite Field of size 3 - """ - if self.characteristic() == 0: - import sage.rings.rational_field - return sage.rings.rational_field.RationalField() - else: - from sage.rings.finite_rings.finite_field_constructor import GF - return GF(self.characteristic()) - def algebraic_closure(self): """ Return the algebraic closure of ``self``. From 39e2465638c35d79ec81daf03bd05aa4b7306963 Mon Sep 17 00:00:00 2001 From: Noel Roemmele Date: Mon, 27 Jan 2025 17:42:21 -0700 Subject: [PATCH 115/187] Fix documentation of random_diagonalizable_matrix. Updated documentation of random_matrix. Removed redundant check to see if the base ring provided was teh rationals. Moved doctest from tests to examples. Use the matrix.identity function for the eigenvector_matrix instead. --- src/sage/matrix/special.py | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/sage/matrix/special.py b/src/sage/matrix/special.py index 8a486772bdb..11d5c563340 100644 --- a/src/sage/matrix/special.py +++ b/src/sage/matrix/special.py @@ -241,8 +241,11 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation - ``'unimodular'`` -- creates a matrix of determinant 1 - - ``'diagonalizable'`` -- creates a diagonalizable matrix whose - eigenvectors, if computed by hand, will have only integer entries + - ``'diagonalizable'`` -- if the base ring is ``QQ`` creates a + diagonalizable matrix whose eigenvectors, if computed by hand, + will have only integer entries. See the documentation of + :meth:`~sage.matrix.special.random_diagonalizable_matrix` + for more information - ``implementation`` -- (``None`` or string or a matrix class) a possible implementation. See the documentation of the constructor of @@ -3054,15 +3057,16 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): """ Create a random matrix that diagonalizes nicely. - To be used as a teaching tool. If the ring used is QQ then return matrices - have real eigenvalues. Otherwise eignevalues are elements of the ring. + To be used as a teaching tool. The eigenvalues will be elements of the + base ring. If the base ring used is ``QQ`` then the returned matrix will + have integer eigenvalues. INPUT: If eigenvalues and dimensions are not specified in a list, they will be assigned randomly. - - ``parent`` -- the matrix space required + - ``parent`` -- the corresponding matrix space of the base ring - ``eigenvalues`` -- the list of desired eigenvalues (default=None) @@ -3071,10 +3075,10 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): OUTPUT: - A square, diagonalizable, matrix. If the ring used is QQ then we have - integer entries. Otherwise entries are elements of the ring. If the - ring used is QQ the eigenspaces of this matrix, if computed by hand, - give basis vectors with only integer entries. + A square, diagonalizable, matrix. Elements of the matrix are elements + of the base ring. If the ring used is ``QQ`` then we have integer entries. + If the base ring used is ``QQ`` the eigenspaces of this matrix, if computed + by hand, gives basis vectors with only integer entries. .. NOTE:: @@ -3119,6 +3123,12 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): sage: all(e in eigenvalues for e in eigenvalues2) True + Matrices over finite fields are also supported:: + + sage: K = GF(3) + sage: random_matrix(K, 3, 3, algorithm="diagonalizable").parent() + Full MatrixSpace of 3 by 3 dense matrices over Finite Field of size 3 + TESTS: Eigenvalues must all be elements of the ring. :: @@ -3178,11 +3188,6 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): ... ValueError: each eigenvalue must have a corresponding dimension and each dimension a corresponding eigenvalue. - The elements of the random matrix must be a member of the correct corresponding ring. :: - sage: K = GF(3) - sage: random_matrix(K, 3,3,algorithm="diagonalizable").parent() - Full MatrixSpace of 3 by 3 dense matrices over Finite Field of size 3 - .. TODO:: Modify the routine to allow for complex eigenvalues. @@ -3196,8 +3201,6 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): size = parent.nrows() ring = parent.base_ring() - if ring == QQ: - ring = ZZ if parent.nrows() != parent.ncols(): raise TypeError("a diagonalizable matrix must be square.") if eigenvalues is not None and dimensions is None: @@ -3246,7 +3249,7 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): low_bound = low_bound+dimensions[row_index] # Create a matrix to hold each of the eigenvectors as its columns, begin with an identity matrix so that after row and column # operations the resulting matrix will be unimodular. - eigenvector_matrix = matrix(ring, size, size, 1) + eigenvector_matrix = matrix.identity(ring, size, size) upper_limit = 0 lower_limit = 0 # run the routine over the necessary number of columns corresponding eigenvalue dimension. From ecfee63d1a7188774b18b99d937c4c3151b67b3a Mon Sep 17 00:00:00 2001 From: Noel Roemmele Date: Mon, 27 Jan 2025 20:32:19 -0700 Subject: [PATCH 116/187] Added changes recommened to the documentation by Dave Morris. Change the matrix.identity call also suggested by Dave Morris. --- src/sage/matrix/special.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/matrix/special.py b/src/sage/matrix/special.py index 11d5c563340..ccb39b334c0 100644 --- a/src/sage/matrix/special.py +++ b/src/sage/matrix/special.py @@ -241,10 +241,10 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation - ``'unimodular'`` -- creates a matrix of determinant 1 - - ``'diagonalizable'`` -- if the base ring is ``QQ`` creates a - diagonalizable matrix whose eigenvectors, if computed by hand, - will have only integer entries. See the documentation of - :meth:`~sage.matrix.special.random_diagonalizable_matrix` + - ``'diagonalizable'`` -- creates a diagonalizable matrix. if the + base ring is ``QQ`` creates a diagonalizable matrix whose eigenvectors, + if computed by hand, will have only integer entries. See the + documentation of :meth:`~sage.matrix.special.random_diagonalizable_matrix` for more information - ``implementation`` -- (``None`` or string or a matrix class) a possible @@ -3066,7 +3066,7 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): If eigenvalues and dimensions are not specified in a list, they will be assigned randomly. - - ``parent`` -- the corresponding matrix space of the base ring + - ``parent`` -- the desired parent of the square matrix (a matrix space) - ``eigenvalues`` -- the list of desired eigenvalues (default=None) @@ -3076,9 +3076,9 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): OUTPUT: A square, diagonalizable, matrix. Elements of the matrix are elements - of the base ring. If the ring used is ``QQ`` then we have integer entries. - If the base ring used is ``QQ`` the eigenspaces of this matrix, if computed - by hand, gives basis vectors with only integer entries. + of the base ring. If the ring used is ``QQ`` then we have integer entries, + and the eigenspaces of this matrix, if computed by hand, gives basis + vectors with only integer entries. .. NOTE:: @@ -3249,7 +3249,7 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): low_bound = low_bound+dimensions[row_index] # Create a matrix to hold each of the eigenvectors as its columns, begin with an identity matrix so that after row and column # operations the resulting matrix will be unimodular. - eigenvector_matrix = matrix.identity(ring, size, size) + eigenvector_matrix = matrix.identity(ring, size) upper_limit = 0 lower_limit = 0 # run the routine over the necessary number of columns corresponding eigenvalue dimension. From 50b0b7d8c9ed6fa22eb59546c0ad0392cc4b5e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 28 Jan 2025 08:18:04 +0100 Subject: [PATCH 117/187] fixing the doctest in src/doc --- 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 12a5cebe3aa..2a039fb920b 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -123,18 +123,15 @@ This base class provides a lot more methods than a general parent:: 'algebraic_closure', 'an_embedding', 'base_extend', - 'divides', 'epsilon', 'extension', 'fraction_field', 'gen', 'gens', - 'integral_closure', 'is_field', 'ngens', 'one', 'order', - 'prime_subfield', 'random_element', 'zero', 'zeta', From 05c32b93297db1706c5d345b2208b7bd191b2d37 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Tue, 28 Jan 2025 19:50:47 +0700 Subject: [PATCH 118/187] Simplify __invert__ for polynomial quotient ring element --- .../polynomial_quotient_ring_element.py | 34 +++++-------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index c167caeb352..c6e97f03be3 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -386,10 +386,6 @@ def __invert__(self): """ Return the inverse of this element. - .. WARNING:: - - Only implemented when the base ring is a field. - EXAMPLES:: sage: R. = QQ[] @@ -414,35 +410,21 @@ def __invert__(self): sage: (2*y)^(-1) Traceback (most recent call last): ... - NotImplementedError: The base ring (=Ring of integers modulo 16) is not a field + NotImplementedError Check that :issue:`29469` is fixed:: sage: ~S(3) 11 """ - if self._polynomial.is_zero(): - raise ZeroDivisionError("element %s of quotient polynomial ring not invertible" % self) - if self._polynomial.is_one(): - return self - - parent = self.parent() - + P = self.parent() try: - if self._polynomial.is_unit(): - inv_pol = self._polynomial.inverse_of_unit() - return parent(inv_pol) - except (TypeError, NotImplementedError): - pass - - base = parent.base_ring() - if not base.is_field(): - raise NotImplementedError("The base ring (=%s) is not a field" % base) - g, _, a = parent.modulus().xgcd(self._polynomial) - if g.degree() != 0: - raise ZeroDivisionError("element %s of quotient polynomial ring not invertible" % self) - c = g[0] - return self.__class__(self.parent(), (~c)*a, check=False) + return type(self)(P, self._polynomial.inverse_mod(P.modulus()), check=False) + except ValueError as e: + if e.args[0] == "Impossible inverse modulo": + raise ZeroDivisionError(f"element {self} of quotient polynomial ring not invertible") + else: + raise NotImplementedError def field_extension(self, names): r""" From 0625fc1a0360116a6fe7aac7f8fadb071ff19ee7 Mon Sep 17 00:00:00 2001 From: Pierre Lairez Date: Mon, 27 Jan 2025 18:52:29 +0100 Subject: [PATCH 119/187] Add wrapper for FLINT's `acb_dirichlet_zeta_zeros` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New method `ComplexBallField.zeta_zeros` that wraps `acb_dirichlet_zeta_zeros` for computing zeros of the Rieman ζ function. --- src/sage/rings/complex_arb.pyx | 65 ++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index fb9d821a413..fe7740b7a07 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -168,6 +168,7 @@ from sage.libs.flint.acb_hypgeom cimport * from sage.libs.flint.acb_elliptic cimport * from sage.libs.flint.acb_modular cimport * from sage.libs.flint.acb_poly cimport * +from sage.libs.flint.acb_dirichlet cimport * from sage.libs.flint.arf cimport arf_init, arf_get_d, arf_get_mpfr, arf_clear, arf_set, arf_is_nan from sage.libs.flint.mag cimport (mag_init, mag_clear, mag_set_d, MAG_BITS, mag_zero, mag_set_ui_2exp_si, @@ -1261,6 +1262,70 @@ class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): return res + def zeta_zeros(self, count, start=1): + r""" + Compute consecutive zeros of the Riemann zeta function. + + INPUT: + + - ``count`` -- positive integer; number of zeros to be computed, must fit in a machine integer + + - ``start`` -- positive integer (default: 1); index of the first zero to be computed + + OUTPUT: + + A list of ``count`` consecutive zeros of the Riemann zeta function, starting from the ``start``-th zero. + Indexing starts at one, following usual mathematical notations. + + EXAMPLES:: + + sage: CBF.zeta_zeros(10) + [0.5000000000000000 + [14.134725141734...]*I, + 0.5000000000000000 + [21.0220396387715...]*I, + 0.5000000000000000 + [25.010857580145...]*I, + 0.5000000000000000 + [30.4248761258595...]*I, + 0.5000000000000000 + [32.935061587739...]*I, + 0.5000000000000000 + [37.586178158825...]*I, + 0.5000000000000000 + [40.918719012147...]*I, + 0.5000000000000000 + [43.32707328091...]*I, + 0.5000000000000000 + [48.005150881167...]*I, + 0.5000000000000000 + [49.773832477672...]*I] + + sage: CBF.zeta_zeros(6, start=5) + [0.5000000000000000 + [32.935061587739...]*I, + 0.5000000000000000 + [37.586178158825...]*I, + 0.5000000000000000 + [40.918719012147...]*I, + 0.5000000000000000 + [43.32707328091...]*I, + 0.5000000000000000 + [48.005150881167...]*I, + 0.5000000000000000 + [49.773832477672...]*I] + """ + cdef fmpz_t _start + fmpz_init(_start) + fmpz_set_mpz(_start, ( Integer(start)).value) + + cdef long _count = count + if _count < 1: + raise ValueError("count must be positive") + + cdef acb_ptr ar = _acb_vec_init(_count) + + sig_on() + acb_dirichlet_zeta_zeros(ar, _start, _count, self._prec) + sig_off() + + res = [] + cdef ComplexBall b + for i in range(_count): + b = ComplexBall.__new__(ComplexBall) + b._parent = self + acb_swap(b.value, &ar[i]) + res.append(b) + + _acb_vec_clear(ar, _count) + fmpz_clear(_start) + + return res + cdef inline bint _do_sig(long prec) noexcept: """ From 3da335461af110919caef28e8bc5f429129a621d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 28 Jan 2025 16:46:29 +0100 Subject: [PATCH 120/187] adding conversion of symmetric functions to magma and back --- src/sage/combinat/sf/elementary.py | 8 ++++++ src/sage/combinat/sf/homogeneous.py | 8 ++++++ src/sage/combinat/sf/monomial.py | 8 ++++++ src/sage/combinat/sf/powersum.py | 8 ++++++ src/sage/combinat/sf/schur.py | 8 ++++++ src/sage/ext_data/magma/sage/basic.m | 27 +++++++++++++++++++ .../modules/with_basis/indexed_element.pyx | 10 +++++++ 7 files changed, 77 insertions(+) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 675c02604fd..15b0a7ea0d4 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -98,6 +98,14 @@ def P(i): T = self.tensor_square() return T.sum_of_monomials( (P(j), P(i-j)) for j in range(i+1) ) + def _magma_init_(self, magma): + """ + Used in converting this ring to the corresponding ring in MAGMA. + """ + B = magma(self.base_ring()) + Bref = B._ref() + return f"SymmetricFunctionAlgebraElementary({Bref})" + class Element(classical.SymmetricFunctionAlgebra_classical.Element): def omega(self): r""" diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index e6bc361f3b0..4566bcbbd67 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -125,6 +125,14 @@ def P(i): T = self.tensor_square() return T.sum_of_monomials( (P(j), P(i-j)) for j in range(i+1) ) + def _magma_init_(self, magma): + """ + Used in converting this ring to the corresponding ring in MAGMA. + """ + B = magma(self.base_ring()) + Bref = B._ref() + return f"SymmetricFunctionAlgebraHomogeneous({Bref})" + class Element(classical.SymmetricFunctionAlgebra_classical.Element): def omega(self): r""" diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index bb7b54bae4e..5040e3f1e49 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -276,6 +276,14 @@ def antipode_by_coercion(self, element): s = self.realization_of().schur() return self(s.antipode(s(element))) + def _magma_init_(self, magma): + """ + Used in converting this ring to the corresponding ring in MAGMA. + """ + B = magma(self.base_ring()) + Bref = B._ref() + return f"SymmetricFunctionAlgebraMonomial({Bref})" + class Element(classical.SymmetricFunctionAlgebra_classical.Element): def expand(self, n, alphabet='x'): """ diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index ce64edef000..57a1b266f70 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -216,6 +216,14 @@ def eval_at_permutation_roots_on_generators(self, k, rho): """ return self.base_ring().sum(d*list(rho).count(d) for d in divisors(k)) + def _magma_init_(self, magma): + """ + Used in converting this ring to the corresponding ring in MAGMA. + """ + B = magma(self.base_ring()) + Bref = B._ref() + return f"SymmetricFunctionAlgebraPower({Bref})" + class Element(classical.SymmetricFunctionAlgebra_classical.Element): def omega(self): r""" diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 6d68365f270..5d9cfac82d2 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -224,6 +224,14 @@ def _repeated_bernstein_creation_operator_on_basis(self, la, nu): return (-1)**m * self([a+b for (a,b) in zip(ga, range(-r,0))]) return self.zero() + def _magma_init_(self, magma): + """ + Used in converting this ring to the corresponding ring in MAGMA. + """ + B = magma(self.base_ring()) + Bref = B._ref() + return f"SymmetricFunctionAlgebraSchur({Bref})" + class Element(classical.SymmetricFunctionAlgebra_classical.Element): def __pow__(self, n): """ diff --git a/src/sage/ext_data/magma/sage/basic.m b/src/sage/ext_data/magma/sage/basic.m index 678174dfd49..3b772c3eeda 100644 --- a/src/sage/ext_data/magma/sage/basic.m +++ b/src/sage/ext_data/magma/sage/basic.m @@ -233,6 +233,33 @@ intrinsic Sage(I::RngOrdIdl) -> MonStgElt, BoolElt return Sprintf("%o.ideal(%o)", Sage(K),Sage(seq)), true; end intrinsic; +/* Symmetric functions */ + +intrinsic Sage(X::AlgSym) -> MonStgElt, BoolElt +{} +if HasSchurBasis(X) then + return Sprintf("SymmetricFunctions(%o).s()", Sage(BaseRing(X))), false; +elif HasHomogeneousBasis(X) then + return Sprintf("SymmetricFunctions(%o).h()", Sage(BaseRing(X))), false; +elif HasElementaryBasis(X) then + return Sprintf("SymmetricFunctions(%o).e()", Sage(BaseRing(X))), false; +elif HasPowerSumBasis(X) then + return Sprintf("SymmetricFunctions(%o).p()", Sage(BaseRing(X))), false; +elif HasMonomialBasis(X) then + return Sprintf("SymmetricFunctions(%o).m()", Sage(BaseRing(X))), false; +end if; +end intrinsic; + +intrinsic Sage(X::AlgSymElt) -> MonStgElt, BoolElt +{} +PA := Parent(X); +SF := Sage(PA); +BR := Sage(BaseRing(PA)); +parts, coeffs := Support(X); +dict := (&* [ Sprintf("Partition(%o):%o(%o),", Sage(parts[i]), BR, Sage(coeffs[i])) : i in [1..#parts] ]); +return Sprintf("%o._from_dict({%o})", SF, dict), false; +end intrinsic; + /* Elliptic curves */ intrinsic Sage(X::CrvEll) -> MonStgElt, BoolElt diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index 73917208342..168ade9c361 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -1020,6 +1020,16 @@ cdef class IndexedFreeModuleElement(ModuleElement): x_inv = B(x) ** -1 return type(self)(F, scal(x_inv, D)) + def _magma_init_(self, magma): + r""" + Convert ``self`` to Magma. + """ + # Get a reference to Magma version of parent. + R = magma(self.parent()).name() + # use dict {key: coefficient}. + return '+'.join(f"({c._magma_init_(magma)})*{R}.{m._magma_init_(magma)}" + for m, c in self.monomial_coefficients().items()) + def _unpickle_element(C, d): """ From 771dd67b30c652a70592d2b4f6741b954cf313e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 28 Jan 2025 17:38:05 +0100 Subject: [PATCH 121/187] adding examples --- src/sage/combinat/sf/elementary.py | 10 ++++++++++ src/sage/combinat/sf/homogeneous.py | 10 ++++++++++ src/sage/combinat/sf/monomial.py | 10 ++++++++++ src/sage/combinat/sf/powersum.py | 10 ++++++++++ src/sage/combinat/sf/schur.py | 10 ++++++++++ 5 files changed, 50 insertions(+) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 15b0a7ea0d4..ec742466c47 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -101,6 +101,16 @@ def P(i): def _magma_init_(self, magma): """ Used in converting this ring to the corresponding ring in MAGMA. + + EXAMPLES:: + + sage: # optional - magma + sage: S = SymmetricFunctions(QQ).e() + sage: t = 4*S[3,2]+9 + sage: mt = magma(t); mt + 9 + 4*$.[3,2] + sage: mt.sage() + 9*p[] + 4*e[3, 2] """ B = magma(self.base_ring()) Bref = B._ref() diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 4566bcbbd67..a9189241e36 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -128,6 +128,16 @@ def P(i): def _magma_init_(self, magma): """ Used in converting this ring to the corresponding ring in MAGMA. + + EXAMPLES:: + + sage: # optional - magma + sage: S = SymmetricFunctions(QQ).h() + sage: t = 4*S[3,2]+9 + sage: mt = magma(t); mt + 9 + 4*$.[3,2] + sage: mt.sage() + 9*p[] + 4*h[3, 2] """ B = magma(self.base_ring()) Bref = B._ref() diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 5040e3f1e49..57422ee8c08 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -279,6 +279,16 @@ def antipode_by_coercion(self, element): def _magma_init_(self, magma): """ Used in converting this ring to the corresponding ring in MAGMA. + + EXAMPLES:: + + sage: # optional - magma + sage: S = SymmetricFunctions(QQ).m() + sage: t = 4*S[3,2]+9 + sage: mt = magma(t); mt + 9 + 4*$.[3,2] + sage: mt.sage() + 9*p[] + 4*m[3, 2] """ B = magma(self.base_ring()) Bref = B._ref() diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 57a1b266f70..1aa11033291 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -219,6 +219,16 @@ def eval_at_permutation_roots_on_generators(self, k, rho): def _magma_init_(self, magma): """ Used in converting this ring to the corresponding ring in MAGMA. + + EXAMPLES:: + + sage: # optional - magma + sage: S = SymmetricFunctions(QQ).p() + sage: t = 4*S[3,2]+9 + sage: mt = magma(t); mt + 9 + 4*$.[3,2] + sage: mt.sage() + 9*p[] + 4*p[3, 2] """ B = magma(self.base_ring()) Bref = B._ref() diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 5d9cfac82d2..859c00a935a 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -227,6 +227,16 @@ def _repeated_bernstein_creation_operator_on_basis(self, la, nu): def _magma_init_(self, magma): """ Used in converting this ring to the corresponding ring in MAGMA. + + EXAMPLES:: + + sage: # optional - magma + sage: S = SymmetricFunctions(QQ).s() + sage: t = 4*S[3,2]+9 + sage: mt = magma(t); mt + 9 + 4*$.[3,2] + sage: mt.sage() + 9*p[] + 4*s[3, 2] """ B = magma(self.base_ring()) Bref = B._ref() From 24cd34aeaacabf25b0bcf31ba9f5e0173007e0c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 28 Jan 2025 17:45:43 +0100 Subject: [PATCH 122/187] polishing the doctests --- src/sage/combinat/sf/elementary.py | 6 +++--- src/sage/combinat/sf/homogeneous.py | 6 +++--- src/sage/combinat/sf/monomial.py | 6 +++--- src/sage/combinat/sf/powersum.py | 4 ++-- src/sage/combinat/sf/schur.py | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index ec742466c47..d24e3425116 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -105,12 +105,12 @@ def _magma_init_(self, magma): EXAMPLES:: sage: # optional - magma - sage: S = SymmetricFunctions(QQ).e() - sage: t = 4*S[3,2]+9 + sage: E = SymmetricFunctions(QQ).e() + sage: t = 4*E[3,2]+9 sage: mt = magma(t); mt 9 + 4*$.[3,2] sage: mt.sage() - 9*p[] + 4*e[3, 2] + 9*e[] + 4*e[3, 2] """ B = magma(self.base_ring()) Bref = B._ref() diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index a9189241e36..aa25b1a6ebb 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -132,12 +132,12 @@ def _magma_init_(self, magma): EXAMPLES:: sage: # optional - magma - sage: S = SymmetricFunctions(QQ).h() - sage: t = 4*S[3,2]+9 + sage: H = SymmetricFunctions(QQ).h() + sage: t = 4*H[3,2]+9 sage: mt = magma(t); mt 9 + 4*$.[3,2] sage: mt.sage() - 9*p[] + 4*h[3, 2] + 9*h[] + 4*h[3, 2] """ B = magma(self.base_ring()) Bref = B._ref() diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 57422ee8c08..7dc003e00ca 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -283,12 +283,12 @@ def _magma_init_(self, magma): EXAMPLES:: sage: # optional - magma - sage: S = SymmetricFunctions(QQ).m() - sage: t = 4*S[3,2]+9 + sage: M = SymmetricFunctions(QQ).m() + sage: t = 4*M[3,2]+9 sage: mt = magma(t); mt 9 + 4*$.[3,2] sage: mt.sage() - 9*p[] + 4*m[3, 2] + 9*m[] + 4*m[3, 2] """ B = magma(self.base_ring()) Bref = B._ref() diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 1aa11033291..9b4faa329cc 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -223,8 +223,8 @@ def _magma_init_(self, magma): EXAMPLES:: sage: # optional - magma - sage: S = SymmetricFunctions(QQ).p() - sage: t = 4*S[3,2]+9 + sage: P = SymmetricFunctions(QQ).p() + sage: t = 4*P[3,2]+9 sage: mt = magma(t); mt 9 + 4*$.[3,2] sage: mt.sage() diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 859c00a935a..9ff7072ea8f 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -236,7 +236,7 @@ def _magma_init_(self, magma): sage: mt = magma(t); mt 9 + 4*$.[3,2] sage: mt.sage() - 9*p[] + 4*s[3, 2] + 9*s[] + 4*s[3, 2] """ B = magma(self.base_ring()) Bref = B._ref() From 1bbefc47547ff460e546b43de66662d4d6a8df2f Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Tue, 28 Jan 2025 18:40:51 +0000 Subject: [PATCH 123/187] apply review changes --- src/sage/modular/modform/element.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 6bbc087ce49..8ad817d2373 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -377,8 +377,7 @@ def coefficients(self, X): self.__coefficients except AttributeError: self.__coefficients = {} - if isinstance(X, (int, Integer)): - X = list(range(1, X + 1)) + X = list(range(1, ZZ(X) + 1)) Y = [n for n in X if n not in self.__coefficients] v = self._compute(Y) for i in range(len(v)): @@ -2590,7 +2589,7 @@ def _pow_int(self, n): Testing modular forms of nontrivial character:: - sage: F = ModularForms(DirichletGroup(17).0^2,2).2 + sage: F = ModularForms(DirichletGroup(17).0^2, 2).2 sage: F3 = F^3; F3 q^3 + (-3*zeta8^2 + 6)*q^4 + (-12*zeta8^2 + 3*zeta8 + 18)*q^5 + O(q^6) sage: F3.qexp(6) == F.qexp(6)^3 @@ -3452,7 +3451,7 @@ def coefficients(self, X): INPUT: - - ``X`` -- an iterator or an integer. If ``X`` is an iterator, a list + - ``X`` -- an iterable or an integer. If ``X`` is iterable, a list containing all `a_{X_i}` is returned. If ``X`` is an integer, it must be positive, in which case the coefficients `a_1` to `a_X` are returned in a list. From 40d0e60243343cdd00c7123de9c76c25985ea14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 28 Jan 2025 20:13:05 +0100 Subject: [PATCH 124/187] using Integer more --- src/sage/combinat/affine_permutation.py | 8 ++++---- src/sage/combinat/baxter_permutations.py | 9 +++++---- src/sage/combinat/blob_algebra.py | 4 ++-- src/sage/combinat/dyck_word.py | 16 ++++++++-------- src/sage/combinat/posets/posets.py | 10 +++++----- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/sage/combinat/affine_permutation.py b/src/sage/combinat/affine_permutation.py index 536ccae8291..4060ea9793f 100644 --- a/src/sage/combinat/affine_permutation.py +++ b/src/sage/combinat/affine_permutation.py @@ -22,7 +22,7 @@ from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.misc.prandom import randint -from sage.rings.integer_ring import ZZ +from sage.rings.integer import Integer from sage.structure.list_clone import ClonableArray from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -75,8 +75,8 @@ def __init__(self, parent, lst, check=True): Type A affine permutation with window [1, 2, 3, 4] """ if check: - lst = [ZZ(val) for val in lst] - self.k = ZZ(parent.k) + lst = [Integer(val) for val in lst] + self.k = parent.k self.n = self.k + 1 # This N doesn't matter for type A, but comes up in all other types. if parent.cartan_type()[0] == 'A': @@ -2014,7 +2014,7 @@ def __init__(self, cartan_type): """ Parent.__init__(self, category=AffineWeylGroups()) ct = CartanType(cartan_type) - self.k = ZZ(ct.n) + self.k = Integer(ct.n) self.n = ct.rank() # This N doesn't matter for type A, but comes up in all other types. if ct.letter == 'A': diff --git a/src/sage/combinat/baxter_permutations.py b/src/sage/combinat/baxter_permutations.py index 6717dc59076..6cddccb1940 100644 --- a/src/sage/combinat/baxter_permutations.py +++ b/src/sage/combinat/baxter_permutations.py @@ -2,6 +2,7 @@ Baxter permutations """ from sage.combinat.permutation import Permutations +from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.structure.parent import Parent @@ -77,11 +78,11 @@ def __init__(self, n): Baxter permutations of size 5 """ self.element_class = Permutations(n).element_class - self._n = ZZ(n) + self._n = Integer(n) from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets super().__init__(category=FiniteEnumeratedSets()) - def _repr_(self): + def _repr_(self) -> str: """ Return a string representation of ``self``. @@ -91,9 +92,9 @@ def _repr_(self): sage: BaxterPermutations_size(5) Baxter permutations of size 5 """ - return "Baxter permutations of size %s" % self._n + return f"Baxter permutations of size {self._n}" - def __contains__(self, x): + def __contains__(self, x) -> bool: r""" Return ``True`` if and only if ``x`` is a Baxter permutation of size ``self._n``. diff --git a/src/sage/combinat/blob_algebra.py b/src/sage/combinat/blob_algebra.py index 7477d6a8822..2ea8a223e40 100644 --- a/src/sage/combinat/blob_algebra.py +++ b/src/sage/combinat/blob_algebra.py @@ -25,7 +25,7 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.subset import powerset from sage.misc.cachefunc import cached_method -from sage.rings.integer_ring import ZZ +from sage.rings.integer import Integer from sage.structure.element import Element, get_coercion_model from sage.structure.parent import Parent from sage.structure.richcmp import richcmp @@ -164,7 +164,7 @@ def __init__(self, n): sage: BD4 = BlobDiagrams(4) sage: TestSuite(BD4).run() """ - self._n = ZZ(n) + self._n = Integer(n) self._TL_diagrams = TemperleyLiebDiagrams(n) Parent.__init__(self, category=FiniteEnumeratedSets()) diff --git a/src/sage/combinat/dyck_word.py b/src/sage/combinat/dyck_word.py index e29c70dec78..22aa66d39f9 100644 --- a/src/sage/combinat/dyck_word.py +++ b/src/sage/combinat/dyck_word.py @@ -90,7 +90,7 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.posets import Posets -from sage.rings.integer_ring import ZZ +from sage.rings.integer import Integer from sage.rings.rational_field import QQ from sage.combinat.permutation import Permutation, Permutations from sage.combinat.words.word import Word @@ -3286,14 +3286,14 @@ def __classcall_private__(cls, k1=None, k2=None, complete=True): return CompleteDyckWords_all() return DyckWords_all() - k1 = ZZ(k1) + k1 = Integer(k1) if k1 < 0: raise ValueError("k1 (= %s) must be nonnegative" % k1) return CompleteDyckWords_size(k1) else: - k1 = ZZ(k1) + k1 = Integer(k1) - k2 = ZZ(k2) + k2 = Integer(k2) if k1 < 0 or (k2 is not None and k2 < 0): raise ValueError("k1 (= %s) and k2 (= %s) must be nonnegative, with k1 >= k2" % (k1, k2)) if k1 < k2: @@ -3638,8 +3638,8 @@ def __init__(self, k1, k2): # Dyck paths, not words; having k1 opening parens and k2 closing # parens corresponds to paths of length k1 + k2 ending at height # k1 - k2. - k1 = ZZ(k1) - k2 = ZZ(k2) + k1 = Integer(k1) + k2 = Integer(k2) self.n = k1 + k2 self.endht = k1 - k2 @@ -3697,8 +3697,8 @@ def __init__(self, k1, k2): Integer Ring sage: TestSuite(DyckWords(4,2)).run() """ - self.k1 = ZZ(k1) - self.k2 = ZZ(k2) + self.k1 = Integer(k1) + self.k2 = Integer(k2) DyckWords.__init__(self, category=FiniteEnumeratedSets()) def _repr_(self) -> str: diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 0ab3588261a..f9f6e0c0f12 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -7167,12 +7167,12 @@ def order_polytope(self): True """ from sage.geometry.polyhedron.constructor import Polyhedron - ineqs = [[0] + [ZZ(j == v) - ZZ(j == u) for j in self] + ineqs = [[0] + [Integer(j == v) - Integer(j == u) for j in self] for u, v in self.hasse_diagram().edges(sort=False, labels=False)] for i in self.maximal_elements(): - ineqs += [[1] + [-ZZ(j == i) for j in self]] + ineqs += [[1] + [-Integer(j == i) for j in self]] for i in self.minimal_elements(): - ineqs += [[0] + [ZZ(j == i) for j in self]] + ineqs += [[0] + [Integer(j == i) for j in self]] return Polyhedron(ieqs=ineqs, base_ring=ZZ) def chain_polytope(self): @@ -7206,10 +7206,10 @@ def chain_polytope(self): A 5-dimensional polyhedron in ZZ^5 defined as the convex hull of 8 vertices """ from sage.geometry.polyhedron.constructor import Polyhedron - ineqs = [[1] + [-ZZ(j in chain) for j in self] + ineqs = [[1] + [-Integer(j in chain) for j in self] for chain in self.maximal_chains_iterator()] for i in self: - ineqs += [[0] + [ZZ(j == i) for j in self]] + ineqs += [[0] + [Integer(j == i) for j in self]] return Polyhedron(ieqs=ineqs, base_ring=ZZ) def zeta_polynomial(self): From 919fc345f59c6fbe462e78aa3bd7e66e5a75bf0d Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Tue, 28 Jan 2025 23:24:12 +0200 Subject: [PATCH 125/187] Resolve error in `transversal_matroid.pyx` An error appears on Python 3.12 due to the default value of an argument of a cpdef function being ``[]``. We now use ``None`` instead. --- src/sage/matroids/transversal_matroid.pyx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/matroids/transversal_matroid.pyx b/src/sage/matroids/transversal_matroid.pyx index 7532fac62b0..a492816d775 100644 --- a/src/sage/matroids/transversal_matroid.pyx +++ b/src/sage/matroids/transversal_matroid.pyx @@ -668,7 +668,7 @@ cdef class TransversalMatroid(BasisExchangeMatroid): labels.append(l) return TransversalMatroid(sets, groundset=self.groundset(), set_labels=labels) - cpdef transversal_extension(self, element=None, newset=False, sets=[]): + cpdef transversal_extension(self, element=None, newset=False, sets=None): r""" Return a :class:`TransversalMatroid` extended by an element. @@ -751,6 +751,8 @@ cdef class TransversalMatroid(BasisExchangeMatroid): Transversal matroid of rank 3 on 5 elements, with 3 sets sage: Ne = N.transversal_extension(element='f', sets=['s2']) """ + if sets is None: + sets = [] cdef set parsed_sets = set(sets) if element is None: element = newlabel(self._groundset) From ef07593ae5ee166b9f5fb98dd0833accf76d7c8b Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Wed, 29 Jan 2025 01:21:22 +0200 Subject: [PATCH 126/187] Ensure `newset`'s label is not `element` --- src/sage/matroids/transversal_matroid.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/matroids/transversal_matroid.pyx b/src/sage/matroids/transversal_matroid.pyx index a492816d775..a11c59f570f 100644 --- a/src/sage/matroids/transversal_matroid.pyx +++ b/src/sage/matroids/transversal_matroid.pyx @@ -783,17 +783,17 @@ cdef class TransversalMatroid(BasisExchangeMatroid): else: new_sets.append(s) + groundset = self._groundset.union([element]) if newset: if newset is True: - newset = newlabel(self._groundset.union(labels)) + newset = newlabel(groundset.union(labels)) new_sets.append([element]) labels = list(labels) # Make a shallow copy since we mutate it labels.append(newset) - groundset = self._groundset.union([element]) return TransversalMatroid(new_sets, groundset, labels) - def transversal_extensions(self, element=None, sets=[]): + def transversal_extensions(self, element=None, sets=None): r""" Return an iterator of extensions based on the transversal presentation. @@ -831,7 +831,7 @@ cdef class TransversalMatroid(BasisExchangeMatroid): raise ValueError("cannot extend by element already in groundset") labels = self._set_labels_input - if not sets: + if sets is None: sets = labels elif not set(sets).issubset(labels): raise ValueError("sets do not match presentation") From 354cdef05deeab4f083f7536e415b933b80d63e2 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Wed, 29 Jan 2025 10:23:32 +0700 Subject: [PATCH 127/187] Fallback inverse_mod to inverse_of_unit --- .../rings/polynomial/polynomial_element.pyx | 43 ++++++++++++++++--- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 4d2e607b37d..a9ca689f5de 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -1608,6 +1608,27 @@ cdef class Polynomial(CommutativePolynomial): AUTHORS: - Robert Bradshaw (2007-05-31) + + TESTS: + + At the time of writing :meth:`inverse_mod` is not implemented in general for the following ring, + but it should fallback to :meth:`inverse_of_unit` when possible:: + + sage: R. = ZZ[] + sage: S = R.localization(u) + sage: T. = S[] + sage: T + Univariate Polynomial Ring in x over Multivariate Polynomial Ring in u, v over Integer Ring localized at (u,) + sage: T(u).is_unit() + True + sage: T(u).inverse_of_unit() + 1/u + sage: T(u).inverse_mod(T(v)) + 1/u + sage: T(v).inverse_mod(T(v^2-1)) + Traceback (most recent call last): + ... + NotImplementedError: Multivariate Polynomial Ring in u, v over Integer Ring localized at (u,) does not provide... """ from sage.rings.ideal import Ideal_generic if isinstance(m, Ideal_generic): @@ -1625,13 +1646,21 @@ cdef class Polynomial(CommutativePolynomial): return a.parent()(~u) if a.parent().is_exact(): # use xgcd - g, s, _ = a.xgcd(m) - if g == 1: - return s - elif g.is_unit(): - return g.inverse_of_unit() * s - else: - raise ValueError("Impossible inverse modulo") + try: + g, s, _ = a.xgcd(m) + if g == 1: + return s + elif g.is_unit(): + return g.inverse_of_unit() * s + else: + raise ValueError("Impossible inverse modulo") + except NotImplementedError: + # attempt fallback, return inverse_of_unit() if this is already an unit + try: + return a.inverse_of_unit() + except (ArithmeticError, ValueError, NotImplementedError, ZeroDivisionError): + pass + raise else: # xgcd may not converge for inexact rings. # Instead solve for the coefficients of From 90e448635802052607eaee54aac318d3c0b6f69e Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Wed, 29 Jan 2025 10:56:29 +0700 Subject: [PATCH 128/187] Fix another bug --- .../rings/polynomial/polynomial_element.pyx | 24 +++++++++++++++++-- .../polynomial_integer_dense_ntl.pyx | 2 +- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index a9ca689f5de..6caa90d8a5d 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -1629,6 +1629,22 @@ cdef class Polynomial(CommutativePolynomial): Traceback (most recent call last): ... NotImplementedError: Multivariate Polynomial Ring in u, v over Integer Ring localized at (u,) does not provide... + + The behavior of ``xgcd`` over rings like ``ZZ`` are nonstandard, we check the behavior:: + + sage: R. = ZZ[] + sage: a = 2*x^2+1 + sage: b = -2*x^2+1 + sage: a.inverse_mod(b) + Traceback (most recent call last): + ... + NotImplementedError: The base ring (=Integer Ring) is not a field + sage: a.xgcd(b) + (16, 8, 8) + sage: a*x^2+b*(x^2+1) + 1 + sage: a*x^2%b # shows the result exists, thus we cannot raise ValueError, only NotImplementedError + 1 """ from sage.rings.ideal import Ideal_generic if isinstance(m, Ideal_generic): @@ -1653,12 +1669,16 @@ cdef class Polynomial(CommutativePolynomial): elif g.is_unit(): return g.inverse_of_unit() * s else: - raise ValueError("Impossible inverse modulo") + R = m.base_ring() + if R.is_field(): + raise ValueError("Impossible inverse modulo") + else: + raise NotImplementedError(f"The base ring (={R}) is not a field") except NotImplementedError: # attempt fallback, return inverse_of_unit() if this is already an unit try: return a.inverse_of_unit() - except (ArithmeticError, ValueError, NotImplementedError, ZeroDivisionError): + except (ArithmeticError, ValueError, NotImplementedError): pass raise else: diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx index 142c7b324ad..0ad2b1a835b 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx @@ -618,7 +618,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): since they need not exist. Instead, over the integers, we first multiply `g` by a divisor of the resultant of `a/g` and `b/g`, up to sign, and return ``g, u, v`` such that - ``g = s*self + s*right``. But note that this `g` may be a + ``g = u*self + v*right``. But note that this `g` may be a multiple of the gcd. If ``self`` and ``right`` are coprime as polynomials over the From 5c5b8dffac3799ef4972e6b41d7513fcf0880471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 29 Jan 2025 08:34:41 +0100 Subject: [PATCH 129/187] suggested details --- src/sage/coding/binary_code.pyx | 15 +++--- src/sage/libs/singular/singular.pyx | 4 +- src/sage/rings/finite_rings/element_base.pyx | 47 ++++++++----------- src/sage/rings/finite_rings/integer_mod.pyx | 46 +++++++----------- .../rings/polynomial/polynomial_element.pyx | 19 ++++---- 5 files changed, 55 insertions(+), 76 deletions(-) diff --git a/src/sage/coding/binary_code.pyx b/src/sage/coding/binary_code.pyx index 58f6572b2c9..c137cc26932 100644 --- a/src/sage/coding/binary_code.pyx +++ b/src/sage/coding/binary_code.pyx @@ -3373,14 +3373,16 @@ cdef class BinaryCodeClassifier: e[k] = 0 # see state 12 and 17 state = 2 # continue down the tree - elif state == 5: # same as state 3, but in the case where we haven't yet defined zeta - # i.e. this is our first time down the tree. Once we get to the bottom, - # we will have zeta = nu = rho, so we do: + elif state == 5: + # same as state 3, but in the case where we haven't yet defined zeta + # i.e. this is our first time down the tree. Once we get to the bottom, + # we will have zeta = nu = rho, so we do: zf__Lambda_zeta[k] = Lambda[k] zb__Lambda_rho[k] = Lambda[k] state = 4 - elif state == 6: # at this stage, there is no reason to continue downward, so backtrack + elif state == 6: + # at this stage, there is no reason to continue downward, so backtrack j = k # return to the longest ancestor nu[i] of nu that could have a @@ -3401,9 +3403,10 @@ cdef class BinaryCodeClassifier: else: k = hh-1 # TODO: is the following line necessary? - if k == -1: k = 0 + if k == -1: + k = 0 - if hb > k:# update hb since we are backtracking + if hb > k: # update hb since we are backtracking hb = k # if j == hh, then all nodes lower than our current position are equivalent, so bail out if j == hh: diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index 8e19f883b60..5acef85c3e6 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -104,7 +104,7 @@ cdef Rational si2sa_QQ(number *n, number **nn, ring *_ring): nom = nlGetNumerator(n, _ring.cf) mpz_init(nom_z) - if (SR_HDL(nom) & SR_INT): + if SR_HDL(nom) & SR_INT: mpz_set_si(nom_z, SR_TO_INT(nom)) else: mpz_set(nom_z,nom.z) @@ -116,7 +116,7 @@ cdef Rational si2sa_QQ(number *n, number **nn, ring *_ring): denom = nlGetDenom(n, _ring.cf) mpz_init(denom_z) - if (SR_HDL(denom) & SR_INT): + if SR_HDL(denom) & SR_INT: mpz_set_si(denom_z, SR_TO_INT(denom)) else: mpz_set(denom_z,denom.z) diff --git a/src/sage/rings/finite_rings/element_base.pyx b/src/sage/rings/finite_rings/element_base.pyx index 7f6cfd9fee3..4677b4682ca 100644 --- a/src/sage/rings/finite_rings/element_base.pyx +++ b/src/sage/rings/finite_rings/element_base.pyx @@ -88,14 +88,12 @@ cdef class FiniteRingElement(CommutativeRingElement): if self.is_one(): if gcd == 1: return [self] if all else self - else: - nthroot = K.zeta(gcd) - return [nthroot**a for a in range(gcd)] if all else nthroot + nthroot = K.zeta(gcd) + return [nthroot**a for a in range(gcd)] if all else nthroot if gcd == q-1: if all: return [] - else: - raise ValueError("no nth root") + raise ValueError("no nth root") gcd, alpha, _ = n.xgcd(q-1) # gcd = alpha*n + beta*(q-1), so 1/n = alpha/gcd (mod q-1) if gcd == 1: return [self**alpha] if all else self**alpha @@ -105,8 +103,7 @@ cdef class FiniteRingElement(CommutativeRingElement): if self**q1overn != 1: if all: return [] - else: - raise ValueError("no nth root") + raise ValueError("no nth root") self = self**alpha if cunningham: from sage.rings.factorint import factor_cunningham @@ -136,12 +133,11 @@ cdef class FiniteRingElement(CommutativeRingElement): if all: nthroot = K.zeta(n) L = [self] - for i in range(1,n): + for i in range(1, n): self *= nthroot L.append(self) return L - else: - return self + return self else: raise ValueError("unknown algorithm") @@ -243,10 +239,11 @@ cdef class FinitePolyExtElement(FiniteRingElement): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R = PolynomialRing(self.parent().prime_subfield(), var) return R(self.__pari__().minpoly('x').lift()) - elif algorithm == 'matrix': + + if algorithm == 'matrix': return self.matrix().minpoly(var) - else: - raise ValueError("unknown algorithm '%s'" % algorithm) + + raise ValueError("unknown algorithm '%s'" % algorithm) # We have two names for the same method # for compatibility with sage.matrix @@ -505,8 +502,7 @@ cdef class FinitePolyExtElement(FiniteRingElement): """ if self.parent().degree()>1: return self.polynomial()._latex_() - else: - return str(self) + return str(self) def __pari__(self, var=None): r""" @@ -626,10 +622,11 @@ cdef class FinitePolyExtElement(FiniteRingElement): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R = PolynomialRing(self.parent().prime_subfield(), var) return R(self.__pari__().charpoly('x').lift()) - elif algorithm == 'matrix': + + if algorithm == 'matrix': return self.matrix().charpoly(var) - else: - raise ValueError("unknown algorithm '%s'" % algorithm) + + raise ValueError("unknown algorithm '%s'" % algorithm) def norm(self): """ @@ -659,10 +656,7 @@ cdef class FinitePolyExtElement(FiniteRingElement): """ f = self.charpoly('x') n = f[0] - if f.degree() % 2: - return -n - else: - return n + return -n if f.degree() % 2 else n def trace(self): """ @@ -926,8 +920,7 @@ cdef class FinitePolyExtElement(FiniteRingElement): if n <= 0: if all: return [] - else: - raise ValueError + raise ValueError return [self] if all else self if n < 0: self = ~self @@ -936,13 +929,11 @@ cdef class FinitePolyExtElement(FiniteRingElement): if self == 1: if all: return [a for a in self.parent().list() if a != 0] - else: - return self + return self else: if all: return [] - else: - raise ValueError + raise ValueError if extend: raise NotImplementedError n = Integer(n) diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index 0e2fd9b9f0f..67902d41fa4 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -1507,19 +1507,16 @@ cdef class IntegerMod_abstract(FiniteRingElement): if self == 1: if all: return [K(a) for a in range(1, K.order())] - else: - return self + return self else: if all: return [] - else: - raise ValueError + raise ValueError F = K.factored_order() if len(F) == 0: if all: return [self] - else: - return self + return self if len(F) != 1: if all: # we should probably do a first pass to see if there are any solutions so that we don't get giant intermediate lists and waste time... @@ -1539,24 +1536,20 @@ cdef class IntegerMod_abstract(FiniteRingElement): if n < 0: if all: return [] - else: - raise ValueError + raise ValueError if all: if k == 1: return [self] - else: - minval = max(1, (k/n).ceil()) - return [K(a*p**minval) for a in range(p**(k-minval))] - else: - return self + minval = max(1, (k/n).ceil()) + return [K(a*p**minval) for a in range(p**(k-minval))] + return self if n < 0: try: self = ~self except ZeroDivisionError: if all: return [] - else: - raise ValueError + raise ValueError n = -n if p == 2 and k == 1: return [self] if all else self @@ -1565,8 +1558,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): if not n.divides(pval): if all: return [] - else: - raise ValueError("no nth root") + raise ValueError("no nth root") if pval > 0: if all: return [K(a.lift()*p**(pval // n) + p**(k - (pval - pval//n)) * b) for a in mod(upart, p**(k-pval)).nth_root(n, all=True, algorithm=algorithm) for b in range(p**(pval - pval//n))] @@ -1580,8 +1572,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): if n % 2 == 0: if all: return [] - else: - raise ValueError("no nth root") + raise ValueError("no nth root") else: sign = [-1] self = -self @@ -1589,18 +1580,15 @@ cdef class IntegerMod_abstract(FiniteRingElement): if k > 2 and self % 8 == 5: if all: return [] - else: - raise ValueError("no nth root") + raise ValueError("no nth root") sign = [1, -1] if k == 2: if all: return [K(s) for s in sign[:2]] - else: - return K(sign[0]) + return K(sign[0]) if all: - modp = [mod(self,8)] - else: - modp = mod(self,8) + modp = [mod(self, 8)] + modp = mod(self, 8) else: sign = [1] modp = self % p @@ -1614,13 +1602,11 @@ cdef class IntegerMod_abstract(FiniteRingElement): if self == 1: if all: return [s*K(p*a+m.lift()) for a in range(p**(k-(2 if p==2 else 1))) for m in modp for s in sign] - else: - return K(modp.lift()) + return K(modp.lift()) else: if all: return [] - else: - raise ValueError("no nth root") + raise ValueError("no nth root") if all: ans = [plog // n + p**(k - nval) * i for i in range(p**nval)] ans = [s*K(R.teichmuller(m) * a.exp()) for a in ans for m in modp for s in sign] diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index dff684e0467..aac651235f7 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -1175,8 +1175,7 @@ cdef class Polynomial(CommutativePolynomial): cdef Py_ssize_t d = self.degree() if 0 <= i <= d: return self.get_unsafe(i) - else: - return self._parent._base.zero() + return self._parent._base.zero() cdef get_unsafe(self, Py_ssize_t i): """ @@ -1822,13 +1821,14 @@ cdef class Polynomial(CommutativePolynomial): cdef Polynomial _right = right if self.is_term(): return _right._mul_term(self, term_on_right=False) - elif _right.is_term(): + + if _right.is_term(): return self._mul_term(_right, term_on_right=True) - elif self._parent.is_exact(): + if self._parent.is_exact(): return self._mul_karatsuba(right) - else: - return self._mul_generic(right) + + return self._mul_generic(right) cpdef Polynomial _mul_trunc_(self, Polynomial right, long n): r""" @@ -6814,8 +6814,7 @@ cdef class Polynomial(CommutativePolynomial): if len(e) == 1: if e[0] == 0: return [] - else: - return [(infinity.infinity, e[0])] + return [(infinity.infinity, e[0])] if e[0] == 0: slopes = [] @@ -6831,8 +6830,8 @@ cdef class Polynomial(CommutativePolynomial): slopes = slopes[:-1] points = points[:-1] s = -(v-points[-1][1])/(e[i]-points[-1][0]) - slopes.append((s,e[i]-points[-1][0])) - points.append((e[i],v)) + slopes.append((s, e[i]-points[-1][0])) + points.append((e[i], v)) return slopes From 7e7d52a13c76af295d1ec7b91e52876f51a89e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 29 Jan 2025 09:06:00 +0100 Subject: [PATCH 130/187] fix lint --- src/sage/rings/finite_rings/element_base.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/finite_rings/element_base.pyx b/src/sage/rings/finite_rings/element_base.pyx index 4677b4682ca..5da0dfded3f 100644 --- a/src/sage/rings/finite_rings/element_base.pyx +++ b/src/sage/rings/finite_rings/element_base.pyx @@ -239,7 +239,7 @@ cdef class FinitePolyExtElement(FiniteRingElement): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R = PolynomialRing(self.parent().prime_subfield(), var) return R(self.__pari__().minpoly('x').lift()) - + if algorithm == 'matrix': return self.matrix().minpoly(var) From f998c1fc429646f5edd56fc98f22ffc27d94af64 Mon Sep 17 00:00:00 2001 From: Noel Roemmele Date: Wed, 29 Jan 2025 09:40:23 -0700 Subject: [PATCH 131/187] Added spaces that were forgotten to the documentation of the diagonalizable algorihtm of random_matrix. Added verification of diagonalizability to the doctest for a random diagonal matrix of GF(3). --- src/sage/matrix/special.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/sage/matrix/special.py b/src/sage/matrix/special.py index ccb39b334c0..851fb623ddd 100644 --- a/src/sage/matrix/special.py +++ b/src/sage/matrix/special.py @@ -242,10 +242,10 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation - ``'unimodular'`` -- creates a matrix of determinant 1 - ``'diagonalizable'`` -- creates a diagonalizable matrix. if the - base ring is ``QQ`` creates a diagonalizable matrix whose eigenvectors, - if computed by hand, will have only integer entries. See the - documentation of :meth:`~sage.matrix.special.random_diagonalizable_matrix` - for more information + base ring is ``QQ`` creates a diagonalizable matrix whose eigenvectors, + if computed by hand, will have only integer entries. See the + documentation of :meth:`~sage.matrix.special.random_diagonalizable_matrix` + for more information - ``implementation`` -- (``None`` or string or a matrix class) a possible implementation. See the documentation of the constructor of @@ -3126,8 +3126,15 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): Matrices over finite fields are also supported:: sage: K = GF(3) - sage: random_matrix(K, 3, 3, algorithm="diagonalizable").parent() + sage: M = random_matrix(K, 3, 3, algorithm="diagonalizable") + sage: M.parent() Full MatrixSpace of 3 by 3 dense matrices over Finite Field of size 3 + sage: M.is_diagonalizable() + True + sage: M # random + [0 0 1] + [2 1 1] + [1 0 0] TESTS: From d8dc279c2ea560141cd313b81c6e00a952d7d5f4 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 27 Jan 2025 10:44:32 -0800 Subject: [PATCH 132/187] Test that the Sage git repo is clean by adding a new 'make' target. --- Makefile | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 6bc60acdca3..15dbbb411c0 100644 --- a/Makefile +++ b/Makefile @@ -253,9 +253,19 @@ TEST_TARGET = $@ TEST = ./sage -t --logfile=$(TEST_LOG) $(TEST_FLAGS) --optional=$(TEST_OPTIONAL) $(TEST_FILES) +test-git-no-uncommitted-changes: + @UNCOMMITTED=$$(git status --porcelain); \ + if [ -n "$$UNCOMMITTED" ]; then \ + echo "Error: the git repo has uncommitted changes:"; \ + echo "$$UNCOMMITTED"; \ + echo; \ + exit 1; \ + fi + test: all @echo '### make $(TEST_TARGET): Running $(TEST)' >> $(TEST_LOG) - $(TEST) + $(TEST); \ + $(MAKE) test-git-no-uncommitted-changes check: @$(MAKE) test @@ -302,7 +312,8 @@ ptestoptionallong: test-nodoc: TEST_OPTIONAL := $(TEST_OPTIONAL),!sagemath_doc_html,!sagemath_doc_pdf test-nodoc: build @echo '### make $(TEST_TARGET): Running $(TEST)' >> $(TEST_LOG) - $(TEST) + $(TEST); \ + $(MAKE) test-git-no-uncommitted-changes check-nodoc: @$(MAKE) test-nodoc @@ -387,5 +398,6 @@ list: misc-clean bdist-clean distclean bootstrap-clean maintainer-clean \ test check testoptional testall testlong testoptionallong testallong \ ptest ptestoptional ptestall ptestlong ptestoptionallong ptestallong \ + test-git-no-uncommitted-changes \ list \ doc-clean clean sagelib-clean build-clean From 9f0b2c364d7ebcc38b5de5360638a56936267f2c Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Fri, 31 Jan 2025 10:53:40 +0700 Subject: [PATCH 133/187] Add a doctest for NotImplementedError --- .../rings/polynomial/polynomial_quotient_ring_element.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index c6e97f03be3..999fca6e8fd 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -411,6 +411,12 @@ def __invert__(self): Traceback (most recent call last): ... NotImplementedError + sage: (2*y+1)^(-1) # this cannot raise ValueError because... + Traceback (most recent call last): + ... + NotImplementedError + sage: (2*y+1) * (10*y+5) # the element is in fact invertible + 1 Check that :issue:`29469` is fixed:: From de9128132c64891dba30d602f18389a5b48d369e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 31 Jan 2025 14:05:27 +0900 Subject: [PATCH 134/187] Implementation of the general Burau representation for Artin groups. --- src/doc/en/reference/references/index.rst | 4 + src/sage/groups/artin.py | 297 +++++++++++++++++++++- src/sage/groups/braid.py | 36 ++- 3 files changed, 329 insertions(+), 8 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 31cb3ec8074..d446d271889 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -568,6 +568,10 @@ REFERENCES: Springer Verlag 2006; pre-print available at http://eprint.iacr.org/2005/200 +.. [BQ2024] Asilata Bapat and Hoel Queffelec. + *Some remarks about the faithfulness of the Burau representation + of Artin-Tits groups*. Preprint, 2024. :arxiv:`2409.00144`. + .. [BBS1982] \L. Blum, M. Blum, and M. Shub. Comparison of Two Pseudo-Random Number Generators. *Advances in Cryptology: Proceedings of Crypto '82*, pp.61--78, 1982. diff --git a/src/sage/groups/artin.py b/src/sage/groups/artin.py index 2339394224e..01a3ab476ca 100644 --- a/src/sage/groups/artin.py +++ b/src/sage/groups/artin.py @@ -9,10 +9,17 @@ AUTHORS: - Travis Scrimshaw (2018-02-05): Initial version +- Travis Scrimshaw (2025-01-30): Allowed general construction; implemented + general Burau representation + +.. TODO:: + + Implement affine type Artin groups with their well-known embeddings into + the classical braid group. """ # **************************************************************************** -# Copyright (C) 2018 Travis Scrimshaw +# Copyright (C) 2018-2025 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 @@ -26,6 +33,7 @@ from sage.groups.free_group import FreeGroup from sage.groups.finitely_presented import FinitelyPresentedGroup, FinitelyPresentedGroupElement from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute from sage.rings.infinity import Infinity from sage.structure.richcmp import richcmp, rich_to_bool from sage.structure.unique_representation import UniqueRepresentation @@ -156,6 +164,132 @@ def coxeter_group_element(self, W=None): In = W.index_set() return W.prod(s[In[abs(i)-1]] for i in self.Tietze()) + def burau_matrix(self, var='t', reduced=False): + r""" + Return the Burau matrix of the Artin group element. + + Following [BQ2024]_, the (generalized) Burau representation of an + Artin group is defined by deforming the reflection representation + of the corresponding Coxeter group. However, we substitute + `q \mapsto -t` from [BQ2024]_ to match the unitary + + INPUT: + + - ``var`` -- string (default: ``'t'``); the name of the + variable in the entries of the matrix + + OUTPUT: + + The Burau matrix of the Artin group element over the Laurent + polynomial ring in the variable ``var``. + + EXAMPLES:: + + sage: A. = ArtinGroup(['B',3]) + sage: B1 = s1.burau_matrix() + sage: B2 = s2.burau_matrix() + sage: B3 = s3.burau_matrix() + sage: [B1, B2, B3] + [ + [-t^2 t 0] [ 1 0 0] [ 1 0 0] + [ 0 1 0] [ t -t^2 a*t] [ 0 1 0] + [ 0 0 1], [ 0 0 1], [ 0 a*t -t^2] + ] + sage: B1 * B2 * B1 == B2 * B1 * B2 + True + sage: B2 * B3 * B2 * B3 == B3 * B2 * B3 * B2 + True + sage: B1 * B3 == B3 * B1 + True + sage: (~s1).burau_matrix() * B1 == 1 + True + + We verify the example in Theorem 4.1 of [BQ2024]_:: + + sage: A. = ArtinGroup(['A', 3, 1]) + sage: [g.burau_matrix() for g in A.gens()] + [ + [-t^2 t 0 t] [ 1 0 0 0] [ 1 0 0 0] + [ 0 1 0 0] [ t -t^2 t 0] [ 0 1 0 0] + [ 0 0 1 0] [ 0 0 1 0] [ 0 t -t^2 t] + [ 0 0 0 1], [ 0 0 0 1], [ 0 0 0 1], + + [ 1 0 0 0] + [ 0 1 0 0] + [ 0 0 1 0] + [ t 0 t -t^2] + ] + sage: a = s3^2 * s4 * s3 * s2 *s1 * ~s3 * s4 * s3 * s2 * s1^-2 * s4 + sage: b = s1^2 * ~s2 * s4 * s1 * ~s3 * s2 * ~s4 * s3 * s1 * s4 * s1 * ~s2 * s4^-2 * s3 + sage: alpha = a * s3 * ~a + sage: beta = b * s2 * ~b + sage: elm = alpha * beta * ~alpha * ~beta + sage: print(elm.Tietze()) + (3, 3, 4, 3, 2, 1, -3, 4, 3, 2, -1, -1, 4, 3, -4, 1, 1, -2, -3, + -4, 3, -1, -2, -3, -4, -3, -3, 1, 1, -2, 4, 1, -3, 2, -4, 3, 1, + 4, 1, -2, -4, -4, 3, 2, -3, 4, 4, 2, -1, -4, -1, -3, 4, -2, 3, + -1, -4, 2, -1, -1, 3, 3, 4, 3, 2, 1, -3, 4, 3, 2, -1, -1, 4, + -3, -4, 1, 1, -2, -3, -4, 3, -1, -2, -3, -4, -3, -3, 1, 1, -2, + 4, 1, -3, 2, -4, 3, 1, 4, 1, -2, -4, -4, 3, -2, -3, 4, 4, 2, + -1, -4, -1, -3, 4, -2, 3, -1, -4, 2, -1, -1) + sage: elm.burau_matrix() + [1 0 0 0] + [0 1 0 0] + [0 0 1 0] + [0 0 0 1] + + Next, we show ``elm`` is not the identity by using the embedding of + the affine braid group `\widetilde{B}_n \to B_{n+1}`:: + + sage: B. = BraidGroup(5) + sage: D = t1 * t2 * t3 * t4^2 + sage: t0 = D * t3 * ~D + sage: t0*t1*t0 == t1*t0*t1 + True + sage: t0*t2 == t2*t0 + True + sage: t0*t3*t0 == t3*t0*t3 + True + sage: T = [t0, t1, t2, t3] + sage: emb = B.prod(T[i-1] if i > 0 else ~T[-i-1] for i in elm.Tietze()) + sage: emb.is_one() + False + + Since the Burau representation does not respect the group embedding, + the corresponding `B_5` element's Burau matrix is not the identity + (Bigelow gave an example of the representation not being faithful for + `B_5`, but it is still open for `B_4`):: + + sage: emb.burau_matrix() != 1 + True + + We also verify the result using the elements in [BQ2024]_ Remark 4.2:: + + sage: ap = s3 * s1 * s2 * s1 * ~s3 * s4 * s2 * s3 * s2 * ~s3 * s1^-2 * s4 + sage: bp = s1 * ~s4 * s1^2 * s3^-2 * ~s2 * s4 * s1 * ~s3 * s2 * ~s4 * s3 * s1 * s4 * s1 * ~s2 * s4^-2 * s3 + sage: alpha = ap * s3 * ~ap + sage: beta = bp * s2 * ~bp + sage: elm = alpha * beta * ~alpha * ~beta + sage: elm.burau_matrix() + [1 0 0 0] + [0 1 0 0] + [0 0 1 0] + [0 0 0 1] + + REFERENCES: + + - [BQ2024]_ + """ + gens, invs = self.parent()._burau_generators + MS = gens[0].parent() + ret = MS.prod(gens[i-1] if i > 0 else invs[-i-1] for i in self.Tietze()) + + if var == 't': + return ret + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + poly_ring = LaurentPolynomialRing(ret.base_ring().base_ring(), var) + return ret.change_ring(poly_ring) + class FiniteTypeArtinGroupElement(ArtinGroupElement): """ @@ -453,7 +587,7 @@ def __classcall_private__(cls, coxeter_data, names=None): from sage.groups.raag import RightAngledArtinGroup return RightAngledArtinGroup(coxeter_data.coxeter_graph(), names) if not coxeter_data.is_finite(): - raise NotImplementedError + return super().__classcall__(cls, coxeter_data, names) if coxeter_data.coxeter_type().cartan_type().type() == 'A': from sage.groups.braid import BraidGroup return BraidGroup(coxeter_data.rank()+1, names) @@ -476,15 +610,17 @@ def __init__(self, coxeter_matrix, names): rels = [] # Generate the relations based on the Coxeter graph I = coxeter_matrix.index_set() + gens = free_group.gens() for ii, i in enumerate(I): - for j in I[ii + 1:]: + for jj, j in enumerate(I[ii + 1:], start=ii+1): m = coxeter_matrix[i, j] if m == Infinity: # no relation continue - elt = [i, j] * m - for ind in range(m, 2*m): - elt[ind] = -elt[ind] - rels.append(free_group(elt)) + elt = (gens[ii] * gens[jj]) ** (m // 2) + if m % 2 == 1: + elt = elt * gens[ii] * ~gens[jj] + elt = elt * (~gens[ii] * ~gens[jj]) ** (m // 2) + rels.append(elt) FinitelyPresentedGroup.__init__(self, free_group, tuple(rels)) def _repr_(self): @@ -688,6 +824,153 @@ def _standard_lift(self, w): """ return self(self._standard_lift_Tietze(w)) + @lazy_attribute + def _burau_generators(self): + """ + The Burau matrices for the generators of ``self`` and their inverses. + + EXAMPLES:: + + sage: A = ArtinGroup(['G',2]) + sage: A._burau_generators + [[ + [-t^2 a*t] [ 1 0] + [ 0 1], [ a*t -t^2] + ], + [ + [ -t^-2 a*t^-1] [ 1 0] + [ 0 1], [a*t^-1 -t^-2] + ]] + + sage: A = ArtinGroup(['H',3]) + sage: A._burau_generators + [[ + [-t^2 t 0] [ 1 0 0] + [ 0 1 0] [ t -t^2 (1/2*a + 1/2)*t] + [ 0 0 1], [ 0 0 1], + + [ 1 0 0] + [ 0 1 0] + [ 0 (1/2*a + 1/2)*t -t^2] + ], + [ + [-t^-2 t^-1 0] + [ 0 1 0] + [ 0 0 1], + + [ 1 0 0] + [ t^-1 -t^-2 (1/2*a + 1/2)*t^-1] + [ 0 0 1], + + [ 1 0 0] + [ 0 1 0] + [ 0 (1/2*a + 1/2)*t^-1 -t^-2] + ]] + + sage: CM = matrix([[1,4,7], [4,1,10], [7,10,1]]) + sage: A = ArtinGroup(CM) + sage: gens = A._burau_generators[0]; gens + [ + [ -t^2 (E(8) - E(8)^3)*t (-E(7)^3 - E(7)^4)*t] + [ 0 1 0] + [ 0 0 1], + + [ 1 0 0] + [ (E(8) - E(8)^3)*t -t^2 (E(20) - E(20)^9)*t] + [ 0 0 1], + + [ 1 0 0] + [ 0 1 0] + [(-E(7)^3 - E(7)^4)*t (E(20) - E(20)^9)*t -t^2] + ] + sage: all(gens[i] * A._burau_generators[1][i] == 1 for i in range(3)) + True + sage: B1, B2, B3 = gens + sage: (B1 * B2)^2 == (B2 * B1)^2 + True + sage: (B2 * B3)^5 == (B3 * B2)^5 + True + sage: B1 * B3 * B1 * B3 * B1 * B3 * B1 == B3 * B1 * B3 * B1 * B3 * B1 * B3 + True + """ + data = self.coxeter_type() + coxeter_matrix = self.coxeter_matrix() + n = coxeter_matrix.rank() + + # Determine the base field + if data.is_simply_laced(): + from sage.rings.integer_ring import ZZ + base_ring = ZZ + elif data.is_finite(): + from sage.rings.number_field.number_field import QuadraticField + letter = data.cartan_type().type() + if letter in ['B', 'C', 'F']: + base_ring = QuadraticField(2) + elif letter == 'G': + base_ring = QuadraticField(3) + elif letter == 'H': + base_ring = QuadraticField(5) + else: + from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + base_ring = UniversalCyclotomicField() + else: + from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + base_ring = UniversalCyclotomicField() + + # Construct the matrices + from sage.matrix.args import SparseEntry + from sage.matrix.matrix_space import MatrixSpace + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + import sage.rings.abc + poly_ring = LaurentPolynomialRing(base_ring, 't') + q = -poly_ring.gen() + MS = MatrixSpace(poly_ring, n, sparse=True) + one = MS.one() + # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty + if isinstance(base_ring, sage.rings.abc.UniversalCyclotomicField): + E = base_ring.gen + + def val(x): + if x == -1: + return 2 * q + elif x == 1: + return 1 + q**2 + else: + return q * (E(2*x) + ~E(2*x)) + elif isinstance(base_ring, sage.rings.abc.NumberField_quadratic): + from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + E = UniversalCyclotomicField().gen + + def val(x): + if x == -1: + return 2 * q + elif x == 1: + return 1 + q**2 + else: + return q * base_ring((E(2 * x) + ~E(2 * x)).to_cyclotomic_field()) + else: + def val(x): + if x == -1: + return 2 * q + elif x == 1: + return 1 + q**2 + elif x == 2: + return 0 + elif x == 3: + return q + else: + from sage.functions.trig import cos + from sage.symbolic.constants import pi + return q * base_ring(2 * cos(pi / x)) + index_set = data.index_set() + gens = [one - MS([SparseEntry(i, j, val(coxeter_matrix[index_set[i], index_set[j]])) + for j in range(n)]) + for i in range(n)] + invs = [one - q**-2 * MS([SparseEntry(i, j, val(coxeter_matrix[index_set[i], index_set[j]])) + for j in range(n)]) + for i in range(n)] + return [gens, invs] + Element = ArtinGroupElement diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index ce0375b121f..f302118904b 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -226,7 +226,7 @@ def burau_matrix(self, var='t', reduced=False): sage: B = BraidGroup(4) sage: B.inject_variables() Defining s0, s1, s2 - sage: b = s0*s1/s2/s1 + sage: b = s0 * s1 / s2 / s1 sage: b.burau_matrix() [ 1 - t 0 t - t^2 t^2] [ 1 0 0 0] @@ -265,6 +265,40 @@ def burau_matrix(self, var='t', reduced=False): sage: M * H * Madj == H True + The adjoined matrix (``Madj`` in the above example) matches the + output of :meth:`sage.groups.artin.ArtinGroupElement.burau_matrix`:: + + sage: from sage.groups.artin import ArtinGroupElement + sage: Madj == ArtinGroupElement.burau_matrix(b) + True + + sage: a = s0^2 * s1 * s0 * s2 *s1 * ~s0 * s1^3 * s0 * s2 * s1^-2 * s0 + sage: a.burau_matrix(reduced='unitary')[1] == ArtinGroupElement.burau_matrix(a) + True + + We verify Bigelow's example that in `B_5` the Burau representation + is not faithful:: + + sage: B. = BraidGroup(5) + sage: psi1 = ~s3 * s2 * s1^2 * s2 * s4^3 * s3 * s2 + sage: psi2 = ~s4 * s3 * s2 * s1^-2 * s2 * s1^2 * s2^2 * s1 * s4^5 + sage: alpha = ~psi1 * s4 * psi1 + sage: beta = ~psi2 * s4 * s3 * s2 * s1^2 * s2 * s3 * s4 * psi2 + sage: elm = alpha * beta * ~alpha * ~beta + sage: elm.burau_matrix() + [1 0 0 0 0] + [0 1 0 0 0] + [0 0 1 0 0] + [0 0 0 1 0] + [0 0 0 0 1] + sage: elm.burau_matrix(reduced=True) + [1 0 0 0] + [0 1 0 0] + [0 0 1 0] + [0 0 0 1] + sage: elm.is_one() + False + REFERENCES: - :wikipedia:`Burau_representation` From 07517dd7e84c49773fa5fcc89e4111a2f4fd0099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 31 Jan 2025 09:15:46 +0100 Subject: [PATCH 135/187] code detail --- src/sage/combinat/posets/posets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index f9f6e0c0f12..173cbb872da 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -5305,7 +5305,7 @@ def factor(self): prod_dg = dg.relabel(dic, inplace=False) v0 = next(iter(dic.values())) n = len(v0) - factors_range = list(range(n)) + factors_range = range(n) fusion = Graph(n) def edge_color(va, vb): From db52fb0c402dc8572126db5b6d5c6098ba599003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 31 Jan 2025 09:23:47 +0100 Subject: [PATCH 136/187] other code details --- src/sage/combinat/affine_permutation.py | 91 ++++++++++++------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/src/sage/combinat/affine_permutation.py b/src/sage/combinat/affine_permutation.py index 4060ea9793f..cc2a03ec499 100644 --- a/src/sage/combinat/affine_permutation.py +++ b/src/sage/combinat/affine_permutation.py @@ -304,7 +304,7 @@ def reduced_word(self): sage: p.reduced_word() [0, 7, 4, 1, 0, 7, 5, 4, 2, 1] """ - #This is about 25% faster than the default algorithm. + # This is about 25% faster than the default algorithm. x = self i = 0 word = [] @@ -409,10 +409,10 @@ def grassmannian_quotient(self, i=0, side='right'): class AffinePermutationTypeA(AffinePermutation): - #---------------------- - #Type-specific methods. - #(Methods existing in all types, but with type-specific definition.) - #---------------------- + # ---------------------- + # Type-specific methods. + # (Methods existing in all types, but with type-specific definition.) + # ---------------------- def check(self): r""" Check that ``self`` is an affine permutation. @@ -510,11 +510,11 @@ def apply_simple_reflection_right(self, i): Type A affine permutation with window [3, -1, 6, 0, 5, 4, 10, 9] """ j = i % (self.k+1) - #Cloning is currently kinda broken, in that caches don't clear which - #leads to strangeness with the cloned object. - #The clone approach is quite a bit (2x) faster, though, so this should - #switch once the caching situation is fixed. - #with self.clone(check=False) as l: + # Cloning is currently kinda broken, in that caches don't clear which + # leads to strangeness with the cloned object. + # The clone approach is quite a bit (2x) faster, though, so this should + # switch once the caching situation is fixed. + # with self.clone(check=False) as l: l = self[:] if j == 0: a = l[0] @@ -524,7 +524,6 @@ def apply_simple_reflection_right(self, i): a = l[j-1] l[j-1] = l[j] l[j] = a - #return l return type(self)(self.parent(), l, check=False) def apply_simple_reflection_left(self, i): @@ -539,18 +538,18 @@ def apply_simple_reflection_left(self, i): sage: p.apply_simple_reflection_left(11) Type A affine permutation with window [4, -1, 0, 6, 5, 3, 10, 9] """ - #Here are a couple other methods we tried out, but turned out - #to be slower than the current implementation. - #1) This one was very bad: - # return self.inverse().apply_simple_reflection_right(i).inverse() - #2) Also bad, though not quite so bad: - # return (self.parent().simple_reflection(i))*self - i = i % (self.k+1) - #Cloning is currently kinda broken, in that caches don't clear which - #leads to strangeness with the cloned object. - #The clone approach is quite a bit faster, though, so this should switch - #once the caching situation is fixed. - #with self.clone(check=False) as l: + # Here are a couple other methods we tried out, but turned out + # to be slower than the current implementation. + # 1) This one was very bad: + # return self.inverse().apply_simple_reflection_right(i).inverse() + # 2) Also bad, though not quite so bad: + # return (self.parent().simple_reflection(i))*self + i = i % (self.k + 1) + # Cloning is currently kinda broken, in that caches don't clear which + # leads to strangeness with the cloned object. + # The clone approach is quite a bit faster, though, + # so this should switch once the caching situation is fixed. + # with self.clone(check=False) as l: l = [] if i != self.k: for m in range(self.k + 1): @@ -627,10 +626,10 @@ def to_type_a(self): """ return self - #---------------------- - #Type-A-specific methods. - #Only available in Type A. - #---------------------- + # ---------------------- + # Type-A-specific methods. + # Only available in Type A. + # ---------------------- def flip_automorphism(self): r""" @@ -699,7 +698,7 @@ def maximal_cyclic_factor(self, typ='decreasing', side='right', verbose=False): else: descents = self.descents(side='left') side = 'left' - #for now, assume side is 'right') + # for now, assume side is 'right') best_T = [] for i in descents: y = self.clone().apply_simple_reflection(i,side) @@ -834,8 +833,8 @@ def to_lehmer_code(self, typ='decreasing', side='right'): """ code = [0 for i in range(self.k+1)] if typ[0] == 'i' and side[0] == 'r': - #Find number of positions to the right of position i with smaller - #value than the number in position i. + # Find number of positions to the right of position i with smaller + # value than the number in position i. for i in range(self.k+1): a = self(i) for j in range(i+1, i+self.k+1): @@ -843,9 +842,9 @@ def to_lehmer_code(self, typ='decreasing', side='right'): if b < a: code[i] += (a-b) // (self.k+1) + 1 elif typ[0] == 'd' and side[0] == 'r': - #Find number of positions to the left of position i with larger - #value than the number in position i. Then cyclically shift - #the resulting vector. + # Find number of positions to the left of position i with larger + # value than the number in position i. Then cyclically shift + # the resulting vector. for i in range(self.k+1): a = self(i) for j in range(i-self.k, i): @@ -855,18 +854,18 @@ def to_lehmer_code(self, typ='decreasing', side='right'): if a < b: code[i-1] += ((b-a)//(self.k+1)+1) elif typ[0] == 'i' and side[0] == 'l': - #Find number of positions to the right of i smaller than i, then - #cyclically shift the resulting vector. + # Find number of positions to the right of i smaller than i, then + # cyclically shift the resulting vector. for i in range(self.k+1): pos = self.position(i) for j in range(pos+1, pos+self.k+1): b = self(j) - #A small rotation is necessary for the reduced word from - #the lehmer code to match the element. + # A small rotation is necessary for the reduced word from + # the lehmer code to match the element. if b < i: code[i-1] += (i-b) // (self.k+1) + 1 elif typ[0] == 'd' and side[0] == 'l': - #Find number of positions to the left of i larger than i. + # Find number of positions to the left of i larger than i. for i in range(self.k+1): pos = self.position(i) for j in range(pos-self.k, pos): @@ -1103,7 +1102,7 @@ def value(self, i): sage: C = AffinePermutationGroup(['C',4,1]) sage: x = C.one() - sage: [x.value(i) for i in range(-10,10)] == list(range(-10,10)) + sage: all(x.value(i) == i for i in range(-10,10)) True """ N = 2*self.k + 1 @@ -1124,7 +1123,7 @@ def position(self, i): sage: C = AffinePermutationGroup(['C',4,1]) sage: x = C.one() - sage: [x.position(i) for i in range(-10,10)] == list(range(-10,10)) + sage: all(x.position(i) == i for i in range(-10,10)) True """ N = 2*self.k + 1 @@ -2242,12 +2241,12 @@ def one(self): True sage: TestSuite(A).run() """ - return self(list(range(1, self.k + 2))) + return self(range(1, self.k + 2)) - #------------------------ - #Type-unique methods. - #(Methods which do not exist in all types.) - #------------------------ + # ------------------------ + # Type-unique methods. + # (Methods which do not exist in all types.) + # ------------------------ def from_lehmer_code(self, C, typ='decreasing', side='right'): r""" Return the affine permutation with the supplied Lehmer code (a weak @@ -2353,7 +2352,7 @@ def one(self): True sage: TestSuite(C).run() """ - return self(list(range(1, self.k + 1))) + return self(range(1, self.k + 1)) Element = AffinePermutationTypeC From de5834187ea071a1522c3e83f660683e6cdd7ec2 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 31 Jan 2025 14:27:09 -0600 Subject: [PATCH 137/187] more spkg-configures (new/fixes) --- build/pkgs/h11/spkg-configure.m4 | 1 + build/pkgs/symengine_py/spkg-configure.m4 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 build/pkgs/h11/spkg-configure.m4 diff --git a/build/pkgs/h11/spkg-configure.m4 b/build/pkgs/h11/spkg-configure.m4 new file mode 100644 index 00000000000..4e2f4839a5f --- /dev/null +++ b/build/pkgs/h11/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([h11], [SAGE_PYTHON_PACKAGE_CHECK([h11])]) diff --git a/build/pkgs/symengine_py/spkg-configure.m4 b/build/pkgs/symengine_py/spkg-configure.m4 index 9559bdb6da0..b065d24fbb9 100644 --- a/build/pkgs/symengine_py/spkg-configure.m4 +++ b/build/pkgs/symengine_py/spkg-configure.m4 @@ -1 +1 @@ -SAGE_SPKG_CONFIGURE([symengine_py], [SAGE_PYTHON_PACKAGE_CHECK([symengine_py])]) +SAGE_SPKG_CONFIGURE([symengine_py], [SAGE_PYTHON_PACKAGE_CHECK([symengine])]) From 5d35cf43f899825b3f3bb5d80f91c9d702410fa9 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 1 Feb 2025 11:43:44 +0530 Subject: [PATCH 138/187] updated is_brick() --- src/sage/graphs/matching_covered_graph.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 0fec9cfc394..9ad39482a85 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -3098,17 +3098,16 @@ def is_brick(self, coNP_certificate=False): spqr_tree = self.spqr_tree() two_vertex_cut = [] - # Check for 2-vertex cuts in P and S nodes + # Check for 2-vertex cuts in a P node + # Since the graph is matching covered, it is free of cut vertices + # It can be shown using counting arguments that the spqr tree + # decomposition for a bicritical graph, that is 2-connected but not + # 3-connected, is free of 'S' nodes for u in spqr_tree: if u[0] == 'P': two_vertex_cut.extend(u[1]) break - elif u[0] == 'S' and u[1].order() > 3: - s_vertex_set = set(u[1]) - s_vertex_set -= {next(u[1].vertex_iterator())} | set(u[1].neighbors(next(u[1].vertex_iterator()))) - two_vertex_cut.extend([next(u[1].vertex_iterator()), next(iter(s_vertex_set))]) - # If no 2-vertex cut found, look for R nodes if not two_vertex_cut: from collections import Counter @@ -3117,6 +3116,9 @@ def is_brick(self, coNP_certificate=False): for t, g in spqr_tree: if t == 'R': R_frequency.update(g) + + # R frequency must be at least 2, + # since the graph is 2-connected but not 3-connected two_vertex_cut = [u for u, f in R_frequency.items() if f >= 2][:2] # We obtain a 2-vertex cut (u, v) From 44153509abe345129280a871dc66d2894012dd89 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 1 Feb 2025 12:31:20 +0530 Subject: [PATCH 139/187] added a doctest for is_brace() --- src/sage/graphs/matching_covered_graph.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 9ad39482a85..4ac0071b2a6 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2641,6 +2641,15 @@ def is_brace(self, coNP_certificate=False): sage: cut_identifier == {a for u, v, *_ in nontrivial_tight_cut for a in [u, v] \ ....: if a not in nontrivial_odd_component} True + sage: H = graphs.CompleteBipartiteGraph(3, 3) + sage: H.delete_edge(0, 3) + sage: G = MatchingCoveredGraph(G) + sage: G.is_brace(coNP_certificate=True) + (False, + [(1, 2, None), (1, 4, None), (3, 4, None)], + {0, 1, 3}, + 'nontrivial barrier cut', + {2, 4}) If the input matching covered graph is nonbipartite, a :exc:`ValueError` is thrown:: From e12674ae3be9299c6c1e9cc6e05ff8f1e03b8260 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 1 Feb 2025 12:40:47 +0530 Subject: [PATCH 140/187] updated is_brace() --- src/sage/graphs/matching_covered_graph.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 4ac0071b2a6..b52333443a9 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -2643,13 +2643,13 @@ def is_brace(self, coNP_certificate=False): True sage: H = graphs.CompleteBipartiteGraph(3, 3) sage: H.delete_edge(0, 3) - sage: G = MatchingCoveredGraph(G) + sage: G = MatchingCoveredGraph(H) sage: G.is_brace(coNP_certificate=True) (False, - [(1, 2, None), (1, 4, None), (3, 4, None)], - {0, 1, 3}, + [(4, 1, None), (5, 1, None), (4, 2, None), (5, 2, None)], + {0, 4, 5}, 'nontrivial barrier cut', - {2, 4}) + {1, 2}) If the input matching covered graph is nonbipartite, a :exc:`ValueError` is thrown:: From 91181a27cfafc91f42243daf53a8e134568b879d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 1 Feb 2025 09:13:22 +0100 Subject: [PATCH 141/187] fix one optional internet doctest in oeis.py --- src/sage/databases/oeis.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index dec5cabd8a4..77d3473a21f 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -1809,11 +1809,9 @@ def programs(self, language='all', preparsing=True, keep_comments=False): EXAMPLES:: - sage: ee = oeis('A001113') ; ee # optional -- internet - A001113: Decimal expansion of e. - + sage: ee = oeis.find_by_id('A00260') # optional -- internet sage: ee.programs('pari')[0] # optional -- internet - 0: default(realprecision, 50080); x=exp(1); for (n=1, 50000, d=floor(x); x=(x-d)*10; write("b001113.txt", n, " ", d)); \\ _Harry J. Smith_, Apr 15 2009 + 0: {a(n) = binomial(...)};... sage: G = oeis.find_by_id('A27642') # optional -- internet sage: G.programs('all') # optional -- internet From 2a3aee06e79ea2c4f442a1a96e632fce8bad1197 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sat, 1 Feb 2025 18:42:46 +0700 Subject: [PATCH 142/187] Fix bug with sage_getfile in meson editable install --- src/sage/misc/sageinspect.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 12f319fc8e3..4f7aed2820f 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -276,8 +276,10 @@ def _extract_embedded_position(docstring): from sage.misc.temporary_file import spyx_tmp if raw_filename.startswith('sage/'): import sage - try_filenames = [os.path.join(directory, raw_filename[5:]) + from sage.env import SAGE_SRC + try_filenames = [os.path.join(directory, raw_filename.removeprefix('sage/')) for directory in sage.__path__] + try_filenames.append(os.path.join(SAGE_SRC, raw_filename)) # meson editable install else: try_filenames = [] try_filenames.append( @@ -1286,6 +1288,15 @@ def sage_getfile(obj): sage: sage_getfile(P) # needs sage.libs.singular '...sage/rings/polynomial/multi_polynomial_libsingular...' + Another bug with editable meson install:: + + sage: P. = QQ[] + sage: I = P * [x,y] + sage: path = sage_getfile(I.groebner_basis); path + '.../sage/rings/qqbar_decorators.py' + sage: path == sage_getfile(sage.rings.qqbar_decorators) + True + A problem fixed in :issue:`16309`:: sage: cython( # needs sage.misc.cython @@ -1325,7 +1336,7 @@ def sage_getfile(obj): return '' for suffix in import_machinery.EXTENSION_SUFFIXES: if sourcefile.endswith(suffix): - return sourcefile[:-len(suffix)]+os.path.extsep+'pyx' + return sourcefile.removesuffix(suffix)+os.path.extsep+'pyx' return sourcefile From 6478f4386e8dcdee16231c5022d18d33b91d6e35 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sat, 1 Feb 2025 19:47:05 +0700 Subject: [PATCH 143/187] Revert "Test pip editable install with meson" This reverts commit b1ae7383d87ac72364ae75bb32a18c3a662dbc7f. --- .github/workflows/ci-meson.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-meson.yml b/.github/workflows/ci-meson.yml index 56d01aaffbb..ab073aae87c 100644 --- a/.github/workflows/ci-meson.yml +++ b/.github/workflows/ci-meson.yml @@ -16,7 +16,7 @@ concurrency: jobs: test: - name: Conda (${{ matrix.os }}, Python ${{ matrix.python }}${{ matrix.editable && ', editable' || '' }}) + name: Conda (${{ matrix.os }}, Python ${{ matrix.python }}) runs-on: ${{ matrix.os }}-latest strategy: @@ -24,7 +24,6 @@ jobs: matrix: os: [ubuntu] python: ['3.11', '3.12'] - editable: [false, true] steps: - uses: actions/checkout@v4 @@ -71,7 +70,7 @@ jobs: export CC="ccache $CC" export CXX="ccache $CXX" # Use --no-deps and pip check below to verify that all necessary dependencies are installed via conda - pip install --no-build-isolation --no-deps --config-settings=builddir=builddir ${{ matrix.editable && '--editable' || '' }} . -v + pip install --no-build-isolation --no-deps --config-settings=builddir=builddir . -v - name: Verify dependencies shell: bash -l {0} @@ -81,9 +80,7 @@ jobs: shell: bash -l {0} run: | # We don't install sage_setup, so don't try to test it - # If editable then deleting the directory will cause sage to detect rebuild, which will cause ninja to fail - # so we don't delete the directory in this case - ${{ matrix.editable && 'true' || 'rm -R ./src/sage_setup/' }} + rm -R ./src/sage_setup/ ./sage -t --all -p4 - name: Upload log From d150e18ad6d06b4e2b1051a123c98735179a0d61 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Sat, 1 Feb 2025 21:31:06 +0700 Subject: [PATCH 144/187] Fix basis of multivariate polynomial ring --- src/sage/combinat/integer_vector.py | 10 +++++ .../polynomial/multi_polynomial_ring_base.pyx | 39 +++++++++++++++++-- src/sage/rings/polynomial/polydict.pyx | 3 +- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index 6848609cf5d..3ee66212f11 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -1043,11 +1043,21 @@ def __iter__(self): [2, 1], [1, 2], [0, 3]] + + TESTS: + + Check corner case:: + + sage: IV = IntegerVectors(k=0) + sage: list(IV) + [[]] """ n = 0 while True: for iv in integer_vectors_nk_fast_iter(n, self.k): yield self.element_class(self, iv, check=False) + if self.k == 0: + return n += 1 def __contains__(self, x): diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index 8baa8b40b24..cdd4c859af0 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -77,6 +77,20 @@ cdef class MPolynomialRing_base(CommutativeRing): ....: pass sage: Foo(QQ, 2, ['x','y'], 'degrevlex') # needs sage.libs.singular Multivariate Polynomial Ring in x, y over Rational Field + + Check that :meth:`basis` works correctly:: + + sage: R = PolynomialRing(QQ, []) + sage: R.basis() + Lazy family (...monomial...(i))_{i in Integer vectors of length 0} + sage: [*R.basis()] + [1] + sage: R. = QQ[] + sage: R.basis() + Lazy family (...monomial...(i))_{i in Integer vectors of length 2} + sage: import itertools + sage: list(itertools.islice(R.basis(), 16)) + [1, x, y, x^2, x*y, y^2, x^3, x^2*y, x*y^2, y^3, x^4, x^3*y, x^2*y^2, x*y^3, y^4, x^5] """ if base_ring not in _CommutativeRings: raise TypeError("The base ring %s is not a commutative ring" % base_ring) @@ -97,7 +111,7 @@ cdef class MPolynomialRing_base(CommutativeRing): # Ring.__init__ assigns the names. Ring.__init__(self, base_ring, names, category=category) from sage.combinat.integer_vector import IntegerVectors - self._indices = IntegerVectors(self._ngens) + self._indices = IntegerVectors(length=self._ngens) def is_integral_domain(self, proof=True): """ @@ -1380,13 +1394,32 @@ cdef class MPolynomialRing_base(CommutativeRing): TESTS: - Check that ETuples also work:: + Check that :class:`.ETuple`s and :class:`.IntegerVector` also work + (:class:`.IntegerVector` is used for :meth:`basis`):: + sage: from sage.combinat.integer_vector import IntegerVector, IntegerVectors sage: from sage.rings.polynomial.polydict import ETuple sage: R.monomial(ETuple(e)) x*y^2*z^3 + sage: R.monomial(IntegerVector(IntegerVectors(), e)) + x*y^2*z^3 + + Corner case:: + + sage: R = PolynomialRing(QQ, []) + sage: R + Multivariate Polynomial Ring in no variables over Rational Field + sage: R.monomial(()) + 1 + sage: R.monomial() + 1 + sage: R.monomial(ETuple([])) + 1 + sage: R.monomial(IntegerVector(IntegerVectors(), [])) + 1 """ - if len(exponents) == 1 and isinstance((e := exponents[0]), (tuple, ETuple)): + from sage.combinat.integer_vector import IntegerVector + if len(exponents) == 1 and isinstance((e := exponents[0]), (tuple, IntegerVector, ETuple)): return self({e: self.base_ring().one()}) return self({exponents: self.base_ring().one()}) diff --git a/src/sage/rings/polynomial/polydict.pyx b/src/sage/rings/polynomial/polydict.pyx index fe2438c8e4f..43cb77e823e 100644 --- a/src/sage/rings/polynomial/polydict.pyx +++ b/src/sage/rings/polynomial/polydict.pyx @@ -1481,6 +1481,7 @@ cdef class ETuple: return cdef size_t ind cdef int v + from sage.combinat.integer_vector import IntegerVector if isinstance(data, ETuple): self._length = (data)._length self._nonzero = (data)._nonzero @@ -1496,7 +1497,7 @@ cdef class ETuple: self._data[2*ind] = index self._data[2*ind+1] = exp ind += 1 - elif isinstance(data, (list, tuple)): + elif isinstance(data, (list, tuple, IntegerVector)): self._length = len(data) self._nonzero = 0 for v in data: From 5cf5a34efc9b6e236cf14252c3c5525fbcf911d4 Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Sat, 1 Feb 2025 20:44:13 +0200 Subject: [PATCH 145/187] Declare `del_edge` as cpdef Consistent with its parent class; a build warning gets resolved: ``` warning: /home/runner/work/sage/sage/src/sage/graphs/base/static_sparse_backend.pyx:677:4: Overriding cdef method with def method. ``` --- src/sage/graphs/base/static_sparse_backend.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index 62bce67f5c0..53189984bee 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -674,7 +674,7 @@ cdef class StaticSparseBackend(CGraphBackend): """ raise ValueError("graph is immutable; please change a copy instead (use function copy())") - def del_edge(self, object u, object v, object l, bint directed): + cpdef del_edge(self, object u, object v, object l, bint directed): r""" Delete an edge of the graph. No way. From aaa07053e8cc9eae1b2adfda7289f78c9b880019 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sun, 2 Feb 2025 01:45:54 +0000 Subject: [PATCH 146/187] fix coefficients method --- src/sage/modular/modform/element.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index ef7ab1fe1cf..16cb86c129b 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -550,7 +550,8 @@ def coefficients(self, X): self.__coefficients except AttributeError: self.__coefficients = {} - X = list(range(1, ZZ(X) + 1)) + if isinstance(X, (int, Integer)): + X = list(range(1, ZZ(X) + 1)) Y = [n for n in X if n not in self.__coefficients] v = self._compute(Y) for i in range(len(v)): From 744fda607eb9de8410f00391941c81ba1aac591b Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 31 Jan 2025 17:04:17 +0000 Subject: [PATCH 147/187] src/sage/misc/latex.py: drop the "engine_name" option This does nothing, except waste your time trying to ensure that it is consistent with the "engine" property and that It iS PrOpErLy CapItALizEd. --- src/sage/misc/latex.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 9d8fcd4a341..5a999a9d23b 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -485,16 +485,16 @@ def default_engine(): sage: from sage.misc.latex import default_engine sage: default_engine() # random - ('lualatex', 'LuaLaTeX') + 'lualatex' """ from sage.features.latex import pdflatex, xelatex, lualatex if lualatex().is_present(): - return 'lualatex', 'LuaLaTeX' + return 'lualatex' if xelatex().is_present(): - return 'xelatex', 'XeLaTeX' + return 'xelatex' if pdflatex().is_present(): - return 'pdflatex', 'pdfLaTeX' - return 'latex', 'LaTeX' + return 'pdflatex' + return 'latex' class _Latex_prefs_object(SageObject): @@ -535,11 +535,9 @@ def _option(self): 'matrix_column_alignment': 'r', 'macros': '', 'preamble': '', - 'engine': 'lualatex', - 'engine_name': 'LuaLaTeX'} + 'engine': 'lualatex'} """ - self.__option["engine"] = default_engine()[0] - self.__option["engine_name"] = default_engine()[1] + self.__option["engine"] = default_engine() return self.__option @@ -1535,16 +1533,12 @@ def engine(self, e=None): if e == "latex": _Latex_prefs._option["engine"] = "latex" - _Latex_prefs._option["engine_name"] = "LaTeX" elif e == "pdflatex": _Latex_prefs._option["engine"] = "pdflatex" - _Latex_prefs._option["engine_name"] = "PDFLaTeX" elif e == "xelatex": _Latex_prefs._option["engine"] = e - _Latex_prefs._option["engine_name"] = "XeLaTeX" elif e == "lualatex": _Latex_prefs._option["engine"] = e - _Latex_prefs._option["engine_name"] = "LuaLaTeX" else: raise ValueError("%s is not a supported LaTeX engine. Use latex, pdflatex, xelatex, or lualatex" % e) From ff24ef51750e0f59929f8efcce38b976378b1f72 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 31 Jan 2025 17:13:16 +0000 Subject: [PATCH 148/187] src/sage/misc/latex.py: default the "engine" option to None This delays probing the default engine (which tries to compile some LaTeX code in a temporary directory) when you merely wish to query e.g. the matrix delimiters. A later commit will re-insert the probe at a later point. The doctest for the options dict was updated to print a sorted list of items, so now its output is no longer random. --- src/sage/misc/latex.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 5a999a9d23b..9cebc898306 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -519,6 +519,7 @@ def __init__(self, bb=False, delimiters=["(", ")"], self.__option["matrix_column_alignment"] = matrix_column_alignment self.__option["macros"] = "" self.__option["preamble"] = "" + self.__option["engine"] = None @lazy_attribute def _option(self): @@ -528,16 +529,16 @@ def _option(self): EXAMPLES:: sage: from sage.misc.latex import _Latex_prefs_object - sage: _Latex_prefs_object()._option # random - {'blackboard_bold': False, - 'matrix_delimiters': ['(', ')'], - 'vector_delimiters': ['(', ')'], - 'matrix_column_alignment': 'r', - 'macros': '', - 'preamble': '', - 'engine': 'lualatex'} + sage: sorted(_Latex_prefs_object()._option.items()) + [('blackboard_bold', False), + ('engine', None), + ('macros', ''), + ('matrix_column_alignment', 'r'), + ('matrix_delimiters', ['(', ')']), + ('preamble', ''), + ('vector_delimiters', ['(', ')'])] + """ - self.__option["engine"] = default_engine() return self.__option From 3b3030484ae284b0fd035ebf486704cbac611192 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 31 Jan 2025 17:26:47 +0000 Subject: [PATCH 149/187] src/sage/misc/latex.py: invoke default_engine() as late as possible When we try to find the current LaTeX engine, the preferences dict will now have __options["engine"] == None to indicate that we should fall back to the default engine. In each case we check for None, and invoke default_engine() only if necessary. This allows us to query the options dict without triggering the expensive is_functional() method for the LaTeX features. --- src/sage/misc/latex.py | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 9cebc898306..5cd7fca23b4 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -519,6 +519,8 @@ def __init__(self, bb=False, delimiters=["(", ")"], self.__option["matrix_column_alignment"] = matrix_column_alignment self.__option["macros"] = "" self.__option["preamble"] = "" + + # If None, the default_engine() will be used. self.__option["engine"] = None @lazy_attribute @@ -648,6 +650,8 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i """ if engine is None: engine = _Latex_prefs._option["engine"] + if engine is None: + engine = default_engine() if not engine or engine == "latex": from sage.features.latex import latex @@ -1061,10 +1065,12 @@ def eval(self, x, globals, strip=False, filename=None, debug=None, O.close() if engine is None: - if self.__engine is None: + engine = self.__engine + if engine is None: engine = _Latex_prefs._option["engine"] - else: - engine = self.__engine + if engine is None: + engine = default_engine() + e = _run_latex_(os.path.join(base, filename + ".tex"), debug=debug, density=density, @@ -1530,19 +1536,17 @@ def engine(self, e=None): 'pdflatex' """ if e is None: - return _Latex_prefs._option["engine"] - - if e == "latex": - _Latex_prefs._option["engine"] = "latex" - elif e == "pdflatex": - _Latex_prefs._option["engine"] = "pdflatex" - elif e == "xelatex": - _Latex_prefs._option["engine"] = e - elif e == "lualatex": - _Latex_prefs._option["engine"] = e - else: + e = _Latex_prefs._option["engine"] + if e is None: + return default_engine() + else: + return e + + if e not in ["latex", "pdflatex", "xelatex", "luatex"]: raise ValueError("%s is not a supported LaTeX engine. Use latex, pdflatex, xelatex, or lualatex" % e) + _Latex_prefs._option["engine"] = e + # Note: latex used to be a separate function, which by default was # only loaded in command-line mode: in the old notebook, @@ -1841,6 +1845,9 @@ def view(objects, title='Sage', debug=False, sep='', tiny=False, s = _latex_file_(objects, title=title, sep=sep, tiny=tiny, debug=debug, **latex_options) if engine is None: engine = _Latex_prefs._option["engine"] + if engine is None: + engine = default_engine() + if viewer == "pdf" and engine == "latex": engine = "pdflatex" # command line or notebook with viewer @@ -1942,6 +1949,9 @@ def pdf(x, filename, tiny=False, tightpage=True, margin=None, engine=None, debug s = _latex_file_([x], title='', tiny=tiny, debug=debug, **latex_options) if engine is None: engine = _Latex_prefs._option["engine"] + if engine is None: + engine = default_engine() + # path name for permanent pdf output abs_path_to_pdf = os.path.abspath(filename) # temporary directory to store stuff @@ -2002,6 +2012,9 @@ def png(x, filename, density=150, debug=False, extra_preamble='\\textheight=2\\textheight') if engine is None: engine = _Latex_prefs._option["engine"] + if engine is None: + engine = default_engine() + # path name for permanent png output abs_path_to_png = os.path.abspath(filename) # temporary directory to store stuff From 2aa371e99c28d72ad66f79f7b9f0c9eb2c13647b Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 2 Feb 2025 01:48:49 +0000 Subject: [PATCH 150/187] src/sage/misc/latex.py: add a test for the laziness of default_engine() We should not need to test the functionality of various engines before we can e.g. obtain the latex representation of a matrix. We add a doctest to ensure that this is the case. Closes GH-39351 --- src/sage/misc/latex.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 5cd7fca23b4..9023857adbc 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -475,7 +475,7 @@ def has_latex_attr(x) -> bool: @cached_function def default_engine(): - """ + r""" Return the default latex engine and the official name of the engine. This is determined by availability of the popular engines on the user's @@ -486,6 +486,25 @@ def default_engine(): sage: from sage.misc.latex import default_engine sage: default_engine() # random 'lualatex' + + TESTS: + + Ensure that this (expensive) function is not necessary to obtain + the latex representation of a matrix (doing so probes the latex + options dict for the delimiters):: + + sage: import sage.misc.latex + sage: real_de = sage.misc.latex.default_engine + sage: def crash(): + ....: raise ValueError + sage: sage.misc.latex.default_engine = crash + sage: latex(matrix.identity(QQ, 2)) + \left(\begin{array}{rr} + 1 & 0 \\ + 0 & 1 + \end{array}\right) + sage: sage.misc.latex.default_engine = real_de + """ from sage.features.latex import pdflatex, xelatex, lualatex if lualatex().is_present(): From 2b22f25a6f7ef31c4e29e8333128349643e14eb0 Mon Sep 17 00:00:00 2001 From: Noel Roemmele Date: Sat, 1 Feb 2025 20:21:05 -0700 Subject: [PATCH 151/187] Fixed error in the FFT.__setitem__ function. The function was assuming that the pair of values was uninitalized when assigning values to it. --- src/sage/calculus/transforms/fft.pyx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/calculus/transforms/fft.pyx b/src/sage/calculus/transforms/fft.pyx index 1f190f00685..1b84daa02ee 100644 --- a/src/sage/calculus/transforms/fft.pyx +++ b/src/sage/calculus/transforms/fft.pyx @@ -163,6 +163,16 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): Traceback (most recent call last): ... TypeError: unable to convert 1.0*I to float; use abs() or real_part() as desired + + TESTS: + + Assigning a value to a pair no longer assumes that the values are uninitialized. :: + + sage: F = FFT(1) + sage: F[0] = (1,1) + sage: F[0] = 1 + sage: F[0] + (1.0, 0.0) """ # just set real for now if i < 0 or i >= self.n: @@ -172,6 +182,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): self.data[2*i+1] = xy[1] else: self.data[2*i] = xy + self.data[2*i+1] = 0 def __getitem__(self, i): """ From 8ed829c9011fcec0560eae7a0a249980e2889568 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 2 Feb 2025 03:14:58 +0000 Subject: [PATCH 152/187] src/sage/misc/latex.py: make default_engine() an internal function This function is relatively new and is only used in sage.misc.latex. I don't think there is a compelling need to have it as part of the public API, so let's give it an underscore. --- src/sage/misc/latex.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 9023857adbc..a40381b7bf9 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -474,7 +474,7 @@ def has_latex_attr(x) -> bool: @cached_function -def default_engine(): +def _default_engine(): r""" Return the default latex engine and the official name of the engine. @@ -483,8 +483,8 @@ def default_engine(): EXAMPLES:: - sage: from sage.misc.latex import default_engine - sage: default_engine() # random + sage: from sage.misc.latex import _default_engine + sage: _default_engine() # random 'lualatex' TESTS: @@ -494,16 +494,16 @@ def default_engine(): options dict for the delimiters):: sage: import sage.misc.latex - sage: real_de = sage.misc.latex.default_engine + sage: real_de = sage.misc.latex._default_engine sage: def crash(): ....: raise ValueError - sage: sage.misc.latex.default_engine = crash + sage: sage.misc.latex._default_engine = crash sage: latex(matrix.identity(QQ, 2)) \left(\begin{array}{rr} 1 & 0 \\ 0 & 1 \end{array}\right) - sage: sage.misc.latex.default_engine = real_de + sage: sage.misc.latex._default_engine = real_de """ from sage.features.latex import pdflatex, xelatex, lualatex @@ -539,7 +539,7 @@ def __init__(self, bb=False, delimiters=["(", ")"], self.__option["macros"] = "" self.__option["preamble"] = "" - # If None, the default_engine() will be used. + # If None, the _default_engine() will be used. self.__option["engine"] = None @lazy_attribute @@ -670,7 +670,7 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i if engine is None: engine = _Latex_prefs._option["engine"] if engine is None: - engine = default_engine() + engine = _default_engine() if not engine or engine == "latex": from sage.features.latex import latex @@ -1088,7 +1088,7 @@ def eval(self, x, globals, strip=False, filename=None, debug=None, if engine is None: engine = _Latex_prefs._option["engine"] if engine is None: - engine = default_engine() + engine = _default_engine() e = _run_latex_(os.path.join(base, filename + ".tex"), debug=debug, @@ -1557,7 +1557,7 @@ def engine(self, e=None): if e is None: e = _Latex_prefs._option["engine"] if e is None: - return default_engine() + return _default_engine() else: return e @@ -1865,7 +1865,7 @@ def view(objects, title='Sage', debug=False, sep='', tiny=False, if engine is None: engine = _Latex_prefs._option["engine"] if engine is None: - engine = default_engine() + engine = _default_engine() if viewer == "pdf" and engine == "latex": engine = "pdflatex" @@ -1969,7 +1969,7 @@ def pdf(x, filename, tiny=False, tightpage=True, margin=None, engine=None, debug if engine is None: engine = _Latex_prefs._option["engine"] if engine is None: - engine = default_engine() + engine = _default_engine() # path name for permanent pdf output abs_path_to_pdf = os.path.abspath(filename) @@ -2032,7 +2032,7 @@ def png(x, filename, density=150, debug=False, if engine is None: engine = _Latex_prefs._option["engine"] if engine is None: - engine = default_engine() + engine = _default_engine() # path name for permanent png output abs_path_to_png = os.path.abspath(filename) From f5dcdc663e00b29aa86e47f09082de59faff49ad Mon Sep 17 00:00:00 2001 From: Noel Roemmele Date: Sat, 1 Feb 2025 22:20:11 -0700 Subject: [PATCH 153/187] Fixed a doctest in the bigraphical function for hyperplanes that had a test failing every 1 in 1000 times. Made example have # random so it can fail and made a seperate test in the test block that runs the original test 5 times. --- src/sage/geometry/hyperplane_arrangement/library.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/hyperplane_arrangement/library.py b/src/sage/geometry/hyperplane_arrangement/library.py index 2c731eba212..239069afb3e 100644 --- a/src/sage/geometry/hyperplane_arrangement/library.py +++ b/src/sage/geometry/hyperplane_arrangement/library.py @@ -130,7 +130,8 @@ def bigraphical(self, G, A=None, K=QQ, names=None): sage: HA = hyperplane_arrangements.bigraphical(G, A) sage: HA.n_regions() 63 - sage: hyperplane_arrangements.bigraphical(G, 'generic').n_regions() + sage: hyperplane_arrangements.bigraphical(G, # random + ....: 'generic').n_regions() 65 sage: hyperplane_arrangements.bigraphical(G).n_regions() 59 @@ -138,6 +139,15 @@ def bigraphical(self, G, A=None, K=QQ, names=None): REFERENCES: - [HP2016]_ + + TESTS: + + We try:: + + sage: G = graphs.CycleGraph(4) + sage: any(hyperplane_arrangements.bigraphical(G, + ....: 'generic').n_regions() == 65 for _ in range(5)) + True """ n = G.num_verts() if A is None: # default to G-semiorder arrangement From 0fc1d1b2d5a6cfc9d088410bff588241335e4c32 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sun, 2 Feb 2025 12:19:06 -0600 Subject: [PATCH 154/187] bump GAP to 4.14.0 --- build/pkgs/gap/checksums.ini | 4 +- build/pkgs/gap/package-version.txt | 2 +- ...arwin-Remove-use-of-single_module-ob.patch | 29 --- .../gap/patches/gap-4.13.1-hash-fixes.patch | 178 ------------------ 4 files changed, 3 insertions(+), 210 deletions(-) delete mode 100644 build/pkgs/gap/patches/0001-Makefile.rules-Darwin-Remove-use-of-single_module-ob.patch delete mode 100644 build/pkgs/gap/patches/gap-4.13.1-hash-fixes.patch diff --git a/build/pkgs/gap/checksums.ini b/build/pkgs/gap/checksums.ini index 3704072d609..7f8c0e24541 100644 --- a/build/pkgs/gap/checksums.ini +++ b/build/pkgs/gap/checksums.ini @@ -1,4 +1,4 @@ tarball=gap-VERSION.tar.gz -sha1=cf91834954849dbaeae17079a4c4565bc28d03a8 -sha256=9794dbdba6fb998e0a2d0aa8ce21fc8848ad3d3f9cc9993b0b8e20be7e1dbeba +sha1=403c261db32049cc124b8f43221f7c57f2616133 +sha256=845f5272c26feb1b8eb9ef294bf0545f264c1fe5a19b0601bbc65d79d9506487 upstream_url=https://github.com/gap-system/gap/releases/download/vVERSION/gap-VERSION.tar.gz diff --git a/build/pkgs/gap/package-version.txt b/build/pkgs/gap/package-version.txt index 56d2fb548a2..c412a4e2e1e 100644 --- a/build/pkgs/gap/package-version.txt +++ b/build/pkgs/gap/package-version.txt @@ -1 +1 @@ -4.13.1 +4.14.0 diff --git a/build/pkgs/gap/patches/0001-Makefile.rules-Darwin-Remove-use-of-single_module-ob.patch b/build/pkgs/gap/patches/0001-Makefile.rules-Darwin-Remove-use-of-single_module-ob.patch deleted file mode 100644 index 46f5e36f109..00000000000 --- a/build/pkgs/gap/patches/0001-Makefile.rules-Darwin-Remove-use-of-single_module-ob.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 89b95994807970d90671e1e02cc03ddca4cf0a10 Mon Sep 17 00:00:00 2001 -From: Matthias Koeppe -Date: Sat, 8 Jun 2024 14:01:16 -0700 -Subject: [PATCH] Makefile.rules [Darwin]: Remove use of '-single_module' - (obsolete), activate '-install_name' - ---- - Makefile.rules | 5 +---- - 1 file changed, 1 insertion(+), 4 deletions(-) - -diff --git a/Makefile.rules b/Makefile.rules -index 8bfd3dba0..adfed731f 100644 ---- a/Makefile.rules -+++ b/Makefile.rules -@@ -446,10 +446,7 @@ else ifneq (,$(findstring darwin,$(host_os))) - LINK_SHLIB_FLAGS = -dynamiclib - LINK_SHLIB_FLAGS += -compatibility_version $(LIBGAP_COMPAT_VER) - LINK_SHLIB_FLAGS += -current_version $(LIBGAP_CURRENT_VER) -- LINK_SHLIB_FLAGS += -Wl,-single_module -- -- # TODO: set install_name, at least for installed version of the lib? -- #LINK_SHLIB_FLAGS += -install_name $(libdir)/$(LIBGAP_FULL) -+ LINK_SHLIB_FLAGS += -install_name $(libdir)/$(LIBGAP_FULL) - - GAP_CPPFLAGS += -DPIC - GAP_CFLAGS += -fno-common --- -2.42.0 - diff --git a/build/pkgs/gap/patches/gap-4.13.1-hash-fixes.patch b/build/pkgs/gap/patches/gap-4.13.1-hash-fixes.patch deleted file mode 100644 index c99b39ab91c..00000000000 --- a/build/pkgs/gap/patches/gap-4.13.1-hash-fixes.patch +++ /dev/null @@ -1,178 +0,0 @@ -diff --git a/lib/dicthf.gi b/lib/dicthf.gi -index 5ee7341..e4349ac 100644 ---- a/lib/dicthf.gi -+++ b/lib/dicthf.gi -@@ -152,16 +152,37 @@ end); - ## - InstallMethod(SparseIntKey,"for bounded tuples",true, - [ IsList,IsList and IsCyclotomicCollection ], 0, --function(m,v) --local c; -- if Length(m)<>3 or m[1]<>"BoundedTuples" then -+function(m, v) -+ if Length(m)<> 3 or m[1]<>"BoundedTuples" then - TryNextMethod(); - fi; -- c:=[1,Maximum(m[2])+1]; -- return function(a) -- return a*c; -+ # Due to the way BoundedTuples are presently implemented we expect the input -+ # to the hash function to always be a list of positive immediate integers. This means -+ # that using HashKeyWholeBag should be safe. -+ return function(x) -+ Assert(1, IsPositionsList(x)); -+ if not IsPlistRep(x) then -+ x := AsPlist(x); -+ fi; -+ return HashKeyWholeBag(x, 1); - end; - -+ # alternative code w/o HashKeyBag -+ ## build a weight vector to distinguish lists. Make entries large while staying clearly within -+ ## immediate int (2^55 replacing 2^60, since we take subsequent primes). -+ #step:=NextPrimeInt(QuoInt(2^55,Maximum(m[2])*m[3])); -+ #weights:=[1]; -+ #len:=Length(v); -+ ## up to 56 full, then increasingly reduce -+ #len:=Minimum(len,8*RootInt(len)); -+ #while Length(weights)0 and ForAll(pnt,IsPosInt) and -+ ForAll(acts,IsPerm) and - (act=OnSets or act=OnPoints or act=OnRight or act=\^)) then - TryNextMethod(); - fi; -diff --git a/lib/vecmat.gi b/lib/vecmat.gi -index 017c3c6..93ba828 100644 ---- a/lib/vecmat.gi -+++ b/lib/vecmat.gi -@@ -2142,7 +2142,8 @@ InstallMethod(DomainForAction,"matrix/matrix",IsElmsCollsX, - function(pnt,acts,act) - local l,f; - if (not ForAll(acts,IsMatrix)) or -- (act<>OnPoints and act<>OnSubspacesByCanonicalBasis and act<>OnRight) then -+ (act<>OnPoints and act<>OnSubspacesByCanonicalBasis and act<>OnRight and act<>OnSets and -+ act<>OnTuples) then - TryNextMethod(); # strange operation, might extend the domain - fi; - l:=NaturalActedSpace(acts,pnt); -diff --git a/tst/testbugfix/2024-09-14-actdomain.tst b/tst/testbugfix/2024-09-14-actdomain.tst -new file mode 100644 -index 0000000..84f8b50 ---- /dev/null -+++ b/tst/testbugfix/2024-09-14-actdomain.tst -@@ -0,0 +1,85 @@ -+# Fix #5786 and error reported by Len Soicher in support list -+gap> gg:=SpecialUnitaryGroup(4,2);; -+gap> hl:=Z(2)*[ -+> [0,0,1,0], -+> [1,1,0,0], -+> [0,1,0,1], -+> [0,1,1,0], -+> [1,1,0,1]];; -+gap> o:=Orbit(gg,Set(hl),OnSets);; -+gap> Length(o); -+216 -+gap> set:=[ 1,10,15,24,29,33,38,40,44,59, 60, 63, 69, 74, 77,79,85, 86, 90, -+> 95, 99, 103, 105, 110, 122, 125, 143, 148, 149, 153, 162, 165, 174, 182, -+> 185, 191, 197, 198, 202, 218, 223, 227, 228, 235, 236, 240, 243, 248, -+> 254, -+> 256, 259, 270, 275, 288, 291, 295, 298, 302, 305, 310, 312, 315, 325, -+> 329, -+> 333, 340, 341, 350, 356, 366, 369, 381, 385, 390, 397, 402, 412, 414, -+> 419, -+> 421, 425, 428, 433, 436, 445, 447, 451, 452, 453, 454, 461, 466, 474, -+> 479, -+> 481, 489, 490, 493, 497, 507, 509, 512, 513, 519, 521 ];; -+gap> gp:=Group( -+> ( 1,340,124,306,216,492,100, 25,108,270,220,332)( 2,138, 54,161,132,159,198, -+> 336,439,269, 89,419)( 3,467,177,404,505,437,379,312,481,271,223,135) -+> ( 4,510, 79,504,259,234,378,251,272,268,360,303)( 5,278,176,191,231,275,263, -+> 190,230,146,265,192)( 6,486,126,523,490,448,375,237,288,400,243,329) -+> ( 7,131,123,516, 48,392,350,333,418, 16,139,175)( 8,289,125,386,241, 29,376, -+> 334,242,417,442,331)( 9,430, 32, 59,446,367,377,335,411,416,515,330) -+> ( 10,391, 56,407,475,414,200,328,165,473, 86,119)( 11,368, 35,390,522,408,199, -+> 415,440,326, 87,503)( 12,412, 55,457,399,245,201, 33,438,431, 88,317) -+> ( 13,471, 40,348,452,292, 43,346,373, 77, 41,347)( 14,137,174,162, 60, 69,321, -+> 487, 61,158,322,370)( 15,101,114,109,130,160,488,489,352,351,420, 17) -+> ( 18,339,167,290,202,385, 99, 22, 90,323,217,129)( 19, 26, 93,304, 96,342) -+> ( 20,338,166,305,215,141, 97, 24, 51,150,219,507)( 21,337, 63,186,214,424, 98, -+> 23,107,382,218,349)( 27, 91,445,451,525, 67,519,239,144,203,155,353) -+> ( 28,324,444,128, 70,428,496,238,286,300,283, 64)( 30,236,287,441,387,354) -+> ( 31,345,366,517, 45,344,413,521, 46,248,244,121)( 34,314,394,402,222,447, 81, -+> 282,262,173,246,435)( 36,482,178,364,148,495,179,363,140,102,113,111) -+> ( 37,253,273,168,294,302,226,183, 72,480,154,233)( 38,483,520,393,403,465,362, -+> 298,143,356,153,369)( 39,157,320,472)( 42,228,277,264)( 44,343,147,501) -+> ( 47, 73,308,380,184,389,310,327,163,295,151,425)( 49,221,456, 80,474,260,405, -+> 325,164,524,152,449)( 50,479,365,477,461,459,497,169,296,247,134,117) -+> ( 52,361,299,285,355,188,423,464,434,453,133,118)( 53,257,509, 68,511,458,293, -+> 204,384,374, 75, 82)( 57,116,112,149,514,396,470,485,493,249,421,120) -+> ( 58,500,266,250,429,122)( 62,156,319,311)( 65,187,225,357,127, 71,388,235, -+> 460,252,274,371)( 66,106,462,291,205,383,372, 76, 92,410,280,498) -+> ( 74,401,381,476,409,281,171,104,297,307,426,182)( 78, 84,261,256,180,436,512, -+> 313,181,491,224,499)( 83,466,255,508,506,395,469,422,142,103,115,110) -+> ( 85,468,258,502,267,136)( 94,341)( 95,211)(105,478,195,432,518,316,197,484, -+> 494,455,196,170)(145,513,359,232,227,254)(172,209,398,207,279,206) -+> (185,194,309,443)(189,406,463,318,450,427,433,454,315,301,284,358) -+> (193,229,276,240)(208,397)(210,213,212) -+> ,( 1,379,148, 48,128,430,416)( 2, 34,338, 35,235,131,521)( 3,512,352, 47, -+> 318,289,237)( 4,272,506, 49,434,486,282)( 5,524,485, 10,483,340, 55) -+> ( 6,458, 36,487, 60,121, 16)( 7,313,140,336,127,435,270)( 8, 85,147,489, -+> 98,201,417)( 9,469, 94,488,129,329,400)( 11,291, 26, 54,234,473,169) -+> ( 12,207,339, 56,233,503,515)( 13,426,337, 40,232,295,500)( 14, 32,414, 27, -+> 167,130,472)( 15, 33,188, 38,382,109,501)( 17, 31,459, 37,496,132,517) -+> ( 18,263,294,446,451,134,497)( 19,198,525,241,441,244,470)( 20,100,199,490, -+> 242,429,413)( 21,378,403,216,523,421, 58)( 22,124,159, 77, 63,123,292) -+> ( 23,176,275,431,168, 86,293)( 24,177,492,326,104,151,290)( 25, 79,437,269, -+> 163,152,144)( 28,462,150,162, 62,120,415)( 29,239, 83,311, 61,117,260) -+> ( 30,452,149,370, 39,122,389)( 41,468, 73,254,277,432,371)( 42,210,319,502, -+> 373,205,283)( 43,387,194,212,320,508, 99)( 44,396,349,331,399,250,420) -+> ( 45,411,461,375,475,377,418)( 46,344,409,519,522,477,419)( 50,253,278,433, -+> 231, 88,422)( 51,482,138,358,229,463,381)( 52, 91,467,221,230,518,484) -+> ( 53,390,510,494,228,454, 92)( 57,310,460,118,259,367,363)( 59,281,227,274, -+> 505,402,215)( 64,125,245, 76, 93,160,471)( 65,126,408, 75,166, 69,264) -+> ( 66,302,186,116,257,424,327)( 67,187,297,479,217,425,171)( 68,303,296,345, -+> 280,226,273)( 70,240,359,366,364, 97,200)( 71,265,360,394,393,133,423) -+> ( 72,251,146,164,268, 87,312)( 74,252,276,406,513, 89,181)( 78,395,158,185, -+> 315,287,333)( 80,136,351,156,316,286,334)( 81,511,350,184,317,288,335) -+> ( 82,261,392,183,105,309,238)( 84,224,439,182,284,193,236)( 90,466,391,357, -+> 443,170,465)( 95,321,509,353,203,243,197)( 96,516,498,354,300,246,401) -+> (101,405,453,464,154,112,341)(102,139,450,208,388,365,111)(103,440,520,285, -+> 192,266,343)(106,308,218,119,262,448,298)(107,219,368,356,442,301,209) -+> (108,514,412,355,376,474,222)(110,495,137,478,361,444,380)(113,255,342,175, -+> 173,247,305)(114,256,141,328,153,307,304)(115,258,385,325,172,214,306) -+> (135,493,157,455,362,445,407)(142,346,189,398,323,161,499)(143,190,145,436, -+> 271,165,314)(155,195,211,174,404,374,204)(178,507,332,330,248,249,179) -+> (180,372,202,386,196,213,322)(191,267,491,384,438,279,225)(206,428,299,369, -+> 480,220,449)(223,481,383,427,397,324,504)(347,457,447,410,348,456,476));; -+gap> Length(Orbit(gp,set,OnSets)); -+241920 -diff --git a/tst/teststandard/hash2.tst b/tst/teststandard/hash2.tst -index 6bfa4d3..d47452e 100644 ---- a/tst/teststandard/hash2.tst -+++ b/tst/teststandard/hash2.tst -@@ -32,4 +32,8 @@ gap> Length(Orbit(h,h.1[1],OnRight)); - 2079 - gap> Length(Orbit(h,h.2^5,OnPoints)); - 693 -+gap> Length(Orbit(SymmetricGroup(14), [1 .. 7], OnSets)); -+3432 -+gap> Length(Orbit(SymmetricGroup(16), [1 .. 8], OnSets)); -+12870 - gap> STOP_TEST( "hash2.tst", 1); From d5fa1126df36c631497f8077794dd0bb7233a14d Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 3 Feb 2025 00:30:20 +0000 Subject: [PATCH 155/187] src/sage/misc/latex.py: bring back default_engine() for deprecation In case anyone is using this, we avoid removing it (or changing its return type) by surprise, and instead deprecate it. changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch lazier-latex-feature-tests # Changes to be committed: # modified: src/sage/misc/latex.py # --- src/sage/misc/latex.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index a40381b7bf9..f0da5be08e0 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -473,6 +473,35 @@ def has_latex_attr(x) -> bool: return hasattr(x, '_latex_') and not isinstance(x, type) +@cached_function +def default_engine(): + """ + Return the default latex engine and the official name of the engine. + This is determined by availability of the popular engines on the user's + system. It is assumed that at least latex is available. + + This function is deprecated as part of the public API. There is + instead an internal counterpart :func:`_default_engine`, but no + stability promises are made with regards to its interface. + + EXAMPLES:: + + sage: from sage.misc.latex import default_engine + sage: default_engine() # random + ('lualatex', 'LuaLaTeX') + """ + from sage.misc.superseded import deprecation + deprecation(39351, "default_engine is being removed from the public API and replaced with the internal function _default_engine") + + from sage.features.latex import pdflatex, xelatex, lualatex + if lualatex().is_present(): + return 'lualatex', 'LuaLaTeX' + if xelatex().is_present(): + return 'xelatex', 'XeLaTeX' + if pdflatex().is_present(): + return 'pdflatex', 'pdfLaTeX' + return 'latex', 'LaTeX' + @cached_function def _default_engine(): r""" From 6f08bb14aca6afb31cf2f3ea783ea4a3846fb924 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 3 Feb 2025 01:17:40 +0000 Subject: [PATCH 156/187] src/sage/misc/latex.py: update docstring for _default_engine() This function no longer returns the stylized engine name, so its docstring needs an update to reflect that. --- src/sage/misc/latex.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index f0da5be08e0..892a0a5e815 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -505,10 +505,10 @@ def default_engine(): @cached_function def _default_engine(): r""" - Return the default latex engine and the official name of the engine. + Return the name of the default latex engine. - This is determined by availability of the popular engines on the user's - system. It is assumed that at least latex is available. + This is determined by availability of the popular engines on the + user's system. It is assumed that at least "latex" is available. EXAMPLES:: From 478bc87e7953391ce84bfeece21313a1403e05ca Mon Sep 17 00:00:00 2001 From: Caleb Van't Land Date: Sun, 2 Feb 2025 18:42:00 -0700 Subject: [PATCH 157/187] Fixed derivative of constant matrix in matrix_dense.pyx --- src/sage/matrix/matrix_dense.pyx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix_dense.pyx b/src/sage/matrix/matrix_dense.pyx index f26078bde7e..09377f28df1 100644 --- a/src/sage/matrix/matrix_dense.pyx +++ b/src/sage/matrix/matrix_dense.pyx @@ -13,6 +13,7 @@ cimport sage.matrix.matrix as matrix from sage.structure.richcmp cimport richcmp_item, rich_to_bool import sage.matrix.matrix_space import sage.structure.sequence +import sage.calculus.functional cdef class Matrix_dense(matrix.Matrix): @@ -275,11 +276,17 @@ cdef class Matrix_dense(matrix.Matrix): sage: m._derivative(x) # needs sage.symbolic [ 0 1] [ 2*x 3*x^2] + + TESTS: + + sage: u = matrix(1, 2, [-1, 1]) + sage: derivative(u, x) + [0 0] """ # We could just use apply_map if self._nrows==0 or self._ncols==0: return self.__copy__() - v = [z.derivative(var) for z in self.list()] + v = [sage.calculus.functional.derivative(z, var) for z in self.list()] if R is None: v = sage.structure.sequence.Sequence(v) R = v.universe() From 1f1bab1776fecc5a59b4f4906c5f20878e690bad Mon Sep 17 00:00:00 2001 From: Caleb Van't Land Date: Sun, 2 Feb 2025 18:58:06 -0700 Subject: [PATCH 158/187] Fixed constant matrix derivative in matrix_sparse.pyx --- src/sage/matrix/matrix_sparse.pyx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix_sparse.pyx b/src/sage/matrix/matrix_sparse.pyx index 92a2d18d846..2c15391b1f6 100644 --- a/src/sage/matrix/matrix_sparse.pyx +++ b/src/sage/matrix/matrix_sparse.pyx @@ -23,6 +23,7 @@ from cpython cimport * from cpython.object cimport Py_EQ, Py_NE import sage.matrix.matrix_space +import sage.calculus.functional cdef class Matrix_sparse(matrix.Matrix): @@ -810,13 +811,21 @@ cdef class Matrix_sparse(matrix.Matrix): sage: m._derivative(x) # needs sage.symbolic [ 0 1] [ 2*x 3*x^2] + + TESTS: + + sage: m = matrix(3, 3, {(1, 1): 2, (0,2): 5}) + sage: derivative(m, x) + [0 0 0] + [0 0 0] + [0 0 0] """ # We would just use apply_map, except that Cython does not # allow lambda functions if self._nrows==0 or self._ncols==0: return self.__copy__() - v = [(ij, z.derivative(var)) for ij, z in self.dict().iteritems()] + v = [(ij, sage.calculus.functional.derivative(z, var)) for ij, z in self.dict().iteritems()] if R is None: w = [x for _, x in v] w = sage.structure.sequence.Sequence(w) From 02a798664b80b515b8ed2c53cac32cdc5cd7ce7c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 3 Feb 2025 13:20:08 +0900 Subject: [PATCH 159/187] Adding more documentation. --- src/sage/groups/artin.py | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/sage/groups/artin.py b/src/sage/groups/artin.py index 01a3ab476ca..6697a55bbb8 100644 --- a/src/sage/groups/artin.py +++ b/src/sage/groups/artin.py @@ -164,14 +164,36 @@ def coxeter_group_element(self, W=None): In = W.index_set() return W.prod(s[In[abs(i)-1]] for i in self.Tietze()) - def burau_matrix(self, var='t', reduced=False): + def burau_matrix(self, var='t'): r""" Return the Burau matrix of the Artin group element. - Following [BQ2024]_, the (generalized) Burau representation of an - Artin group is defined by deforming the reflection representation - of the corresponding Coxeter group. However, we substitute - `q \mapsto -t` from [BQ2024]_ to match the unitary + Following [BQ2024]_, the (generalized) Burau representation + of an Artin group is defined by deforming the reflection + representation of the corresponding Coxeter group. However, + we substitute `q \mapsto -t` from [BQ2024]_ to match one of + the unitary (reduced) Burau representations of the braid group + (see :meth:`sage.groups.braid.Braid.burau_matrix()` for details.) + + More precisely, let `(m_{ij})_{i,j \in I}` be the + :meth:`Coxeter matrix`. Then the action is + given on the basis `(\alpha_1, \ldots \alpha_n)` (corresponding + to the reflection representation of the corresponding + :meth:`Coxeter group`) by + + .. MATH:: + + \sigma_i(\alpha_j) = \alpha_j + - \langle \alpha_i, \alpha_j \rangle_q \alpha_i, + \qquad \text{ where } + \langle \alpha_i, \alpha_j \rangle_q := \begin{cases} + 1 + t^2 & \text{if } i = j, \\ + -2 t \cos(\pi/m_{ij}) & \text{if } i \neq j. + \end{cases}. + + By convention `\cos(\pi/\infty) = 1`. Note that the inverse of the + generators act by `\sigma_i^{-1}(\alpha_j) = \alpha_j - q^{-2} + \langle \alpha_j, \alpha_i \rangle_q \alpha_i`. INPUT: @@ -286,6 +308,7 @@ def burau_matrix(self, var='t', reduced=False): if var == 't': return ret + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing poly_ring = LaurentPolynomialRing(ret.base_ring().base_ring(), var) return ret.change_ring(poly_ring) From 840d406e027139e977279c6ff818bfc25c3a0d28 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:39:05 +0700 Subject: [PATCH 160/187] Apply suggested change Co-authored-by: Travis Scrimshaw --- src/sage/combinat/integer_vector.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index 3ee66212f11..6f42c9097a8 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -1053,11 +1053,12 @@ def __iter__(self): [[]] """ n = 0 + if self.k == 0: # special case + yield self.element_class(self, [], check=False) + return while True: for iv in integer_vectors_nk_fast_iter(n, self.k): yield self.element_class(self, iv, check=False) - if self.k == 0: - return n += 1 def __contains__(self, x): From a10eb6f8b25cdd50754e0c822b1a7239dc3df280 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:40:32 +0700 Subject: [PATCH 161/187] Fix indentation --- src/sage/combinat/integer_vector.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index 6f42c9097a8..4587cb5f46c 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -1054,8 +1054,8 @@ def __iter__(self): """ n = 0 if self.k == 0: # special case - yield self.element_class(self, [], check=False) - return + yield self.element_class(self, [], check=False) + return while True: for iv in integer_vectors_nk_fast_iter(n, self.k): yield self.element_class(self, iv, check=False) From bc0ad12514d11a841b902df804c5cd069e0b1d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 3 Feb 2025 14:21:28 +0100 Subject: [PATCH 162/187] enhanced details in link.py --- src/sage/knots/link.py | 94 +++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index 2c5f59ef19f..7e597a49d87 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -515,9 +515,9 @@ def fundamental_group(self, presentation='wirtinger'): F = FreeGroup(len(arcs)) rels = [] for crossing, orientation in zip(self.pd_code(), self.orientation()): - a = arcs.index([i for i in arcs if crossing[0] in i][0]) - b = arcs.index([i for i in arcs if crossing[3] in i][0]) - c = arcs.index([i for i in arcs if crossing[2] in i][0]) + a = next(idx for idx, i in enumerate(arcs) if crossing[0] in i) + b = next(idx for idx, i in enumerate(arcs) if crossing[3] in i) + c = next(idx for idx, i in enumerate(arcs) if crossing[2] in i) ela = F.gen(a) elb = F.gen(b) if orientation < 0: @@ -526,7 +526,7 @@ def fundamental_group(self, presentation='wirtinger'): rels.append(ela * elb / elc / elb) return F.quotient(rels) - def _repr_(self): + def _repr_(self) -> str: r""" Return a string representation. @@ -705,9 +705,8 @@ def idx(cross, edge): """ i = cross.index(edge) if cross.count(edge) > 1: - return cross.index(edge, i+1) - else: - return i + return cross.index(edge, i + 1) + return i seifert_circles = self.seifert_circles() newedge = max(flatten(pd_code)) + 1 @@ -740,8 +739,8 @@ def idx(cross, edge): C1[idx(C1, a)] = newedge + 1 C2 = newPD[newPD.index(tails[b])] C2[idx(C2, b)] = newedge + 2 - newPD.append([newedge + 3, newedge, b, a]) # D - newPD.append([newedge + 2, newedge, newedge + 3, newedge + 1]) # E + newPD.append([newedge + 3, newedge, b, a]) # D + newPD.append([newedge + 2, newedge, newedge + 3, newedge + 1]) # E self._braid = Link(newPD).braid(remove_loops=remove_loops) return self._braid else: @@ -761,21 +760,21 @@ def idx(cross, edge): C1[idx(C1, -a)] = newedge + 1 C2 = newPD[newPD.index(tails[-b])] C2[idx(C2, -b)] = newedge + 2 - newPD.append([newedge + 2, newedge + 1, newedge + 3, newedge]) # D - newPD.append([newedge + 3, -a, -b, newedge]) # E + newPD.append([newedge + 2, newedge + 1, newedge + 3, newedge]) # D + newPD.append([newedge + 3, -a, -b, newedge]) # E self._braid = Link(newPD).braid(remove_loops=remove_loops) return self._braid # We are in the case where no Vogel moves are necessary. G = DiGraph() G.add_vertices([tuple(c) for c in seifert_circles]) - for i,c in enumerate(pd_code): + for i, c in enumerate(pd_code): if self.orientation()[i] == 1: - a = [x for x in seifert_circles if c[3] in x][0] - b = [x for x in seifert_circles if c[0] in x][0] + a = next(x for x in seifert_circles if c[3] in x) + b = next(x for x in seifert_circles if c[0] in x) else: - a = [x for x in seifert_circles if c[0] in x][0] - b = [x for x in seifert_circles if c[1] in x][0] + a = next(x for x in seifert_circles if c[0] in x) + b = next(x for x in seifert_circles if c[1] in x) G.add_edge(tuple(a), tuple(b)) # Get a simple path from a source to a sink in the digraph @@ -785,7 +784,7 @@ def idx(cross, edge): B = BraidGroup(len(ordered_cycles)) available_crossings = copy(pd_code) oc_set = set(ordered_cycles[0]) - for i,x in enumerate(pd_code): + for i, x in enumerate(pd_code): if any(elt in oc_set for elt in x): crossing = x crossing_index = i @@ -903,7 +902,7 @@ def _directions_of_edges(self): heads[a] = next_crossing[0] tails[a] = D D = next_crossing[0] - a = D[(D.index(a)+2) % 4] + a = D[(D.index(a) + 2) % 4] unassigned = set(flatten(pd_code)).difference(set(tails)) while unassigned: @@ -920,7 +919,7 @@ def _directions_of_edges(self): break heads[a] = next_crossing D = next_crossing - a = D[(D.index(a)+2) % 4] + a = D[(D.index(a) + 2) % 4] if a in unassigned: unassigned.remove(a) return tails, heads @@ -1110,7 +1109,7 @@ def _enhanced_states(self): nmax = max(flatten(crossings)) + 1 for i in range(2 ** ncross): v = Integer(i).bits() - v = v + (ncross - len(v))*[0] + v = v + (ncross - len(v)) * [0] G = Graph() for j, cr in enumerate(crossings): n = nmax + j @@ -1134,7 +1133,7 @@ def _enhanced_states(self): smoothings.append((tuple(v), sm, iindex, jmin, jmax)) states = [] # we got all the smoothings, now find all the states for sm in smoothings: - for k in range(len(sm[1])+1): + for k in range(len(sm[1]) + 1): for circpos in combinations(sorted(sm[1]), k): # Add each state circneg = sm[1].difference(circpos) j = writhe + sm[2] + len(circpos) - len(circneg) @@ -1197,13 +1196,13 @@ def _khovanov_homology_cached(self, height, ring=ZZ): difs = [index for index, value in enumerate(V1[0]) if value != V20[index]] if len(difs) == 1 and not (V2[2].intersection(V1[1]) or V2[1].intersection(V1[2])): - m[ii, jj] = (-1)**sum(V2[0][x] for x in range(difs[0]+1, ncross)) + m[ii, jj] = (-1)**sum(V2[0][x] for x in range(difs[0] + 1, ncross)) # Here we have the matrix constructed, now we have to put it in the dictionary of complexes else: m = matrix(ring, len(bij), 0) complexes[i] = m.transpose() - if (i-1, j) not in bases: - complexes[i-1] = matrix(ring, len(bases[(i,j)]), 0) + if (i - 1, j) not in bases: + complexes[i - 1] = matrix(ring, len(bases[(i, j)]), 0) homologies = ChainComplex(complexes).homology() return tuple(sorted(homologies.items())) @@ -1457,7 +1456,7 @@ def pd_code(self): for i, j in zip(last_component, first_component): d_dic[i][1] = d_dic[j][0] crossing_dic = {} - for i,x in enumerate(oriented_gauss_code[1]): + for i, x in enumerate(oriented_gauss_code[1]): if x == -1: crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][0], d_dic[-(i + 1)][1], d_dic[i + 1][1]] @@ -1611,7 +1610,7 @@ def _braid_word_components(self): missing = sorted(missing1) x = [[] for i in range(len(missing) + 1)] - for i,a in enumerate(missing): + for i, a in enumerate(missing): for j, mlj in enumerate(ml): if mlj != 0 and abs(mlj) < a: x[i].append(mlj) @@ -2108,7 +2107,7 @@ def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ): gens = [g for g in H.gens() if g.order() == infinity or ch.divides(g.order())] l = len(gens) if l: - coeff[(h,d)] = l + coeff[(h, d)] = l return L(coeff) def determinant(self): @@ -2826,7 +2825,7 @@ def jones_polynomial(self, variab=None, skein_normalization=False, algorithm='jo if variab is None: variab = 't' # We force the result to be in the symbolic ring because of the expand - return jones(SR(variab)**(ZZ(1)/ZZ(4))).expand() + return jones(SR(variab)**(ZZ.one() / ZZ(4))).expand() elif algorithm == 'jonesrep': braid = self.braid() # Special case for the trivial knot with no crossings @@ -3084,14 +3083,14 @@ def homfly_polynomial(self, var1=None, var2=None, normalization='lm'): L = LaurentPolynomialRing(ZZ, [var1, var2]) if len(self._isolated_components()) > 1: if normalization == 'lm': - fact = L({(1, -1):-1, (-1, -1):-1}) + fact = L({(1, -1): -1, (-1, -1): -1}) elif normalization == 'az': - fact = L({(1, -1):1, (-1, -1):-1}) + fact = L({(1, -1): 1, (-1, -1): -1}) elif normalization == 'vz': - fact = L({(1, -1):-1, (-1, -1):1}) + fact = L({(1, -1): -1, (-1, -1): 1}) else: raise ValueError('normalization must be either `lm`, `az` or `vz`') - fact = fact ** (len(self._isolated_components())-1) + fact = fact ** (len(self._isolated_components()) - 1) for i in self._isolated_components(): fact = fact * Link(i).homfly_polynomial(var1, var2, normalization) return fact @@ -3102,7 +3101,7 @@ def homfly_polynomial(self, var1=None, var2=None, normalization='lm'): for comp in ogc[0]: s += ' {}'.format(len(comp)) for cr in comp: - s += ' {} {}'.format(abs(cr)-1, sign(cr)) + s += ' {} {}'.format(abs(cr) - 1, sign(cr)) for i, cr in enumerate(ogc[1]): s += ' {} {}'.format(i, cr) from sage.libs.homfly import homfly_polynomial_dict @@ -3124,7 +3123,7 @@ def homfly_polynomial(self, var1=None, var2=None, normalization='lm'): h_az = self.homfly_polynomial(var1=var1, var2=var2, normalization='az') a, z = h_az.parent().gens() v = ~a - return h_az.subs({a:v}) + return h_az.subs({a: v}) else: raise ValueError('normalization must be either `lm`, `az` or `vz`') @@ -3313,8 +3312,8 @@ def colorings(self, n=None): M = self._coloring_matrix(n=n) KM = M.right_kernel_matrix() F = FreeModule(M.base_ring(), KM.dimensions()[0]) - K = [v*KM for v in F] - res = set([]) + K = [v * KM for v in F] + res = set() arcs = self.arcs('pd') for coloring in K: colors = sorted(set(coloring)) @@ -3408,7 +3407,7 @@ def coloring_maps(self, n=None, finitely_presented=False): maps = [] for c in cols: t = list(c.values()) - ims = [b*a**i for i in t] + ims = [b * a**i for i in t] maps.append(gr.hom(ims)) return maps @@ -3627,7 +3626,7 @@ def plot(self, gap=0.1, component_gap=0.5, solver=None, # Special case for the unknot if not pd_code: - return circle((0,0), ZZ(1)/ZZ(2), color=color, **kwargs) + return circle((0, 0), ZZ.one() / ZZ(2), color=color, **kwargs) # The idea is the same followed in spherogram, but using MLP instead of # network flows. @@ -3653,9 +3652,9 @@ def flow_from_source(e): Return the flow variable from the source. """ if e > 0: - return v[2*edges.index(e)] + return v[2 * edges.index(e)] else: - return v[2*edges.index(-e)+1] + return v[2 * edges.index(-e) + 1] def flow_to_sink(e): r""" @@ -3680,9 +3679,10 @@ def flow_to_sink(e): MLP.solve() # we store the result in a vector s packing right bends as negative left ones values = MLP.get_values(v, convert=ZZ, tolerance=1e-3) - s = [values[2*i] - values[2*i + 1] for i in range(len(edges))] + s = [values[2 * i] - values[2 * i + 1] for i in range(len(edges))] # segments represents the different parts of the previous edges after bending - segments = {e: [(e,i) for i in range(abs(s[edges.index(e)])+1)] for e in edges} + segments = {e: [(e, i) for i in range(abs(s[edges.index(e)]) + 1)] + for e in edges} pieces = {tuple(i): [i] for j in segments.values() for i in j} nregions = [] for r in regions[:-1]: # interior regions @@ -3711,7 +3711,7 @@ def flow_to_sink(e): c = -1 b = a while c != 2: - if b == len(badregion)-1: + if b == len(badregion) - 1: b = 0 else: b += 1 @@ -3739,15 +3739,15 @@ def flow_to_sink(e): if a < b: r1 = badregion[:a] + [[badregion[a][0], 0], [N1, 1]] + badregion[b:] - r2 = badregion[a + 1:b] + [[N2, 1],[N1, 1]] + r2 = badregion[a + 1:b] + [[N2, 1], [N1, 1]] else: r1 = badregion[b:a] + [[badregion[a][0], 0], [N1, 1]] - r2 = badregion[:b] + [[N2, 1],[N1, 1]] + badregion[a + 1:] + r2 = badregion[:b] + [[N2, 1], [N1, 1]] + badregion[a + 1:] if otherregion: c = [x for x in otherregion if badregion[b][0] == x[0]] c = otherregion.index(c[0]) - otherregion.insert(c + 1, [N2,otherregion[c][1]]) + otherregion.insert(c + 1, [N2, otherregion[c][1]]) otherregion[c][1] = 0 nregions.remove(badregion) nregions.append(r1) @@ -3805,7 +3805,7 @@ def flow_to_sink(e): turn = -1 else: turn = 1 - lengthse = [lengths[(e,k)] for k in range(abs(s[edges.index(e)])+1)] + lengthse = [lengths[(e, k)] for k in range(abs(s[edges.index(e)]) + 1)] if c.index(e) == 0 or (c.index(e) == 3 and orien == 1) or (c.index(e) == 1 and orien == -1): turn = -turn lengthse.reverse() From 6eed1bc7fc746ffd2e7ea6f12eceab31c60cfd3c Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 3 Feb 2025 13:42:52 +0000 Subject: [PATCH 163/187] src/sage/misc/latex.py: move a newline somewhere else (This appeases pycodestyle, and makes the docstring endings more consistent.) --- src/sage/misc/latex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 892a0a5e815..9863d8b7789 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -502,6 +502,7 @@ def default_engine(): return 'pdflatex', 'pdfLaTeX' return 'latex', 'LaTeX' + @cached_function def _default_engine(): r""" @@ -533,7 +534,6 @@ def _default_engine(): 0 & 1 \end{array}\right) sage: sage.misc.latex._default_engine = real_de - """ from sage.features.latex import pdflatex, xelatex, lualatex if lualatex().is_present(): From e315d7756d4425444383223f482a8c0efad22566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 3 Feb 2025 17:07:46 +0100 Subject: [PATCH 164/187] using next in isogeny plotting --- .../schemes/elliptic_curves/isogeny_class.py | 63 +++++++++++-------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/isogeny_class.py b/src/sage/schemes/elliptic_curves/isogeny_class.py index 13edc68a022..863a35783ae 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_class.py +++ b/src/sage/schemes/elliptic_curves/isogeny_class.py @@ -434,60 +434,71 @@ def graph(self): elif n == 2: # one edge, two vertices. We align horizontally and put # the lower number on the left vertex. - G.set_pos(pos={0:[-0.5,0],1:[0.5,0]}) + G.set_pos(pos={0: [-0.5, 0], 1: [0.5, 0]}) else: maxdegree = max(max(N)) if n == 3: # o--o--o - centervert = [i for i in range(3) if max(N.row(i)) < maxdegree][0] + centervert = next(i for i in range(3) if max(N.row(i)) < maxdegree) other = [i for i in range(3) if i != centervert] - G.set_pos(pos={centervert:[0,0],other[0]:[-1,0],other[1]:[1,0]}) + G.set_pos(pos={centervert: [0, 0], other[0]: [-1, 0], other[1]: [1, 0]}) elif maxdegree == 4: # o--o<8 - centervert = [i for i in range(4) if max(N.row(i)) < maxdegree][0] + centervert = next(i for i in range(4) if max(N.row(i)) < maxdegree) other = [i for i in range(4) if i != centervert] - G.set_pos(pos={centervert:[0,0],other[0]:[0,1],other[1]:[-0.8660254,-0.5],other[2]:[0.8660254,-0.5]}) + G.set_pos(pos={centervert: [0, 0], other[0]: [0, 1], + other[1]: [-0.8660254, -0.5], other[2]: [0.8660254, -0.5]}) elif maxdegree == 27: # o--o--o--o centers = [i for i in range(4) if list(N.row(i)).count(3) == 2] - left = [j for j in range(4) if N[centers[0],j] == 3 and j not in centers][0] - right = [j for j in range(4) if N[centers[1],j] == 3 and j not in centers][0] - G.set_pos(pos={left:[-1.5,0],centers[0]:[-0.5,0],centers[1]:[0.5,0],right:[1.5,0]}) + left = next(j for j in range(4) if N[centers[0], j] == 3 and j not in centers) + right = next(j for j in range(4) if N[centers[1], j] == 3 and j not in centers) + G.set_pos(pos={left: [-1.5, 0], centers[0]: [-0.5, 0], + centers[1]: [0.5, 0], right: [1.5, 0]}) elif n == 4: # square - opp = [i for i in range(1,4) if not N[0,i].is_prime()][0] - other = [i for i in range(1,4) if i != opp] - G.set_pos(pos={0:[1,1],other[0]:[-1,1],opp:[-1,-1],other[1]:[1,-1]}) + opp = next(i for i in range(1, 4) if not N[0, i].is_prime()) + other = [i for i in range(1, 4) if i != opp] + G.set_pos(pos={0: [1, 1], other[0]: [-1, 1], + opp: [-1, -1], other[1]: [1, -1]}) elif maxdegree == 8: # 8>o--o<8 centers = [i for i in range(6) if list(N.row(i)).count(2) == 3] - left = [j for j in range(6) if N[centers[0],j] == 2 and j not in centers] - right = [j for j in range(6) if N[centers[1],j] == 2 and j not in centers] - G.set_pos(pos={centers[0]:[-0.5,0],left[0]:[-1,0.8660254],left[1]:[-1,-0.8660254],centers[1]:[0.5,0],right[0]:[1,0.8660254],right[1]:[1,-0.8660254]}) + left = [j for j in range(6) if N[centers[0], j] == 2 and j not in centers] + right = [j for j in range(6) if N[centers[1], j] == 2 and j not in centers] + G.set_pos(pos={centers[0]: [-0.5, 0], left[0]: [-1, 0.8660254], + left[1]: [-1, -0.8660254], centers[1]: [0.5, 0], + right[0]: [1, 0.8660254], right[1]: [1, -0.8660254]}) elif maxdegree == 18: # two squares joined on an edge centers = [i for i in range(6) if list(N.row(i)).count(3) == 2] - top = [j for j in range(6) if N[centers[0],j] == 3] - bl = [j for j in range(6) if N[top[0],j] == 2][0] - br = [j for j in range(6) if N[top[1],j] == 2][0] - G.set_pos(pos={centers[0]:[0,0.5],centers[1]:[0,-0.5],top[0]:[-1,0.5],top[1]:[1,0.5],bl:[-1,-0.5],br:[1,-0.5]}) + top = [j for j in range(6) if N[centers[0], j] == 3] + bl = next(j for j in range(6) if N[top[0], j] == 2) + br = next(j for j in range(6) if N[top[1], j] == 2) + G.set_pos(pos={centers[0]: [0, 0.5], centers[1]: [0, -0.5], + top[0]: [-1, 0.5], top[1]: [1, 0.5], + bl: [-1, -0.5], br: [1, -0.5]}) elif maxdegree == 16: # tree from bottom, 3 regular except for the leaves. centers = [i for i in range(8) if list(N.row(i)).count(2) == 3] - center = [i for i in centers if len([j for j in centers if N[i,j] == 2]) == 2][0] + center = next(i for i in centers if len([j for j in centers if N[i, j] == 2]) == 2) centers.remove(center) - bottom = [j for j in range(8) if N[center,j] == 2 and j not in centers][0] - left = [j for j in range(8) if N[centers[0],j] == 2 and j != center] - right = [j for j in range(8) if N[centers[1],j] == 2 and j != center] - G.set_pos(pos={center:[0,0],bottom:[0,-1],centers[0]:[-0.8660254,0.5],centers[1]:[0.8660254,0.5],left[0]:[-0.8660254,1.5],right[0]:[0.8660254,1.5],left[1]:[-1.7320508,0],right[1]:[1.7320508,0]}) + bottom = next(j for j in range(8) if N[center, j] == 2 and j not in centers) + left = [j for j in range(8) if N[centers[0], j] == 2 and j != center] + right = [j for j in range(8) if N[centers[1], j] == 2 and j != center] + G.set_pos(pos={center: [0, 0], bottom: [0, -1], centers[0]: [-0.8660254, 0.5], + centers[1]: [0.8660254, 0.5], left[0]: [-0.8660254, 1.5], + right[0]: [0.8660254, 1.5], left[1]: [-1.7320508, 0], right[1]: [1.7320508, 0]}) elif maxdegree == 12: # tent centers = [i for i in range(8) if list(N.row(i)).count(2) == 3] - left = [j for j in range(8) if N[centers[0],j] == 2] + left = [j for j in range(8) if N[centers[0], j] == 2] right = [] for i in range(3): - right.append([j for j in range(8) if N[centers[1],j] == 2 and N[left[i],j] == 3][0]) - G.set_pos(pos={centers[0]:[-0.75,0],centers[1]:[0.75,0],left[0]:[-0.75,1],right[0]:[0.75,1],left[1]:[-1.25,-0.75],right[1]:[0.25,-0.75],left[2]:[-0.25,-0.25],right[2]:[1.25,-0.25]}) + right.append(next(j for j in range(8) if N[centers[1], j] == 2 and N[left[i], j] == 3)) + G.set_pos(pos={centers[0]: [-0.75, 0], centers[1]: [0.75, 0], left[0]: [-0.75, 1], + right[0]: [0.75, 1], left[1]: [-1.25, -0.75], right[1]: [0.25, -0.75], + left[2]: [-0.25, -0.25], right[2]: [1.25, -0.25]}) G.set_vertices(D) G.relabel(list(range(1, n + 1))) return G From ca8b5981a81cfb2af0723ce357ab829400992dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 3 Feb 2025 21:02:35 +0100 Subject: [PATCH 165/187] introduce the alias "is_congruence_uniform" in lattices --- src/doc/en/reference/references/index.rst | 4 +++ src/sage/combinat/posets/lattices.py | 32 ++++++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 31cb3ec8074..d8441267c2b 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -2099,6 +2099,10 @@ REFERENCES: Adv. Math. ***177** no. 1 (2002) pp. 115-179. :arxiv:`math/0203127`. +.. [Day1979] Alan Day, *Characterizations of Finite Lattices that are + Bounded-Homomorphic Images or Sublattices of Free Lattices*, + Canadian Journal of Mathematics 31 (1979), 69-78 + .. [DB1996] K. Duggal, A. Bejancu, *Lightlike Submanifolds of Semi-Riemannian Manifolds and Applications*, Mathematics and Its Applications, 1996. diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py index 149915f8fb5..542213f0f06 100644 --- a/src/sage/combinat/posets/lattices.py +++ b/src/sage/combinat/posets/lattices.py @@ -1292,7 +1292,8 @@ def is_semidistributive(self): - Weaker properties: :meth:`is_join_semidistributive`, :meth:`is_meet_semidistributive` - - Stronger properties: :meth:`is_distributive` + - Stronger properties: :meth:`is_distributive`, + :meth:`is_congruence_uniform` TESTS:: @@ -3549,7 +3550,7 @@ def day_doubling(self, S): True """ # Rationale for naming of elements: a lattice can have - # elements 1, (1, 1), (1, (1, 1)) and so on. We can't just + # elements 1, (1, 1), (1, (1, 1)) and so on. We cannot just # make a copy of S with elements (s, 1). # The construction could be defined for any convex @@ -3954,7 +3955,7 @@ def is_sublattice_dismantlable(self): Add a certificate-option. """ - # Todo: This can be made much faster, if we don't regenerate meet- and + # Todo: This can be made much faster, if we do not regenerate meet- and # join-matrices every time, but instead remove some rows and columns # from them. @@ -4270,7 +4271,7 @@ def is_constructible_by_doublings(self, type) -> bool: The congruence lattice of this lattice has maximal chains satisfying the needed property, but also maximal chains not satisfying that; this shows that the code - can't be optimized to test just some maximal chain:: + cannot be optimized to test just some maximal chain:: sage: L = LatticePoset(DiGraph('QSO?I?_?_GBG??_??a???@?K??A??B???C??s??G??I??@??A??@???')) sage: L.is_constructible_by_doublings('convex') @@ -4343,6 +4344,29 @@ def splitting_depth_2(a, b): todo.append(e_up) return False + def is_congruence_uniform(self) -> bool: + """ + Return whether ``self`` is congruence uniform. + + This is equivalent to being constructible by doubling intervals. + + .. SEEALSO:: :meth:`is_constructible_by_doublings` + + EXAMPLES:: + + sage: P = posets.PentagonPoset() + sage: P.is_congruence_uniform() + True + sage: P = posets.DiamondPoset(5) + sage: P.is_congruence_uniform() + False + + REFERENCES: + + - [Day1979]_ + """ + return self.is_constructible_by_doublings(type="interval") + def is_isoform(self, certificate=False): """ Return ``True`` if the lattice is isoform and ``False`` otherwise. From a9027a4c7a79ac367cd3de41da7b08597cb2bdec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 3 Feb 2025 21:15:54 +0100 Subject: [PATCH 166/187] some details in KR crystals --- .../combinat/crystals/kirillov_reshetikhin.py | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/sage/combinat/crystals/kirillov_reshetikhin.py b/src/sage/combinat/crystals/kirillov_reshetikhin.py index 18b1882014d..de5f2c35ddb 100644 --- a/src/sage/combinat/crystals/kirillov_reshetikhin.py +++ b/src/sage/combinat/crystals/kirillov_reshetikhin.py @@ -519,7 +519,7 @@ def module_generator(self): r = self.r() s = self.s() weight = s*Lambda[r] - s*Lambda[0] * Lambda[r].level() / Lambda[0].level() - return [b for b in self.module_generators if b.weight() == weight][0] + return next(b for b in self.module_generators if b.weight() == weight) def r(self): """ @@ -993,8 +993,8 @@ def from_pm_diagram_to_highest_weight_vector(self, pm): sage: K.from_pm_diagram_to_highest_weight_vector(pm) [[2], [-2]] """ - u = [b for b in self.classical_decomposition().module_generators - if b.to_tableau().shape() == pm.outer_shape()][0] + u = next(b for b in self.classical_decomposition().module_generators + if b.to_tableau().shape() == pm.outer_shape()) ct = self.cartan_type() rank = ct.rank() - 1 ct_type = ct.classical().type() @@ -1031,7 +1031,7 @@ class KR_type_E6(KirillovReshetikhinCrystalFromPromotion): [(1,)] sage: b.e(0) [(-2, 1)] - sage: b = [t for t in K if t.epsilon(1) == 1 and t.phi(3) == 1 and t.phi(2) == 0 and t.epsilon(2) == 0][0] + sage: b = next(t for t in K if t.epsilon(1) == 1 and t.phi(3) == 1 and t.phi(2) == 0 and t.epsilon(2) == 0) sage: b [(-1, 3)] sage: b.e(0) @@ -1622,7 +1622,7 @@ def module_generator(self): weight = s*Lambda[r] - s*Lambda[0] if r == self.cartan_type().rank() - 1: weight += s*Lambda[r] # Special case for r == n - return [b for b in self.module_generators if b.weight() == weight][0] + return next(b for b in self.module_generators if b.weight() == weight) def classical_decomposition(self): r""" @@ -2489,7 +2489,8 @@ def from_pm_diagram_to_highest_weight_vector(self, pm): sage: K.from_pm_diagram_to_highest_weight_vector(pm) [[2, 2], [3, 3], [-3, -1]] """ - u = [b for b in self.classical_decomposition().module_generators if b.to_tableau().shape() == pm.outer_shape()][0] + u = next(b for b in self.classical_decomposition().module_generators + if b.to_tableau().shape() == pm.outer_shape()) ct = self.cartan_type() rank = ct.rank()-1 ct_type = ct.classical().type() @@ -2537,7 +2538,7 @@ def e0(self): [[3, -3], [-3, -2], [-1, -1]] """ n = self.parent().cartan_type().n - b, l = self.lift().to_highest_weight(index_set=list(range(2, n + 1))) + b, l = self.lift().to_highest_weight(index_set=range(2, n + 1)) pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) l1, l2 = pm.pm_diagram[n-1] if l1 == 0: @@ -2562,7 +2563,7 @@ def f0(self): sage: b.f(0) # indirect doctest """ n = self.parent().cartan_type().n - b, l = self.lift().to_highest_weight(index_set=list(range(2, n + 1))) + b, l = self.lift().to_highest_weight(index_set=range(2, n + 1)) pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) l1, l2 = pm.pm_diagram[n-1] if l2 == 0: @@ -2585,7 +2586,7 @@ def epsilon0(self): 1 """ n = self.parent().cartan_type().n - b = self.lift().to_highest_weight(index_set=list(range(2, n + 1)))[0] + b = self.lift().to_highest_weight(index_set=range(2, n + 1))[0] pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) l1, l2 = pm.pm_diagram[n-1] return l1 @@ -2602,7 +2603,7 @@ def phi0(self): 0 """ n = self.parent().cartan_type().n - b = self.lift().to_highest_weight(index_set=list(range(2, n + 1)))[0] + b = self.lift().to_highest_weight(index_set=range(2, n + 1))[0] pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) l1, l2 = pm.pm_diagram[n-1] return l2 @@ -2825,7 +2826,7 @@ def e0(self): """ n = self.parent().cartan_type().rank()-1 s = self.parent().s() - b, l = self.lift().to_highest_weight(index_set=list(range(2, n + 1))) + b, l = self.lift().to_highest_weight(index_set=range(2, n + 1)) pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) l1, l2 = pm.pm_diagram[n-1] l3 = pm.pm_diagram[n-2][0] @@ -2860,7 +2861,7 @@ def f0(self): """ n = self.parent().cartan_type().rank()-1 s = self.parent().s() - b, l = self.lift().to_highest_weight(index_set=list(range(2, n + 1))) + b, l = self.lift().to_highest_weight(index_set=range(2, n + 1)) pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) l1, l2 = pm.pm_diagram[n-1] l3 = pm.pm_diagram[n-2][0] @@ -2907,7 +2908,7 @@ def epsilon0(self): True """ n = self.parent().cartan_type().rank() - 1 - b, l = self.lift().to_highest_weight(index_set=list(range(2, n + 1))) + b, l = self.lift().to_highest_weight(index_set=range(2, n + 1)) pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) l1 = pm.pm_diagram[n-1][0] l4 = pm.pm_diagram[n][0] @@ -2940,7 +2941,7 @@ def phi0(self): True """ n = self.parent().cartan_type().rank() - 1 - b, l = self.lift().to_highest_weight(index_set=list(range(2, n + 1))) + b, l = self.lift().to_highest_weight(index_set=range(2, n + 1)) pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) l2 = pm.pm_diagram[n-1][1] l4 = pm.pm_diagram[n][0] @@ -3075,9 +3076,9 @@ def classical_decomposition(self): C = self.cartan_type().classical() s = QQ(self.s()) if self.r() == C.n: - c = [s/QQ(2)]*C.n + c = [s / QQ(2)]*C.n else: - c = [s/QQ(2)]*(C.n-1)+[-s/QQ(2)] + c = [s / QQ(2)]*(C.n-1) + [-s / QQ(2)] return CrystalOfTableaux(C, shape=c) def dynkin_diagram_automorphism(self, i): @@ -3155,6 +3156,7 @@ def neg(x): y = list(x) # map a (shallow) copy y[0] = -y[0] return tuple(y) + return {dic_weight[w]: dic_weight_dual[neg(w)] for w in dic_weight} @cached_method @@ -3779,7 +3781,7 @@ def __init__(self, pm_diagram, from_shapes=None): self._list = [i for a in reversed(pm_diagram) for i in a] self.width = sum(self._list) - def _repr_(self): + def _repr_(self) -> str: r""" Turning on pretty printing allows to display the `\pm` diagram as a tableau with the `+` and `-` displayed. @@ -3791,7 +3793,7 @@ def _repr_(self): """ return repr(self.pm_diagram) - def _repr_diagram(self): + def _repr_diagram(self) -> str: """ Return a string representation of ``self`` as a diagram. @@ -3910,7 +3912,7 @@ def intermediate_shape(self): p = [p[i] + ll[2*i+1] for i in range(self.n)] return Partition(p) - def heights_of_minus(self): + def heights_of_minus(self) -> list: r""" Return a list with the heights of all minus in the `\pm` diagram. @@ -3930,7 +3932,7 @@ def heights_of_minus(self): heights += [n-2*i]*((self.outer_shape()+[0]*n)[n-2*i-1]-(self.intermediate_shape()+[0]*n)[n-2*i-1]) return heights - def heights_of_addable_plus(self): + def heights_of_addable_plus(self) -> list: r""" Return a list with the heights of all addable plus in the `\pm` diagram. @@ -4176,7 +4178,7 @@ def _call_(self, x): self._cache[x] = y return y - def _repr_type(self): + def _repr_type(self) -> str: """ Return a string describing ``self``. @@ -4188,7 +4190,7 @@ def _repr_type(self): """ return "Diagram automorphism" - def is_isomorphism(self): + def is_isomorphism(self) -> bool: """ Return ``True`` as ``self`` is a crystal isomorphism. From 5d0985d40f4c6cce3378d392960214a5a4233993 Mon Sep 17 00:00:00 2001 From: Noel Roemmele Date: Mon, 3 Feb 2025 17:31:18 -0700 Subject: [PATCH 167/187] Updated wording of doctest to make it more clear why the doctest was included. --- src/sage/calculus/transforms/fft.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/calculus/transforms/fft.pyx b/src/sage/calculus/transforms/fft.pyx index 1b84daa02ee..0ba5838839e 100644 --- a/src/sage/calculus/transforms/fft.pyx +++ b/src/sage/calculus/transforms/fft.pyx @@ -166,7 +166,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): TESTS: - Assigning a value to a pair no longer assumes that the values are uninitialized. :: + Verify that :issue:10758 is fixed. :: sage: F = FFT(1) sage: F[0] = (1,1) From 85b52d78b31c440219015a589253422340ac2e0b Mon Sep 17 00:00:00 2001 From: Noel Roemmele Date: Mon, 3 Feb 2025 17:37:49 -0700 Subject: [PATCH 168/187] Fixed unhelpful doctest description and replaced it with a much more helpful one. --- src/sage/geometry/hyperplane_arrangement/library.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/hyperplane_arrangement/library.py b/src/sage/geometry/hyperplane_arrangement/library.py index 239069afb3e..a0decbcbd2a 100644 --- a/src/sage/geometry/hyperplane_arrangement/library.py +++ b/src/sage/geometry/hyperplane_arrangement/library.py @@ -142,7 +142,10 @@ def bigraphical(self, G, A=None, K=QQ, names=None): TESTS: - We try:: + One of the above examples was marked "# random" because the output is + not always the same. However, the answer is "65" more than 99.9% of the + time, so we can make a doctest by running it repeatedly + (see :issue:39167). :: sage: G = graphs.CycleGraph(4) sage: any(hyperplane_arrangements.bigraphical(G, From 4a123f09ec85ee7d968d39015280c21d723f8faf Mon Sep 17 00:00:00 2001 From: Noel Roemmele Date: Mon, 3 Feb 2025 19:18:50 -0700 Subject: [PATCH 169/187] Added missing ` from issue number in doctest description. --- src/sage/calculus/transforms/fft.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/calculus/transforms/fft.pyx b/src/sage/calculus/transforms/fft.pyx index 0ba5838839e..eb82b397766 100644 --- a/src/sage/calculus/transforms/fft.pyx +++ b/src/sage/calculus/transforms/fft.pyx @@ -166,7 +166,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): TESTS: - Verify that :issue:10758 is fixed. :: + Verify that :issue:`10758` is fixed. :: sage: F = FFT(1) sage: F[0] = (1,1) From d4461d49b5a8e3226a6a062ac84e5289e6cb3dd1 Mon Sep 17 00:00:00 2001 From: Noel Roemmele Date: Mon, 3 Feb 2025 19:22:58 -0700 Subject: [PATCH 170/187] Added missing ` from issue number in doctest description. --- src/sage/geometry/hyperplane_arrangement/library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/hyperplane_arrangement/library.py b/src/sage/geometry/hyperplane_arrangement/library.py index a0decbcbd2a..2019cf4d363 100644 --- a/src/sage/geometry/hyperplane_arrangement/library.py +++ b/src/sage/geometry/hyperplane_arrangement/library.py @@ -145,7 +145,7 @@ def bigraphical(self, G, A=None, K=QQ, names=None): One of the above examples was marked "# random" because the output is not always the same. However, the answer is "65" more than 99.9% of the time, so we can make a doctest by running it repeatedly - (see :issue:39167). :: + (see :issue:`39167`). :: sage: G = graphs.CycleGraph(4) sage: any(hyperplane_arrangements.bigraphical(G, From ea37295ad61289682cc31fd174844c15f786be07 Mon Sep 17 00:00:00 2001 From: Caleb Van't Land Date: Tue, 4 Feb 2025 10:03:57 -0700 Subject: [PATCH 171/187] Made import statements more specific --- src/sage/matrix/matrix_dense.pyx | 2 +- src/sage/matrix/matrix_sparse.pyx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_dense.pyx b/src/sage/matrix/matrix_dense.pyx index 09377f28df1..32c91d22371 100644 --- a/src/sage/matrix/matrix_dense.pyx +++ b/src/sage/matrix/matrix_dense.pyx @@ -11,9 +11,9 @@ TESTS:: cimport sage.matrix.matrix as matrix from sage.structure.richcmp cimport richcmp_item, rich_to_bool +from sage.calculus.functional import derivative import sage.matrix.matrix_space import sage.structure.sequence -import sage.calculus.functional cdef class Matrix_dense(matrix.Matrix): diff --git a/src/sage/matrix/matrix_sparse.pyx b/src/sage/matrix/matrix_sparse.pyx index 2c15391b1f6..1d8a74db7c0 100644 --- a/src/sage/matrix/matrix_sparse.pyx +++ b/src/sage/matrix/matrix_sparse.pyx @@ -16,6 +16,7 @@ from cysignals.signals cimport sig_check cimport sage.matrix.matrix as matrix cimport sage.matrix.matrix0 as matrix0 from sage.categories.rings import Rings +from sage.calculus.functional import derivative from sage.structure.element cimport Element, Vector from sage.structure.richcmp cimport richcmp_item, rich_to_bool @@ -23,7 +24,6 @@ from cpython cimport * from cpython.object cimport Py_EQ, Py_NE import sage.matrix.matrix_space -import sage.calculus.functional cdef class Matrix_sparse(matrix.Matrix): From d92247407baf72cb7b592d86db74c63083169c53 Mon Sep 17 00:00:00 2001 From: Caleb Van't Land Date: Tue, 4 Feb 2025 10:20:18 -0700 Subject: [PATCH 172/187] Added explanation of why doctests were needed --- src/sage/matrix/matrix_dense.pyx | 2 ++ src/sage/matrix/matrix_sparse.pyx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/sage/matrix/matrix_dense.pyx b/src/sage/matrix/matrix_dense.pyx index 32c91d22371..767e0539377 100644 --- a/src/sage/matrix/matrix_dense.pyx +++ b/src/sage/matrix/matrix_dense.pyx @@ -279,6 +279,8 @@ cdef class Matrix_dense(matrix.Matrix): TESTS: + Verify that :issue:`15067` is fixed:: + sage: u = matrix(1, 2, [-1, 1]) sage: derivative(u, x) [0 0] diff --git a/src/sage/matrix/matrix_sparse.pyx b/src/sage/matrix/matrix_sparse.pyx index 1d8a74db7c0..b8e5d76d8ea 100644 --- a/src/sage/matrix/matrix_sparse.pyx +++ b/src/sage/matrix/matrix_sparse.pyx @@ -814,6 +814,8 @@ cdef class Matrix_sparse(matrix.Matrix): TESTS: + Verify that :issue:`15067` is fixed:: + sage: m = matrix(3, 3, {(1, 1): 2, (0,2): 5}) sage: derivative(m, x) [0 0 0] From 3378294b3175868815593825dacc71c87abdde27 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 4 Feb 2025 18:00:23 -0600 Subject: [PATCH 173/187] fix gap's spkg-check --- build/pkgs/gap/spkg-check.in | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/build/pkgs/gap/spkg-check.in b/build/pkgs/gap/spkg-check.in index 6dc12ca9266..917c8eb7209 100644 --- a/build/pkgs/gap/spkg-check.in +++ b/build/pkgs/gap/spkg-check.in @@ -1,29 +1,3 @@ cd src -# #28728: Fix test failure in tst/testinstall/strings.tst -export LC_CTYPE=en_US.UTF-8 - -# #34391: in GAP 4.12 some packages need GAP package io -# to let tests run, otherwise this hangs. Thus we install io here. -cd pkg/io -./configure --with-gaproot=../.. -make -cd ../.. - -# This is the same as 'dev/ci.sh testinstall' (but dev/ci.sh is not part of the GAP tarball) -./gap tst/testinstall.g -if [[ $? -ne 0 ]]; then - exit 1 -fi - -LOG=dev/log/testinstall2_* - -echo "================================================================" -echo "Test log:" -cat $LOG -echo "================================================================" - -ERRORS=`grep ^##### $LOG` -if [[ ! -z "$ERRORS" ]]; then - exit 1 -fi +$MAKE check From 11cba3ddec072373c5953130c4cbfe0eeb7ef21b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 5 Feb 2025 10:16:58 +0100 Subject: [PATCH 174/187] fixed wrong changes --- src/sage/coding/binary_code.pyx | 15 +++++++-------- src/sage/rings/finite_rings/integer_mod.pyx | 7 +++---- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/sage/coding/binary_code.pyx b/src/sage/coding/binary_code.pyx index c137cc26932..1b8b1d17ae1 100644 --- a/src/sage/coding/binary_code.pyx +++ b/src/sage/coding/binary_code.pyx @@ -3370,8 +3370,8 @@ cdef class BinaryCodeClassifier: # equal to its minimum element v[k] = nu.new_first_smallest_nontrivial(k, W, self.Phi_size * k) if not nu.sat_225(k): hh = k + 1 - e[k] = 0 # see state 12 and 17 - state = 2 # continue down the tree + e[k] = 0 # see state 12 and 17 + state = 2 # continue down the tree elif state == 5: # same as state 3, but in the case where we haven't yet defined zeta @@ -3381,8 +3381,7 @@ cdef class BinaryCodeClassifier: zb__Lambda_rho[k] = Lambda[k] state = 4 - elif state == 6: - # at this stage, there is no reason to continue downward, so backtrack + elif state == 6: # at this stage, there is no reason to continue downward, so backtrack j = k # return to the longest ancestor nu[i] of nu that could have a @@ -3473,7 +3472,7 @@ cdef class BinaryCodeClassifier: state = 10 - elif state == 9: # nu is a better guess at the canonical label than rho + elif state == 9: # nu is a better guess at the canonical label than rho rho = PartitionStack(nu) k_rho = k qzb = 0 @@ -3483,7 +3482,7 @@ cdef class BinaryCodeClassifier: zb__Lambda_rho[k+1] = -1 state = 6 - elif state == 10: # we have an automorphism to process + elif state == 10: # we have an automorphism to process # increment l if l < self.L-1: l += 1 # store information about the automorphism to Omega and Phi @@ -3504,8 +3503,8 @@ cdef class BinaryCodeClassifier: Omega[ii] ^= (1< Date: Wed, 5 Feb 2025 23:02:27 +0100 Subject: [PATCH 175/187] Remove all__sagemath_categories --- pkgs/sagemath-categories/MANIFEST.in.m4 | 1 - src/sage/all__sagemath_categories.py | 6 ------ src/sage/meson.build | 1 - src/sage/misc/fpickle.pyx | 5 +---- src/sage/misc/package_dir.py | 3 +-- 5 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 src/sage/all__sagemath_categories.py diff --git a/pkgs/sagemath-categories/MANIFEST.in.m4 b/pkgs/sagemath-categories/MANIFEST.in.m4 index b2e35673ec0..ae0c1085e3d 100644 --- a/pkgs/sagemath-categories/MANIFEST.in.m4 +++ b/pkgs/sagemath-categories/MANIFEST.in.m4 @@ -42,7 +42,6 @@ global-exclude *.c global-exclude *.cpp global-exclude all__sagemath_*.* -global-include all__sagemath_categories.py global-exclude __pycache__ global-exclude *.py[co] diff --git a/src/sage/all__sagemath_categories.py b/src/sage/all__sagemath_categories.py deleted file mode 100644 index cb37b0baf2f..00000000000 --- a/src/sage/all__sagemath_categories.py +++ /dev/null @@ -1,6 +0,0 @@ -# sage_setup: distribution = sagemath-categories -from sage.all__sagemath_objects import * - -from sage.categories.all import * - -from sage.rings.all__sagemath_categories import * diff --git a/src/sage/meson.build b/src/sage/meson.build index d0cf55161b9..c90df69663f 100644 --- a/src/sage/meson.build +++ b/src/sage/meson.build @@ -89,7 +89,6 @@ py.install_sources( '__init__.py', 'all.py', 'all__sagemath_bliss.py', - 'all__sagemath_categories.py', 'all__sagemath_coxeter3.py', 'all__sagemath_environment.py', 'all__sagemath_mcqd.py', diff --git a/src/sage/misc/fpickle.pyx b/src/sage/misc/fpickle.pyx index 7a45ecc4f75..1dd438de210 100644 --- a/src/sage/misc/fpickle.pyx +++ b/src/sage/misc/fpickle.pyx @@ -106,10 +106,7 @@ def unpickle_function(pickled): def call_pickled_function(fpargs): - try: - import sage.all as toplevel - except ImportError: - import sage.all__sagemath_categories as toplevel + import sage.all as toplevel (fp, (args, kwds)) = fpargs f = eval("unpickle_function(fp)", toplevel.__dict__, {'fp': fp}) res = eval("f(*args, **kwds)", toplevel.__dict__, diff --git a/src/sage/misc/package_dir.py b/src/sage/misc/package_dir.py index 3ef3adf73be..6b6ca12803f 100644 --- a/src/sage/misc/package_dir.py +++ b/src/sage/misc/package_dir.py @@ -246,8 +246,7 @@ def is_package_or_sage_namespace_package_dir(path, *, distribution_filter=None): Implicit namespace packages (PEP 420) are only recognized if they follow the conventions of the Sage library, i.e., the directory contains - a file ``all.py`` or a file matching the pattern ``all__*.py`` - such as ``all__sagemath_categories.py``. + a file ``all.py`` or a file matching the pattern ``all__*.py``. INPUT: From 674824e47c8e7451ca2f3fa7ccc950a6ac223f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 6 Feb 2025 12:02:02 +0100 Subject: [PATCH 176/187] remove old deprecation in modular symbols --- src/sage/modular/modsym/p1list.pyx | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/sage/modular/modsym/p1list.pyx b/src/sage/modular/modsym/p1list.pyx index f7d5f4b209b..8831d084640 100644 --- a/src/sage/modular/modsym/p1list.pyx +++ b/src/sage/modular/modsym/p1list.pyx @@ -828,7 +828,7 @@ cdef class P1List(): """ return len(self.__list) - def __repr__(self): + def __repr__(self) -> str: """ Return the string representation of this P1List. @@ -838,7 +838,7 @@ cdef class P1List(): sage: str(L) # indirect doctest 'The projective line over the integers modulo 8' """ - return "The projective line over the integers modulo %s" % self.__N + return f"The projective line over the integers modulo {self.__N}" def lift_to_sl2z(self, int i): r""" @@ -1369,22 +1369,3 @@ def lift_to_sl2z(c, d, N): if N <= 2147483647: return lift_to_sl2z_llong(c, d, N) raise NotImplementedError("N too large") - - -def _make_p1list(n): - """ - Helper function used in pickling. - - Not intended for end-users. - - EXAMPLES:: - - sage: from sage.modular.modsym.p1list import _make_p1list - sage: _make_p1list(3) - doctest:...: DeprecationWarning: _make_p1list() is deprecated - See https://github.com/sagemath/sage/issues/25848 for details. - The projective line over the integers modulo 3 - """ - from sage.misc.superseded import deprecation_cython as deprecation - deprecation(25848, '_make_p1list() is deprecated') - return P1List(n) From 646392caf4ba4b50ce8967bf96451a115942660e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 6 Feb 2025 13:19:34 +0100 Subject: [PATCH 177/187] remove a deprecation simplicial complexes --- src/sage/topology/simplicial_complex.py | 27 +++++++------------------ 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/sage/topology/simplicial_complex.py b/src/sage/topology/simplicial_complex.py index ac0af5dcd7b..6b43dfb00ac 100644 --- a/src/sage/topology/simplicial_complex.py +++ b/src/sage/topology/simplicial_complex.py @@ -802,7 +802,7 @@ def __hash__(self): """ return hash(self.__set) - def _repr_(self): + def _repr_(self) -> str: """ Print representation. @@ -2003,7 +2003,7 @@ def suspension(self, n=1, is_mutable=True): rename_vertices=True) return self.suspension(1, is_mutable).suspension(int(n-1), is_mutable) - def disjoint_union(self, right, rename_vertices=None, is_mutable=True): + def disjoint_union(self, right, is_mutable=True): """ The disjoint union of this simplicial complex with another one. @@ -2011,14 +2011,6 @@ def disjoint_union(self, right, rename_vertices=None, is_mutable=True): - ``right`` -- the other simplicial complex (the right-hand factor) - - ``rename_vertices`` -- boolean (default: ``True``); if this is - ``True``, the vertices in the disjoint union will be renamed by the - formula: vertex "v" in the left-hand factor --> vertex "Lv" in the - disjoint union, vertex "w" in the right-hand factor --> vertex "Rw" - in the disjoint union. If this is false, this tries to construct the - disjoint union without renaming the vertices; this will cause - problems if the two factors have any vertices with names in common. - EXAMPLES:: sage: S1 = simplicial_complexes.Sphere(1) @@ -2026,15 +2018,10 @@ def disjoint_union(self, right, rename_vertices=None, is_mutable=True): sage: S1.disjoint_union(S2).homology() # needs sage.modules {0: Z, 1: Z, 2: Z} """ - if rename_vertices is not None: - from sage.misc.superseded import deprecation - deprecation(35907, 'the "rename_vertices" argument is deprecated') - - facets = [] - for f in self._facets: - facets.append(tuple(["L" + str(v) for v in f])) - for f in right._facets: - facets.append(tuple(["R" + str(v) for v in f])) + facets = [tuple(["L" + str(v) for v in f]) + for f in self._facets] + facets.extend(tuple(["R" + str(v) for v in f]) + for f in right._facets) return SimplicialComplex(facets, is_mutable=is_mutable) def wedge(self, right, rename_vertices=True, is_mutable=True): @@ -4516,7 +4503,7 @@ def _translation_from_numeric(self): # this function overrides the standard one for GenericCellComplex, # because it lists the maximal faces, not the total number of faces. - def _repr_(self): + def _repr_(self) -> str: """ Print representation. From 4fa4d539e9f31b339badb1811b6b62672d460908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 6 Feb 2025 13:34:39 +0100 Subject: [PATCH 178/187] remove deprecated stuff in cremona_database --- src/sage/databases/cremona.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index 9b881ed70ea..bf3b8989cf0 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -177,7 +177,7 @@ def is_optimal_id(id): return id[-1] == '1' and not id[-2].isdigit() -def cremona_letter_code(n): +def cremona_letter_code(n) -> str: """ Return the Cremona letter code corresponding to an integer. @@ -252,7 +252,7 @@ def cremona_letter_code(n): return s -def old_cremona_letter_code(n): +def old_cremona_letter_code(n) -> str: r""" Return the *old* Cremona letter code corresponding to an integer. @@ -1651,9 +1651,11 @@ def _init_allgens(self, ftpdata, largest_conductor=0): _db = None -def CremonaDatabase(name=None, mini=None, set_global=None): +def CremonaDatabase(name=None, mini=None): """ - Initialize the Cremona database with name ``name``. If ``name`` is + Initialize the Cremona database with name ``name``. + + If ``name`` is ``None`` it instead initializes large Cremona database (named 'cremona'), if available or default mini Cremona database (named 'cremona mini'). @@ -1690,10 +1692,6 @@ def CremonaDatabase(name=None, mini=None, set_global=None): ... ValueError: the full Cremona database is not available; consider using the mini Cremona database by setting mini=True """ - if set_global is not None: - from sage.misc.superseded import deprecation - deprecation(25825, "the set_global argument for CremonaDatabase is deprecated and ignored") - if name is None: if mini is None: if DatabaseCremona().is_present(): From 1dda562f8c420ced8b69337a0a3f13446632eb28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 6 Feb 2025 13:50:40 +0100 Subject: [PATCH 179/187] remove deprecated stuff in polyhedron plot --- src/sage/geometry/polyhedron/plot.py | 48 +++++++++++----------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 7a0ad2a2153..5aca0134d34 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -390,7 +390,7 @@ def __init__(self, polyhedron, proj=projection_func_identity): self(proj) - def _repr_(self): + def _repr_(self) -> str: """ Return a string describing the projection. @@ -1234,7 +1234,7 @@ 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, - output_type=None): + output_type='TikzPicture'): r""" Return a tikz picture of ``self`` as a string or as a :class:`~sage.misc.latex_standalone.TikzPicture` @@ -1256,8 +1256,8 @@ 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'``, + - ``output_type`` -- string (default: ``'TikzPicture'``); valid values + are ``'LatexExpr'`` and ``'TikzPicture'``, whether to return a :class:`LatexExpr` object (which inherits from Python :class:`str`) or a :class:`TikzPicture` object from module :mod:`sage.misc.latex_standalone` @@ -1372,8 +1372,7 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, 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') + ....: vertex_color='yellow', axis=True) sage: Image3 \documentclass[tikz]{standalone} \begin{document} @@ -1425,39 +1424,30 @@ 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 - tikz_string = self._tikz_2d(scale, edge_color, facet_color, opacity, - vertex_color, axis) + 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 tikz_string = self._tikz_2d_in_3d(view, angle, scale, edge_color, - facet_color, opacity, vertex_color, axis) + facet_color, opacity, + vertex_color, axis) else: # self is a 3-polytope in 3-space 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 = ("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' + facet_color, opacity, + vertex_color, axis) # return if output_type == 'LatexExpr': return tikz_string - elif output_type == 'TikzPicture': + + if 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)) + usepackage=None, usetikzlibrary=None, + macros=None, use_sage_preamble=False) + + 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""" From ba71bbd9e966212b4ecb11d1a05f2b0f79f0be65 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Thu, 6 Feb 2025 20:47:05 +0700 Subject: [PATCH 180/187] Revert unintended changes --- src/sage/numerical/optimize.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/numerical/optimize.py b/src/sage/numerical/optimize.py index 742de62d5de..38ff1316629 100644 --- a/src/sage/numerical/optimize.py +++ b/src/sage/numerical/optimize.py @@ -155,7 +155,7 @@ def find_root(f, a, b, xtol=10e-13, rtol=2.0**-50, maxiter=100, full_output=Fals import scipy.optimize import numpy if int(numpy.version.short_version[0]) > 1: - _ = numpy.set_printoptions(legacy="1.25") + numpy.set_printoptions(legacy="1.25") g = lambda x: float(f(x)) brentqRes = scipy.optimize.brentq(g, a, b, @@ -290,7 +290,7 @@ def find_local_minimum(f, a, b, tol=1.48e-08, maxfun=500): import scipy.optimize import numpy if int(numpy.version.short_version[0]) > 1: - _ = numpy.set_printoptions(legacy="1.25") + numpy.set_printoptions(legacy="1.25") xmin, fval, iter, funcalls = scipy.optimize.fminbound(f, a, b, full_output=1, xtol=tol, maxfun=maxfun) return fval, xmin @@ -400,7 +400,7 @@ def minimize(func, x0, gradient=None, hessian=None, algorithm='default', from sage.ext.fast_callable import fast_callable import numpy if int(numpy.version.short_version[0]) > 1: - _ = numpy.set_printoptions(legacy="1.25") + numpy.set_printoptions(legacy="1.25") from scipy import optimize if isinstance(func, Expression): @@ -539,7 +539,7 @@ def minimize_constrained(func, cons, x0, gradient=None, algorithm='default', **a from sage.ext.fast_callable import fast_callable import numpy if int(numpy.version.short_version[0]) > 1: - _ = numpy.set_printoptions(legacy="1.25") + numpy.set_printoptions(legacy="1.25") from scipy import optimize function_type = type(lambda x,y: x+y) @@ -662,7 +662,7 @@ def find_fit(data, model, initial_guess=None, parameters=None, variables=None, s """ import numpy if int(numpy.version.short_version[0]) > 1: - _ = numpy.set_printoptions(legacy="1.25") + numpy.set_printoptions(legacy="1.25") if not isinstance(data, numpy.ndarray): try: From 3c2b836bc0acc797400d92eae67ab39daffa8119 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Thu, 6 Feb 2025 22:45:47 +0700 Subject: [PATCH 181/187] Add title for integral_points --- src/sage/geometry/integral_points.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/geometry/integral_points.py b/src/sage/geometry/integral_points.py index 48153591bcf..a35cf7a3689 100644 --- a/src/sage/geometry/integral_points.py +++ b/src/sage/geometry/integral_points.py @@ -1,3 +1,7 @@ +r""" +Cython helper methods to compute integral points in polyhedra +""" + try: from .integral_points_integer_dense import ( parallelotope_points, From 5c350758e4344c25bce59251e728794aa537a2d8 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Thu, 6 Feb 2025 16:47:31 +0100 Subject: [PATCH 182/187] small improvement in classically_highest_weight_vectors --- src/sage/categories/loop_crystals.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/loop_crystals.py b/src/sage/categories/loop_crystals.py index a13925b8f6e..5948090c3a7 100644 --- a/src/sage/categories/loop_crystals.py +++ b/src/sage/categories/loop_crystals.py @@ -773,16 +773,17 @@ def classically_highest_weight_vectors(self): except StopIteration: it.pop() if path: - path.pop(0) + path.pop() continue - b = self.element_class(self, [x] + path) + path.append(x) + b = self.element_class(self, reversed(path)) if not b.is_highest_weight(index_set=I0): + path.pop() continue - path.insert(0, x) if len(path) == n: ret.append(b) - path.pop(0) + path.pop() else: it.append(iter(self.crystals[-len(path) - 1])) return tuple(ret) From 0ddb79ae295c99c2990a4fc56763e5fb99b89ae8 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Thu, 6 Feb 2025 23:41:47 +0700 Subject: [PATCH 183/187] Add __all__ --- src/sage/geometry/integral_points.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/geometry/integral_points.py b/src/sage/geometry/integral_points.py index a35cf7a3689..155c70480b9 100644 --- a/src/sage/geometry/integral_points.py +++ b/src/sage/geometry/integral_points.py @@ -26,3 +26,9 @@ Inequality_int, InequalityCollection, ) + + +# __all__ is needed to generate Sphinx documentation +__all__ = ['InequalityCollection', 'Inequality_generic', 'Inequality_int', + 'loop_over_parallelotope_points', 'parallelotope_points', 'print_cache', + 'ray_matrix_normal_form', 'rectangular_box_points', 'simplex_points'] From 82f5890bf1604d4d07a1c8b2b17df8d73ad876b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 6 Feb 2025 18:59:22 +0100 Subject: [PATCH 184/187] doctest added --- src/sage/geometry/polyhedron/plot.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 5aca0134d34..a93690e345f 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1405,6 +1405,15 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, ... NotImplementedError: The polytope has to live in 2 or 3 dimensions. + TESTS:: + + sage: P = Polyhedron(vertices=[[0,0,0], [1,0,0], + ....: [0,0,1], [0,1,0]]) + sage: P.projection().tikz(output_type='kawai') + Traceback (most recent call last): + ... + ValueError: output_type (='kawai') must be 'LatexExpr' or 'TikzPicture' + .. TODO:: Make it possible to draw Schlegel diagram for 4-polytopes. :: From 547b3a61adbbc0c6bb815d7ad6448ff47daa4032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 6 Feb 2025 19:02:27 +0100 Subject: [PATCH 185/187] suggested detail --- src/sage/topology/simplicial_complex.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/topology/simplicial_complex.py b/src/sage/topology/simplicial_complex.py index 6b43dfb00ac..6a1291579b2 100644 --- a/src/sage/topology/simplicial_complex.py +++ b/src/sage/topology/simplicial_complex.py @@ -2018,10 +2018,8 @@ def disjoint_union(self, right, is_mutable=True): sage: S1.disjoint_union(S2).homology() # needs sage.modules {0: Z, 1: Z, 2: Z} """ - facets = [tuple(["L" + str(v) for v in f]) - for f in self._facets] - facets.extend(tuple(["R" + str(v) for v in f]) - for f in right._facets) + facets = [tuple(f"L{v}" for v in f) for f in self._facets] + facets.extend(tuple(f"R{v}" for v in f) for f in right._facets) return SimplicialComplex(facets, is_mutable=is_mutable) def wedge(self, right, rename_vertices=True, is_mutable=True): From 8cecf8c5128c3c94cd910765ab05916826812c8a Mon Sep 17 00:00:00 2001 From: Caleb Van't Land Date: Thu, 6 Feb 2025 11:48:29 -0700 Subject: [PATCH 186/187] Removed whitespace at the end of a line --- src/sage/matrix/matrix_dense.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix_dense.pyx b/src/sage/matrix/matrix_dense.pyx index 767e0539377..5280d1e2778 100644 --- a/src/sage/matrix/matrix_dense.pyx +++ b/src/sage/matrix/matrix_dense.pyx @@ -280,7 +280,7 @@ cdef class Matrix_dense(matrix.Matrix): TESTS: Verify that :issue:`15067` is fixed:: - + sage: u = matrix(1, 2, [-1, 1]) sage: derivative(u, x) [0 0] From 766c7a0c5b89a97be80cd14da84a99793697dc5a Mon Sep 17 00:00:00 2001 From: Release Manager Date: Tue, 11 Feb 2025 00:36:13 +0100 Subject: [PATCH 187/187] Updated SageMath version to 10.6.beta6 --- CITATION.cff | 4 ++-- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 4 ++-- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/sage_conf/version_requirements.txt | 2 +- build/pkgs/sage_docbuild/version_requirements.txt | 2 +- build/pkgs/sage_setup/version_requirements.txt | 2 +- build/pkgs/sage_sws2rst/version_requirements.txt | 2 +- build/pkgs/sagelib/version_requirements.txt | 2 +- build/pkgs/sagemath_bliss/version_requirements.txt | 2 +- build/pkgs/sagemath_categories/version_requirements.txt | 2 +- build/pkgs/sagemath_coxeter3/version_requirements.txt | 2 +- build/pkgs/sagemath_environment/version_requirements.txt | 2 +- build/pkgs/sagemath_mcqd/version_requirements.txt | 2 +- build/pkgs/sagemath_meataxe/version_requirements.txt | 2 +- build/pkgs/sagemath_objects/version_requirements.txt | 2 +- build/pkgs/sagemath_repl/version_requirements.txt | 2 +- build/pkgs/sagemath_sirocco/version_requirements.txt | 2 +- build/pkgs/sagemath_tdlib/version_requirements.txt | 2 +- pkgs/sage-conf/VERSION.txt | 2 +- pkgs/sage-conf_conda/VERSION.txt | 2 +- pkgs/sage-conf_pypi/VERSION.txt | 2 +- pkgs/sage-docbuild/VERSION.txt | 2 +- pkgs/sage-setup/VERSION.txt | 2 +- pkgs/sage-sws2rst/VERSION.txt | 2 +- pkgs/sagemath-bliss/VERSION.txt | 2 +- pkgs/sagemath-categories/VERSION.txt | 2 +- pkgs/sagemath-coxeter3/VERSION.txt | 2 +- pkgs/sagemath-environment/VERSION.txt | 2 +- pkgs/sagemath-mcqd/VERSION.txt | 2 +- pkgs/sagemath-meataxe/VERSION.txt | 2 +- pkgs/sagemath-objects/VERSION.txt | 2 +- pkgs/sagemath-repl/VERSION.txt | 2 +- pkgs/sagemath-sirocco/VERSION.txt | 2 +- pkgs/sagemath-tdlib/VERSION.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 38 files changed, 44 insertions(+), 44 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index b4e3a375a3a..305ef37cbd5 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -4,8 +4,8 @@ title: SageMath abstract: SageMath is a free open-source mathematics software system. authors: - name: "The SageMath Developers" -version: 10.6.beta5 +version: 10.6.beta6 doi: 10.5281/zenodo.8042260 -date-released: 2025-01-26 +date-released: 2025-02-10 repository-code: "https://github.com/sagemath/sage" url: "https://www.sagemath.org/" diff --git a/VERSION.txt b/VERSION.txt index 5c3eb78337a..0dec762feaa 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 10.6.beta5, Release Date: 2025-01-26 +SageMath version 10.6.beta6, Release Date: 2025-02-10 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 7fe623c69c1..a0a7107a52d 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,3 +1,3 @@ tarball=configure-VERSION.tar.gz -sha1=2a6cd0b57346c92a73fc14246672abd6f150b423 -sha256=a732b3abcdf5f63995c63b765af00bfeed8efb67f1f451caac3ae2f48a105ad4 +sha1=db7e875cd888f974f7de2c038b2ae75ea5a31b1b +sha256=c905a38a83d6f718258cab25cb643c574fdb600016605c5e252584271bf6ac53 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 499ff6aca3c..62ea228719b 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -3735a1f77361171f19919b1651e14a56332c41ba +00c302e55c156a7dd678229ff976ed90ce3d5161 diff --git a/build/pkgs/sage_conf/version_requirements.txt b/build/pkgs/sage_conf/version_requirements.txt index 040b5f2631a..77d6c0cb0c5 100644 --- a/build/pkgs/sage_conf/version_requirements.txt +++ b/build/pkgs/sage_conf/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 10.6b5 +sage-conf ~= 10.6b6 diff --git a/build/pkgs/sage_docbuild/version_requirements.txt b/build/pkgs/sage_docbuild/version_requirements.txt index c0283b9405a..50eb65e2172 100644 --- a/build/pkgs/sage_docbuild/version_requirements.txt +++ b/build/pkgs/sage_docbuild/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 10.6b5 +sage-docbuild ~= 10.6b6 diff --git a/build/pkgs/sage_setup/version_requirements.txt b/build/pkgs/sage_setup/version_requirements.txt index bd4234f31a6..06adbdc6df6 100644 --- a/build/pkgs/sage_setup/version_requirements.txt +++ b/build/pkgs/sage_setup/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 10.6b5 +sage-setup ~= 10.6b6 diff --git a/build/pkgs/sage_sws2rst/version_requirements.txt b/build/pkgs/sage_sws2rst/version_requirements.txt index e856ed4cc63..dd05f21376e 100644 --- a/build/pkgs/sage_sws2rst/version_requirements.txt +++ b/build/pkgs/sage_sws2rst/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 10.6b5 +sage-sws2rst ~= 10.6b6 diff --git a/build/pkgs/sagelib/version_requirements.txt b/build/pkgs/sagelib/version_requirements.txt index c6e36270655..e64a5d0c206 100644 --- a/build/pkgs/sagelib/version_requirements.txt +++ b/build/pkgs/sagelib/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-standard ~= 10.6b5 +sagemath-standard ~= 10.6b6 diff --git a/build/pkgs/sagemath_bliss/version_requirements.txt b/build/pkgs/sagemath_bliss/version_requirements.txt index bf5262fa6eb..d88731f06e9 100644 --- a/build/pkgs/sagemath_bliss/version_requirements.txt +++ b/build/pkgs/sagemath_bliss/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-bliss ~= 10.6b5 +sagemath-bliss ~= 10.6b6 diff --git a/build/pkgs/sagemath_categories/version_requirements.txt b/build/pkgs/sagemath_categories/version_requirements.txt index 39c5c3b7890..198cb911336 100644 --- a/build/pkgs/sagemath_categories/version_requirements.txt +++ b/build/pkgs/sagemath_categories/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 10.6b5 +sagemath-categories ~= 10.6b6 diff --git a/build/pkgs/sagemath_coxeter3/version_requirements.txt b/build/pkgs/sagemath_coxeter3/version_requirements.txt index d1ebc2d30a9..7415f70536b 100644 --- a/build/pkgs/sagemath_coxeter3/version_requirements.txt +++ b/build/pkgs/sagemath_coxeter3/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-coxeter3 ~= 10.6b5 +sagemath-coxeter3 ~= 10.6b6 diff --git a/build/pkgs/sagemath_environment/version_requirements.txt b/build/pkgs/sagemath_environment/version_requirements.txt index c88968f714c..09106be9ba3 100644 --- a/build/pkgs/sagemath_environment/version_requirements.txt +++ b/build/pkgs/sagemath_environment/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 10.6b5 +sagemath-environment ~= 10.6b6 diff --git a/build/pkgs/sagemath_mcqd/version_requirements.txt b/build/pkgs/sagemath_mcqd/version_requirements.txt index ef5a7f503b7..bff6125dcaf 100644 --- a/build/pkgs/sagemath_mcqd/version_requirements.txt +++ b/build/pkgs/sagemath_mcqd/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-mcqd ~= 10.6b5 +sagemath-mcqd ~= 10.6b6 diff --git a/build/pkgs/sagemath_meataxe/version_requirements.txt b/build/pkgs/sagemath_meataxe/version_requirements.txt index 569e25992ab..662a7b7e7f6 100644 --- a/build/pkgs/sagemath_meataxe/version_requirements.txt +++ b/build/pkgs/sagemath_meataxe/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-meataxe ~= 10.6b5 +sagemath-meataxe ~= 10.6b6 diff --git a/build/pkgs/sagemath_objects/version_requirements.txt b/build/pkgs/sagemath_objects/version_requirements.txt index 2e920aa86d6..df4dc506909 100644 --- a/build/pkgs/sagemath_objects/version_requirements.txt +++ b/build/pkgs/sagemath_objects/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 10.6b5 +sagemath-objects ~= 10.6b6 diff --git a/build/pkgs/sagemath_repl/version_requirements.txt b/build/pkgs/sagemath_repl/version_requirements.txt index cfff7dea4c2..5f906d7000a 100644 --- a/build/pkgs/sagemath_repl/version_requirements.txt +++ b/build/pkgs/sagemath_repl/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-repl ~= 10.6b5 +sagemath-repl ~= 10.6b6 diff --git a/build/pkgs/sagemath_sirocco/version_requirements.txt b/build/pkgs/sagemath_sirocco/version_requirements.txt index b0d92f0ad87..9077fb7fff0 100644 --- a/build/pkgs/sagemath_sirocco/version_requirements.txt +++ b/build/pkgs/sagemath_sirocco/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-sirocco ~= 10.6b5 +sagemath-sirocco ~= 10.6b6 diff --git a/build/pkgs/sagemath_tdlib/version_requirements.txt b/build/pkgs/sagemath_tdlib/version_requirements.txt index 0d1d8e4eaaa..37d47b62c5f 100644 --- a/build/pkgs/sagemath_tdlib/version_requirements.txt +++ b/build/pkgs/sagemath_tdlib/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-tdlib ~= 10.6b5 +sagemath-tdlib ~= 10.6b6 diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sage-conf_conda/VERSION.txt b/pkgs/sage-conf_conda/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sage-conf_conda/VERSION.txt +++ b/pkgs/sage-conf_conda/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sagemath-bliss/VERSION.txt +++ b/pkgs/sagemath-bliss/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sagemath-coxeter3/VERSION.txt +++ b/pkgs/sagemath-coxeter3/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sagemath-mcqd/VERSION.txt +++ b/pkgs/sagemath-mcqd/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sagemath-meataxe/VERSION.txt +++ b/pkgs/sagemath-meataxe/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sagemath-sirocco/VERSION.txt +++ b/pkgs/sagemath-sirocco/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/pkgs/sagemath-tdlib/VERSION.txt +++ b/pkgs/sagemath-tdlib/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/src/VERSION.txt b/src/VERSION.txt index d201bc08e28..8b3698135db 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -10.6.beta5 +10.6.beta6 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index a4df2cecd2c..d1e2aa14731 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='10.6.beta5' -SAGE_RELEASE_DATE='2025-01-26' -SAGE_VERSION_BANNER='SageMath version 10.6.beta5, Release Date: 2025-01-26' +SAGE_VERSION='10.6.beta6' +SAGE_RELEASE_DATE='2025-02-10' +SAGE_VERSION_BANNER='SageMath version 10.6.beta6, Release Date: 2025-02-10' diff --git a/src/sage/version.py b/src/sage/version.py index a8b68889f48..6291f1b503f 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '10.6.beta5' -date = '2025-01-26' -banner = 'SageMath version 10.6.beta5, Release Date: 2025-01-26' +version = '10.6.beta6' +date = '2025-02-10' +banner = 'SageMath version 10.6.beta6, Release Date: 2025-02-10'