From 1a171d26e83b9c00e9b6f9429db1b4a8c0d578dc Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Mon, 31 Aug 2020 21:50:48 +0200 Subject: [PATCH 001/511] 30477: fix conflict between implicit multiplication and complex literals --- src/sage/repl/preparse.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index 1206835df95..be64691e613 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -1481,6 +1481,13 @@ def implicit_mul(code, level=5): sage: implicit_mul('3λ') '3*λ' + + Check support for complex literals (:trac:`30477`):: + + sage: implicit_mul('2r-1JR') + '2r-1JR' + sage: implicit_mul('1E3 + 0.3E-3rj') + '1e3 + 0.3e-3rj' """ from keyword import iskeyword keywords_py2 = ['print', 'exec'] @@ -1502,8 +1509,8 @@ def re_no_keyword(pattern, code): no_mul_token = " '''_no_mult_token_''' " code = re.sub(r'\b0x', r'0%sx' % no_mul_token, code) # hex digits code = re.sub(r'( *)time ', r'\1time %s' % no_mul_token, code) # first word may be magic 'time' - code = re.sub(r'\b(\d+(?:\.\d+)?(?:e\d+)?)([rR]\b)', r'\1%s\2' % no_mul_token, code) # exclude such things as 10r - code = re.sub(r'\b(\d+(?:\.\d+)?)e([-\d])', r'\1%se%s\2' % (no_mul_token, no_mul_token), code) # exclude such things as 1e5 + code = re.sub(r'\b(\d+(?:\.\d+)?(?:e\d+)?)(rj?\b|j?r\b)', r'\1%s\2' % no_mul_token, code, flags=re.I) # exclude such things as 10r, 10rj, 10jr + code = re.sub(r'\b(\d+(?:\.\d+)?)e([-\d])', r'\1%se%s\2' % (no_mul_token, no_mul_token), code, flags=re.I) # exclude such things as 1e5 code = re_no_keyword(r'\b((?:\d+(?:\.\d+)?)|(?:%s[0-9eEpn]*\b)) *([^\W\d(]\w*)\b' % numeric_literal_prefix, code) if level >= 2: code = re.sub(r'(\%\(L\d+\))s', r'\1%ss%s' % (no_mul_token, no_mul_token), code) # literal strings From ac5350d40241e0b09547c5acc2784a9d05d6b535 Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Wed, 16 Jun 2021 16:59:02 -0400 Subject: [PATCH 002/511] 31994: initial commit, contains zero division error --- src/doc/en/reference/references/index.rst | 3 + .../arithmetic_dynamics/projective_ds.py | 55 ++++++++++++++++++- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index a5b4d54eeed..72ee62693ff 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -3037,6 +3037,9 @@ REFERENCES: .. [Hutz2015] \B. Hutz. Determination of all rational preperiodic points for morphisms of PN. Mathematics of Computation, 84:291 (2015), 289-308. +.. [Hutz2019] \B. Hutz. Multipliers and invariants of endomorphisms of projective + space in dimension greater than 1 + .. [Huy2005] \D. Huybrechts : *Complex Geometry*, Springer (Berlin) (2005). diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index e61061c5622..757a6ca05cd 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4359,7 +4359,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur return multipliers - def sigma_invariants(self, n, formal=False, embedding=None, type='point'): + def sigma_invariants(self, n, formal=False, embedding=None, type='point', return_polynomial=False): r""" Computes the values of the elementary symmetric polynomials of the ``n`` multiplier spectra of this dynamical system. @@ -4392,6 +4392,9 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point'): variable `w`. Note that if `f` is a rational function, we clear denominators for `g`. + To calculate the full polynomial defining the sigma invariants, + we follow the algorithm outlined in section 4 of [Hutz2019]_. + INPUT: - ``n`` -- a positive integer, the period @@ -4409,6 +4412,12 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point'): or ``'cycle'`` depending on whether you compute with one multiplier per point or one per cycle + - ``return polynomial`` -- (default: ``False``) boolean; + ``True`` specifies returning the polynomial which generates + the sigma invariants, see [Hutz2019]_ for the full definition. + The polynomial is always a multivariate polynomial with variables + ``w`` and ``t``. + OUTPUT: a list of elements in the base ring EXAMPLES:: @@ -4513,13 +4522,53 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point'): dom = self.domain() if not is_ProjectiveSpace(dom): raise NotImplementedError("not implemented for subschemes") - if dom.dimension_relative() > 1: - raise NotImplementedError("only implemented for dimension 1") if not embedding is None: from sage.misc.superseded import deprecation deprecation(23333, "embedding keyword no longer used") if self.degree() <= 1: raise TypeError("must have degree at least 2") + if dom.dimension_relative() > 1 or return_polynomial: + from sage.calculus.functions import jacobian + d = self.degree() + N = dom.dimension_relative() + Fn = self.nth_iterate_map(n) + base_ring = self.base_ring() + X = Fn.periodic_points(1, minimal=False, return_scheme=True) + R = PolynomialRing(base_ring, 'v', N+N+3, order='lex') + var = list(R.gens()) + R2 = PolynomialRing(base_ring, var[:N] + var[-2:]) + newR = PolynomialRing(base_ring, 'w, t', 2, order='lex') + psi = R2.hom(N*[0]+list(newR.gens()), newR) + R_zero = {R.gen(N):1} + for j in range(N+1, N+N+1): + R_zero[R.gen(j)] = 0 + t = var.pop() + w = var.pop() + var = var[:N] + sigma_polynomial = 1 + for j in range(N,-1,-1): + Xa = X.affine_patch(j) + fa = Fn.dehomogenize(j) + Pa = fa.domain() + im = [R.gen(i) for i in range(j)] + (N-j)*[0] + phi = Pa.coordinate_ring().hom(im, R) + M = t*matrix.identity(R, N) + print(jacobian([phi(F.numerator())/phi(F.denominator()) for F in fa], var)) + g = (M-jacobian([phi(F.numerator())/phi(F.denominator()) for F in fa], var)).det() + L = [phi(h) for h in Xa.defining_polynomials()] + L += [w*g.denominator()-R.gen(N)*g.numerator() + sum(R.gen(j-1)*R.gen(N+j)*g.denominator() for j in range(1,N+1))] + I = R.ideal(L) + G = I.groebner_basis() + sigma_polynomial *= psi(G[-1].specialization(R_zero)) + if return_polynomial: + return sigma_polynomial + sigmas = [] + sigma_dictionary = dict([list(reversed(i)) for i in list(sigma_polynomial)]) + degree = sigma_polynomial.degree() + for i in range(degree, -1, -1): + for j in range(degree-j, -1, -1): + sigmas.append(sigma_dictionary.pop(w**i*t**j, 0)) + return sigmas if not type in ['point', 'cycle']: raise ValueError("type must be either point or cycle") From 18c12b3dbee056f527b83d4d72dd1016c457ec3a Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Fri, 18 Jun 2021 17:14:31 -0400 Subject: [PATCH 003/511] 31994: added chow algorithm, documentation, examples --- .../arithmetic_dynamics/projective_ds.py | 101 ++++++++++++++---- 1 file changed, 79 insertions(+), 22 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 757a6ca05cd..a4e519f22b4 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4359,7 +4359,8 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur return multipliers - def sigma_invariants(self, n, formal=False, embedding=None, type='point', return_polynomial=False): + def sigma_invariants(self, n, formal=False, embedding=None, type='point', + return_polynomial=False, chow=False): r""" Computes the values of the elementary symmetric polynomials of the ``n`` multiplier spectra of this dynamical system. @@ -4418,7 +4419,14 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', return The polynomial is always a multivariate polynomial with variables ``w`` and ``t``. - OUTPUT: a list of elements in the base ring + - ``chow`` -- (default: ``False``) boolean; ``True`` specifies + using the Chow algorithm from [Hutz2019]_ to compute the sigma + invariants. While slower, the Chow algorithm does not lose + information about multiplicities. Helpful when this map has + repeated multipliers or fixed points with high multiplicity. + + OUTPUT: a list of elements in the base ring, unless ``return_polynomial`` + is ``True``, in which case a polynomial in ``w`` and ``t`` is returned. EXAMPLES:: @@ -4431,6 +4439,20 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', return -2622661107937102104196133701280271632423/549755813888, 338523204830161116503153209450763500631714178825448006778305/72057594037927936, 0] + :: + + sage: P. = ProjectiveSpace(QQ,1) + sage: f = DynamicalSystem_projective([x^2 + 2*y^2, y^2]) + sage: poly = f.sigma_invariants(1, return_polynomial=True); poly + w^3 - 3*w^2*t + 2*w^2 + 3*w*t^2 - 4*w*t + 8*w - t^3 + 2*t^2 - 8*t + + From the full polynomial, we can easily get the one variable polynomial whose coefficients + are symmetric functions in the multipliers:: + + sage: w, t = poly.variabls() + sage: poly.subs({w:0}) + -t^3 + 2*t^2 - 8*t + :: sage: set_verbose(None) @@ -4460,10 +4482,25 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', return sage: P. = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) - sage: f.sigma_invariants(1) - Traceback (most recent call last): - ... - NotImplementedError: only implemented for dimension 1 + sage: f.sigma_invariants(1, return_polynomial=True, chow=True) + w^7 - 7*w^6*t^2 + 10*w^6*t - 4*w^6 + 21*w^5*t^4 - 60*w^5*t^3 + 60*w^5*t^2 - + 24*w^5*t - 35*w^4*t^6 + 150*w^4*t^5 - 240*w^4*t^4 + 176*w^4*t^3 - 48*w^4*t^2 + + 35*w^3*t^8 - 200*w^3*t^7 + 440*w^3*t^6 - 464*w^3*t^5 + 224*w^3*t^4 - 32*w^3*t^3 + - 21*w^2*t^10 + 150*w^2*t^9 - 420*w^2*t^8 + 576*w^2*t^7 - 384*w^2*t^6 + 96*w^2*t^5 + + 7*w*t^12 - 60*w*t^11 + 204*w*t^10 - 344*w*t^9 + 288*w*t^8 - 96*w*t^7 - t^14 + + 10*t^13 - 40*t^12 + 80*t^11 - 80*t^10 + 32*t^9 + + :: + + sage: P. = ProjectiveSpace(QQ, 3) + sage: f = DynamicalSystem_projective([x^2, w^2, z^2, y^2]) + sage: f.sigma_invariants(1, return_polynomial=True) + w^6 - 6*w^5*t^3 + 2*w^5*t^2 + 8*w^5*t - 8*w^5 + 15*w^4*t^6 - 10*w^4*t^5 - + 44*w^4*t^4 + 48*w^4*t^3 + 16*w^4*t^2 - 32*w^4*t - 20*w^3*t^9 + 20*w^3*t^8 + + 96*w^3*t^7 - 120*w^3*t^6 - 96*w^3*t^5 + 160*w^3*t^4 + 15*w^2*t^12 - 20*w^2*t^11 + - 104*w^2*t^10 + 152*w^2*t^9 + 192*w^2*t^8 - 320*w^2*t^7 - 64*w^2*t^6 + 128*w^2*t^5 + - 6*w*t^15 + 10*w*t^14 + 56*w*t^13 - 96*w*t^12 - 160*w*t^11 + 288*w*t^10 + 128*w*t^9 + - 256*w*t^8 + t^18 - 2*t^17 - 12*t^16 + 24*t^15 + 48*t^14 - 96*t^13 - 64*t^12 + 128*t^11 :: @@ -4534,32 +4571,52 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', return Fn = self.nth_iterate_map(n) base_ring = self.base_ring() X = Fn.periodic_points(1, minimal=False, return_scheme=True) - R = PolynomialRing(base_ring, 'v', N+N+3, order='lex') - var = list(R.gens()) - R2 = PolynomialRing(base_ring, var[:N] + var[-2:]) newR = PolynomialRing(base_ring, 'w, t', 2, order='lex') - psi = R2.hom(N*[0]+list(newR.gens()), newR) - R_zero = {R.gen(N):1} - for j in range(N+1, N+N+1): - R_zero[R.gen(j)] = 0 - t = var.pop() - w = var.pop() - var = var[:N] + if chow: + R = PolynomialRing(base_ring, 'v', N+N+3, order='lex') + var = list(R.gens()) + R2 = PolynomialRing(base_ring, var[:N] + var[-2:]) + psi = R2.hom(N*[0]+list(newR.gens()), newR) + R_zero = {R.gen(N):1} + for j in range(N+1, N+N+1): + R_zero[R.gen(j)] = 0 + t = var.pop() + w = var.pop() + var = var[:N] + else: + R = PolynomialRing(base_ring,'v', N+2, order='lex') + psi = R.hom(N*[0] + list(newR.gens()), newR) + var = list(R.gens()) + t = var.pop() + w = var.pop() sigma_polynomial = 1 for j in range(N,-1,-1): Xa = X.affine_patch(j) fa = Fn.dehomogenize(j) Pa = fa.domain() - im = [R.gen(i) for i in range(j)] + (N-j)*[0] - phi = Pa.coordinate_ring().hom(im, R) + Ra = Pa.coordinate_ring() + if chow: + im = [R.gen(i) for i in range(j)] + (N-j)*[0] + [R.gen(i) for i in range(N, R.ngens())] + else: + im = list(R.gens())[:j] + (N-j)*[0] + [R.gen(i) for i in range(N, R.ngens())] + phi = Ra.hom(Ra.gens(), R) M = t*matrix.identity(R, N) - print(jacobian([phi(F.numerator())/phi(F.denominator()) for F in fa], var)) g = (M-jacobian([phi(F.numerator())/phi(F.denominator()) for F in fa], var)).det() - L = [phi(h) for h in Xa.defining_polynomials()] - L += [w*g.denominator()-R.gen(N)*g.numerator() + sum(R.gen(j-1)*R.gen(N+j)*g.denominator() for j in range(1,N+1))] + g_prime = w*R(g.denominator())(im)-R(g.numerator())(im) + L = [phi(h)(im) for h in Xa.defining_polynomials()] + if chow: + L += [g_prime + sum(R.gen(j-1)*R.gen(N+j)*(R(g.denominator())(im)) for j in range(1,N+1))] + else: + L += [g_prime] I = R.ideal(L) G = I.groebner_basis() - sigma_polynomial *= psi(G[-1].specialization(R_zero)) + if chow: + poly = psi(G[-1].specialization(R_zero)) + if len(list(poly)) > 0: + poly *= poly.coefficients()[0].inverse_of_unit() + sigma_polynomial *= poly + else: + sigma_polynomial *= psi(G[-1]) if return_polynomial: return sigma_polynomial sigmas = [] From 8b3ea6a41e12b82eff6d2f1c6c5c5b5124c581bf Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Fri, 18 Jun 2021 17:17:47 -0400 Subject: [PATCH 004/511] 31994: added formal parameter --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index f1a980d1f7e..5fa3ba31b05 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4737,7 +4737,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', N = dom.dimension_relative() Fn = self.nth_iterate_map(n) base_ring = self.base_ring() - X = Fn.periodic_points(1, minimal=False, return_scheme=True) + X = Fn.periodic_points(1, minimal=False, formal=formal, return_scheme=True) newR = PolynomialRing(base_ring, 'w, t', 2, order='lex') if chow: R = PolynomialRing(base_ring, 'v', N+N+3, order='lex') From abedd5944595c822e30fe946ddbab35c182a9eaf Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 21 Jun 2021 16:41:24 -0400 Subject: [PATCH 005/511] 31994: updated documentation and list return --- src/doc/en/reference/references/index.rst | 2 +- .../arithmetic_dynamics/projective_ds.py | 95 +++++++++++++++---- 2 files changed, 76 insertions(+), 21 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 3f2eb299094..11e7d27654c 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -3042,7 +3042,7 @@ REFERENCES: for morphisms of PN. Mathematics of Computation, 84:291 (2015), 289-308. .. [Hutz2019] \B. Hutz. Multipliers and invariants of endomorphisms of projective - space in dimension greater than 1 + space in dimension greater than 1, :arxiv:`1908.03184`, 2019. .. [Huy2005] \D. Huybrechts : *Complex Geometry*, Springer (Berlin) (2005). diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 5fa3ba31b05..43211194272 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4595,30 +4595,70 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', OUTPUT: a list of elements in the base ring, unless ``return_polynomial`` is ``True``, in which case a polynomial in ``w`` and ``t`` is returned. + If this map is defined over `\mathbb{P}^N`, where `N > 1`, then + the first element of the list is the degree of the polynomial in `w` and + the second element is the degree of the polynomial in `t`. The rest of the + list are the coefficients of `w` and `t`, in lexographical order with `w > t`. + EXAMPLES:: - sage: P. = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([512*x^5 - 378128*x^4*y + 76594292*x^3*y^2 - 4570550136*x^2*y^3 - 2630045017*x*y^4\ - + 28193217129*y^5, 512*y^5]) + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([x^2 + x*y + y^2, y^2 + x*y]) sage: f.sigma_invariants(1) - [19575526074450617/1048576, -9078122048145044298567432325/2147483648, - -2622661114909099878224381377917540931367/1099511627776, - -2622661107937102104196133701280271632423/549755813888, - 338523204830161116503153209450763500631714178825448006778305/72057594037927936, 0] + [3, 3, 1] - :: + If ``return_polynomial`` is ``True``, then following [Hutz2019]_ + we return a two variable polynomial in `w` and `t`:: - sage: P. = ProjectiveSpace(QQ,1) + sage: P. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([x^2 + 2*y^2, y^2]) sage: poly = f.sigma_invariants(1, return_polynomial=True); poly w^3 - 3*w^2*t + 2*w^2 + 3*w*t^2 - 4*w*t + 8*w - t^3 + 2*t^2 - 8*t - From the full polynomial, we can easily get the one variable polynomial whose coefficients - are symmetric functions in the multipliers:: + From the full polynomial, we can easily recover the one variable polynomial whose coefficients + are symmetric functions in the multipliers, up to sign:: + + sage: w, t = poly.variables() + sage: poly.specialization({w:0}).monic() + t^3 - 2*t^2 + 8*t + sage: f.sigma_invariants(1) + [2, 8, 0] + + For dynamical systems on `\mathbb{P}^N`, where `N > 1`, the full polynomial + is needed to distinguish the conjugacy class. We can, however, still return + a list in this case. Here, the first element of the list is the degree in `w` and + the second element is the degree in `t`. The rest of the list are the coefficients + of the polynomial, sorted in lexographical order with `w > t`:: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: f = DynamicalSystem_projective([x^2, z^2, y^2]) + sage: f.sigma_invariants(1) + [3, 6, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -3, -2, 4, 0, + 0, 3, 4, -8, -8, 0, -1, -2, 4, 8, 0, 0, 0] + + When calculating the sigma invariants for `\mathbb{P}^N`, with `N > 1`, + the default algorithm loses information about multiplicities. Note that + the following call to sigma invariants returns a degree 6 polynomial in `w`:: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) + sage: f.sigma_invariants(1, return_polynomial=True) + w^6 - 6*w^5*t^2 + 8*w^5*t - 4*w^5 + 15*w^4*t^4 - 40*w^4*t^3 + 40*w^4*t^2 - + 16*w^4*t - 20*w^3*t^6 + 80*w^3*t^5 - 120*w^3*t^4 + 80*w^3*t^3 - 16*w^3*t^2 + + 15*w^2*t^8 - 80*w^2*t^7 + 160*w^2*t^6 - 144*w^2*t^5 + 48*w^2*t^4 - 6*w*t^10 + + 40*w*t^9 - 100*w*t^8 + 112*w*t^7 - 48*w*t^6 + t^12 - 8*t^11 + 24*t^10 - + 32*t^9 + 16*t^8 - sage: w, t = poly.variabls() - sage: poly.subs({w:0}) - -t^3 + 2*t^2 - 8*t + Setting ``chow`` to ``True``, while much slower, accounts correctly for multiplicities. + Note that the following returns a degree 7 polynomial in `w`:: + + sage: f.sigma_invariants(1, return_polynomial=True, chow=True) + w^7 - 7*w^6*t^2 + 10*w^6*t - 4*w^6 + 21*w^5*t^4 - 60*w^5*t^3 + 60*w^5*t^2 - + 24*w^5*t - 35*w^4*t^6 + 150*w^4*t^5 - 240*w^4*t^4 + 176*w^4*t^3 - 48*w^4*t^2 + + 35*w^3*t^8 - 200*w^3*t^7 + 440*w^3*t^6 - 464*w^3*t^5 + 224*w^3*t^4 - + 32*w^3*t^3 - 21*w^2*t^10 + 150*w^2*t^9 - 420*w^2*t^8 + 576*w^2*t^7 - + 384*w^2*t^6 + 96*w^2*t^5 + 7*w*t^12 - 60*w*t^11 + 204*w*t^10 - 344*w*t^9 + + 288*w*t^8 - 96*w*t^7 - t^14 + 10*t^13 - 40*t^12 + 80*t^11 - 80*t^10 + 32*t^9 :: @@ -4681,10 +4721,14 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', :: - sage: P. = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2 + x*y + y^2, y^2 + x*y]) + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([512*x^5 - 378128*x^4*y + 76594292*x^3*y^2 - 4570550136*x^2*y^3 - 2630045017*x*y^4\ + + 28193217129*y^5, 512*y^5]) sage: f.sigma_invariants(1) - [3, 3, 1] + [19575526074450617/1048576, -9078122048145044298567432325/2147483648, + -2622661114909099878224381377917540931367/1099511627776, + -2622661107937102104196133701280271632423/549755813888, + 338523204830161116503153209450763500631714178825448006778305/72057594037927936, 0] :: @@ -4719,6 +4763,15 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sage: f = DynamicalSystem_projective([x^2 + (t/(t^2+1))*y^2, y^2], P) sage: f.sigma_invariants(1) [2, 4*t/(t^2 + 1), 0] + + :: + + sage: R. = QQ[] + sage: N. = NumberField(w^2 + 1) + sage: P. = ProjectiveSpace(N, 2) + sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) + sage: f.sigma_invariants(1) == f.change_ring(QQ).sigma_invariants(1) + True """ n = ZZ(n) if n < 1: @@ -4788,9 +4841,11 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', return sigma_polynomial sigmas = [] sigma_dictionary = dict([list(reversed(i)) for i in list(sigma_polynomial)]) - degree = sigma_polynomial.degree() - for i in range(degree, -1, -1): - for j in range(degree-j, -1, -1): + degree_w, degree_t = sigma_polynomial.degrees() + w, t = sigma_polynomial.variables() + sigmas += [degree_w, degree_t] + for i in range(degree_w, -1, -1): + for j in range(degree_t, -1, -1): sigmas.append(sigma_dictionary.pop(w**i*t**j, 0)) return sigmas if not type in ['point', 'cycle']: From 1a5a601ce0791605d4535e38aac0757a737cca69 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 30 Jun 2021 14:01:51 -0400 Subject: [PATCH 006/511] 31994: removed duplicate example --- .../dynamics/arithmetic_dynamics/projective_ds.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 43211194272..9fab7208f9d 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4685,18 +4685,6 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sage: f.sigma_invariants(2, type='point', formal=True) [0, 0] - :: - - sage: P. = ProjectiveSpace(QQ, 2) - sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) - sage: f.sigma_invariants(1, return_polynomial=True, chow=True) - w^7 - 7*w^6*t^2 + 10*w^6*t - 4*w^6 + 21*w^5*t^4 - 60*w^5*t^3 + 60*w^5*t^2 - - 24*w^5*t - 35*w^4*t^6 + 150*w^4*t^5 - 240*w^4*t^4 + 176*w^4*t^3 - 48*w^4*t^2 - + 35*w^3*t^8 - 200*w^3*t^7 + 440*w^3*t^6 - 464*w^3*t^5 + 224*w^3*t^4 - 32*w^3*t^3 - - 21*w^2*t^10 + 150*w^2*t^9 - 420*w^2*t^8 + 576*w^2*t^7 - 384*w^2*t^6 + 96*w^2*t^5 - + 7*w*t^12 - 60*w*t^11 + 204*w*t^10 - 344*w*t^9 + 288*w*t^8 - 96*w*t^7 - t^14 + - 10*t^13 - 40*t^12 + 80*t^11 - 80*t^10 + 32*t^9 - :: sage: P. = ProjectiveSpace(QQ, 3) From 89a417d19a8402e51465167def9712505e088f58 Mon Sep 17 00:00:00 2001 From: bhutz Date: Tue, 6 Jul 2021 12:15:40 -0500 Subject: [PATCH 007/511] 31994 - added some comments to code --- .../arithmetic_dynamics/projective_ds.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 1e97b485cce..3389423177b 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -53,6 +53,7 @@ class initialization directly. # **************************************************************************** from sage.arith.misc import is_prime +from sage.calculus.functions import jacobian from sage.categories.fields import Fields from sage.categories.function_fields import FunctionFields from sage.categories.number_fields import NumberFields @@ -4635,6 +4636,8 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', OUTPUT: a list of elements in the base ring, unless ``return_polynomial`` is ``True``, in which case a polynomial in ``w`` and ``t`` is returned. + The variable ``t`` is the variable of the characteristic + polynomials of the multipliers. If this map is defined over `\mathbb{P}^N`, where `N > 1`, then the first element of the list is the degree of the polynomial in `w` and @@ -4814,7 +4817,6 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', if self.degree() <= 1: raise TypeError("must have degree at least 2") if dom.dimension_relative() > 1 or return_polynomial: - from sage.calculus.functions import jacobian d = self.degree() N = dom.dimension_relative() Fn = self.nth_iterate_map(n) @@ -4822,10 +4824,13 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', X = Fn.periodic_points(1, minimal=False, formal=formal, return_scheme=True) newR = PolynomialRing(base_ring, 'w, t', 2, order='lex') if chow: + # create full polynomial ring R = PolynomialRing(base_ring, 'v', N+N+3, order='lex') var = list(R.gens()) + # create polynomial ring for result R2 = PolynomialRing(base_ring, var[:N] + var[-2:]) psi = R2.hom(N*[0]+list(newR.gens()), newR) + # create substition to set extra variables to 0 R_zero = {R.gen(N):1} for j in range(N+1, N+N+1): R_zero[R.gen(j)] = 0 @@ -4839,26 +4844,37 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', t = var.pop() w = var.pop() sigma_polynomial = 1 + # go through each affine patch to avoid repeating periodic points + # setting the visited coordiantes to 0 as we go for j in range(N,-1,-1): Xa = X.affine_patch(j) fa = Fn.dehomogenize(j) Pa = fa.domain() Ra = Pa.coordinate_ring() + # create the images for the Hom to the ring we will do the elimination over + # with done affine patch coordinates as 0 if chow: im = [R.gen(i) for i in range(j)] + (N-j)*[0] + [R.gen(i) for i in range(N, R.ngens())] else: im = list(R.gens())[:j] + (N-j)*[0] + [R.gen(i) for i in range(N, R.ngens())] phi = Ra.hom(Ra.gens(), R) + # create polymomial that evaluates to the characteristic polynomial M = t*matrix.identity(R, N) g = (M-jacobian([phi(F.numerator())/phi(F.denominator()) for F in fa], var)).det() + # create the terms of the sigma invariants prod(w-lambda) g_prime = w*R(g.denominator())(im)-R(g.numerator())(im) + # move the defining polynomials to the polynomial ring L = [phi(h)(im) for h in Xa.defining_polynomials()] + # add the appropriate final polynomial to compute the sigma invariant polynomial + # via a Poisson product in elimination if chow: L += [g_prime + sum(R.gen(j-1)*R.gen(N+j)*(R(g.denominator())(im)) for j in range(1,N+1))] else: L += [g_prime] I = R.ideal(L) + # since R is lex ordering, this is an elimination step G = I.groebner_basis() + # the polynomial we need is the one just in w and t if chow: poly = psi(G[-1].specialization(R_zero)) if len(list(poly)) > 0: @@ -4868,6 +4884,8 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sigma_polynomial *= psi(G[-1]) if return_polynomial: return sigma_polynomial + # if we are returing a numerical list, read off the coefficients + # in order of degree adjusting sign appropriately sigmas = [] sigma_dictionary = dict([list(reversed(i)) for i in list(sigma_polynomial)]) degree_w, degree_t = sigma_polynomial.degrees() From 2be2b66071cf5744d87ee178158748ddb71a9073 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 6 Jul 2021 18:31:29 -0400 Subject: [PATCH 008/511] 31994: added flattening --- .../arithmetic_dynamics/projective_ds.py | 72 ++++++++++++++----- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 34f97366328..dc3f0934826 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4634,7 +4634,8 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', - ``type`` -- (default: ``'point'``) string; either ``'point'`` or ``'cycle'`` depending on whether you compute with one - multiplier per point or one per cycle + multiplier per point or one per cycle. Not implemented for + dimension greater than 1. - ``return polynomial`` -- (default: ``False``) boolean; ``True`` specifies returning the polynomial which generates @@ -4691,8 +4692,8 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sage: P. = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem_projective([x^2, z^2, y^2]) sage: f.sigma_invariants(1) - [3, 6, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -3, -2, 4, 0, - 0, 3, 4, -8, -8, 0, -1, -2, 4, 8, 0, 0, 0] + [3, 6, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3, -2, -4, 0, 0, 3, -4, -8, 8, 0, + 1, -2, -4, 8, 0, 0, 0] When calculating the sigma invariants for `\mathbb{P}^N`, with `N > 1`, the default algorithm loses information about multiplicities. Note that @@ -4830,33 +4831,61 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', deprecation(23333, "embedding keyword no longer used") if self.degree() <= 1: raise TypeError("must have degree at least 2") + if not type in ['point', 'cycle']: + raise ValueError("type must be either point or cycle") if dom.dimension_relative() > 1 or return_polynomial: + if type == 'cycle': + raise NotImplementedError('cycle not implemented for dimension greater than 1') + base_ring = self.base_ring() + if isinstance(base_ring, FractionField_1poly_field) or is_FunctionField(base_ring): + raise NotImplementedError('Sigma invariants not implemented for fraction function fields.' + + 'Clear denominators and use the polynomial ring instead.') d = self.degree() N = dom.dimension_relative() Fn = self.nth_iterate_map(n) - base_ring = self.base_ring() - X = Fn.periodic_points(1, minimal=False, formal=formal, return_scheme=True) - newR = PolynomialRing(base_ring, 'w, t', 2, order='lex') + if not base_ring.is_field(): + F = FractionField(base_ring) + Fn.normalize_coordinates() + X = Fn.change_ring(base_ring).periodic_points(1, minimal=False, formal=formal, return_scheme=True) + X = X.change_ring(F) + else: + F = base_ring + X = Fn.periodic_points(1, minimal=False, formal=formal, return_scheme=True) + newR_unordered = PolynomialRing(base_ring, 'w, t', 2) + newR = newR_unordered.change_ring(order='lex') if chow: # create full polynomial ring - R = PolynomialRing(base_ring, 'v', N+N+3, order='lex') + R_unordered = PolynomialRing(base_ring, 'v', 2*N+3) + R = R_unordered.change_ring(order='lex') var = list(R.gens()) # create polynomial ring for result R2 = PolynomialRing(base_ring, var[:N] + var[-2:]) psi = R2.hom(N*[0]+list(newR.gens()), newR) # create substition to set extra variables to 0 R_zero = {R.gen(N):1} - for j in range(N+1, N+N+1): + for j in range(N+1, 2*N+1): R_zero[R.gen(j)] = 0 t = var.pop() w = var.pop() var = var[:N] else: - R = PolynomialRing(base_ring,'v', N+2, order='lex') - psi = R.hom(N*[0] + list(newR.gens()), newR) + R_unordered = PolynomialRing(base_ring, 'v', N+2) + R = R_unordered.change_ring(order='lex') + psi = R_unordered.hom(N*[0] + list(newR_unordered.gens()), newR_unordered) var = list(R.gens()) t = var.pop() w = var.pop() + if is_FractionField(F): + if is_PolynomialRing(F.ring()) or is_MPolynomialRing(F.ring()): + flat_phi = FlatteningMorphism(R) + flatR_unordered = flat_phi.codomain() + Id = matrix.identity(len(flatR_unordered.gens()) - len(F.gens())) + Id2 = matrix.identity(len(F.gens())) + from sage.matrix.special import block_matrix + b = block_matrix([[ZZ(0), Id],[Id2, ZZ(0)]]) + from sage.rings.polynomial.term_order import TermOrder + flatR = flatR_unordered.change_ring(order=TermOrder(b)) + unflat_phi = UnflatteningMorphism(flatR_unordered, R) sigma_polynomial = 1 # go through each affine patch to avoid repeating periodic points # setting the visited coordiantes to 0 as we go @@ -4871,7 +4900,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', im = [R.gen(i) for i in range(j)] + (N-j)*[0] + [R.gen(i) for i in range(N, R.ngens())] else: im = list(R.gens())[:j] + (N-j)*[0] + [R.gen(i) for i in range(N, R.ngens())] - phi = Ra.hom(Ra.gens(), R) + phi = Ra.hom(R.gens()[0:len(Ra.gens())]) # create polymomial that evaluates to the characteristic polynomial M = t*matrix.identity(R, N) g = (M-jacobian([phi(F.numerator())/phi(F.denominator()) for F in fa], var)).det() @@ -4886,16 +4915,25 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', else: L += [g_prime] I = R.ideal(L) + if is_FractionField(F): + I = flatR.ideal([flat_phi(poly) for poly in I.gens()]) # since R is lex ordering, this is an elimination step G = I.groebner_basis() # the polynomial we need is the one just in w and t if chow: - poly = psi(G[-1].specialization(R_zero)) + if is_FractionField(F): + unflattened = unflat_phi(G[-1]) + else: + unflattened = G[-1] + poly = psi(unflattened.specialization(R_zero)) if len(list(poly)) > 0: poly *= poly.coefficients()[0].inverse_of_unit() sigma_polynomial *= poly else: - sigma_polynomial *= psi(G[-1]) + if is_FractionField(F): + sigma_polynomial *= psi(unflat_phi(flatR_unordered(G[-1]))) + else: + sigma_polynomial *= psi(flatR_unordered(G[-1])) if return_polynomial: return sigma_polynomial # if we are returing a numerical list, read off the coefficients @@ -4905,12 +4943,10 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', degree_w, degree_t = sigma_polynomial.degrees() w, t = sigma_polynomial.variables() sigmas += [degree_w, degree_t] - for i in range(degree_w, -1, -1): - for j in range(degree_t, -1, -1): - sigmas.append(sigma_dictionary.pop(w**i*t**j, 0)) + for i in range(degree_w+1): + for j in range(degree_t+1): + sigmas.append((-1)**(i+j)*sigma_dictionary.pop(w**(degree_w - i)*t**(degree_t - j), 0)) return sigmas - if not type in ['point', 'cycle']: - raise ValueError("type must be either point or cycle") base_ring = dom.base_ring() if is_FractionField(base_ring): From a410756fc54563375e4b641ad1e90ccda70a1a74 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 6 Jul 2021 18:43:07 -0400 Subject: [PATCH 009/511] 31994: added support for fraction fields of polynomial rings --- .../dynamics/arithmetic_dynamics/projective_ds.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index ee6e70b90b6..827bf50ec1d 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4841,9 +4841,6 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', if type == 'cycle': raise NotImplementedError('cycle not implemented for dimension greater than 1') base_ring = self.base_ring() - if isinstance(base_ring, FractionField_1poly_field) or is_FunctionField(base_ring): - raise NotImplementedError('Sigma invariants not implemented for fraction function fields.' - + 'Clear denominators and use the polynomial ring instead.') d = self.degree() N = dom.dimension_relative() Fn = self.nth_iterate_map(n) @@ -4854,7 +4851,14 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', X = X.change_ring(F) else: F = base_ring - X = Fn.periodic_points(1, minimal=False, formal=formal, return_scheme=True) + if is_FractionField(base_ring): + if is_MPolynomialRing(base_ring.ring()) or is_PolynomialRing(base_ring.ring()): + Fn.normalize_coordinates() + Fn_ring = Fn.change_ring(base_ring.ring()) + X = Fn_ring.periodic_points(1, minimal=False, formal=formal, return_scheme=True) + X = X.change_ring(F) + else: + X = Fn.periodic_points(1, minimal=False, formal=formal, return_scheme=True) newR_unordered = PolynomialRing(base_ring, 'w, t', 2) newR = newR_unordered.change_ring(order='lex') if chow: From 97c33ffeb9fb050c63dc705d236343cda69967fc Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 7 Jul 2021 12:28:33 -0400 Subject: [PATCH 010/511] 31994: added examples, simpler code for polynomial rings --- .../arithmetic_dynamics/projective_ds.py | 69 ++++++++++--------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 827bf50ec1d..1f17c04cfd6 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4781,6 +4781,14 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', -2622661107937102104196133701280271632423/549755813888, 338523204830161116503153209450763500631714178825448006778305/72057594037927936, 0] + :: + + sage: P. = ProjectiveSpace(GF(5), 2) + sage: f = DynamicalSystem([x^2, y^2, z^2]) + sage: f.sigma_invariants(1, return_polynomial=True) + w^6 - w^5*t^2 - 2*w^5*t + w^5 - w^4*t - w^3*t^2 + w^2*t^5 - + 2*w^2*t^4 - w*t^10 + 2*w*t^7 + 2*w*t^6 + t^12 + 2*t^11 - t^10 - 2*t^9 + t^8 + :: sage: R. = QQ[] @@ -4793,6 +4801,24 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sage: f.sigma_invariants(2, formal=True, type='cycle') [4*c + 4] + :: + + sage: R. = QQ[] + sage: P. = ProjectiveSpace(R, 1) + sage: f = DynamicalSystem([x^2 + c*y^2, y^2]) + sage: f.sigma_invariants(1, return_polynomial=True) + w^3 + (-3)*w^2*t + 2*w^2 + 3*w*t^2 + (-4)*w*t + 4*c*w - t^3 + 2*t^2 + (-4*c)*t + sage: f.sigma_invariants(2, formal=True, return_polynomial=True) + w^2 + (-2)*w*t + (8*c + 8)*w + t^2 + (-8*c - 8)*t + 16*c^2 + 32*c + 16 + + :: + + sage: R. = QQ[] + sage: P. = ProjectiveSpace(R, 2) + sage: f = DynamicalSystem([x^2 + c*z^2, y^2 + d*z^2, z^2]) + sage: len(dict(f.sigma_invariants(1, return_polynomial=True))) + 51 + doubled fixed point:: sage: P. = ProjectiveSpace(QQ, 1) @@ -4847,7 +4873,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', if not base_ring.is_field(): F = FractionField(base_ring) Fn.normalize_coordinates() - X = Fn.change_ring(base_ring).periodic_points(1, minimal=False, formal=formal, return_scheme=True) + X = Fn.periodic_points(1, minimal=False, formal=formal, return_scheme=True) X = X.change_ring(F) else: F = base_ring @@ -4859,15 +4885,15 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', X = X.change_ring(F) else: X = Fn.periodic_points(1, minimal=False, formal=formal, return_scheme=True) - newR_unordered = PolynomialRing(base_ring, 'w, t', 2) - newR = newR_unordered.change_ring(order='lex') + newR = PolynomialRing(F, 'w, t', 2, order='lex') + if not base_ring.is_field(): + ringR = PolynomialRing(base_ring, 'w, t', 2, order='lex') if chow: # create full polynomial ring - R_unordered = PolynomialRing(base_ring, 'v', 2*N+3) - R = R_unordered.change_ring(order='lex') + R = PolynomialRing(F, 'v', 2*N+3, order='lex') var = list(R.gens()) # create polynomial ring for result - R2 = PolynomialRing(base_ring, var[:N] + var[-2:]) + R2 = PolynomialRing(F, var[:N] + var[-2:]) psi = R2.hom(N*[0]+list(newR.gens()), newR) # create substition to set extra variables to 0 R_zero = {R.gen(N):1} @@ -4877,23 +4903,11 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', w = var.pop() var = var[:N] else: - R_unordered = PolynomialRing(base_ring, 'v', N+2) - R = R_unordered.change_ring(order='lex') - psi = R_unordered.hom(N*[0] + list(newR_unordered.gens()), newR_unordered) + R = PolynomialRing(F, 'v', N+2, order='lex') + psi = R.hom(N*[0] + list(newR.gens()), newR) var = list(R.gens()) t = var.pop() w = var.pop() - if is_FractionField(F): - if is_PolynomialRing(F.ring()) or is_MPolynomialRing(F.ring()): - flat_phi = FlatteningMorphism(R) - flatR_unordered = flat_phi.codomain() - Id = matrix.identity(len(flatR_unordered.gens()) - len(F.gens())) - Id2 = matrix.identity(len(F.gens())) - from sage.matrix.special import block_matrix - b = block_matrix([[ZZ(0), Id],[Id2, ZZ(0)]]) - from sage.rings.polynomial.term_order import TermOrder - flatR = flatR_unordered.change_ring(order=TermOrder(b)) - unflat_phi = UnflatteningMorphism(flatR_unordered, R) sigma_polynomial = 1 # go through each affine patch to avoid repeating periodic points # setting the visited coordiantes to 0 as we go @@ -4923,25 +4937,18 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', else: L += [g_prime] I = R.ideal(L) - if is_FractionField(F): - I = flatR.ideal([flat_phi(poly) for poly in I.gens()]) # since R is lex ordering, this is an elimination step G = I.groebner_basis() # the polynomial we need is the one just in w and t if chow: - if is_FractionField(F): - unflattened = unflat_phi(G[-1]) - else: - unflattened = G[-1] - poly = psi(unflattened.specialization(R_zero)) + poly = psi(G[-1].specialization(R_zero)) if len(list(poly)) > 0: poly *= poly.coefficients()[0].inverse_of_unit() sigma_polynomial *= poly else: - if is_FractionField(F): - sigma_polynomial *= psi(unflat_phi(flatR_unordered(G[-1]))) - else: - sigma_polynomial *= psi(flatR_unordered(G[-1])) + sigma_polynomial *= psi(G[-1]) + if not base_ring.is_field(): + sigma_polynomial = ringR(sigma_polynomial) if return_polynomial: return sigma_polynomial # if we are returing a numerical list, read off the coefficients From d220330d79ea8b1a7e206e31e49989f1b189f03f Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 7 Jul 2021 12:33:47 -0400 Subject: [PATCH 011/511] 31994: fixed n > 1 --- .../arithmetic_dynamics/projective_ds.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 1f17c04cfd6..913d715529a 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4808,7 +4808,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sage: f = DynamicalSystem([x^2 + c*y^2, y^2]) sage: f.sigma_invariants(1, return_polynomial=True) w^3 + (-3)*w^2*t + 2*w^2 + 3*w*t^2 + (-4)*w*t + 4*c*w - t^3 + 2*t^2 + (-4*c)*t - sage: f.sigma_invariants(2, formal=True, return_polynomial=True) + sage: f.sigma_invariants(2, chow=True, formal=True, return_polynomial=True) w^2 + (-2)*w*t + (8*c + 8)*w + t^2 + (-8*c - 8)*t + 16*c^2 + 32*c + 16 :: @@ -4869,22 +4869,23 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', base_ring = self.base_ring() d = self.degree() N = dom.dimension_relative() - Fn = self.nth_iterate_map(n) + f = copy(self) + Fn = f.nth_iterate_map(n) if not base_ring.is_field(): F = FractionField(base_ring) - Fn.normalize_coordinates() - X = Fn.periodic_points(1, minimal=False, formal=formal, return_scheme=True) + f.normalize_coordinates() + X = f.periodic_points(n, minimal=False, formal=formal, return_scheme=True) X = X.change_ring(F) else: F = base_ring if is_FractionField(base_ring): if is_MPolynomialRing(base_ring.ring()) or is_PolynomialRing(base_ring.ring()): - Fn.normalize_coordinates() - Fn_ring = Fn.change_ring(base_ring.ring()) - X = Fn_ring.periodic_points(1, minimal=False, formal=formal, return_scheme=True) + f.normalize_coordinates() + f_ring = f.change_ring(base_ring.ring()) + X = f_ring.periodic_points(n, minimal=False, formal=formal, return_scheme=True) X = X.change_ring(F) else: - X = Fn.periodic_points(1, minimal=False, formal=formal, return_scheme=True) + X = f.periodic_points(n, minimal=False, formal=formal, return_scheme=True) newR = PolynomialRing(F, 'w, t', 2, order='lex') if not base_ring.is_field(): ringR = PolynomialRing(base_ring, 'w, t', 2, order='lex') From c5277f2c0647b3254381ec312ec6c0ec65c85be8 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 7 Jul 2021 13:29:40 -0400 Subject: [PATCH 012/511] 32155: initial commit with method and documentation --- .../schemes/projective/projective_space.py | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 5327aebe5b7..1d5988e2470 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -79,6 +79,7 @@ # http://www.gnu.org/licenses/ # **************************************************************************** +from typing import Type from sage.arith.all import gcd, binomial, srange from sage.rings.all import (PolynomialRing, Integer, @@ -1300,6 +1301,80 @@ def veronese_embedding(self, d, CS=None, order='lex'): monomials.reverse() # order the monomials greatest to least via the given monomial order return Hom(self, CS)(monomials) + def is_linearly_independent(self, points): + r""" + Return whether the set of points is linearly independent. + + INPUT: + + - ``points`` -- a list points of this projective space. + + OUTPUT: + + - ``True`` if ``points`` is linearly independent, ``False`` otherwise. + + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: points = [P((1, 0)), P((1, 1)), P((2, 1))] + sage: P.is_linearly_independent(points) + True + + :: + + sage: P. = ProjectiveSpace(ZZ, 2) + sage: points = [P((1, 0, 1)), P((1, 2, 1)), P((1, 3, 4))] + sage: P.is_linearly_independent(points) + True + + :: + + sage: P. = ProjectiveSpace(GF(5), 2) + sage: points = [P((1, 0, 1)), P((1, 2, 1)), P((1, 3, 4)), P((0, 0 ,1))] + sage: P.is_linearly_independent(points) + True + + :: + + sage: R. = QQ[] + sage: P. = ProjectiveSpace(R, 2) + sage: points = [P((c, 0, 1)), P((0, c, 1)), P((1, 0, 4)), P((0, 0 ,1))] + sage: P.is_linearly_independent(points) + False + + :: + + sage: R. = QQ[] + sage: P. = ProjectiveSpace(FractionField(R), 2) + sage: points = [P((c, 0, 1)), P((0, c, 1)), P((1, 3, 4)), P((0, 0 ,1))] + sage: P.is_linearly_independent(points) + True + + :: + + sage: K. = CyclotomicField(3) + sage: P. = ProjectiveSpace(K, 2) + sage: points = [P((k, k^2, 1)), P((0, k, 1)), P((1, 0, 4)), P((0, 0 ,1))] + sage: P.is_linearly_independent(points) + True + """ + if not isinstance(points, list): + raise TypeError("points must be a list") + if any(not isinstance(point, SchemeMorphism_point_projective_ring) for point in points): + raise TypeError("points must be a list of projective points") + if any(x.codomain() != self for x in points): + raise ValueError("points not in this projective space") + M = matrix([list(t) for t in points]) + N = self.dimension_relative() + if len(points) < N+1: + if M.rank() == len(points): + return True + return False + elif len(points) < N+3: + if any(l == 0 for l in M.minors(N+1)): + return False + return True + return False class ProjectiveSpace_field(ProjectiveSpace_ring): def _point_homset(self, *args, **kwds): From 6897aa406532c104b39ab4b6655f61df58834b4c Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 8 Jul 2021 13:07:01 -0400 Subject: [PATCH 013/511] 32155: updated parameter --- .../schemes/projective/projective_space.py | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 1d5988e2470..2a2d64511ad 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -1301,13 +1301,19 @@ def veronese_embedding(self, d, CS=None, order='lex'): monomials.reverse() # order the monomials greatest to least via the given monomial order return Hom(self, CS)(monomials) - def is_linearly_independent(self, points): + def is_linearly_independent(self, points, n=None): r""" Return whether the set of points is linearly independent. + Alternatively, specify ``n`` to check if every subset of + size ``n`` is linearly independent. + INPUT: - - ``points`` -- a list points of this projective space. + - ``points`` -- a list of points in this projective space. + + - ``n`` -- (Optional) An integer. Specifies the size of the subsets to + check for linear independence. OUTPUT: @@ -1316,7 +1322,7 @@ def is_linearly_independent(self, points): EXAMPLES:: sage: P. = ProjectiveSpace(QQ, 1) - sage: points = [P((1, 0)), P((1, 1)), P((2, 1))] + sage: points = [P((1, 0)), P((1, 1))] sage: P.is_linearly_independent(points) True @@ -1331,7 +1337,7 @@ def is_linearly_independent(self, points): sage: P. = ProjectiveSpace(GF(5), 2) sage: points = [P((1, 0, 1)), P((1, 2, 1)), P((1, 3, 4)), P((0, 0 ,1))] - sage: P.is_linearly_independent(points) + sage: P.is_linearly_independent(points, 3) True :: @@ -1339,7 +1345,7 @@ def is_linearly_independent(self, points): sage: R. = QQ[] sage: P. = ProjectiveSpace(R, 2) sage: points = [P((c, 0, 1)), P((0, c, 1)), P((1, 0, 4)), P((0, 0 ,1))] - sage: P.is_linearly_independent(points) + sage: P.is_linearly_independent(points, 3) False :: @@ -1347,7 +1353,7 @@ def is_linearly_independent(self, points): sage: R. = QQ[] sage: P. = ProjectiveSpace(FractionField(R), 2) sage: points = [P((c, 0, 1)), P((0, c, 1)), P((1, 3, 4)), P((0, 0 ,1))] - sage: P.is_linearly_independent(points) + sage: P.is_linearly_independent(points, 3) True :: @@ -1355,7 +1361,7 @@ def is_linearly_independent(self, points): sage: K. = CyclotomicField(3) sage: P. = ProjectiveSpace(K, 2) sage: points = [P((k, k^2, 1)), P((0, k, 1)), P((1, 0, 4)), P((0, 0 ,1))] - sage: P.is_linearly_independent(points) + sage: P.is_linearly_independent(points, 3) True """ if not isinstance(points, list): @@ -1364,17 +1370,17 @@ def is_linearly_independent(self, points): raise TypeError("points must be a list of projective points") if any(x.codomain() != self for x in points): raise ValueError("points not in this projective space") + if not n is None: + n = Integer(n) M = matrix([list(t) for t in points]) N = self.dimension_relative() - if len(points) < N+1: + if len(points) < n or n == None: if M.rank() == len(points): return True return False - elif len(points) < N+3: - if any(l == 0 for l in M.minors(N+1)): - return False - return True - return False + if any(l == 0 for l in M.minors(n)): + return False + return True class ProjectiveSpace_field(ProjectiveSpace_ring): def _point_homset(self, *args, **kwds): From a5b8913dcf63a1ebabef0994452b16473dc66231 Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Thu, 8 Jul 2021 14:13:41 -0400 Subject: [PATCH 014/511] 32155: fixed check for independence --- .../schemes/projective/projective_space.py | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 2a2d64511ad..3ffada5e995 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -107,6 +107,7 @@ from sage.combinat.permutation import Permutation from sage.combinat.tuple import Tuples from sage.combinat.tuple import UnorderedTuples +from sage.combinat.subset import Subsets from sage.matrix.constructor import matrix from sage.modules.free_module_element import prepare from sage.schemes.generic.ambient_space import AmbientSpace @@ -1337,7 +1338,7 @@ def is_linearly_independent(self, points, n=None): sage: P. = ProjectiveSpace(GF(5), 2) sage: points = [P((1, 0, 1)), P((1, 2, 1)), P((1, 3, 4)), P((0, 0 ,1))] - sage: P.is_linearly_independent(points, 3) + sage: P.is_linearly_independent(points, 2) True :: @@ -1370,17 +1371,22 @@ def is_linearly_independent(self, points, n=None): raise TypeError("points must be a list of projective points") if any(x.codomain() != self for x in points): raise ValueError("points not in this projective space") - if not n is None: - n = Integer(n) - M = matrix([list(t) for t in points]) + if n is None: + M = matrix([list(t) for t in points]) + return M.rank() == len(points) + n = Integer(n) N = self.dimension_relative() - if len(points) < n or n == None: - if M.rank() == len(points): - return True - return False - if any(l == 0 for l in M.minors(n)): - return False - return True + all_subsets = Subsets(range(len(points)), n) + linearly_independent = True + for subset in all_subsets: + point_list = [] + for index in subset: + point_list.append(list(points[index])) + M = matrix(point_list) + if M.rank() != n: + linearly_independent = False + break + return linearly_independent class ProjectiveSpace_field(ProjectiveSpace_ring): def _point_homset(self, *args, **kwds): From 533213c9d6924ed009053b752e189652c055af9b Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Thu, 8 Jul 2021 14:39:09 -0400 Subject: [PATCH 015/511] 32155: added check on n --- src/sage/schemes/projective/projective_space.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 3ffada5e995..70e8f31ad6b 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -1313,8 +1313,9 @@ def is_linearly_independent(self, points, n=None): - ``points`` -- a list of points in this projective space. - - ``n`` -- (Optional) An integer. Specifies the size of the subsets to - check for linear independence. + - ``n`` -- (Optional) A positive integer less than or equal to the length + of ``points``. Specifies the size of the subsets to check for + linear independence. OUTPUT: @@ -1364,6 +1365,15 @@ def is_linearly_independent(self, points, n=None): sage: points = [P((k, k^2, 1)), P((0, k, 1)), P((1, 0, 4)), P((0, 0 ,1))] sage: P.is_linearly_independent(points, 3) True + + TESTS:: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: points = [P(1, 0), P(1, 1), P(2, 1)] + sage: P.is_linearly_independent(points, 5) + Traceback (most recent call last): + ... + ValueError: n must be a non negative integer not greater than the length of points """ if not isinstance(points, list): raise TypeError("points must be a list") @@ -1375,7 +1385,8 @@ def is_linearly_independent(self, points, n=None): M = matrix([list(t) for t in points]) return M.rank() == len(points) n = Integer(n) - N = self.dimension_relative() + if n < 1 or n > len(points): + raise ValueError('n must be a non negative integer not greater than the length of points') all_subsets = Subsets(range(len(points)), n) linearly_independent = True for subset in all_subsets: From 008d6db1a72761b7bb6f5164410685e3b5582a4d Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 9 Jul 2021 15:37:03 -0400 Subject: [PATCH 016/511] 31994: added deformation --- .../arithmetic_dynamics/projective_ds.py | 202 +++++++++++------- 1 file changed, 122 insertions(+), 80 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 3ca1814764a..c0d54ca16e4 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4727,7 +4727,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur return multipliers def sigma_invariants(self, n, formal=False, embedding=None, type='point', - return_polynomial=False, chow=False): + return_polynomial=False, chow=False, deform=False, check=True): r""" Computes the values of the elementary symmetric polynomials of the ``n`` multiplier spectra of this dynamical system. @@ -4790,8 +4790,26 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', - ``chow`` -- (default: ``False``) boolean; ``True`` specifies using the Chow algorithm from [Hutz2019]_ to compute the sigma invariants. While slower, the Chow algorithm does not lose - information about multiplicities. Helpful when this map has - repeated multipliers or fixed points with high multiplicity. + information about multiplicities of the multipliers. In order + to accurately compute the sigma polynomial when there is a + repeated multiplier, ``chow`` must be ``True``. + + - ``deform`` -- (default: ``False``) boolean; ``True`` specifies + first deforming the map so that all periodic points are distinct + and then calculating the sigma invariants. In order to accurately + calculate the sigma polynomial when there is a periodic point with + multiplicity, ``deform`` must be ``True``. + + - ``check`` -- (default: ``True``) boolean; when ``True`` the degree of + the sigma polynomial is checked against the expected degree. This is + done as the sigma polynomial may drop degree if multiplicites of periodic + points or multipliers are not correctly accounted for using ``chow`` or + ``deform``. + + .. WARNING:: + + Setting ``check`` to ``False`` can lead to mathematically incorrect + answers. OUTPUT: a list of elements in the base ring, unless ``return_polynomial`` is ``True``, in which case a polynomial in ``w`` and ``t`` is returned. @@ -4799,9 +4817,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', polynomials of the multipliers. If this map is defined over `\mathbb{P}^N`, where `N > 1`, then - the first element of the list is the degree of the polynomial in `w` and - the second element is the degree of the polynomial in `t`. The rest of the - list are the coefficients of `w` and `t`, in lexographical order with `w > t`. + the list is the coefficients of `w` and `t`, in lexographical order with `w > t`. EXAMPLES:: @@ -5011,85 +5027,112 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', N = dom.dimension_relative() f = copy(self) Fn = f.nth_iterate_map(n) - if not base_ring.is_field(): - F = FractionField(base_ring) - f.normalize_coordinates() - X = f.periodic_points(n, minimal=False, formal=formal, return_scheme=True) - X = X.change_ring(F) + if deform: + # we need a model with all affine periodic points + new_f = f.affine_preperiodic_model(0, n) + new_f.normalize_coordinates() + # we now deform by a parameter t + T = base_ring['k'] + k = T.gens()[0] + Pt = ProjectiveSpace(N, R=T, names = [str(i) for i in CR.gens()]) + deformed_polys = [poly + k*Pt.gens()[-1]**d for poly in new_f.defining_polynomials()[:-1]] + deformed_polys += [new_f.defining_polynomials()[-1]] + f_deformed = DynamicalSystem(deformed_polys) + sigma_poly = sigma(f_deformed, n, chow=chow, deform=False, return_polynomial=True) + sigma_polynomial = sigma_poly.specialization({k:0}) + # we fix the ordering of the parent polynomial ring + new_parent = sigma_polynomial.parent().change_ring(order='lex') + sigma_polynomial = new_parent(sigma_polynomial) + sigma_polynomial *= sigma_polynomial.coefficients()[0].inverse_of_unit() else: - F = base_ring - if is_FractionField(base_ring): - if is_MPolynomialRing(base_ring.ring()) or is_PolynomialRing(base_ring.ring()): - f.normalize_coordinates() - f_ring = f.change_ring(base_ring.ring()) - X = f_ring.periodic_points(n, minimal=False, formal=formal, return_scheme=True) - X = X.change_ring(F) - else: + if not base_ring.is_field(): + F = FractionField(base_ring) + f.normalize_coordinates() X = f.periodic_points(n, minimal=False, formal=formal, return_scheme=True) - newR = PolynomialRing(F, 'w, t', 2, order='lex') - if not base_ring.is_field(): - ringR = PolynomialRing(base_ring, 'w, t', 2, order='lex') - if chow: - # create full polynomial ring - R = PolynomialRing(F, 'v', 2*N+3, order='lex') - var = list(R.gens()) - # create polynomial ring for result - R2 = PolynomialRing(F, var[:N] + var[-2:]) - psi = R2.hom(N*[0]+list(newR.gens()), newR) - # create substition to set extra variables to 0 - R_zero = {R.gen(N):1} - for j in range(N+1, 2*N+1): - R_zero[R.gen(j)] = 0 - t = var.pop() - w = var.pop() - var = var[:N] - else: - R = PolynomialRing(F, 'v', N+2, order='lex') - psi = R.hom(N*[0] + list(newR.gens()), newR) - var = list(R.gens()) - t = var.pop() - w = var.pop() - sigma_polynomial = 1 - # go through each affine patch to avoid repeating periodic points - # setting the visited coordiantes to 0 as we go - for j in range(N,-1,-1): - Xa = X.affine_patch(j) - fa = Fn.dehomogenize(j) - Pa = fa.domain() - Ra = Pa.coordinate_ring() - # create the images for the Hom to the ring we will do the elimination over - # with done affine patch coordinates as 0 - if chow: - im = [R.gen(i) for i in range(j)] + (N-j)*[0] + [R.gen(i) for i in range(N, R.ngens())] + X = X.change_ring(F) else: - im = list(R.gens())[:j] + (N-j)*[0] + [R.gen(i) for i in range(N, R.ngens())] - phi = Ra.hom(R.gens()[0:len(Ra.gens())]) - # create polymomial that evaluates to the characteristic polynomial - M = t*matrix.identity(R, N) - g = (M-jacobian([phi(F.numerator())/phi(F.denominator()) for F in fa], var)).det() - # create the terms of the sigma invariants prod(w-lambda) - g_prime = w*R(g.denominator())(im)-R(g.numerator())(im) - # move the defining polynomials to the polynomial ring - L = [phi(h)(im) for h in Xa.defining_polynomials()] - # add the appropriate final polynomial to compute the sigma invariant polynomial - # via a Poisson product in elimination + F = base_ring + if is_FractionField(base_ring): + if is_MPolynomialRing(base_ring.ring()) or is_PolynomialRing(base_ring.ring()): + f.normalize_coordinates() + f_ring = f.change_ring(base_ring.ring()) + X = f_ring.periodic_points(n, minimal=False, formal=formal, return_scheme=True) + X = X.change_ring(F) + else: + X = f.periodic_points(n, minimal=False, formal=formal, return_scheme=True) + newR = PolynomialRing(F, 'w, t', 2, order='lex') + if not base_ring.is_field(): + ringR = PolynomialRing(base_ring, 'w, t', 2, order='lex') if chow: - L += [g_prime + sum(R.gen(j-1)*R.gen(N+j)*(R(g.denominator())(im)) for j in range(1,N+1))] + # create full polynomial ring + R = PolynomialRing(F, 'v', 2*N+3, order='lex') + var = list(R.gens()) + # create polynomial ring for result + R2 = PolynomialRing(F, var[:N] + var[-2:]) + psi = R2.hom(N*[0]+list(newR.gens()), newR) + # create substition to set extra variables to 0 + R_zero = {R.gen(N):1} + for j in range(N+1, 2*N+1): + R_zero[R.gen(j)] = 0 + t = var.pop() + w = var.pop() + var = var[:N] else: - L += [g_prime] - I = R.ideal(L) - # since R is lex ordering, this is an elimination step - G = I.groebner_basis() - # the polynomial we need is the one just in w and t - if chow: - poly = psi(G[-1].specialization(R_zero)) - if len(list(poly)) > 0: - poly *= poly.coefficients()[0].inverse_of_unit() + R = PolynomialRing(F, 'v', N+2, order='lex') + psi = R.hom(N*[0] + list(newR.gens()), newR) + var = list(R.gens()) + t = var.pop() + w = var.pop() + sigma_polynomial = 1 + # go through each affine patch to avoid repeating periodic points + # setting the visited coordiantes to 0 as we go + for j in range(N,-1,-1): + Xa = X.affine_patch(j) + fa = Fn.dehomogenize(j) + Pa = fa.domain() + Ra = Pa.coordinate_ring() + # create the images for the Hom to the ring we will do the elimination over + # with done affine patch coordinates as 0 + if chow: + im = [R.gen(i) for i in range(j)] + (N-j)*[0] + [R.gen(i) for i in range(N, R.ngens())] + else: + im = list(R.gens())[:j] + (N-j)*[0] + [R.gen(i) for i in range(N, R.ngens())] + phi = Ra.hom(R.gens()[0:len(Ra.gens())]) + # create polymomial that evaluates to the characteristic polynomial + M = t*matrix.identity(R, N) + g = (M-jacobian([phi(F.numerator())/phi(F.denominator()) for F in fa], var)).det() + # create the terms of the sigma invariants prod(w-lambda) + g_prime = w*R(g.denominator())(im)-R(g.numerator())(im) + # move the defining polynomials to the polynomial ring + L = [phi(h)(im) for h in Xa.defining_polynomials()] + # add the appropriate final polynomial to compute the sigma invariant polynomial + # via a Poisson product in elimination + if chow: + L += [g_prime + sum(R.gen(j-1)*R.gen(N+j)*(R(g.denominator())(im)) for j in range(1,N+1))] + else: + L += [g_prime] + I = R.ideal(L) + # since R is lex ordering, this is an elimination step + G = I.groebner_basis() + # the polynomial we need is the one just in w and t + if chow: + poly = psi(G[-1].specialization(R_zero)) + if len(list(poly)) > 0: + poly *= poly.coefficients()[0].inverse_of_unit() + else: + poly = psi(G[-1]) + if not base_ring.is_field(): + denom = lcm([coeff[0].denominator() for coeff in poly]) + poly *= denom sigma_polynomial *= poly - else: - sigma_polynomial *= psi(G[-1]) - if not base_ring.is_field(): - sigma_polynomial = ringR(sigma_polynomial) + if not base_ring.is_field(): + sigma_polynomial = ringR(sigma_polynomial) + if check: + degree_w = sigma_polynomial.degrees()[0] + expected_degree = sum(d**(n*i) for i in range(N+1)) + if degree_w != expected_degree: + raise ValueError('sigma polynomial dropped degree, as multiplicities were not accounted for correctly.'+ + ' try setting chow=True or deform=True') if return_polynomial: return sigma_polynomial # if we are returing a numerical list, read off the coefficients @@ -5098,7 +5141,6 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sigma_dictionary = dict([list(reversed(i)) for i in list(sigma_polynomial)]) degree_w, degree_t = sigma_polynomial.degrees() w, t = sigma_polynomial.variables() - sigmas += [degree_w, degree_t] for i in range(degree_w+1): for j in range(degree_t+1): sigmas.append((-1)**(i+j)*sigma_dictionary.pop(w**(degree_w - i)*t**(degree_t - j), 0)) From fc12a328b8853299227173c7e5de4801ae1ebeae Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 9 Jul 2021 16:40:49 -0400 Subject: [PATCH 017/511] 31994: fixed tests --- .../arithmetic_dynamics/projective_ds.py | 54 +++++++++---------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 86c1ac2b596..cbcac881a21 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4830,15 +4830,14 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', For dynamical systems on `\mathbb{P}^N`, where `N > 1`, the full polynomial is needed to distinguish the conjugacy class. We can, however, still return - a list in this case. Here, the first element of the list is the degree in `w` and - the second element is the degree in `t`. The rest of the list are the coefficients - of the polynomial, sorted in lexographical order with `w > t`:: + a list in this case:: sage: P. = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem_projective([x^2, z^2, y^2]) - sage: f.sigma_invariants(1) - [3, 6, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3, -2, -4, 0, 0, 3, -4, -8, 8, 0, - 1, -2, -4, 8, 0, 0, 0] + sage: f.sigma_invariants(1, chow=True) + [1, 7, -6, -12, 21, -36, -60, 72, 48, 35, -90, -120, 352, 96, -288, -64, 35, -120, -120, 688, -96, + -1056, 320, 384, 0, 21, -90, -60, 672, -384, -1440, 1344, 768, -768, 0, 0, 7, -36, -12, 328, -336, + -864, 1472, 384, -1536, 512, 0, 0, 0, 1, -6, 0, 64, -96, -192, 512, 0, -768, 512, 0, 0, 0, 0, 0] When calculating the sigma invariants for `\mathbb{P}^N`, with `N > 1`, the default algorithm loses information about multiplicities. Note that @@ -4846,7 +4845,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sage: P. = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) - sage: f.sigma_invariants(1, return_polynomial=True) + sage: f.sigma_invariants(1, return_polynomial=True, check=False) w^6 - 6*w^5*t^2 + 8*w^5*t - 4*w^5 + 15*w^4*t^4 - 40*w^4*t^3 + 40*w^4*t^2 - 16*w^4*t - 20*w^3*t^6 + 80*w^3*t^5 - 120*w^3*t^4 + 80*w^3*t^3 - 16*w^3*t^2 + 15*w^2*t^8 - 80*w^2*t^7 + 160*w^2*t^6 - 144*w^2*t^5 + 48*w^2*t^4 - 6*w*t^10 + @@ -4889,18 +4888,6 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sage: f.sigma_invariants(2, type='point', formal=True) [0, 0] - :: - - sage: P. = ProjectiveSpace(QQ, 3) - sage: f = DynamicalSystem_projective([x^2, w^2, z^2, y^2]) - sage: f.sigma_invariants(1, return_polynomial=True) - w^6 - 6*w^5*t^3 + 2*w^5*t^2 + 8*w^5*t - 8*w^5 + 15*w^4*t^6 - 10*w^4*t^5 - - 44*w^4*t^4 + 48*w^4*t^3 + 16*w^4*t^2 - 32*w^4*t - 20*w^3*t^9 + 20*w^3*t^8 + - 96*w^3*t^7 - 120*w^3*t^6 - 96*w^3*t^5 + 160*w^3*t^4 + 15*w^2*t^12 - 20*w^2*t^11 - - 104*w^2*t^10 + 152*w^2*t^9 + 192*w^2*t^8 - 320*w^2*t^7 - 64*w^2*t^6 + 128*w^2*t^5 - - 6*w*t^15 + 10*w*t^14 + 56*w*t^13 - 96*w*t^12 - 160*w*t^11 + 288*w*t^10 + 128*w*t^9 - - 256*w*t^8 + t^18 - 2*t^17 - 12*t^16 + 24*t^15 + 48*t^14 - 96*t^13 - 64*t^12 + 128*t^11 - :: sage: K. = QuadraticField(3) @@ -4926,9 +4913,10 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sage: P. = ProjectiveSpace(GF(5), 2) sage: f = DynamicalSystem([x^2, y^2, z^2]) - sage: f.sigma_invariants(1, return_polynomial=True) - w^6 - w^5*t^2 - 2*w^5*t + w^5 - w^4*t - w^3*t^2 + w^2*t^5 - - 2*w^2*t^4 - w*t^10 + 2*w*t^7 + 2*w*t^6 + t^12 + 2*t^11 - t^10 - 2*t^9 + t^8 + sage: f.sigma_invariants(1, chow=True, return_polynomial=True) + w^7 - 2*w^6*t^2 + w^6 + w^5*t^4 + w^5*t + w^4*t^3 + 2*w^4*t^2 + w^3*t^5 - + w^3*t^4 - 2*w^3*t^3 - w^2*t^10 + w^2*t^7 + w^2*t^6 + w^2*t^5 + 2*w*t^12 - + w*t^10 + w*t^9 - 2*w*t^8 - w*t^7 - t^14 + 2*t^9 :: @@ -4960,6 +4948,13 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sage: len(dict(f.sigma_invariants(1, return_polynomial=True))) 51 + :: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([x^2 + 3*y^2, x*y]) + sage: f.sigma_invariants(1, deform = True, return_polynomial=True) + w^3 - 3*w^2*t + 3*w^2 + 3*w*t^2 - 6*w*t + 3*w - t^3 + 3*t^2 - 3*t + 1 + doubled fixed point:: sage: P. = ProjectiveSpace(QQ, 1) @@ -4988,7 +4983,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sage: N. = NumberField(w^2 + 1) sage: P. = ProjectiveSpace(N, 2) sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) - sage: f.sigma_invariants(1) == f.change_ring(QQ).sigma_invariants(1) + sage: #f.sigma_invariants(1, chow=True) == f.change_ring(QQ).sigma_invariants(1, chow=True) True """ n = ZZ(n) @@ -5012,6 +5007,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', N = dom.dimension_relative() f = copy(self) Fn = f.nth_iterate_map(n) + CR = f.codomain().ambient_space().coordinate_ring() if deform: # we need a model with all affine periodic points new_f = f.affine_preperiodic_model(0, n) @@ -5023,7 +5019,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', deformed_polys = [poly + k*Pt.gens()[-1]**d for poly in new_f.defining_polynomials()[:-1]] deformed_polys += [new_f.defining_polynomials()[-1]] f_deformed = DynamicalSystem(deformed_polys) - sigma_poly = sigma(f_deformed, n, chow=chow, deform=False, return_polynomial=True) + sigma_poly = f_deformed.sigma_invariants(n, chow=chow, deform=False, return_polynomial=True, check=False) sigma_polynomial = sigma_poly.specialization({k:0}) # we fix the ordering of the parent polynomial ring new_parent = sigma_polynomial.parent().change_ring(order='lex') @@ -5112,7 +5108,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sigma_polynomial *= poly if not base_ring.is_field(): sigma_polynomial = ringR(sigma_polynomial) - if check: + if check and not formal: degree_w = sigma_polynomial.degrees()[0] expected_degree = sum(d**(n*i) for i in range(N+1)) if degree_w != expected_degree: @@ -5124,11 +5120,11 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', # in order of degree adjusting sign appropriately sigmas = [] sigma_dictionary = dict([list(reversed(i)) for i in list(sigma_polynomial)]) - degree_w, degree_t = sigma_polynomial.degrees() + degree_w = sigma_polynomial.degrees()[0] w, t = sigma_polynomial.variables() - for i in range(degree_w+1): - for j in range(degree_t+1): - sigmas.append((-1)**(i+j)*sigma_dictionary.pop(w**(degree_w - i)*t**(degree_t - j), 0)) + for i in range(degree_w + 1): + for j in range(2*i, -1, -1): + sigmas.append((-1)**(i+j)*sigma_dictionary.pop(w**(degree_w - i)*t**(j), 0)) return sigmas base_ring = dom.base_ring() From 7f113c7e0e7d031e351ff5d39aea8985d356ae85 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 12 Jul 2021 15:23:44 -0400 Subject: [PATCH 018/511] first commit with code and docs --- .../endPN_automorphism_group.py | 483 +++++++++++++++++- .../arithmetic_dynamics/projective_ds.py | 159 ++---- 2 files changed, 535 insertions(+), 107 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index d46c8601b25..5bdc8c53bcc 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -8,6 +8,8 @@ Xander Faber, Michelle Manes, and Bianca Viray [FMV]_. - Joao de Faria, Ben Hutz, Bianca Thompson (11-2013): adaptation for inclusion in Sage + +- Alexander Galarraga (7-2021): Added helper functions for conjugating set """ #***************************************************************************** @@ -19,10 +21,10 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from copy import copy +from copy import copy, deepcopy from sage.combinat.subset import Subsets from sage.functions.all import sqrt -from itertools import permutations, combinations +from itertools import permutations, combinations, product from sage.matrix.constructor import matrix from sage.structure.element import is_Matrix from sage.misc.misc_c import prod @@ -34,6 +36,10 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ from sage.sets.primes import Primes +from sage.sets.set import Set +from sage.combinat.permutation import Arrangements +from sage.parallel.use_fork import p_iter_fork +from sage.functions.other import floor def automorphism_group_QQ_fixedpoints(rational_function, return_functions=False, iso_type=False): r""" @@ -1783,3 +1789,476 @@ def which_group(list_of_elements): return ['S_4'] else: return ['A_5'] + +def conjugating_set_initializer(f, g): + """ + Return a conjugation invariant set together with information + to reduce the combinatorics of checking all possible conjugations. + + Do not call this function directly, instead use ``f.conjugating_set(g)``. + + INPUT: + + - ``f`` -- a rational function of degree at least 2, and the same + degree as ``g`` + + - ``g`` -- a nonconstant rational function of the same + degree as ``f`` + + OUTPUT: + + A tuple of the form (``source``, ``possible_targets``). + + - ``source`` -- a conjugation invariant set, used to specify PGL elements which conjugate `f` to `g`. + a list of `n+2` points of the domain of `f`, of which no `n+1` are linearly dependent. + Used to specify a possible conjugation from `f` to `g`. + + - ``possible_targets`` -- a list of tuples of the form (``points``, ``repeated``). ``points`` + is a list of ``points`` which are possible targets for point(s) in ``source``. ``repeated`` + specifies how many points in ``source`` have points in ``points`` as their possible target. + + """ + n = f.domain().dimension_relative() + + L = Set(f.periodic_points(1)) + K = Set(g.periodic_points(1)) + P = f.codomain().ambient_space() + if len(L) != len(K): # checks maps have the same number of fixed points + return [] + + # we store fixed points an multipliers in dictionaries + # to avoid recalculating them + mult_to_point_L = {} + mult_to_point_K = {} + point_to_mult_L = {} + point_to_mult_K = {} + + # as we will calculate preimages, we differentiate points by their 'level' + # which is how many preimages of a fixed point they are, i.e. a fixed point + # has level 0, a preimage of a fixed point level 1, etc. + level = 0 + + # initializing the dictionaries + for i in range(len(L)): + mult_L = f.multiplier(L[i], 1).charpoly() + mult_K = g.multiplier(K[i], 1).charpoly() + tup_L = (mult_L, level) + tup_K = (mult_K, level) + if tup_L not in mult_to_point_L: + mult_to_point_L[tup_L] = [L[i]] + else: + mult_to_point_L[tup_L] += [L[i]] + if tup_K not in mult_to_point_K: + mult_to_point_K[tup_K] = [K[i]] + else: + mult_to_point_K[tup_K] += [K[i]] + point_to_mult_L[L[i]] = (mult_L, level) + point_to_mult_K[K[i]] = (mult_K, level) + + # we keep a dictionary which tracks how often a (multiplier, level) pair + # is repeated. As points can only be sent to points with the same (multiplier, level) + # pair, the less times a (multiplier, level) pair are repeated the better the + # combinatorics + repeated_mult_L = {} + for mult_L in mult_to_point_L: + repeated = len(mult_to_point_L[mult_L]) + if mult_L not in mult_to_point_K: + return [] + elif len(mult_to_point_K[mult_L]) != repeated: + return [] + if repeated not in repeated_mult_L: + repeated_mult_L[repeated] = [mult_to_point_L[mult_L]] + else: + repeated_mult_L[repeated] += [mult_to_point_L[mult_L]] + r = f.domain().base_ring() + more = True + + # the n+2 points to be used to specificy PGL conjugations + source = [] + + # a list of tuples of the form ((multiplier, level), repeat) where the + # (multiplier, level) pair specifies the possible targets of a point in source and repeat + # specifies how many points in source have that (multiplier, level) pair + corresponding = [] + + # we look for a set of n+2 points, of which no n+1 are linearly dependent, + # and we make sure to add the points with the best combinatorics first + for r in sorted(repeated_mult_L.keys()): + for point_lst in repeated_mult_L[r]: + for point in point_lst: + if P.is_linearly_independent(source + [point], n+1): + source.append(point) + mult = point_to_mult_L[point] + # if another point with this multiplier and level pair is in S + # then the multiplier level pair will be the last element of corresponding + if len(corresponding) != 0: + if corresponding[-1][0] == mult: + corresponding[-1][1] += 1 + else: + corresponding.append([mult, 1]) + else: + corresponding.append([mult, 1]) + if len(source) == n+2: + more = False + break + if len(source) == n+2: + break + if len(source) == n+2: + break + + # we keep 3 dictionaries to allow looping over a dictionary + i_repeated_mult = deepcopy(repeated_mult_L) # loop dictionary + a_repeated_mult = {} # loop dictionary for next iteration of loop (if necessary) + found_no_more = True + + # if we don't find enough points, we go to preimages + while more: + level += 1 + # we calculate preimages, starting with preimages with the best + # expected combinatorics + for r in sorted(i_repeated_mult.keys()): + for point_lst_L in i_repeated_mult[r]: + old_tup_L = point_to_mult_L[point_lst_L[0]] + point_lst_K = mult_to_point_K[old_tup_L] + mult_L = old_tup_L[0] + Tl = [] + Tk = [] + + # first we calculate preimages + for pnt in point_lst_L: + for preimage in f.rational_preimages(pnt): + if preimage != pnt: + Tl.append(preimage) + for pnt in point_lst_K: + for preimage in g.rational_preimages(pnt): + if preimage != pnt: + Tk.append(preimage) + if len(Tl) != len(Tk): + return [] + if len(Tl) != 0: + found_no_more = False + new_tup_L = (mult_L, level) + new_tup_K = (mult_L, level) + + # we update dictionaries with the new preimages + mult_to_point_L[new_tup_L] = Tl + mult_to_point_K[new_tup_K] = Tk + for i in range(len(Tl)): + point_to_mult_L[Tl[i]] = new_tup_L + point_to_mult_K[Tk[i]] = new_tup_K + repeated = len(Tl) + if repeated not in repeated_mult_L: + repeated_mult_L[repeated] = [Tl] + else: + repeated_mult_L[repeated] += [Tl] + if repeated not in a_repeated_mult: + a_repeated_mult[repeated] = [Tl] + else: + a_repeated_mult[repeated] += [Tl] + source = [] + corresponding = [] + for r in sorted(repeated_mult_L.keys()): + for point_lst in repeated_mult_L[r]: + for point in point_lst: + if P.is_linearly_independent(source + [point], n+1): + source.append(point) + mult = point_to_mult_L[point] + # if another point with this multiplier and level pair is in S + # then the multiplier level pair will be the last element of corresponding + if len(corresponding) != 0: + if corresponding[-1][0] == mult: + corresponding[-1][1] += 1 + else: + corresponding.append([mult, 1]) + else: + corresponding.append([mult, 1]) + if len(source) == n+2: + more = False + break + if len(source) == n+2: + break + if len(source) == n+2: + break + if not more: + break + if not more: + break + + # if no more preimages can be found, the algorithm fails + if found_no_more: + raise ValueError('no more rational preimages. try extending the base field and trying again.') + + # if we need to add more preimages, we update loop dictionaries + if more: + i_repeated_mult = deepcopy(a_repeated_mult) + a_repeated_mult = {} + found_no_more = True + + # we build a list of iterators in order to loop over the product of those iterators + possible_targets = [] + for tup in corresponding: + possible_targets.append([mult_to_point_K[tup[0]], tup[1]]) + return source, possible_targets + +def conjugating_set_helper(f, g, num_cpus, source, possible_targets): + r""" + Return the set of elements in PGL over the base ring + that conjugates ``f`` to ``g``. + + Do not call this function directly, instead do ``f.conjugate_set(g)``. + + INPUT: + + - ``f`` -- a rational function of degree at least 2, and the same + degree as ``g`` + + - ``g`` -- a rational function of the same + degree as ``f`` + + - ``num_cpus`` -- the number of threads to run in parallel + + - ``source`` -- a list of `n+2` conjugation invariant points, of which + no `n+1` are linearly dependent. + + - ``possible_targets`` -- a list of tuples of the form (``points``, ``repeated``). ``points`` + is a list of ``points`` which are possible targets for point(s) in ``source``. ``repeated`` + specifies how many points in ``source`` have points in ``points`` as their possible target. + + OUTPUT: + + a list of elements of PGL which conjugate ``f`` to ``g``. + """ + Conj = [] + P = f.domain().ambient_space() + n = f.domain().dimension_relative() + + subset_iterators = [] + + for lst in possible_targets: + subset_iterators.append(Subsets(range(len(lst[0])), lst[1])) + + # helper function for parallelization + # given a list of tuples which specify indicies of possible target points + # in possible_targets, check all arragements of those possible target points + # and if any of them define a conjugation which sends f to g, return + # those conjugations as a list + def find_conjugations_subset(tuples): + conj = [] + for tup in tuples: + target_set = [] + for i in range(len(tup)): + for j in tup[i]: + target_set.append(possible_targets[i][0][j]) + + # if there is a subset of n+1 points which is linearly dependent, + # we don't need to check any of these arrangements + if P.is_linearly_independent(target_set, n+1): + subset_arrangements = [] + for subset in tup: + subset_arrangements.append(Arrangements(subset, len(subset))) + for tup in product(*subset_arrangements): + current_target = [] + for i in range(len(tup)): + for j in tup[i]: + current_target.append(possible_targets[i][0][j]) + phi = P.point_transformation_matrix(current_target, source) + if f.conjugate(phi) == g: + conj.append(phi) + return conj + + # helper function for parallelization + # given a list of tuples which specify indicies of possible target points + # in possible_targets, check all possible target points + # and if any of them define a conjugation which sends f to g, return + # those conjugations as a list + def find_conjugations_arrangement(tuples): + conj = [] + for tup in tuples: + current_target = [] + for i in range(len(tup)): + for j in tup[i]: + current_target.append(possible_targets[i][0][j]) + phi = P.point_transformation_matrix(current_target, source) + if f.conjugate(phi) == g: + conj.append(phi) + return conj + + if num_cpus > 1: + all_subsets = list(product(*subset_iterators)) + parallel_data = [] + + # if there are enough subsets, we can divide up the work based on subsets + # and check linear independence in parallel + if len(all_subsets) > num_cpus: + for i in range(num_cpus): + start = floor(len(all_subsets)*i/num_cpus) + end = floor(len(all_subsets)*(i+1)/num_cpus) + tuples = all_subsets[start:end] + parallel_data.append(([tuples], {})) + + X = p_iter_fork(num_cpus) + for ret in X(find_conjugations_subset, parallel_data): + if ret[1]: + Conj += ret[1] + # otherwise, we need to first check linear independence of the subsets + # and then build a big list of all the arrangemenets to split among + # the threads + else: + good_targets = [] + for tup in product(*subset_iterators): + target_set = [] + for i in range(len(tup)): + for j in tup[i]: + target_set.append(possible_targets[i][0][j]) + if P.is_linearly_independent(target_set, n+1): + good_targets.append(tup) + all_arrangements = [] + for tup in good_targets: + subset_arrangements = [] + for subset in tup: + subset_arrangements.append(Arrangements(subset, len(subset))) + all_arrangements += list(product(*subset_arrangements)) + parallel_data = [] + for i in range(num_cpus): + start = floor(len(all_arrangements)*i/num_cpus) + end = floor(len(all_arrangements)*(i+1)/num_cpus) + tuples = all_arrangements[start:end] + parallel_data.append(([tuples], {})) + X = p_iter_fork(num_cpus) + for ret in X(find_conjugations_arrangement, parallel_data): + if ret[1]: + Conj += ret[1] + else: + Conj = find_conjugations_subset(product(*subset_iterators)) + return Conj + +def is_conjugate_helper(f, g, num_cpus, source, possible_targets): + r""" + Return if ``f`` is conjugate to ``g``. + + Do not call this function directly, instead do ``f.is_conjugate(g)``. + + INPUT: + + - ``f`` -- a rational function of degree at least 2, and the same + degree as ``g`` + + - ``g`` -- a rational function of the same + degree as ``f`` + + - ``num_cpus`` -- the number of threads to run in parallel + + - ``source`` -- a list of `n+2` conjugation invariant points, of which + no `n+1` are linearly dependent. + + - ``possible_targets`` -- a list of tuples of the form (``points``, ``repeated``). ``points`` + is a list of ``points`` which are possible targets for point(s) in ``source``. ``repeated`` + specifies how many points in ``source`` have points in ``points`` as their possible target. + + OUTPUT: + + a list of elements of PGL which conjugate ``f`` to ``g``. + """ + is_conj = False + P = f.domain().ambient_space() + n = f.domain().dimension_relative() + + subset_iterators = [] + + for lst in possible_targets: + subset_iterators.append(Subsets(range(len(lst[0])), lst[1])) + + # helper function for parallelization + # given a list of tuples which specify indicies of possible target points + # in possible_targets, check all arragements of those possible target points + # and if any of them define a conjugation which sends f to g, return + # those conjugations as a list + def find_conjugations_subset(tuples): + for tup in tuples: + target_set = [] + for i in range(len(tup)): + for j in tup[i]: + target_set.append(possible_targets[i][0][j]) + + # if there is a subset of n+1 points which is linearly dependent, + # we don't need to check any of these arrangements + if P.is_linearly_independent(target_set, n+1): + subset_arrangements = [] + for subset in tup: + subset_arrangements.append(Arrangements(subset, len(subset))) + for tup in product(*subset_arrangements): + current_target = [] + for i in range(len(tup)): + for j in tup[i]: + current_target.append(possible_targets[i][0][j]) + phi = P.point_transformation_matrix(current_target, source) + if f.conjugate(phi) == g: + return True + return False + + # helper function for parallelization + # given a list of tuples which specify indicies of possible target points + # in possible_targets, check all possible target points + # and if any of them define a conjugation which sends f to g, return + # those conjugations as a list + def find_conjugations_arrangement(tuples): + for tup in tuples: + current_target = [] + for i in range(len(tup)): + for j in tup[i]: + current_target.append(possible_targets[i][0][j]) + phi = P.point_transformation_matrix(current_target, source) + if f.conjugate(phi) == g: + return True + return False + + if num_cpus > 1: + all_subsets = list(product(*subset_iterators)) + parallel_data = [] + + # if there are enough subsets, we can divide up the work based on subsets + # and check linear independence in parallel + if len(all_subsets) > num_cpus: + for i in range(num_cpus): + start = floor(len(all_subsets)*i/num_cpus) + end = floor(len(all_subsets)*(i+1)/num_cpus) + tuples = all_subsets[start:end] + parallel_data.append(([tuples], {})) + + X = p_iter_fork(num_cpus) + for ret in X(find_conjugations_subset, parallel_data): + if ret[1]: + is_conj = True + break + # otherwise, we need to first check linear independence of the subsets + # and then build a big list of all the arrangemenets to split among + # the threads + else: + good_targets = [] + for tup in product(*subset_iterators): + target_set = [] + for i in range(len(tup)): + for j in tup[i]: + target_set.append(possible_targets[i][0][j]) + if P.is_linearly_independent(target_set, n+1): + good_targets.append(tup) + all_arrangements = [] + for tup in good_targets: + subset_arrangements = [] + for subset in tup: + subset_arrangements.append(Arrangements(subset, len(subset))) + all_arrangements += list(product(*subset_arrangements)) + parallel_data = [] + for i in range(num_cpus): + start = floor(len(all_arrangements)*i/num_cpus) + end = floor(len(all_arrangements)*(i+1)/num_cpus) + tuples = all_arrangements[start:end] + parallel_data.append(([tuples], {})) + X = p_iter_fork(num_cpus) + for ret in X(find_conjugations_arrangement, parallel_data): + if ret[1]: + is_conj = True + break + else: + is_conj = find_conjugations_subset(product(*subset_iterators)) + return is_conj \ No newline at end of file diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 1a6d5ce39ab..739aeabcfd8 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -109,6 +109,13 @@ class initialization directly. from sage.combinat.subset import Subsets from sage.symbolic.ring import SR from itertools import count, product +from .endPN_automorphism_group import ( + automorphism_group_QQ_CRT, + automorphism_group_QQ_fixedpoints, + conjugating_set_helper, + conjugating_set_initializer, + is_conjugate_helper) +from .endPN_automorphism_group import automorphism_group_FF class DynamicalSystem_projective(SchemeMorphism_polynomial_projective_space, @@ -3241,7 +3248,13 @@ def automorphism_group(self, **kwds): INPUT: - keywords: + The following keywords are used in most cases: + + - ``num_cpus`` -- (default: 1) the number of threads to use. Setting to a + larger number can greatly speed up this function. + + The following keywords are used only when the dimension of the domain is 1 and + the base ring is the rationals, but ignored in all other cases: - ``starting_prime`` -- (default: 5) the first prime to use for CRT @@ -3318,7 +3331,7 @@ def automorphism_group(self, **kwds): sage: P. = ProjectiveSpace(QQ,2) sage: f = DynamicalSystem_projective([x**2 + x*z, y**2, z**2]) - sage: f.automorphism_group() # long time + sage: f.automorphism_group() [ [1 0 0] [0 1 0] @@ -3340,10 +3353,11 @@ def automorphism_group(self, **kwds): p = kwds.get('starting_prime', 5) return_functions = kwds.get('return_functions', False) iso_type = kwds.get('iso_type', False) + num_cpus = kwds.get('num_cpus', 1) if self.domain().dimension_relative() != 1: - return self.conjugating_set(self) - if self.base_ring() != QQ and self.base_ring != ZZ: - return self.conjugating_set(self) + return self.conjugating_set(self, num_cpus) + if self.base_ring() != QQ and self.base_ring() != ZZ: + return self.conjugating_set(self, num_cpus) self.normalize_coordinates() if (self.degree() == 1) or (self.degree() == 0): raise NotImplementedError("Rational function of degree 1 not implemented.") @@ -3353,7 +3367,6 @@ def automorphism_group(self, **kwds): F = (f[0].numerator().univariate_polynomial(R))/f[0].denominator().univariate_polynomial(R) else: F = f[0].univariate_polynomial(R) - from .endPN_automorphism_group import automorphism_group_QQ_CRT, automorphism_group_QQ_fixedpoints if alg is None: if self.degree() <= 12: return automorphism_group_QQ_fixedpoints(F, return_functions, iso_type) @@ -6426,7 +6439,7 @@ def connected_rational_component(self, P, n=0): return points[0] - def conjugating_set(self, other, R=None): + def conjugating_set(self, other, R=None, num_cpus=1): r""" Return the set of elements in PGL over the base ring that conjugates one dynamical system to the other. @@ -6464,6 +6477,9 @@ def conjugating_set(self, other, R=None): - ``R`` -- a field or embedding + - ``num_cpus`` -- (default: 1) the number of threads to run in parallel. + Increasing ``num_cpus`` can potentially greatly speed up this function. + OUTPUT: Set of conjugating `n+1` by `n+1` matrices. @@ -6475,6 +6491,8 @@ def conjugating_set(self, other, R=None): - Implemented by Rebecca Lauren Miller, as part of GSOC 2016. + - Algorithmic improvement by Alexander Galarraga as part of GSOC 2021. + EXAMPLES:: sage: P. = ProjectiveSpace(QQ,1) @@ -6518,7 +6536,7 @@ def conjugating_set(self, other, R=None): sage: D8.conjugating_set(D8) Traceback (most recent call last): ... - ValueError: not enough rational preimages + ValueError: no more rational preimages. try extending the base field and trying again. :: @@ -6668,60 +6686,18 @@ def conjugating_set(self, other, R=None): return [m] #not similar return [] - # sigma invariants are invariant under conjugacy but are only implemented in dim 1 + # sigma invariants are invariant under conjugacy but are only fast in dim 1 n = f.domain().dimension_relative() if (n == 1) and (R in NumberFields() or R in FiniteFields())\ and (f.sigma_invariants(1) != g.sigma_invariants(1)): return [] - L = Set(f.periodic_points(1)) - K = Set(g.periodic_points(1)) - if len(L) != len(K): # checks maps have the same number of fixed points + tup = conjugating_set_initializer(f, g) + if tup == []: return [] - d = len(L) - r = f.domain().base_ring() - more = True - if d >= n+2: # need at least n+2 points - for i in Subsets(range(len(L)), n+2): - # make sure all n+1 subsets are linearly independent - TL = [L[il] for il in i] - Ml = matrix(r, [list(s) for s in TL]) - if not any(j == 0 for j in Ml.minors(n + 1)): - Tf = list(TL) - more = False - break - while more: - # finds preimages of fixed points - Tl = [Q for i in L for Q in f.rational_preimages(i)] - Tk = [Q for i in K for Q in g.rational_preimages(i)] - if len(Tl) != len(Tk): - return [] - L = L.union(Set(Tl)) - K = K.union(Set(Tk)) - if d == len(L): # if no new preimages then not enough points - raise ValueError("not enough rational preimages") - d = len(L) - if d >= n + 2: # makes sure all n+1 subsets are linearly independent - for i in Subsets(range(len(L)), n+2): - TL = [L[il] for il in i] - Ml = matrix(r, [list(s) for s in TL]) - if not any(j == 0 for j in Ml.minors(n + 1)): - more = False - Tf = list(TL) - break - Conj = [] - for i in Arrangements(range(len(K)),(n+2)): - TK = [K[ik] for ik in i] - # try all possible conjugations between invariant sets - try: # need all n+1 subsets linearly independent - s = f.domain().point_transformation_matrix(TK,Tf) - # finds elements of PGL that maps one map to another - if self.conjugate(s) == other: - Conj.append(s) - except (ValueError): - pass - return Conj + source, possible_targets = tup + return conjugating_set_helper(f, g, num_cpus, source, possible_targets) - def is_conjugate(self, other, R=None): + def is_conjugate(self, other, R=None, num_cpus=1): r""" Return whether two dynamical systems are conjugate over their base ring (by default) or over the ring `R` entered as an @@ -6740,6 +6716,9 @@ def is_conjugate(self, other, R=None): - ``R`` -- a field or embedding + - ``num_cpus`` -- (default: 1) the number of threads to run in parallel. + Increasing ``num_cpus`` can potentially greatly speed up this function. + OUTPUT: boolean AUTHORS: @@ -6886,57 +6865,16 @@ def is_conjugate(self, other, R=None): # so we can scale to have the determinants equal m1 = (1/det_root)*m1 return m1.is_similar(m2) - # sigma invariants are invariant under conjugacy but are only implemented in dim 1 + # sigma invariants are invariant under conjugacy but are only fast in dim 1 n = f.domain().dimension_relative() if (n==1) and (R in NumberFields() or R in FiniteFields())\ and (f.sigma_invariants(1) != g.sigma_invariants(1)): return False - L = Set(f.periodic_points(1)) - K = Set(g.periodic_points(1)) - if len(L) != len(K): # checks maps have the same number of fixed points + tup = conjugating_set_initializer(f, g) + if tup == []: return False - d = len(L) - r = f.domain().base_ring() - more = True - if d >= n+2: # need at least n+2 points - for i in Subsets(range(len(L)), n+2): - # make sure all n+1 subsets are linearly independent - TL = [L[il] for il in i] - Ml = matrix(r, [list(s) for s in TL]) - if not any(j == 0 for j in Ml.minors(n + 1)): - Tf = list(TL) - more = False - break - while more: - # finds preimages of fixed points - Tl = [Q for i in L for Q in f.rational_preimages(i)] - Tk = [Q for i in K for Q in g.rational_preimages(i)] - if len(Tl) != len(Tk): - return False - L = L.union(Set(Tl)) - K = K.union(Set(Tk)) - if d == len(L):# if no new preimages then not enough points - raise ValueError("not enough rational preimages") - d = len(L) - if d >= n + 2: # makes sure all n+1 subsets are linearly independent - for i in Subsets(range(len(L)), n+2): - TL = [L[il] for il in i] - Ml = matrix(r, [list(s) for s in TL]) - if not any(j == 0 for j in Ml.minors(n + 1)): - more = False - Tf = list(TL) - break - for i in Arrangements(range(len(K)),(n+2)): - TK = [K[ik] for ik in i] - # try all possible conjugations between invariant sets - try: # need all n+1 subsets linearly independent - s = f.domain().point_transformation_matrix(TK,Tf) - # finds elements of PGL that maps one map to another - if self.conjugate(s) == other: - return True - except (ValueError): - pass - return False + source, possible_targets = tup + return is_conjugate_helper(f, g, num_cpus, source, possible_targets) def is_polynomial(self): r""" @@ -7797,7 +7735,7 @@ def possible_periods(self, return_points=False): """ return _fast_possible_periods(self, return_points) - def automorphism_group(self, absolute=False, iso_type=False, return_functions=False): + def automorphism_group(self, **kwds): r""" Return the subgroup of `PGL2` that is the automorphism group of this dynamical system. @@ -7808,6 +7746,14 @@ def automorphism_group(self, absolute=False, iso_type=False, return_functions=Fa INPUT: + The following keywords are used when the dimension of the domain + is greater than 1: + + - ``num_cpus`` -- (default: 1) the number of threads to use. Setting to a + larger number can greatly speed up this function. + + The following keywords are used when the dimension of the domain is 1: + - ``absolute``-- (default: ``False``) boolean; if ``True``, then return the absolute automorphism group and a field of definition @@ -7887,8 +7833,12 @@ def automorphism_group(self, absolute=False, iso_type=False, return_functions=Fa [0 1] ]] """ + absolute = kwds.get('absolute', False) + iso_type = kwds.get('iso_type', False) + return_functions = kwds.get('return_functions', False) + num_cpus = kwds.get('num_cpus', 1) if self.domain().dimension_relative() != 1: - raise NotImplementedError("must be dimension 1") + return self.conjugating_set(self, num_cpus) else: f = self.dehomogenize(1) z = f[0].parent().gen() @@ -7899,7 +7849,6 @@ def automorphism_group(self, absolute=False, iso_type=False, return_functions=Fa F = f[0].numerator().polynomial(z) / f[0].denominator().polynomial(z) else: F = f[0].numerator().polynomial(z) - from .endPN_automorphism_group import automorphism_group_FF return automorphism_group_FF(F, absolute, iso_type, return_functions) def all_periodic_points(self, **kwds): From 76249f2c8e34852ae1a4a44f7cd301816063826e Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 12 Jul 2021 15:34:36 -0400 Subject: [PATCH 019/511] 31994: doc fix --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index cbcac881a21..86890bea165 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -5113,7 +5113,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', expected_degree = sum(d**(n*i) for i in range(N+1)) if degree_w != expected_degree: raise ValueError('sigma polynomial dropped degree, as multiplicities were not accounted for correctly.'+ - ' try setting chow=True or deform=True') + ' try setting chow=True and/or deform=True') if return_polynomial: return sigma_polynomial # if we are returing a numerical list, read off the coefficients From e6a2bb78e454b9ea266c87ceb6dcc5cb305a9136 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 12 Jul 2021 16:18:27 -0400 Subject: [PATCH 020/511] updated docs --- .../arithmetic_dynamics/projective_ds.py | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 739aeabcfd8..d4f9983d31d 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -6466,9 +6466,10 @@ def conjugating_set(self, other, R=None, num_cpus=1): ALGORITHM: Implementing invariant set algorithm from the paper [FMV2014]_. - Given that the set of `n` th preimages of fixed points is - invariant under conjugation find all elements of PGL that - take one set to another. + Uses the set of `n` th preimages of fixed points, as this set is + invariant under conjugation to find all elements of PGL that + take one set to another. Additionally, keeps track of multiplier + information to reduce the necessary combinatorics. INPUT: @@ -6552,7 +6553,7 @@ def conjugating_set(self, other, R=None, num_cpus=1): sage: P. = ProjectiveSpace(QQ,2) sage: f = DynamicalSystem_projective([x^2 + x*z, y^2, z^2]) - sage: f.conjugating_set(f) # long time + sage: f.conjugating_set(f) [ [1 0 0] [0 1 0] @@ -6706,8 +6707,10 @@ def is_conjugate(self, other, R=None, num_cpus=1): ALGORITHM: Implementing invariant set algorithm from the paper [FMV2014]_. - Given that the set of `n` th preimages is invariant under - conjugation this function finds whether two maps are conjugate. + Uses the set of `n` th preimages of fixed points, as this set is + invariant under conjugation to find all elements of PGL that + take one set to another. Additionally, keeps track of multiplier + information to reduce the necessary combinatorics. INPUT: @@ -6784,7 +6787,7 @@ def is_conjugate(self, other, R=None, num_cpus=1): sage: P. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([-3*y^2, 3*x^2]) sage: g = DynamicalSystem_projective([-x^2 - 2*x*y, 2*x*y + y^2]) - sage: f.is_conjugate(g), f.is_conjugate(g, R=QQbar) # long time + sage: f.is_conjugate(g), f.is_conjugate(g, R=QQbar) (False, True) :: @@ -7740,9 +7743,12 @@ def automorphism_group(self, **kwds): Return the subgroup of `PGL2` that is the automorphism group of this dynamical system. - Only for dimension 1. The automorphism group is the set of `PGL2` - elements that fixed the map under conjugation. See [FMV2014]_ - for the algorithm. + The automorphism group is the set of `PGL2` elements that fixed the map under conjugation. + + For dimension 1, see [FMV2014]_ for the algorithm. + + For dimension greater than 1, we compute the conjugating set of this + dynamical system with itself. INPUT: From 2a247bb24b73bc6597ff388a4c21b9abf57cc34a Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 12 Jul 2021 16:56:16 -0400 Subject: [PATCH 021/511] independent set calculation bug fixed --- .../endPN_automorphism_group.py | 23 ++++++++++++++++++- .../arithmetic_dynamics/projective_ds.py | 8 +++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index 5bdc8c53bcc..ed3f0ed3022 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -1986,7 +1986,28 @@ def conjugating_set_initializer(f, g): # if no more preimages can be found, the algorithm fails if found_no_more: - raise ValueError('no more rational preimages. try extending the base field and trying again.') + all_points = [] + for r in sorted(repeated_mult_L.keys()): + for point_lst in repeated_mult_L[r]: + all_points += point_lst + for subset in Subsets(range(len(all_points)), n+2): + source = [] + for i in subset: + source.append(all_points[i]) + if P.is_linearly_independent(source, n+1): + more = False + corresponding = [] + mult_only = [] + for i in subset: + mult = point_to_mult_L[all_points[i]] + if mult in mult_only: + corresponding[mult_only.index(mult)][1] += 1 + else: + corresponding.append([mult, 1]) + mult_only.append(mult) + break + if more: + raise ValueError('no more rational preimages. try extending the base field and trying again.') # if we need to add more preimages, we update loop dictionaries if more: diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index d4f9983d31d..93b8742b3e9 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -6513,7 +6513,7 @@ def conjugating_set(self, other, R=None, num_cpus=1): sage: f = DynamicalSystem_projective([x^2 + y^2, x*y]) sage: m = matrix(K, 2, 2, [1, 1, 2, 1]) sage: g = f.conjugate(m) - sage: sorted(f.conjugating_set(g)) # long time + sage: sorted(f.conjugating_set(g)) [ [-1 -1] [1 1] [ 2 1], [2 1] @@ -6524,7 +6524,7 @@ def conjugating_set(self, other, R=None, num_cpus=1): sage: K. = QuadraticField(-1) sage: P. = ProjectiveSpace(K,1) sage: D8 = DynamicalSystem_projective([y^3, x^3]) - sage: sorted(D8.conjugating_set(D8)) # long time + sage: sorted(D8.conjugating_set(D8)) [ [-1 0] [-i 0] [ 0 -1] [ 0 -i] [0 i] [0 1] [i 0] [1 0] [ 0 1], [ 0 1], [ 1 0], [ 1 0], [1 0], [1 0], [0 1], [0 1] @@ -6746,7 +6746,7 @@ def is_conjugate(self, other, R=None, num_cpus=1): sage: f = DynamicalSystem_projective([x^2 + x*y,y^2]) sage: m = matrix(QQbar, 2, 2, [1, 1, 2, 1]) sage: g = f.conjugate(m) - sage: f.is_conjugate(g) # long time + sage: f.is_conjugate(g) True :: @@ -6814,7 +6814,7 @@ def is_conjugate(self, other, R=None, num_cpus=1): sage: f = DynamicalSystem_projective([2*x^2 + 12*y*x, 11*y*x+2*y^2, x^2+z^2]) sage: m1 = matrix(QQ, 3, 3, [1,4,1,0,2,1,1,1,1]) sage: g = f.conjugate(m1) - sage: f.is_conjugate(g) # long time + sage: f.is_conjugate(g) True TESTS: From 03bd0e2100895f80b173b54dd97f3a72136dd2ea Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 13 Jul 2021 14:01:46 -0400 Subject: [PATCH 022/511] added examples, new function --- .../endPN_automorphism_group.py | 183 +++++++++++++----- .../arithmetic_dynamics/projective_ds.py | 42 ++-- 2 files changed, 161 insertions(+), 64 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index ed3f0ed3022..9ec7adbaf7e 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -1809,14 +1809,25 @@ def conjugating_set_initializer(f, g): A tuple of the form (``source``, ``possible_targets``). - - ``source`` -- a conjugation invariant set, used to specify PGL elements which conjugate `f` to `g`. - a list of `n+2` points of the domain of `f`, of which no `n+1` are linearly dependent. - Used to specify a possible conjugation from `f` to `g`. + - ``source`` -- a conjugation invariant set of `n+2` points of the domain of `f`, + of which no `n+1` are linearly dependent. Used to specify a possible conjugation + from `f` to `g`. - ``possible_targets`` -- a list of tuples of the form (``points``, ``repeated``). ``points`` is a list of ``points`` which are possible targets for point(s) in ``source``. ``repeated`` specifies how many points in ``source`` have points in ``points`` as their possible target. + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: f = DynamicalSystem([(8*x^7 - 35*x^4*y^3 - 35*x^4*z^3 - 7*x*y^6 - 140*x*y^3*z^3 \ + - 7*x*z^6), (-7*x^6*y - 35*x^3*y^4 - 140*x^3*y*z^3 + 8*y^7 - 35*y^4*z^3 \ + - 7*y*z^6), -7*x^6*z - 140*x^3*y^3*z - 35*x^3*z^4 - 7*y^6*z - 35*y^3*z^4 + 8*z^7]) + sage: from sage.dynamics.arithmetic_dynamics.endPN_automorphism_group import conjugating_set_initializer + sage: conjugating_set_initializer(f, f) + ([(-1 : 0 : 1), (0 : -1 : 1), (0 : 1 : 0), (1 : 0 : 0)], + [[[(-1 : 0 : 1), (0 : -1 : 1), (-1 : 1 : 0)], 2], + [[(0 : 1 : 0), (1 : 0 : 0), (1 : 1 : 1), (0 : 0 : 1)], 2]]) """ n = f.domain().dimension_relative() @@ -1881,30 +1892,16 @@ def conjugating_set_initializer(f, g): # specifies how many points in source have that (multiplier, level) pair corresponding = [] - # we look for a set of n+2 points, of which no n+1 are linearly dependent, - # and we make sure to add the points with the best combinatorics first - for r in sorted(repeated_mult_L.keys()): - for point_lst in repeated_mult_L[r]: - for point in point_lst: - if P.is_linearly_independent(source + [point], n+1): - source.append(point) - mult = point_to_mult_L[point] - # if another point with this multiplier and level pair is in S - # then the multiplier level pair will be the last element of corresponding - if len(corresponding) != 0: - if corresponding[-1][0] == mult: - corresponding[-1][1] += 1 - else: - corresponding.append([mult, 1]) - else: - corresponding.append([mult, 1]) - if len(source) == n+2: - more = False - break - if len(source) == n+2: - break - if len(source) == n+2: - break + # we now greedily look for a set of n+2 points, of which no n+1 are linearly dependent, + # and we make sure to add the points with the best combinatorics first. + # this check sometimes fails, i.e. sometimes there is a subset with the + # desired property which is not found. however, this check is very fast and if it + # does find a subset, then the subset will most likely minimize the combinatorics + # of checking conjugations + tup = greedy_independence_check(P, repeated_mult_L, point_to_mult_L) + if not tup is None: + more = False + source, corresponding = tup # we keep 3 dictionaries to allow looping over a dictionary i_repeated_mult = deepcopy(repeated_mult_L) # loop dictionary @@ -1955,41 +1952,28 @@ def conjugating_set_initializer(f, g): a_repeated_mult[repeated] = [Tl] else: a_repeated_mult[repeated] += [Tl] - source = [] - corresponding = [] - for r in sorted(repeated_mult_L.keys()): - for point_lst in repeated_mult_L[r]: - for point in point_lst: - if P.is_linearly_independent(source + [point], n+1): - source.append(point) - mult = point_to_mult_L[point] - # if another point with this multiplier and level pair is in S - # then the multiplier level pair will be the last element of corresponding - if len(corresponding) != 0: - if corresponding[-1][0] == mult: - corresponding[-1][1] += 1 - else: - corresponding.append([mult, 1]) - else: - corresponding.append([mult, 1]) - if len(source) == n+2: - more = False - break - if len(source) == n+2: - break - if len(source) == n+2: - break + # we again do a greedy check for a subset of n+2 points, of which no n+1 + # are linearly dependent + tup = greedy_independence_check(P, repeated_mult_L, point_to_mult_L) + if not tup is None: + more = False + source, corresponding = tup if not more: break if not more: break - # if no more preimages can be found, the algorithm fails + # if no more preimages can be found, we must check all subsets + # of size n+2 to see if there is a subset in which no n+1 points + # are linearly dependent if found_no_more: all_points = [] for r in sorted(repeated_mult_L.keys()): for point_lst in repeated_mult_L[r]: all_points += point_lst + # this loop is quite long, so we break after finding the first subset + # with the desired property. There is, however, no guarentee that the + # subset we found minimizes the combinatorics when checking conjugations for subset in Subsets(range(len(all_points)), n+2): source = [] for i in subset: @@ -2006,6 +1990,9 @@ def conjugating_set_initializer(f, g): corresponding.append([mult, 1]) mult_only.append(mult) break + # if we iterated over all subsets of size n+2, and did not find one + # in which all subsets of size n+1 are linearly independent, + # then we fail as we cannot specify conjugations if more: raise ValueError('no more rational preimages. try extending the base field and trying again.') @@ -2021,6 +2008,75 @@ def conjugating_set_initializer(f, g): possible_targets.append([mult_to_point_K[tup[0]], tup[1]]) return source, possible_targets +def greedy_independence_check(P, repeated_mult, point_to_mult): + r""" + Return a conjugation invariant set together with information + to reduce the combinatorics of checking all possible conjugations. + + This function may sometimes fail to find the conjugation invariant + set even though one exists. It is useful, however, as it is fast + and returns a set which usually minimizes the combinatorics of + checking all conjugations. + + INPUT: + + - ``P`` -- a projective space + + - ``repeated_mult`` -- a dictionary of integers to lists of points of + the projective space ``P``. The list of points should be conjugation + invariant. The keys are considered as weights, and this function attempts + to minimize the total weight + + - ``point_to_mult`` -- a dictionary of points of ``P`` to tuples of the form + (multiplier, level), where multiplier is the characteristic polynomial + of the multiplier of the point, and level is the number of preimages + taken to find the point + + OUTPUT: + + If no set of `n+2` points of which all subsets of size `n+1` are linearly + independent can be found, then ``None`` is returned. + + Otherwise, a tuple of the form (``source``, ``corresponding``) is returned. + + - ``source`` -- a conjugation invariant set of `n+2` points of the domain of `f`, + of which no `n+1` are linearly dependent. Used to specify a possible conjugation + from `f` to `g`. + + - ``corresponding`` -- a list of tuples of the form ((multiplier, level), repeat) where the + (multiplier, level) pair is the multiplier of a point in ``source`` and repeat + specifies how many points in source have that (multiplier, level) pair + + EXAMPLES:: + + sage: from sage.dynamics.arithmetic_dynamics.endPN_automorphism_group import greedy_independence_check + sage: P. = ProjectiveSpace(QQ, 1) + sage: repeated_mult = {2: [[P((0, 1)), P((1, 0))]], 1: [[P((1, 1))]]} + sage: point_to_mult = {P((0, 1)): (x, 0), P((1, 0)): (x, 0), P((1, 1)): (x - 2, 0)} + sage: greedy_independence_check(P, repeated_mult, point_to_mult) + ([(1 : 1), (0 : 1), (1 : 0)], [[(x - 2, 0), 1], [(x, 0), 2]]) + """ + n = P.dimension_relative() + source = [] + corresponding = [] + for r in sorted(repeated_mult.keys()): + for point_lst in repeated_mult[r]: + for point in point_lst: + if P.is_linearly_independent(source + [point], n+1): + source.append(point) + mult = point_to_mult[point] + # if another point with this multiplier and level pair is in S + # then the multiplier level pair will be the last element of corresponding + if len(corresponding) != 0: + if corresponding[-1][0] == mult: + corresponding[-1][1] += 1 + else: + corresponding.append([mult, 1]) + else: + corresponding.append([mult, 1]) + if len(source) == n+2: + return source, corresponding + def conjugating_set_helper(f, g, num_cpus, source, possible_targets): r""" Return the set of elements in PGL over the base ring @@ -2048,6 +2104,19 @@ def conjugating_set_helper(f, g, num_cpus, source, possible_targets): OUTPUT: a list of elements of PGL which conjugate ``f`` to ``g``. + + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([x^2, y^2]) + sage: source = [P((1, 1)), P((0, 1)), P((1, 0))] + sage: possible_targets = [[[P((1, 1))], 1], [[P((0, 1)), P((1, 0))], 2]] + sage: from sage.dynamics.arithmetic_dynamics.endPN_automorphism_group import conjugating_set_helper + sage: conjugating_set_helper(f, f, 2, source, possible_targets) + [ + [1 0] [0 1] + [0 1], [1 0] + ] """ Conj = [] P = f.domain().ambient_space() @@ -2179,6 +2248,16 @@ def is_conjugate_helper(f, g, num_cpus, source, possible_targets): OUTPUT: a list of elements of PGL which conjugate ``f`` to ``g``. + + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([x^2, y^2]) + sage: source = [P((1, 1)), P((0, 1)), P((1, 0))] + sage: possible_targets = [[[P((1, 1))], 1], [[P((0, 1)), P((1, 0))], 2]] + sage: from sage.dynamics.arithmetic_dynamics.endPN_automorphism_group import is_conjugate_helper + sage: is_conjugate_helper(f, f, 2, source, possible_targets) + True """ is_conj = False P = f.domain().ambient_space() diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 93b8742b3e9..fabc4c432b1 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -6451,8 +6451,10 @@ def conjugating_set(self, other, R=None, num_cpus=1): The optional argument `R` specifies the field of definition of the PGL elements. The set is determined by taking the fixed points of one map and mapping - them to all unique permutations of the fixed points of - the other map. If there are not enough fixed points the + them to permutations of the fixed points of the other map. + As conjugacy preserves the multipliers as a set, fixed points + are only maped to fixed points with the same multiplier. + If there are not enough fixed points the function compares the mapping between rational preimages of fixed points and the rational preimages of the preimages of fixed points until there are enough points; such that there @@ -6490,7 +6492,7 @@ def conjugating_set(self, other, R=None, num_cpus=1): - Original algorithm written by Xander Faber, Michelle Manes, Bianca Viray [FMV2014]_. - - Implemented by Rebecca Lauren Miller, as part of GSOC 2016. + - Implemented by Rebecca Lauren Miller as part of GSOC 2016. - Algorithmic improvement by Alexander Galarraga as part of GSOC 2021. @@ -6506,6 +6508,13 @@ def conjugating_set(self, other, R=None, num_cpus=1): [ 2 1] ] + Increasing ``num_cpus`` can speed up computation:: + + sage: P. = ProjectiveSpace(QQ,3) + sage: f = DynamicalSystem_projective([x^2, y^2, z^2, w^2]) + sage: len(f.conjugating_set(f, num_cpus=2)) + 24 + :: sage: K. = QuadraticField(-1) @@ -6731,19 +6740,28 @@ def is_conjugate(self, other, R=None, num_cpus=1): - Implemented by Rebecca Lauren Miller as part of GSOC 2016. + - Algorithmic improvement by Alexander Galarraga as part of GSOC 2016. + EXAMPLES:: sage: K. = CyclotomicField(3) - sage: P. = ProjectiveSpace(K,1) + sage: P. = ProjectiveSpace(K, 1) sage: D8 = DynamicalSystem_projective([y^2, x^2]) sage: D8.is_conjugate(D8) True + We can speed up computation by increasing ``num_cpus``:: + + sage: P. = ProjectiveSpace(QQ,3) + sage: f = DynamicalSystem_projective([x^2, y^2, z^2, w^2]) + sage: f.is_conjugate(f, num_cpus=2) + True + :: sage: set_verbose(None) - sage: P. = ProjectiveSpace(QQbar,1) - sage: f = DynamicalSystem_projective([x^2 + x*y,y^2]) + sage: P. = ProjectiveSpace(QQbar, 1) + sage: f = DynamicalSystem_projective([x^2 + x*y, y^2]) sage: m = matrix(QQbar, 2, 2, [1, 1, 2, 1]) sage: g = f.conjugate(m) sage: f.is_conjugate(g) @@ -6751,8 +6769,8 @@ def is_conjugate(self, other, R=None, num_cpus=1): :: - sage: P. = ProjectiveSpace(GF(5),1) - sage: f = DynamicalSystem_projective([x^3 + x*y^2,y^3]) + sage: P. = ProjectiveSpace(GF(5), 1) + sage: f = DynamicalSystem_projective([x^3 + x*y^2, y^3]) sage: m = matrix(GF(5), 2, 2, [1, 3, 2, 9]) sage: g = f.conjugate(m) sage: f.is_conjugate(g) @@ -6760,15 +6778,15 @@ def is_conjugate(self, other, R=None, num_cpus=1): :: - sage: P. = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2 + x*y,y^2]) + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([x^2 + x*y, y^2]) sage: g = DynamicalSystem_projective([x^3 + x^2*y, y^3]) sage: f.is_conjugate(g) False :: - sage: P. = ProjectiveSpace(QQ,1) + sage: P. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([x^2 + x*y, y^2]) sage: g = DynamicalSystem_projective([x^2 - 2*y^2, y^2]) sage: f.is_conjugate(g) @@ -6810,7 +6828,7 @@ def is_conjugate(self, other, R=None, num_cpus=1): :: - sage: P. = ProjectiveSpace(QQ,2) + sage: P. = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem_projective([2*x^2 + 12*y*x, 11*y*x+2*y^2, x^2+z^2]) sage: m1 = matrix(QQ, 3, 3, [1,4,1,0,2,1,1,1,1]) sage: g = f.conjugate(m1) From f7f22a8865b94ea499c33c198bc13edc432622d6 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 13 Jul 2021 14:15:55 -0400 Subject: [PATCH 023/511] 31994: added degree check when formal=True --- .../arithmetic_dynamics/projective_ds.py | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 86890bea165..cb4d77489cc 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -52,7 +52,7 @@ class initialization directly. # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.misc import is_prime +from sage.arith.misc import is_prime, moebius from sage.calculus.functions import jacobian from sage.categories.fields import Fields from sage.categories.function_fields import FunctionFields @@ -4983,8 +4983,28 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sage: N. = NumberField(w^2 + 1) sage: P. = ProjectiveSpace(N, 2) sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) - sage: #f.sigma_invariants(1, chow=True) == f.change_ring(QQ).sigma_invariants(1, chow=True) + sage: f.sigma_invariants(1, chow=True) == f.change_ring(QQ).sigma_invariants(1, chow=True) True + + :: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([x^2 + 3*y^2, x*y]) + sage: f.sigma_invariants(1, formal=True, return_polynomial=True) + Traceback (most recent call last): + .. + ValueError: sigma polynomial dropped degree, as multiplicities were not accounted + for correctly. try setting chow=True and/or deform=True + + :: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([x^2 + 3*y^2, x*y]) + sage: f.sigma_invariants(1, return_polynomial=True) + Traceback (most recent call last): + .. + ValueError: sigma polynomial dropped degree, as multiplicities were not accounted + for correctly. try setting chow=True and/or deform=True """ n = ZZ(n) if n < 1: @@ -5108,9 +5128,16 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sigma_polynomial *= poly if not base_ring.is_field(): sigma_polynomial = ringR(sigma_polynomial) - if check and not formal: + if check: degree_w = sigma_polynomial.degrees()[0] - expected_degree = sum(d**(n*i) for i in range(N+1)) + if formal: + expected_degree = 0 + for D in n.divisors(): + u = moebius(n/D) + inner_sum = sum(d**(D*j) for j in range(N+1)) + expected_degree += u*inner_sum + else: + expected_degree = sum(d**(n*i) for i in range(N+1)) if degree_w != expected_degree: raise ValueError('sigma polynomial dropped degree, as multiplicities were not accounted for correctly.'+ ' try setting chow=True and/or deform=True') From b86822d90266c102b9bf97a24e84f0d5ed0c132d Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 13 Jul 2021 16:49:57 -0400 Subject: [PATCH 024/511] fixed comments --- .../endPN_automorphism_group.py | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index 9ec7adbaf7e..a6d77e854ac 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -1795,6 +1795,13 @@ def conjugating_set_initializer(f, g): Return a conjugation invariant set together with information to reduce the combinatorics of checking all possible conjugations. + This function constructs the conjugation invariant set (``source``) + necessary for the conjugating set algorithm described in [FMV2014]_. + Additionally, it keeps track of multipliers to reduce the combinatorics. + This information is then passed to ``conjugating_set_helper`` or + ``is_conjugate_helper``, which check all possible conjugations determined + by the conjugation invariant set. + Do not call this function directly, instead use ``f.conjugating_set(g)``. INPUT: @@ -1903,24 +1910,25 @@ def conjugating_set_initializer(f, g): more = False source, corresponding = tup - # we keep 3 dictionaries to allow looping over a dictionary - i_repeated_mult = deepcopy(repeated_mult_L) # loop dictionary - a_repeated_mult = {} # loop dictionary for next iteration of loop (if necessary) - found_no_more = True + else: + # loop_repeated_mult stores the points to find preimages of + loop_repeated_mult = deepcopy(repeated_mult_L) + # next_repeated_mult stores the points to find preimages of on the next loop + next_repeated_mult = {} + found_no_more = True # if we don't find enough points, we go to preimages while more: level += 1 # we calculate preimages, starting with preimages with the best # expected combinatorics - for r in sorted(i_repeated_mult.keys()): - for point_lst_L in i_repeated_mult[r]: + for r in sorted(loop_repeated_mult.keys()): + for point_lst_L in loop_repeated_mult[r]: old_tup_L = point_to_mult_L[point_lst_L[0]] point_lst_K = mult_to_point_K[old_tup_L] mult_L = old_tup_L[0] Tl = [] Tk = [] - # first we calculate preimages for pnt in point_lst_L: for preimage in f.rational_preimages(pnt): @@ -1936,7 +1944,6 @@ def conjugating_set_initializer(f, g): found_no_more = False new_tup_L = (mult_L, level) new_tup_K = (mult_L, level) - # we update dictionaries with the new preimages mult_to_point_L[new_tup_L] = Tl mult_to_point_K[new_tup_K] = Tk @@ -1948,10 +1955,10 @@ def conjugating_set_initializer(f, g): repeated_mult_L[repeated] = [Tl] else: repeated_mult_L[repeated] += [Tl] - if repeated not in a_repeated_mult: - a_repeated_mult[repeated] = [Tl] + if repeated not in next_repeated_mult: + next_repeated_mult[repeated] = [Tl] else: - a_repeated_mult[repeated] += [Tl] + next_repeated_mult[repeated] += [Tl] # we again do a greedy check for a subset of n+2 points, of which no n+1 # are linearly dependent tup = greedy_independence_check(P, repeated_mult_L, point_to_mult_L) @@ -1967,7 +1974,10 @@ def conjugating_set_initializer(f, g): # of size n+2 to see if there is a subset in which no n+1 points # are linearly dependent if found_no_more: + # we construct a list of all the possible sources points all_points = [] + # we order the list by how many repeated multipliers each point has + # in an attempt to reduce the combinatorics of checking conjugations for r in sorted(repeated_mult_L.keys()): for point_lst in repeated_mult_L[r]: all_points += point_lst @@ -1998,8 +2008,8 @@ def conjugating_set_initializer(f, g): # if we need to add more preimages, we update loop dictionaries if more: - i_repeated_mult = deepcopy(a_repeated_mult) - a_repeated_mult = {} + loop_repeated_mult = deepcopy(next_repeated_mult) + next_repeated_mult = {} found_no_more = True # we build a list of iterators in order to loop over the product of those iterators @@ -2082,6 +2092,9 @@ def conjugating_set_helper(f, g, num_cpus, source, possible_targets): Return the set of elements in PGL over the base ring that conjugates ``f`` to ``g``. + This function takes as input the conjugation invariant set + and multiplier data from ``conjugating_set_initializer``. + Do not call this function directly, instead do ``f.conjugate_set(g)``. INPUT: @@ -2226,6 +2239,9 @@ def is_conjugate_helper(f, g, num_cpus, source, possible_targets): r""" Return if ``f`` is conjugate to ``g``. + This function takes as input the conjugation invariant set + and multiplier data from ``conjugating_set_initializer``. + Do not call this function directly, instead do ``f.is_conjugate(g)``. INPUT: @@ -2247,7 +2263,7 @@ def is_conjugate_helper(f, g, num_cpus, source, possible_targets): OUTPUT: - a list of elements of PGL which conjugate ``f`` to ``g``. + ``True`` if ``f`` is conjugate to ``g``, ``False`` otherwise. EXAMPLES:: @@ -2271,8 +2287,7 @@ def is_conjugate_helper(f, g, num_cpus, source, possible_targets): # helper function for parallelization # given a list of tuples which specify indicies of possible target points # in possible_targets, check all arragements of those possible target points - # and if any of them define a conjugation which sends f to g, return - # those conjugations as a list + # and if any of them define a conjugation which sends f to g, return True def find_conjugations_subset(tuples): for tup in tuples: target_set = [] @@ -2299,8 +2314,7 @@ def find_conjugations_subset(tuples): # helper function for parallelization # given a list of tuples which specify indicies of possible target points # in possible_targets, check all possible target points - # and if any of them define a conjugation which sends f to g, return - # those conjugations as a list + # and if any of them define a conjugation which sends f to g, return True def find_conjugations_arrangement(tuples): for tup in tuples: current_target = [] From 063f159f6c1fa82966a3173da2a0558333758fe7 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 15 Jul 2021 11:57:48 -0400 Subject: [PATCH 025/511] 31994: added more documentation --- .../arithmetic_dynamics/projective_ds.py | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 9a723dc7b72..079d37b48ec 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4750,20 +4750,24 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', Computes the values of the elementary symmetric polynomials of the ``n`` multiplier spectra of this dynamical system. + For maps defined over projective space of dimension greater than 1, + the sigma invariants are the symetric polynomials in the characteristic + polynomials of the multipliers. See [Hutz2019]_ for the full definition. + Can specify to instead compute the values corresponding to the elementary symmetric polynomials of the formal ``n`` multiplier - spectra. The map must be defined over projective space of dimension - `1`. The base ring should be a number field, number field order, or + spectra. The base ring should be a number field, number field order, or a finite field or a polynomial ring or function field over a number field, number field order, or finite field. The parameter ``type`` determines if the sigma are computed from the multipliers calculated at one per cycle (with multiplicity) - or one per point (with multiplicity). Note that in the ``cycle`` - case, a map with a cycle which collapses into multiple smaller - cycles, this is still considered one cycle. In other words, if a - 4-cycle collapses into a 2-cycle with multiplicity 2, there is only - one multiplier used for the doubled 2-cycle when computing ``n=4``. + or one per point (with multiplicity). Only implemented + for dimension 1. Note that in the ``cycle`` case, a map with a cycle + which collapses into multiple smaller cycles, this is still + considered one cycle. In other words, if a 4-cycle collapses into + a 2-cycle with multiplicity 2, there is only one multiplier used + for the doubled 2-cycle when computing ``n=4``. ALGORITHM: @@ -4779,7 +4783,28 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', denominators for `g`. To calculate the full polynomial defining the sigma invariants, - we follow the algorithm outlined in section 4 of [Hutz2019]_. + we follow the algorithm outlined in section 4 of [Hutz2019]_. There + are 4 cases: + + - multipliers and ``n`` periodic points all distinct -- in this case, + we can use Proposition 4.1 of [Hutz2019]_ to compute the sigma invariants. + + - ``n`` periodic points are all distinct, multipliers are repeated -- here we + can use Proposition 4.2 of [Hutz2019]_ to compute the sigma invariants. + This corresponds to ``chow=True``. + + - ``n`` periodic points are repeated, multipliers are all distinct -- to deal + with this case, we deform the map by a formal parameter `k`. The deformation + seperates the ``n`` periodic points, making them distinct, and we can recover + the ``n`` periodic points of the original map by specializing `k` to 0. + This corresponds to ``deform=True``. + + - ``n`` periodic points are repeated, multipliers are repeated -- here we + can use both cases 2 and 3 together. This corresponds to ``deform=True`` + and ``chow=True``. + + As we do not want to check which case we are in beforehand, we throw an error + if the computed polynomial drops in degree. INPUT: From 6186c586af31171f64a1d1c8fb372280a1319ecf Mon Sep 17 00:00:00 2001 From: bhutz Date: Thu, 15 Jul 2021 14:21:32 -0500 Subject: [PATCH 026/511] 31994: updated docs --- src/doc/en/reference/references/index.rst | 3 +- .../arithmetic_dynamics/projective_ds.py | 42 ++++++++++++------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index f1f79881b62..2b61d75e4fd 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -3042,7 +3042,8 @@ REFERENCES: for morphisms of PN. Mathematics of Computation, 84:291 (2015), 289-308. .. [Hutz2019] \B. Hutz. Multipliers and invariants of endomorphisms of projective - space in dimension greater than 1, :arxiv:`1908.03184`, 2019. + space in dimension greater than 1, Journal de Théorie des Nombres de + Bordeaux, Tome 32 (2020) no. 2, pp. 439-469. .. [Huy2005] \D. Huybrechts : *Complex Geometry*, Springer (Berlin) (2005). diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 079d37b48ec..0d9f5d2557c 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4747,16 +4747,26 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur def sigma_invariants(self, n, formal=False, embedding=None, type='point', return_polynomial=False, chow=False, deform=False, check=True): r""" - Computes the values of the elementary symmetric polynomials of - the ``n`` multiplier spectra of this dynamical system. + Computes the values of the elementary symmetric polynomials evaluated + on the ``n`` multiplier spectra of this dynamical system. - For maps defined over projective space of dimension greater than 1, - the sigma invariants are the symetric polynomials in the characteristic - polynomials of the multipliers. See [Hutz2019]_ for the full definition. + The sigma invariants are the symetric polynomials evaluated on the + characteristic polynomial of the multipliers. See [Hutz2019]_ for + the full definition. Spepcifically, this function returns either + the following polynomial or its coefficients (with signs + appropriately adjusted): - Can specify to instead compute the values corresponding to the - elementary symmetric polynomials of the formal ``n`` multiplier - spectra. The base ring should be a number field, number field order, or + .. MATH:: + + \prod_{P \text{ period n}} ( w - c(P,t)), + + where `c(P,t)` is the charateristic polynomial (variable `t`) of the + multiplier at `P`. Note that in dimension 1, only the coefficients + of the constant term is returned. + + The invariants can be computed for points of period ``n`` or + points of formal period ``n``. The base + ring should be a number field, number field order, or a finite field or a polynomial ring or function field over a number field, number field order, or finite field. @@ -4771,15 +4781,19 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', ALGORITHM: - We use the Poisson product of the resultant of two polynomials: + In dimension 1, we use the Poisson product of the resultant of + two polynomials: .. MATH:: res(f,g) = \prod_{f(a)=0} g(a). - Letting `f` be the polynomial defining the periodic or formal - periodic points and `g` the polynomial `w - f'` for an auxilarly - variable `w`. Note that if `f` is a rational function, we clear + In higher dimensions, we use elimination theory (Groebner bases) + to compute the equivalent of the Poisson product. Letting `f` be + the polynomial defining the periodic or formal + periodic points and `g` the polynomial `w - F` for an auxilarly + variable `w` and `F` the characteristic polynomial of the Jacobian matrix + of `f`. Note that if `f` is a rational function, we clear denominators for `g`. To calculate the full polynomial defining the sigma invariants, @@ -4803,8 +4817,8 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', can use both cases 2 and 3 together. This corresponds to ``deform=True`` and ``chow=True``. - As we do not want to check which case we are in beforehand, we throw an error - if the computed polynomial drops in degree. + As we do not want to check which case we are in beforehand, we throw a + ValueError if the computed polynomial does not have the correct degree. INPUT: From b882a6a8bb61edbf92ca95ed76d2337820c4cbaa Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 20 Jul 2021 12:42:35 -0400 Subject: [PATCH 027/511] 32199: set default cpus to 2 --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index bd9ddef3496..91402c18da3 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -6472,7 +6472,7 @@ def connected_rational_component(self, P, n=0): return points[0] - def conjugating_set(self, other, R=None, num_cpus=1): + def conjugating_set(self, other, R=None, num_cpus=2): r""" Return the set of elements in PGL over the base ring that conjugates one dynamical system to the other. @@ -6513,7 +6513,7 @@ def conjugating_set(self, other, R=None, num_cpus=1): - ``R`` -- a field or embedding - - ``num_cpus`` -- (default: 1) the number of threads to run in parallel. + - ``num_cpus`` -- (default: 2) the number of threads to run in parallel. Increasing ``num_cpus`` can potentially greatly speed up this function. OUTPUT: @@ -7806,7 +7806,7 @@ def automorphism_group(self, **kwds): The following keywords are used when the dimension of the domain is greater than 1: - - ``num_cpus`` -- (default: 1) the number of threads to use. Setting to a + - ``num_cpus`` -- (default: 2) the number of threads to use. Setting to a larger number can greatly speed up this function. The following keywords are used when the dimension of the domain is 1: @@ -7893,7 +7893,7 @@ def automorphism_group(self, **kwds): absolute = kwds.get('absolute', False) iso_type = kwds.get('iso_type', False) return_functions = kwds.get('return_functions', False) - num_cpus = kwds.get('num_cpus', 1) + num_cpus = kwds.get('num_cpus', 2) if self.domain().dimension_relative() != 1: return self.conjugating_set(self, num_cpus) else: From f073844d8b3878b679d7858c03da999564dfca7a Mon Sep 17 00:00:00 2001 From: Christian Wuthrich Date: Wed, 21 Jul 2021 13:19:19 +0100 Subject: [PATCH 028/511] adjust 2-adic lseries for elliptic curves --- .../schemes/elliptic_curves/padic_lseries.py | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index 3506a565459..030607b5c72 100644 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -851,7 +851,7 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): raise ValueError("Insufficient precision (%s)" % prec) # check if the conditions on quadratic_twist are satisfied - eta = ZZ(eta) % (self._p - 1) + eta = ZZ(eta) % (self._p- 1) if self._p != 2 else ZZ(eta) % 2 D = ZZ(quadratic_twist) if D != 1: if eta != 0: @@ -870,6 +870,7 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): if valuation(self._E.conductor(), ell) > valuation(D, ell): raise ValueError("cannot twist a curve of conductor (=%s) by the quadratic twist (=%s)."%(self._E.conductor(),D)) p = self._p + si = 1-2*(eta % 2) #verbose("computing L-series for p=%s, n=%s, and prec=%s"%(p,n,prec)) @@ -891,17 +892,9 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): return L else: # here we need some sums anyway - if eta % 2 == 1: - si = ZZ(-1) - else: - si = ZZ(1) bounds = self._prec_bounds(n,prec,sign=si) padic_prec = 20 else: - if eta % 2 == 1: - si = ZZ(-1) - else: - si = ZZ(1) bounds = self._prec_bounds(n,prec,sign=si) padic_prec = max(bounds[1:]) + 5 @@ -935,7 +928,6 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): gamma = K(1+ p) p_power = p**(n-1) a_range = p - si = 1-2*(eta % 2) verbose("Now iterating over %s summands"%((p-1)*p_power)) verbose_level = get_verbose() @@ -964,7 +956,9 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): [aj[j].add_bigoh(bounds[j]) for j in range(1,len(aj))] L = R(aj,res_series_prec ) - L /= self._quotient_of_periods_to_twist(D)*self._E.real_components() + L /= self._quotient_of_periods_to_twist(D) + if si == +1: + L /= self._E.real_components() self._set_series_in_cache(n, res_series_prec, D, eta, L) @@ -1226,9 +1220,7 @@ def series(self, n=3, quadratic_twist=+1, prec=5, eta=0): raise ValueError("cannot twist a curve of conductor (=%s) by the quadratic twist (=%s)." % (self._E.conductor(), D)) p = self._p - eta = ZZ(eta) % (p - 1) - #if p == 2 and self._normalize: - #print('Warning : for p = 2 the normalization might not be correct !') + eta = ZZ(eta) % (p - 1) if p != 2 else ZZ(eta) % 2 if prec == 1: if eta == 0: @@ -1306,7 +1298,9 @@ def series(self, n=3, quadratic_twist=+1, prec=5, eta=0): bj.append( aj[j].add_bigoh(bounds[j]) ) j += 1 L = R(bj, prec) - L /= self._quotient_of_periods_to_twist(D)*self._E.real_components() + L /= self._quotient_of_periods_to_twist(D) + if si == +1 : + L /= self._E.real_components() self._set_series_in_cache(n, prec, quadratic_twist, eta, L) return L From 9005db2ddeaacab075c6f8d44ddd5cf427f7af68 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 23 Jul 2021 00:56:42 -0600 Subject: [PATCH 029/511] Ensure elements of coxeter3 CoxeterGroup are normalized on construction (particularly, after multiplication). --- src/sage/libs/coxeter3/coxeter_group.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index b4118ca9592..9ebb8137ebc 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -158,7 +158,7 @@ def simple_reflections(self): sage: W = CoxeterGroup(['A', 3], implementation='coxeter3') # optional - coxeter3 sage: s = W.simple_reflections() # optional - coxeter3 sage: s[2]*s[1]*s[2] # optional - coxeter3 - [2, 1, 2] + [1, 2, 1] """ from sage.combinat.family import Family return Family(self.index_set(), lambda i: self.element_class(self, [i])) @@ -422,6 +422,7 @@ def __init__(self, parent, x): """ if not isinstance(x, CoxGroupElement): x = CoxGroupElement(parent._coxgroup, x).reduced() + x = x.normal_form() ElementWrapper.__init__(self, parent, x) def __iter__(self): @@ -446,7 +447,7 @@ def coatoms(self): sage: W = CoxeterGroup(['B', 3], implementation='coxeter3') # optional - coxeter3 sage: w = W([1,2,3]) # optional - coxeter3 sage: w.coatoms() # optional - coxeter3 - [[2, 3], [1, 3], [1, 2]] + [[2, 3], [3, 1], [1, 2]] """ W = self.parent() return [W(w) for w in self.value.coatoms()] @@ -528,6 +529,8 @@ def _mul_(self, y): [] sage: s[1]*s[2]*s[1] # optional - coxeter3 [1, 2, 1] + sage: s[2]*s[1]*s[2] # optional - coxeter3 + [1, 2, 1] """ return self.__class__(self.parent(), self.value * y.value) From dcad52d1d16b8b575a6faee3e6814178cdd367a7 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 23 Jul 2021 00:57:05 -0600 Subject: [PATCH 030/511] Provide direct/efficient implementation of from_reduced_word for coxeter3 CoxeterGroups. --- src/sage/libs/coxeter3/coxeter_group.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 9ebb8137ebc..d0c13f12a11 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -165,6 +165,20 @@ def simple_reflections(self): gens = simple_reflections + def from_reduced_word(self, w): + """ + Return an element of ``self`` from its (reduced) word. + + EXAMPLES:: + + sage: W = CoxeterGroup(['A', 3], implementation='coxeter3') + sage: W.from_reduced_word([1, 3]) + [1, 3] + sage: W.from_reduced_word([3, 1]) + [1, 3] + """ + return self.element_class(self, w) + def rank(self): """ Return the rank of this Coxeter group, that is, the number of generators. From edfb6a0a7f3b34363741cd02aab2dde119cbbbc4 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 14 Jul 2021 11:13:49 +0900 Subject: [PATCH 031/511] 32200: Add developer manual section on integer return values --- src/doc/en/developer/coding_in_python.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/doc/en/developer/coding_in_python.rst b/src/doc/en/developer/coding_in_python.rst index 1d8b7c1d3bf..f6ee0c9527d 100644 --- a/src/doc/en/developer/coding_in_python.rst +++ b/src/doc/en/developer/coding_in_python.rst @@ -465,6 +465,26 @@ Note that the syntax in ``except`` is to list all the exceptions that are caught as a tuple, followed by an error message. +Integer Return Value +==================== + +Many functions and methods of objects in Sage return an integer, which users +often treat mathematically and may want to explore its number-theoretic +properties such as prime factorization. Hence if a function or method for your +object returns an integer, consider returning Sage integer of type ``Integer`` +rather than Python integer of type ``int``, unless there is a good reason not +to (such as performance or compatibility with Python code). If ``i`` is an +integer of type ``int``, then code for the return statement would be + +.. CODE-BLOCK:: python + + from sage.rings.integer import Integer + return Integer(i) + +Notable definite exceptions to this rule are special methods like ``__hash__``, +``__len__``, and ``__int__``. + + Importing ========= From 5d545019639407e60985c9112ba70685acc1d26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Sat, 24 Jul 2021 17:20:51 +0200 Subject: [PATCH 032/511] 32200: Rephrase section on integer return values --- src/doc/en/developer/coding_in_python.rst | 29 ++++++++++++++--------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/doc/en/developer/coding_in_python.rst b/src/doc/en/developer/coding_in_python.rst index f6ee0c9527d..c81d5736eb9 100644 --- a/src/doc/en/developer/coding_in_python.rst +++ b/src/doc/en/developer/coding_in_python.rst @@ -465,24 +465,31 @@ Note that the syntax in ``except`` is to list all the exceptions that are caught as a tuple, followed by an error message. -Integer Return Value -==================== +Integer Return Values +===================== -Many functions and methods of objects in Sage return an integer, which users -often treat mathematically and may want to explore its number-theoretic -properties such as prime factorization. Hence if a function or method for your -object returns an integer, consider returning Sage integer of type ``Integer`` -rather than Python integer of type ``int``, unless there is a good reason not -to (such as performance or compatibility with Python code). If ``i`` is an -integer of type ``int``, then code for the return statement would be +Many functions and methods in Sage return integer values. +Those should usually be returned as Sage integers of class +:class:`Integer ` rather than +as Python integers of class :class:`int`, as users may want +to explore the resulting integers' number-theoretic properties +such as prime factorization. Exceptions should be made when +there are good reasons such as performance or compatibility +with Python code, for instance in methods such as +``__hash__``, ``__len__``, and ``__int__``. + +To return a Python integer ``i`` as a Sage integer, use: .. CODE-BLOCK:: python from sage.rings.integer import Integer return Integer(i) -Notable definite exceptions to this rule are special methods like ``__hash__``, -``__len__``, and ``__int__``. +To return a Sage integer ``i`` as a Python ineger, use: + +.. CODE-BLOCK:: python + + return int(i) Importing From 56202355f5df69bd015014ade3a7a25732138240 Mon Sep 17 00:00:00 2001 From: Christian Wuthrich Date: Sat, 24 Jul 2021 19:26:55 +0100 Subject: [PATCH 033/511] trac 32258: add doctest --- .../schemes/elliptic_curves/padic_lseries.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index 030607b5c72..72250f3ed6b 100644 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -841,6 +841,20 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): sage: lp = E.padic_lseries(2) sage: lp.series(6) 2^2 + 2^6 + O(2^7) + (2 + O(2^4))*T + O(2^3)*T^2 + (2^2 + O(2^3))*T^3 + (2 + O(2^2))*T^4 + O(T^5) + + Check that twists by odd Teichmuller charachters are ok (:trac:`32258`):: + + sage: E = EllipticCurve("443c1") + sage: lp = E.padic_lseries(17, implementation="num") + sage: l8 = lp.series(2,eta=8,prec=3) + sage: l8.list()[0] - 1/lp.alpha() + O(17^4) + sage: lp = E.padic_lseries(2, implementation="num") + sage: l1 = lp.series(8,eta=1,prec=3) + sage: l1.list()[0] - 4/lp.alpha()^2 + O(2^9) + + """ n = ZZ(n) if n < 1: @@ -919,7 +933,7 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): gamma_power = K(1) teich = self.teichmuller(padic_prec) if p == 2: - teich = [0, 1,-1] + teich = [0, 1, -1] gamma = K(5) p_power = 2**(n-2) a_range = 3 From abdade36276e7c5c51fc2a818f599c667f0f1627 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 26 Jul 2021 17:56:57 -0400 Subject: [PATCH 034/511] 31994: return sorted list of preperiodic points --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 0d9f5d2557c..4a8e69a4084 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4182,6 +4182,7 @@ def preperiodic_points(self, m, n, **kwds): Z(list(Q)) except TypeError: good_points.append(Q) + good_points.sort() return good_points else: raise NotImplementedError("ring must a number field or finite field") @@ -4526,6 +4527,7 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari Z(list(Q)) except TypeError: good_points.append(Q) + good_points.sort() return good_points else: raise NotImplementedError("ring must be a number field or finite field") From 79cedf0b33140fe79ec40986b8ba673d1cf8ebfe Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 27 Jul 2021 15:48:47 -0400 Subject: [PATCH 035/511] 32199: fixed documentation issues --- .../endPN_automorphism_group.py | 58 +++++++++++-------- .../arithmetic_dynamics/projective_ds.py | 58 ++++++++++++------- 2 files changed, 69 insertions(+), 47 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index a6d77e854ac..c6fd4789978 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -1795,12 +1795,19 @@ def conjugating_set_initializer(f, g): Return a conjugation invariant set together with information to reduce the combinatorics of checking all possible conjugations. - This function constructs the conjugation invariant set (``source``) - necessary for the conjugating set algorithm described in [FMV2014]_. - Additionally, it keeps track of multipliers to reduce the combinatorics. + This function constructs the invariant pair (``source``, ``possible_targets``) + necessary for the conjugating set algorithm described in [FMV2014]_. + Let `f` and `g` be dynamical systems on `\mathbb{P}^n`. + An invariant pair is a pair of two sets `U`, `V` such that + `|U| = |V|` and for all `\phi \in PGL` such that `f^\phi = g`, + `\phi(u) \in V` for all `u \in U`. Invariant pairs can be used + to determine all conjugations from `f` to `g`. For details + in the `\mathbb{P}^1` case, see [FMV2014]_. + + Additionally, this function keeps track of multipliers to reduce the combinatorics. This information is then passed to ``conjugating_set_helper`` or ``is_conjugate_helper``, which check all possible conjugations determined - by the conjugation invariant set. + by the invariant pair. Do not call this function directly, instead use ``f.conjugating_set(g)``. @@ -2020,10 +2027,17 @@ def conjugating_set_initializer(f, g): def greedy_independence_check(P, repeated_mult, point_to_mult): r""" - Return a conjugation invariant set together with information + Return an invariant pair together with information to reduce the combinatorics of checking all possible conjugations. - This function may sometimes fail to find the conjugation invariant + Let `f` and `g` be dynamical systems on `\mathbb{P}^n`. + An invariant pair is a pair of two sets `U`, `V` such that + `|U| = |V|` and for all `\phi \in PGL` such that `f^\phi = g`, + `\phi(u) \in V` for all `u \in U`. Invariant pairs can be used + to determine all conjugations from `f` to `g`. For details + in the `\mathbb{P}^1` case, see [FMV2014]_. + + This function may sometimes fail to find the invariant pair set even though one exists. It is useful, however, as it is fast and returns a set which usually minimizes the combinatorics of checking all conjugations. @@ -2049,13 +2063,13 @@ def greedy_independence_check(P, repeated_mult, point_to_mult): Otherwise, a tuple of the form (``source``, ``corresponding``) is returned. - - ``source`` -- a conjugation invariant set of `n+2` points of the domain of `f`, - of which no `n+1` are linearly dependent. Used to specify a possible conjugation - from `f` to `g`. + - ``source`` -- the set `U` of the conjugation invariant pair. A set of `n+2` points + of the domain of `f`, of which no `n+1` are linearly dependent. - ``corresponding`` -- a list of tuples of the form ((multiplier, level), repeat) where the (multiplier, level) pair is the multiplier of a point in ``source`` and repeat - specifies how many points in source have that (multiplier, level) pair + specifies how many points in source have that (multiplier, level) pair. This + information specifies the set `V` of the invariant pair. EXAMPLES:: @@ -2092,18 +2106,17 @@ def conjugating_set_helper(f, g, num_cpus, source, possible_targets): Return the set of elements in PGL over the base ring that conjugates ``f`` to ``g``. - This function takes as input the conjugation invariant set + This function takes as input the invariant pair and multiplier data from ``conjugating_set_initializer``. - Do not call this function directly, instead do ``f.conjugate_set(g)``. + Do not call this function directly, instead use ``f.conjugate_set(g)``. INPUT: - ``f`` -- a rational function of degree at least 2, and the same degree as ``g`` - - ``g`` -- a rational function of the same - degree as ``f`` + - ``g`` -- a rational function of the same degree as ``f`` - ``num_cpus`` -- the number of threads to run in parallel @@ -2114,9 +2127,7 @@ def conjugating_set_helper(f, g, num_cpus, source, possible_targets): is a list of ``points`` which are possible targets for point(s) in ``source``. ``repeated`` specifies how many points in ``source`` have points in ``points`` as their possible target. - OUTPUT: - - a list of elements of PGL which conjugate ``f`` to ``g``. + OUTPUT: a list of elements of PGL which conjugate ``f`` to ``g``. EXAMPLES:: @@ -2239,18 +2250,17 @@ def is_conjugate_helper(f, g, num_cpus, source, possible_targets): r""" Return if ``f`` is conjugate to ``g``. - This function takes as input the conjugation invariant set + This function takes as input the invariant pair and multiplier data from ``conjugating_set_initializer``. - Do not call this function directly, instead do ``f.is_conjugate(g)``. + Do not call this function directly, instead use ``f.is_conjugate(g)``. INPUT: - ``f`` -- a rational function of degree at least 2, and the same degree as ``g`` - - ``g`` -- a rational function of the same - degree as ``f`` + - ``g`` -- a rational function of the same degree as ``f`` - ``num_cpus`` -- the number of threads to run in parallel @@ -2261,9 +2271,7 @@ def is_conjugate_helper(f, g, num_cpus, source, possible_targets): is a list of ``points`` which are possible targets for point(s) in ``source``. ``repeated`` specifies how many points in ``source`` have points in ``points`` as their possible target. - OUTPUT: - - ``True`` if ``f`` is conjugate to ``g``, ``False`` otherwise. + OUTPUT: ``True`` if ``f`` is conjugate to ``g``, ``False`` otherwise. EXAMPLES:: @@ -2375,4 +2383,4 @@ def find_conjugations_arrangement(tuples): break else: is_conj = find_conjugations_subset(product(*subset_iterators)) - return is_conj \ No newline at end of file + return is_conj diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 91402c18da3..96f0f4f4fc8 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -3250,7 +3250,7 @@ def automorphism_group(self, **kwds): The following keywords are used in most cases: - - ``num_cpus`` -- (default: 1) the number of threads to use. Setting to a + - ``num_cpus`` -- (default: 2) the number of threads to use. Setting to a larger number can greatly speed up this function. The following keywords are used only when the dimension of the domain is 1 and @@ -3285,14 +3285,14 @@ def automorphism_group(self, **kwds): EXAMPLES:: - sage: R. = ProjectiveSpace(QQ,1) + sage: R. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([x^2-y^2, x*y]) sage: f.automorphism_group(return_functions=True) [x, -x] :: - sage: R. = ProjectiveSpace(QQ,1) + sage: R. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([x^2 + 5*x*y + 5*y^2, 5*x^2 + 5*x*y + y^2]) sage: f.automorphism_group() [ @@ -3302,14 +3302,21 @@ def automorphism_group(self, **kwds): :: - sage: R. = ProjectiveSpace(QQ,1) + sage: P. = ProjectiveSpace(QQ, 2) + sage: f = DynamicalSystem([x^3, y^3, z^3]) + sage: len(f.automorphism_group()) + 24 + + :: + + sage: R. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([x^2-2*x*y-2*y^2, -2*x^2-2*x*y+y^2]) sage: f.automorphism_group(return_functions=True) [x, 1/x, -x - 1, -x/(x + 1), (-x - 1)/x, -1/(x + 1)] :: - sage: R. = ProjectiveSpace(QQ,1) + sage: R. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([3*x^2*y - y^3, x^3 - 3*x*y^2]) sage: lst, label = f.automorphism_group(algorithm='CRT', return_functions=True, iso_type=True) sage: sorted(lst), label @@ -3318,7 +3325,7 @@ def automorphism_group(self, **kwds): :: - sage: A. = AffineSpace(QQ,1) + sage: A. = AffineSpace(QQ, 1) sage: f = DynamicalSystem_affine([1/z^3]) sage: F = f.homogenize(1) sage: F.automorphism_group() @@ -3329,7 +3336,7 @@ def automorphism_group(self, **kwds): :: - sage: P. = ProjectiveSpace(QQ,2) + sage: P. = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem_projective([x**2 + x*z, y**2, z**2]) sage: f.automorphism_group() [ @@ -3353,7 +3360,7 @@ def automorphism_group(self, **kwds): p = kwds.get('starting_prime', 5) return_functions = kwds.get('return_functions', False) iso_type = kwds.get('iso_type', False) - num_cpus = kwds.get('num_cpus', 1) + num_cpus = kwds.get('num_cpus', 2) if self.domain().dimension_relative() != 1: return self.conjugating_set(self, num_cpus) if self.base_ring() != QQ and self.base_ring() != ZZ: @@ -6531,7 +6538,7 @@ def conjugating_set(self, other, R=None, num_cpus=2): EXAMPLES:: - sage: P. = ProjectiveSpace(QQ,1) + sage: P. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([x^2 - 2*y^2, y^2]) sage: m = matrix(QQbar, 2, 2, [-1, 3, 2, 1]) sage: g = f.conjugate(m) @@ -6543,15 +6550,15 @@ def conjugating_set(self, other, R=None, num_cpus=2): Increasing ``num_cpus`` can speed up computation:: - sage: P. = ProjectiveSpace(QQ,3) + sage: P. = ProjectiveSpace(QQ, 3) sage: f = DynamicalSystem_projective([x^2, y^2, z^2, w^2]) - sage: len(f.conjugating_set(f, num_cpus=2)) + sage: len(f.conjugating_set(f, num_cpus=3)) 24 :: sage: K. = QuadraticField(-1) - sage: P. = ProjectiveSpace(K,1) + sage: P. = ProjectiveSpace(K, 1) sage: f = DynamicalSystem_projective([x^2 + y^2, x*y]) sage: m = matrix(K, 2, 2, [1, 1, 2, 1]) sage: g = f.conjugate(m) @@ -6564,7 +6571,7 @@ def conjugating_set(self, other, R=None, num_cpus=2): :: sage: K. = QuadraticField(-1) - sage: P. = ProjectiveSpace(K,1) + sage: P. = ProjectiveSpace(K, 1) sage: D8 = DynamicalSystem_projective([y^3, x^3]) sage: sorted(D8.conjugating_set(D8)) [ @@ -6574,7 +6581,7 @@ def conjugating_set(self, other, R=None, num_cpus=2): :: - sage: P. = ProjectiveSpace(QQ,1) + sage: P. = ProjectiveSpace(QQ, 1) sage: D8 = DynamicalSystem_projective([y^2, x^2]) sage: D8.conjugating_set(D8) Traceback (most recent call last): @@ -6583,7 +6590,7 @@ def conjugating_set(self, other, R=None, num_cpus=2): :: - sage: P. = ProjectiveSpace(GF(7),1) + sage: P. = ProjectiveSpace(GF(7), 1) sage: D6 = DynamicalSystem_projective([y^2, x^2]) sage: D6.conjugating_set(D6) [ @@ -6593,7 +6600,7 @@ def conjugating_set(self, other, R=None, num_cpus=2): :: - sage: P. = ProjectiveSpace(QQ,2) + sage: P. = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem_projective([x^2 + x*z, y^2, z^2]) sage: f.conjugating_set(f) [ @@ -6623,7 +6630,7 @@ def conjugating_set(self, other, R=None, num_cpus=2): note that only one possible conjugation is returned:: - sage: P. = ProjectiveSpace(GF(11),2) + sage: P. = ProjectiveSpace(GF(11), 2) sage: f = DynamicalSystem_projective([2*x + 12*y, 11*y+2*z, x+z]) sage: m1 = matrix(GF(11), 3, 3, [1,4,1,0,2,1,1,1,1]) sage: g = f.conjugate(m1) @@ -6650,7 +6657,7 @@ def conjugating_set(self, other, R=None, num_cpus=2): Make sure the caching problem is fixed, see #28070 :: sage: K. = QuadraticField(-1) - sage: P. = ProjectiveSpace(QQ,1) + sage: P. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([x^2 - 2*y^2, y^2]) sage: m = matrix(QQ, 2, 2, [-1, 3, 2, 1]) sage: g = f.conjugate(m) @@ -6724,7 +6731,7 @@ def conjugating_set(self, other, R=None, num_cpus=2): if f.conjugate(m_emb) == g: return [m_emb] else: #finite field case - #always comes from prime field so an coerce + #always comes from prime field so can coerce m = matrix(base, M, M, [base(u.as_finite_field_element()[1]) for t in list(m) for u in t]) return [m] #not similar @@ -6740,7 +6747,7 @@ def conjugating_set(self, other, R=None, num_cpus=2): source, possible_targets = tup return conjugating_set_helper(f, g, num_cpus, source, possible_targets) - def is_conjugate(self, other, R=None, num_cpus=1): + def is_conjugate(self, other, R=None, num_cpus=2): r""" Return whether two dynamical systems are conjugate over their base ring (by default) or over the ring `R` entered as an @@ -6761,7 +6768,7 @@ def is_conjugate(self, other, R=None, num_cpus=1): - ``R`` -- a field or embedding - - ``num_cpus`` -- (default: 1) the number of threads to run in parallel. + - ``num_cpus`` -- (default: 2) the number of threads to run in parallel. Increasing ``num_cpus`` can potentially greatly speed up this function. OUTPUT: boolean @@ -6773,7 +6780,7 @@ def is_conjugate(self, other, R=None, num_cpus=1): - Implemented by Rebecca Lauren Miller as part of GSOC 2016. - - Algorithmic improvement by Alexander Galarraga as part of GSOC 2016. + - Algorithmic improvement by Alexander Galarraga as part of GSOC 2021. EXAMPLES:: @@ -7889,6 +7896,13 @@ def automorphism_group(self, **kwds): [1 0] [0 1] ]] + + :: + + sage: R. = ProjectiveSpace(GF(5), 2) + sage: f = DynamicalSystem_projective([x^3 + x*z^2, y^3 + y*z^2, z^3]) + sage: all([f.conjugate(m) == f for m in f.automorphism_group()]) + True """ absolute = kwds.get('absolute', False) iso_type = kwds.get('iso_type', False) From 6e4139efa630e66aabf5fcf8301032b573d61a36 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 29 Jul 2021 10:59:07 -0400 Subject: [PATCH 036/511] 32199: fixed call to is_linearly_independent --- .../arithmetic_dynamics/endPN_automorphism_group.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index c6fd4789978..a089419754b 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -2086,7 +2086,11 @@ def greedy_independence_check(P, repeated_mult, point_to_mult): for r in sorted(repeated_mult.keys()): for point_lst in repeated_mult[r]: for point in point_lst: - if P.is_linearly_independent(source + [point], n+1): + if len(source) == n+1: + independent = P.is_linearly_independent(source + [point], n+1) + else: + independent = P.is_linearly_independent(source + [point]) + if independent: source.append(point) mult = point_to_mult[point] # if another point with this multiplier and level pair is in S From 231862dc186b620cf0f00f7397cf0141b455d682 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Fri, 30 Jul 2021 22:53:49 +0800 Subject: [PATCH 037/511] make gcd() work on generators --- src/sage/arith/misc.py | 2 +- src/sage/rings/integer.pyx | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 83f3a957d17..e80488dcb93 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -1785,7 +1785,7 @@ def gcd(a, b=None, **kwargs): from sage.structure.sequence import Sequence seq = Sequence(py_scalar_to_element(el) for el in a) if seq.universe() is ZZ: - return GCD_list(a) + return GCD_list(seq) else: return __GCD_sequence(seq, **kwargs) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 14eec0c8c3b..80228f53d92 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -7148,13 +7148,14 @@ def GCD_list(v): sage: GCD_list([]) 0 """ + if not isinstance(v, list): + v = list(v) + cdef int i, n = len(v) cdef Integer z = PY_NEW(Integer) for i from 0 <= i < n: if not isinstance(v[i], Integer): - if not isinstance(v, list): - v = list(v) v[i] = Integer(v[i]) if n == 0: From 9a9e4d803feaa70dd30989ed4647b1f13581a5cf Mon Sep 17 00:00:00 2001 From: Alexander Galarraga Date: Sun, 25 Jul 2021 15:13:51 -0400 Subject: [PATCH 038/511] Remove deprecated parameters and methods in projective_ds --- .../arithmetic_dynamics/projective_ds.py | 143 +----------------- 1 file changed, 5 insertions(+), 138 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 7b53546f1ee..df9ef518420 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4787,7 +4787,8 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point'): multiplier spectra, which includes the multipliers of all periodic points of period ``n`` - - ``embedding`` -- deprecated in :trac:`23333` + - ``embedding`` -- (default: ``None``) must be ``None``, passing an embedding + is no longer supported, see :trac: `32205`. - ``type`` -- (default: ``'point'``) string; either ``'point'`` or ``'cycle'`` depending on whether you compute with one @@ -4892,6 +4893,9 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point'): [2, 4*t/(t^2 + 1), 0] """ n = ZZ(n) + + if not embedding is None: + raise ValueError('do not specify an embedding') if n < 1: raise ValueError("period must be a positive integer") dom = self.domain() @@ -4899,9 +4903,6 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point'): raise NotImplementedError("not implemented for subschemes") if dom.dimension_relative() > 1: raise NotImplementedError("only implemented for dimension 1") - if not embedding is None: - from sage.misc.superseded import deprecation - deprecation(23333, "embedding keyword no longer used") if self.degree() <= 1: raise TypeError("must have degree at least 2") if not type in ['point', 'cycle']: @@ -5896,72 +5897,6 @@ def all_periodic_points(self, **kwds): else: raise TypeError("base field must be an absolute number field") - def rational_periodic_points(self, **kwds): - r""" - Determine the set of rational periodic points - for this dynamical system. - - The map must be defined over `\QQ` and be an endomorphism of - projective space. If the map is a polynomial endomorphism of - `\mathbb{P}^1`, i.e. has a totally ramified fixed point, then - the base ring can be an absolute number field. - This is done by passing to the Weil restriction. - - The default parameter values are typically good choices for - `\mathbb{P}^1`. If you are having trouble getting a particular - map to finish, try first computing the possible periods, then - try various different ``lifting_prime`` values. - - ALGORITHM: - - Modulo each prime of good reduction `p` determine the set of - periodic points modulo `p`. For each cycle modulo `p` compute - the set of possible periods (`mrp^e`). Take the intersection - of the list of possible periods modulo several primes of good - reduction to get a possible list of minimal periods of rational - periodic points. Take each point modulo `p` associated to each - of these possible periods and try to lift it to a rational point - with a combination of `p`-adic approximation and the LLL basis - reduction algorithm. - - See [Hutz2015]_. - - INPUT: - - kwds: - - - ``prime_bound`` -- (default: ``[1,20]``) a pair (list or tuple) - of positive integers that represent the limits of primes to use - in the reduction step or an integer that represents the upper bound - - - ``lifting_prime`` -- (default: 23) a prime integer; argument that - specifies modulo which prime to try and perform the lifting - - - ``periods`` -- (optional) a list of positive integers that is - the list of possible periods - - - ``bad_primes`` -- (optional) a list or tuple of integer primes; - the primes of bad reduction - - - ``ncpus`` -- (default: all cpus) number of cpus to use in parallel - - OUTPUT: a list of rational points in projective space - - EXAMPLES:: - - sage: R. = QQ[] - sage: K. = NumberField(x^2-x+1) - sage: P. = ProjectiveSpace(K,1) - sage: f = DynamicalSystem_projective([u^2 + v^2,v^2]) - sage: sorted(f.rational_periodic_points()) - doctest:warning - ... - [(-w + 1 : 1), (w : 1), (1 : 0)] - """ - from sage.misc.superseded import deprecation - deprecation(28109, "use sage.dynamics.arithmetic_dynamics.projective_ds.all_periodic_points instead") - return self.all_periodic_points(**kwds) - def all_rational_preimages(self, points): r""" Given a set of rational points in the domain of this @@ -6045,74 +5980,6 @@ def all_rational_preimages(self, points): preperiodic.add(preimages[i]) return list(preperiodic) - def rational_preperiodic_points(self, **kwds): - r""" - Determine the set of rational preperiodic points for - this dynamical system. - - The map must be defined over `\QQ` and be an endomorphism of - projective space. If the map is a polynomial endomorphism of - `\mathbb{P}^1`, i.e. has a totally ramified fixed point, then - the base ring can be an absolute number field. - This is done by passing to the Weil restriction. - - The default parameter values are typically good choices for - `\mathbb{P}^1`. If you are having trouble getting a particular - map to finish, try first computing the possible periods, then - try various different values for ``lifting_prime``. - - ALGORITHM: - - - Determines the list of possible periods. - - - Determines the rational periodic points from the possible periods. - - - Determines the rational preperiodic points from the rational - periodic points by determining rational preimages. - - INPUT: - - kwds: - - - ``prime_bound`` -- (default: ``[1, 20]``) a pair (list or tuple) - of positive integers that represent the limits of primes to use - in the reduction step or an integer that represents the upper bound - - - ``lifting_prime`` -- (default: 23) a prime integer; specifies - modulo which prime to try and perform the lifting - - - ``periods`` -- (optional) a list of positive integers that is - the list of possible periods - - - ``bad_primes`` -- (optional) a list or tuple of integer primes; - the primes of bad reduction - - - ``ncpus`` -- (default: all cpus) number of cpus to use in parallel - - - ``period_degree_bounds`` -- (default: ``[4,4]``) a pair of positive integers - (max period, max degree) for which the dynatomic polynomial should be solved - for when in dimension 1 - - - ``algorithm`` -- (optional) specifies which algorithm to use; - current options are `dynatomic` and `lifting`; defaults to solving the - dynatomic for low periods and degrees and lifts for everything else - - OUTPUT: a list of rational points in projective space - - EXAMPLES:: - - sage: PS. = ProjectiveSpace(1,QQ) - sage: f = DynamicalSystem_projective([x^2 -y^2, 3*x*y]) - sage: sorted(f.rational_preperiodic_points()) - doctest:warning - ... - [(-2 : 1), (-1 : 1), (-1/2 : 1), (0 : 1), (1/2 : 1), (1 : 0), (1 : 1), - (2 : 1)] - """ - from sage.misc.superseded import deprecation - deprecation(28213, "use sage.dynamics.arithmetic_dynamics.projective_ds.all_preperiodic_points instead") - return self.all_preperiodic_points(**kwds) - def all_preperiodic_points(self, **kwds): r""" Determine the set of rational preperiodic points for From 13de775ac290b351d1f5dfb934a45833a1c05ed1 Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Mon, 2 Aug 2021 19:41:10 -0400 Subject: [PATCH 039/511] 32328: initial commit --- .../arithmetic_dynamics/projective_ds.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 7b53546f1ee..85f9c2b09c0 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -5419,6 +5419,53 @@ def _is_preperiodic(self, P, err=0.1, return_period=False): else: return False + def post_critical_set(self): + r""" + Return the post critical set of this dynamical system. + + Raises an error if this dynamical system is not post-critically finite. + + Note that the orbit of all critical points is found, even if the + critical points are defined in an extension of the base ring of + this dynamical system. + + OUTPUT: The combined orbits of the critical points, as a set + + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([x^3 - 3/2* x*y^2, y^3]) + sage: f.post_critical_set() + [(-1/2*a : 1), (1/2*a : 1), (1 : 0)] + + :: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([3*x^3 - 9/2* x^2*y+y^3, y^3]) + sage: f.post_critical_set() + [(0 : 1), (1 : 1), (-1/2 : 1), (1 : 0)] + + :: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem([-4*y^2, 9*x^2 - 12*x*y]) + sage: f.post_critical_set() + [(2/3 : 1), (1 : 1), (4/3 : 1), (1 : 0), (0 : 1)] + """ + if not is_ProjectiveSpace(self.domain()): + raise ValueError('must not be a dynamical system on a subscheme') + if self.domain().dimension_relative() != 1: + raise ValueError('must be defined on projective space of dimension 1') + f = self.change_ring(self.field_of_definition_critical()) + critical_points = f.critical_points() + post_critical_list = [] + for point in critical_points: + next_point = point + while not(next_point in post_critical_list): + post_critical_list.append(next_point) + next_point = f(next_point) + return post_critical_list + class DynamicalSystem_projective_field(DynamicalSystem_projective, SchemeMorphism_polynomial_projective_space_field): From f8e7d19ec2ae40d2cd46ea51aef18b17c12f6d15 Mon Sep 17 00:00:00 2001 From: bhutz Date: Tue, 3 Aug 2021 07:53:56 -0500 Subject: [PATCH 040/511] 32155: remove unused import --- src/sage/schemes/projective/projective_space.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 1d43737a98d..2d6f327c4ca 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -79,7 +79,6 @@ # http://www.gnu.org/licenses/ # **************************************************************************** -from typing import Type from sage.arith.all import gcd, binomial, srange from sage.rings.all import (PolynomialRing, Integer, From 2e320b59aa963bd76d3e03f484fbb4aa235c890f Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Tue, 3 Aug 2021 12:47:02 -0400 Subject: [PATCH 041/511] 32328: added examples and fixed errors --- .../arithmetic_dynamics/projective_ds.py | 63 ++++++++++++++----- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 85f9c2b09c0..f5da0eabb30 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -5419,48 +5419,83 @@ def _is_preperiodic(self, P, err=0.1, return_period=False): else: return False - def post_critical_set(self): + def postcritical_set(self, check=True): r""" - Return the post critical set of this dynamical system. + Return the postcritical set of this dynamical system. - Raises an error if this dynamical system is not post-critically finite. + Raises an error if this dynamical system is not postcritically finite. + + The postcritical set is union of points which are in the forward orbits + of the critical points. In other words, the set of points `Q` such that + `f^n(P) = Q` for some positive integer `n` and critical point `P`, where + `f` is this map. Note that the orbit of all critical points is found, even if the critical points are defined in an extension of the base ring of - this dynamical system. + this dynamical system. We extend to the field defined by + ``f.field_of_definition_critical()``, where ``f`` is this map. + + INPUT: - OUTPUT: The combined orbits of the critical points, as a set + - ``check`` -- (default: ``True``) boolean; whether to check + if this dynamical system is postcritically finite or not. + + OUTPUT: The set of postcritical points. EXAMPLES:: sage: P. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem([x^3 - 3/2* x*y^2, y^3]) - sage: f.post_critical_set() - [(-1/2*a : 1), (1/2*a : 1), (1 : 0)] + sage: f.postcritical_set() + [(1/2*a : 1), (-1/2*a : 1), (1 : 0)] :: sage: P. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem([3*x^3 - 9/2* x^2*y+y^3, y^3]) - sage: f.post_critical_set() - [(0 : 1), (1 : 1), (-1/2 : 1), (1 : 0)] + sage: f.postcritical_set(check=False) + [(1 : 1), (-1/2 : 1), (1 : 0)] :: sage: P. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem([-4*y^2, 9*x^2 - 12*x*y]) - sage: f.post_critical_set() - [(2/3 : 1), (1 : 1), (4/3 : 1), (1 : 0), (0 : 1)] + sage: f.postcritical_set() + [(1 : 1), (4/3 : 1), (1 : 0), (0 : 1)] + + :: + + sage: K. = QuadraticField(2) + sage: P. = ProjectiveSpace(K,1) + sage: f = DynamicalSystem([x^2 + (-2)*y^2, y^2]) + sage: m = matrix(K, 2, 2, [v, 1, 0, 1]) + sage: g = f.conjugate(m) + sage: g.postcritical_set() + [(-3/2*a : 1), (1/2*a : 1), (1 : 0)] + + :: + + sage: F. = FiniteField(9) + sage: P. = ProjectiveSpace(F, 1) + sage: f = DynamicalSystem([x^2 + (-2)*y^2, y^2]) + sage: m = matrix(F, 2, 2, [z, 1, 0, 1]) + sage: g = f.conjugate(m) + sage: g.postcritical_set() + [(1 : 0), (0 : 1), (a + 2 : 1)] """ if not is_ProjectiveSpace(self.domain()): - raise ValueError('must not be a dynamical system on a subscheme') + raise ValueError('must be a dynamical system on projective space') if self.domain().dimension_relative() != 1: raise ValueError('must be defined on projective space of dimension 1') - f = self.change_ring(self.field_of_definition_critical()) + if check: + if not self.is_postcritically_finite(): + raise ValueError('map must be postcritically finite') + new_base_ring = self.field_of_definition_critical(return_embedding=True)[1] + f = self.change_ring(new_base_ring) critical_points = f.critical_points() post_critical_list = [] for point in critical_points: - next_point = point + next_point = f(point) while not(next_point in post_critical_list): post_critical_list.append(next_point) next_point = f(next_point) From eb218c1ee74abe7aeafaba8b6077246c33d85ca1 Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Wed, 4 Aug 2021 12:10:21 -0700 Subject: [PATCH 042/511] 32199: removed unused imports attempted fix for example --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 3 --- src/sage/schemes/projective/projective_space.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index f39c31b98f2..8fcc4e9f0d4 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -104,9 +104,6 @@ class initialization directly. from sage.parallel.ncpus import ncpus from sage.parallel.use_fork import p_iter_fork from sage.dynamics.arithmetic_dynamics.projective_ds_helper import (_fast_possible_periods,_all_periodic_points) -from sage.sets.set import Set -from sage.combinat.permutation import Arrangements -from sage.combinat.subset import Subsets from sage.symbolic.ring import SR from itertools import count, product from .endPN_automorphism_group import ( diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 2d6f327c4ca..95a4cfcb058 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -1728,7 +1728,7 @@ def is_linearly_independent(self, points, n=None): EXAMPLES:: - sage: P. = ProjectiveSpace(ZZ, 2) + sage: P. = ProjectiveSpace(QQ, 2) sage: points = [P((1, 0, 1)), P((1, 2, 1)), P((1, 3, 4))] sage: P.is_linearly_independent(points) True From 0f73fcd3009b174d88c6dc67a7a4e55afeaa6adb Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Thu, 5 Aug 2021 10:58:44 -0700 Subject: [PATCH 043/511] 32199: changed check in examples --- .../endPN_automorphism_group.py | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index a089419754b..e5ef59acf59 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -1831,17 +1831,21 @@ def conjugating_set_initializer(f, g): is a list of ``points`` which are possible targets for point(s) in ``source``. ``repeated`` specifies how many points in ``source`` have points in ``points`` as their possible target. - EXAMPLES:: + EXAMPLES: + + We check that ``source`` has no `n+1` linearly dependent points, and that + ``possible_targets`` tracks multiplier information:: sage: P. = ProjectiveSpace(QQ, 2) sage: f = DynamicalSystem([(8*x^7 - 35*x^4*y^3 - 35*x^4*z^3 - 7*x*y^6 - 140*x*y^3*z^3 \ - 7*x*z^6), (-7*x^6*y - 35*x^3*y^4 - 140*x^3*y*z^3 + 8*y^7 - 35*y^4*z^3 \ - 7*y*z^6), -7*x^6*z - 140*x^3*y^3*z - 35*x^3*z^4 - 7*y^6*z - 35*y^3*z^4 + 8*z^7]) sage: from sage.dynamics.arithmetic_dynamics.endPN_automorphism_group import conjugating_set_initializer - sage: conjugating_set_initializer(f, f) - ([(-1 : 0 : 1), (0 : -1 : 1), (0 : 1 : 0), (1 : 0 : 0)], - [[[(-1 : 0 : 1), (0 : -1 : 1), (-1 : 1 : 0)], 2], - [[(0 : 1 : 0), (1 : 0 : 0), (1 : 1 : 1), (0 : 0 : 1)], 2]]) + sage: source, possible_targets = conjugating_set_initializer(f, f) + sage: P.is_linearly_independent(source, 3) + True + sage: f.multiplier(possible_targets[0][0][0], 1) == f.multiplier(source[0], 1) + True """ n = f.domain().dimension_relative() @@ -2140,10 +2144,10 @@ def conjugating_set_helper(f, g, num_cpus, source, possible_targets): sage: source = [P((1, 1)), P((0, 1)), P((1, 0))] sage: possible_targets = [[[P((1, 1))], 1], [[P((0, 1)), P((1, 0))], 2]] sage: from sage.dynamics.arithmetic_dynamics.endPN_automorphism_group import conjugating_set_helper - sage: conjugating_set_helper(f, f, 2, source, possible_targets) + sage: sorted(conjugating_set_helper(f, f, 2, source, possible_targets)) [ - [1 0] [0 1] - [0 1], [1 0] + [0 1] [1 0] + [1 0], [0 1] ] """ Conj = [] From e6a3c5dfeca8e37ce61efe25dbb3473475ba912c Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Fri, 6 Aug 2021 19:54:07 +0800 Subject: [PATCH 044/511] undo earlier list cast in GCD_list --- src/sage/rings/integer.pyx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 80228f53d92..14eec0c8c3b 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -7148,14 +7148,13 @@ def GCD_list(v): sage: GCD_list([]) 0 """ - if not isinstance(v, list): - v = list(v) - cdef int i, n = len(v) cdef Integer z = PY_NEW(Integer) for i from 0 <= i < n: if not isinstance(v[i], Integer): + if not isinstance(v, list): + v = list(v) v[i] = Integer(v[i]) if n == 0: From 05cfb4ef31bfe7542027498ffd1f6a76ba5f22ba Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Tue, 13 Jul 2021 01:15:46 -0600 Subject: [PATCH 045/511] Draft implementation of fast Cp basis for IwahoriHeckeAlgebra --- src/sage/algebras/iwahori_hecke_algebra.py | 106 +++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index ae50b39a3e0..ab86c1d56a1 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -32,6 +32,8 @@ from sage.combinat.root_system.coxeter_group import CoxeterGroup from sage.combinat.family import Family from sage.combinat.free_module import CombinatorialFreeModule +from sage.algebras.free_algebra import FreeAlgebra +from sage.libs.coxeter3.coxeter_group import CoxeterGroup as Coxeter3Group def normalized_laurent_polynomial(R, p): @@ -1948,6 +1950,110 @@ def hash_involution_on_basis(self, w): C_prime = Cp + class Cp_native(_Basis): + _basis_name = 'Cp_native' + + def __init__(self, algebra, prefix='Cp'): + if not isinstance(algebra._W, Coxeter3Group): + raise ValueError('Algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_native basis.') + + super(IwahoriHeckeAlgebra.Cp_native, self).__init__(algebra, prefix) + + self._W = algebra._W + self.gen_algebra = FreeAlgebra(algebra.base_ring(), ['g' + str(i) for i in self.index_set()]) + self.delta = algebra.q1() - algebra.q2() + + def _product_with_generator_on_basis(self, side, s, w): + # C_s * C_w = (v + 1/v) * C_w if s is a left descent, otherwise: + # Left: C_s * C_w = C_{sw} + \sum_{sx < x < w} mu(x, w) C_x + # Right: C_w * C_s = C_{ws} + \sum_{xs < x < w} mu(x, w) C_x + + if w.has_descent(s, side=side): + return self.delta * self.monomial(w) + else: + element = self(0) + between = self._W.bruhat_interval([], w) + for x in between: + x_elt = self._W(x) + if x_elt.has_descent(s, side=side): + element += x.mu_coefficient(w) * self.monomial(x_elt) + + # Doing self._W([s]) * w may not ensure that the word is is normal form + # Since W's element constructor does ensure that, use this method. + longer_word = self._W([s] + list(w) if side == 'left' else list(w) + [s]) + return self.monomial(longer_word) + element + + def _product_with_generator(self, side, s, x): + return self.linear_combination((self._product_with_generator_on_basis(side, s, w), coeff) for (w, coeff) in x) + + def _decompose_into_generators(self, w): + r""" + Returns an element of self.gen_algebra, a free algebra over {g_1, ..., g_n} + describing how to write 'word' in terms of the generators + """ + gs = self.gen_algebra.gens() + if len(w) == 0: + return self.gen_algebra(1) + if len(w) == 1: + return gs[w[0]] + + s = w[0] + w1 = w[1:] + + # We have C_w = C_s * C_{w1} + # Use the reverse of the left-multiplication by generator rule: + # We know s is not a left descent, so + # C_w = C_s * C_{w1} - \sum_{sy < y < w1} C_y + + # The sum from the above + rest = self(0) + between = self._W.bruhat_interval([], w1) + for x in between: + x_elt = self._W(x) + if x_elt.has_left_descent(s): + rest += self.base_ring()(x.mu_coefficient(w1)) * self.monomial(x_elt) + + # In the expression above, we need to recurse and decompose C_{w1} into generators, + # and then go through the terms of the sum 'rest' and decompose those C_y's into generators + alg_element = gs[s] * self._decompose_into_generators(w1) + for (v, coeff) in rest: + # We're subtracting 'rest' + alg_element -= coeff * self._decompose_into_generators(v) + + return alg_element + + def product_on_basis(self, w1, w2): + # Otherwise, decompose the first word into generators + # (as expressed as an element of the FreeAlgebra over 'generator' variables g1, ..., gn) + if len(w1) <= len(w2): + side = 'left' + gens = self._decompose_into_generators(w1) + other_element = self.monomial(w2) + else: + side = 'right' + gens = self._decompose_into_generators(w2) + other_element = self.monomial(w1) + + # Now, build everything back up, continually multiplying on the left by a single generator + # Multiply gens by other_element, doing "manual distribution" + + result = self(0) + for (p, coeff) in gens: + # p is a product of generators, i.e. 2*g1*g2*g1; multiply it by other_element + # Build summand multiplicatively, going through variables and thier powers in p + # If gens are on the right, we need to start at the left end of p, and vice versa. + summand = coeff * other_element + p_list = list(p) if side == 'right' else list(p)[::-1] + for (g, power) in p_list: + s = self.gen_algebra.gens().index(g) + # Multiply this_element on the apppropriate side by the generator this variable g corresponds to + for i in range(power): + summand = self._product_with_generator(side, s, summand) + + result += summand + + return result + class C(_KLHeckeBasis): r""" The Kazhdan-Lusztig `C`-basis of Iwahori-Hecke algebra. From 37333ba11ace9c857242f2e9d079d1031d01c506 Mon Sep 17 00:00:00 2001 From: Tianyuan Xu Date: Mon, 19 Jul 2021 18:40:58 -0600 Subject: [PATCH 046/511] first doc change for Cp_Coxeter3 class --- src/sage/algebras/iwahori_hecke_algebra.py | 131 +++++++++++++++++++-- 1 file changed, 124 insertions(+), 7 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index ab86c1d56a1..16b14181cc4 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -8,6 +8,11 @@ - Brant Jones, Travis Scrimshaw, Andrew Mathas (2013): Moved into the category framework and implemented the Kazhdan-Lusztig `C` and `C^{\prime}` bases + +- Chase Meadors, Tianyuan Xu (2021): + Implemented direct computation of products in the + `C^{\prime}` basis using du Cloux's Coxeter3 package + """ # **************************************************************************** # Copyright (C) 2013 Brant Jones @@ -1950,23 +1955,120 @@ def hash_involution_on_basis(self, w): C_prime = Cp - class Cp_native(_Basis): - _basis_name = 'Cp_native' + class Cp_Coxeter3(_Basis): + r""" + Directly compute products in the `C^{\prime}`-basis by using du Cloux's Coxeter3 package. + + [State assumptions] normalization/coxeter3 implementation + + Expanding products of the form `C^{\prime}_x \cdot C^{\prime}_y` in the `C^{\prime}`-basis is useful for + computing Kazhdan-Lusztig cells of Coxeter systems and the corresponding cell modules of Iwahori-Hecke + algebras. Such expansion is controlled by the following formula (and the analogous formula for + `C^{\prime}_s \cdot C^{\prime}_w`) under both the "standard" and the "normalized" presentations of the + Iwahori-Hecke algebra, where the quadratic relation is `(T_s-q^2)(T_s+1)=0` and `(T_s-q)(T_s+q^-1)=0` for + each generator `s`, respectively. + + .. MATH:: + C^{\prime}_s \cdot C^{\prime}_w = + \begin{cases} + (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ + C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, & \text{if } \ell(sw) = \ell(w)+1. + \end{cases} + + where `\leq` is the Bruhat order on the underlying Coxeter group and `\mu(v,w)` is the "leading coefficient + of Kazhdan-Lusztig polynomials"; see [KL1979]_ and [Lus2014]_ for more details. + + The emphasis of this class is to compute products in the `C^{\prime}`-basis directly, by using the above + formula and calling the necessary `\mu`-coefficients from Sage's implementation of Fokko du Cloux's + Coxeter3 package. This methods computes the products faster than the _Basis.product_on_basis method on Line + 1298, which needs to convert the `C^{\prime}`-basis to the `T`-basis, calculate the product in the + `T`-basis, and convert the results back to the `C^{\prime}`-basis. For example, the product + `C^{\prime}_{32345} * C^{\prime}_{23}` in the Hecke algebra of type 'B_9' takes more than 30 seconds with + the latter method but is instant using this class. + + .. TODO:: + Use the analog of the displayed formula to implement `C^{\prime}`-products in the multi-parameter + Iwahori-Hecke algebra; see Section 6 of [Lus2013]_. + + EXAMPLES:: + + sage: R = LaurentPolynomialRing(QQ, 'q') + [A3 examples with warnings caused by wrong presentation or implementation...] + + Create the Hecke algebra of type 'A3' and label the `C^{\prime}`-basis by `B`: + + sage: H = IwahoriHeckeAlgebra('A3',implementation = 'coxeter3') + sage: B = H.Cp_Coxeter3() [careful about printing: B or Cp] + + Product of the form `B_s \cdot B_y` where `s` is a generator are computed by the earlier formula:: + + sage: B[1] * B[1] + (q^-1+q) * B[1] + sage: B[1] * B[2] + B[1,2] + sage: B[1] * B[2,1] + B[1,2,1] + B[1] + sage: B[1] * B[2,1,3] + B[1,2,3,1] + B[3,1] + sage: B[2] * B[1,3,2,1,3] + B[1,2,3,1,2,1] + Cp[2,3,2,1] + Cp[1,2,3,1] + + + More generally, we can compute products of the form 'B_x \cdot B_y` for general `x, y`:: + + sage: B[1,2,1] * B[3,1] + (q^-1+q)*B[1,2,3,1] + sage: B[1,2,1] * B[3,1,2] (q^-1+q)*B[1,2,3,1,2] + (q^-1+q)*B[1,2,1] + + [More examples: B9 examples; showcase labelling, compare speed with the indirect method ] + + + .. NOTE:: + + The products `B_x \cdot B_y` are computed as follows: if `\ell(x) \leq \ell(y)`, then we first + decompose `B_x` into a linear combination of products of generators `B_s (s\in S)`, then multiplies + that linear combination onto `B_y`; otherwise we decompose `B_y` and multiply the result onto + `B_x`. For example, in the computation of `B[1,2,1] * B[3,1,2]` in type `A3`, the left term + `B[1,2,1]` is first (essentially) decomposed into the linear combination `B[1]*B[2]*B[1] - B[1]` + behind the scenes. The decomposition is achieved via the [_decompose_into_generators function], + which in turn uses an auxiliary free algebra with generators corresponding to the Coxeter + generators. + + .. SEEALSO:: + + :ref: [KL1979]_, [Lus2013]_ + :meth:`sage.somewhere.other_useful_method`, + [coxeter3?] + + TESTS:: + + [show our direct method yields the same results as the indirect method?] + + """ + _basis_name = 'Cp_Coxeter3' def __init__(self, algebra, prefix='Cp'): if not isinstance(algebra._W, Coxeter3Group): - raise ValueError('Algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_native basis.') + raise ValueError('Algebra must be initialized with a coxeter3-implemented Coxeter group to use the + Cp_Coxeter3 basis.') super(IwahoriHeckeAlgebra.Cp_native, self).__init__(algebra, prefix) self._W = algebra._W + self.delta = q + q^{-1} #[better way to write this, maybe q as R.gen(0)?] + + #[can we move the following to _decompose_into_generators and avoid it in the manual distribution part + # of product_on_basis? Not a big deal; we could also use the comment below.] + + # the auxiliary free algebra mentioned in ..NOTE:: self.gen_algebra = FreeAlgebra(algebra.base_ring(), ['g' + str(i) for i in self.index_set()]) - self.delta = algebra.q1() - algebra.q2() def _product_with_generator_on_basis(self, side, s, w): - # C_s * C_w = (v + 1/v) * C_w if s is a left descent, otherwise: - # Left: C_s * C_w = C_{sw} + \sum_{sx < x < w} mu(x, w) C_x - # Right: C_w * C_s = C_{ws} + \sum_{xs < x < w} mu(x, w) C_x + r""" + Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting `C^{\prime}_s` on the given ``side``. + + [recycle the examples from the class' documentation, or not?] + """ if w.has_descent(s, side=side): return self.delta * self.monomial(w) @@ -1984,13 +2086,20 @@ def _product_with_generator_on_basis(self, side, s, w): return self.monomial(longer_word) + element def _product_with_generator(self, side, s, x): + r""" + Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elemens. + """ return self.linear_combination((self._product_with_generator_on_basis(side, s, w), coeff) for (w, coeff) in x) def _decompose_into_generators(self, w): r""" Returns an element of self.gen_algebra, a free algebra over {g_1, ..., g_n} describing how to write 'word' in terms of the generators + + [need a good running example or several examples, maybe including how C_121=C_1*C_2*C_1-C_1 in type A; + decomposing from one side is probably enough in the example(s)] """ + gs = self.gen_algebra.gens() if len(w) == 0: return self.gen_algebra(1) @@ -2023,6 +2132,11 @@ def _decompose_into_generators(self, w): return alg_element def product_on_basis(self, w1, w2): + r""" + Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` in the `C^{\prime}`-basis. + + [recycle example from class' doc?] + """ # Otherwise, decompose the first word into generators # (as expressed as an element of the FreeAlgebra over 'generator' variables g1, ..., gn) if len(w1) <= len(w2): @@ -2034,6 +2148,9 @@ def product_on_basis(self, w1, w2): gens = self._decompose_into_generators(w2) other_element = self.monomial(w1) + # [I'm a little confused by 'powers' below; also, should we write a helper function earlier for the 'manual + # distribution'?] + # Now, build everything back up, continually multiplying on the left by a single generator # Multiply gens by other_element, doing "manual distribution" From a5e4808962183a02deaf600cb59dd38232912513 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Tue, 20 Jul 2021 16:35:34 -0600 Subject: [PATCH 047/511] Tweak to compile; change error message to python convention --- src/sage/algebras/iwahori_hecke_algebra.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 16b14181cc4..5a6a187bb19 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2049,13 +2049,12 @@ class Cp_Coxeter3(_Basis): def __init__(self, algebra, prefix='Cp'): if not isinstance(algebra._W, Coxeter3Group): - raise ValueError('Algebra must be initialized with a coxeter3-implemented Coxeter group to use the - Cp_Coxeter3 basis.') + raise ValueError('algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis') - super(IwahoriHeckeAlgebra.Cp_native, self).__init__(algebra, prefix) + super(IwahoriHeckeAlgebra.Cp_Coxeter3, self).__init__(algebra, prefix) self._W = algebra._W - self.delta = q + q^{-1} #[better way to write this, maybe q as R.gen(0)?] + self.delta = algebra.q1() + ~algebra.q1() #[better way to write this, maybe q as R.gen(0)?] #[can we move the following to _decompose_into_generators and avoid it in the manual distribution part # of product_on_basis? Not a big deal; we could also use the comment below.] From e137d1c8af7f678bd93dcd0189b2fc1e8e2e02dd Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Tue, 20 Jul 2021 16:37:22 -0600 Subject: [PATCH 048/511] Implement coercions between Cp_Coxeter3 and the other bases --- src/sage/algebras/iwahori_hecke_algebra.py | 49 ++++++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 5a6a187bb19..70ca468ddd9 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1581,6 +1581,11 @@ def to_Cp_basis(self, w): generic_T = H._generic_iwahori_hecke_algebra.T() return generic_T.to_Cp_basis(w).specialize_to(H) + def to_Cp_Coxeter3_basis(self, w): + H = self.realization_of() + generic_T = H._generic_iwahori_hecke_algebra.T() + return generic_T.to_Cp_Coxeter3_basis(w).specialize_to(H) + def bar_on_basis(self, w): """ Return the bar involution of `T_w`, which is `T^{-1}_{w^-1}`. @@ -1932,6 +1937,11 @@ class Cp(_KLHeckeBasis): """ _basis_name = 'Cp' # this is used, for example, by specialize_to and is the default prefix + def to_Cp_Coxeter3_basis(self, w): + A = self.realization_of() + Cp = A.Cp_Coxeter3() + return Cp.monomial(w) + def hash_involution_on_basis(self, w): r""" Return the effect of applying the hash involution to the basis @@ -1955,7 +1965,7 @@ def hash_involution_on_basis(self, w): C_prime = Cp - class Cp_Coxeter3(_Basis): + class Cp_Coxeter3(_KLHeckeBasis): r""" Directly compute products in the `C^{\prime}`-basis by using du Cloux's Coxeter3 package. @@ -2062,6 +2072,19 @@ def __init__(self, algebra, prefix='Cp'): # the auxiliary free algebra mentioned in ..NOTE:: self.gen_algebra = FreeAlgebra(algebra.base_ring(), ['g' + str(i) for i in self.index_set()]) + # Define conversion to the other Cp basis + self.module_morphism(self.to_Cp_basis, codomain=algebra.Cp(), category=self.category() + ).register_as_coercion() + + # ...and from the other Cp basis to the Cp_Coxeter3 basis + Cp = algebra.Cp() + Cp.module_morphism(Cp.to_Cp_Coxeter3_basis, codomain=self, category=self.category()).register_as_coercion() + + def to_Cp_basis(self, w): + A = self.realization_of() + Cp = A.Cp() + return Cp.monomial(w) + def _product_with_generator_on_basis(self, side, s, w): r""" Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting `C^{\prime}_s` on the given ``side``. @@ -2739,9 +2762,9 @@ class T(IwahoriHeckeAlgebra.T): r""" The `T`-basis for the generic Iwahori-Hecke algebra. """ - @cached_method - def to_Cp_basis(self, w): + def _to_Cp_basis(self, w, Cp): r""" + TODO: Change this documentation and the two below Return `T_w` as a linear combination of `C^{\prime}`-basis elements. @@ -2765,7 +2788,7 @@ def to_Cp_basis(self, w): + (u^-2*v^5)*Cp[1] + (u^-2*v^5)*Cp[2] + (-u^-3*v^6) """ A = self.realization_of() - Cp = A.Cp() + # Cp = A.Cp() if not use_Cp_Coxeter3 else A.Cp_Coxeter3() if w == A._W.one(): # the identity element of the Coxeter group return Cp.one() @@ -2780,6 +2803,16 @@ def to_Cp_basis(self, w): return result + @cached_method + def to_Cp_basis(self, w): + A = self.realization_of() + return self._to_Cp_basis(w, A.Cp()) + + @cached_method + def to_Cp_Coxeter3_basis(self, w): + A = self.realization_of() + return self._to_Cp_basis(w, A.Cp_Coxeter3()) + @cached_method def to_C_basis(self, w): r""" @@ -2891,6 +2924,14 @@ def key_func(x): C_prime = Cp + class Cp_Coxeter3(IwahoriHeckeAlgebra.Cp_Coxeter3): + @cached_method + def to_T_basis(self, w): + A = self.realization_of() + Cp = A.Cp() + T = A.T() + return T(Cp.monomial(w)) + class C(IwahoriHeckeAlgebra.C): r""" The Kazhdan-Lusztig `C`-basis for the generic Iwahori-Hecke algebra. From d2a237b7d71cee6df1d6397f8cb1103027762354 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Tue, 20 Jul 2021 17:47:28 -0600 Subject: [PATCH 049/511] Draft of some better naming/commenting and some documentation --- src/sage/algebras/iwahori_hecke_algebra.py | 51 ++++++++++++++-------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 70ca468ddd9..232cca63496 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2040,9 +2040,9 @@ class Cp_Coxeter3(_KLHeckeBasis): that linear combination onto `B_y`; otherwise we decompose `B_y` and multiply the result onto `B_x`. For example, in the computation of `B[1,2,1] * B[3,1,2]` in type `A3`, the left term `B[1,2,1]` is first (essentially) decomposed into the linear combination `B[1]*B[2]*B[1] - B[1]` - behind the scenes. The decomposition is achieved via the [_decompose_into_generators function], - which in turn uses an auxiliary free algebra with generators corresponding to the Coxeter - generators. + behind the scenes. The decomposition is achieved via the [_decompose_into_generators function], which + takes an element `B_w` and gives an element of the free algebra over \{ B_s \; : \; s \in S \}, whose + image under the canonical homomorphism from the free algebra is precisely `B_w`. .. SEEALSO:: @@ -2065,11 +2065,8 @@ def __init__(self, algebra, prefix='Cp'): self._W = algebra._W self.delta = algebra.q1() + ~algebra.q1() #[better way to write this, maybe q as R.gen(0)?] - - #[can we move the following to _decompose_into_generators and avoid it in the manual distribution part - # of product_on_basis? Not a big deal; we could also use the comment below.] - # the auxiliary free algebra mentioned in ..NOTE:: + # The free algebra over our algebra generators, used in _decompose_into_generators self.gen_algebra = FreeAlgebra(algebra.base_ring(), ['g' + str(i) for i in self.index_set()]) # Define conversion to the other Cp basis @@ -2087,19 +2084,27 @@ def to_Cp_basis(self, w): def _product_with_generator_on_basis(self, side, s, w): r""" - Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting `C^{\prime}_s` on the given ``side``. + Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting + `C^{\prime}_s` on the given ``side``. + + TODO: Repeat the explanation in Cp_Coxeter3's docstring about + C_s * C_w = { cases ... }? [recycle the examples from the class' documentation, or not?] """ if w.has_descent(s, side=side): + # Descent case, return (q + q^-1) C'_w return self.delta * self.monomial(w) else: + # Additively build the sum \sum_{v \leq w; sv < v} mu(v, w) C'_v element = self(0) between = self._W.bruhat_interval([], w) for x in between: + # Get (coxeter3-implemented) group element corresponding to x x_elt = self._W(x) if x_elt.has_descent(s, side=side): + # Compute mu-coefficient via coxeter3 element += x.mu_coefficient(w) * self.monomial(x_elt) # Doing self._W([s]) * w may not ensure that the word is is normal form @@ -2110,6 +2115,9 @@ def _product_with_generator_on_basis(self, side, s, w): def _product_with_generator(self, side, s, x): r""" Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elemens. + + TODO: Say more here; maybe that this just does distribution? I think + the one line is fairly self-explanatory. """ return self.linear_combination((self._product_with_generator_on_basis(side, s, w), coeff) for (w, coeff) in x) @@ -2135,20 +2143,23 @@ def _decompose_into_generators(self, w): # Use the reverse of the left-multiplication by generator rule: # We know s is not a left descent, so # C_w = C_s * C_{w1} - \sum_{sy < y < w1} C_y + # TODO: Explain this ^ in the docstring? - # The sum from the above - rest = self(0) + # Additively build the sum just mentioned above + sum_term = self(0) between = self._W.bruhat_interval([], w1) for x in between: + # Get (coxeter3-implemented) group element corresponding to x x_elt = self._W(x) if x_elt.has_left_descent(s): - rest += self.base_ring()(x.mu_coefficient(w1)) * self.monomial(x_elt) + # Compute mu-coefficient via coxeter3 + sum_term += self.base_ring()(x.mu_coefficient(w1)) * self.monomial(x_elt) # In the expression above, we need to recurse and decompose C_{w1} into generators, # and then go through the terms of the sum 'rest' and decompose those C_y's into generators alg_element = gs[s] * self._decompose_into_generators(w1) - for (v, coeff) in rest: - # We're subtracting 'rest' + for (v, coeff) in sum_term: + # We're subtracting 'sum_term' alg_element -= coeff * self._decompose_into_generators(v) return alg_element @@ -2173,20 +2184,24 @@ def product_on_basis(self, w1, w2): # [I'm a little confused by 'powers' below; also, should we write a helper function earlier for the 'manual # distribution'?] - # Now, build everything back up, continually multiplying on the left by a single generator - # Multiply gens by other_element, doing "manual distribution" + # gens is a linear combination of products of the C' generators + # Now, build everything back up, continually multiplying on the left by a single generator at a time result = self(0) + # Iterate through the sum of terms for (p, coeff) in gens: # p is a product of generators, i.e. 2*g1*g2*g1; multiply it by other_element # Build summand multiplicatively, going through variables and thier powers in p # If gens are on the right, we need to start at the left end of p, and vice versa. summand = coeff * other_element p_list = list(p) if side == 'right' else list(p)[::-1] - for (g, power) in p_list: + # Iterate through the product of generators + for (g, exponent) in p_list: s = self.gen_algebra.gens().index(g) - # Multiply this_element on the apppropriate side by the generator this variable g corresponds to - for i in range(power): + # Multiply this_element on the apppropriate side by the generator this variable g corresponds to, + # however many times it is represented in the product (according to the exponent) + for i in range(exponent): + # Perform C'_s * (summand) summand = self._product_with_generator(side, s, summand) result += summand From a000d6cf5fed22b41ab7de8b927c3f6427c3b743 Mon Sep 17 00:00:00 2001 From: Tianyuan Xu Date: Wed, 21 Jul 2021 16:51:27 -0600 Subject: [PATCH 050/511] more docstrings for methods in Cp_Coxeter3 --- src/sage/algebras/iwahori_hecke_algebra.py | 98 +++++++++++++++------- 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 232cca63496..d5c65b9d2b4 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2036,18 +2036,18 @@ class Cp_Coxeter3(_KLHeckeBasis): .. NOTE:: The products `B_x \cdot B_y` are computed as follows: if `\ell(x) \leq \ell(y)`, then we first - decompose `B_x` into a linear combination of products of generators `B_s (s\in S)`, then multiplies - that linear combination onto `B_y`; otherwise we decompose `B_y` and multiply the result onto - `B_x`. For example, in the computation of `B[1,2,1] * B[3,1,2]` in type `A3`, the left term - `B[1,2,1]` is first (essentially) decomposed into the linear combination `B[1]*B[2]*B[1] - B[1]` - behind the scenes. The decomposition is achieved via the [_decompose_into_generators function], which - takes an element `B_w` and gives an element of the free algebra over \{ B_s \; : \; s \in S \}, whose - image under the canonical homomorphism from the free algebra is precisely `B_w`. + decompose `B_x` into a polynomial in the generators `B_s (s\in S)`, then multiplies that linear + combination onto `B_y`; otherwise we decompose `B_y` and multiply the result onto `B_x`. For + example, in the computation of `B[1,2,1] * B[3,1,2]` in type `A3`, the left term `B[1,2,1]` is + first (essentially) decomposed into the linear combination `B[1]*B[2]*B[1] - B[1]` behind the + scenes. The decomposition is achieved via the [_decompose_into_generators function], which takes an + element `B_w` and gives an element of the free algebra over \{ B_s \; : \; s \in S \}, whose image + under the canonical homomorphism from the free algebra is precisely `B_w`. .. SEEALSO:: :ref: [KL1979]_, [Lus2013]_ - :meth:`sage.somewhere.other_useful_method`, + :meth:`sage.somewhere.other_useful_method`, cell stuff [coxeter3?] TESTS:: @@ -2064,10 +2064,11 @@ def __init__(self, algebra, prefix='Cp'): super(IwahoriHeckeAlgebra.Cp_Coxeter3, self).__init__(algebra, prefix) self._W = algebra._W - self.delta = algebra.q1() + ~algebra.q1() #[better way to write this, maybe q as R.gen(0)?] - - # The free algebra over our algebra generators, used in _decompose_into_generators + self.delta = q + ~q # need the normalizations q_1=q^2, q_2=-1 or q_1=q,q_2=-q^-1 + + # The free algebra over our algebra generators, used to create monomials in these generators in _decompose_into_generators self.gen_algebra = FreeAlgebra(algebra.base_ring(), ['g' + str(i) for i in self.index_set()]) + # Define conversion to the other Cp basis self.module_morphism(self.to_Cp_basis, codomain=algebra.Cp(), category=self.category() @@ -2087,8 +2088,23 @@ def _product_with_generator_on_basis(self, side, s, w): Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting `C^{\prime}_s` on the given ``side``. - TODO: Repeat the explanation in Cp_Coxeter3's docstring about - C_s * C_w = { cases ... }? + For each generator `s` and element `x`, the products `C^{\prime}_s \cdot C^{\prime}_w` + is given by the following formulas: + + .. MATH:: + C^{\prime}_s \cdot C^{\prime}_w = + \begin{cases} + (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ + C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, & \text{if } \ell(sw) = \ell(w)+1. + \end{cases} + + C^{\prime}_w \cdot C^{\prime}_s = + \begin{cases} + (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(ws) = \ell(w)-1,\\ + C^{\prime}_{ws}+\sum_{v\leq w, vs \leq v} \mu(v,w)C^{\prime}_v, & \text{if } \ell(ws) = \ell(w)+1. + \end{cases} + + where `\leq` is the Bruhat order and the numbers `\mu(v,w)` are the `mu`-coefficients of [Lus2014]_. [recycle the examples from the class' documentation, or not?] """ @@ -2114,21 +2130,47 @@ def _product_with_generator_on_basis(self, side, s, w): def _product_with_generator(self, side, s, x): r""" - Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elemens. + Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elements. - TODO: Say more here; maybe that this just does distribution? I think - the one line is fairly self-explanatory. + EXAMPLE:: + + [one example is enough] """ return self.linear_combination((self._product_with_generator_on_basis(side, s, w), coeff) for (w, coeff) in x) def _decompose_into_generators(self, w): r""" - Returns an element of self.gen_algebra, a free algebra over {g_1, ..., g_n} - describing how to write 'word' in terms of the generators + Decompose `C^{\prime}_s` into a polynomial in the KL generators `C^{\prime}_s`. + + The decomposition is obtained recursively, by induction on `\ell(w)`. If `ell(w) < 2` the decomposition + is trivial (see Examples). If `\ell(w) \geq 2`, write `w=su` where `s` is a left descent of `w` so that + `\ell(w) = \ell(u) + 1`, then use the formula that - [need a good running example or several examples, maybe including how C_121=C_1*C_2*C_1-C_1 in type A; - decomposing from one side is probably enough in the example(s)] - """ + .. MATH:: + C^{\prime}_s \cdot C^{\prime}_u = + C^{\prime}_{su}+\sum_{v\leq u, sv \leq v} \mu(v,u)C^{\prime}_v + + to conclude that + + .. MATH:: + C^{\prime}_{w}= C^{\prime}_s \cdot C^{\prime}_u - \sum_{v\leq u, sv \leq v} \mu(v,u)C^{\prime}_v. + + The element `u` and the elements `v` on the right side all have smaller length than `w`, so they can be + obtained by induction. + + + EXAMPLES:: + # A3 + sage: _decompose_into_generators((1,2)) + {[1,2]: 1} # C_{12}=C_1C_2 + sage: _decompose_into_generators((1,2,1)) + {[1,2,1]: 1, [1]:-1} # C_{121}=C_1C_2C_1-C_1=m_121-m_1 + sage: _decompose_into_generators((1,2,3,1,2)) + the suitable dictionary # use "monomial" somehow to get the result natively? + + """ + # Returns an element of self.gen_algebra, a free algebra over {g_1, ..., g_n} + # describing how to write 'word' in terms of the generators gs = self.gen_algebra.gens() if len(w) == 0: @@ -2139,12 +2181,7 @@ def _decompose_into_generators(self, w): s = w[0] w1 = w[1:] - # We have C_w = C_s * C_{w1} - # Use the reverse of the left-multiplication by generator rule: - # We know s is not a left descent, so - # C_w = C_s * C_{w1} - \sum_{sy < y < w1} C_y - # TODO: Explain this ^ in the docstring? - + # Additively build the sum just mentioned above sum_term = self(0) between = self._W.bruhat_interval([], w1) @@ -2156,7 +2193,7 @@ def _decompose_into_generators(self, w): sum_term += self.base_ring()(x.mu_coefficient(w1)) * self.monomial(x_elt) # In the expression above, we need to recurse and decompose C_{w1} into generators, - # and then go through the terms of the sum 'rest' and decompose those C_y's into generators + # and then go through the terms of the sum_term (lower order terms) and decompose those C_y's into generators alg_element = gs[s] * self._decompose_into_generators(w1) for (v, coeff) in sum_term: # We're subtracting 'sum_term' @@ -2181,10 +2218,7 @@ def product_on_basis(self, w1, w2): gens = self._decompose_into_generators(w2) other_element = self.monomial(w1) - # [I'm a little confused by 'powers' below; also, should we write a helper function earlier for the 'manual - # distribution'?] - - # gens is a linear combination of products of the C' generators + # gens is a linear combination of products of the C' generators # Now, build everything back up, continually multiplying on the left by a single generator at a time result = self(0) From 2e9f6d6616c11c5e0f5b0a3c9896f5e105630a97 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Thu, 22 Jul 2021 11:54:48 -0600 Subject: [PATCH 051/511] Only allow the standard normalizations for the Cp_Coxeter3 basis. --- src/sage/algebras/iwahori_hecke_algebra.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index d5c65b9d2b4..583db458673 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2064,11 +2064,15 @@ def __init__(self, algebra, prefix='Cp'): super(IwahoriHeckeAlgebra.Cp_Coxeter3, self).__init__(algebra, prefix) self._W = algebra._W - self.delta = q + ~q # need the normalizations q_1=q^2, q_2=-1 or q_1=q,q_2=-q^-1 - # The free algebra over our algebra generators, used to create monomials in these generators in _decompose_into_generators - self.gen_algebra = FreeAlgebra(algebra.base_ring(), ['g' + str(i) for i in self.index_set()]) - + v = algebra.base_ring().gen(0) + if ((algebra.q1() == v**2 and algebra.q2() == -1) or (algebra.q1() == v and algebra.q2() == -1/v)): + self.delta = v + ~v + else: + if not algebra._is_generic: + # If this algebra is generic, it's only being used to coerce to the T basis, not perform computations + raise ValueError('the Cp_Coxeter3 basis is only supported in a Hecke algebra with standard normalizations (explain)') + # Define conversion to the other Cp basis self.module_morphism(self.to_Cp_basis, codomain=algebra.Cp(), category=self.category() From 787be9175f69b71da58035fd4bb96a462782b826 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Thu, 22 Jul 2021 11:56:16 -0600 Subject: [PATCH 052/511] Tweak _decompose_into_generators and related free algebra stuff for clarity and readability. --- src/sage/algebras/iwahori_hecke_algebra.py | 52 ++++++++++++---------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 583db458673..129fe26a7e0 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2073,6 +2073,11 @@ def __init__(self, algebra, prefix='Cp'): # If this algebra is generic, it's only being used to coerce to the T basis, not perform computations raise ValueError('the Cp_Coxeter3 basis is only supported in a Hecke algebra with standard normalizations (explain)') + # Construct a free algebra over generators representing the C' generators: { Cp_s : s in S } + self._generator_algebra = FreeAlgebra(algebra.base_ring(), ['Cp{}'.format(s) for s in self.index_set()]) + # The correspondence between indices and generators of the generator algebra + self._generators = { s: self._generator_algebra('Cp{}'.format(s)) for s in self.index_set() } + self._index_of_generator = { v: k for (k, v) in self._generators.items() } # Define conversion to the other Cp basis self.module_morphism(self.to_Cp_basis, codomain=algebra.Cp(), category=self.category() @@ -2144,7 +2149,8 @@ def _product_with_generator(self, side, s, x): def _decompose_into_generators(self, w): r""" - Decompose `C^{\prime}_s` into a polynomial in the KL generators `C^{\prime}_s`. + Decompose `C^{\prime}_w` into a polynomial in the KL generators `C^{\prime}_s` (an element of the + free algebra `self.generator_algebra`) The decomposition is obtained recursively, by induction on `\ell(w)`. If `ell(w) < 2` the decomposition is trivial (see Examples). If `\ell(w) \geq 2`, write `w=su` where `s` is a left descent of `w` so that @@ -2166,27 +2172,23 @@ def _decompose_into_generators(self, w): EXAMPLES:: # A3 sage: _decompose_into_generators((1,2)) - {[1,2]: 1} # C_{12}=C_1C_2 + Cp1*Cp2 # C_{12} = C_1C_2 sage: _decompose_into_generators((1,2,1)) - {[1,2,1]: 1, [1]:-1} # C_{121}=C_1C_2C_1-C_1=m_121-m_1 + Cp1*Cp2*Cp1 - Cp1 # C_{121} = C_1C_2C_1 - C_1 sage: _decompose_into_generators((1,2,3,1,2)) the suitable dictionary # use "monomial" somehow to get the result natively? - """ - # Returns an element of self.gen_algebra, a free algebra over {g_1, ..., g_n} - # describing how to write 'word' in terms of the generators - - gs = self.gen_algebra.gens() + """ if len(w) == 0: - return self.gen_algebra(1) + return self.generator_algebra(1) if len(w) == 1: - return gs[w[0]] + return self._generators[w[0]] s = w[0] w1 = w[1:] - # Additively build the sum just mentioned above + # Additively build the sum term (lower order terms) sum_term = self(0) between = self._W.bruhat_interval([], w1) for x in between: @@ -2197,8 +2199,8 @@ def _decompose_into_generators(self, w): sum_term += self.base_ring()(x.mu_coefficient(w1)) * self.monomial(x_elt) # In the expression above, we need to recurse and decompose C_{w1} into generators, - # and then go through the terms of the sum_term (lower order terms) and decompose those C_y's into generators - alg_element = gs[s] * self._decompose_into_generators(w1) + # and then go through the terms of sum_term (lower order terms) and decompose those C_y's into generators + alg_element = self._generators[s] * self._decompose_into_generators(w1) for (v, coeff) in sum_term: # We're subtracting 'sum_term' alg_element -= coeff * self._decompose_into_generators(v) @@ -2215,31 +2217,33 @@ def product_on_basis(self, w1, w2): # (as expressed as an element of the FreeAlgebra over 'generator' variables g1, ..., gn) if len(w1) <= len(w2): side = 'left' - gens = self._decompose_into_generators(w1) + gen_expression = self._decompose_into_generators(w1) other_element = self.monomial(w2) else: side = 'right' - gens = self._decompose_into_generators(w2) + gen_expression = self._decompose_into_generators(w2) other_element = self.monomial(w1) - # gens is a linear combination of products of the C' generators + # gen_expression is a linear combination of products of the C' generators # Now, build everything back up, continually multiplying on the left by a single generator at a time result = self(0) # Iterate through the sum of terms - for (p, coeff) in gens: + for (p, coeff) in gen_expression: # p is a product of generators, i.e. 2*g1*g2*g1; multiply it by other_element - # Build summand multiplicatively, going through variables and thier powers in p - # If gens are on the right, we need to start at the left end of p, and vice versa. + # Build summand multiplicatively, going through variables (and their exponents) in p + # If gen_expression is being multiplied on the right, we need to start at the left + # end of p, and vice versa. summand = coeff * other_element p_list = list(p) if side == 'right' else list(p)[::-1] # Iterate through the product of generators - for (g, exponent) in p_list: - s = self.gen_algebra.gens().index(g) - # Multiply this_element on the apppropriate side by the generator this variable g corresponds to, - # however many times it is represented in the product (according to the exponent) + for (gen, exponent) in p_list: + s = self._index_of_generator[self._generator_algebra(gen)] + # gen is in the underlying monoid of _generator_algebra, so coercion is required for i in range(exponent): - # Perform C'_s * (summand) + # Perform C'_s * summand (on the appropriate side), + # however many times C'_s is represented in the product + # according to the exponent. summand = self._product_with_generator(side, s, summand) result += summand From 56707178f43e3b821020a2dc6cfe4cbf63dd2166 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Thu, 22 Jul 2021 18:25:51 -0600 Subject: [PATCH 053/511] Some TODO's and documentation tweaks; make docstrings functional through "to_Cp_basis" --- src/sage/algebras/iwahori_hecke_algebra.py | 159 +++++++++++++++------ 1 file changed, 114 insertions(+), 45 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 129fe26a7e0..f7da859c508 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1969,7 +1969,7 @@ class Cp_Coxeter3(_KLHeckeBasis): r""" Directly compute products in the `C^{\prime}`-basis by using du Cloux's Coxeter3 package. - [State assumptions] normalization/coxeter3 implementation + TODO: [State assumptions] normalization/coxeter3 implementation Expanding products of the form `C^{\prime}_x \cdot C^{\prime}_y` in the `C^{\prime}`-basis is useful for computing Kazhdan-Lusztig cells of Coxeter systems and the corresponding cell modules of Iwahori-Hecke @@ -2000,49 +2000,86 @@ class Cp_Coxeter3(_KLHeckeBasis): Use the analog of the displayed formula to implement `C^{\prime}`-products in the multi-parameter Iwahori-Hecke algebra; see Section 6 of [Lus2013]_. - EXAMPLES:: - - sage: R = LaurentPolynomialRing(QQ, 'q') - [A3 examples with warnings caused by wrong presentation or implementation...] - - Create the Hecke algebra of type 'A3' and label the `C^{\prime}`-basis by `B`: - - sage: H = IwahoriHeckeAlgebra('A3',implementation = 'coxeter3') - sage: B = H.Cp_Coxeter3() [careful about printing: B or Cp] - - Product of the form `B_s \cdot B_y` where `s` is a generator are computed by the earlier formula:: + EXAMPLES: - sage: B[1] * B[1] - (q^-1+q) * B[1] - sage: B[1] * B[2] - B[1,2] - sage: B[1] * B[2,1] - B[1,2,1] + B[1] - sage: B[1] * B[2,1,3] - B[1,2,3,1] + B[3,1] - sage: B[2] * B[1,3,2,1,3] - B[1,2,3,1,2,1] + Cp[2,3,2,1] + Cp[1,2,3,1] + Basic usage:: + sage: R. = LaurentPolynomialRing(ZZ) + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: s1, s2, s3 = A3.simple_reflections() + sage: H = IwahoriHeckeAlgebra(A3, v**2) + sage: Cp = H.Cp_Coxeter3() + sage: Cp(s1*s2*s1) + Cp[1,2,1] + sage: Cp(s1)**2 + (v^-1+v)*Cp[1] + sage: Cp(s1)*Cp(s2)*Cp(s1) + Cp[1,2,1] + Cp[1] + sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] + Cp[1,2,1,3,2] + Cp[1,2,1] + Cp[1,3,2] - More generally, we can compute products of the form 'B_x \cdot B_y` for general `x, y`:: - - sage: B[1,2,1] * B[3,1] - (q^-1+q)*B[1,2,3,1] - sage: B[1,2,1] * B[3,1,2] (q^-1+q)*B[1,2,3,1,2] + (q^-1+q)*B[1,2,1] - - [More examples: B9 examples; showcase labelling, compare speed with the indirect method ] - + The IwahoriHeckeAlgebra must be initialized with a ``CoxeterGroup`` + implemented with coxeter3 and the Hecke parameters must be v^2, -1 or + v, -1/v:: - .. NOTE:: + sage: H = IwahoriHeckeAlgebra('A3', v**2) + sage: H.Cp_Coxeter3() + Traceback (most recent call last): + ... + ValueError: algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(A3, QQ(1)) + sage: H.Cp_Coxeter3() + Traceback (most recent call last): + ... + ValueError: the Cp_Coxeter3 basis is only supported in a Hecke algebra with standard normalizations (explain) + + Products of the form `Cp_s \cdot Cp_y` where `s` is a generator are computed by the earlier formula:: - The products `B_x \cdot B_y` are computed as follows: if `\ell(x) \leq \ell(y)`, then we first - decompose `B_x` into a polynomial in the generators `B_s (s\in S)`, then multiplies that linear - combination onto `B_y`; otherwise we decompose `B_y` and multiply the result onto `B_x`. For - example, in the computation of `B[1,2,1] * B[3,1,2]` in type `A3`, the left term `B[1,2,1]` is - first (essentially) decomposed into the linear combination `B[1]*B[2]*B[1] - B[1]` behind the - scenes. The decomposition is achieved via the [_decompose_into_generators function], which takes an - element `B_w` and gives an element of the free algebra over \{ B_s \; : \; s \in S \}, whose image - under the canonical homomorphism from the free algebra is precisely `B_w`. + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(A3, v**2) + sage: Cp = H.Cp_Coxeter3() + sage: Cp[1] * Cp[1] + (v^-1+v)*Cp[1] + sage: Cp[1] * Cp[2] + Cp[1,2] + sage: Cp[1] * Cp[2,1] + Cp[1,2,1] + Cp[1] + sage: Cp[1] * Cp[2,1,3] + Cp[1,2,1,3] + Cp[1,3] + sage: Cp[2] * Cp[1,3,2,1,3] + Cp[1,2,1,3,2,1] + Cp[1,2,1,3] + Cp[2,3,2,1] + + More generally, we can compute products of the form `C^{\prime}_x \cdot C^{\prime}_y` for + general `x, y`:: + + sage: Cp[1,2,1] * Cp[3,1] + (v^-1+v)*Cp[1,2,1,3] + sage: Cp[1,2,1] * Cp[3,1,2] + (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] + (v^-1+v)*Cp[1,3,2] - (v^-1+v)*Cp[3,1,2] + + We can compute complex products in in type `B9`, while relabelling the + generators so that the long braid is between the first two generators:: + + sage: B9 = CoxeterGroup(CoxeterType(['B', 9]).relabel({ i: 9-i+1 for i in range(1, 10) }), implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(B9, v, -1/v) + sage: Cp = H.Cp_Coxeter3() + sage: Cp[1,2,1,2] + Cp[1,2,1,2] + sage: Cp[3,2,3,4,5] * Cp[2,3] + (v^-1+v)*Cp[2,3,2,4,3,5] + (v^-1+v)*Cp[2,3,2,5] + + + .. NOTE:: + + The products `B_x \cdot B_y` are computed as follows: if `\ell(x) \leq \ell(y)`, then we first + decompose `B_x` into a polynomial in the generators `B_s (s\in S)`, then multiplies that linear + combination onto `B_y`; otherwise we decompose `B_y` and multiply the result onto `B_x`. For + example, in the computation of `B[1,2,1] * B[3,1,2]` in type `A3`, the left term `B[1,2,1]` is + first (essentially) decomposed into the linear combination `B[1]*B[2]*B[1] - B[1]` behind the + scenes. The decomposition is achieved via the [_decompose_into_generators function], which takes an + element `B_w` and gives an element of the free algebra over \{ B_s \; : \; s \in S \}, whose image + under the canonical homomorphism from the free algebra is precisely `B_w`. .. SEEALSO:: @@ -2050,14 +2087,27 @@ class Cp_Coxeter3(_KLHeckeBasis): :meth:`sage.somewhere.other_useful_method`, cell stuff [coxeter3?] - TESTS:: - - [show our direct method yields the same results as the indirect method?] - """ _basis_name = 'Cp_Coxeter3' def __init__(self, algebra, prefix='Cp'): + r""" + Initialize the Cp_Coxeter3 Kazdahn-Luzstig basis of the + Iwahori-Hecke algebra ``algebra''. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(ZZ, 'v') + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(A3, v**2) + sage: Cp = H.Cp_Coxeter3() + + sage: H = IwahoriHeckeAlgebra('A3', v**2) + sage: Cp = H.Cp_Coxeter3() + Traceback (most recent call last): + ... + ValueError: algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis + """ if not isinstance(algebra._W, Coxeter3Group): raise ValueError('algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis') @@ -2066,16 +2116,19 @@ def __init__(self, algebra, prefix='Cp'): self._W = algebra._W v = algebra.base_ring().gen(0) - if ((algebra.q1() == v**2 and algebra.q2() == -1) or (algebra.q1() == v and algebra.q2() == -1/v)): + + # TODO: rewrite this horribly ugly condition: + if v != algebra.base_ring().one() and ((algebra.q1() == v**2 and algebra.q2() == -1) or (algebra.q1() == v and algebra.q2() == -1/v)): self.delta = v + ~v else: if not algebra._is_generic: # If this algebra is generic, it's only being used to coerce to the T basis, not perform computations + # TODO: Better error message raise ValueError('the Cp_Coxeter3 basis is only supported in a Hecke algebra with standard normalizations (explain)') # Construct a free algebra over generators representing the C' generators: { Cp_s : s in S } self._generator_algebra = FreeAlgebra(algebra.base_ring(), ['Cp{}'.format(s) for s in self.index_set()]) - # The correspondence between indices and generators of the generator algebra + # The correspondence between indices and formal generators of the generator algebra self._generators = { s: self._generator_algebra('Cp{}'.format(s)) for s in self.index_set() } self._index_of_generator = { v: k for (k, v) in self._generators.items() } @@ -2088,6 +2141,22 @@ def __init__(self, algebra, prefix='Cp'): Cp.module_morphism(Cp.to_Cp_Coxeter3_basis, codomain=self, category=self.category()).register_as_coercion() def to_Cp_basis(self, w): + r""" + Return the element ``self[w]`` as a linear combination of + ``Cp``-basis elements. This transformation is trivial as both + bases are implementations of the `C^{\prime}` basis. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(ZZ, 'v') + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp(); CpC=H.Cp_Coxeter3() + sage: s1, s2, s3 = A3.simple_reflections() + sage: CpC.to_Cp_basis(s1*s2) + Cp[1,2] + sage: CpC.to_Cp_basis(s1*s2*s1) + Cp[1,2,1] + """ A = self.realization_of() Cp = A.Cp() return Cp.monomial(w) From 9510a6813b0d65973c4b9e1c62e595943d2c52e4 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 23 Jul 2021 01:21:39 -0600 Subject: [PATCH 054/511] Finish getting docstrings drafted and examples functional for all added methods --- src/sage/algebras/iwahori_hecke_algebra.py | 328 +++++++++++++++------ 1 file changed, 241 insertions(+), 87 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index f7da859c508..128fce56ccf 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1582,6 +1582,25 @@ def to_Cp_basis(self, w): return generic_T.to_Cp_basis(w).specialize_to(H) def to_Cp_Coxeter3_basis(self, w): + r""" + Return `T-w` as a linear combination of `C^{\prime}`-basis elements, + using the ``Cp_Coxeter3`` basis. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(ZZ, 'v') + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(A3, v**2); T=H.T(); Cp=H.Cp_Coxeter3() + sage: s1,s2,s3 = A3.simple_reflections() + sage: T.to_Cp_Coxeter3_basis(s1) + v*Cp[1] - 1 + sage: Cp(T(s1)) + v*Cp[1] - 1 + sage: Cp(T[1] + 1) + v*Cp[1] + sage: Cp(T[1,2] + T[1] + T[2] + 1) + v^2*Cp[1,2] + """ H = self.realization_of() generic_T = H._generic_iwahori_hecke_algebra.T() return generic_T.to_Cp_Coxeter3_basis(w).specialize_to(H) @@ -1938,6 +1957,21 @@ class Cp(_KLHeckeBasis): _basis_name = 'Cp' # this is used, for example, by specialize_to and is the default prefix def to_Cp_Coxeter3_basis(self, w): + r""" + Return ``self[w]`` as an element of the ``Cp_Coxeter3`` basis. This + transformation is trivial since both bases are implementations of + the `C^{\prime}` basis. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(ZZ, 'v') + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp = H.Cp(); CpC=H.Cp_Coxeter3() + sage: Cp.to_Cp_Coxeter3_basis(A3([1,2])) + Cp[1,2] + sage: CpC(Cp[1,2]) + Cp[1,2] + """ A = self.realization_of() Cp = A.Cp_Coxeter3() return Cp.monomial(w) @@ -1967,38 +2001,46 @@ def hash_involution_on_basis(self, w): class Cp_Coxeter3(_KLHeckeBasis): r""" - Directly compute products in the `C^{\prime}`-basis by using du Cloux's Coxeter3 package. + Directly compute products in the `C^{\prime}`-basis by using du Cloux's + Coxeter3 package. TODO: [State assumptions] normalization/coxeter3 implementation - Expanding products of the form `C^{\prime}_x \cdot C^{\prime}_y` in the `C^{\prime}`-basis is useful for - computing Kazhdan-Lusztig cells of Coxeter systems and the corresponding cell modules of Iwahori-Hecke - algebras. Such expansion is controlled by the following formula (and the analogous formula for - `C^{\prime}_s \cdot C^{\prime}_w`) under both the "standard" and the "normalized" presentations of the - Iwahori-Hecke algebra, where the quadratic relation is `(T_s-q^2)(T_s+1)=0` and `(T_s-q)(T_s+q^-1)=0` for - each generator `s`, respectively. + Expanding products of the form `C^{\prime}_x \cdot C^{\prime}_y` in the + `C^{\prime}`-basis is useful for computing Kazhdan-Lusztig cells of + Coxeter systems and the corresponding cell modules of Iwahori-Hecke + algebras. Such expansion is controlled by the following formula (and + the analogous formula for `C^{\prime}_s \cdot C^{\prime}_w`) under both + the "standard" and the "normalized" presentations of the Iwahori-Hecke + algebra, where the quadratic relation is `(T_s-q^2)(T_s+1)=0` and + `(T_s-q)(T_s+q^-1)=0` for each generator `s`, respectively. + + .. MATH:: C^{\prime}_s \cdot C^{\prime}_w = \begin{cases} + (q+q^-1)C^{\prime}_{w}, & + \text{if } \ell(sw) = \ell(w)-1,\\ + C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, & + \text{if } \ell(sw) = \ell(w)+1. \end{cases} + + where `\leq` is the Bruhat order on the underlying Coxeter group and + `\mu(v,w)` is the "leading coefficient of Kazhdan-Lusztig polynomials"; + see [KL1979]_ and [Lus2014]_ for more details. + + The emphasis of this class is to compute products in the + `C^{\prime}`-basis directly, by using the above formula and calling the + necessary `\mu`-coefficients from Sage's implementation of Fokko du + Cloux's Coxeter3 package. This methods computes the products faster than + the _Basis.product_on_basis method on Line 1298, which needs to convert + the `C^{\prime}`-basis to the `T`-basis, calculate the product in the + `T`-basis, and convert the results back to the `C^{\prime}`-basis. For + example, the product `C^{\prime}_{32345} * C^{\prime}_{23}` in the Hecke + algebra of type 'B_9' takes more than 30 seconds with the latter method + but is instant using this class. - .. MATH:: - C^{\prime}_s \cdot C^{\prime}_w = - \begin{cases} - (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ - C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, & \text{if } \ell(sw) = \ell(w)+1. - \end{cases} - - where `\leq` is the Bruhat order on the underlying Coxeter group and `\mu(v,w)` is the "leading coefficient - of Kazhdan-Lusztig polynomials"; see [KL1979]_ and [Lus2014]_ for more details. - - The emphasis of this class is to compute products in the `C^{\prime}`-basis directly, by using the above - formula and calling the necessary `\mu`-coefficients from Sage's implementation of Fokko du Cloux's - Coxeter3 package. This methods computes the products faster than the _Basis.product_on_basis method on Line - 1298, which needs to convert the `C^{\prime}`-basis to the `T`-basis, calculate the product in the - `T`-basis, and convert the results back to the `C^{\prime}`-basis. For example, the product - `C^{\prime}_{32345} * C^{\prime}_{23}` in the Hecke algebra of type 'B_9' takes more than 30 seconds with - the latter method but is instant using this class. - .. TODO:: - Use the analog of the displayed formula to implement `C^{\prime}`-products in the multi-parameter - Iwahori-Hecke algebra; see Section 6 of [Lus2013]_. + + Use the analog of the displayed formula to implement + `C^{\prime}`-products in the multi-parameter Iwahori-Hecke algebra; + see Section 6 of [Lus2013]_. EXAMPLES: @@ -2019,8 +2061,8 @@ class Cp_Coxeter3(_KLHeckeBasis): Cp[1,2,1,3,2] + Cp[1,2,1] + Cp[1,3,2] The IwahoriHeckeAlgebra must be initialized with a ``CoxeterGroup`` - implemented with coxeter3 and the Hecke parameters must be v^2, -1 or - v, -1/v:: + implemented with coxeter3 and the Hecke parameters must be v^2, -1 or v, + -1/v:: sage: H = IwahoriHeckeAlgebra('A3', v**2) sage: H.Cp_Coxeter3() @@ -2033,8 +2075,9 @@ class Cp_Coxeter3(_KLHeckeBasis): Traceback (most recent call last): ... ValueError: the Cp_Coxeter3 basis is only supported in a Hecke algebra with standard normalizations (explain) - - Products of the form `Cp_s \cdot Cp_y` where `s` is a generator are computed by the earlier formula:: + + Products of the form `Cp_s \cdot Cp_y` where `s` is a generator are + computed by the earlier formula:: sage: A3 = CoxeterGroup('A3', implementation='coxeter3') sage: H = IwahoriHeckeAlgebra(A3, v**2) @@ -2050,13 +2093,13 @@ class Cp_Coxeter3(_KLHeckeBasis): sage: Cp[2] * Cp[1,3,2,1,3] Cp[1,2,1,3,2,1] + Cp[1,2,1,3] + Cp[2,3,2,1] - More generally, we can compute products of the form `C^{\prime}_x \cdot C^{\prime}_y` for - general `x, y`:: + More generally, we can compute products of the form `C^{\prime}_x \cdot + C^{\prime}_y` for general `x, y`:: sage: Cp[1,2,1] * Cp[3,1] (v^-1+v)*Cp[1,2,1,3] sage: Cp[1,2,1] * Cp[3,1,2] - (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] + (v^-1+v)*Cp[1,3,2] - (v^-1+v)*Cp[3,1,2] + (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] We can compute complex products in in type `B9`, while relabelling the generators so that the long braid is between the first two generators:: @@ -2071,15 +2114,19 @@ class Cp_Coxeter3(_KLHeckeBasis): .. NOTE:: - - The products `B_x \cdot B_y` are computed as follows: if `\ell(x) \leq \ell(y)`, then we first - decompose `B_x` into a polynomial in the generators `B_s (s\in S)`, then multiplies that linear - combination onto `B_y`; otherwise we decompose `B_y` and multiply the result onto `B_x`. For - example, in the computation of `B[1,2,1] * B[3,1,2]` in type `A3`, the left term `B[1,2,1]` is - first (essentially) decomposed into the linear combination `B[1]*B[2]*B[1] - B[1]` behind the - scenes. The decomposition is achieved via the [_decompose_into_generators function], which takes an - element `B_w` and gives an element of the free algebra over \{ B_s \; : \; s \in S \}, whose image - under the canonical homomorphism from the free algebra is precisely `B_w`. + + The products `B_x \cdot B_y` are computed as follows: if + `\ell(x) \leq \ell(y)`, then we first decompose `B_x` into a + polynomial in the generators `B_s (s\in S)`, then multiplies that + linear combination onto `B_y`; otherwise we decompose `B_y` and + multiply the result onto `B_x`. For example, in the computation of + `B[1,2,1] * B[3,1,2]` in type `A3`, the left term `B[1,2,1]` is + first (essentially) decomposed into the linear combination + `B[1]*B[2]*B[1] - B[1]` behind the scenes. The decomposition is + achieved via the [_decompose_into_generators function], which takes + an element `B_w` and gives an element of the free algebra over \{ + B_s \; : \; s \in S \}, whose image under the canonical homomorphism + from the free algebra is precisely `B_w`. .. SEEALSO:: @@ -2092,7 +2139,7 @@ class Cp_Coxeter3(_KLHeckeBasis): def __init__(self, algebra, prefix='Cp'): r""" - Initialize the Cp_Coxeter3 Kazdahn-Luzstig basis of the + Initialize the Cp_Coxeter3 Kazdahn-Luzstig basis of the Iwahori-Hecke algebra ``algebra''. EXAMPLES:: @@ -2142,9 +2189,9 @@ def __init__(self, algebra, prefix='Cp'): def to_Cp_basis(self, w): r""" - Return the element ``self[w]`` as a linear combination of - ``Cp``-basis elements. This transformation is trivial as both - bases are implementations of the `C^{\prime}` basis. + Return the element ``self[w]`` in the ``Cp``-basis. This + transformation is trivial as both bases are implementations of the + `C^{\prime}` basis. EXAMPLES:: @@ -2166,10 +2213,11 @@ def _product_with_generator_on_basis(self, side, s, w): Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting `C^{\prime}_s` on the given ``side``. - For each generator `s` and element `x`, the products `C^{\prime}_s \cdot C^{\prime}_w` - is given by the following formulas: + For each generator `s` and element `x`, the products `C^{\prime}_s + \cdot C^{\prime}_w` is given by the following formulas: .. MATH:: + C^{\prime}_s \cdot C^{\prime}_w = \begin{cases} (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ @@ -2184,10 +2232,27 @@ def _product_with_generator_on_basis(self, side, s, w): where `\leq` is the Bruhat order and the numbers `\mu(v,w)` are the `mu`-coefficients of [Lus2014]_. - [recycle the examples from the class' documentation, or not?] + INPUT: + + - ``side`` -- string; 'left' or 'right' + + - ``s`` -- integer in self.index_set() + + - ``w`` -- a word in self.coxeter_group() + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(ZZ, 'v') + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp_Coxeter3() + sage: Cp._product_with_generator_on_basis('left', 1, A3([2,1])) + Cp[1,2,1] + Cp[1] + sage: Cp._product_with_generator_on_basis('right', 2, A3([1,3,2,1,3])) + Cp[1,2,1,3,2,1] + Cp[1,2,3,2] + Cp[1,3,2,1] """ if w.has_descent(s, side=side): + # TODO: notation? # Descent case, return (q + q^-1) C'_w return self.delta * self.monomial(w) else: @@ -2208,22 +2273,40 @@ def _product_with_generator_on_basis(self, side, s, w): def _product_with_generator(self, side, s, x): r""" - Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elements. + Compute the product of `C^{\prime}_s` with any linear combination of + `C^{\prime}`-basis elements. + + INPUT: + + - ``side`` -- string; 'left' or 'right' - EXAMPLE:: + - ``s`` -- integer in self.index_set() - [one example is enough] + - ``w`` -- any element of self + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(ZZ, 'v') + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp_Coxeter3() + sage: Cp._product_with_generator('left', 1, Cp[1]+Cp[2]) + Cp[1,2] + (v^-1+v)*Cp[1] + sage: Cp._product_with_generator('right', 1, Cp[1]+Cp[2]) + Cp[2,1] + (v^-1+v)*Cp[1] """ return self.linear_combination((self._product_with_generator_on_basis(side, s, w), coeff) for (w, coeff) in x) def _decompose_into_generators(self, w): r""" - Decompose `C^{\prime}_w` into a polynomial in the KL generators `C^{\prime}_s` (an element of the - free algebra `self.generator_algebra`) - - The decomposition is obtained recursively, by induction on `\ell(w)`. If `ell(w) < 2` the decomposition - is trivial (see Examples). If `\ell(w) \geq 2`, write `w=su` where `s` is a left descent of `w` so that - `\ell(w) = \ell(u) + 1`, then use the formula that + Decompose `C^{\prime}_w` into a polynomial in the KL generators + `C^{\prime}_s` (an element of the free algebra + `self.generator_algebra`) + + The decomposition is obtained recursively, by induction on + `\ell(w)`. If `ell(w) < 2` the decomposition is trivial (see + Examples). If `\ell(w) \geq 2`, write `w=su` where `s` is a left + descent of `w` so that `\ell(w) = \ell(u) + 1`, then use the formula + that .. MATH:: C^{\prime}_s \cdot C^{\prime}_u = @@ -2234,19 +2317,29 @@ def _decompose_into_generators(self, w): .. MATH:: C^{\prime}_{w}= C^{\prime}_s \cdot C^{\prime}_u - \sum_{v\leq u, sv \leq v} \mu(v,u)C^{\prime}_v. - The element `u` and the elements `v` on the right side all have smaller length than `w`, so they can be - obtained by induction. + The element `u` and the elements `v` on the right side all have + smaller length than `w`, so they can be obtained by induction. + + INPUT: + + - ``w`` -- word in self.coxeter_group() + OUTPUT: + + An element of ``self._generator_algebra`` describing how to express + `C^{\prime}_w` in terms of the generators `C^{\prime}_s`. EXAMPLES:: - # A3 - sage: _decompose_into_generators((1,2)) - Cp1*Cp2 # C_{12} = C_1C_2 - sage: _decompose_into_generators((1,2,1)) - Cp1*Cp2*Cp1 - Cp1 # C_{121} = C_1C_2C_1 - C_1 - sage: _decompose_into_generators((1,2,3,1,2)) - the suitable dictionary # use "monomial" somehow to get the result natively? + sage: R. = LaurentPolynomialRing(ZZ, 'v') + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp_Coxeter3() + sage: Cp._decompose_into_generators(A3([1,2])) # C_{12} = C_1C_2 + Cp1*Cp2 + sage: Cp._decompose_into_generators(A3([1,2,1])) # C_{121} = C_1C_2C_1 - C_1 + -Cp1 + Cp1*Cp2*Cp1 + sage: Cp._decompose_into_generators(A3([1,2,3,1,2])) + Cp1 - Cp1*Cp2*Cp1 - Cp1*Cp3*Cp2 + Cp1*Cp2*Cp1*Cp3*Cp2 """ if len(w) == 0: return self.generator_algebra(1) @@ -2278,9 +2371,22 @@ def _decompose_into_generators(self, w): def product_on_basis(self, w1, w2): r""" - Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` in the `C^{\prime}`-basis. - - [recycle example from class' doc?] + Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` in + the `C^{\prime}`-basis. + + TODO: Describe our decision to decompose the smaller word...? Or is + class docs enough here. I lean towards describing the algorithm once + in the class docs. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(ZZ, 'v') + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp_Coxeter3() + sage: Cp.product_on_basis(A3([1,2,1]), A3([3,1])) + (v^-1+v)*Cp[1,2,1,3] + sage: Cp.product_on_basis(A3([1,2,1]), A3([3,1,2])) + (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] """ # Otherwise, decompose the first word into generators # (as expressed as an element of the FreeAlgebra over 'generator' variables g1, ..., gn) @@ -2890,28 +2996,30 @@ class T(IwahoriHeckeAlgebra.T): """ def _to_Cp_basis(self, w, Cp): r""" - TODO: Change this documentation and the two below - Return `T_w` as a linear combination of `C^{\prime}`-basis - elements. + Return `T_w` as a linear combination of `C^{\prime}`-basis elements, + using either the ``Cp`` basis or the ``Cp_Coxeter3`` implementation. + + INPUT: + + - ``w`` -- a word in self.coxeter_group() + + - ``Cp`` -- the target `C^{\prime}` basis to use; either ``Cp`` or + ``Cp_Coxeter3`` EXAMPLES:: - sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard("A2") - sage: s1,s2 = H.coxeter_group().simple_reflections() - sage: T = H.T() - sage: Cp = H.Cp() - sage: T.to_Cp_basis(s1) + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard(A3) + sage: s1,s2,s3 = A3.simple_reflections() + sage: T = H.T(); Cp = H.Cp(); CpC = H.Cp_Coxeter3() + sage: T._to_Cp_basis(s1, Cp) v*Cp[1] + (-u^-1*v^2) sage: Cp(T(s1)) v*Cp[1] + (-u^-1*v^2) - sage: Cp(T(s1)+1) - v*Cp[1] + (-u^-1*v^2+1) - sage: Cp(T(s1*s2)+T(s1)+T(s2)+1) - v^2*Cp[1,2] + (-u^-1*v^3+v)*Cp[1] + (-u^-1*v^3+v)*Cp[2] - + (u^-2*v^4-2*u^-1*v^2+1) - sage: Cp(T(s1*s2*s1)) - v^3*Cp[1,2,1] + (-u^-1*v^4)*Cp[2,1] + (-u^-1*v^4)*Cp[1,2] - + (u^-2*v^5)*Cp[1] + (u^-2*v^5)*Cp[2] + (-u^-3*v^6) + sage: T._to_Cp_basis(s1, CpC) + v*Cp[1] + (-u^-1*v^2) + sage: CpC(T(s1)) + v*Cp[1] + (-u^-1*v^2) """ A = self.realization_of() # Cp = A.Cp() if not use_Cp_Coxeter3 else A.Cp_Coxeter3() @@ -2931,11 +3039,57 @@ def _to_Cp_basis(self, w, Cp): @cached_method def to_Cp_basis(self, w): + r""" + Return `T_w` as a linear combination of `C^{\prime}`-basis elements + + EXAMPLES:: + + sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard("A2") + sage: s1,s2 = H.coxeter_group().simple_reflections() + sage: T = H.T() + sage: Cp = H.Cp() + sage: T.to_Cp_basis(s1) + v*Cp[1] + (-u^-1*v^2) + sage: Cp(T(s1)) + v*Cp[1] + (-u^-1*v^2) + sage: Cp(T(s1)+1) + v*Cp[1] + (-u^-1*v^2+1) + sage: Cp(T(s1*s2)+T(s1)+T(s2)+1) + v^2*Cp[1,2] + (-u^-1*v^3+v)*Cp[1] + (-u^-1*v^3+v)*Cp[2] + + (u^-2*v^4-2*u^-1*v^2+1) + sage: Cp(T(s1*s2*s1)) + v^3*Cp[1,2,1] + (-u^-1*v^4)*Cp[2,1] + (-u^-1*v^4)*Cp[1,2] + + (u^-2*v^5)*Cp[1] + (u^-2*v^5)*Cp[2] + (-u^-3*v^6) + """ A = self.realization_of() return self._to_Cp_basis(w, A.Cp()) @cached_method def to_Cp_Coxeter3_basis(self, w): + r""" + Return `T_w` as a linear combination of `C^{\prime}`-basis elements, + using the ``Cp_Coxeter3`` implementation. + + EXAMPLES:: + + sage: A2 = CoxeterGroup('A2', implementation='coxeter3') + sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard(A2) + sage: s1,s2 = H.coxeter_group().simple_reflections() + sage: T = H.T() + sage: Cp = H.Cp_Coxeter3() + sage: T.to_Cp_Coxeter3_basis(s1) + v*Cp[1] + (-u^-1*v^2) + sage: Cp(T(s1)) + v*Cp[1] + (-u^-1*v^2) + sage: Cp(T(s1)+1) + v*Cp[1] + (-u^-1*v^2+1) + sage: Cp(T(s1*s2)+T(s1)+T(s2)+1) + v^2*Cp[1,2] + (-u^-1*v^3+v)*Cp[1] + (-u^-1*v^3+v)*Cp[2] + + (u^-2*v^4-2*u^-1*v^2+1) + sage: Cp(T(s1*s2*s1)) + v^3*Cp[1,2,1] + (-u^-1*v^4)*Cp[1,2] + (-u^-1*v^4)*Cp[2,1] + + (u^-2*v^5)*Cp[1] + (u^-2*v^5)*Cp[2] + (-u^-3*v^6) + """ A = self.realization_of() return self._to_Cp_basis(w, A.Cp_Coxeter3()) From 236b8b324fc3a6c4ecc409ba8fbb1af6bda35bd8 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 23 Jul 2021 15:37:45 -0600 Subject: [PATCH 055/511] Improve commenting on generator decomposition stuff --- src/sage/algebras/iwahori_hecke_algebra.py | 29 ++++++++++++---------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 128fce56ccf..e3c3bdd4fa9 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2173,7 +2173,9 @@ def __init__(self, algebra, prefix='Cp'): # TODO: Better error message raise ValueError('the Cp_Coxeter3 basis is only supported in a Hecke algebra with standard normalizations (explain)') - # Construct a free algebra over generators representing the C' generators: { Cp_s : s in S } + # Construct a free algebra over generators representing the Cp generators: { Cp_s : s in S } + # We use this to represent polynomials in the Cp generators. e.g., we represent the element + # Cp_{121} as Cp1*Cp2*Cp1 - Cp1 self._generator_algebra = FreeAlgebra(algebra.base_ring(), ['Cp{}'.format(s) for s in self.index_set()]) # The correspondence between indices and formal generators of the generator algebra self._generators = { s: self._generator_algebra('Cp{}'.format(s)) for s in self.index_set() } @@ -2399,26 +2401,27 @@ class docs enough here. I lean towards describing the algorithm once gen_expression = self._decompose_into_generators(w2) other_element = self.monomial(w1) - # gen_expression is a linear combination of products of the C' generators - # Now, build everything back up, continually multiplying on the left by a single generator at a time + # gen_expression is a linear combination of products of the Cp + # generators. e.g., gen_expression = 2*Cp1*Cp2*Cp1 - Cp1 We now + # perform (2*Cp1*Cp2*Cp1 - Cp1) * other_element by proceeding one + # generator at a time. result = self(0) - # Iterate through the sum of terms + # Proceed through the terms, multiplying each term onto other_element + # and adding that summand onto result. for (p, coeff) in gen_expression: - # p is a product of generators, i.e. 2*g1*g2*g1; multiply it by other_element - # Build summand multiplicatively, going through variables (and their exponents) in p - # If gen_expression is being multiplied on the right, we need to start at the left - # end of p, and vice versa. + # is a term, e.g. p = Cp1*Cp2*Cp1 and coeff = 2 summand = coeff * other_element p_list = list(p) if side == 'right' else list(p)[::-1] - # Iterate through the product of generators + # Iterate through the generators in the term, multiplying each generator + # onto other_element and multiplying the result onto summand. for (gen, exponent) in p_list: + # gen is some formal generator Cp{s} (it is in the + # underlying monoid of self._generator_algebra so coercion + # is required). e.g. gen = Cp1 and exponent = 1. s = self._index_of_generator[self._generator_algebra(gen)] - # gen is in the underlying monoid of _generator_algebra, so coercion is required for i in range(exponent): - # Perform C'_s * summand (on the appropriate side), - # however many times C'_s is represented in the product - # according to the exponent. + # Perform the product C'_s * summand, exponent-many times. summand = self._product_with_generator(side, s, summand) result += summand From b4d7c9e45d46b06cd804d34d45af9bf9f354ad59 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 23 Jul 2021 15:37:54 -0600 Subject: [PATCH 056/511] Remove long-form descriptions from private method docs. --- src/sage/algebras/iwahori_hecke_algebra.py | 49 +--------------------- 1 file changed, 1 insertion(+), 48 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index e3c3bdd4fa9..2c74443c0a8 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2215,25 +2215,6 @@ def _product_with_generator_on_basis(self, side, s, w): Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting `C^{\prime}_s` on the given ``side``. - For each generator `s` and element `x`, the products `C^{\prime}_s - \cdot C^{\prime}_w` is given by the following formulas: - - .. MATH:: - - C^{\prime}_s \cdot C^{\prime}_w = - \begin{cases} - (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ - C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, & \text{if } \ell(sw) = \ell(w)+1. - \end{cases} - - C^{\prime}_w \cdot C^{\prime}_s = - \begin{cases} - (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(ws) = \ell(w)-1,\\ - C^{\prime}_{ws}+\sum_{v\leq w, vs \leq v} \mu(v,w)C^{\prime}_v, & \text{if } \ell(ws) = \ell(w)+1. - \end{cases} - - where `\leq` is the Bruhat order and the numbers `\mu(v,w)` are the `mu`-coefficients of [Lus2014]_. - INPUT: - ``side`` -- string; 'left' or 'right' @@ -2301,35 +2282,7 @@ def _product_with_generator(self, side, s, x): def _decompose_into_generators(self, w): r""" Decompose `C^{\prime}_w` into a polynomial in the KL generators - `C^{\prime}_s` (an element of the free algebra - `self.generator_algebra`) - - The decomposition is obtained recursively, by induction on - `\ell(w)`. If `ell(w) < 2` the decomposition is trivial (see - Examples). If `\ell(w) \geq 2`, write `w=su` where `s` is a left - descent of `w` so that `\ell(w) = \ell(u) + 1`, then use the formula - that - - .. MATH:: - C^{\prime}_s \cdot C^{\prime}_u = - C^{\prime}_{su}+\sum_{v\leq u, sv \leq v} \mu(v,u)C^{\prime}_v - - to conclude that - - .. MATH:: - C^{\prime}_{w}= C^{\prime}_s \cdot C^{\prime}_u - \sum_{v\leq u, sv \leq v} \mu(v,u)C^{\prime}_v. - - The element `u` and the elements `v` on the right side all have - smaller length than `w`, so they can be obtained by induction. - - INPUT: - - - ``w`` -- word in self.coxeter_group() - - OUTPUT: - - An element of ``self._generator_algebra`` describing how to express - `C^{\prime}_w` in terms of the generators `C^{\prime}_s`. + `C^{\prime}_s`. EXAMPLES:: From 89c8ee33b913e143bae9404cfdab2c62195b896a Mon Sep 17 00:00:00 2001 From: Tianyuan Xu Date: Wed, 28 Jul 2021 15:57:37 -0600 Subject: [PATCH 057/511] more docstring edits --- build/pkgs/sage_sws2rst/src | 1 - src/sage/algebras/iwahori_hecke_algebra.py | 311 +++++++++++++-------- 2 files changed, 191 insertions(+), 121 deletions(-) delete mode 120000 build/pkgs/sage_sws2rst/src diff --git a/build/pkgs/sage_sws2rst/src b/build/pkgs/sage_sws2rst/src deleted file mode 120000 index 2de26d80e1e..00000000000 --- a/build/pkgs/sage_sws2rst/src +++ /dev/null @@ -1 +0,0 @@ -../../../pkgs/sage-sws2rst \ No newline at end of file diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 2c74443c0a8..40d60fd1835 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2004,136 +2004,152 @@ class Cp_Coxeter3(_KLHeckeBasis): Directly compute products in the `C^{\prime}`-basis by using du Cloux's Coxeter3 package. - TODO: [State assumptions] normalization/coxeter3 implementation + To use this class, the Hecke algebra needs to be created in the + "standard" presentation where `\{q_1,q_2\} = \{v^2,1\}` as sets or the + "normalized" presentations where `\{q_1,q_2\} = \{v,-v^-1\}` as sets. + The Hecke algebra also needs to be created from a Coxeter group defined + using the 'coxeter3' implementation; see the examples to follow. Expanding products of the form `C^{\prime}_x \cdot C^{\prime}_y` in the `C^{\prime}`-basis is useful for computing Kazhdan-Lusztig cells of Coxeter systems and the corresponding cell modules of Iwahori-Hecke - algebras. Such expansion is controlled by the following formula (and - the analogous formula for `C^{\prime}_s \cdot C^{\prime}_w`) under both - the "standard" and the "normalized" presentations of the Iwahori-Hecke - algebra, where the quadratic relation is `(T_s-q^2)(T_s+1)=0` and - `(T_s-q)(T_s+q^-1)=0` for each generator `s`, respectively. - - .. MATH:: C^{\prime}_s \cdot C^{\prime}_w = \begin{cases} - (q+q^-1)C^{\prime}_{w}, & - \text{if } \ell(sw) = \ell(w)-1,\\ - C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, & - \text{if } \ell(sw) = \ell(w)+1. \end{cases} - - where `\leq` is the Bruhat order on the underlying Coxeter group and + algebras. The emphasis of this class is to compute such products more + directly in the `C^{\prime}`-basis, as opposed to converting the + `C^{\prime}`-basis to the `T`-basis, calculating the product in the + `T`-basis, and converting the results back to the `C^{\prime}`-basis + (see Line 1303). The latter approach is used in the + _Basis.product_on_basis method on Line 1298. The direct + method significantly speeds up the product computations. + + The following formulas for products of the forms `C^{\prime}_s \cdot + C^{\prime}_w` and `C^{\prime}_w \cdot C^{\prime}_s`, where `s` is a + generator of the Coxeter group and `w` an arbitrary element, are key to + this class. The formulas are valid for both the standard and normalized + presentation of the Hecke algebra, and they control the products of the + `C^{\prime}_x \cdot C^{\prime}_y` for arbitrary `x,y`. + + .. MATH:: + C^{\prime}_s \cdot C^{\prime}_w = + \begin{cases} + (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ + C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, + & \text{if } \ell(sw) = \ell(w)+1. + \end{cases} + + C^{\prime}_w \cdot C^{\prime}_s = + \begin{cases} + (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(ws) = \ell(w)-1,\\ + C^{\prime}_{ws}+\sum_{v\leq w, vs \leq v} \mu(v,w)C^{\prime}_v, + & \text{if } \ell(ws) = \ell(w)+1. + \end{cases} + + In the above, `\leq` is the Bruhat order on the Coxeter group and `\mu(v,w)` is the "leading coefficient of Kazhdan-Lusztig polynomials"; - see [KL1979]_ and [Lus2014]_ for more details. - - The emphasis of this class is to compute products in the - `C^{\prime}`-basis directly, by using the above formula and calling the - necessary `\mu`-coefficients from Sage's implementation of Fokko du - Cloux's Coxeter3 package. This methods computes the products faster than - the _Basis.product_on_basis method on Line 1298, which needs to convert - the `C^{\prime}`-basis to the `T`-basis, calculate the product in the - `T`-basis, and convert the results back to the `C^{\prime}`-basis. For - example, the product `C^{\prime}_{32345} * C^{\prime}_{23}` in the Hecke - algebra of type 'B_9' takes more than 30 seconds with the latter method - but is instant using this class. - - .. TODO:: - - Use the analog of the displayed formula to implement - `C^{\prime}`-products in the multi-parameter Iwahori-Hecke algebra; - see Section 6 of [Lus2013]_. - + see [KL1979]_ and [Lus2014]_ for more details. The method designates + the computation of the `\mu`-coefficients to Fokko du Cloux's + 'coxeter3' package (wrapped in Sage), which is why the method requires + the creation of the Coxeter group in the 'coxeter3' implementation. + EXAMPLES: Basic usage:: + + # To create the basis, define the Coxeter group with 'coxeter3' and + # the Hecke algebra with the standard or normalized presentation. sage: R. = LaurentPolynomialRing(ZZ) sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: s1, s2, s3 = A3.simple_reflections() - sage: H = IwahoriHeckeAlgebra(A3, v**2) + sage: H = IwahoriHeckeAlgebra(A3, v**2) # standard presentation sage: Cp = H.Cp_Coxeter3() + + # TODO: 1. avoid Cp, maybe CpC or CpC3? 2. show that CpC3 IS Cp (more reason for 1) + + sage: s1, s2, s3 = A3.simple_reflections() sage: Cp(s1*s2*s1) Cp[1,2,1] sage: Cp(s1)**2 (v^-1+v)*Cp[1] sage: Cp(s1)*Cp(s2)*Cp(s1) Cp[1,2,1] + Cp[1] - sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] + + The following computation take a long time in the + _Basis.product_on_basis method as mentioned on Line 1941, but it is + instant in the current method :: + + sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] Cp[1,2,1,3,2] + Cp[1,2,1] + Cp[1,3,2] - The IwahoriHeckeAlgebra must be initialized with a ``CoxeterGroup`` - implemented with coxeter3 and the Hecke parameters must be v^2, -1 or v, - -1/v:: + Another example, with the Hecke algebra of type `B9` in the normalized + presentation :: + + sage: B9 = CoxeterGroup(CoxeterType(['B', 9]).relabel({ i: 9-i+1 for i in range(1, 10) }), implementation='coxeter3') + # the (optional) relabeling above ensures `m(1,2)=4`, i.e., that + # the generators 1, 2 form the strong bond in the Dynkin diagram. + + sage: H = IwahoriHeckeAlgebra(B9, v, -1/v) + sage: Cp = H.Cp_Coxeter3() + sage: Cp[1,2,1,2] + Cp[1,2,1,2] + + The following computation also takes a long time in + _Basis.product_on_basis, but it is instant here :: + + sage: Cp[3,2,3,4,5] * Cp[2,3] + (v^-1+v)*Cp[2,3,2,4,3,5] + (v^-1+v)*Cp[2,3,2,5] + + Directly creating a Hecke algebra from its Coxeter type does not work + currently. Instead, a Coxeter group implemented with 'coxeter3' must be + created first :: sage: H = IwahoriHeckeAlgebra('A3', v**2) sage: H.Cp_Coxeter3() Traceback (most recent call last): ... ValueError: algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis + + With the Coxeter group created first, the Hecke algebra must be defined + with the standard or normalized presentation mentioned before :: + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, QQ(1)) + sage: H = IwahoriHeckeAlgebra(A3, QQ(1)) sage: H.Cp_Coxeter3() Traceback (most recent call last): ... - ValueError: the Cp_Coxeter3 basis is only supported in a Hecke algebra with standard normalizations (explain) - - Products of the form `Cp_s \cdot Cp_y` where `s` is a generator are - computed by the earlier formula:: + ValueError: the Cp_Coxeter3 basis is only supported in a Hecke + algebra with the standard or normalized presentations (i.e., need + `\{q_1,q_2\} = \{v^2,1\}` or `\{q_1,q_2\} = \{v,-v^-1\}` as sets) + sage: H.Cp_Coxeter3() + - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, v**2) - sage: Cp = H.Cp_Coxeter3() - sage: Cp[1] * Cp[1] - (v^-1+v)*Cp[1] - sage: Cp[1] * Cp[2] - Cp[1,2] - sage: Cp[1] * Cp[2,1] - Cp[1,2,1] + Cp[1] - sage: Cp[1] * Cp[2,1,3] - Cp[1,2,1,3] + Cp[1,3] - sage: Cp[2] * Cp[1,3,2,1,3] - Cp[1,2,1,3,2,1] + Cp[1,2,1,3] + Cp[2,3,2,1] - More generally, we can compute products of the form `C^{\prime}_x \cdot - C^{\prime}_y` for general `x, y`:: + ALGORITHM : + Write `b` for `C^{\prime}`. This class computes each product `b_x + \cdot b_y` as follows. - sage: Cp[1,2,1] * Cp[3,1] - (v^-1+v)*Cp[1,2,1,3] - sage: Cp[1,2,1] * Cp[3,1,2] - (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] + If `\ell(x) \leq \ell(y)`, then we first decompose `b_x` into a + polynomial in the generators `b_s (s\in S)` and then multiply that + polynomial with `b_y`. Both steps are carried out by repeated + application of the formula for `b_s * b_w` mentioned before. For + example, in the computation of the product `b[1,2,1] * b[3,1,2]` in + type `A3`, the left term `b_{121}` is first decomposed into the + linear combination `b_1*b_2*b_1 - b_1` behind the scenes. - We can compute complex products in in type `B9`, while relabelling the - generators so that the long braid is between the first two generators:: - - sage: B9 = CoxeterGroup(CoxeterType(['B', 9]).relabel({ i: 9-i+1 for i in range(1, 10) }), implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(B9, v, -1/v) - sage: Cp = H.Cp_Coxeter3() - sage: Cp[1,2,1,2] - Cp[1,2,1,2] - sage: Cp[3,2,3,4,5] * Cp[2,3] - (v^-1+v)*Cp[2,3,2,4,3,5] + (v^-1+v)*Cp[2,3,2,5] - - - .. NOTE:: - - The products `B_x \cdot B_y` are computed as follows: if - `\ell(x) \leq \ell(y)`, then we first decompose `B_x` into a - polynomial in the generators `B_s (s\in S)`, then multiplies that - linear combination onto `B_y`; otherwise we decompose `B_y` and - multiply the result onto `B_x`. For example, in the computation of - `B[1,2,1] * B[3,1,2]` in type `A3`, the left term `B[1,2,1]` is - first (essentially) decomposed into the linear combination - `B[1]*B[2]*B[1] - B[1]` behind the scenes. The decomposition is - achieved via the [_decompose_into_generators function], which takes - an element `B_w` and gives an element of the free algebra over \{ - B_s \; : \; s \in S \}, whose image under the canonical homomorphism - from the free algebra is precisely `B_w`. + If `\ell(x) > \ell(y)`, we decompose `b_y` into a polynomial in + `b_s (s\in S)` and multiply that polynomial with `b_x`. .. SEEALSO:: + # TODO: edit the following + :ref: [KL1979]_, [Lus2013]_ - :meth:`sage.somewhere.other_useful_method`, cell stuff - [coxeter3?] + :meth: _Basis.product_on_basis, cell stuff + :package?[coxeter3?] + .. TODO:: + + Use the analog of the displayed formulas to implement + `C^{\prime}`-products in the multi-parameter Iwahori-Hecke algebra; + see Section 6 of [Lus2013]_. """ _basis_name = 'Cp_Coxeter3' @@ -2144,6 +2160,8 @@ def __init__(self, algebra, prefix='Cp'): EXAMPLES:: + TODO: Do we still need all these here? Space after (to + separate good and bad) sage: R. = LaurentPolynomialRing(ZZ, 'v') sage: A3 = CoxeterGroup('A3', implementation='coxeter3') sage: H = IwahoriHeckeAlgebra(A3, v**2) @@ -2170,12 +2188,24 @@ def __init__(self, algebra, prefix='Cp'): else: if not algebra._is_generic: # If this algebra is generic, it's only being used to coerce to the T basis, not perform computations - # TODO: Better error message - raise ValueError('the Cp_Coxeter3 basis is only supported in a Hecke algebra with standard normalizations (explain)') + # TODO: Better error message (TX made some changes) + raise ValueError('the Cp_Coxeter3 basis is only supported in a Hecke algebra with the standard or normalized presentations (i.e., need `\{q_1,q_2\} = \{v^2,1\}` or `\{q_1,q_2\} = \{v,-v^-1\}` as sets)') + + # TODO: change the name systematically, bad to use Cp. (sorry I + # went back to g) + + # Construct a free algebra over generators {g_s:s in S} + # The free algebra is merely a formal device to encode polynomials + # in the `C^{prime}`-basis. For example, we mentioned in + # "ALGORITHM" how it is useful to decompose `b_{121}` to the + # polynomial `b_1*b_2* b_1 - b_1` where `b` stands for + # `C^{\prime}`. The polynomial will be encoded as `g_1*g_2*g_1 - + # g_1`. While this formal construction may seem unnecessary, it + # appears to be the most convenient way to encode the polynomials + # mentioned above, and we are not able to remove it at the moment. + + # TODO: better explain the last sentence, maybe with an example? - # Construct a free algebra over generators representing the Cp generators: { Cp_s : s in S } - # We use this to represent polynomials in the Cp generators. e.g., we represent the element - # Cp_{121} as Cp1*Cp2*Cp1 - Cp1 self._generator_algebra = FreeAlgebra(algebra.base_ring(), ['Cp{}'.format(s) for s in self.index_set()]) # The correspondence between indices and formal generators of the generator algebra self._generators = { s: self._generator_algebra('Cp{}'.format(s)) for s in self.index_set() } @@ -2215,6 +2245,9 @@ def _product_with_generator_on_basis(self, side, s, w): Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting `C^{\prime}_s` on the given ``side``. + # TODO: again, 'Cp' might be bad; put left as default side (since s + # comes before w in the input tuple)? + INPUT: - ``side`` -- string; 'left' or 'right' @@ -2230,16 +2263,21 @@ def _product_with_generator_on_basis(self, side, s, w): sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp_Coxeter3() sage: Cp._product_with_generator_on_basis('left', 1, A3([2,1])) Cp[1,2,1] + Cp[1] + sage: Cp._product_with_generator_on_basis('right', 1, A3([2,1])) + (v+v^-1) * Cp[1] sage: Cp._product_with_generator_on_basis('right', 2, A3([1,3,2,1,3])) Cp[1,2,1,3,2,1] + Cp[1,2,3,2] + Cp[1,3,2,1] """ - + + # TODO: consistency in our docstring: ticks or not + other things. + + # If `s` is a descent of `w` on the `side`, the product is (v + v^-1) C'_w: if w.has_descent(s, side=side): - # TODO: notation? - # Descent case, return (q + q^-1) C'_w return self.delta * self.monomial(w) + # Otherwise the product is \sum_{v \leq w; sv < v} mu(v, w) C'_v + # if `side` is left and \sum_{v \leq w; vs < v} mu(v, w) C'_s if + # `side` is right, as mentioned before. else: - # Additively build the sum \sum_{v \leq w; sv < v} mu(v, w) C'_v element = self(0) between = self._W.bruhat_interval([], w) for x in between: @@ -2249,15 +2287,17 @@ def _product_with_generator_on_basis(self, side, s, w): # Compute mu-coefficient via coxeter3 element += x.mu_coefficient(w) * self.monomial(x_elt) - # Doing self._W([s]) * w may not ensure that the word is is normal form - # Since W's element constructor does ensure that, use this method. - longer_word = self._W([s] + list(w) if side == 'left' else list(w) + [s]) - return self.monomial(longer_word) + element + # Doing self._W([s]) * w may not ensure that the word is + # normal form Since W's element constructor does ensure that, + # use the constructor. + # TODO: change the above for better reader friendliness. + longer_word = self._W([s] + list(w) if side == 'left' else + list(w) + [s]) return self.monomial(longer_word) + + element - def _product_with_generator(self, side, s, x): - r""" - Compute the product of `C^{\prime}_s` with any linear combination of - `C^{\prime}`-basis elements. + def _product_with_generator(self, side, s, x): + r""" + Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elements. INPUT: @@ -2284,27 +2324,60 @@ def _decompose_into_generators(self, w): Decompose `C^{\prime}_w` into a polynomial in the KL generators `C^{\prime}_s`. + For every element `y\in W` with length `\ell(w)>1` and every left descent `s` of + `y`, write `y=sw` (so `x=sw`) and note that + + .. MATH:: + C^{\prime}_y = C^{\prime}_s * C^{\prime}_{w} - \sum_{v\le w; sv< + v} \mu(v,w) C^{\prime}_v + + by the formula for `C^{\prime}_s * C^{\prime}_w`. All `v`'s in the + sum on the right side are lower than `w` in the Bruhat order and + hence shorter than `w`, so the above formula allows us to decompose + `C^{\prime}_y` into the generators `C^{\prime}_s` by induction on + `\ell(y)`, with the base case being `\ell(y)=1` where `y` is itself + a Coxeter generator. (For the group identity `e` we have `C_e=1` in + the Hecke algebra.) + EXAMPLES:: + + # TODO: fix notation sage: R. = LaurentPolynomialRing(ZZ, 'v') sage: A3 = CoxeterGroup('A3', implementation='coxeter3') sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp_Coxeter3() - sage: Cp._decompose_into_generators(A3([1,2])) # C_{12} = C_1C_2 - Cp1*Cp2 + + When `y` is itself a generator `s`, the decomposition is trivial :: + + sage: Cp._decompose_into_generators(A3([1])) + Cp[1] + + Another example, where it happens that `C^{\prime}_y = C^{\prime}_s * C^{\prime}_{w}` exactly :: + + sage: Cp._decompose_into_generators(A3([2,1])) # C_{21} = C_2C_1 + Cp[2]*Cp[1] + + In more general situations the sum is a linear combination because + of the lower order terms `v`'s that can appear in each intermediate + step; for example, we have C_121=C_1*C_21 - C_1= C_1*C_2*C_1-C_1 :: + sage: Cp._decompose_into_generators(A3([1,2,1])) # C_{121} = C_1C_2C_1 - C_1 -Cp1 + Cp1*Cp2*Cp1 sage: Cp._decompose_into_generators(A3([1,2,3,1,2])) Cp1 - Cp1*Cp2*Cp1 - Cp1*Cp3*Cp2 + Cp1*Cp2*Cp1*Cp3*Cp2 """ + # \ell(y) < 1 if len(w) == 0: return self.generator_algebra(1) if len(w) == 1: return self._generators[w[0]] - + # \ell(y) > 1, we use the induction on `\ell(y)` and recursively + # find the decomposition s = w[0] w1 = w[1:] - + # TODO: remove some doc strings below. We've explained the ideas in enough detail. + # Additively build the sum term (lower order terms) sum_term = self(0) between = self._W.bruhat_interval([], w1) @@ -2329,9 +2402,12 @@ def product_on_basis(self, w1, w2): Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` in the `C^{\prime}`-basis. + The product is computed in the two steps as described in "ALGORITHM". + + # When `w` is the identity, `C_w` is the identity of the algebra. TODO: Describe our decision to decompose the smaller word...? Or is class docs enough here. I lean towards describing the algorithm once - in the class docs. + in the class docs. AGREED! EXAMPLES:: @@ -2343,8 +2419,8 @@ class docs enough here. I lean towards describing the algorithm once sage: Cp.product_on_basis(A3([1,2,1]), A3([3,1,2])) (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] """ - # Otherwise, decompose the first word into generators - # (as expressed as an element of the FreeAlgebra over 'generator' variables g1, ..., gn) + # Decompose one of `C_{w_1}` and `C_{w_2}` into a polynomial in the + # generators, then multiply the remaining one with the polynomial. if len(w1) <= len(w2): side = 'left' gen_expression = self._decompose_into_generators(w1) @@ -2354,11 +2430,6 @@ class docs enough here. I lean towards describing the algorithm once gen_expression = self._decompose_into_generators(w2) other_element = self.monomial(w1) - # gen_expression is a linear combination of products of the Cp - # generators. e.g., gen_expression = 2*Cp1*Cp2*Cp1 - Cp1 We now - # perform (2*Cp1*Cp2*Cp1 - Cp1) * other_element by proceeding one - # generator at a time. - result = self(0) # Proceed through the terms, multiplying each term onto other_element # and adding that summand onto result. From ce7d2edb0a45a72ae6c34cb10ea93740464be9bb Mon Sep 17 00:00:00 2001 From: Tianyuan Xu Date: Wed, 28 Jul 2021 17:58:33 -0600 Subject: [PATCH 058/511] edit ALGORITHM and doc string for the decomposition step --- src/sage/algebras/iwahori_hecke_algebra.py | 105 ++++++++++----------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 40d60fd1835..cc43dee34a2 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2079,15 +2079,15 @@ class Cp_Coxeter3(_KLHeckeBasis): sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] Cp[1,2,1,3,2] + Cp[1,2,1] + Cp[1,3,2] - Another example, with the Hecke algebra of type `B9` in the normalized - presentation :: + Below is another example, with the Hecke algebra of type `B9` in the normalized + presentation. The (optional) relabeling command ensures that `m(1,2)=4`, i.e., that + the generators 1, 2 form the strong bond in the Dynkin diagram. :: sage: B9 = CoxeterGroup(CoxeterType(['B', 9]).relabel({ i: 9-i+1 for i in range(1, 10) }), implementation='coxeter3') - # the (optional) relabeling above ensures `m(1,2)=4`, i.e., that - # the generators 1, 2 form the strong bond in the Dynkin diagram. - sage: H = IwahoriHeckeAlgebra(B9, v, -1/v) - sage: Cp = H.Cp_Coxeter3() + sage: Cp = H.Cp_Coxeter3() + + # TODO: create s1 to s9 sage: Cp[1,2,1,2] Cp[1,2,1,2] @@ -2118,25 +2118,44 @@ class Cp_Coxeter3(_KLHeckeBasis): ValueError: the Cp_Coxeter3 basis is only supported in a Hecke algebra with the standard or normalized presentations (i.e., need `\{q_1,q_2\} = \{v^2,1\}` or `\{q_1,q_2\} = \{v,-v^-1\}` as sets) - sage: H.Cp_Coxeter3() - ALGORITHM : Write `b` for `C^{\prime}`. This class computes each product `b_x - \cdot b_y` as follows. + \cdot b_y` in two steps as follows. If `\ell(x) \leq \ell(y)`, then we first decompose `b_x` into a polynomial in the generators `b_s (s\in S)` and then multiply that - polynomial with `b_y`. Both steps are carried out by repeated - application of the formula for `b_s * b_w` mentioned before. For - example, in the computation of the product `b[1,2,1] * b[3,1,2]` in - type `A3`, the left term `b_{121}` is first decomposed into the - linear combination `b_1*b_2*b_1 - b_1` behind the scenes. + polynomial with `b_y`. If `\ell(x) > \ell(y)`, we decompose `b_y` + into a polynomial in `b_s (s\in S)` and multiply that polynomial + with `b_x`. The second step (multiplication) is done by repeatedly + applying the key formulas displayed earlier directly. The first + step (decomposition) is done by induction on the Bruhat order as + follows: for every element `u\in W` with length `\ell(u)>1` and + every left descent `s` of `u`, write `u=sw` (so `w=su`) and note + that - If `\ell(x) > \ell(y)`, we decompose `b_y` into a polynomial in - `b_s (s\in S)` and multiply that polynomial with `b_x`. + .. MATH:: + C^{\prime}_u = C^{\prime}_s * C^{\prime}_{w} - \sum_{v\le u; sv< + v} \mu(v,w) C^{\prime}_v + by the key formulas, where the element `w` and all elements `v`'s + on the right side are lower than `u` in the Bruhat order; this + allows us to finish the computation by decomposing the lower order + terms `b_w` and each `b_v`. For example, for `u=121, s=1, w=21` in + type `A3` we have + + .. MATH:: + b_{121} = b_1*b_{21} - b_1, + + where the lower order term `b_{21}` further decomposes into + `b_2*b_1`, therefore `b_{121}=b_1*b_2 b_1 -b1`. We note that the + the base cases `\ell(x)=1` or `\ell(x)=0` of the above induction + occur when `x` is itself a Coxeter generator `s` or the group + identity, respectively. The decomposition is trivial in these cases + (we have `C_x=C_s` or `C_x=1`, the unit of the Hecke algebra). + + .. SEEALSO:: # TODO: edit the following @@ -2147,6 +2166,9 @@ class Cp_Coxeter3(_KLHeckeBasis): .. TODO:: + Accommodate generic presentations of the Hecke algebra other than + the standard and normalized ones. + Use the analog of the displayed formulas to implement `C^{\prime}`-products in the multi-parameter Iwahori-Hecke algebra; see Section 6 of [Lus2013]_. @@ -2167,6 +2189,7 @@ def __init__(self, algebra, prefix='Cp'): sage: H = IwahoriHeckeAlgebra(A3, v**2) sage: Cp = H.Cp_Coxeter3() + sage: H = IwahoriHeckeAlgebra('A3', v**2) sage: Cp = H.Cp_Coxeter3() Traceback (most recent call last): @@ -2184,7 +2207,7 @@ def __init__(self, algebra, prefix='Cp'): # TODO: rewrite this horribly ugly condition: if v != algebra.base_ring().one() and ((algebra.q1() == v**2 and algebra.q2() == -1) or (algebra.q1() == v and algebra.q2() == -1/v)): - self.delta = v + ~v + self.delta = v + ~v # TODO: this is why we need the two normalizations else: if not algebra._is_generic: # If this algebra is generic, it's only being used to coerce to the T basis, not perform computations @@ -2245,8 +2268,7 @@ def _product_with_generator_on_basis(self, side, s, w): Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting `C^{\prime}_s` on the given ``side``. - # TODO: again, 'Cp' might be bad; put left as default side (since s - # comes before w in the input tuple)? + # TODO: again, 'Cp' might be bad; INPUT: @@ -2286,14 +2308,12 @@ def _product_with_generator_on_basis(self, side, s, w): if x_elt.has_descent(s, side=side): # Compute mu-coefficient via coxeter3 element += x.mu_coefficient(w) * self.monomial(x_elt) - + # TODO: do something about the following; there's the bug fix now # Doing self._W([s]) * w may not ensure that the word is # normal form Since W's element constructor does ensure that, # use the constructor. - # TODO: change the above for better reader friendliness. - longer_word = self._W([s] + list(w) if side == 'left' else - list(w) + [s]) return self.monomial(longer_word) + - element + longer_word = self._W([s] + list(w) if side == 'left' else list(w) + [s]) + return self.monomial(longer_word) + element def _product_with_generator(self, side, s, x): r""" @@ -2319,25 +2339,11 @@ def _product_with_generator(self, side, s, x): """ return self.linear_combination((self._product_with_generator_on_basis(side, s, w), coeff) for (w, coeff) in x) - def _decompose_into_generators(self, w): + def _decompose_into_generators(self, w): r""" Decompose `C^{\prime}_w` into a polynomial in the KL generators - `C^{\prime}_s`. - - For every element `y\in W` with length `\ell(w)>1` and every left descent `s` of - `y`, write `y=sw` (so `x=sw`) and note that - - .. MATH:: - C^{\prime}_y = C^{\prime}_s * C^{\prime}_{w} - \sum_{v\le w; sv< - v} \mu(v,w) C^{\prime}_v + `C^{\prime}_s`; see "ALGORITHM". - by the formula for `C^{\prime}_s * C^{\prime}_w`. All `v`'s in the - sum on the right side are lower than `w` in the Bruhat order and - hence shorter than `w`, so the above formula allows us to decompose - `C^{\prime}_y` into the generators `C^{\prime}_s` by induction on - `\ell(y)`, with the base case being `\ell(y)=1` where `y` is itself - a Coxeter generator. (For the group identity `e` we have `C_e=1` in - the Hecke algebra.) EXAMPLES:: @@ -2348,25 +2354,23 @@ def _decompose_into_generators(self, w): sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp_Coxeter3() When `y` is itself a generator `s`, the decomposition is trivial :: - - sage: Cp._decompose_into_generators(A3([1])) + sage: w= A3([1]) + sage: Cp._decompose_into_generators(w) Cp[1] - Another example, where it happens that `C^{\prime}_y = C^{\prime}_s * C^{\prime}_{w}` exactly :: + Another example, where `C^{\prime}_y` happens to be a monomial :: sage: Cp._decompose_into_generators(A3([2,1])) # C_{21} = C_2C_1 Cp[2]*Cp[1] - In more general situations the sum is a linear combination because - of the lower order terms `v`'s that can appear in each intermediate - step; for example, we have C_121=C_1*C_21 - C_1= C_1*C_2*C_1-C_1 :: + In more general situations the sum is a polynomial :: sage: Cp._decompose_into_generators(A3([1,2,1])) # C_{121} = C_1C_2C_1 - C_1 -Cp1 + Cp1*Cp2*Cp1 sage: Cp._decompose_into_generators(A3([1,2,3,1,2])) Cp1 - Cp1*Cp2*Cp1 - Cp1*Cp3*Cp2 + Cp1*Cp2*Cp1*Cp3*Cp2 """ - # \ell(y) < 1 + # \ell(y) \leq 1 if len(w) == 0: return self.generator_algebra(1) if len(w) == 1: @@ -2404,11 +2408,6 @@ def product_on_basis(self, w1, w2): The product is computed in the two steps as described in "ALGORITHM". - # When `w` is the identity, `C_w` is the identity of the algebra. - TODO: Describe our decision to decompose the smaller word...? Or is - class docs enough here. I lean towards describing the algorithm once - in the class docs. AGREED! - EXAMPLES:: sage: R. = LaurentPolynomialRing(ZZ, 'v') @@ -2429,7 +2428,6 @@ class docs enough here. I lean towards describing the algorithm once side = 'right' gen_expression = self._decompose_into_generators(w2) other_element = self.monomial(w1) - result = self(0) # Proceed through the terms, multiplying each term onto other_element # and adding that summand onto result. @@ -2451,6 +2449,7 @@ class docs enough here. I lean towards describing the algorithm once result += summand return result + class C(_KLHeckeBasis): r""" From 235b4f9305cf03ab1664f375e5135af6de1474ab Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Wed, 28 Jul 2021 18:41:56 -0600 Subject: [PATCH 059/511] Fix documentation formatting --- src/sage/algebras/iwahori_hecke_algebra.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index cc43dee34a2..b95be14a75d 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2316,8 +2316,8 @@ def _product_with_generator_on_basis(self, side, s, w): return self.monomial(longer_word) + element def _product_with_generator(self, side, s, x): - r""" - Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elements. + r""" + Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elements. INPUT: From a1c8da901e2e45aa81310414a75beabbc898a070 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Wed, 28 Jul 2021 18:57:52 -0600 Subject: [PATCH 060/511] Remove the free algebra in _decompose_into_generators; use dictionaries --- src/sage/algebras/iwahori_hecke_algebra.py | 96 ++++++++-------------- 1 file changed, 35 insertions(+), 61 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index b95be14a75d..4737788cc10 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2214,26 +2214,6 @@ def __init__(self, algebra, prefix='Cp'): # TODO: Better error message (TX made some changes) raise ValueError('the Cp_Coxeter3 basis is only supported in a Hecke algebra with the standard or normalized presentations (i.e., need `\{q_1,q_2\} = \{v^2,1\}` or `\{q_1,q_2\} = \{v,-v^-1\}` as sets)') - # TODO: change the name systematically, bad to use Cp. (sorry I - # went back to g) - - # Construct a free algebra over generators {g_s:s in S} - # The free algebra is merely a formal device to encode polynomials - # in the `C^{prime}`-basis. For example, we mentioned in - # "ALGORITHM" how it is useful to decompose `b_{121}` to the - # polynomial `b_1*b_2* b_1 - b_1` where `b` stands for - # `C^{\prime}`. The polynomial will be encoded as `g_1*g_2*g_1 - - # g_1`. While this formal construction may seem unnecessary, it - # appears to be the most convenient way to encode the polynomials - # mentioned above, and we are not able to remove it at the moment. - - # TODO: better explain the last sentence, maybe with an example? - - self._generator_algebra = FreeAlgebra(algebra.base_ring(), ['Cp{}'.format(s) for s in self.index_set()]) - # The correspondence between indices and formal generators of the generator algebra - self._generators = { s: self._generator_algebra('Cp{}'.format(s)) for s in self.index_set() } - self._index_of_generator = { v: k for (k, v) in self._generators.items() } - # Define conversion to the other Cp basis self.module_morphism(self.to_Cp_basis, codomain=algebra.Cp(), category=self.category() ).register_as_coercion() @@ -2342,39 +2322,40 @@ def _product_with_generator(self, side, s, x): def _decompose_into_generators(self, w): r""" Decompose `C^{\prime}_w` into a polynomial in the KL generators - `C^{\prime}_s`; see "ALGORITHM". - - - EXAMPLES:: - - # TODO: fix notation + `C^{\prime}_s`; see "ALGORITHM". TODO: Reference "ALGORITHM" + + EXAMPLES: + + :: sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + sage: W = CoxeterGroup('A3', implementation='coxeter3') sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp_Coxeter3() - When `y` is itself a generator `s`, the decomposition is trivial :: - sage: w= A3([1]) - sage: Cp._decompose_into_generators(w) - Cp[1] + When `y` is itself a generator `s`, the decomposition is trivial:: - Another example, where `C^{\prime}_y` happens to be a monomial :: + sage: Cp._decompose_into_generators(W([1])) + {(1,): 1} - sage: Cp._decompose_into_generators(A3([2,1])) # C_{21} = C_2C_1 - Cp[2]*Cp[1] + Another example, where Cp_y happens to be a monomial; Cp_{21} = + Cp_2*Cp_1:: - In more general situations the sum is a polynomial :: + sage: Cp._decompose_into_generators(A3([2,1])) + {(2, 1): 1} + + In more general situations the sum is a polynomial; Cp_{121} = + Cp_1*Cp_2*Cp_1 - Cp_1 sage: Cp._decompose_into_generators(A3([1,2,1])) # C_{121} = C_1C_2C_1 - C_1 - -Cp1 + Cp1*Cp2*Cp1 + {(1, 2, 1): 1, (1,): -1} sage: Cp._decompose_into_generators(A3([1,2,3,1,2])) - Cp1 - Cp1*Cp2*Cp1 - Cp1*Cp3*Cp2 + Cp1*Cp2*Cp1*Cp3*Cp2 + {(1, 2, 1, 3, 2): 1, (1, 2, 1): -1, (1,): 1, (1, 3, 2): -1} """ # \ell(y) \leq 1 if len(w) == 0: - return self.generator_algebra(1) + return {(): 1} if len(w) == 1: - return self._generators[w[0]] + return {(w[0],): 1} # \ell(y) > 1, we use the induction on `\ell(y)` and recursively # find the decomposition s = w[0] @@ -2392,14 +2373,16 @@ def _decompose_into_generators(self, w): # Compute mu-coefficient via coxeter3 sum_term += self.base_ring()(x.mu_coefficient(w1)) * self.monomial(x_elt) - # In the expression above, we need to recurse and decompose C_{w1} into generators, - # and then go through the terms of sum_term (lower order terms) and decompose those C_y's into generators - alg_element = self._generators[s] * self._decompose_into_generators(w1) - for (v, coeff) in sum_term: - # We're subtracting 'sum_term' - alg_element -= coeff * self._decompose_into_generators(v) + # Recurse and decompose C_{w1} into generators, then go through the + # lower order terms in sum_term and decompose those into generators. + # Perform (distrubute) Cp_s * Cp_{w1} + result = {(s,) + gens: coeff for (gens, coeff) in self._decompose_into_generators(w1).items()} + for (v, c1) in sum_term: + # Subtract off each term from `sum_term`. + for (gens, c2) in self._decompose_into_generators(v).items(): + result[gens] = result.get(gens, 0) - c1*c2 - return alg_element + return result def product_on_basis(self, w1, w2): r""" @@ -2418,7 +2401,7 @@ def product_on_basis(self, w1, w2): sage: Cp.product_on_basis(A3([1,2,1]), A3([3,1,2])) (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] """ - # Decompose one of `C_{w_1}` and `C_{w_2}` into a polynomial in the + # Decompose one of Cp_{w1} and Cp_{w2} into a polynomial in the # generators, then multiply the remaining one with the polynomial. if len(w1) <= len(w2): side = 'left' @@ -2429,22 +2412,13 @@ def product_on_basis(self, w1, w2): gen_expression = self._decompose_into_generators(w2) other_element = self.monomial(w1) result = self(0) - # Proceed through the terms, multiplying each term onto other_element - # and adding that summand onto result. - for (p, coeff) in gen_expression: - # is a term, e.g. p = Cp1*Cp2*Cp1 and coeff = 2 + # Proceed through the terms, multiplying the generators in each term + # onto other_element and adding that summand onto result. + for (p, coeff) in gen_expression.items(): summand = coeff * other_element p_list = list(p) if side == 'right' else list(p)[::-1] - # Iterate through the generators in the term, multiplying each generator - # onto other_element and multiplying the result onto summand. - for (gen, exponent) in p_list: - # gen is some formal generator Cp{s} (it is in the - # underlying monoid of self._generator_algebra so coercion - # is required). e.g. gen = Cp1 and exponent = 1. - s = self._index_of_generator[self._generator_algebra(gen)] - for i in range(exponent): - # Perform the product C'_s * summand, exponent-many times. - summand = self._product_with_generator(side, s, summand) + for s in p_list: + summand = self._product_with_generator(side, s, summand) result += summand From 2e8eb1e998099b179d12e51058e2adfd4d6b9fb5 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Wed, 28 Jul 2021 18:58:09 -0600 Subject: [PATCH 061/511] Documentation fixes; comment consistency; remove coxeter3 bug workaround --- src/sage/algebras/iwahori_hecke_algebra.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 4737788cc10..d0f137fb678 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2273,7 +2273,7 @@ def _product_with_generator_on_basis(self, side, s, w): # TODO: consistency in our docstring: ticks or not + other things. - # If `s` is a descent of `w` on the `side`, the product is (v + v^-1) C'_w: + # If `s` is a descent of `w` on the `side`, the product is (v + v^-1) Cp_w: if w.has_descent(s, side=side): return self.delta * self.monomial(w) # Otherwise the product is \sum_{v \leq w; sv < v} mu(v, w) C'_v @@ -2288,11 +2288,7 @@ def _product_with_generator_on_basis(self, side, s, w): if x_elt.has_descent(s, side=side): # Compute mu-coefficient via coxeter3 element += x.mu_coefficient(w) * self.monomial(x_elt) - # TODO: do something about the following; there's the bug fix now - # Doing self._W([s]) * w may not ensure that the word is - # normal form Since W's element constructor does ensure that, - # use the constructor. - longer_word = self._W([s] + list(w) if side == 'left' else list(w) + [s]) + longer_word = self._W([s]) * w if side == 'left' else w * self._W([s]) return self.monomial(longer_word) + element def _product_with_generator(self, side, s, x): @@ -2305,7 +2301,7 @@ def _product_with_generator(self, side, s, x): - ``s`` -- integer in self.index_set() - - ``w`` -- any element of self + - ``x`` -- any element of self EXAMPLES:: From cc41a95921ec1182c23ce1f5b3324727dba17634 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Wed, 28 Jul 2021 19:15:20 -0600 Subject: [PATCH 062/511] Fix some doctests for dictionary output; use W for group name consistently --- src/sage/algebras/iwahori_hecke_algebra.py | 59 ++++++++++++---------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index d0f137fb678..e43dfa3d28e 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2180,16 +2180,18 @@ def __init__(self, algebra, prefix='Cp'): Initialize the Cp_Coxeter3 Kazdahn-Luzstig basis of the Iwahori-Hecke algebra ``algebra''. - EXAMPLES:: + EXAMPLES: + + Valid construction:: - TODO: Do we still need all these here? Space after (to - separate good and bad) sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, v**2) + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v**2) sage: Cp = H.Cp_Coxeter3() + Invalid construction:: + sage: H = IwahoriHeckeAlgebra('A3', v**2) sage: Cp = H.Cp_Coxeter3() Traceback (most recent call last): @@ -2231,9 +2233,9 @@ def to_Cp_basis(self, w): EXAMPLES:: sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp(); CpC=H.Cp_Coxeter3() - sage: s1, s2, s3 = A3.simple_reflections() + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp(); CpC=H.Cp_Coxeter3() + sage: s1, s2, s3 = W.simple_reflections() sage: CpC.to_Cp_basis(s1*s2) Cp[1,2] sage: CpC.to_Cp_basis(s1*s2*s1) @@ -2261,13 +2263,13 @@ def _product_with_generator_on_basis(self, side, s, w): EXAMPLES:: sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp_Coxeter3() - sage: Cp._product_with_generator_on_basis('left', 1, A3([2,1])) + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp_Coxeter3() + sage: Cp._product_with_generator_on_basis('left', 1, W([2,1])) Cp[1,2,1] + Cp[1] - sage: Cp._product_with_generator_on_basis('right', 1, A3([2,1])) - (v+v^-1) * Cp[1] - sage: Cp._product_with_generator_on_basis('right', 2, A3([1,3,2,1,3])) + sage: Cp._product_with_generator_on_basis('right', 1, W([2,1])) + (v^-1+v)*Cp[2,1] + sage: Cp._product_with_generator_on_basis('right', 2, W([1,3,2,1,3])) Cp[1,2,1,3,2,1] + Cp[1,2,3,2] + Cp[1,3,2,1] """ @@ -2306,8 +2308,8 @@ def _product_with_generator(self, side, s, x): EXAMPLES:: sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp_Coxeter3() + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp_Coxeter3() sage: Cp._product_with_generator('left', 1, Cp[1]+Cp[2]) Cp[1,2] + (v^-1+v)*Cp[1] sage: Cp._product_with_generator('right', 1, Cp[1]+Cp[2]) @@ -2326,7 +2328,7 @@ def _decompose_into_generators(self, w): sage: R. = LaurentPolynomialRing(ZZ, 'v') sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp_Coxeter3() + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp_Coxeter3() When `y` is itself a generator `s`, the decomposition is trivial:: @@ -2336,16 +2338,16 @@ def _decompose_into_generators(self, w): Another example, where Cp_y happens to be a monomial; Cp_{21} = Cp_2*Cp_1:: - sage: Cp._decompose_into_generators(A3([2,1])) + sage: Cp._decompose_into_generators(W([2,1])) {(2, 1): 1} - In more general situations the sum is a polynomial; Cp_{121} = + In more general situations the sum is a polynomial; e.g. Cp_{121} = Cp_1*Cp_2*Cp_1 - Cp_1 - sage: Cp._decompose_into_generators(A3([1,2,1])) # C_{121} = C_1C_2C_1 - C_1 - {(1, 2, 1): 1, (1,): -1} - sage: Cp._decompose_into_generators(A3([1,2,3,1,2])) - {(1, 2, 1, 3, 2): 1, (1, 2, 1): -1, (1,): 1, (1, 3, 2): -1} + sage: Cp._decompose_into_generators(W([1,2,1])) + {(1,): -1, (1, 2, 1): 1} + sage: Cp._decompose_into_generators(W([1,2,3,1,2])) + {(1,): 1, (1, 2, 1): -1, (1, 2, 1, 3, 2): 1, (1, 3, 2): -1} """ # \ell(y) \leq 1 if len(w) == 0: @@ -2385,16 +2387,17 @@ def product_on_basis(self, w1, w2): Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` in the `C^{\prime}`-basis. - The product is computed in the two steps as described in "ALGORITHM". + The product is computed in the two steps as described in + "ALGORITHM". TODO: Reference "ALGORITHM" EXAMPLES:: sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp=H.Cp_Coxeter3() - sage: Cp.product_on_basis(A3([1,2,1]), A3([3,1])) + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp_Coxeter3() + sage: Cp.product_on_basis(W([1,2,1]), W([3,1])) (v^-1+v)*Cp[1,2,1,3] - sage: Cp.product_on_basis(A3([1,2,1]), A3([3,1,2])) + sage: Cp.product_on_basis(W([1,2,1]), W([3,1,2])) (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] """ # Decompose one of Cp_{w1} and Cp_{w2} into a polynomial in the From f7138c2768db07b75ed1f961eb650ab66ea44c7c Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Wed, 28 Jul 2021 19:38:03 -0600 Subject: [PATCH 063/511] More docstring additions and edits; take care of some TODOs --- src/sage/algebras/iwahori_hecke_algebra.py | 89 +++++++++++++--------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index e43dfa3d28e..89f66212500 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2052,54 +2052,70 @@ class Cp_Coxeter3(_KLHeckeBasis): EXAMPLES: - Basic usage:: - - # To create the basis, define the Coxeter group with 'coxeter3' and - # the Hecke algebra with the standard or normalized presentation. + To create the basis, define the Coxeter group with 'coxeter3' and the + Hecke algebra with the standard or normalized presentation:: sage: R. = LaurentPolynomialRing(ZZ) - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, v**2) # standard presentation - sage: Cp = H.Cp_Coxeter3() + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v**2) # standard presentation + sage: CpC = H.Cp_Coxeter3() - # TODO: 1. avoid Cp, maybe CpC or CpC3? 2. show that CpC3 IS Cp (more reason for 1) + Perform computations with the `C^{\prime}` basis elements indexed by W:: - sage: s1, s2, s3 = A3.simple_reflections() - sage: Cp(s1*s2*s1) + sage: s1, s2, s3 = W.simple_reflections() + sage: CpC(s1*s2*s1) Cp[1,2,1] - sage: Cp(s1)**2 + sage: CpC(s1)**2 (v^-1+v)*Cp[1] + sage: CpC(s1)*CpC(s2)*CpC(s1) + Cp[1,2,1] + Cp[1] + + TODO: Change the prefix (so that items print CpC[1,2,1] etc.), or not? + This would make this block in particular clearer, but not much elsewhere. + + This basis is a reimplementation of the ``Cp`` basis. The computations + are identical:: + + sage: Cp = H.Cp() sage: Cp(s1)*Cp(s2)*Cp(s1) Cp[1,2,1] + Cp[1] + sage: CpC(Cp(s1)*Cp(s2)*Cp(s1)) + Cp[1,2,1] + Cp[1] + sage: Cp(CpC(s1)*CpC(s2)*CpC(s1)) + Cp[1,2,1] + Cp[1] - The following computation take a long time in the + TODO: reference + The following computation takes a long time in the _Basis.product_on_basis method as mentioned on Line 1941, but it is - instant in the current method :: + instant in the current method:: sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] Cp[1,2,1,3,2] + Cp[1,2,1] + Cp[1,3,2] - Below is another example, with the Hecke algebra of type `B9` in the normalized - presentation. The (optional) relabeling command ensures that `m(1,2)=4`, i.e., that - the generators 1, 2 form the strong bond in the Dynkin diagram. :: + Below is another example, with the Hecke algebra of type `B9` in the + normalized presentation. The (optional) relabeling command ensures that + `m(1,2)=4`, i.e., that the generators 1, 2 form the strong bond in the + Dynkin diagram:: - sage: B9 = CoxeterGroup(CoxeterType(['B', 9]).relabel({ i: 9-i+1 for i in range(1, 10) }), implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(B9, v, -1/v) + sage: B9 = CoxeterType(['B', 9]).relabel({ i: 9-i+1 for i in range(1, 10) }) + sage: W = CoxeterGroup(B9, implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v, -1/v) sage: Cp = H.Cp_Coxeter3() + sage: s = W.simple_reflections() + sage: Cp(s[1]*s[2]*s[1]*s[2]) + Cp[1,2,1,2] - # TODO: create s1 to s9 - sage: Cp[1,2,1,2] - Cp[1,2,1,2] - + TODO: reference The following computation also takes a long time in _Basis.product_on_basis, but it is instant here :: sage: Cp[3,2,3,4,5] * Cp[2,3] (v^-1+v)*Cp[2,3,2,4,3,5] + (v^-1+v)*Cp[2,3,2,5] - Directly creating a Hecke algebra from its Coxeter type does not work - currently. Instead, a Coxeter group implemented with 'coxeter3' must be - created first :: + Since the underlying Coxeter group must be implemented with + ``coxeter3``, directly creating a Hecke algebra from its Coxeter type + does not work. Instead, a Coxeter group implemented with 'coxeter3' must + be created first:: sage: H = IwahoriHeckeAlgebra('A3', v**2) sage: H.Cp_Coxeter3() @@ -2108,10 +2124,10 @@ class Cp_Coxeter3(_KLHeckeBasis): ValueError: algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis With the Coxeter group created first, the Hecke algebra must be defined - with the standard or normalized presentation mentioned before :: + with the standard or normalized presentation mentioned before:: - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, QQ(1)) + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, QQ(1)) sage: H.Cp_Coxeter3() Traceback (most recent call last): ... @@ -2207,14 +2223,15 @@ def __init__(self, algebra, prefix='Cp'): v = algebra.base_ring().gen(0) - # TODO: rewrite this horribly ugly condition: - if v != algebra.base_ring().one() and ((algebra.q1() == v**2 and algebra.q2() == -1) or (algebra.q1() == v and algebra.q2() == -1/v)): - self.delta = v + ~v # TODO: this is why we need the two normalizations + parameters = {algebra.q1(), algebra.q2()} + if v != algebra.base_ring().one() and (parameters == {v**2, -1} or parameters == {v, -1/v}): + # TODO: this is why we need the two normalizations + self.delta = v + ~v else: if not algebra._is_generic: # If this algebra is generic, it's only being used to coerce to the T basis, not perform computations - # TODO: Better error message (TX made some changes) - raise ValueError('the Cp_Coxeter3 basis is only supported in a Hecke algebra with the standard or normalized presentations (i.e., need `\{q_1,q_2\} = \{v^2,1\}` or `\{q_1,q_2\} = \{v,-v^-1\}` as sets)') + raise ValueError('the Cp_Coxeter3 basis is only supported in a Hecke algebra with the standard or normalized \ +presentations (i.e., need `\{q_1,q_2\} = \{v^2,1\}` or `\{q_1,q_2\} = \{v,-v^-1\}` as sets)') # Define conversion to the other Cp basis self.module_morphism(self.to_Cp_basis, codomain=algebra.Cp(), category=self.category() @@ -2273,13 +2290,11 @@ def _product_with_generator_on_basis(self, side, s, w): Cp[1,2,1,3,2,1] + Cp[1,2,3,2] + Cp[1,3,2,1] """ - # TODO: consistency in our docstring: ticks or not + other things. - # If `s` is a descent of `w` on the `side`, the product is (v + v^-1) Cp_w: if w.has_descent(s, side=side): return self.delta * self.monomial(w) - # Otherwise the product is \sum_{v \leq w; sv < v} mu(v, w) C'_v - # if `side` is left and \sum_{v \leq w; vs < v} mu(v, w) C'_s if + # Otherwise the product is \sum_{v \leq w; sv < v} mu(v, w) Cp_v + # if `side` is left and \sum_{v \leq w; vs < v} mu(v, w) Cp_s if # `side` is right, as mentioned before. else: element = self(0) From 033053e9e18a9a5b0e528e033214c727b9b0a651 Mon Sep 17 00:00:00 2001 From: Tianyuan Xu Date: Fri, 30 Jul 2021 12:49:52 -0600 Subject: [PATCH 064/511] minor doc string changes --- src/sage/algebras/iwahori_hecke_algebra.py | 99 ++++++++++------------ 1 file changed, 46 insertions(+), 53 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 89f66212500..0dea5dcbf67 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2019,7 +2019,7 @@ class Cp_Coxeter3(_KLHeckeBasis): `T`-basis, and converting the results back to the `C^{\prime}`-basis (see Line 1303). The latter approach is used in the _Basis.product_on_basis method on Line 1298. The direct - method significantly speeds up the product computations. + method implemented here significantly speeds up the product computations. The following formulas for products of the forms `C^{\prime}_s \cdot C^{\prime}_w` and `C^{\prime}_w \cdot C^{\prime}_s`, where `s` is a @@ -2140,38 +2140,37 @@ class Cp_Coxeter3(_KLHeckeBasis): Write `b` for `C^{\prime}`. This class computes each product `b_x \cdot b_y` in two steps as follows. - If `\ell(x) \leq \ell(y)`, then we first decompose `b_x` into a + If `\ell(x) \leq \ell(y)`, we first decompose `b_x` into a polynomial in the generators `b_s (s\in S)` and then multiply that polynomial with `b_y`. If `\ell(x) > \ell(y)`, we decompose `b_y` into a polynomial in `b_s (s\in S)` and multiply that polynomial with `b_x`. The second step (multiplication) is done by repeatedly applying the key formulas displayed earlier directly. The first step (decomposition) is done by induction on the Bruhat order as - follows: for every element `u\in W` with length `\ell(u)>1` and - every left descent `s` of `u`, write `u=sw` (so `w=su`) and note - that + follows: for every element `u\in W` with length `\ell(u)>1`, pick a + left descent `s` of `u` and write `u=sw` (so `w=su`), then note that .. MATH:: C^{\prime}_u = C^{\prime}_s * C^{\prime}_{w} - \sum_{v\le u; sv< v} \mu(v,w) C^{\prime}_v - by the key formulas, where the element `w` and all elements `v`'s - on the right side are lower than `u` in the Bruhat order; this - allows us to finish the computation by decomposing the lower order - terms `b_w` and each `b_v`. For example, for `u=121, s=1, w=21` in - type `A3` we have + by the key formulas mentioned earlier, where the element `w` and + all elements `v`'s on the right side are lower than `u` in the + Bruhat order; this allows us to finish the computation by + decomposing the lower order terms `b_w` and each `b_v`. For + example, for `u=121, s=1, w=21` in type `A3` we have .. MATH:: b_{121} = b_1*b_{21} - b_1, where the lower order term `b_{21}` further decomposes into `b_2*b_1`, therefore `b_{121}=b_1*b_2 b_1 -b1`. We note that the - the base cases `\ell(x)=1` or `\ell(x)=0` of the above induction - occur when `x` is itself a Coxeter generator `s` or the group - identity, respectively. The decomposition is trivial in these cases - (we have `C_x=C_s` or `C_x=1`, the unit of the Hecke algebra). - + base cases `\ell(x)=1` or `\ell(x)=0` of the above induction occur + when `x` is itself a Coxeter generator `s` or the group identity, + respectively. The decomposition is trivial in these cases (we have + `C_x=C_s` or `C_x=1`, the unit of the Hecke algebra). + .. SEEALSO:: # TODO: edit the following @@ -2185,15 +2184,15 @@ class Cp_Coxeter3(_KLHeckeBasis): Accommodate generic presentations of the Hecke algebra other than the standard and normalized ones. - Use the analog of the displayed formulas to implement - `C^{\prime}`-products in the multi-parameter Iwahori-Hecke algebra; - see Section 6 of [Lus2013]_. + Use analogs of the key formulas to implement `C^{\prime}`-products + in the multi-parameter Iwahori-Hecke algebra; see Section 6 of + [Lus2013]_. """ _basis_name = 'Cp_Coxeter3' def __init__(self, algebra, prefix='Cp'): r""" - Initialize the Cp_Coxeter3 Kazdahn-Luzstig basis of the + Initialize the Cp_Coxeter3 Kazdahn-Lusztig basis of the Iwahori-Hecke algebra ``algebra''. EXAMPLES: @@ -2332,11 +2331,13 @@ def _product_with_generator(self, side, s, x): """ return self.linear_combination((self._product_with_generator_on_basis(side, s, w), coeff) for (w, coeff) in x) - def _decompose_into_generators(self, w): + def _decompose_into_generators(self, u): r""" - Decompose `C^{\prime}_w` into a polynomial in the KL generators + Decompose `C^{\prime}_u` into a polynomial in the KL generators `C^{\prime}_s`; see "ALGORITHM". TODO: Reference "ALGORITHM" + TODO: 1. describe output; 2. possibly: change w to u? + EXAMPLES: :: @@ -2365,34 +2366,27 @@ def _decompose_into_generators(self, w): {(1,): 1, (1, 2, 1): -1, (1, 2, 1, 3, 2): 1, (1, 3, 2): -1} """ # \ell(y) \leq 1 - if len(w) == 0: + if len(u) == 0: return {(): 1} - if len(w) == 1: - return {(w[0],): 1} - # \ell(y) > 1, we use the induction on `\ell(y)` and recursively - # find the decomposition - s = w[0] - w1 = w[1:] - - # TODO: remove some doc strings below. We've explained the ideas in enough detail. - - # Additively build the sum term (lower order terms) + if len(u) == 1: + return {(u[0],): 1} + # \ell(y) > 1, use the recursive method described in ALGORITHM + s = u[0] + w = u[1:] # so C^{prime}_s * C^{\prime}_{w} = C^\prime{u} + lower order terms + # get the lower order terms ("sum_term") sum_term = self(0) - between = self._W.bruhat_interval([], w1) - for x in between: - # Get (coxeter3-implemented) group element corresponding to x - x_elt = self._W(x) - if x_elt.has_left_descent(s): + between = self._W.bruhat_interval([], w) + for v in between: + # Get (coxeter3-implemented) group element corresponding to v + v_elt = self._W(x) + if v_elt.has_left_descent(s): # Compute mu-coefficient via coxeter3 - sum_term += self.base_ring()(x.mu_coefficient(w1)) * self.monomial(x_elt) - - # Recurse and decompose C_{w1} into generators, then go through the - # lower order terms in sum_term and decompose those into generators. - # Perform (distrubute) Cp_s * Cp_{w1} - result = {(s,) + gens: coeff for (gens, coeff) in self._decompose_into_generators(w1).items()} - for (v, c1) in sum_term: + sum_term += self.base_ring()(v.mu_coefficient(w)) * self.monomial(v_elt) + # Recurse now: decompose C_s * C_{w} and the lower order terms + result = {(s,) + gens: coeff for (gens, coeff) in self._decompose_into_generators(w).items()} + for (z, c1) in sum_term: # Subtract off each term from `sum_term`. - for (gens, c2) in self._decompose_into_generators(v).items(): + for (gens, c2) in self._decompose_into_generators(z).items(): result[gens] = result.get(gens, 0) - c1*c2 return result @@ -2402,8 +2396,9 @@ def product_on_basis(self, w1, w2): Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` in the `C^{\prime}`-basis. - The product is computed in the two steps as described in - "ALGORITHM". TODO: Reference "ALGORITHM" + The product is computed in the two steps (decomposition + + multiplication) as described in "ALGORITHM". TODO: Reference + "ALGORITHM" EXAMPLES:: @@ -2415,8 +2410,8 @@ def product_on_basis(self, w1, w2): sage: Cp.product_on_basis(W([1,2,1]), W([3,1,2])) (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] """ - # Decompose one of Cp_{w1} and Cp_{w2} into a polynomial in the - # generators, then multiply the remaining one with the polynomial. + # Decomposition: write one of Cp_{w1} and Cp_{w2} as a polynomial in the + # generators if len(w1) <= len(w2): side = 'left' gen_expression = self._decompose_into_generators(w1) @@ -2426,16 +2421,14 @@ def product_on_basis(self, w1, w2): gen_expression = self._decompose_into_generators(w2) other_element = self.monomial(w1) result = self(0) - # Proceed through the terms, multiplying the generators in each term - # onto other_element and adding that summand onto result. + # Multiplication: multiply the generators in each term of the above + # polynomial onto other_element and add that summand onto result. for (p, coeff) in gen_expression.items(): summand = coeff * other_element p_list = list(p) if side == 'right' else list(p)[::-1] for s in p_list: summand = self._product_with_generator(side, s, summand) - result += summand - return result From 067c103876b528e0b0f3685554be59dd80d21d88 Mon Sep 17 00:00:00 2001 From: Tianyuan Xu Date: Fri, 30 Jul 2021 16:05:37 -0600 Subject: [PATCH 065/511] Cp-to-CpC label changes --- src/sage/algebras/iwahori_hecke_algebra.py | 195 +++++++++++---------- 1 file changed, 99 insertions(+), 96 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 0dea5dcbf67..795c9539c94 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1583,23 +1583,23 @@ def to_Cp_basis(self, w): def to_Cp_Coxeter3_basis(self, w): r""" - Return `T-w` as a linear combination of `C^{\prime}`-basis elements, + Return `T_w` as a linear combination of `C^{\prime}`-basis elements, using the ``Cp_Coxeter3`` basis. EXAMPLES:: sage: R. = LaurentPolynomialRing(ZZ, 'v') sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, v**2); T=H.T(); Cp=H.Cp_Coxeter3() + sage: H = IwahoriHeckeAlgebra(A3, v**2); T=H.T(); CpC=H.Cp_Coxeter3() sage: s1,s2,s3 = A3.simple_reflections() sage: T.to_Cp_Coxeter3_basis(s1) - v*Cp[1] - 1 - sage: Cp(T(s1)) - v*Cp[1] - 1 - sage: Cp(T[1] + 1) - v*Cp[1] - sage: Cp(T[1,2] + T[1] + T[2] + 1) - v^2*Cp[1,2] + v*CpC[1] - 1 + sage: CpC(T(s1)) + v*CpC[1] - 1 + sage: CpC(T[1] + 1) + v*CpC[1] + sage: CpC(T[1,2] + T[1] + T[2] + 1) + v^2*CpC[1,2] """ H = self.realization_of() generic_T = H._generic_iwahori_hecke_algebra.T() @@ -1968,13 +1968,13 @@ def to_Cp_Coxeter3_basis(self, w): sage: A3 = CoxeterGroup('A3', implementation='coxeter3') sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp = H.Cp(); CpC=H.Cp_Coxeter3() sage: Cp.to_Cp_Coxeter3_basis(A3([1,2])) - Cp[1,2] + CpC[1,2] sage: CpC(Cp[1,2]) - Cp[1,2] + CpC[1,2] """ A = self.realization_of() - Cp = A.Cp_Coxeter3() - return Cp.monomial(w) + CpC = A.Cp_Coxeter3() + return CpC.monomial(w) def hash_involution_on_basis(self, w): r""" @@ -2017,8 +2017,8 @@ class Cp_Coxeter3(_KLHeckeBasis): directly in the `C^{\prime}`-basis, as opposed to converting the `C^{\prime}`-basis to the `T`-basis, calculating the product in the `T`-basis, and converting the results back to the `C^{\prime}`-basis - (see Line 1303). The latter approach is used in the - _Basis.product_on_basis method on Line 1298. The direct + #TODO:(see Line 1303). The latter approach is used in the + #TODO:_Basis.product_on_basis method on Line 1298. The direct method implemented here significantly speeds up the product computations. The following formulas for products of the forms `C^{\prime}_s \cdot @@ -2060,37 +2060,33 @@ class Cp_Coxeter3(_KLHeckeBasis): sage: H = IwahoriHeckeAlgebra(W, v**2) # standard presentation sage: CpC = H.Cp_Coxeter3() - Perform computations with the `C^{\prime}` basis elements indexed by W:: + The new basis here (CpC) and Cp basis are both implementations of the + the `C^{\prime}` basis. The only difference between the implementations + lies in their different methods for computing products:: sage: s1, s2, s3 = W.simple_reflections() - sage: CpC(s1*s2*s1) + sage: Cp = H.Cp() + sage: a = CpC(s1*s2*s1) + CpC[1,2,1] + sage: b = Cp(s1*s2*s1) Cp[1,2,1] + sage: a == b + True + sage: CpC(s1)**2 + (v^-1+v)*CpC[1] + sage: Cp(s1)**2 (v^-1+v)*Cp[1] - sage: CpC(s1)*CpC(s2)*CpC(s1) - Cp[1,2,1] + Cp[1] - - TODO: Change the prefix (so that items print CpC[1,2,1] etc.), or not? - This would make this block in particular clearer, but not much elsewhere. - This basis is a reimplementation of the ``Cp`` basis. The computations - are identical:: - - sage: Cp = H.Cp() sage: Cp(s1)*Cp(s2)*Cp(s1) Cp[1,2,1] + Cp[1] - sage: CpC(Cp(s1)*Cp(s2)*Cp(s1)) - Cp[1,2,1] + Cp[1] - sage: Cp(CpC(s1)*CpC(s2)*CpC(s1)) - Cp[1,2,1] + Cp[1] - - TODO: reference - The following computation takes a long time in the - _Basis.product_on_basis method as mentioned on Line 1941, but it is - instant in the current method:: + sage: CpC(s1)*CpC(s2)*CpC(s1) + CpC[1,2,1] + CpC[1] sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] - Cp[1,2,1,3,2] + Cp[1,2,1] + Cp[1,3,2] + Cp[1,2,1,3,2] + Cp[1,2,1] + Cp[1,3,2] # long time in the Cp implementation; TODO: ref Line 1941 + sage: CpC[1]*CpC[2]*CpC[3]*CpC[1]*CpC[2] + CpC[1,2,1,3,2] + CpC[1,2,1] + CpC[1,3,2] # instant in the CpC implementation Below is another example, with the Hecke algebra of type `B9` in the normalized presentation. The (optional) relabeling command ensures that @@ -2100,22 +2096,19 @@ class Cp_Coxeter3(_KLHeckeBasis): sage: B9 = CoxeterType(['B', 9]).relabel({ i: 9-i+1 for i in range(1, 10) }) sage: W = CoxeterGroup(B9, implementation='coxeter3') sage: H = IwahoriHeckeAlgebra(W, v, -1/v) - sage: Cp = H.Cp_Coxeter3() + sage: CpC, Cp = H.Cp_Coxeter3(), H.Cp() sage: s = W.simple_reflections() sage: Cp(s[1]*s[2]*s[1]*s[2]) Cp[1,2,1,2] - TODO: reference - The following computation also takes a long time in - _Basis.product_on_basis, but it is instant here :: - sage: Cp[3,2,3,4,5] * Cp[2,3] - (v^-1+v)*Cp[2,3,2,4,3,5] + (v^-1+v)*Cp[2,3,2,5] + (v^-1+v)*Cp[2,3,2,4,3,5] + (v^-1+v)*Cp[2,3,2,5]# long time in the Cp implementation; + sage: CpC[3,2,3,4,5] * CpC[2,3] + (v^-1+v)*CpC[2,3,2,4,3,5] + (v^-1+v)*CpC[2,3,2,5] # instant in the CpC implementation - Since the underlying Coxeter group must be implemented with - ``coxeter3``, directly creating a Hecke algebra from its Coxeter type - does not work. Instead, a Coxeter group implemented with 'coxeter3' must - be created first:: + Note that to use the CpC basis for a Hecke algebra, a Coxeter group + must be created first with implemntation 'coxeter3'. Directly creating + a Hecke algebra from its Coxeter type does not work:: sage: H = IwahoriHeckeAlgebra('A3', v**2) sage: H.Cp_Coxeter3() @@ -2190,7 +2183,7 @@ class Cp_Coxeter3(_KLHeckeBasis): """ _basis_name = 'Cp_Coxeter3' - def __init__(self, algebra, prefix='Cp'): + def __init__(self, algebra, prefix='CpC'): r""" Initialize the Cp_Coxeter3 Kazdahn-Lusztig basis of the Iwahori-Hecke algebra ``algebra''. @@ -2202,16 +2195,28 @@ def __init__(self, algebra, prefix='Cp'): sage: R. = LaurentPolynomialRing(ZZ, 'v') sage: W = CoxeterGroup('A3', implementation='coxeter3') sage: H = IwahoriHeckeAlgebra(W, v**2) - sage: Cp = H.Cp_Coxeter3() + sage: CpC = H.Cp_Coxeter3() - Invalid construction:: + Invalid construction (not creating a Coxeter group with 'coxeter3'):: sage: H = IwahoriHeckeAlgebra('A3', v**2) - sage: Cp = H.Cp_Coxeter3() + sage: H.Cp_Coxeter3() Traceback (most recent call last): ... ValueError: algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis + + + Invalid construction (bad presentation for Hecke algebra):: + + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, QQ(1)) + sage: H.Cp_Coxeter3() + Traceback (most recent call last): + ... + ValueError: the Cp_Coxeter3 basis is only supported in a Hecke + algebra with the standard or normalized presentations (i.e., need + `\{q_1,q_2\} = \{v^2,1\}` or `\{q_1,q_2\} = \{v,-v^-1\}` as sets) """ if not isinstance(algebra._W, Coxeter3Group): raise ValueError('algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis') @@ -2224,7 +2229,8 @@ def __init__(self, algebra, prefix='Cp'): parameters = {algebra.q1(), algebra.q2()} if v != algebra.base_ring().one() and (parameters == {v**2, -1} or parameters == {v, -1/v}): - # TODO: this is why we need the two normalizations + # The following quantity delta is used in product computations. + # To use it we need the standard or normalized normalizations. self.delta = v + ~v else: if not algebra._is_generic: @@ -2266,8 +2272,6 @@ def _product_with_generator_on_basis(self, side, s, w): Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting `C^{\prime}_s` on the given ``side``. - # TODO: again, 'Cp' might be bad; - INPUT: - ``side`` -- string; 'left' or 'right' @@ -2280,21 +2284,17 @@ def _product_with_generator_on_basis(self, side, s, w): sage: R. = LaurentPolynomialRing(ZZ, 'v') sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp_Coxeter3() - sage: Cp._product_with_generator_on_basis('left', 1, W([2,1])) - Cp[1,2,1] + Cp[1] - sage: Cp._product_with_generator_on_basis('right', 1, W([2,1])) - (v^-1+v)*Cp[2,1] - sage: Cp._product_with_generator_on_basis('right', 2, W([1,3,2,1,3])) - Cp[1,2,1,3,2,1] + Cp[1,2,3,2] + Cp[1,3,2,1] + sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() + sage: CpC._product_with_generator_on_basis('left', 1, W([2,1])) + CpC[1,2,1] + CpC[1] + sage: CpC._product_with_generator_on_basis('right', 1, W([2,1])) + (v^-1+v)*CpC[2,1] + sage: CpC._product_with_generator_on_basis('right', 2, W([1,3,2,1,3])) + CpC[1,2,1,3,2,1] + CpC[1,2,3,2] + CpC[1,3,2,1] """ - - # If `s` is a descent of `w` on the `side`, the product is (v + v^-1) Cp_w: + # use the product formula from TODO: ref algorithm if w.has_descent(s, side=side): return self.delta * self.monomial(w) - # Otherwise the product is \sum_{v \leq w; sv < v} mu(v, w) Cp_v - # if `side` is left and \sum_{v \leq w; vs < v} mu(v, w) Cp_s if - # `side` is right, as mentioned before. else: element = self(0) between = self._W.bruhat_interval([], w) @@ -2323,11 +2323,11 @@ def _product_with_generator(self, side, s, x): sage: R. = LaurentPolynomialRing(ZZ, 'v') sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp_Coxeter3() - sage: Cp._product_with_generator('left', 1, Cp[1]+Cp[2]) - Cp[1,2] + (v^-1+v)*Cp[1] - sage: Cp._product_with_generator('right', 1, Cp[1]+Cp[2]) - Cp[2,1] + (v^-1+v)*Cp[1] + sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() + sage: CpC._product_with_generator('left', 1, CpC[1]+CpC[2]) + CpC[1,2] + (v^-1+v)*CpC[1] + sage: CpC._product_with_generator('right', 1, CpC[1]+CpC[2]) + CpC[2,1] + (v^-1+v)*CpC[1] """ return self.linear_combination((self._product_with_generator_on_basis(side, s, w), coeff) for (w, coeff) in x) @@ -2336,7 +2336,7 @@ def _decompose_into_generators(self, u): Decompose `C^{\prime}_u` into a polynomial in the KL generators `C^{\prime}_s`; see "ALGORITHM". TODO: Reference "ALGORITHM" - TODO: 1. describe output; 2. possibly: change w to u? + TODO: explain output format EXAMPLES: @@ -2344,48 +2344,51 @@ def _decompose_into_generators(self, u): sage: R. = LaurentPolynomialRing(ZZ, 'v') sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp_Coxeter3() + sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() - When `y` is itself a generator `s`, the decomposition is trivial:: + When `u` is itself a generator `s`, the decomposition is trivial:: - sage: Cp._decompose_into_generators(W([1])) + sage: CpC._decompose_into_generators(W([1])) {(1,): 1} - Another example, where Cp_y happens to be a monomial; Cp_{21} = - Cp_2*Cp_1:: + Another example, where `C^{\prime}_u` happens to be a monomial + (e.g., CpC_{21} = CpC_2 * CpC_1):: - sage: Cp._decompose_into_generators(W([2,1])) - {(2, 1): 1} + sage: CpC._decompose_into_generators(W([2,1])) + {(2, 1): 1} - In more general situations the sum is a polynomial; e.g. Cp_{121} = - Cp_1*Cp_2*Cp_1 - Cp_1 + In more general situations the sum is a polynomial (e.g., + CpC_{121}=CpC_1*CpC_2*CpC_1-CpC_1):: - sage: Cp._decompose_into_generators(W([1,2,1])) - {(1,): -1, (1, 2, 1): 1} - sage: Cp._decompose_into_generators(W([1,2,3,1,2])) + sage: CpC._decompose_into_generators(W([1,2,1])) + {(1,): -1, (1, 2, 1): 1} + sage: CpC._decompose_into_generators(W([1,2,3,1,2])) {(1,): 1, (1, 2, 1): -1, (1, 2, 1, 3, 2): 1, (1, 3, 2): -1} """ - # \ell(y) \leq 1 + # l(y) = 0 or 1 if len(u) == 0: return {(): 1} if len(u) == 1: return {(u[0],): 1} - # \ell(y) > 1, use the recursive method described in ALGORITHM + + # l(y) > 1, use the recursive method described in TODO:ref ALGORITHM s = u[0] - w = u[1:] # so C^{prime}_s * C^{\prime}_{w} = C^\prime{u} + lower order terms + w = u[1:] # so CpC_s * CpC_w = CpC_u + lower order terms + # get the lower order terms ("sum_term") sum_term = self(0) between = self._W.bruhat_interval([], w) for v in between: # Get (coxeter3-implemented) group element corresponding to v - v_elt = self._W(x) + v_elt = self._W(v) if v_elt.has_left_descent(s): # Compute mu-coefficient via coxeter3 sum_term += self.base_ring()(v.mu_coefficient(w)) * self.monomial(v_elt) - # Recurse now: decompose C_s * C_{w} and the lower order terms + + # recursion: decompose C'_s * C'_w and the lower order terms result = {(s,) + gens: coeff for (gens, coeff) in self._decompose_into_generators(w).items()} for (z, c1) in sum_term: - # Subtract off each term from `sum_term`. + # Subtract off each term from sum_term. for (gens, c2) in self._decompose_into_generators(z).items(): result[gens] = result.get(gens, 0) - c1*c2 @@ -2404,14 +2407,14 @@ def product_on_basis(self, w1, w2): sage: R. = LaurentPolynomialRing(ZZ, 'v') sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp_Coxeter3() - sage: Cp.product_on_basis(W([1,2,1]), W([3,1])) - (v^-1+v)*Cp[1,2,1,3] - sage: Cp.product_on_basis(W([1,2,1]), W([3,1,2])) - (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] + sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() + sage: CpC.product_on_basis(W([1,2,1]), W([3,1])) + (v^-1+v)*CpC[1,2,1,3] + sage: CpC.product_on_basis(W([1,2,1]), W([3,1,2])) + (v^-1+v)*CpC[1,2,1,3,2] + (v^-1+v)*CpC[1,2,1] """ - # Decomposition: write one of Cp_{w1} and Cp_{w2} as a polynomial in the - # generators + # Decomposition: write one of C'_{w1} and C'_{w2} as a polynomial in the + # generators C'_{s}. if len(w1) <= len(w2): side = 'left' gen_expression = self._decompose_into_generators(w1) From 32a240ef91023a35cb6e096ddc5d0a60e2c77985 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 31 Jul 2021 02:23:54 -0600 Subject: [PATCH 066/511] Format and fix docstrings; get tests passing --- src/sage/algebras/iwahori_hecke_algebra.py | 101 +++++++++++---------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 795c9539c94..4cc5594db70 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2018,8 +2018,8 @@ class Cp_Coxeter3(_KLHeckeBasis): `C^{\prime}`-basis to the `T`-basis, calculating the product in the `T`-basis, and converting the results back to the `C^{\prime}`-basis #TODO:(see Line 1303). The latter approach is used in the - #TODO:_Basis.product_on_basis method on Line 1298. The direct - method implemented here significantly speeds up the product computations. + #TODO:_Basis.product_on_basis method on Line 1298. The direct method + implemented here significantly speeds up the product computations. The following formulas for products of the forms `C^{\prime}_s \cdot C^{\prime}_w` and `C^{\prime}_w \cdot C^{\prime}_s`, where `s` is a @@ -2028,13 +2028,11 @@ class Cp_Coxeter3(_KLHeckeBasis): presentation of the Hecke algebra, and they control the products of the `C^{\prime}_x \cdot C^{\prime}_y` for arbitrary `x,y`. - .. MATH:: - C^{\prime}_s \cdot C^{\prime}_w = - \begin{cases} - (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ - C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, - & \text{if } \ell(sw) = \ell(w)+1. - \end{cases} + .. MATH:: C^{\prime}_s \cdot C^{\prime}_w = \begin{cases} + (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ + C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, + & \text{if } \ell(sw) = + \ell(w)+1. \end{cases} C^{\prime}_w \cdot C^{\prime}_s = \begin{cases} @@ -2045,11 +2043,11 @@ class Cp_Coxeter3(_KLHeckeBasis): In the above, `\leq` is the Bruhat order on the Coxeter group and `\mu(v,w)` is the "leading coefficient of Kazhdan-Lusztig polynomials"; - see [KL1979]_ and [Lus2014]_ for more details. The method designates - the computation of the `\mu`-coefficients to Fokko du Cloux's - 'coxeter3' package (wrapped in Sage), which is why the method requires - the creation of the Coxeter group in the 'coxeter3' implementation. - + see [KL1979]_ and [Lus2014]_ for more details. The method designates the + computation of the `\mu`-coefficients to Fokko du Cloux's 'coxeter3' + package (wrapped in Sage), which is why the method requires the creation + of the Coxeter group in the 'coxeter3' implementation. + EXAMPLES: To create the basis, define the Coxeter group with 'coxeter3' and the @@ -2060,33 +2058,38 @@ class Cp_Coxeter3(_KLHeckeBasis): sage: H = IwahoriHeckeAlgebra(W, v**2) # standard presentation sage: CpC = H.Cp_Coxeter3() - The new basis here (CpC) and Cp basis are both implementations of the - the `C^{\prime}` basis. The only difference between the implementations - lies in their different methods for computing products:: + The new basis here (``CpC``) and ``Cp`` basis are both implementations + of the the `C^{\prime}` basis. The only difference between the + implementations lies in their different methods for computing products, + elements can be converted between the two trivially TODO: I'm not sure + this example block is as useful or clear as it could be:: sage: s1, s2, s3 = W.simple_reflections() sage: Cp = H.Cp() - sage: a = CpC(s1*s2*s1) + sage: a = CpC(s1*s2*s1); a CpC[1,2,1] - sage: b = Cp(s1*s2*s1) + sage: b = Cp(s1*s2*s1); b Cp[1,2,1] - sage: a == b + sage: Cp(a) == b True + sage: a == CpC(b) + True + + This example demonstrates an example that takes a long time in the + existing ``Cp`` basis, but is fast using this implementation:: sage: CpC(s1)**2 (v^-1+v)*CpC[1] sage: Cp(s1)**2 (v^-1+v)*Cp[1] - sage: Cp(s1)*Cp(s2)*Cp(s1) Cp[1,2,1] + Cp[1] sage: CpC(s1)*CpC(s2)*CpC(s1) CpC[1,2,1] + CpC[1] - - sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] - Cp[1,2,1,3,2] + Cp[1,2,1] + Cp[1,3,2] # long time in the Cp implementation; TODO: ref Line 1941 + sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] # long time + Cp[1,2,1,3,2] + Cp[1,2,1] + Cp[1,3,2] sage: CpC[1]*CpC[2]*CpC[3]*CpC[1]*CpC[2] - CpC[1,2,1,3,2] + CpC[1,2,1] + CpC[1,3,2] # instant in the CpC implementation + CpC[1,2,1,3,2] + CpC[1,2,1] + CpC[1,3,2] Below is another example, with the Hecke algebra of type `B9` in the normalized presentation. The (optional) relabeling command ensures that @@ -2100,15 +2103,14 @@ class Cp_Coxeter3(_KLHeckeBasis): sage: s = W.simple_reflections() sage: Cp(s[1]*s[2]*s[1]*s[2]) Cp[1,2,1,2] - - sage: Cp[3,2,3,4,5] * Cp[2,3] - (v^-1+v)*Cp[2,3,2,4,3,5] + (v^-1+v)*Cp[2,3,2,5]# long time in the Cp implementation; + sage: Cp[3,2,3,4,5] * Cp[2,3] # long time + (v^-1+v)*Cp[2,3,2,4,3,5] + (v^-1+v)*Cp[2,3,2,5] sage: CpC[3,2,3,4,5] * CpC[2,3] - (v^-1+v)*CpC[2,3,2,4,3,5] + (v^-1+v)*CpC[2,3,2,5] # instant in the CpC implementation + (v^-1+v)*CpC[2,3,2,4,3,5] + (v^-1+v)*CpC[2,3,2,5] - Note that to use the CpC basis for a Hecke algebra, a Coxeter group - must be created first with implemntation 'coxeter3'. Directly creating - a Hecke algebra from its Coxeter type does not work:: + Note that to use the CpC basis for a Hecke algebra, a Coxeter group must + be created first with implemntation 'coxeter3'. Directly creating a + Hecke algebra from its Coxeter type does not work:: sage: H = IwahoriHeckeAlgebra('A3', v**2) sage: H.Cp_Coxeter3() @@ -2129,9 +2131,8 @@ class Cp_Coxeter3(_KLHeckeBasis): `\{q_1,q_2\} = \{v^2,1\}` or `\{q_1,q_2\} = \{v,-v^-1\}` as sets) - ALGORITHM : - Write `b` for `C^{\prime}`. This class computes each product `b_x - \cdot b_y` in two steps as follows. + ALGORITHM : Write `b` for `C^{\prime}`. This class computes each product + `b_x \cdot b_y` in two steps as follows. If `\ell(x) \leq \ell(y)`, we first decompose `b_x` into a polynomial in the generators `b_s (s\in S)` and then multiply that @@ -2162,7 +2163,7 @@ class Cp_Coxeter3(_KLHeckeBasis): when `x` is itself a Coxeter generator `s` or the group identity, respectively. The decomposition is trivial in these cases (we have `C_x=C_s` or `C_x=1`, the unit of the Hecke algebra). - + .. SEEALSO:: @@ -2173,7 +2174,7 @@ class Cp_Coxeter3(_KLHeckeBasis): :package?[coxeter3?] .. TODO:: - + Accommodate generic presentations of the Hecke algebra other than the standard and normalized ones. @@ -3027,9 +3028,9 @@ def _to_Cp_basis(self, w, Cp): sage: Cp(T(s1)) v*Cp[1] + (-u^-1*v^2) sage: T._to_Cp_basis(s1, CpC) - v*Cp[1] + (-u^-1*v^2) + v*CpC[1] + (-u^-1*v^2) sage: CpC(T(s1)) - v*Cp[1] + (-u^-1*v^2) + v*CpC[1] + (-u^-1*v^2) """ A = self.realization_of() # Cp = A.Cp() if not use_Cp_Coxeter3 else A.Cp_Coxeter3() @@ -3086,19 +3087,19 @@ def to_Cp_Coxeter3_basis(self, w): sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard(A2) sage: s1,s2 = H.coxeter_group().simple_reflections() sage: T = H.T() - sage: Cp = H.Cp_Coxeter3() + sage: CpC = H.Cp_Coxeter3() sage: T.to_Cp_Coxeter3_basis(s1) - v*Cp[1] + (-u^-1*v^2) - sage: Cp(T(s1)) - v*Cp[1] + (-u^-1*v^2) - sage: Cp(T(s1)+1) - v*Cp[1] + (-u^-1*v^2+1) - sage: Cp(T(s1*s2)+T(s1)+T(s2)+1) - v^2*Cp[1,2] + (-u^-1*v^3+v)*Cp[1] + (-u^-1*v^3+v)*Cp[2] + v*CpC[1] + (-u^-1*v^2) + sage: CpC(T(s1)) + v*CpC[1] + (-u^-1*v^2) + sage: CpC(T(s1)+1) + v*CpC[1] + (-u^-1*v^2+1) + sage: CpC(T(s1*s2)+T(s1)+T(s2)+1) + v^2*CpC[1,2] + (-u^-1*v^3+v)*CpC[1] + (-u^-1*v^3+v)*CpC[2] + (u^-2*v^4-2*u^-1*v^2+1) - sage: Cp(T(s1*s2*s1)) - v^3*Cp[1,2,1] + (-u^-1*v^4)*Cp[1,2] + (-u^-1*v^4)*Cp[2,1] - + (u^-2*v^5)*Cp[1] + (u^-2*v^5)*Cp[2] + (-u^-3*v^6) + sage: CpC(T(s1*s2*s1)) + v^3*CpC[1,2,1] + (-u^-1*v^4)*CpC[1,2] + (-u^-1*v^4)*CpC[2,1] + + (u^-2*v^5)*CpC[1] + (u^-2*v^5)*CpC[2] + (-u^-3*v^6) """ A = self.realization_of() return self._to_Cp_basis(w, A.Cp_Coxeter3()) From 32d0a2aa2af1afb47c783b1b471c6e84c4064dcb Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 31 Jul 2021 02:27:16 -0600 Subject: [PATCH 067/511] Change side to be last argument in all methods that take it; default 'left' --- src/sage/algebras/iwahori_hecke_algebra.py | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 4cc5594db70..e1791ba229d 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2268,29 +2268,29 @@ def to_Cp_basis(self, w): Cp = A.Cp() return Cp.monomial(w) - def _product_with_generator_on_basis(self, side, s, w): + def _product_with_generator_on_basis(self, s, w, side='left'): r""" Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting `C^{\prime}_s` on the given ``side``. INPUT: - - ``side`` -- string; 'left' or 'right' - - ``s`` -- integer in self.index_set() - ``w`` -- a word in self.coxeter_group() + - ``side`` -- string; 'left' or 'right' + EXAMPLES:: sage: R. = LaurentPolynomialRing(ZZ, 'v') sage: W = CoxeterGroup('A3', implementation='coxeter3') sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() - sage: CpC._product_with_generator_on_basis('left', 1, W([2,1])) + sage: CpC._product_with_generator_on_basis(1, W([2,1]), 'left') CpC[1,2,1] + CpC[1] - sage: CpC._product_with_generator_on_basis('right', 1, W([2,1])) + sage: CpC._product_with_generator_on_basis(1, W([2,1]), 'right') (v^-1+v)*CpC[2,1] - sage: CpC._product_with_generator_on_basis('right', 2, W([1,3,2,1,3])) + sage: CpC._product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') CpC[1,2,1,3,2,1] + CpC[1,2,3,2] + CpC[1,3,2,1] """ # use the product formula from TODO: ref algorithm @@ -2308,29 +2308,29 @@ def _product_with_generator_on_basis(self, side, s, w): longer_word = self._W([s]) * w if side == 'left' else w * self._W([s]) return self.monomial(longer_word) + element - def _product_with_generator(self, side, s, x): + def _product_with_generator(self, s, x, side='left'): r""" Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elements. INPUT: - - ``side`` -- string; 'left' or 'right' - - ``s`` -- integer in self.index_set() - ``x`` -- any element of self + - ``side`` -- string; 'left' or 'right' + EXAMPLES:: sage: R. = LaurentPolynomialRing(ZZ, 'v') sage: W = CoxeterGroup('A3', implementation='coxeter3') sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() - sage: CpC._product_with_generator('left', 1, CpC[1]+CpC[2]) + sage: CpC._product_with_generator(1, CpC[1]+CpC[2], 'left') CpC[1,2] + (v^-1+v)*CpC[1] - sage: CpC._product_with_generator('right', 1, CpC[1]+CpC[2]) + sage: CpC._product_with_generator(1, CpC[1]+CpC[2], 'right') CpC[2,1] + (v^-1+v)*CpC[1] """ - return self.linear_combination((self._product_with_generator_on_basis(side, s, w), coeff) for (w, coeff) in x) + return self.linear_combination((self._product_with_generator_on_basis(s, w, side), coeff) for (w, coeff) in x) def _decompose_into_generators(self, u): r""" @@ -2431,7 +2431,7 @@ def product_on_basis(self, w1, w2): summand = coeff * other_element p_list = list(p) if side == 'right' else list(p)[::-1] for s in p_list: - summand = self._product_with_generator(side, s, summand) + summand = self._product_with_generator(s, summand, side) result += summand return result From efc5b0e698649f8a11b3b139485bb71509911dfa Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 31 Jul 2021 14:08:24 -0600 Subject: [PATCH 068/511] Fix typos; handle some TODOs --- src/sage/algebras/iwahori_hecke_algebra.py | 119 +++++++++++---------- 1 file changed, 64 insertions(+), 55 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index e1791ba229d..969ad0c3e20 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2006,7 +2006,7 @@ class Cp_Coxeter3(_KLHeckeBasis): To use this class, the Hecke algebra needs to be created in the "standard" presentation where `\{q_1,q_2\} = \{v^2,1\}` as sets or the - "normalized" presentations where `\{q_1,q_2\} = \{v,-v^-1\}` as sets. + "normalized" presentations where `\{q_1,q_2\} = \{v,-v^{-1}\}` as sets. The Hecke algebra also needs to be created from a Coxeter group defined using the 'coxeter3' implementation; see the examples to follow. @@ -2016,10 +2016,10 @@ class Cp_Coxeter3(_KLHeckeBasis): algebras. The emphasis of this class is to compute such products more directly in the `C^{\prime}`-basis, as opposed to converting the `C^{\prime}`-basis to the `T`-basis, calculating the product in the - `T`-basis, and converting the results back to the `C^{\prime}`-basis - #TODO:(see Line 1303). The latter approach is used in the - #TODO:_Basis.product_on_basis method on Line 1298. The direct method - implemented here significantly speeds up the product computations. + `T`-basis, and converting the results back to the `C^{\prime}`-basis, as + is the default technique in ``_Basis.product_on_basis``, used by the + :class:`IwahoriHeckeAlgebra.Cp` basis. The direct method implemented + here significantly speeds up the product computations. The following formulas for products of the forms `C^{\prime}_s \cdot C^{\prime}_w` and `C^{\prime}_w \cdot C^{\prime}_s`, where `s` is a @@ -2043,19 +2043,20 @@ class Cp_Coxeter3(_KLHeckeBasis): In the above, `\leq` is the Bruhat order on the Coxeter group and `\mu(v,w)` is the "leading coefficient of Kazhdan-Lusztig polynomials"; - see [KL1979]_ and [Lus2014]_ for more details. The method designates the - computation of the `\mu`-coefficients to Fokko du Cloux's 'coxeter3' - package (wrapped in Sage), which is why the method requires the creation - of the Coxeter group in the 'coxeter3' implementation. + see [KL1979]_ and [Lus2013]_ for more details. The method designates the + computation of the `\mu`-coefficients to Sage's interface to Fokko du + Cloux's ``coxeter3`` package, which is why the method requires the + creation of the Coxeter group using the 'coxeter3' implementation. EXAMPLES: - To create the basis, define the Coxeter group with 'coxeter3' and the - Hecke algebra with the standard or normalized presentation:: + To create the basis, define the Coxeter group with + ``implementation='coxeter3'`` and the Hecke algebra with the standard or + normalized presentation:: sage: R. = LaurentPolynomialRing(ZZ) sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2) # standard presentation + sage: H = IwahoriHeckeAlgebra(W, v**2) sage: CpC = H.Cp_Coxeter3() The new basis here (``CpC``) and ``Cp`` basis are both implementations @@ -2091,7 +2092,7 @@ class Cp_Coxeter3(_KLHeckeBasis): sage: CpC[1]*CpC[2]*CpC[3]*CpC[1]*CpC[2] CpC[1,2,1,3,2] + CpC[1,2,1] + CpC[1,3,2] - Below is another example, with the Hecke algebra of type `B9` in the + Below is another example, with the Hecke algebra of type `B_9` in the normalized presentation. The (optional) relabeling command ensures that `m(1,2)=4`, i.e., that the generators 1, 2 form the strong bond in the Dynkin diagram:: @@ -2109,7 +2110,7 @@ class Cp_Coxeter3(_KLHeckeBasis): (v^-1+v)*CpC[2,3,2,4,3,5] + (v^-1+v)*CpC[2,3,2,5] Note that to use the CpC basis for a Hecke algebra, a Coxeter group must - be created first with implemntation 'coxeter3'. Directly creating a + be created first with ``implementation='coxeter3'``. Directly creating a Hecke algebra from its Coxeter type does not work:: sage: H = IwahoriHeckeAlgebra('A3', v**2) @@ -2128,48 +2129,49 @@ class Cp_Coxeter3(_KLHeckeBasis): ... ValueError: the Cp_Coxeter3 basis is only supported in a Hecke algebra with the standard or normalized presentations (i.e., need - `\{q_1,q_2\} = \{v^2,1\}` or `\{q_1,q_2\} = \{v,-v^-1\}` as sets) + {q_1,q_2} = {v^2,1} or {q_1,q_2} = {v,-v^-1} as sets) - ALGORITHM : Write `b` for `C^{\prime}`. This class computes each product - `b_x \cdot b_y` in two steps as follows. + ALGORITHM: - If `\ell(x) \leq \ell(y)`, we first decompose `b_x` into a - polynomial in the generators `b_s (s\in S)` and then multiply that - polynomial with `b_y`. If `\ell(x) > \ell(y)`, we decompose `b_y` - into a polynomial in `b_s (s\in S)` and multiply that polynomial - with `b_x`. The second step (multiplication) is done by repeatedly - applying the key formulas displayed earlier directly. The first - step (decomposition) is done by induction on the Bruhat order as - follows: for every element `u\in W` with length `\ell(u)>1`, pick a - left descent `s` of `u` and write `u=sw` (so `w=su`), then note that + Write `b` for `C^{\prime}`. This class computes each product `b_x \cdot + b_y` in two steps as follows. - .. MATH:: - C^{\prime}_u = C^{\prime}_s * C^{\prime}_{w} - \sum_{v\le u; sv< - v} \mu(v,w) C^{\prime}_v + If `\ell(x) \leq \ell(y)`, we first decompose `b_x` into a polynomial in + the generators `b_s (s\in S)` and then multiply that polynomial with + `b_y`. If `\ell(x) > \ell(y)`, we decompose `b_y` into a polynomial in + `b_s (s\in S)` and multiply that polynomial with `b_x`. The second step + (multiplication) is done by repeatedly applying the key formulas + displayed earlier directly. The first step (decomposition) is done by + induction on the Bruhat order as follows: for every element `u\in W` + with length `\ell(u)>1`, pick a left descent `s` of `u` and write `u=sw` + (so `w=su`), then note that - by the key formulas mentioned earlier, where the element `w` and - all elements `v`'s on the right side are lower than `u` in the - Bruhat order; this allows us to finish the computation by - decomposing the lower order terms `b_w` and each `b_v`. For - example, for `u=121, s=1, w=21` in type `A3` we have + .. MATH:: C^{\prime}_u = C^{\prime}_s \cdot C^{\prime}_{w} - \sum_{v\le + u; sv< v} \mu(v,w) C^{\prime}_v - .. MATH:: - b_{121} = b_1*b_{21} - b_1, + by the key formulas mentioned earlier, where the element `w` and all + elements `v`'s on the right side are lower than `u` in the Bruhat order; + this allows us to finish the computation by decomposing the lower order + terms `b_w` and each `b_v`. For example, for `u=121, s=1, w=21` in type + `A3` we have - where the lower order term `b_{21}` further decomposes into - `b_2*b_1`, therefore `b_{121}=b_1*b_2 b_1 -b1`. We note that the - base cases `\ell(x)=1` or `\ell(x)=0` of the above induction occur - when `x` is itself a Coxeter generator `s` or the group identity, - respectively. The decomposition is trivial in these cases (we have - `C_x=C_s` or `C_x=1`, the unit of the Hecke algebra). + .. MATH:: b_{121} = b_1 b_{21} - b_1, + where the lower order term `b_{21}` further decomposes into `b_2 b_1`, + therefore `b_{121}=b_1 b_2 b_1 - b_1`. We note that the base cases + `\ell(x)=1` or `\ell(x)=0` of the above induction occur when `x` is + itself a Coxeter generator `s` or the group identity, respectively. The + decomposition is trivial in these cases (we have `b_x=C_s` or `b_x=1`, + the unit of the Hecke algebra). + TODO: Edit seealso; We can probably not reference cell stuff given our + decision on that, and we *can't* reference _Basis.product_on_basis. + coxeter3? - .. SEEALSO:: - # TODO: edit the following + .. SEEALSO:: - :ref: [KL1979]_, [Lus2013]_ + [KL1979]_, [Lus2013]_ :meth: _Basis.product_on_basis, cell stuff :package?[coxeter3?] @@ -2180,7 +2182,7 @@ class Cp_Coxeter3(_KLHeckeBasis): Use analogs of the key formulas to implement `C^{\prime}`-products in the multi-parameter Iwahori-Hecke algebra; see Section 6 of - [Lus2013]_. + [Lus2013]_. """ _basis_name = 'Cp_Coxeter3' @@ -2199,7 +2201,8 @@ def __init__(self, algebra, prefix='CpC'): sage: CpC = H.Cp_Coxeter3() - Invalid construction (not creating a Coxeter group with 'coxeter3'):: + Invalid construction (not creating a Coxeter group with + 'coxeter3'):: sage: H = IwahoriHeckeAlgebra('A3', v**2) sage: H.Cp_Coxeter3() @@ -2217,7 +2220,7 @@ def __init__(self, algebra, prefix='CpC'): ... ValueError: the Cp_Coxeter3 basis is only supported in a Hecke algebra with the standard or normalized presentations (i.e., need - `\{q_1,q_2\} = \{v^2,1\}` or `\{q_1,q_2\} = \{v,-v^-1\}` as sets) + {q_1,q_2} = {v^2,1} or {q_1,q_2} = {v,-v^-1} as sets) """ if not isinstance(algebra._W, Coxeter3Group): raise ValueError('algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis') @@ -2237,7 +2240,7 @@ def __init__(self, algebra, prefix='CpC'): if not algebra._is_generic: # If this algebra is generic, it's only being used to coerce to the T basis, not perform computations raise ValueError('the Cp_Coxeter3 basis is only supported in a Hecke algebra with the standard or normalized \ -presentations (i.e., need `\{q_1,q_2\} = \{v^2,1\}` or `\{q_1,q_2\} = \{v,-v^-1\}` as sets)') +presentations (i.e., need {q_1,q_2} = {v^2,1} or {q_1,q_2} = {v,-v^-1} as sets)') # Define conversion to the other Cp basis self.module_morphism(self.to_Cp_basis, codomain=algebra.Cp(), category=self.category() @@ -2293,7 +2296,7 @@ def _product_with_generator_on_basis(self, s, w, side='left'): sage: CpC._product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') CpC[1,2,1,3,2,1] + CpC[1,2,3,2] + CpC[1,3,2,1] """ - # use the product formula from TODO: ref algorithm + # use the product formula described in ALGORITHM if w.has_descent(s, side=side): return self.delta * self.monomial(w) else: @@ -2335,9 +2338,15 @@ def _product_with_generator(self, s, x, side='left'): def _decompose_into_generators(self, u): r""" Decompose `C^{\prime}_u` into a polynomial in the KL generators - `C^{\prime}_s`; see "ALGORITHM". TODO: Reference "ALGORITHM" + `C^{\prime}_s`; see the ALGORITHM section of + :class:`IwahoriHeckeAlgebra.Cp_Coxeter3`. + + OUTPUT: - TODO: explain output format + A dictionary keyed by tuples with integer values. Each entry + represents a term, where the tuple contains the indices of the KL + generators in the term, and its value is the coefficient of that + term. EXAMPLES: @@ -2372,7 +2381,7 @@ def _decompose_into_generators(self, u): if len(u) == 1: return {(u[0],): 1} - # l(y) > 1, use the recursive method described in TODO:ref ALGORITHM + # l(y) > 1, use the recursive method described in ALGORITHM s = u[0] w = u[1:] # so CpC_s * CpC_w = CpC_u + lower order terms @@ -2401,8 +2410,8 @@ def product_on_basis(self, w1, w2): the `C^{\prime}`-basis. The product is computed in the two steps (decomposition + - multiplication) as described in "ALGORITHM". TODO: Reference - "ALGORITHM" + multiplication) as described in the ALGORITHM section of + :class:`IwahoriHeckeAlgebra.Cp_Coxeter3` EXAMPLES:: From e7eecf675e687eb3dded1873e1fa475ce217555d Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 31 Jul 2021 15:01:27 -0600 Subject: [PATCH 069/511] Better examples for speed up demonstration --- src/sage/algebras/iwahori_hecke_algebra.py | 50 +++++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 969ad0c3e20..814425ed3b9 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2076,8 +2076,9 @@ class Cp_Coxeter3(_KLHeckeBasis): sage: a == CpC(b) True - This example demonstrates an example that takes a long time in the - existing ``Cp`` basis, but is fast using this implementation:: + Some computations that agree with computations in the existing ``Cp`` + basis; the last example is one that significantly faster in this + implementation than in ``Cp``:: sage: CpC(s1)**2 (v^-1+v)*CpC[1] @@ -2087,15 +2088,35 @@ class Cp_Coxeter3(_KLHeckeBasis): Cp[1,2,1] + Cp[1] sage: CpC(s1)*CpC(s2)*CpC(s1) CpC[1,2,1] + CpC[1] - sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] # long time + sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] Cp[1,2,1,3,2] + Cp[1,2,1] + Cp[1,3,2] - sage: CpC[1]*CpC[2]*CpC[3]*CpC[1]*CpC[2] + sage: CpC[1]*CpC[2]*CpC[3]*CpC[1]*CpC[2] CpC[1,2,1,3,2] + CpC[1,2,1] + CpC[1,3,2] + A computation in type `H_4` that is significantly faster in this + implementation than in the existing ``Cp`` basis:: + + sage: W = CoxeterGroup('H4', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v**2) + sage: Cp = H.Cp(); CpC = H.Cp_Coxeter3() + sage: Cp[3,4,3]*Cp[3,4,3,4]*Cp[1,2,3,4] # long time (5 seconds) + (v^-2+2+v^2)*Cp[4,3,4,3,4,1,2,3,4] + + (v^-2+2+v^2)*Cp[4,3,4,3,4,1,2] + + (v^-1+v)*Cp[3,4,1,2,3,4] + + (v^-3+3*v^-1+3*v+v^3)*Cp[4,3,4,3,4,1] + + (v^-1+v)*Cp[3,4,1,2] + sage: CpC[3,4,3]*CpC[3,4,3,4]*CpC[1,2,3,4] + (v^-2+2+v^2)*CpC[4,3,4,3,4,1,2,3,4] + + (v^-2+2+v^2)*CpC[4,3,4,3,4,1,2] + + (v^-1+v)*CpC[3,4,1,2,3,4] + + (v^-3+3*v^-1+3*v+v^3)*CpC[4,3,4,3,4,1] + + (v^-1+v)*CpC[3,4,1,2] + Below is another example, with the Hecke algebra of type `B_9` in the normalized presentation. The (optional) relabeling command ensures that `m(1,2)=4`, i.e., that the generators 1, 2 form the strong bond in the - Dynkin diagram:: + Dynkin diagram. The final two examples are calculations that are very + quick using this implementation, but infeasible for the ``Cp`` basis:: sage: B9 = CoxeterType(['B', 9]).relabel({ i: 9-i+1 for i in range(1, 10) }) sage: W = CoxeterGroup(B9, implementation='coxeter3') @@ -2104,10 +2125,27 @@ class Cp_Coxeter3(_KLHeckeBasis): sage: s = W.simple_reflections() sage: Cp(s[1]*s[2]*s[1]*s[2]) Cp[1,2,1,2] - sage: Cp[3,2,3,4,5] * Cp[2,3] # long time + sage: Cp[3,2,3,4,5] * Cp[2,3] (v^-1+v)*Cp[2,3,2,4,3,5] + (v^-1+v)*Cp[2,3,2,5] sage: CpC[3,2,3,4,5] * CpC[2,3] (v^-1+v)*CpC[2,3,2,4,3,5] + (v^-1+v)*CpC[2,3,2,5] + sage: CpC[9,5,6,7,8,9,2,3,4,5,6,7,8,9] * CpC[9,8,7,6] + (v^-3+3*v^-1+3*v+v^3)*CpC[2,3,4,5,4,6,5,7,6,8,7,9,8,7,6] + sage: CpC[1,5,4,3,2,1,8,7,6,5,4,3,2,1] * CpC[1,2,3,4] # long time (4 seconds) + (v^-1+v)*CpC[1,5,4,3,2,1,8,7,6,5,4,3,2,1,2,3,4] + + (v^-1+v)*CpC[1,2,1,5,4,3,2,1,2,3,8,7,6,5,4] + + (v^-1+v)*CpC[1,3,2,1,5,4,3,2,1,2,3,4,8,7,6] + + (v^-1+v)*CpC[1,4,3,2,1,5,4,3,2,1,2,3,4,8,7] + + (v^-1+v)*CpC[1,5,4,3,2,1,2,3,8,7,6,5,4,3,2] + + (v^-1+v)*CpC[1,2,5,4,3,2,1,8,7,6,5,4,3] + + (v^-1+v)*CpC[1,2,5,4,3,2,8,7,6,5,4,3,2] + + (v^-1+v)*CpC[1,2,3,2,5,4,3,2,8,7,6] + + (v^-1+v)*CpC[1,2,4,3,2,5,4,3,2,8,7] + + (v^-1+v)*CpC[1,2,5,4,3,2,8,7,6,5,4] + + (v^-1+v)*CpC[1,5,4,3,2,1,8,7,6,5,4] + + (v^-1+v)*CpC[1,5,4,3,8,7,6,5,4,3,2] + + (v^-1+v)*CpC[1,3,5,4,3,2,8,7,6] + + (v^-1+v)*CpC[1,4,3,5,4,3,2,8,7] Note that to use the CpC basis for a Hecke algebra, a Coxeter group must be created first with ``implementation='coxeter3'``. Directly creating a From 4fd9688af683669ff60e2eea4978e897c5da39b8 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 31 Jul 2021 15:02:13 -0600 Subject: [PATCH 070/511] Mark doctests throughout with # optional - coxeter3. Tweak _to_T_basis() tests --- src/sage/algebras/iwahori_hecke_algebra.py | 209 +++++++++++---------- 1 file changed, 110 insertions(+), 99 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 814425ed3b9..d501b571ed0 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1588,17 +1588,17 @@ def to_Cp_Coxeter3_basis(self, w): EXAMPLES:: - sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, v**2); T=H.T(); CpC=H.Cp_Coxeter3() - sage: s1,s2,s3 = A3.simple_reflections() - sage: T.to_Cp_Coxeter3_basis(s1) + sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(A3, v**2); T=H.T(); CpC=H.Cp_Coxeter3() # optional - coxeter3 + sage: s1,s2,s3 = A3.simple_reflections() # optional - coxeter3 + sage: T.to_Cp_Coxeter3_basis(s1) # optional - coxeter3 v*CpC[1] - 1 - sage: CpC(T(s1)) + sage: CpC(T(s1)) # optional - coxeter3 v*CpC[1] - 1 - sage: CpC(T[1] + 1) + sage: CpC(T[1] + 1) # optional - coxeter3 v*CpC[1] - sage: CpC(T[1,2] + T[1] + T[2] + 1) + sage: CpC(T[1,2] + T[1] + T[2] + 1) # optional - coxeter3 v^2*CpC[1,2] """ H = self.realization_of() @@ -2054,10 +2054,10 @@ class Cp_Coxeter3(_KLHeckeBasis): ``implementation='coxeter3'`` and the Hecke algebra with the standard or normalized presentation:: - sage: R. = LaurentPolynomialRing(ZZ) - sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2) - sage: CpC = H.Cp_Coxeter3() + sage: R. = LaurentPolynomialRing(ZZ) # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 + sage: CpC = H.Cp_Coxeter3() # optional - coxeter3 The new basis here (``CpC``) and ``Cp`` basis are both implementations of the the `C^{\prime}` basis. The only difference between the @@ -2065,47 +2065,47 @@ class Cp_Coxeter3(_KLHeckeBasis): elements can be converted between the two trivially TODO: I'm not sure this example block is as useful or clear as it could be:: - sage: s1, s2, s3 = W.simple_reflections() - sage: Cp = H.Cp() - sage: a = CpC(s1*s2*s1); a + sage: s1, s2, s3 = W.simple_reflections() # optional - coxeter3 + sage: Cp = H.Cp() # optional - coxeter3 + sage: a = CpC(s1*s2*s1); a # optional - coxeter3 CpC[1,2,1] - sage: b = Cp(s1*s2*s1); b + sage: b = Cp(s1*s2*s1); b # optional - coxeter3 Cp[1,2,1] - sage: Cp(a) == b + sage: Cp(a) == b # optional - coxeter3 True - sage: a == CpC(b) + sage: a == CpC(b) # optional - coxeter3 True Some computations that agree with computations in the existing ``Cp`` basis; the last example is one that significantly faster in this implementation than in ``Cp``:: - sage: CpC(s1)**2 + sage: CpC(s1)**2 # optional - coxeter3 (v^-1+v)*CpC[1] - sage: Cp(s1)**2 + sage: Cp(s1)**2 # optional - coxeter3 (v^-1+v)*Cp[1] - sage: Cp(s1)*Cp(s2)*Cp(s1) + sage: Cp(s1)*Cp(s2)*Cp(s1) # optional - coxeter3 Cp[1,2,1] + Cp[1] - sage: CpC(s1)*CpC(s2)*CpC(s1) + sage: CpC(s1)*CpC(s2)*CpC(s1) # optional - coxeter3 CpC[1,2,1] + CpC[1] - sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] + sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] # optional - coxeter3 Cp[1,2,1,3,2] + Cp[1,2,1] + Cp[1,3,2] - sage: CpC[1]*CpC[2]*CpC[3]*CpC[1]*CpC[2] + sage: CpC[1]*CpC[2]*CpC[3]*CpC[1]*CpC[2] # optional - coxeter3 CpC[1,2,1,3,2] + CpC[1,2,1] + CpC[1,3,2] A computation in type `H_4` that is significantly faster in this implementation than in the existing ``Cp`` basis:: - sage: W = CoxeterGroup('H4', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2) - sage: Cp = H.Cp(); CpC = H.Cp_Coxeter3() - sage: Cp[3,4,3]*Cp[3,4,3,4]*Cp[1,2,3,4] # long time (5 seconds) + sage: W = CoxeterGroup('H4', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 + sage: Cp = H.Cp(); CpC = H.Cp_Coxeter3() # optional - coxeter3 + sage: Cp[3,4,3]*Cp[3,4,3,4]*Cp[1,2,3,4] # long time (5 seconds) # optional - coxeter3 (v^-2+2+v^2)*Cp[4,3,4,3,4,1,2,3,4] + (v^-2+2+v^2)*Cp[4,3,4,3,4,1,2] + (v^-1+v)*Cp[3,4,1,2,3,4] + (v^-3+3*v^-1+3*v+v^3)*Cp[4,3,4,3,4,1] + (v^-1+v)*Cp[3,4,1,2] - sage: CpC[3,4,3]*CpC[3,4,3,4]*CpC[1,2,3,4] + sage: CpC[3,4,3]*CpC[3,4,3,4]*CpC[1,2,3,4] # optional - coxeter3 (v^-2+2+v^2)*CpC[4,3,4,3,4,1,2,3,4] + (v^-2+2+v^2)*CpC[4,3,4,3,4,1,2] + (v^-1+v)*CpC[3,4,1,2,3,4] @@ -2118,20 +2118,21 @@ class Cp_Coxeter3(_KLHeckeBasis): Dynkin diagram. The final two examples are calculations that are very quick using this implementation, but infeasible for the ``Cp`` basis:: - sage: B9 = CoxeterType(['B', 9]).relabel({ i: 9-i+1 for i in range(1, 10) }) - sage: W = CoxeterGroup(B9, implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v, -1/v) - sage: CpC, Cp = H.Cp_Coxeter3(), H.Cp() - sage: s = W.simple_reflections() - sage: Cp(s[1]*s[2]*s[1]*s[2]) + sage: B9 = CoxeterType(['B', 9]) + sage: B9 = B9.relabel({ i: 9-i+1 for i in range(1, 10) }) # optional - coxeter3 + sage: W = CoxeterGroup(B9, implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v, -1/v) # optional - coxeter3 + sage: CpC, Cp = H.Cp_Coxeter3(), H.Cp() # optional - coxeter3 + sage: s = W.simple_reflections() # optional - coxeter3 + sage: Cp(s[1]*s[2]*s[1]*s[2]) # optional - coxeter3 Cp[1,2,1,2] - sage: Cp[3,2,3,4,5] * Cp[2,3] + sage: Cp[3,2,3,4,5] * Cp[2,3] # optional - coxeter3 (v^-1+v)*Cp[2,3,2,4,3,5] + (v^-1+v)*Cp[2,3,2,5] - sage: CpC[3,2,3,4,5] * CpC[2,3] + sage: CpC[3,2,3,4,5] * CpC[2,3] # optional - coxeter3 (v^-1+v)*CpC[2,3,2,4,3,5] + (v^-1+v)*CpC[2,3,2,5] - sage: CpC[9,5,6,7,8,9,2,3,4,5,6,7,8,9] * CpC[9,8,7,6] + sage: CpC[9,5,6,7,8,9,2,3,4,5,6,7,8,9] * CpC[9,8,7,6] # optional - coxeter3 (v^-3+3*v^-1+3*v+v^3)*CpC[2,3,4,5,4,6,5,7,6,8,7,9,8,7,6] - sage: CpC[1,5,4,3,2,1,8,7,6,5,4,3,2,1] * CpC[1,2,3,4] # long time (4 seconds) + sage: CpC[1,5,4,3,2,1,8,7,6,5,4,3,2,1] * CpC[1,2,3,4] # long time (4 seconds) # optional - coxeter3 (v^-1+v)*CpC[1,5,4,3,2,1,8,7,6,5,4,3,2,1,2,3,4] + (v^-1+v)*CpC[1,2,1,5,4,3,2,1,2,3,8,7,6,5,4] + (v^-1+v)*CpC[1,3,2,1,5,4,3,2,1,2,3,4,8,7,6] @@ -2151,8 +2152,8 @@ class Cp_Coxeter3(_KLHeckeBasis): be created first with ``implementation='coxeter3'``. Directly creating a Hecke algebra from its Coxeter type does not work:: - sage: H = IwahoriHeckeAlgebra('A3', v**2) - sage: H.Cp_Coxeter3() + sage: H = IwahoriHeckeAlgebra('A3', v**2) # optional - coxeter3 + sage: H.Cp_Coxeter3() # optional - coxeter3 Traceback (most recent call last): ... ValueError: algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis @@ -2160,9 +2161,9 @@ class Cp_Coxeter3(_KLHeckeBasis): With the Coxeter group created first, the Hecke algebra must be defined with the standard or normalized presentation mentioned before:: - sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, QQ(1)) - sage: H.Cp_Coxeter3() + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, QQ(1)) # optional - coxeter3 + sage: H.Cp_Coxeter3() # optional - coxeter3 Traceback (most recent call last): ... ValueError: the Cp_Coxeter3 basis is only supported in a Hecke @@ -2233,17 +2234,17 @@ def __init__(self, algebra, prefix='CpC'): Valid construction:: - sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2) - sage: CpC = H.Cp_Coxeter3() + sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 + sage: CpC = H.Cp_Coxeter3() # optional - coxeter3 Invalid construction (not creating a Coxeter group with 'coxeter3'):: - sage: H = IwahoriHeckeAlgebra('A3', v**2) - sage: H.Cp_Coxeter3() + sage: H = IwahoriHeckeAlgebra('A3', v**2) # optional - coxeter3 + sage: H.Cp_Coxeter3() # optional - coxeter3 Traceback (most recent call last): ... ValueError: algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis @@ -2251,9 +2252,9 @@ def __init__(self, algebra, prefix='CpC'): Invalid construction (bad presentation for Hecke algebra):: - sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, QQ(1)) - sage: H.Cp_Coxeter3() + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, QQ(1)) # optional - coxeter3 + sage: H.Cp_Coxeter3() # optional - coxeter3 Traceback (most recent call last): ... ValueError: the Cp_Coxeter3 basis is only supported in a Hecke @@ -2296,13 +2297,14 @@ def to_Cp_basis(self, w): EXAMPLES:: - sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp(); CpC=H.Cp_Coxeter3() - sage: s1, s2, s3 = W.simple_reflections() - sage: CpC.to_Cp_basis(s1*s2) + sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 + sage: Cp=H.Cp(); CpC=H.Cp_Coxeter3() # optional - coxeter3 + sage: s1, s2, s3 = W.simple_reflections() # optional - coxeter3 + sage: CpC.to_Cp_basis(s1*s2) # optional - coxeter3 Cp[1,2] - sage: CpC.to_Cp_basis(s1*s2*s1) + sage: CpC.to_Cp_basis(s1*s2*s1) # optional - coxeter3 Cp[1,2,1] """ A = self.realization_of() @@ -2324,14 +2326,14 @@ def _product_with_generator_on_basis(self, s, w, side='left'): EXAMPLES:: - sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() - sage: CpC._product_with_generator_on_basis(1, W([2,1]), 'left') + sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() # optional - coxeter3 + sage: CpC._product_with_generator_on_basis(1, W([2,1]), 'left') # optional - coxeter3 CpC[1,2,1] + CpC[1] - sage: CpC._product_with_generator_on_basis(1, W([2,1]), 'right') + sage: CpC._product_with_generator_on_basis(1, W([2,1]), 'right') # optional - coxeter3 (v^-1+v)*CpC[2,1] - sage: CpC._product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') + sage: CpC._product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') # optional - coxeter3 CpC[1,2,1,3,2,1] + CpC[1,2,3,2] + CpC[1,3,2,1] """ # use the product formula described in ALGORITHM @@ -2363,12 +2365,12 @@ def _product_with_generator(self, s, x, side='left'): EXAMPLES:: - sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() - sage: CpC._product_with_generator(1, CpC[1]+CpC[2], 'left') + sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() # optional - coxeter3 + sage: CpC._product_with_generator(1, CpC[1]+CpC[2], 'left') # optional - coxeter3 CpC[1,2] + (v^-1+v)*CpC[1] - sage: CpC._product_with_generator(1, CpC[1]+CpC[2], 'right') + sage: CpC._product_with_generator(1, CpC[1]+CpC[2], 'right') # optional - coxeter3 CpC[2,1] + (v^-1+v)*CpC[1] """ return self.linear_combination((self._product_with_generator_on_basis(s, w, side), coeff) for (w, coeff) in x) @@ -2390,27 +2392,27 @@ def _decompose_into_generators(self, u): :: - sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() + sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() # optional - coxeter3 When `u` is itself a generator `s`, the decomposition is trivial:: - sage: CpC._decompose_into_generators(W([1])) + sage: CpC._decompose_into_generators(W([1])) # optional - coxeter3 {(1,): 1} Another example, where `C^{\prime}_u` happens to be a monomial (e.g., CpC_{21} = CpC_2 * CpC_1):: - sage: CpC._decompose_into_generators(W([2,1])) + sage: CpC._decompose_into_generators(W([2,1])) # optional - coxeter3 {(2, 1): 1} In more general situations the sum is a polynomial (e.g., CpC_{121}=CpC_1*CpC_2*CpC_1-CpC_1):: - sage: CpC._decompose_into_generators(W([1,2,1])) + sage: CpC._decompose_into_generators(W([1,2,1])) # optional - coxeter3 {(1,): -1, (1, 2, 1): 1} - sage: CpC._decompose_into_generators(W([1,2,3,1,2])) + sage: CpC._decompose_into_generators(W([1,2,3,1,2])) # optional - coxeter3 {(1,): 1, (1, 2, 1): -1, (1, 2, 1, 3, 2): 1, (1, 3, 2): -1} """ # l(y) = 0 or 1 @@ -2453,12 +2455,12 @@ def product_on_basis(self, w1, w2): EXAMPLES:: - sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: W = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() - sage: CpC.product_on_basis(W([1,2,1]), W([3,1])) + sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() # optional - coxeter3 + sage: CpC.product_on_basis(W([1,2,1]), W([3,1])) # optional - coxeter3 (v^-1+v)*CpC[1,2,1,3] - sage: CpC.product_on_basis(W([1,2,1]), W([3,1,2])) + sage: CpC.product_on_basis(W([1,2,1]), W([3,1,2])) # optional - coxeter3 (v^-1+v)*CpC[1,2,1,3,2] + (v^-1+v)*CpC[1,2,1] """ # Decomposition: write one of C'_{w1} and C'_{w2} as a polynomial in the @@ -3064,20 +3066,29 @@ def _to_Cp_basis(self, w, Cp): - ``Cp`` -- the target `C^{\prime}` basis to use; either ``Cp`` or ``Cp_Coxeter3`` - EXAMPLES:: + EXAMPLES: - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') + :: + + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard(A3) # optional - coxeter3 + sage: s1,s2,s3 = A3.simple_reflections() # optional - coxeter3 + sage: T = H.T(); CpC = H.Cp_Coxeter3() # optional - coxeter3 + sage: T._to_Cp_basis(s1, CpC) # optional - coxeter3 + v*CpC[1] + (-u^-1*v^2) + sage: CpC(T(s1)) # optional - coxeter3 + v*CpC[1] + (-u^-1*v^2) + + :: + + sage: A3 = CoxeterGroup('A3') sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard(A3) sage: s1,s2,s3 = A3.simple_reflections() - sage: T = H.T(); Cp = H.Cp(); CpC = H.Cp_Coxeter3() + sage: T = H.T(); Cp = H.Cp() sage: T._to_Cp_basis(s1, Cp) v*Cp[1] + (-u^-1*v^2) sage: Cp(T(s1)) v*Cp[1] + (-u^-1*v^2) - sage: T._to_Cp_basis(s1, CpC) - v*CpC[1] + (-u^-1*v^2) - sage: CpC(T(s1)) - v*CpC[1] + (-u^-1*v^2) """ A = self.realization_of() # Cp = A.Cp() if not use_Cp_Coxeter3 else A.Cp_Coxeter3() @@ -3130,21 +3141,21 @@ def to_Cp_Coxeter3_basis(self, w): EXAMPLES:: - sage: A2 = CoxeterGroup('A2', implementation='coxeter3') - sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard(A2) - sage: s1,s2 = H.coxeter_group().simple_reflections() - sage: T = H.T() - sage: CpC = H.Cp_Coxeter3() - sage: T.to_Cp_Coxeter3_basis(s1) + sage: A2 = CoxeterGroup('A2', implementation='coxeter3') # optional - coxeter3 + sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard(A2) # optional - coxeter3 + sage: s1,s2 = H.coxeter_group().simple_reflections() # optional - coxeter3 + sage: T = H.T() # optional - coxeter3 + sage: CpC = H.Cp_Coxeter3() # optional - coxeter3 + sage: T.to_Cp_Coxeter3_basis(s1) # optional - coxeter3 v*CpC[1] + (-u^-1*v^2) - sage: CpC(T(s1)) + sage: CpC(T(s1)) # optional - coxeter3 v*CpC[1] + (-u^-1*v^2) - sage: CpC(T(s1)+1) + sage: CpC(T(s1)+1) # optional - coxeter3 v*CpC[1] + (-u^-1*v^2+1) - sage: CpC(T(s1*s2)+T(s1)+T(s2)+1) + sage: CpC(T(s1*s2)+T(s1)+T(s2)+1) # optional - coxeter3 v^2*CpC[1,2] + (-u^-1*v^3+v)*CpC[1] + (-u^-1*v^3+v)*CpC[2] + (u^-2*v^4-2*u^-1*v^2+1) - sage: CpC(T(s1*s2*s1)) + sage: CpC(T(s1*s2*s1)) # optional - coxeter3 v^3*CpC[1,2,1] + (-u^-1*v^4)*CpC[1,2] + (-u^-1*v^4)*CpC[2,1] + (u^-2*v^5)*CpC[1] + (u^-2*v^5)*CpC[2] + (-u^-3*v^6) """ From 6acc0ec637f92790dd4c249b2c2ab0f4772fa71d Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 31 Jul 2021 15:18:21 -0600 Subject: [PATCH 071/511] Move ALGORITHM to the docstring of product_on_basis --- src/sage/algebras/iwahori_hecke_algebra.py | 95 ++++++++++------------ 1 file changed, 45 insertions(+), 50 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index d501b571ed0..24e6261e07d 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2048,6 +2048,9 @@ class Cp_Coxeter3(_KLHeckeBasis): Cloux's ``coxeter3`` package, which is why the method requires the creation of the Coxeter group using the 'coxeter3' implementation. + The multiplication algorithm is described in detail in + :func:`product_on_basis`. + EXAMPLES: To create the basis, define the Coxeter group with @@ -2170,50 +2173,6 @@ class Cp_Coxeter3(_KLHeckeBasis): algebra with the standard or normalized presentations (i.e., need {q_1,q_2} = {v^2,1} or {q_1,q_2} = {v,-v^-1} as sets) - - ALGORITHM: - - Write `b` for `C^{\prime}`. This class computes each product `b_x \cdot - b_y` in two steps as follows. - - If `\ell(x) \leq \ell(y)`, we first decompose `b_x` into a polynomial in - the generators `b_s (s\in S)` and then multiply that polynomial with - `b_y`. If `\ell(x) > \ell(y)`, we decompose `b_y` into a polynomial in - `b_s (s\in S)` and multiply that polynomial with `b_x`. The second step - (multiplication) is done by repeatedly applying the key formulas - displayed earlier directly. The first step (decomposition) is done by - induction on the Bruhat order as follows: for every element `u\in W` - with length `\ell(u)>1`, pick a left descent `s` of `u` and write `u=sw` - (so `w=su`), then note that - - .. MATH:: C^{\prime}_u = C^{\prime}_s \cdot C^{\prime}_{w} - \sum_{v\le - u; sv< v} \mu(v,w) C^{\prime}_v - - by the key formulas mentioned earlier, where the element `w` and all - elements `v`'s on the right side are lower than `u` in the Bruhat order; - this allows us to finish the computation by decomposing the lower order - terms `b_w` and each `b_v`. For example, for `u=121, s=1, w=21` in type - `A3` we have - - .. MATH:: b_{121} = b_1 b_{21} - b_1, - - where the lower order term `b_{21}` further decomposes into `b_2 b_1`, - therefore `b_{121}=b_1 b_2 b_1 - b_1`. We note that the base cases - `\ell(x)=1` or `\ell(x)=0` of the above induction occur when `x` is - itself a Coxeter generator `s` or the group identity, respectively. The - decomposition is trivial in these cases (we have `b_x=C_s` or `b_x=1`, - the unit of the Hecke algebra). - TODO: Edit seealso; We can probably not reference cell stuff given our - decision on that, and we *can't* reference _Basis.product_on_basis. - coxeter3? - - - .. SEEALSO:: - - [KL1979]_, [Lus2013]_ - :meth: _Basis.product_on_basis, cell stuff - :package?[coxeter3?] - .. TODO:: Accommodate generic presentations of the Hecke algebra other than @@ -2336,7 +2295,7 @@ def _product_with_generator_on_basis(self, s, w, side='left'): sage: CpC._product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') # optional - coxeter3 CpC[1,2,1,3,2,1] + CpC[1,2,3,2] + CpC[1,3,2,1] """ - # use the product formula described in ALGORITHM + # use the product formula described in product_on_basis if w.has_descent(s, side=side): return self.delta * self.monomial(w) else: @@ -2379,7 +2338,7 @@ def _decompose_into_generators(self, u): r""" Decompose `C^{\prime}_u` into a polynomial in the KL generators `C^{\prime}_s`; see the ALGORITHM section of - :class:`IwahoriHeckeAlgebra.Cp_Coxeter3`. + :func:`product_on_basis`. OUTPUT: @@ -2421,7 +2380,7 @@ def _decompose_into_generators(self, u): if len(u) == 1: return {(u[0],): 1} - # l(y) > 1, use the recursive method described in ALGORITHM + # l(y) > 1, use the recursive method described in product_on_basis s = u[0] w = u[1:] # so CpC_s * CpC_w = CpC_u + lower order terms @@ -2449,9 +2408,45 @@ def product_on_basis(self, w1, w2): Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` in the `C^{\prime}`-basis. - The product is computed in the two steps (decomposition + - multiplication) as described in the ALGORITHM section of - :class:`IwahoriHeckeAlgebra.Cp_Coxeter3` + ALGORITHM: + + This class computes each product `C^{\prime}_x \cdot C^{\prime}_y` + in two steps as follows. + + If `\ell(x) \leq \ell(y)`, we first decompose `C^{\prime}_x` into a + polynomial in the generators `C^{\prime}_s (s\in S)` and then + multiply that polynomial with `C^{\prime}_y`. If `\ell(x) > + \ell(y)`, we decompose `C^{\prime}_y` into a polynomial in + `C^{\prime}_s (s\in S)` and multiply that polynomial with + `C^{\prime}_x`. The second step (multiplication) is done by + repeatedly applying the key formulas displayed earlier directly. The + first step (decomposition) is done by induction on the Bruhat order + as follows: for every element `u\in W` with length `\ell(u)>1`, pick + a left descent `s` of `u` and write `u=sw` (so `w=su`), then note + that + + .. MATH:: C^{\prime}_u = C^{\prime}_s \cdot C^{\prime}_{w} - \sum_{v\le u; sv< v} \mu(v,w) C^{\prime}_v + + by the key formulas mentioned earlier, where the element `w` and all + elements `v`'s on the right side are lower than `u` in the Bruhat + order; this allows us to finish the computation by decomposing the + lower order terms `C^{\prime}_w` and each `C^{\prime}_v`. For + example, for `u=121, s=1, w=21` in type `A_3` we have + `C^{\prime}_{121} = C^{\prime}_1 C^{\prime}_{21} - C^{\prime}_1`, + where the lower order term `C^{\prime}_{21}` further decomposes into + `C^{\prime}_2 C^{\prime}_1`, therefore + + .. MATH:: C^{\prime}_{121}=C^{\prime}_1 C^{\prime}_2 C^{\prime}_1 - C^{\prime}_1 + + We note that the base cases `\ell(x)=1` or `\ell(x)=0` of the above + induction occur when `x` is itself a Coxeter generator `s` or the + group identity, respectively. The decomposition is trivial in these + cases (we have `C^{\prime}_x=C^{\prime}_s` or `C^{\prime}_x=1`, the + unit of the Hecke algebra). + + .. SEEALSO:: + + [KL1979]_, [Lus2013]_ EXAMPLES:: From 7d9d80916d722b5533160d53c840d40c080ca227 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 31 Jul 2021 16:40:12 -0600 Subject: [PATCH 072/511] Tweak class docs --- src/sage/algebras/iwahori_hecke_algebra.py | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 24e6261e07d..09eeb27d647 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2065,24 +2065,18 @@ class Cp_Coxeter3(_KLHeckeBasis): The new basis here (``CpC``) and ``Cp`` basis are both implementations of the the `C^{\prime}` basis. The only difference between the implementations lies in their different methods for computing products, - elements can be converted between the two trivially TODO: I'm not sure - this example block is as useful or clear as it could be:: + elements can be converted between the two trivially:: - sage: s1, s2, s3 = W.simple_reflections() # optional - coxeter3 - sage: Cp = H.Cp() # optional - coxeter3 - sage: a = CpC(s1*s2*s1); a # optional - coxeter3 - CpC[1,2,1] - sage: b = Cp(s1*s2*s1); b # optional - coxeter3 + sage: Cp = H.Cp() # optional - coxeter3 + sage: Cp(CpC[1,2,1]) # optional - coxeter3 Cp[1,2,1] - sage: Cp(a) == b # optional - coxeter3 - True - sage: a == CpC(b) # optional - coxeter3 - True + sage: CpC(Cp[1,2,1]) # optional - coxeter3 + CpC[1,2,1] - Some computations that agree with computations in the existing ``Cp`` - basis; the last example is one that significantly faster in this - implementation than in ``Cp``:: + Some computations; these agree with computations in the existing ``Cp`` + basis:: + sage: s1, s2, s3 = W.simple_reflections() # optional - coxeter3 sage: CpC(s1)**2 # optional - coxeter3 (v^-1+v)*CpC[1] sage: Cp(s1)**2 # optional - coxeter3 From dca76a307b95862314b7e07492e6b92f134662f4 Mon Sep 17 00:00:00 2001 From: Tianyuan Xu Date: Sun, 1 Aug 2021 12:05:08 -0600 Subject: [PATCH 073/511] very minor changes to doc strings --- src/sage/algebras/iwahori_hecke_algebra.py | 54 +++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 09eeb27d647..1d2ed32b93b 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2008,7 +2008,8 @@ class Cp_Coxeter3(_KLHeckeBasis): "standard" presentation where `\{q_1,q_2\} = \{v^2,1\}` as sets or the "normalized" presentations where `\{q_1,q_2\} = \{v,-v^{-1}\}` as sets. The Hecke algebra also needs to be created from a Coxeter group defined - using the 'coxeter3' implementation; see the examples to follow. + using the 'coxeter3' implementation, because this class designates the + computation of certain important coefficients to 'coxeter3'. Expanding products of the form `C^{\prime}_x \cdot C^{\prime}_y` in the `C^{\prime}`-basis is useful for computing Kazhdan-Lusztig cells of @@ -2016,10 +2017,10 @@ class Cp_Coxeter3(_KLHeckeBasis): algebras. The emphasis of this class is to compute such products more directly in the `C^{\prime}`-basis, as opposed to converting the `C^{\prime}`-basis to the `T`-basis, calculating the product in the - `T`-basis, and converting the results back to the `C^{\prime}`-basis, as - is the default technique in ``_Basis.product_on_basis``, used by the - :class:`IwahoriHeckeAlgebra.Cp` basis. The direct method implemented - here significantly speeds up the product computations. + `T`-basis, and converting the results back to the `C^{\prime}`-basis. + The latter approach is used in the function ``_Basis.product_on_basis`` + of for the :class:`IwahoriHeckeAlgebra.Cp` basis. The direct method + implemented here significantly speeds up the product computations. The following formulas for products of the forms `C^{\prime}_s \cdot C^{\prime}_w` and `C^{\prime}_w \cdot C^{\prime}_s`, where `s` is a @@ -2064,8 +2065,8 @@ class Cp_Coxeter3(_KLHeckeBasis): The new basis here (``CpC``) and ``Cp`` basis are both implementations of the the `C^{\prime}` basis. The only difference between the - implementations lies in their different methods for computing products, - elements can be converted between the two trivially:: + implementations lies in their different methods for computing products. + The conversion between ``CpC`` and ``Cp`` is trivial:: sage: Cp = H.Cp() # optional - coxeter3 sage: Cp(CpC[1,2,1]) # optional - coxeter3 @@ -2073,14 +2074,14 @@ class Cp_Coxeter3(_KLHeckeBasis): sage: CpC(Cp[1,2,1]) # optional - coxeter3 CpC[1,2,1] - Some computations; these agree with computations in the existing ``Cp`` - basis:: + Some computations in the ``CpC`` basis; these agree with computations + in the existing ``Cp`` basis:: sage: s1, s2, s3 = W.simple_reflections() # optional - coxeter3 - sage: CpC(s1)**2 # optional - coxeter3 - (v^-1+v)*CpC[1] sage: Cp(s1)**2 # optional - coxeter3 (v^-1+v)*Cp[1] + sage: CpC(s1)**2 # optional - coxeter3 + (v^-1+v)*CpC[1] sage: Cp(s1)*Cp(s2)*Cp(s1) # optional - coxeter3 Cp[1,2,1] + Cp[1] sage: CpC(s1)*CpC(s2)*CpC(s1) # optional - coxeter3 @@ -2090,7 +2091,7 @@ class Cp_Coxeter3(_KLHeckeBasis): sage: CpC[1]*CpC[2]*CpC[3]*CpC[1]*CpC[2] # optional - coxeter3 CpC[1,2,1,3,2] + CpC[1,2,1] + CpC[1,3,2] - A computation in type `H_4` that is significantly faster in this + A computation in type `H_4` that is significantly faster in the ``CpC`` implementation than in the existing ``Cp`` basis:: sage: W = CoxeterGroup('H4', implementation='coxeter3') # optional - coxeter3 @@ -2112,8 +2113,9 @@ class Cp_Coxeter3(_KLHeckeBasis): Below is another example, with the Hecke algebra of type `B_9` in the normalized presentation. The (optional) relabeling command ensures that `m(1,2)=4`, i.e., that the generators 1, 2 form the strong bond in the - Dynkin diagram. The final two examples are calculations that are very - quick using this implementation, but infeasible for the ``Cp`` basis:: + Dynkin diagram. The final two examples are calculations that are quick + in this implementation but seem prohibitively slow for the ``Cp`` + basis:: sage: B9 = CoxeterType(['B', 9]) sage: B9 = B9.relabel({ i: 9-i+1 for i in range(1, 10) }) # optional - coxeter3 @@ -2172,7 +2174,8 @@ class Cp_Coxeter3(_KLHeckeBasis): Accommodate generic presentations of the Hecke algebra other than the standard and normalized ones. - Use analogs of the key formulas to implement `C^{\prime}`-products + Use analogs of the formulas for `C^{\prime}_s C^{\prime}_w` and + `C^{\prime}_w C^{\prime}_s` to implement `C^{\prime}`-products in the multi-parameter Iwahori-Hecke algebra; see Section 6 of [Lus2013]_. """ @@ -2180,7 +2183,7 @@ class Cp_Coxeter3(_KLHeckeBasis): def __init__(self, algebra, prefix='CpC'): r""" - Initialize the Cp_Coxeter3 Kazdahn-Lusztig basis of the + Initialize the Cp_Coxeter3 Kazhdan-Lusztig basis of the Iwahori-Hecke algebra ``algebra''. EXAMPLES: @@ -2226,7 +2229,7 @@ def __init__(self, algebra, prefix='CpC'): parameters = {algebra.q1(), algebra.q2()} if v != algebra.base_ring().one() and (parameters == {v**2, -1} or parameters == {v, -1/v}): # The following quantity delta is used in product computations. - # To use it we need the standard or normalized normalizations. + # To use v+~v as its value we need the standard or normalized presentations of the Hecke algebra. self.delta = v + ~v else: if not algebra._is_generic: @@ -2234,7 +2237,7 @@ def __init__(self, algebra, prefix='CpC'): raise ValueError('the Cp_Coxeter3 basis is only supported in a Hecke algebra with the standard or normalized \ presentations (i.e., need {q_1,q_2} = {v^2,1} or {q_1,q_2} = {v,-v^-1} as sets)') - # Define conversion to the other Cp basis + # Define the (trivial) conversion to the other Cp basis self.module_morphism(self.to_Cp_basis, codomain=algebra.Cp(), category=self.category() ).register_as_coercion() @@ -2289,7 +2292,7 @@ def _product_with_generator_on_basis(self, s, w, side='left'): sage: CpC._product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') # optional - coxeter3 CpC[1,2,1,3,2,1] + CpC[1,2,3,2] + CpC[1,3,2,1] """ - # use the product formula described in product_on_basis + # use the product formula described in the class' documentation if w.has_descent(s, side=side): return self.delta * self.monomial(w) else: @@ -2337,9 +2340,10 @@ def _decompose_into_generators(self, u): OUTPUT: A dictionary keyed by tuples with integer values. Each entry - represents a term, where the tuple contains the indices of the KL - generators in the term, and its value is the coefficient of that - term. + represents a term, where the tuple represents a monomial term in + the KL generators and the value represents the coefficient of that + term. For example, an item `(1,2): 3` stands for `3 * + C^{\prime}_1C^{\prime}_2`. EXAMPLES: @@ -2430,7 +2434,7 @@ def product_on_basis(self, w1, w2): where the lower order term `C^{\prime}_{21}` further decomposes into `C^{\prime}_2 C^{\prime}_1`, therefore - .. MATH:: C^{\prime}_{121}=C^{\prime}_1 C^{\prime}_2 C^{\prime}_1 - C^{\prime}_1 + .. MATH:: C^{\prime}_{121}=C^{\prime}_1 C^{\prime}_2 C^{\prime}_1 - C^{\prime}_1. We note that the base cases `\ell(x)=1` or `\ell(x)=0` of the above induction occur when `x` is itself a Coxeter generator `s` or the @@ -2438,10 +2442,6 @@ def product_on_basis(self, w1, w2): cases (we have `C^{\prime}_x=C^{\prime}_s` or `C^{\prime}_x=1`, the unit of the Hecke algebra). - .. SEEALSO:: - - [KL1979]_, [Lus2013]_ - EXAMPLES:: sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 From 4d949013a3e9e248ade7aeef04abb5d486cd0d9a Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Mon, 9 Aug 2021 16:34:09 -0600 Subject: [PATCH 074/511] Include basic cell computations using the CpC basis. --- src/sage/libs/coxeter3/coxeter_group.py | 99 +++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index d0c13f12a11..746d6080fdb 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -9,9 +9,13 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from collections import deque + from sage.libs.coxeter3.coxeter import get_CoxGroup, CoxGroupElement from sage.misc.cachefunc import cached_method +from sage.graphs.digraph import DiGraph + from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper from sage.structure.richcmp import richcmp @@ -21,6 +25,7 @@ from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -423,6 +428,100 @@ def parabolic_kazhdan_lusztig_polynomial(self, u, v, J, constant_term_one=True): return P.sum((-1)**(z.length()) * self.kazhdan_lusztig_polynomial(u*z,v, constant_term_one=False).shift(z.length()) for z in WOI if (u*z).bruhat_le(v)) + def kazhdan_lusztig_cell(self, w, side='left'): + r""" + Compute the left, right, or two-sided Kazhdan-Lusztig cell containing + the element ``w``. + + This method products in the `C^{\prime}` basis by using the + :class:`IwahoriHeckeAlgebra.CpC` basis. + + INPUT: + + - ``w`` -- an element of self. + + - ``side`` -- string; one of 'left', 'right', or 'both', corresponding + to the kind of cell to compute. + + EXAMPLES: + + Compute some cells in type `B_3`:: + + sage: W = CoxeterGroup('B3', implementation='coxeter3') # optional - coxeter3 + sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 + sage: W.kazhdan_lusztig_cell(s1*s2*s1) # optional - coxeter3 + {[2, 1, 2], [2, 3, 2, 1, 2], [3, 2, 1, 2]} + sage: W.kazhdan_lusztig_cell(s2*s3*s2) # optional - coxeter3 + {[1, 2], [1, 2, 3, 2], [2], [2, 3, 2], [3, 2]} + sage: W.kazhdan_lusztig_cell(s1*s2*s3) # optional - coxeter3 + {[1, 2, 3], [2, 3], [3], [3, 2, 3]} + sage: W.kazhdan_lusztig_cell(s3) # optional - coxeter3 + {[1, 2, 3], [2, 3], [3], [3, 2, 3]} + sage: W.kazhdan_lusztig_cell(s3, side='right') # optional - coxeter3 + {[3], [3, 2], [3, 2, 1], [3, 2, 3]} + sage: W.kazhdan_lusztig_cell(s3, side='both') # optional - coxeter3 + {[1], [1, 2], [1, 2, 3], [1, 2, 3, 2], [1, 2, 3, 2, 1], [2], [2, 1], + [2, 3], [2, 3, 2], [2, 3, 2, 1], [3], [3, 2], [3, 2, 1], [3, 2, 3]} + + Some slightly longer computations in type `B_4`:: + + sage: W = CoxeterGroup('B4', implementation='coxeter3') # optional - coxeter3 + sage: s1,s2,s3,s4 = W.simple_reflections() # optional - coxeter3 + sage: W.kazhdan_lusztig_cell(s1) # long time (4 seconds) # optional - coxeter3 + {[1], + [1, 2, 3, 4, 3, 2, 1], + [2, 1], + [2, 3, 4, 3, 2, 1], + [3, 2, 1], + [3, 4, 3, 2, 1], + [4, 3, 2, 1]} + sage: W.kazhdan_lusztig_cell(s4*s2*s3*s4) # long time (2 seconds) # optional - coxeter3 + {[2, 3, 4, 1, 2, 3, 4], + [3, 4, 1, 2, 3, 4], + [3, 4, 2, 3, 4], + [3, 4, 2, 3, 4, 1, 2, 3, 4], + [4, 1, 2, 3, 4], + [4, 2, 3, 4], + [4, 2, 3, 4, 1, 2, 3, 4], + [4, 3, 4, 1, 2, 3, 4], + [4, 3, 4, 2, 3, 4], + [4, 3, 4, 2, 3, 4, 1, 2, 3, 4]} + """ + from sage.algebras.iwahori_hecke_algebra import IwahoriHeckeAlgebra + + R = LaurentPolynomialRing(ZZ, 'v') + v = R.gen(0) + H = IwahoriHeckeAlgebra(self, v**2) + CpC = H.Cp_Coxeter3() + + w = self(w) + + vertices, edges = {w}, set() + queue = deque([w]) + + while queue: + x = queue.pop() + cp_x = CpC(x) + for s in self.simple_reflections(): + cp_s = CpC(s) + terms = [] + # Determine the Cp basis elements appearing in the product of Cp_s and Cp_w + if side == 'left' or side == 'both': + terms.extend(list(cp_s * cp_x)) + if side == 'right' or side == 'both': + terms.extend(list(cp_x * cp_s)) + for (y, coeff) in terms: + # the result of multiplication will always have coeff != 0 + if y != x: + edges.add((x, y)) + if y not in vertices: + vertices.add(y) + queue.appendleft(y) + + g = DiGraph([list(vertices), list(edges)]) + return set(g.strongly_connected_component_containing_vertex(w)) + + class Element(ElementWrapper): wrapped_class = CoxGroupElement From 8baaf18793a5f9ff37d70dad92a1f942ab91051b Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Mon, 9 Aug 2021 19:17:24 -0600 Subject: [PATCH 075/511] Change kazhdan_lusztig_cell side argument to accept 'two-sided' instead of 'both' --- src/sage/libs/coxeter3/coxeter_group.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 746d6080fdb..5349229d0b1 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -440,8 +440,8 @@ def kazhdan_lusztig_cell(self, w, side='left'): - ``w`` -- an element of self. - - ``side`` -- string; one of 'left', 'right', or 'both', corresponding - to the kind of cell to compute. + - ``side`` -- string (default: ``'left'``); one of 'left', 'right', or + 'two-sided', corresponding to the kind of cell to compute. EXAMPLES: @@ -459,7 +459,7 @@ def kazhdan_lusztig_cell(self, w, side='left'): {[1, 2, 3], [2, 3], [3], [3, 2, 3]} sage: W.kazhdan_lusztig_cell(s3, side='right') # optional - coxeter3 {[3], [3, 2], [3, 2, 1], [3, 2, 3]} - sage: W.kazhdan_lusztig_cell(s3, side='both') # optional - coxeter3 + sage: W.kazhdan_lusztig_cell(s3, side='two-sided') # optional - coxeter3 {[1], [1, 2], [1, 2, 3], [1, 2, 3, 2], [1, 2, 3, 2, 1], [2], [2, 1], [2, 3], [2, 3, 2], [2, 3, 2, 1], [3], [3, 2], [3, 2, 1], [3, 2, 3]} @@ -506,9 +506,9 @@ def kazhdan_lusztig_cell(self, w, side='left'): cp_s = CpC(s) terms = [] # Determine the Cp basis elements appearing in the product of Cp_s and Cp_w - if side == 'left' or side == 'both': + if side == 'left' or side == 'two-sided': terms.extend(list(cp_s * cp_x)) - if side == 'right' or side == 'both': + if side == 'right' or side == 'two-sided': terms.extend(list(cp_x * cp_s)) for (y, coeff) in terms: # the result of multiplication will always have coeff != 0 From 79d843fe1484a951b09ee9eb3c84c93fc74e5ac2 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Mon, 9 Aug 2021 19:18:08 -0600 Subject: [PATCH 076/511] Improve kazhdan_lusztig_cell docstring --- src/sage/libs/coxeter3/coxeter_group.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 5349229d0b1..09970bec27b 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -431,7 +431,8 @@ def parabolic_kazhdan_lusztig_polynomial(self, u, v, J, constant_term_one=True): def kazhdan_lusztig_cell(self, w, side='left'): r""" Compute the left, right, or two-sided Kazhdan-Lusztig cell containing - the element ``w``. + the element ``w``. Computes left cells by default; use the optional + argument ``side`` to specify right or two-sided cells. This method products in the `C^{\prime}` basis by using the :class:`IwahoriHeckeAlgebra.CpC` basis. From 863520c57c6e728eccd4269b82cef7d4e576d932 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Mon, 9 Aug 2021 19:35:34 -0600 Subject: [PATCH 077/511] Add A9 example to class docs --- src/sage/algebras/iwahori_hecke_algebra.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 1d2ed32b93b..b0b6d81daaa 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2074,8 +2074,8 @@ class Cp_Coxeter3(_KLHeckeBasis): sage: CpC(Cp[1,2,1]) # optional - coxeter3 CpC[1,2,1] - Some computations in the ``CpC`` basis; these agree with computations - in the existing ``Cp`` basis:: + Some computations in the ``CpC`` basis; these agree with computations in + the existing ``Cp`` basis:: sage: s1, s2, s3 = W.simple_reflections() # optional - coxeter3 sage: Cp(s1)**2 # optional - coxeter3 @@ -2110,6 +2110,18 @@ class Cp_Coxeter3(_KLHeckeBasis): + (v^-3+3*v^-1+3*v+v^3)*CpC[4,3,4,3,4,1] + (v^-1+v)*CpC[3,4,1,2] + A computation in type `A_9` that seems prohibitively slow for the ``Cp`` + basis:: + + sage: W = CoxeterGroup('A9', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 + sage: CpC = H.Cp_Coxeter3() # optional - coxeter3 + sage: CpC[1,2,1,8,9,8]*CpC[1,2,3,7,8,9] # optional - coxeter3 + (v^-2+2+v^2)*CpC[1,2,1,3,7,8,7,9,8,7] + + (v^-2+2+v^2)*CpC[1,2,1,3,8,9,8,7] + + (v^-3+3*v^-1+3*v+v^3)*CpC[1,2,1,3,8,9,8] + + Below is another example, with the Hecke algebra of type `B_9` in the normalized presentation. The (optional) relabeling command ensures that `m(1,2)=4`, i.e., that the generators 1, 2 form the strong bond in the From c34b92aa952f2892fc0e89f02c76aee3432f9e85 Mon Sep 17 00:00:00 2001 From: Tianyuan Xu Date: Wed, 11 Aug 2021 15:58:49 -0600 Subject: [PATCH 078/511] slight change to doc string for KL cell function --- src/sage/libs/coxeter3/coxeter_group.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 09970bec27b..4f5840b8445 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -434,8 +434,13 @@ def kazhdan_lusztig_cell(self, w, side='left'): the element ``w``. Computes left cells by default; use the optional argument ``side`` to specify right or two-sided cells. - This method products in the `C^{\prime}` basis by using the - :class:`IwahoriHeckeAlgebra.CpC` basis. + Two elements `x,y` of a Coxeter group `W` are said lie in the same left Kazhdan-Lusztig cell if there exist + sequences `x=w_1, w_2, ..., w_k=y` and `y=u_1, u_2, ..., u_l=x` such that for all `1 \leq i < k` and all `1 + \leq j < l`, there exist some Coxeter generators `s,t` for which `C'_{w_{i+1}}` appears in `C'_sC'_{w_i}` + and `C'_{u_{j+1}}` appears in `C'_sC'_{u_j}` in the Hecke algebra of the Coxeter group, where `C'` denotes + the Kazhdan-Lusztig `C^{\prime}`-basis. Right and two-sided Kazhdan-Lusztig cells of `W` are defined + similarly. In this function, we compute products of the form `C_sC_w` using the function + :func:`product_on_basis` of the class :class:`IwahoriHeckeAlgebra.Cp_Coxeter3`. INPUT: @@ -454,8 +459,6 @@ def kazhdan_lusztig_cell(self, w, side='left'): {[2, 1, 2], [2, 3, 2, 1, 2], [3, 2, 1, 2]} sage: W.kazhdan_lusztig_cell(s2*s3*s2) # optional - coxeter3 {[1, 2], [1, 2, 3, 2], [2], [2, 3, 2], [3, 2]} - sage: W.kazhdan_lusztig_cell(s1*s2*s3) # optional - coxeter3 - {[1, 2, 3], [2, 3], [3], [3, 2, 3]} sage: W.kazhdan_lusztig_cell(s3) # optional - coxeter3 {[1, 2, 3], [2, 3], [3], [3, 2, 3]} sage: W.kazhdan_lusztig_cell(s3, side='right') # optional - coxeter3 From 01ce92a7f9cfad0169e2fb3b959b8fe39b7486f1 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Wed, 11 Aug 2021 18:45:33 -0600 Subject: [PATCH 079/511] Remove unused import --- src/sage/algebras/iwahori_hecke_algebra.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index b0b6d81daaa..2cc262a6117 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -37,7 +37,6 @@ from sage.combinat.root_system.coxeter_group import CoxeterGroup from sage.combinat.family import Family from sage.combinat.free_module import CombinatorialFreeModule -from sage.algebras.free_algebra import FreeAlgebra from sage.libs.coxeter3.coxeter_group import CoxeterGroup as Coxeter3Group From 7428c98b5d8c11bb35dbcd6bc2528198de2174be Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Thu, 12 Aug 2021 11:19:52 -0600 Subject: [PATCH 080/511] Trim whitespace / fix pycodestyle errors --- src/sage/algebras/iwahori_hecke_algebra.py | 45 +++++++++++----------- src/sage/libs/coxeter3/coxeter_group.py | 5 +-- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 2cc262a6117..5ef71273363 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -10,8 +10,8 @@ Kazhdan-Lusztig `C` and `C^{\prime}` bases - Chase Meadors, Tianyuan Xu (2021): - Implemented direct computation of products in the - `C^{\prime}` basis using du Cloux's Coxeter3 package + Implemented direct computation of products in the + `C^{\prime}` basis using du Cloux's Coxeter3 package """ # **************************************************************************** @@ -2026,7 +2026,7 @@ class Cp_Coxeter3(_KLHeckeBasis): generator of the Coxeter group and `w` an arbitrary element, are key to this class. The formulas are valid for both the standard and normalized presentation of the Hecke algebra, and they control the products of the - `C^{\prime}_x \cdot C^{\prime}_y` for arbitrary `x,y`. + `C^{\prime}_x \cdot C^{\prime}_y` for arbitrary `x,y`. .. MATH:: C^{\prime}_s \cdot C^{\prime}_w = \begin{cases} (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ @@ -2034,11 +2034,11 @@ class Cp_Coxeter3(_KLHeckeBasis): & \text{if } \ell(sw) = \ell(w)+1. \end{cases} - C^{\prime}_w \cdot C^{\prime}_s = + C^{\prime}_w \cdot C^{\prime}_s = \begin{cases} (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(ws) = \ell(w)-1,\\ - C^{\prime}_{ws}+\sum_{v\leq w, vs \leq v} \mu(v,w)C^{\prime}_v, - & \text{if } \ell(ws) = \ell(w)+1. + C^{\prime}_{ws}+\sum_{v\leq w, vs \leq v} \mu(v,w)C^{\prime}_v, + & \text{if } \ell(ws) = \ell(w)+1. \end{cases} In the above, `\leq` is the Bruhat order on the Coxeter group and @@ -2119,7 +2119,7 @@ class Cp_Coxeter3(_KLHeckeBasis): (v^-2+2+v^2)*CpC[1,2,1,3,7,8,7,9,8,7] + (v^-2+2+v^2)*CpC[1,2,1,3,8,9,8,7] + (v^-3+3*v^-1+3*v+v^3)*CpC[1,2,1,3,8,9,8] - + Below is another example, with the Hecke algebra of type `B_9` in the normalized presentation. The (optional) relabeling command ensures that @@ -2162,7 +2162,7 @@ class Cp_Coxeter3(_KLHeckeBasis): be created first with ``implementation='coxeter3'``. Directly creating a Hecke algebra from its Coxeter type does not work:: - sage: H = IwahoriHeckeAlgebra('A3', v**2) # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra('A3', v**2) # optional - coxeter3 sage: H.Cp_Coxeter3() # optional - coxeter3 Traceback (most recent call last): ... @@ -2172,7 +2172,7 @@ class Cp_Coxeter3(_KLHeckeBasis): with the standard or normalized presentation mentioned before:: sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, QQ(1)) # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, QQ(1)) # optional - coxeter3 sage: H.Cp_Coxeter3() # optional - coxeter3 Traceback (most recent call last): ... @@ -2220,7 +2220,7 @@ def __init__(self, algebra, prefix='CpC'): Invalid construction (bad presentation for Hecke algebra):: sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, QQ(1)) # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, QQ(1)) # optional - coxeter3 sage: H.Cp_Coxeter3() # optional - coxeter3 Traceback (most recent call last): ... @@ -2317,10 +2317,10 @@ def _product_with_generator_on_basis(self, s, w, side='left'): element += x.mu_coefficient(w) * self.monomial(x_elt) longer_word = self._W([s]) * w if side == 'left' else w * self._W([s]) return self.monomial(longer_word) + element - - def _product_with_generator(self, s, x, side='left'): - r""" - Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elements. + + def _product_with_generator(self, s, x, side='left'): + r""" + Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elements. INPUT: @@ -2342,7 +2342,7 @@ def _product_with_generator(self, s, x, side='left'): """ return self.linear_combination((self._product_with_generator_on_basis(s, w, side), coeff) for (w, coeff) in x) - def _decompose_into_generators(self, u): + def _decompose_into_generators(self, u): r""" Decompose `C^{\prime}_u` into a polynomial in the KL generators `C^{\prime}_s`; see the ALGORITHM section of @@ -2373,13 +2373,13 @@ def _decompose_into_generators(self, u): (e.g., CpC_{21} = CpC_2 * CpC_1):: sage: CpC._decompose_into_generators(W([2,1])) # optional - coxeter3 - {(2, 1): 1} + {(2, 1): 1} In more general situations the sum is a polynomial (e.g., CpC_{121}=CpC_1*CpC_2*CpC_1-CpC_1):: sage: CpC._decompose_into_generators(W([1,2,1])) # optional - coxeter3 - {(1,): -1, (1, 2, 1): 1} + {(1,): -1, (1, 2, 1): 1} sage: CpC._decompose_into_generators(W([1,2,3,1,2])) # optional - coxeter3 {(1,): 1, (1, 2, 1): -1, (1, 2, 1, 3, 2): 1, (1, 3, 2): -1} """ @@ -2401,7 +2401,7 @@ def _decompose_into_generators(self, u): v_elt = self._W(v) if v_elt.has_left_descent(s): # Compute mu-coefficient via coxeter3 - sum_term += self.base_ring()(v.mu_coefficient(w)) * self.monomial(v_elt) + sum_term += self.base_ring()(v.mu_coefficient(w)) * self.monomial(v_elt) # recursion: decompose C'_s * C'_w and the lower order terms result = {(s,) + gens: coeff for (gens, coeff) in self._decompose_into_generators(w).items()} @@ -2409,9 +2409,9 @@ def _decompose_into_generators(self, u): # Subtract off each term from sum_term. for (gens, c2) in self._decompose_into_generators(z).items(): result[gens] = result.get(gens, 0) - c1*c2 - + return result - + def product_on_basis(self, w1, w2): r""" Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` in @@ -2420,7 +2420,7 @@ def product_on_basis(self, w1, w2): ALGORITHM: This class computes each product `C^{\prime}_x \cdot C^{\prime}_y` - in two steps as follows. + in two steps as follows. If `\ell(x) \leq \ell(y)`, we first decompose `C^{\prime}_x` into a polynomial in the generators `C^{\prime}_s (s\in S)` and then @@ -2464,7 +2464,7 @@ def product_on_basis(self, w1, w2): (v^-1+v)*CpC[1,2,1,3,2] + (v^-1+v)*CpC[1,2,1] """ # Decomposition: write one of C'_{w1} and C'_{w2} as a polynomial in the - # generators C'_{s}. + # generators C'_{s}. if len(w1) <= len(w2): side = 'left' gen_expression = self._decompose_into_generators(w1) @@ -2483,7 +2483,6 @@ def product_on_basis(self, w1, w2): summand = self._product_with_generator(s, summand, side) result += summand return result - class C(_KLHeckeBasis): r""" diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 4f5840b8445..7c3f0cfd509 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -440,7 +440,7 @@ def kazhdan_lusztig_cell(self, w, side='left'): and `C'_{u_{j+1}}` appears in `C'_sC'_{u_j}` in the Hecke algebra of the Coxeter group, where `C'` denotes the Kazhdan-Lusztig `C^{\prime}`-basis. Right and two-sided Kazhdan-Lusztig cells of `W` are defined similarly. In this function, we compute products of the form `C_sC_w` using the function - :func:`product_on_basis` of the class :class:`IwahoriHeckeAlgebra.Cp_Coxeter3`. + :func:`product_on_basis` of the class :class:`IwahoriHeckeAlgebra.Cp_Coxeter3`. INPUT: @@ -521,11 +521,10 @@ def kazhdan_lusztig_cell(self, w, side='left'): if y not in vertices: vertices.add(y) queue.appendleft(y) - + g = DiGraph([list(vertices), list(edges)]) return set(g.strongly_connected_component_containing_vertex(w)) - class Element(ElementWrapper): wrapped_class = CoxGroupElement From 5f1ab3e42c082cb22f7faba60c319a67efa1923b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 13 Aug 2021 12:12:00 +1000 Subject: [PATCH 081/511] Added example from ticket and coxeter3 optional marker for doctests. --- src/sage/libs/coxeter3/coxeter_group.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index d0c13f12a11..38fe82451ff 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -171,10 +171,10 @@ def from_reduced_word(self, w): EXAMPLES:: - sage: W = CoxeterGroup(['A', 3], implementation='coxeter3') - sage: W.from_reduced_word([1, 3]) + sage: W = CoxeterGroup(['A', 3], implementation='coxeter3') # optional - coxeter3 + sage: W.from_reduced_word([1, 3]) # optional - coxeter3 [1, 3] - sage: W.from_reduced_word([3, 1]) + sage: W.from_reduced_word([3, 1]) # optional - coxeter3 [1, 3] """ return self.element_class(self, w) @@ -433,6 +433,17 @@ def __init__(self, parent, x): sage: W = CoxeterGroup(['A', 3], implementation='coxeter3') # optional - coxeter3 sage: W([2,1,2]) # optional - coxeter3 [1, 2, 1] + + Check that :trac:`32266` is fixed:: + + sage: A3 = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: s1,s2,s3 = A3.simple_reflections() # optional - coxeter3 + sage: s1*s3 # optional - coxeter3 + [1, 3] + sage: s3*s1 # optional - coxeter3 + [1, 3] + sage: s3*s1 == s1*s3 # optional - coxeter3 + True """ if not isinstance(x, CoxGroupElement): x = CoxGroupElement(parent._coxgroup, x).reduced() From 6492ab1b9433b53eede0b4c640853d208e5b4191 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 13 Aug 2021 09:35:00 -0600 Subject: [PATCH 082/511] Remove basis coercions in prep for integrating into the Cp class --- src/sage/algebras/iwahori_hecke_algebra.py | 145 ++------------------- 1 file changed, 13 insertions(+), 132 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 5ef71273363..b20c84303e7 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1580,30 +1580,6 @@ def to_Cp_basis(self, w): generic_T = H._generic_iwahori_hecke_algebra.T() return generic_T.to_Cp_basis(w).specialize_to(H) - def to_Cp_Coxeter3_basis(self, w): - r""" - Return `T_w` as a linear combination of `C^{\prime}`-basis elements, - using the ``Cp_Coxeter3`` basis. - - EXAMPLES:: - - sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(A3, v**2); T=H.T(); CpC=H.Cp_Coxeter3() # optional - coxeter3 - sage: s1,s2,s3 = A3.simple_reflections() # optional - coxeter3 - sage: T.to_Cp_Coxeter3_basis(s1) # optional - coxeter3 - v*CpC[1] - 1 - sage: CpC(T(s1)) # optional - coxeter3 - v*CpC[1] - 1 - sage: CpC(T[1] + 1) # optional - coxeter3 - v*CpC[1] - sage: CpC(T[1,2] + T[1] + T[2] + 1) # optional - coxeter3 - v^2*CpC[1,2] - """ - H = self.realization_of() - generic_T = H._generic_iwahori_hecke_algebra.T() - return generic_T.to_Cp_Coxeter3_basis(w).specialize_to(H) - def bar_on_basis(self, w): """ Return the bar involution of `T_w`, which is `T^{-1}_{w^-1}`. @@ -1955,26 +1931,6 @@ class Cp(_KLHeckeBasis): """ _basis_name = 'Cp' # this is used, for example, by specialize_to and is the default prefix - def to_Cp_Coxeter3_basis(self, w): - r""" - Return ``self[w]`` as an element of the ``Cp_Coxeter3`` basis. This - transformation is trivial since both bases are implementations of - the `C^{\prime}` basis. - - EXAMPLES:: - - sage: R. = LaurentPolynomialRing(ZZ, 'v') - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') - sage: H = IwahoriHeckeAlgebra(A3, v**2); Cp = H.Cp(); CpC=H.Cp_Coxeter3() - sage: Cp.to_Cp_Coxeter3_basis(A3([1,2])) - CpC[1,2] - sage: CpC(Cp[1,2]) - CpC[1,2] - """ - A = self.realization_of() - CpC = A.Cp_Coxeter3() - return CpC.monomial(w) - def hash_involution_on_basis(self, w): r""" Return the effect of applying the hash involution to the basis @@ -3053,62 +3009,11 @@ class T(IwahoriHeckeAlgebra.T): r""" The `T`-basis for the generic Iwahori-Hecke algebra. """ - def _to_Cp_basis(self, w, Cp): - r""" - Return `T_w` as a linear combination of `C^{\prime}`-basis elements, - using either the ``Cp`` basis or the ``Cp_Coxeter3`` implementation. - - INPUT: - - - ``w`` -- a word in self.coxeter_group() - - - ``Cp`` -- the target `C^{\prime}` basis to use; either ``Cp`` or - ``Cp_Coxeter3`` - - EXAMPLES: - - :: - - sage: A3 = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard(A3) # optional - coxeter3 - sage: s1,s2,s3 = A3.simple_reflections() # optional - coxeter3 - sage: T = H.T(); CpC = H.Cp_Coxeter3() # optional - coxeter3 - sage: T._to_Cp_basis(s1, CpC) # optional - coxeter3 - v*CpC[1] + (-u^-1*v^2) - sage: CpC(T(s1)) # optional - coxeter3 - v*CpC[1] + (-u^-1*v^2) - - :: - - sage: A3 = CoxeterGroup('A3') - sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard(A3) - sage: s1,s2,s3 = A3.simple_reflections() - sage: T = H.T(); Cp = H.Cp() - sage: T._to_Cp_basis(s1, Cp) - v*Cp[1] + (-u^-1*v^2) - sage: Cp(T(s1)) - v*Cp[1] + (-u^-1*v^2) - """ - A = self.realization_of() - # Cp = A.Cp() if not use_Cp_Coxeter3 else A.Cp_Coxeter3() - - if w == A._W.one(): # the identity element of the Coxeter group - return Cp.one() - - T0 = self.zero() - inp = self.monomial(w) - result = Cp.zero() - while inp != T0: - (x, c) = inp.trailing_item(key=sorting_key) - inp = inp - c * A._root**x.length() * Cp.to_T_basis(x) - result = result + c * A._root**x.length() * Cp.monomial(x) - - return result - @cached_method def to_Cp_basis(self, w): r""" - Return `T_w` as a linear combination of `C^{\prime}`-basis elements + Return `T_w` as a linear combination of `C^{\prime}`-basis + elements. EXAMPLES:: @@ -3130,36 +3035,20 @@ def to_Cp_basis(self, w): + (u^-2*v^5)*Cp[1] + (u^-2*v^5)*Cp[2] + (-u^-3*v^6) """ A = self.realization_of() - return self._to_Cp_basis(w, A.Cp()) + Cp = A.Cp() - @cached_method - def to_Cp_Coxeter3_basis(self, w): - r""" - Return `T_w` as a linear combination of `C^{\prime}`-basis elements, - using the ``Cp_Coxeter3`` implementation. + if w == A._W.one(): # the identity element of the Coxeter group + return Cp.one() - EXAMPLES:: + T0 = self.zero() + inp = self.monomial(w) + result = Cp.zero() + while inp != T0: + (x, c) = inp.trailing_item(key=sorting_key) + inp = inp - c * A._root**x.length() * Cp.to_T_basis(x) + result = result + c * A._root**x.length() * Cp.monomial(x) - sage: A2 = CoxeterGroup('A2', implementation='coxeter3') # optional - coxeter3 - sage: H = sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra_nonstandard(A2) # optional - coxeter3 - sage: s1,s2 = H.coxeter_group().simple_reflections() # optional - coxeter3 - sage: T = H.T() # optional - coxeter3 - sage: CpC = H.Cp_Coxeter3() # optional - coxeter3 - sage: T.to_Cp_Coxeter3_basis(s1) # optional - coxeter3 - v*CpC[1] + (-u^-1*v^2) - sage: CpC(T(s1)) # optional - coxeter3 - v*CpC[1] + (-u^-1*v^2) - sage: CpC(T(s1)+1) # optional - coxeter3 - v*CpC[1] + (-u^-1*v^2+1) - sage: CpC(T(s1*s2)+T(s1)+T(s2)+1) # optional - coxeter3 - v^2*CpC[1,2] + (-u^-1*v^3+v)*CpC[1] + (-u^-1*v^3+v)*CpC[2] - + (u^-2*v^4-2*u^-1*v^2+1) - sage: CpC(T(s1*s2*s1)) # optional - coxeter3 - v^3*CpC[1,2,1] + (-u^-1*v^4)*CpC[1,2] + (-u^-1*v^4)*CpC[2,1] - + (u^-2*v^5)*CpC[1] + (u^-2*v^5)*CpC[2] + (-u^-3*v^6) - """ - A = self.realization_of() - return self._to_Cp_basis(w, A.Cp_Coxeter3()) + return result @cached_method def to_C_basis(self, w): @@ -3272,14 +3161,6 @@ def key_func(x): C_prime = Cp - class Cp_Coxeter3(IwahoriHeckeAlgebra.Cp_Coxeter3): - @cached_method - def to_T_basis(self, w): - A = self.realization_of() - Cp = A.Cp() - T = A.T() - return T(Cp.monomial(w)) - class C(IwahoriHeckeAlgebra.C): r""" The Kazhdan-Lusztig `C`-basis for the generic Iwahori-Hecke algebra. From aa63aaa62e6dc457ac0db7616592d7d0ca15f64d Mon Sep 17 00:00:00 2001 From: bhutz Date: Fri, 13 Aug 2021 10:46:11 -0500 Subject: [PATCH 083/511] 31994: removed duplicated import --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index d2bc3d22592..0eb9aada345 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -52,7 +52,7 @@ class initialization directly. # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.misc import is_prime, moebius +from sage.arith.misc import is_prime from sage.calculus.functions import jacobian from sage.categories.fields import Fields from sage.categories.function_fields import FunctionFields From ac2c397d65bc42da10ece4826d5707879d206543 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 13 Aug 2021 10:10:57 -0600 Subject: [PATCH 084/511] Draft implementation of the functionality integrated with Cp --- src/sage/algebras/iwahori_hecke_algebra.py | 323 +++------------------ 1 file changed, 36 insertions(+), 287 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index b20c84303e7..a349a709e5a 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1931,6 +1931,28 @@ class Cp(_KLHeckeBasis): """ _basis_name = 'Cp' # this is used, for example, by specialize_to and is the default prefix + def __init__(self, IHAlgebra, prefix=None): + r""" + TODO: docstring + """ + super().__init__(IHAlgebra, prefix) + + v = IHAlgebra.base_ring().gen(0) + parameters = {IHAlgebra.q1(), IHAlgebra.q2()} + if v != IHAlgebra.base_ring().one() and (parameters == {v**2, -1} or parameters == {v, -1/v}): + # The following quantity delta is used in product computations. + # To use v+~v as its value we need the standard or normalized presentations of the Hecke algebra. + self.delta = v + ~v + + try: + from sage.libs.coxeter3.coxeter_group import CoxeterGroup as Coxeter3Group + if isinstance(IHAlgebra._W, Coxeter3Group): + self._W_Coxeter3 = IHAlgebra._W + else: + self._W_Coxeter3 = CoxeterGroup(IHAlgebra._W.coxeter_type(), implementation='coxeter3') + except ImportError: + pass + def hash_involution_on_basis(self, w): r""" Return the effect of applying the hash involution to the basis @@ -1952,288 +1974,6 @@ def hash_involution_on_basis(self, w): """ return (-1)**w.length() * self(self.realization_of().C().monomial(w)) - C_prime = Cp - - class Cp_Coxeter3(_KLHeckeBasis): - r""" - Directly compute products in the `C^{\prime}`-basis by using du Cloux's - Coxeter3 package. - - To use this class, the Hecke algebra needs to be created in the - "standard" presentation where `\{q_1,q_2\} = \{v^2,1\}` as sets or the - "normalized" presentations where `\{q_1,q_2\} = \{v,-v^{-1}\}` as sets. - The Hecke algebra also needs to be created from a Coxeter group defined - using the 'coxeter3' implementation, because this class designates the - computation of certain important coefficients to 'coxeter3'. - - Expanding products of the form `C^{\prime}_x \cdot C^{\prime}_y` in the - `C^{\prime}`-basis is useful for computing Kazhdan-Lusztig cells of - Coxeter systems and the corresponding cell modules of Iwahori-Hecke - algebras. The emphasis of this class is to compute such products more - directly in the `C^{\prime}`-basis, as opposed to converting the - `C^{\prime}`-basis to the `T`-basis, calculating the product in the - `T`-basis, and converting the results back to the `C^{\prime}`-basis. - The latter approach is used in the function ``_Basis.product_on_basis`` - of for the :class:`IwahoriHeckeAlgebra.Cp` basis. The direct method - implemented here significantly speeds up the product computations. - - The following formulas for products of the forms `C^{\prime}_s \cdot - C^{\prime}_w` and `C^{\prime}_w \cdot C^{\prime}_s`, where `s` is a - generator of the Coxeter group and `w` an arbitrary element, are key to - this class. The formulas are valid for both the standard and normalized - presentation of the Hecke algebra, and they control the products of the - `C^{\prime}_x \cdot C^{\prime}_y` for arbitrary `x,y`. - - .. MATH:: C^{\prime}_s \cdot C^{\prime}_w = \begin{cases} - (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ - C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, - & \text{if } \ell(sw) = - \ell(w)+1. \end{cases} - - C^{\prime}_w \cdot C^{\prime}_s = - \begin{cases} - (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(ws) = \ell(w)-1,\\ - C^{\prime}_{ws}+\sum_{v\leq w, vs \leq v} \mu(v,w)C^{\prime}_v, - & \text{if } \ell(ws) = \ell(w)+1. - \end{cases} - - In the above, `\leq` is the Bruhat order on the Coxeter group and - `\mu(v,w)` is the "leading coefficient of Kazhdan-Lusztig polynomials"; - see [KL1979]_ and [Lus2013]_ for more details. The method designates the - computation of the `\mu`-coefficients to Sage's interface to Fokko du - Cloux's ``coxeter3`` package, which is why the method requires the - creation of the Coxeter group using the 'coxeter3' implementation. - - The multiplication algorithm is described in detail in - :func:`product_on_basis`. - - EXAMPLES: - - To create the basis, define the Coxeter group with - ``implementation='coxeter3'`` and the Hecke algebra with the standard or - normalized presentation:: - - sage: R. = LaurentPolynomialRing(ZZ) # optional - coxeter3 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 - sage: CpC = H.Cp_Coxeter3() # optional - coxeter3 - - The new basis here (``CpC``) and ``Cp`` basis are both implementations - of the the `C^{\prime}` basis. The only difference between the - implementations lies in their different methods for computing products. - The conversion between ``CpC`` and ``Cp`` is trivial:: - - sage: Cp = H.Cp() # optional - coxeter3 - sage: Cp(CpC[1,2,1]) # optional - coxeter3 - Cp[1,2,1] - sage: CpC(Cp[1,2,1]) # optional - coxeter3 - CpC[1,2,1] - - Some computations in the ``CpC`` basis; these agree with computations in - the existing ``Cp`` basis:: - - sage: s1, s2, s3 = W.simple_reflections() # optional - coxeter3 - sage: Cp(s1)**2 # optional - coxeter3 - (v^-1+v)*Cp[1] - sage: CpC(s1)**2 # optional - coxeter3 - (v^-1+v)*CpC[1] - sage: Cp(s1)*Cp(s2)*Cp(s1) # optional - coxeter3 - Cp[1,2,1] + Cp[1] - sage: CpC(s1)*CpC(s2)*CpC(s1) # optional - coxeter3 - CpC[1,2,1] + CpC[1] - sage: Cp[1]*Cp[2]*Cp[3]*Cp[1]*Cp[2] # optional - coxeter3 - Cp[1,2,1,3,2] + Cp[1,2,1] + Cp[1,3,2] - sage: CpC[1]*CpC[2]*CpC[3]*CpC[1]*CpC[2] # optional - coxeter3 - CpC[1,2,1,3,2] + CpC[1,2,1] + CpC[1,3,2] - - A computation in type `H_4` that is significantly faster in the ``CpC`` - implementation than in the existing ``Cp`` basis:: - - sage: W = CoxeterGroup('H4', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 - sage: Cp = H.Cp(); CpC = H.Cp_Coxeter3() # optional - coxeter3 - sage: Cp[3,4,3]*Cp[3,4,3,4]*Cp[1,2,3,4] # long time (5 seconds) # optional - coxeter3 - (v^-2+2+v^2)*Cp[4,3,4,3,4,1,2,3,4] - + (v^-2+2+v^2)*Cp[4,3,4,3,4,1,2] - + (v^-1+v)*Cp[3,4,1,2,3,4] - + (v^-3+3*v^-1+3*v+v^3)*Cp[4,3,4,3,4,1] - + (v^-1+v)*Cp[3,4,1,2] - sage: CpC[3,4,3]*CpC[3,4,3,4]*CpC[1,2,3,4] # optional - coxeter3 - (v^-2+2+v^2)*CpC[4,3,4,3,4,1,2,3,4] - + (v^-2+2+v^2)*CpC[4,3,4,3,4,1,2] - + (v^-1+v)*CpC[3,4,1,2,3,4] - + (v^-3+3*v^-1+3*v+v^3)*CpC[4,3,4,3,4,1] - + (v^-1+v)*CpC[3,4,1,2] - - A computation in type `A_9` that seems prohibitively slow for the ``Cp`` - basis:: - - sage: W = CoxeterGroup('A9', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 - sage: CpC = H.Cp_Coxeter3() # optional - coxeter3 - sage: CpC[1,2,1,8,9,8]*CpC[1,2,3,7,8,9] # optional - coxeter3 - (v^-2+2+v^2)*CpC[1,2,1,3,7,8,7,9,8,7] - + (v^-2+2+v^2)*CpC[1,2,1,3,8,9,8,7] - + (v^-3+3*v^-1+3*v+v^3)*CpC[1,2,1,3,8,9,8] - - - Below is another example, with the Hecke algebra of type `B_9` in the - normalized presentation. The (optional) relabeling command ensures that - `m(1,2)=4`, i.e., that the generators 1, 2 form the strong bond in the - Dynkin diagram. The final two examples are calculations that are quick - in this implementation but seem prohibitively slow for the ``Cp`` - basis:: - - sage: B9 = CoxeterType(['B', 9]) - sage: B9 = B9.relabel({ i: 9-i+1 for i in range(1, 10) }) # optional - coxeter3 - sage: W = CoxeterGroup(B9, implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v, -1/v) # optional - coxeter3 - sage: CpC, Cp = H.Cp_Coxeter3(), H.Cp() # optional - coxeter3 - sage: s = W.simple_reflections() # optional - coxeter3 - sage: Cp(s[1]*s[2]*s[1]*s[2]) # optional - coxeter3 - Cp[1,2,1,2] - sage: Cp[3,2,3,4,5] * Cp[2,3] # optional - coxeter3 - (v^-1+v)*Cp[2,3,2,4,3,5] + (v^-1+v)*Cp[2,3,2,5] - sage: CpC[3,2,3,4,5] * CpC[2,3] # optional - coxeter3 - (v^-1+v)*CpC[2,3,2,4,3,5] + (v^-1+v)*CpC[2,3,2,5] - sage: CpC[9,5,6,7,8,9,2,3,4,5,6,7,8,9] * CpC[9,8,7,6] # optional - coxeter3 - (v^-3+3*v^-1+3*v+v^3)*CpC[2,3,4,5,4,6,5,7,6,8,7,9,8,7,6] - sage: CpC[1,5,4,3,2,1,8,7,6,5,4,3,2,1] * CpC[1,2,3,4] # long time (4 seconds) # optional - coxeter3 - (v^-1+v)*CpC[1,5,4,3,2,1,8,7,6,5,4,3,2,1,2,3,4] - + (v^-1+v)*CpC[1,2,1,5,4,3,2,1,2,3,8,7,6,5,4] - + (v^-1+v)*CpC[1,3,2,1,5,4,3,2,1,2,3,4,8,7,6] - + (v^-1+v)*CpC[1,4,3,2,1,5,4,3,2,1,2,3,4,8,7] - + (v^-1+v)*CpC[1,5,4,3,2,1,2,3,8,7,6,5,4,3,2] - + (v^-1+v)*CpC[1,2,5,4,3,2,1,8,7,6,5,4,3] - + (v^-1+v)*CpC[1,2,5,4,3,2,8,7,6,5,4,3,2] - + (v^-1+v)*CpC[1,2,3,2,5,4,3,2,8,7,6] - + (v^-1+v)*CpC[1,2,4,3,2,5,4,3,2,8,7] - + (v^-1+v)*CpC[1,2,5,4,3,2,8,7,6,5,4] - + (v^-1+v)*CpC[1,5,4,3,2,1,8,7,6,5,4] - + (v^-1+v)*CpC[1,5,4,3,8,7,6,5,4,3,2] - + (v^-1+v)*CpC[1,3,5,4,3,2,8,7,6] - + (v^-1+v)*CpC[1,4,3,5,4,3,2,8,7] - - Note that to use the CpC basis for a Hecke algebra, a Coxeter group must - be created first with ``implementation='coxeter3'``. Directly creating a - Hecke algebra from its Coxeter type does not work:: - - sage: H = IwahoriHeckeAlgebra('A3', v**2) # optional - coxeter3 - sage: H.Cp_Coxeter3() # optional - coxeter3 - Traceback (most recent call last): - ... - ValueError: algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis - - With the Coxeter group created first, the Hecke algebra must be defined - with the standard or normalized presentation mentioned before:: - - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, QQ(1)) # optional - coxeter3 - sage: H.Cp_Coxeter3() # optional - coxeter3 - Traceback (most recent call last): - ... - ValueError: the Cp_Coxeter3 basis is only supported in a Hecke - algebra with the standard or normalized presentations (i.e., need - {q_1,q_2} = {v^2,1} or {q_1,q_2} = {v,-v^-1} as sets) - - .. TODO:: - - Accommodate generic presentations of the Hecke algebra other than - the standard and normalized ones. - - Use analogs of the formulas for `C^{\prime}_s C^{\prime}_w` and - `C^{\prime}_w C^{\prime}_s` to implement `C^{\prime}`-products - in the multi-parameter Iwahori-Hecke algebra; see Section 6 of - [Lus2013]_. - """ - _basis_name = 'Cp_Coxeter3' - - def __init__(self, algebra, prefix='CpC'): - r""" - Initialize the Cp_Coxeter3 Kazhdan-Lusztig basis of the - Iwahori-Hecke algebra ``algebra''. - - EXAMPLES: - - Valid construction:: - - sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 - sage: CpC = H.Cp_Coxeter3() # optional - coxeter3 - - - Invalid construction (not creating a Coxeter group with - 'coxeter3'):: - - sage: H = IwahoriHeckeAlgebra('A3', v**2) # optional - coxeter3 - sage: H.Cp_Coxeter3() # optional - coxeter3 - Traceback (most recent call last): - ... - ValueError: algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis - - - Invalid construction (bad presentation for Hecke algebra):: - - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, QQ(1)) # optional - coxeter3 - sage: H.Cp_Coxeter3() # optional - coxeter3 - Traceback (most recent call last): - ... - ValueError: the Cp_Coxeter3 basis is only supported in a Hecke - algebra with the standard or normalized presentations (i.e., need - {q_1,q_2} = {v^2,1} or {q_1,q_2} = {v,-v^-1} as sets) - """ - if not isinstance(algebra._W, Coxeter3Group): - raise ValueError('algebra must be initialized with a coxeter3-implemented Coxeter group to use the Cp_Coxeter3 basis') - - super(IwahoriHeckeAlgebra.Cp_Coxeter3, self).__init__(algebra, prefix) - - self._W = algebra._W - - v = algebra.base_ring().gen(0) - - parameters = {algebra.q1(), algebra.q2()} - if v != algebra.base_ring().one() and (parameters == {v**2, -1} or parameters == {v, -1/v}): - # The following quantity delta is used in product computations. - # To use v+~v as its value we need the standard or normalized presentations of the Hecke algebra. - self.delta = v + ~v - else: - if not algebra._is_generic: - # If this algebra is generic, it's only being used to coerce to the T basis, not perform computations - raise ValueError('the Cp_Coxeter3 basis is only supported in a Hecke algebra with the standard or normalized \ -presentations (i.e., need {q_1,q_2} = {v^2,1} or {q_1,q_2} = {v,-v^-1} as sets)') - - # Define the (trivial) conversion to the other Cp basis - self.module_morphism(self.to_Cp_basis, codomain=algebra.Cp(), category=self.category() - ).register_as_coercion() - - # ...and from the other Cp basis to the Cp_Coxeter3 basis - Cp = algebra.Cp() - Cp.module_morphism(Cp.to_Cp_Coxeter3_basis, codomain=self, category=self.category()).register_as_coercion() - - def to_Cp_basis(self, w): - r""" - Return the element ``self[w]`` in the ``Cp``-basis. This - transformation is trivial as both bases are implementations of the - `C^{\prime}` basis. - - EXAMPLES:: - - sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 - sage: Cp=H.Cp(); CpC=H.Cp_Coxeter3() # optional - coxeter3 - sage: s1, s2, s3 = W.simple_reflections() # optional - coxeter3 - sage: CpC.to_Cp_basis(s1*s2) # optional - coxeter3 - Cp[1,2] - sage: CpC.to_Cp_basis(s1*s2*s1) # optional - coxeter3 - Cp[1,2,1] - """ - A = self.realization_of() - Cp = A.Cp() - return Cp.monomial(w) - def _product_with_generator_on_basis(self, s, w, side='left'): r""" Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting @@ -2264,14 +2004,14 @@ def _product_with_generator_on_basis(self, s, w, side='left'): return self.delta * self.monomial(w) else: element = self(0) - between = self._W.bruhat_interval([], w) + between = self._W_Coxeter3.bruhat_interval([], w) for x in between: # Get (coxeter3-implemented) group element corresponding to x - x_elt = self._W(x) + x_elt = self._W_Coxeter3(x) if x_elt.has_descent(s, side=side): # Compute mu-coefficient via coxeter3 element += x.mu_coefficient(w) * self.monomial(x_elt) - longer_word = self._W([s]) * w if side == 'left' else w * self._W([s]) + longer_word = self._W_Coxeter3([s]) * w if side == 'left' else w * self._W_Coxeter3([s]) return self.monomial(longer_word) + element def _product_with_generator(self, s, x, side='left'): @@ -2351,10 +2091,10 @@ def _decompose_into_generators(self, u): # get the lower order terms ("sum_term") sum_term = self(0) - between = self._W.bruhat_interval([], w) + between = self._W_Coxeter3.bruhat_interval([], w) for v in between: # Get (coxeter3-implemented) group element corresponding to v - v_elt = self._W(v) + v_elt = self._W_Coxeter3(v) if v_elt.has_left_descent(s): # Compute mu-coefficient via coxeter3 sum_term += self.base_ring()(v.mu_coefficient(w)) * self.monomial(v_elt) @@ -2370,6 +2110,7 @@ def _decompose_into_generators(self, u): def product_on_basis(self, w1, w2): r""" + TODO: Mention fallback and conditions to use this algorithm. Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` in the `C^{\prime}`-basis. @@ -2419,6 +2160,12 @@ def product_on_basis(self, w1, w2): sage: CpC.product_on_basis(W([1,2,1]), W([3,1,2])) # optional - coxeter3 (v^-1+v)*CpC[1,2,1,3,2] + (v^-1+v)*CpC[1,2,1] """ + if self.delta is None or self._W_Coxeter3 is None: + return super().product_on_basis(w1, w2) + + w1 = self._W_Coxeter3.from_reduced_word(w1.reduced_word()) + w2 = self._W_Coxeter3.from_reduced_word(w2.reduced_word()) + # Decomposition: write one of C'_{w1} and C'_{w2} as a polynomial in the # generators C'_{s}. if len(w1) <= len(w2): @@ -2440,6 +2187,8 @@ def product_on_basis(self, w1, w2): result += summand return result + C_prime = Cp + class C(_KLHeckeBasis): r""" The Kazhdan-Lusztig `C`-basis of Iwahori-Hecke algebra. From d1663cbcf64be32e07044f8b7a12c76b9e3463ff Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 13 Aug 2021 10:50:35 -0600 Subject: [PATCH 085/511] Implement conversion to/from original underlying Coxeter group in product_on_basis --- src/sage/algebras/iwahori_hecke_algebra.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index a349a709e5a..eb851a76c1e 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1937,6 +1937,9 @@ def __init__(self, IHAlgebra, prefix=None): """ super().__init__(IHAlgebra, prefix) + self.delta = None + self._W_Coxeter3 = None + v = IHAlgebra.base_ring().gen(0) parameters = {IHAlgebra.q1(), IHAlgebra.q2()} if v != IHAlgebra.base_ring().one() and (parameters == {v**2, -1} or parameters == {v, -1/v}): @@ -2161,10 +2164,15 @@ def product_on_basis(self, w1, w2): (v^-1+v)*CpC[1,2,1,3,2] + (v^-1+v)*CpC[1,2,1] """ if self.delta is None or self._W_Coxeter3 is None: + # We do not meet the conditions to use the direct product + # algorithm; fall back to conversion to/from the T-basis. return super().product_on_basis(w1, w2) - w1 = self._W_Coxeter3.from_reduced_word(w1.reduced_word()) - w2 = self._W_Coxeter3.from_reduced_word(w2.reduced_word()) + # If self._W_Coxeter3 is not the underlying Coxeter group, we need + # to convert elements first for this algorithm. + if (self._W_Coxeter3 != self.realization_of()._W): + w1 = self._W_Coxeter3.from_reduced_word(w1.reduced_word()) + w2 = self._W_Coxeter3.from_reduced_word(w2.reduced_word()) # Decomposition: write one of C'_{w1} and C'_{w2} as a polynomial in the # generators C'_{s}. @@ -2185,6 +2193,15 @@ def product_on_basis(self, w1, w2): for s in p_list: summand = self._product_with_generator(s, summand, side) result += summand + + # Again, if self._W_Coxeter3 is not the underlying Coxeter group, + # we need to convert result. Specifically, make sure basis elements + # appearing therein are actually indexed by elements of the original + # underlying Coxeter group. + if (self._W_Coxeter3 != self.realization_of()._W): + _W = self.realization_of()._W + result = self.linear_combination((self(_W.from_reduced_word(w.reduced_word())), c) for (w, c) in result) + return result C_prime = Cp From 1e47c60c85304fd8d9410cb8b7871e70b95e624f Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 13 Aug 2021 11:01:28 -0600 Subject: [PATCH 086/511] Fix doctests for product_on_basis and helper methods --- src/sage/algebras/iwahori_hecke_algebra.py | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index eb851a76c1e..23b987476be 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1994,13 +1994,13 @@ def _product_with_generator_on_basis(self, s, w, side='left'): sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() # optional - coxeter3 - sage: CpC._product_with_generator_on_basis(1, W([2,1]), 'left') # optional - coxeter3 - CpC[1,2,1] + CpC[1] - sage: CpC._product_with_generator_on_basis(1, W([2,1]), 'right') # optional - coxeter3 - (v^-1+v)*CpC[2,1] - sage: CpC._product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') # optional - coxeter3 - CpC[1,2,1,3,2,1] + CpC[1,2,3,2] + CpC[1,3,2,1] + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 + sage: Cp._product_with_generator_on_basis(1, W([2,1]), 'left') # optional - coxeter3 + Cp[1,2,1] + Cp[1] + sage: Cp._product_with_generator_on_basis(1, W([2,1]), 'right') # optional - coxeter3 + (v^-1+v)*Cp[2,1] + sage: Cp._product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') # optional - coxeter3 + Cp[1,2,1,3,2,1] + Cp[1,2,3,2] + Cp[1,3,2,1] """ # use the product formula described in the class' documentation if w.has_descent(s, side=side): @@ -2033,11 +2033,11 @@ def _product_with_generator(self, s, x, side='left'): sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() # optional - coxeter3 - sage: CpC._product_with_generator(1, CpC[1]+CpC[2], 'left') # optional - coxeter3 - CpC[1,2] + (v^-1+v)*CpC[1] - sage: CpC._product_with_generator(1, CpC[1]+CpC[2], 'right') # optional - coxeter3 - CpC[2,1] + (v^-1+v)*CpC[1] + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 + sage: Cp._product_with_generator(1, Cp[1]+Cp[2], 'left') # optional - coxeter3 + Cp[1,2] + (v^-1+v)*Cp[1] + sage: Cp._product_with_generator(1, Cp[1]+Cp[2], 'right') # optional - coxeter3 + Cp[2,1] + (v^-1+v)*Cp[1] """ return self.linear_combination((self._product_with_generator_on_basis(s, w, side), coeff) for (w, coeff) in x) @@ -2061,25 +2061,25 @@ def _decompose_into_generators(self, u): sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 When `u` is itself a generator `s`, the decomposition is trivial:: - sage: CpC._decompose_into_generators(W([1])) # optional - coxeter3 + sage: Cp._decompose_into_generators(W([1])) # optional - coxeter3 {(1,): 1} Another example, where `C^{\prime}_u` happens to be a monomial (e.g., CpC_{21} = CpC_2 * CpC_1):: - sage: CpC._decompose_into_generators(W([2,1])) # optional - coxeter3 + sage: Cp._decompose_into_generators(W([2,1])) # optional - coxeter3 {(2, 1): 1} In more general situations the sum is a polynomial (e.g., CpC_{121}=CpC_1*CpC_2*CpC_1-CpC_1):: - sage: CpC._decompose_into_generators(W([1,2,1])) # optional - coxeter3 + sage: Cp._decompose_into_generators(W([1,2,1])) # optional - coxeter3 {(1,): -1, (1, 2, 1): 1} - sage: CpC._decompose_into_generators(W([1,2,3,1,2])) # optional - coxeter3 + sage: Cp._decompose_into_generators(W([1,2,3,1,2])) # optional - coxeter3 {(1,): 1, (1, 2, 1): -1, (1, 2, 1, 3, 2): 1, (1, 3, 2): -1} """ # l(y) = 0 or 1 @@ -2157,11 +2157,11 @@ def product_on_basis(self, w1, w2): sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2); CpC=H.Cp_Coxeter3() # optional - coxeter3 - sage: CpC.product_on_basis(W([1,2,1]), W([3,1])) # optional - coxeter3 - (v^-1+v)*CpC[1,2,1,3] - sage: CpC.product_on_basis(W([1,2,1]), W([3,1,2])) # optional - coxeter3 - (v^-1+v)*CpC[1,2,1,3,2] + (v^-1+v)*CpC[1,2,1] + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 + sage: Cp.product_on_basis(W([1,2,1]), W([3,1])) # optional - coxeter3 + (v^-1+v)*Cp[1,2,1,3] + sage: Cp.product_on_basis(W([1,2,1]), W([3,1,2])) # optional - coxeter3 + (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] """ if self.delta is None or self._W_Coxeter3 is None: # We do not meet the conditions to use the direct product From 58b92a1a9b501efc443d524956411d2d2afa8aa8 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 13 Aug 2021 15:39:33 -0600 Subject: [PATCH 087/511] Documentation --- src/sage/algebras/iwahori_hecke_algebra.py | 53 ++++++++++++++++++++-- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 23b987476be..80cbbdd843b 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1882,6 +1882,16 @@ class Cp(_KLHeckeBasis): See [KL1979]_ for more details. + If the optional ``coxeter3`` package is available, and the + Iwahori--Hecke algebra was initialized in the "standard" presentation + (where `\{q_1,q_2\} = \{v^2,1\}` as sets) or the "normalized" + presentation (where `\{q_1,q_2\} = \{v,-v^{-1}\}`), a performant direct + algorithm is available to compute products in the `C^{\prime}` basis, + documented in :func:`product_on_basis`. If these conditions are not met, + the class will fall back to the default implementation which computes + products by converting elements to the `T`-basis and back. This default + implementation may be prohibitively slow for complex calculations. + EXAMPLES:: sage: R = LaurentPolynomialRing(QQ, 'v') @@ -1916,6 +1926,21 @@ class Cp(_KLHeckeBasis): sage: Cp(s1)*Cp(s2)*Cp(s3)*Cp(s1)*Cp(s2) # long time Cp[1,2,3,1,2] + Cp[1,2,1] + Cp[3,1,2] + The most efficient way to use this class is to create the algebra from a + Coxeter group implemented with ``coxeter3``. This will ensure the direct + algorithm can work as efficiently as possible with no unnecessary + conversions:: + + sage: R = LaurentPolynomialRing(QQ, 'v') # optional - coxeter3 + sage: v = R.gen(0) # optional - coxeter3 + sage: W = CoxeterGroup('A9', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 + sage: Cp = H.Cp() # optional - coxeter3 + sage: Cp[1,2,1,8,9,8]*Cp[1,2,3,7,8,9] # optional - coxeter3 + (v^-2+2+v^2)*Cp[1,2,1,3,7,8,7,9,8,7] + + (v^-2+2+v^2)*Cp[1,2,1,3,8,9,8,7] + + (v^-3+3*v^-1+3*v+v^3)*Cp[1,2,1,3,8,9,8] + TESTS:: sage: R. = LaurentPolynomialRing(QQ, 'v') @@ -1933,13 +1958,30 @@ class Cp(_KLHeckeBasis): def __init__(self, IHAlgebra, prefix=None): r""" - TODO: docstring + TESTS:: + + sage: R = LaurentPolynomialRing(QQ, 'v') # optional - coxeter3 + sage: v = R.gen(0) # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 + sage: Cp = H.Cp() # optional - coxeter3 + sage: Cp.delta == v + ~v # optional - coxeter3 + True + sage: Cp._W_Coxeter3 == H._W # optional - coxeter3 + True + sage: H = IwahoriHeckeAlgebra(W, QQ(1)) # optional - coxeter3 + sage: Cp = H.Cp() # optional - coxeter3 + sage: Cp.delta == None # optional - coxeter3 + True """ super().__init__(IHAlgebra, prefix) self.delta = None self._W_Coxeter3 = None + # See if we meet the conditions to use the direct product_on_basis algorithm. + # If we do, both of these will be non-None + v = IHAlgebra.base_ring().gen(0) parameters = {IHAlgebra.q1(), IHAlgebra.q2()} if v != IHAlgebra.base_ring().one() and (parameters == {v**2, -1} or parameters == {v, -1/v}): @@ -2113,9 +2155,12 @@ def _decompose_into_generators(self, u): def product_on_basis(self, w1, w2): r""" - TODO: Mention fallback and conditions to use this algorithm. - Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` in - the `C^{\prime}`-basis. + If possible, uses a direct algorithm to compute the product + `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` (in particular, if + ``coxeter3`` is installed and the Iwahori--Hecke algebra is in the + standard or normalized presentation), detailed below. If not, this + method uses the default implementation of converting to the + `T`-basis, computing the product there, and converting back. ALGORITHM: From 1b0bae1994d9b21436374e7ff06b699e0f8c43f7 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 13 Aug 2021 16:11:11 -0600 Subject: [PATCH 088/511] Move .kazhdan_lusztig_cell --- src/sage/categories/coxeter_groups.py | 109 ++++++++++++++++++++++++ src/sage/libs/coxeter3/coxeter_group.py | 102 ---------------------- 2 files changed, 109 insertions(+), 102 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index a2a6a44b5b8..559316ad601 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -22,7 +22,10 @@ from sage.categories.generalized_coxeter_groups import GeneralizedCoxeterGroups from sage.structure.element import have_same_parent, parent from sage.misc.flatten import flatten +from sage.graphs.digraph import DiGraph +from sage.rings.integer_ring import ZZ from copy import copy +from collections import deque class CoxeterGroups(Category_singleton): @@ -2683,3 +2686,109 @@ def upper_covers(self, side='right', index_set=None): """ return self.weak_covers(side=side, index_set=index_set, positive=True) + + def kazhdan_lusztig_cell(self, side='left'): + r""" + Compute the left, right, or two-sided Kazhdan-Lusztig cell + containing the element ``self``. Computes left cells by default; use + the optional argument ``side`` to specify right or two-sided cells. + + Two elements `x,y` of a Coxeter group `W` are said lie in the same + left Kazhdan-Lusztig cell if there exist sequences `x=w_1, w_2, ..., + w_k=y` and `y=u_1, u_2, ..., u_l=x` such that for all `1 \leq i < k` + and all `1 \leq j < l`, there exist some Coxeter generators `s,t` + for which `C'_{w_{i+1}}` appears in `C'_sC'_{w_i}` and + `C'_{u_{j+1}}` appears in `C'_sC'_{u_j}` in the Hecke algebra of the + Coxeter group, where `C'` denotes the Kazhdan-Lusztig + `C^{\prime}`-basis. Right and two-sided Kazhdan-Lusztig cells of `W` + are defined similarly. + + In this function, we compute products in the `C^{\prime}` basis by + using :class:`IwahoriHeckeAlgebra.Cp`. To use the direct algorithm + for computing such products detailed therein, the package + ``coxeter3`` must be installed; otherwise, this method will most + likely be computationally infeasible. + + INPUT: + + - ``w`` -- an element of self. + + - ``side`` -- string (default: ``'left'``); one of 'left', 'right', + or 'two-sided', corresponding to the kind of cell to compute. + + EXAMPLES: + + Compute some cells in type `B_3`:: + + sage: W = CoxeterGroup('B3', implementation='coxeter3') # optional - coxeter3 + sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 + sage: (s1*s2*s1).kazhdan_lusztig_cell() # optional - coxeter3 + {[2, 1, 2], [2, 3, 2, 1, 2], [3, 2, 1, 2]} + sage: (s2*s3*s2).kazhdan_lusztig_cell() # optional - coxeter3 + {[1, 2], [1, 2, 3, 2], [2], [2, 3, 2], [3, 2]} + sage: s3.kazhdan_lusztig_cell() # optional - coxeter3 + {[1, 2, 3], [2, 3], [3], [3, 2, 3]} + sage: s3.kazhdan_lusztig_cell('right') # optional - coxeter3 + {[3], [3, 2], [3, 2, 1], [3, 2, 3]} + sage: s3.kazhdan_lusztig_cell('two-sided') # optional - coxeter3 + {[1], [1, 2], [1, 2, 3], [1, 2, 3, 2], [1, 2, 3, 2, 1], [2], [2, 1], + [2, 3], [2, 3, 2], [2, 3, 2, 1], [3], [3, 2], [3, 2, 1], [3, 2, 3]} + + Some slightly longer computations in type `B_4`:: + + sage: W = CoxeterGroup('B4', implementation='coxeter3') # optional - coxeter3 + sage: s1,s2,s3,s4 = W.simple_reflections() # optional - coxeter3 + sage: s1.kazhdan_lusztig_cell() # long time (4 seconds) # optional - coxeter3 + {[1], + [1, 2, 3, 4, 3, 2, 1], + [2, 1], + [2, 3, 4, 3, 2, 1], + [3, 2, 1], + [3, 4, 3, 2, 1], + [4, 3, 2, 1]} + sage: (s4*s2*s3*s4).kazhdan_lusztig_cell() # long time (2 seconds) # optional - coxeter3 + {[2, 3, 4, 1, 2, 3, 4], + [3, 4, 1, 2, 3, 4], + [3, 4, 2, 3, 4], + [3, 4, 2, 3, 4, 1, 2, 3, 4], + [4, 1, 2, 3, 4], + [4, 2, 3, 4], + [4, 2, 3, 4, 1, 2, 3, 4], + [4, 3, 4, 1, 2, 3, 4], + [4, 3, 4, 2, 3, 4], + [4, 3, 4, 2, 3, 4, 1, 2, 3, 4]} + """ + from sage.algebras.iwahori_hecke_algebra import IwahoriHeckeAlgebra + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + + R = LaurentPolynomialRing(ZZ, 'v') + v = R.gen(0) + H = IwahoriHeckeAlgebra(self.parent(), v**2) + Cp = H.Cp() + + w = self.parent()(self) + + vertices, edges = {w}, set() + queue = deque([w]) + + while queue: + x = queue.pop() + cp_x = Cp(x) + for s in self.parent().simple_reflections(): + cp_s = Cp(s) + terms = [] + # Determine the Cp basis elements appearing in the product of Cp_s and Cp_w + if side == 'left' or side == 'two-sided': + terms.extend(list(cp_s * cp_x)) + if side == 'right' or side == 'two-sided': + terms.extend(list(cp_x * cp_s)) + for (y, coeff) in terms: + # the result of multiplication will always have coeff != 0 + if y != x: + edges.add((x, y)) + if y not in vertices: + vertices.add(y) + queue.appendleft(y) + + g = DiGraph([list(vertices), list(edges)]) + return set(g.strongly_connected_component_containing_vertex(w)) \ No newline at end of file diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 7c3f0cfd509..d0c13f12a11 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -9,13 +9,9 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from collections import deque - from sage.libs.coxeter3.coxeter import get_CoxGroup, CoxGroupElement from sage.misc.cachefunc import cached_method -from sage.graphs.digraph import DiGraph - from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper from sage.structure.richcmp import richcmp @@ -25,7 +21,6 @@ from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -428,103 +423,6 @@ def parabolic_kazhdan_lusztig_polynomial(self, u, v, J, constant_term_one=True): return P.sum((-1)**(z.length()) * self.kazhdan_lusztig_polynomial(u*z,v, constant_term_one=False).shift(z.length()) for z in WOI if (u*z).bruhat_le(v)) - def kazhdan_lusztig_cell(self, w, side='left'): - r""" - Compute the left, right, or two-sided Kazhdan-Lusztig cell containing - the element ``w``. Computes left cells by default; use the optional - argument ``side`` to specify right or two-sided cells. - - Two elements `x,y` of a Coxeter group `W` are said lie in the same left Kazhdan-Lusztig cell if there exist - sequences `x=w_1, w_2, ..., w_k=y` and `y=u_1, u_2, ..., u_l=x` such that for all `1 \leq i < k` and all `1 - \leq j < l`, there exist some Coxeter generators `s,t` for which `C'_{w_{i+1}}` appears in `C'_sC'_{w_i}` - and `C'_{u_{j+1}}` appears in `C'_sC'_{u_j}` in the Hecke algebra of the Coxeter group, where `C'` denotes - the Kazhdan-Lusztig `C^{\prime}`-basis. Right and two-sided Kazhdan-Lusztig cells of `W` are defined - similarly. In this function, we compute products of the form `C_sC_w` using the function - :func:`product_on_basis` of the class :class:`IwahoriHeckeAlgebra.Cp_Coxeter3`. - - INPUT: - - - ``w`` -- an element of self. - - - ``side`` -- string (default: ``'left'``); one of 'left', 'right', or - 'two-sided', corresponding to the kind of cell to compute. - - EXAMPLES: - - Compute some cells in type `B_3`:: - - sage: W = CoxeterGroup('B3', implementation='coxeter3') # optional - coxeter3 - sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 - sage: W.kazhdan_lusztig_cell(s1*s2*s1) # optional - coxeter3 - {[2, 1, 2], [2, 3, 2, 1, 2], [3, 2, 1, 2]} - sage: W.kazhdan_lusztig_cell(s2*s3*s2) # optional - coxeter3 - {[1, 2], [1, 2, 3, 2], [2], [2, 3, 2], [3, 2]} - sage: W.kazhdan_lusztig_cell(s3) # optional - coxeter3 - {[1, 2, 3], [2, 3], [3], [3, 2, 3]} - sage: W.kazhdan_lusztig_cell(s3, side='right') # optional - coxeter3 - {[3], [3, 2], [3, 2, 1], [3, 2, 3]} - sage: W.kazhdan_lusztig_cell(s3, side='two-sided') # optional - coxeter3 - {[1], [1, 2], [1, 2, 3], [1, 2, 3, 2], [1, 2, 3, 2, 1], [2], [2, 1], - [2, 3], [2, 3, 2], [2, 3, 2, 1], [3], [3, 2], [3, 2, 1], [3, 2, 3]} - - Some slightly longer computations in type `B_4`:: - - sage: W = CoxeterGroup('B4', implementation='coxeter3') # optional - coxeter3 - sage: s1,s2,s3,s4 = W.simple_reflections() # optional - coxeter3 - sage: W.kazhdan_lusztig_cell(s1) # long time (4 seconds) # optional - coxeter3 - {[1], - [1, 2, 3, 4, 3, 2, 1], - [2, 1], - [2, 3, 4, 3, 2, 1], - [3, 2, 1], - [3, 4, 3, 2, 1], - [4, 3, 2, 1]} - sage: W.kazhdan_lusztig_cell(s4*s2*s3*s4) # long time (2 seconds) # optional - coxeter3 - {[2, 3, 4, 1, 2, 3, 4], - [3, 4, 1, 2, 3, 4], - [3, 4, 2, 3, 4], - [3, 4, 2, 3, 4, 1, 2, 3, 4], - [4, 1, 2, 3, 4], - [4, 2, 3, 4], - [4, 2, 3, 4, 1, 2, 3, 4], - [4, 3, 4, 1, 2, 3, 4], - [4, 3, 4, 2, 3, 4], - [4, 3, 4, 2, 3, 4, 1, 2, 3, 4]} - """ - from sage.algebras.iwahori_hecke_algebra import IwahoriHeckeAlgebra - - R = LaurentPolynomialRing(ZZ, 'v') - v = R.gen(0) - H = IwahoriHeckeAlgebra(self, v**2) - CpC = H.Cp_Coxeter3() - - w = self(w) - - vertices, edges = {w}, set() - queue = deque([w]) - - while queue: - x = queue.pop() - cp_x = CpC(x) - for s in self.simple_reflections(): - cp_s = CpC(s) - terms = [] - # Determine the Cp basis elements appearing in the product of Cp_s and Cp_w - if side == 'left' or side == 'two-sided': - terms.extend(list(cp_s * cp_x)) - if side == 'right' or side == 'two-sided': - terms.extend(list(cp_x * cp_s)) - for (y, coeff) in terms: - # the result of multiplication will always have coeff != 0 - if y != x: - edges.add((x, y)) - if y not in vertices: - vertices.add(y) - queue.appendleft(y) - - g = DiGraph([list(vertices), list(edges)]) - return set(g.strongly_connected_component_containing_vertex(w)) - class Element(ElementWrapper): wrapped_class = CoxGroupElement From 5634be53a37a43bb1521c024d56c306b3ea42061 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 13 Aug 2021 16:58:55 -0600 Subject: [PATCH 089/511] Move product_on_basis to be first. --- src/sage/algebras/iwahori_hecke_algebra.py | 192 ++++++++++----------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 80cbbdd843b..74269eb7030 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2019,6 +2019,102 @@ def hash_involution_on_basis(self, w): """ return (-1)**w.length() * self(self.realization_of().C().monomial(w)) + def product_on_basis(self, w1, w2): + r""" + If possible, uses a direct algorithm to compute the product + `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` (in particular, if + ``coxeter3`` is installed and the Iwahori--Hecke algebra is in the + standard or normalized presentation), detailed below. If not, this + method uses the default implementation of converting to the + `T`-basis, computing the product there, and converting back. + + ALGORITHM: + + This class computes each product `C^{\prime}_x \cdot C^{\prime}_y` + in two steps as follows. + + If `\ell(x) \leq \ell(y)`, we first decompose `C^{\prime}_x` into a + polynomial in the generators `C^{\prime}_s (s\in S)` and then + multiply that polynomial with `C^{\prime}_y`. If `\ell(x) > + \ell(y)`, we decompose `C^{\prime}_y` into a polynomial in + `C^{\prime}_s (s\in S)` and multiply that polynomial with + `C^{\prime}_x`. The second step (multiplication) is done by + repeatedly applying the key formulas displayed earlier directly. The + first step (decomposition) is done by induction on the Bruhat order + as follows: for every element `u\in W` with length `\ell(u)>1`, pick + a left descent `s` of `u` and write `u=sw` (so `w=su`), then note + that + + .. MATH:: C^{\prime}_u = C^{\prime}_s \cdot C^{\prime}_{w} - \sum_{v\le u; sv< v} \mu(v,w) C^{\prime}_v + + by the key formulas mentioned earlier, where the element `w` and all + elements `v`'s on the right side are lower than `u` in the Bruhat + order; this allows us to finish the computation by decomposing the + lower order terms `C^{\prime}_w` and each `C^{\prime}_v`. For + example, for `u=121, s=1, w=21` in type `A_3` we have + `C^{\prime}_{121} = C^{\prime}_1 C^{\prime}_{21} - C^{\prime}_1`, + where the lower order term `C^{\prime}_{21}` further decomposes into + `C^{\prime}_2 C^{\prime}_1`, therefore + + .. MATH:: C^{\prime}_{121}=C^{\prime}_1 C^{\prime}_2 C^{\prime}_1 - C^{\prime}_1. + + We note that the base cases `\ell(x)=1` or `\ell(x)=0` of the above + induction occur when `x` is itself a Coxeter generator `s` or the + group identity, respectively. The decomposition is trivial in these + cases (we have `C^{\prime}_x=C^{\prime}_s` or `C^{\prime}_x=1`, the + unit of the Hecke algebra). + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 + sage: Cp.product_on_basis(W([1,2,1]), W([3,1])) # optional - coxeter3 + (v^-1+v)*Cp[1,2,1,3] + sage: Cp.product_on_basis(W([1,2,1]), W([3,1,2])) # optional - coxeter3 + (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] + """ + if self.delta is None or self._W_Coxeter3 is None: + # We do not meet the conditions to use the direct product + # algorithm; fall back to conversion to/from the T-basis. + return super().product_on_basis(w1, w2) + + # If self._W_Coxeter3 is not the underlying Coxeter group, we need + # to convert elements first for this algorithm. + if (self._W_Coxeter3 != self.realization_of()._W): + w1 = self._W_Coxeter3.from_reduced_word(w1.reduced_word()) + w2 = self._W_Coxeter3.from_reduced_word(w2.reduced_word()) + + # Decomposition: write one of C'_{w1} and C'_{w2} as a polynomial in the + # generators C'_{s}. + if len(w1) <= len(w2): + side = 'left' + gen_expression = self._decompose_into_generators(w1) + other_element = self.monomial(w2) + else: + side = 'right' + gen_expression = self._decompose_into_generators(w2) + other_element = self.monomial(w1) + result = self(0) + # Multiplication: multiply the generators in each term of the above + # polynomial onto other_element and add that summand onto result. + for (p, coeff) in gen_expression.items(): + summand = coeff * other_element + p_list = list(p) if side == 'right' else list(p)[::-1] + for s in p_list: + summand = self._product_with_generator(s, summand, side) + result += summand + + # Again, if self._W_Coxeter3 is not the underlying Coxeter group, + # we need to convert result. Specifically, make sure basis elements + # appearing therein are actually indexed by elements of the original + # underlying Coxeter group. + if (self._W_Coxeter3 != self.realization_of()._W): + _W = self.realization_of()._W + result = self.linear_combination((self(_W.from_reduced_word(w.reduced_word())), c) for (w, c) in result) + + return result + def _product_with_generator_on_basis(self, s, w, side='left'): r""" Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting @@ -2153,102 +2249,6 @@ def _decompose_into_generators(self, u): return result - def product_on_basis(self, w1, w2): - r""" - If possible, uses a direct algorithm to compute the product - `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` (in particular, if - ``coxeter3`` is installed and the Iwahori--Hecke algebra is in the - standard or normalized presentation), detailed below. If not, this - method uses the default implementation of converting to the - `T`-basis, computing the product there, and converting back. - - ALGORITHM: - - This class computes each product `C^{\prime}_x \cdot C^{\prime}_y` - in two steps as follows. - - If `\ell(x) \leq \ell(y)`, we first decompose `C^{\prime}_x` into a - polynomial in the generators `C^{\prime}_s (s\in S)` and then - multiply that polynomial with `C^{\prime}_y`. If `\ell(x) > - \ell(y)`, we decompose `C^{\prime}_y` into a polynomial in - `C^{\prime}_s (s\in S)` and multiply that polynomial with - `C^{\prime}_x`. The second step (multiplication) is done by - repeatedly applying the key formulas displayed earlier directly. The - first step (decomposition) is done by induction on the Bruhat order - as follows: for every element `u\in W` with length `\ell(u)>1`, pick - a left descent `s` of `u` and write `u=sw` (so `w=su`), then note - that - - .. MATH:: C^{\prime}_u = C^{\prime}_s \cdot C^{\prime}_{w} - \sum_{v\le u; sv< v} \mu(v,w) C^{\prime}_v - - by the key formulas mentioned earlier, where the element `w` and all - elements `v`'s on the right side are lower than `u` in the Bruhat - order; this allows us to finish the computation by decomposing the - lower order terms `C^{\prime}_w` and each `C^{\prime}_v`. For - example, for `u=121, s=1, w=21` in type `A_3` we have - `C^{\prime}_{121} = C^{\prime}_1 C^{\prime}_{21} - C^{\prime}_1`, - where the lower order term `C^{\prime}_{21}` further decomposes into - `C^{\prime}_2 C^{\prime}_1`, therefore - - .. MATH:: C^{\prime}_{121}=C^{\prime}_1 C^{\prime}_2 C^{\prime}_1 - C^{\prime}_1. - - We note that the base cases `\ell(x)=1` or `\ell(x)=0` of the above - induction occur when `x` is itself a Coxeter generator `s` or the - group identity, respectively. The decomposition is trivial in these - cases (we have `C^{\prime}_x=C^{\prime}_s` or `C^{\prime}_x=1`, the - unit of the Hecke algebra). - - EXAMPLES:: - - sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 - sage: Cp.product_on_basis(W([1,2,1]), W([3,1])) # optional - coxeter3 - (v^-1+v)*Cp[1,2,1,3] - sage: Cp.product_on_basis(W([1,2,1]), W([3,1,2])) # optional - coxeter3 - (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] - """ - if self.delta is None or self._W_Coxeter3 is None: - # We do not meet the conditions to use the direct product - # algorithm; fall back to conversion to/from the T-basis. - return super().product_on_basis(w1, w2) - - # If self._W_Coxeter3 is not the underlying Coxeter group, we need - # to convert elements first for this algorithm. - if (self._W_Coxeter3 != self.realization_of()._W): - w1 = self._W_Coxeter3.from_reduced_word(w1.reduced_word()) - w2 = self._W_Coxeter3.from_reduced_word(w2.reduced_word()) - - # Decomposition: write one of C'_{w1} and C'_{w2} as a polynomial in the - # generators C'_{s}. - if len(w1) <= len(w2): - side = 'left' - gen_expression = self._decompose_into_generators(w1) - other_element = self.monomial(w2) - else: - side = 'right' - gen_expression = self._decompose_into_generators(w2) - other_element = self.monomial(w1) - result = self(0) - # Multiplication: multiply the generators in each term of the above - # polynomial onto other_element and add that summand onto result. - for (p, coeff) in gen_expression.items(): - summand = coeff * other_element - p_list = list(p) if side == 'right' else list(p)[::-1] - for s in p_list: - summand = self._product_with_generator(s, summand, side) - result += summand - - # Again, if self._W_Coxeter3 is not the underlying Coxeter group, - # we need to convert result. Specifically, make sure basis elements - # appearing therein are actually indexed by elements of the original - # underlying Coxeter group. - if (self._W_Coxeter3 != self.realization_of()._W): - _W = self.realization_of()._W - result = self.linear_combination((self(_W.from_reduced_word(w.reduced_word())), c) for (w, c) in result) - - return result - C_prime = Cp class C(_KLHeckeBasis): From cb5dfff6efa80a1122475315e697f60ef4279229 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Fri, 13 Aug 2021 17:05:31 -0600 Subject: [PATCH 090/511] Add H4 example --- src/sage/algebras/iwahori_hecke_algebra.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 74269eb7030..585e50dc36d 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1926,10 +1926,24 @@ class Cp(_KLHeckeBasis): sage: Cp(s1)*Cp(s2)*Cp(s3)*Cp(s1)*Cp(s2) # long time Cp[1,2,3,1,2] + Cp[1,2,1] + Cp[3,1,2] + This computation in type `H_4` takes about 5 seconds without + ``coxeter3`` installed, but is instant in the case that it is installed + and the direct algorithm can be used. + + sage: H = IwahoriHeckeAlgebra('H4', v**2) # optional - coxeter3 + sage: Cp = H.Cp() # optional - coxeter3 + sage: Cp[3,4,3]*Cp[3,4,3,4]*Cp[1,2,3,4] # optional - coxeter3 + (v^-2+2+v^2)*Cp[3,4,3,4,1,2,3,4,2] + + (v^-2+2+v^2)*Cp[3,4,3,4,3,1,2] + + (v^-3+3*v^-1+3*v+v^3)*Cp[3,4,3,4,3,1] + + (v^-1+v)*Cp[3,4,1,2,3,4] + + (v^-1+v)*Cp[3,4,1,2] + The most efficient way to use this class is to create the algebra from a Coxeter group implemented with ``coxeter3``. This will ensure the direct algorithm can work as efficiently as possible with no unnecessary - conversions:: + conversions. This computuation seems to be infeasible without using the + direct algorithm:: sage: R = LaurentPolynomialRing(QQ, 'v') # optional - coxeter3 sage: v = R.gen(0) # optional - coxeter3 From 7e912e8da36e69b9748fecaa5bd0ab4208197fa6 Mon Sep 17 00:00:00 2001 From: Tianyuan Xu Date: Fri, 13 Aug 2021 18:20:05 -0600 Subject: [PATCH 091/511] doc changes in Cp class --- src/sage/algebras/iwahori_hecke_algebra.py | 141 ++++++++++++++------- 1 file changed, 94 insertions(+), 47 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 585e50dc36d..dcbad08667f 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1882,15 +1882,17 @@ class Cp(_KLHeckeBasis): See [KL1979]_ for more details. - If the optional ``coxeter3`` package is available, and the + If the optional ``coxeter3`` package is available and the Iwahori--Hecke algebra was initialized in the "standard" presentation - (where `\{q_1,q_2\} = \{v^2,1\}` as sets) or the "normalized" - presentation (where `\{q_1,q_2\} = \{v,-v^{-1}\}`), a performant direct - algorithm is available to compute products in the `C^{\prime}` basis, - documented in :func:`product_on_basis`. If these conditions are not met, - the class will fall back to the default implementation which computes - products by converting elements to the `T`-basis and back. This default - implementation may be prohibitively slow for complex calculations. + where `\{q_1,q_2\} = \{v^2,1\}` as sets or the "normalized" + presentation where `\{q_1,q_2\} = \{v,-v^{-1}\}` as sets, the function + :func::`product_on_basis` in this class computes products in the + `C^{\prime}`-basis directly in the basis itself, using ``coxeter3`` to + calculate certain `\mu`-coefficients quickly. If the above conditions + are not all met, the function computes such products indirectly, by + converting elements to the `T`-basis, computing products there, and + converting back. The indirect method can be prohibitively slow for more + complex calculations; the direct method is faster. EXAMPLES:: @@ -1923,12 +1925,14 @@ class Cp(_KLHeckeBasis): (v^-1+v)*Cp[1] sage: Cp(s1)*Cp(s2)*Cp(s1) Cp[1,2,1] + Cp[1] - sage: Cp(s1)*Cp(s2)*Cp(s3)*Cp(s1)*Cp(s2) # long time + sage: Cp(s1)*Cp(s2)*Cp(s3)*Cp(s1)*Cp(s2) # long time Cp[1,2,3,1,2] + Cp[1,2,1] + Cp[3,1,2] - This computation in type `H_4` takes about 5 seconds without - ``coxeter3`` installed, but is instant in the case that it is installed - and the direct algorithm can be used. + In the following product computations, whether ``coxeter3`` is + installed makes a big difference: without ``coxeter3`` the product in + type `H_4` takes about 5 seconds to compute and the product in type + `A_9` seems infeasible, while with ``coxeter3`` both the computations + are instant:: sage: H = IwahoriHeckeAlgebra('H4', v**2) # optional - coxeter3 sage: Cp = H.Cp() # optional - coxeter3 @@ -1939,11 +1943,17 @@ class Cp(_KLHeckeBasis): + (v^-1+v)*Cp[3,4,1,2,3,4] + (v^-1+v)*Cp[3,4,1,2] - The most efficient way to use this class is to create the algebra from a - Coxeter group implemented with ``coxeter3``. This will ensure the direct - algorithm can work as efficiently as possible with no unnecessary - conversions. This computuation seems to be infeasible without using the - direct algorithm:: + sage: H = IwahoriHeckeAlgebra('A9', v**2) # optional - coxeter3 + sage: Cp = H.Cp() # optional - coxeter3 + sage: Cp[1,2,1,8,9,8]*Cp[1,2,3,7,8,9] # optional - coxeter3 + (v^-2+2+v^2)*Cp[1,2,1,3,7,8,7,9,8,7] + + (v^-2+2+v^2)*Cp[1,2,1,3,8,9,8,7] + + (v^-3+3*v^-1+3*v+v^3)*Cp[1,2,1,3,8,9,8] + + To use ``coxeter3`` for product computations most efficiently, we + recommend creating the Iwahori-Hecke algebra from a Coxeter group + implemented with ``coxeter3`` to avoid unnecessary conversions, as in + the following example with the same product computed in the last one:: sage: R = LaurentPolynomialRing(QQ, 'v') # optional - coxeter3 sage: v = R.gen(0) # optional - coxeter3 @@ -1994,7 +2004,7 @@ def __init__(self, IHAlgebra, prefix=None): self._W_Coxeter3 = None # See if we meet the conditions to use the direct product_on_basis algorithm. - # If we do, both of these will be non-None + # If we do, both of these will be non-None. v = IHAlgebra.base_ring().gen(0) parameters = {IHAlgebra.q1(), IHAlgebra.q2()} @@ -2002,7 +2012,8 @@ def __init__(self, IHAlgebra, prefix=None): # The following quantity delta is used in product computations. # To use v+~v as its value we need the standard or normalized presentations of the Hecke algebra. self.delta = v + ~v - + + # check if products can be computed directly using ``coxeter3``: try: from sage.libs.coxeter3.coxeter_group import CoxeterGroup as Coxeter3Group if isinstance(IHAlgebra._W, Coxeter3Group): @@ -2035,17 +2046,48 @@ def hash_involution_on_basis(self, w): def product_on_basis(self, w1, w2): r""" - If possible, uses a direct algorithm to compute the product - `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` (in particular, if - ``coxeter3`` is installed and the Iwahori--Hecke algebra is in the - standard or normalized presentation), detailed below. If not, this - method uses the default implementation of converting to the - `T`-basis, computing the product there, and converting back. + Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` in + the `C^{\prime}`-basis. + + If ``coxeter3`` is installed and the Iwahori--Hecke algebra is in + the standard or normalized presentation, the product is computed + directly using the method described in ALGORITHM. If not, the + product is computed indirectly by converting the factors to the + `T`-basis, computing the product there, and converting back. + + The following formulas for products of the forms `C^{\prime}_s + \cdot C^{\prime}_w` and `C^{\prime}_w \cdot C^{\prime}_s`, where + `s` is a generator of the Coxeter group and `w` an arbitrary + element, are key to the direct computation method. The formulas are + valid for both the standard and normalized presentation of the + Hecke algebra. + + .. MATH:: + C^{\prime}_s \cdot C^{\prime}_w = \begin{cases} + (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ + C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, + & \text{if } \ell(sw) = \ell(w)+1. + \end{cases} + + C^{\prime}_w \cdot C^{\prime}_s = \begin{cases} + (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(ws) = \ell(w)-1,\\ + C^{\prime}_{ws}+\sum_{v\leq w, vs \leq v} \mu(v,w)C^{\prime}_v, + & \text{if } \ell(ws) = \ell(w)+1. + \end{cases} + + In the above, `\leq` is the Bruhat order on the Coxeter group and + `\mu(v,w)` is the "leading coefficient of Kazhdan-Lusztig + polynomials"; see [KL1979]_ and [Lus2013]_ for more details. The + method designates the computation of the `\mu`-coefficients to + Sage's interface to Fokko du Cloux's ``coxeter3`` package, which is + why the method requires the creation of the Coxeter group using the + 'coxeter3' implementation. + ALGORITHM: - This class computes each product `C^{\prime}_x \cdot C^{\prime}_y` - in two steps as follows. + The direct algorithm for computing `C^{\prime}_x \cdot + C^{\prime}_y` runs in two steps as follows. If `\ell(x) \leq \ell(y)`, we first decompose `C^{\prime}_x` into a polynomial in the generators `C^{\prime}_s (s\in S)` and then @@ -2053,24 +2095,28 @@ def product_on_basis(self, w1, w2): \ell(y)`, we decompose `C^{\prime}_y` into a polynomial in `C^{\prime}_s (s\in S)` and multiply that polynomial with `C^{\prime}_x`. The second step (multiplication) is done by - repeatedly applying the key formulas displayed earlier directly. The + repeatedly applying the formulas displayed earlier directly. The first step (decomposition) is done by induction on the Bruhat order - as follows: for every element `u\in W` with length `\ell(u)>1`, pick - a left descent `s` of `u` and write `u=sw` (so `w=su`), then note - that - - .. MATH:: C^{\prime}_u = C^{\prime}_s \cdot C^{\prime}_{w} - \sum_{v\le u; sv< v} \mu(v,w) C^{\prime}_v - - by the key formulas mentioned earlier, where the element `w` and all - elements `v`'s on the right side are lower than `u` in the Bruhat - order; this allows us to finish the computation by decomposing the - lower order terms `C^{\prime}_w` and each `C^{\prime}_v`. For - example, for `u=121, s=1, w=21` in type `A_3` we have - `C^{\prime}_{121} = C^{\prime}_1 C^{\prime}_{21} - C^{\prime}_1`, - where the lower order term `C^{\prime}_{21}` further decomposes into - `C^{\prime}_2 C^{\prime}_1`, therefore - - .. MATH:: C^{\prime}_{121}=C^{\prime}_1 C^{\prime}_2 C^{\prime}_1 - C^{\prime}_1. + as follows: for every element `u\in W` with length `\ell(u)>1`, + pick a left descent `s` of `u` and write `u=sw` (so `w=su`), then + note that + + .. MATH:: + C^{\prime}_u = C^{\prime}_s \cdot C^{\prime}_{w} + - \sum_{v\le u; sv< v} \mu(v,w) C^{\prime}_v + + by the earlier formulas, where the element `w` and all elements + `v`'s on the right side are lower than `u` in the Bruhat order; + this allows us to finish the computation by decomposing the lower + order terms `C^{\prime}_w` and each `C^{\prime}_v`. For example, + for `u=121, s=1, w=21` in type `A_3` we have `C^{\prime}_{121} = + C^{\prime}_1 C^{\prime}_{21} - C^{\prime}_1`, where the lower + order term `C^{\prime}_{21}` further decomposes into `C^{\prime}_2 + C^{\prime}_1`, therefore + + .. MATH:: + C^{\prime}_{121} = C^{\prime}_1 C^{\prime}_2 C^{\prime}_1 + - C^{\prime}_1. We note that the base cases `\ell(x)=1` or `\ell(x)=0` of the above induction occur when `x` is itself a Coxeter generator `s` or the @@ -2120,9 +2166,10 @@ def product_on_basis(self, w1, w2): result += summand # Again, if self._W_Coxeter3 is not the underlying Coxeter group, - # we need to convert result. Specifically, make sure basis elements - # appearing therein are actually indexed by elements of the original - # underlying Coxeter group. + # we need to convert the result. Specifically, make sure basis + # elements appearing therein are actually indexed by elements of + # the original underlying Coxeter group. + if (self._W_Coxeter3 != self.realization_of()._W): _W = self.realization_of()._W result = self.linear_combination((self(_W.from_reduced_word(w.reduced_word())), c) for (w, c) in result) From ee2edc72bbfd2bec46ed002b802626228bec40c6 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 14 Aug 2021 09:44:30 -0600 Subject: [PATCH 092/511] Tweak/fix some docstrings --- src/sage/algebras/iwahori_hecke_algebra.py | 71 +++++++++++----------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index dcbad08667f..fa38e115f11 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1953,7 +1953,7 @@ class Cp(_KLHeckeBasis): To use ``coxeter3`` for product computations most efficiently, we recommend creating the Iwahori-Hecke algebra from a Coxeter group implemented with ``coxeter3`` to avoid unnecessary conversions, as in - the following example with the same product computed in the last one:: + the following example with the same product computed in the last one:: sage: R = LaurentPolynomialRing(QQ, 'v') # optional - coxeter3 sage: v = R.gen(0) # optional - coxeter3 @@ -2012,7 +2012,7 @@ def __init__(self, IHAlgebra, prefix=None): # The following quantity delta is used in product computations. # To use v+~v as its value we need the standard or normalized presentations of the Hecke algebra. self.delta = v + ~v - + # check if products can be computed directly using ``coxeter3``: try: from sage.libs.coxeter3.coxeter_group import CoxeterGroup as Coxeter3Group @@ -2053,27 +2053,28 @@ def product_on_basis(self, w1, w2): the standard or normalized presentation, the product is computed directly using the method described in ALGORITHM. If not, the product is computed indirectly by converting the factors to the - `T`-basis, computing the product there, and converting back. - + `T`-basis, computing the product there, and converting back. + The following formulas for products of the forms `C^{\prime}_s \cdot C^{\prime}_w` and `C^{\prime}_w \cdot C^{\prime}_s`, where `s` is a generator of the Coxeter group and `w` an arbitrary element, are key to the direct computation method. The formulas are valid for both the standard and normalized presentation of the - Hecke algebra. + Hecke algebra. + + .. MATH:: - .. MATH:: - C^{\prime}_s \cdot C^{\prime}_w = \begin{cases} - (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ - C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, - & \text{if } \ell(sw) = \ell(w)+1. - \end{cases} + C^{\prime}_s \cdot C^{\prime}_w = \begin{cases} + (q+q^{-1})C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ + C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, + & \text{if } \ell(sw) = \ell(w)+1. + \end{cases} - C^{\prime}_w \cdot C^{\prime}_s = \begin{cases} - (q+q^-1)C^{\prime}_{w}, & \text{if } \ell(ws) = \ell(w)-1,\\ - C^{\prime}_{ws}+\sum_{v\leq w, vs \leq v} \mu(v,w)C^{\prime}_v, - & \text{if } \ell(ws) = \ell(w)+1. - \end{cases} + C^{\prime}_w \cdot C^{\prime}_s = \begin{cases} + (q+q^{-1})C^{\prime}_{w}, & \text{if } \ell(ws) = \ell(w)-1,\\ + C^{\prime}_{ws}+\sum_{v\leq w, vs \leq v} \mu(v,w)C^{\prime}_v, + & \text{if } \ell(ws) = \ell(w)+1. + \end{cases} In the above, `\leq` is the Bruhat order on the Coxeter group and `\mu(v,w)` is the "leading coefficient of Kazhdan-Lusztig @@ -2083,7 +2084,6 @@ def product_on_basis(self, w1, w2): why the method requires the creation of the Coxeter group using the 'coxeter3' implementation. - ALGORITHM: The direct algorithm for computing `C^{\prime}_x \cdot @@ -2101,9 +2101,9 @@ def product_on_basis(self, w1, w2): pick a left descent `s` of `u` and write `u=sw` (so `w=su`), then note that - .. MATH:: - C^{\prime}_u = C^{\prime}_s \cdot C^{\prime}_{w} - - \sum_{v\le u; sv< v} \mu(v,w) C^{\prime}_v + .. MATH:: + + C^{\prime}_u = C^{\prime}_s \cdot C^{\prime}_{w} - \sum_{v\le u; sv< v} \mu(v,w) C^{\prime}_v by the earlier formulas, where the element `w` and all elements `v`'s on the right side are lower than `u` in the Bruhat order; @@ -2114,9 +2114,9 @@ def product_on_basis(self, w1, w2): order term `C^{\prime}_{21}` further decomposes into `C^{\prime}_2 C^{\prime}_1`, therefore - .. MATH:: - C^{\prime}_{121} = C^{\prime}_1 C^{\prime}_2 C^{\prime}_1 - - C^{\prime}_1. + .. MATH:: + + C^{\prime}_{121} = C^{\prime}_1 C^{\prime}_2 C^{\prime}_1 - C^{\prime}_1. We note that the base cases `\ell(x)=1` or `\ell(x)=0` of the above induction occur when `x` is itself a Coxeter generator `s` or the @@ -2135,7 +2135,7 @@ def product_on_basis(self, w1, w2): (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] """ if self.delta is None or self._W_Coxeter3 is None: - # We do not meet the conditions to use the direct product + # We do not meet the conditions to use the direct product # algorithm; fall back to conversion to/from the T-basis. return super().product_on_basis(w1, w2) @@ -2164,10 +2164,10 @@ def product_on_basis(self, w1, w2): for s in p_list: summand = self._product_with_generator(s, summand, side) result += summand - + # Again, if self._W_Coxeter3 is not the underlying Coxeter group, - # we need to convert the result. Specifically, make sure basis - # elements appearing therein are actually indexed by elements of + # we need to convert the result. Specifically, make sure basis + # elements appearing therein are actually indexed by elements of # the original underlying Coxeter group. if (self._W_Coxeter3 != self.realization_of()._W): @@ -2187,7 +2187,7 @@ def _product_with_generator_on_basis(self, s, w, side='left'): - ``w`` -- a word in self.coxeter_group() - - ``side`` -- string; 'left' or 'right' + - ``side`` -- string; ``'left'`` or ``'right'`` EXAMPLES:: @@ -2218,7 +2218,8 @@ def _product_with_generator_on_basis(self, s, w, side='left'): def _product_with_generator(self, s, x, side='left'): r""" - Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elements. + Compute the product of `C^{\prime}_s` with any linear combination of + `C^{\prime}`-basis elements. INPUT: @@ -2226,7 +2227,7 @@ def _product_with_generator(self, s, x, side='left'): - ``x`` -- any element of self - - ``side`` -- string; 'left' or 'right' + - ``side`` -- string; ``'left'`` or ``'right'`` EXAMPLES:: @@ -2249,9 +2250,9 @@ def _decompose_into_generators(self, u): OUTPUT: A dictionary keyed by tuples with integer values. Each entry - represents a term, where the tuple represents a monomial term in - the KL generators and the value represents the coefficient of that - term. For example, an item `(1,2): 3` stands for `3 * + represents a term, where the tuple represents a monomial term in the + KL generators and the value represents the coefficient of that term. + For example, an item `(1,2): 3` stands for `3 \cdot C^{\prime}_1C^{\prime}_2`. EXAMPLES: @@ -2268,13 +2269,13 @@ def _decompose_into_generators(self, u): {(1,): 1} Another example, where `C^{\prime}_u` happens to be a monomial - (e.g., CpC_{21} = CpC_2 * CpC_1):: + (e.g., `C'_{21} = C'_2 C'_1`):: sage: Cp._decompose_into_generators(W([2,1])) # optional - coxeter3 {(2, 1): 1} In more general situations the sum is a polynomial (e.g., - CpC_{121}=CpC_1*CpC_2*CpC_1-CpC_1):: + `C'_{121}=C'_1 C'_2 C'_1 - C'_1)`:: sage: Cp._decompose_into_generators(W([1,2,1])) # optional - coxeter3 {(1,): -1, (1, 2, 1): 1} From eea7340fdfef566a1984bf8883f1553d4b8de6a3 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 14 Aug 2021 09:54:13 -0600 Subject: [PATCH 093/511] Make auxiliary product_on_basis helpers public --- src/sage/algebras/iwahori_hecke_algebra.py | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index fa38e115f11..b268b468d0e 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -2149,11 +2149,11 @@ def product_on_basis(self, w1, w2): # generators C'_{s}. if len(w1) <= len(w2): side = 'left' - gen_expression = self._decompose_into_generators(w1) + gen_expression = self.decompose_into_generators(w1) other_element = self.monomial(w2) else: side = 'right' - gen_expression = self._decompose_into_generators(w2) + gen_expression = self.decompose_into_generators(w2) other_element = self.monomial(w1) result = self(0) # Multiplication: multiply the generators in each term of the above @@ -2162,7 +2162,7 @@ def product_on_basis(self, w1, w2): summand = coeff * other_element p_list = list(p) if side == 'right' else list(p)[::-1] for s in p_list: - summand = self._product_with_generator(s, summand, side) + summand = self.product_with_generator(s, summand, side) result += summand # Again, if self._W_Coxeter3 is not the underlying Coxeter group, @@ -2176,7 +2176,7 @@ def product_on_basis(self, w1, w2): return result - def _product_with_generator_on_basis(self, s, w, side='left'): + def product_with_generator_on_basis(self, s, w, side='left'): r""" Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting `C^{\prime}_s` on the given ``side``. @@ -2194,11 +2194,11 @@ def _product_with_generator_on_basis(self, s, w, side='left'): sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 - sage: Cp._product_with_generator_on_basis(1, W([2,1]), 'left') # optional - coxeter3 + sage: Cp.product_with_generator_on_basis(1, W([2,1]), 'left') # optional - coxeter3 Cp[1,2,1] + Cp[1] - sage: Cp._product_with_generator_on_basis(1, W([2,1]), 'right') # optional - coxeter3 + sage: Cp.product_with_generator_on_basis(1, W([2,1]), 'right') # optional - coxeter3 (v^-1+v)*Cp[2,1] - sage: Cp._product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') # optional - coxeter3 + sage: Cp.product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') # optional - coxeter3 Cp[1,2,1,3,2,1] + Cp[1,2,3,2] + Cp[1,3,2,1] """ # use the product formula described in the class' documentation @@ -2216,7 +2216,7 @@ def _product_with_generator_on_basis(self, s, w, side='left'): longer_word = self._W_Coxeter3([s]) * w if side == 'left' else w * self._W_Coxeter3([s]) return self.monomial(longer_word) + element - def _product_with_generator(self, s, x, side='left'): + def product_with_generator(self, s, x, side='left'): r""" Compute the product of `C^{\prime}_s` with any linear combination of `C^{\prime}`-basis elements. @@ -2234,14 +2234,14 @@ def _product_with_generator(self, s, x, side='left'): sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 - sage: Cp._product_with_generator(1, Cp[1]+Cp[2], 'left') # optional - coxeter3 + sage: Cp.product_with_generator(1, Cp[1]+Cp[2], 'left') # optional - coxeter3 Cp[1,2] + (v^-1+v)*Cp[1] - sage: Cp._product_with_generator(1, Cp[1]+Cp[2], 'right') # optional - coxeter3 + sage: Cp.product_with_generator(1, Cp[1]+Cp[2], 'right') # optional - coxeter3 Cp[2,1] + (v^-1+v)*Cp[1] """ - return self.linear_combination((self._product_with_generator_on_basis(s, w, side), coeff) for (w, coeff) in x) + return self.linear_combination((self.product_with_generator_on_basis(s, w, side), coeff) for (w, coeff) in x) - def _decompose_into_generators(self, u): + def decompose_into_generators(self, u): r""" Decompose `C^{\prime}_u` into a polynomial in the KL generators `C^{\prime}_s`; see the ALGORITHM section of @@ -2265,21 +2265,21 @@ def _decompose_into_generators(self, u): When `u` is itself a generator `s`, the decomposition is trivial:: - sage: Cp._decompose_into_generators(W([1])) # optional - coxeter3 + sage: Cp.decompose_into_generators(W([1])) # optional - coxeter3 {(1,): 1} Another example, where `C^{\prime}_u` happens to be a monomial (e.g., `C'_{21} = C'_2 C'_1`):: - sage: Cp._decompose_into_generators(W([2,1])) # optional - coxeter3 + sage: Cp.decompose_into_generators(W([2,1])) # optional - coxeter3 {(2, 1): 1} In more general situations the sum is a polynomial (e.g., `C'_{121}=C'_1 C'_2 C'_1 - C'_1)`:: - sage: Cp._decompose_into_generators(W([1,2,1])) # optional - coxeter3 + sage: Cp.decompose_into_generators(W([1,2,1])) # optional - coxeter3 {(1,): -1, (1, 2, 1): 1} - sage: Cp._decompose_into_generators(W([1,2,3,1,2])) # optional - coxeter3 + sage: Cp.decompose_into_generators(W([1,2,3,1,2])) # optional - coxeter3 {(1,): 1, (1, 2, 1): -1, (1, 2, 1, 3, 2): 1, (1, 3, 2): -1} """ # l(y) = 0 or 1 @@ -2303,10 +2303,10 @@ def _decompose_into_generators(self, u): sum_term += self.base_ring()(v.mu_coefficient(w)) * self.monomial(v_elt) # recursion: decompose C'_s * C'_w and the lower order terms - result = {(s,) + gens: coeff for (gens, coeff) in self._decompose_into_generators(w).items()} + result = {(s,) + gens: coeff for (gens, coeff) in self.decompose_into_generators(w).items()} for (z, c1) in sum_term: # Subtract off each term from sum_term. - for (gens, c2) in self._decompose_into_generators(z).items(): + for (gens, c2) in self.decompose_into_generators(z).items(): result[gens] = result.get(gens, 0) - c1*c2 return result From 6dbd2e932db732806a2a599965d9591712dea16f Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 14 Aug 2021 10:37:50 -0600 Subject: [PATCH 094/511] Fix doctest When not using implementation=coxeter3, the reduced word convention is different. --- src/sage/algebras/iwahori_hecke_algebra.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index b268b468d0e..c6628f341f4 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1946,9 +1946,9 @@ class Cp(_KLHeckeBasis): sage: H = IwahoriHeckeAlgebra('A9', v**2) # optional - coxeter3 sage: Cp = H.Cp() # optional - coxeter3 sage: Cp[1,2,1,8,9,8]*Cp[1,2,3,7,8,9] # optional - coxeter3 - (v^-2+2+v^2)*Cp[1,2,1,3,7,8,7,9,8,7] - + (v^-2+2+v^2)*Cp[1,2,1,3,8,9,8,7] - + (v^-3+3*v^-1+3*v+v^3)*Cp[1,2,1,3,8,9,8] + (v^-2+2+v^2)*Cp[7,8,9,7,8,7,1,2,3,1] + + (v^-2+2+v^2)*Cp[8,9,8,7,1,2,3,1] + + (v^-3+3*v^-1+3*v+v^3)*Cp[8,9,8,1,2,3,1] To use ``coxeter3`` for product computations most efficiently, we recommend creating the Iwahori-Hecke algebra from a Coxeter group From a785b1c45aaa0b1e0c5064506ebebe38095b65bc Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 14 Aug 2021 11:14:40 -0600 Subject: [PATCH 095/511] Add function to compute all KL cells to Coxeter groups --- src/sage/categories/coxeter_groups.py | 52 +++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 559316ad601..b4bc3c0f50d 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -689,6 +689,58 @@ def simple_projection(self, i, side='right', length_increasing=True): return lambda x: x.apply_simple_projection(i, side=side, length_increasing=length_increasing) + def kazhdan_lusztig_cells(self, side='left'): + r""" + Compute the left, right, or two-sided Kazhdan-Lusztig cells of + ``self`` by using :func:`ElementMethods.kazhdan_lusztig_cell()`. As + detailed there, this function will be much more efficient if the + package ``coxeter3`` is installed, due to the method of computing + products in the `C^{\prime}` basis of the Iwahori--Hecke algebra. + + EXAMPLES:: + + sage: from sage.doctest.fixtures import reproducible_repr # optional - coxeter3 + sage: W = CoxeterGroup('A3') # optional - coxeter3 + sage: [len(c) for c in W.kazhdan_lusztig_cells()] # optional - coxeter3 + [3, 3, 2, 1, 3, 3, 3, 1, 3, 2] + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: print(reproducible_repr(W.kazhdan_lusztig_cells())) # optional - coxeter3 + set([frozenset([[1, 2, 1, 3, 2, 1]]), + frozenset([[1, 2, 1, 3, 2], [1, 2, 3, 2], [2, 3, 2]]), + frozenset([[1, 2, 1, 3], [1, 2, 3, 2, 1], [2, 3, 2, 1]]), + frozenset([[1, 2, 1], [1, 3, 2, 1], [2, 1, 3, 2, 1]]), + frozenset([[1, 2, 3], [2, 3], [3]]), + frozenset([[1, 2], [2], [3, 2]]), + frozenset([[1, 3, 2], [2, 1, 3, 2]]), + frozenset([[1, 3], [2, 1, 3]]), + frozenset([[1], [2, 1], [3, 2, 1]]), + frozenset([[]])]) + sage: W = CoxeterGroup('A4', implementation='coxeter3') # optional - coxeter3 + sage: [len(c) for c in W.kazhdan_lusztig_cells()] # long time (3 seconds) # optional - coxeter3 + [5, 4, 4, 5, 5, 6, 4, 6, 4, 5, 5, 4, 1, 5, 6, 4, 5, 6, 4, 5, 4, 6, 6, 5, 5, 1] + + TESTS:: + + sage: W = CoxeterGroup(['A', 2, 1]) + sage: W.kazhdan_lusztig_cells() + Traceback (most recent call last): + ... + ValueError: the Coxeter group must be finite to compute Kazhdan--Lusztig cells + """ + if not self.coxeter_type().is_finite(): + raise ValueError('the Coxeter group must be finite to compute Kazhdan--Lusztig cells') + + # The identity is its own left-, right-, and two-sided- cell. + identity = frozenset([self.one()]) + cells = {identity} + + for w in self: + if not any(w in c for c in cells): + cell = w.kazhdan_lusztig_cell(side=side) + cells.add(frozenset(cell)) + + return cells + @cached_method def simple_projections(self, side='right', length_increasing=True): r""" From f5706152df1f3545dc265ab6236f6b7ebdbdd263 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 14 Aug 2021 13:54:40 -0600 Subject: [PATCH 096/511] Tweak doctests for KL cell computation methods --- src/sage/categories/coxeter_groups.py | 97 ++++++++++++++++----------- 1 file changed, 56 insertions(+), 41 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index b4bc3c0f50d..a87cee06315 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -692,17 +692,15 @@ def simple_projection(self, i, side='right', length_increasing=True): def kazhdan_lusztig_cells(self, side='left'): r""" Compute the left, right, or two-sided Kazhdan-Lusztig cells of - ``self`` by using :func:`ElementMethods.kazhdan_lusztig_cell()`. As - detailed there, this function will be much more efficient if the + ``self`` by using + :func:`kazhdan_lusztig_cell()`. + As detailed there, this function will be much more efficient if the package ``coxeter3`` is installed, due to the method of computing products in the `C^{\prime}` basis of the Iwahori--Hecke algebra. EXAMPLES:: sage: from sage.doctest.fixtures import reproducible_repr # optional - coxeter3 - sage: W = CoxeterGroup('A3') # optional - coxeter3 - sage: [len(c) for c in W.kazhdan_lusztig_cells()] # optional - coxeter3 - [3, 3, 2, 1, 3, 3, 3, 1, 3, 2] sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 sage: print(reproducible_repr(W.kazhdan_lusztig_cells())) # optional - coxeter3 set([frozenset([[1, 2, 1, 3, 2, 1]]), @@ -715,9 +713,16 @@ def kazhdan_lusztig_cells(self, side='left'): frozenset([[1, 3], [2, 1, 3]]), frozenset([[1], [2, 1], [3, 2, 1]]), frozenset([[]])]) - sage: W = CoxeterGroup('A4', implementation='coxeter3') # optional - coxeter3 - sage: [len(c) for c in W.kazhdan_lusztig_cells()] # long time (3 seconds) # optional - coxeter3 - [5, 4, 4, 5, 5, 6, 4, 6, 4, 5, 5, 4, 1, 5, 6, 4, 5, 6, 4, 5, 4, 6, 6, 5, 5, 1] + sage: W = CoxeterGroup('B4', implementation='coxeter3') # optional - coxeter3 + sage: b4_cells = W.kazhdan_lusztig_cells() # long time (45 seconds) # optional - coxeter3 + sage: len(b4_cells) # optional - coxeter3 + 50 + sage: print(reproducible_repr(b4_cells)) # optional - coxeter3 + set([frozenset([[1, 2, 3, 4, 3, 2, 1], [1], [2, 1], [2, 3, 4, 3, 2, 1], [3, 2, 1], [3, 4, 3, 2, 1], [4, 3, 2, 1]]), + frozenset([[1, 2, 3, 4, 3, 2], [1, 2], [2, 3, 4, 3, 2], [2], [3, 2], [3, 4, 3, 2], [4, 3, 2]]), + frozenset([[1, 2, 3, 4, 3], [1, 2, 3], [2, 3, 4, 3], [2, 3], [3, 4, 3], [3], [4, 3]]), + frozenset([[1, 2, 3, 4], [2, 3, 4], [3, 4], [4, 3, 4], [4]]), + ... TESTS:: @@ -2770,45 +2775,55 @@ def kazhdan_lusztig_cell(self, side='left'): EXAMPLES: - Compute some cells in type `B_3`:: + Some simple computations in type `A_3`; we use two different Coxeter + group implementations:: - sage: W = CoxeterGroup('B3', implementation='coxeter3') # optional - coxeter3 + sage: W = CoxeterGroup('A3') # optional - coxeter3 + sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 + sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 + {[-1 1 0] + [-1 0 1] + [-1 0 0], + [-1 1 0] + [-1 0 1] + [ 0 0 1], + [-1 1 0] + [ 0 1 0] + [ 0 0 1]} + sage: W = CoxeterGroup('A3', implementation='permutation') # optional - coxeter3 sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 - sage: (s1*s2*s1).kazhdan_lusztig_cell() # optional - coxeter3 - {[2, 1, 2], [2, 3, 2, 1, 2], [3, 2, 1, 2]} - sage: (s2*s3*s2).kazhdan_lusztig_cell() # optional - coxeter3 - {[1, 2], [1, 2, 3, 2], [2], [2, 3, 2], [3, 2]} - sage: s3.kazhdan_lusztig_cell() # optional - coxeter3 - {[1, 2, 3], [2, 3], [3], [3, 2, 3]} - sage: s3.kazhdan_lusztig_cell('right') # optional - coxeter3 - {[3], [3, 2], [3, 2, 1], [3, 2, 3]} - sage: s3.kazhdan_lusztig_cell('two-sided') # optional - coxeter3 - {[1], [1, 2], [1, 2, 3], [1, 2, 3, 2], [1, 2, 3, 2, 1], [2], [2, 1], - [2, 3], [2, 3, 2], [2, 3, 2, 1], [3], [3, 2], [3, 2, 1], [3, 2, 3]} - - Some slightly longer computations in type `B_4`:: + sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 + {(1,2,3,12)(4,5,10,11)(6,7,8,9), + (1,2,10)(3,6,5)(4,7,8)(9,12,11), + (1,7)(2,4)(5,6)(8,10)(11,12)} + sage: s1.kazhdan_lusztig_cell(side='right') # optional - coxeter3 + {(1,7)(2,4)(5,6)(8,10)(11,12), + (1,10,2)(3,5,6)(4,8,7)(9,11,12), + (1,12,3,2)(4,11,10,5)(6,9,8,7)} + + Some slightly longer computations in type `B_4`, working directly + with reduced words using the ``coxeter3`` implementation:: sage: W = CoxeterGroup('B4', implementation='coxeter3') # optional - coxeter3 sage: s1,s2,s3,s4 = W.simple_reflections() # optional - coxeter3 - sage: s1.kazhdan_lusztig_cell() # long time (4 seconds) # optional - coxeter3 + sage: s1.kazhdan_lusztig_cell(side='right') # long time (4 seconds) # optional - coxeter3 {[1], - [1, 2, 3, 4, 3, 2, 1], - [2, 1], - [2, 3, 4, 3, 2, 1], - [3, 2, 1], - [3, 4, 3, 2, 1], - [4, 3, 2, 1]} - sage: (s4*s2*s3*s4).kazhdan_lusztig_cell() # long time (2 seconds) # optional - coxeter3 - {[2, 3, 4, 1, 2, 3, 4], - [3, 4, 1, 2, 3, 4], - [3, 4, 2, 3, 4], - [3, 4, 2, 3, 4, 1, 2, 3, 4], - [4, 1, 2, 3, 4], - [4, 2, 3, 4], - [4, 2, 3, 4, 1, 2, 3, 4], - [4, 3, 4, 1, 2, 3, 4], - [4, 3, 4, 2, 3, 4], - [4, 3, 4, 2, 3, 4, 1, 2, 3, 4]} + [1, 2], + [1, 2, 3], + [1, 2, 3, 4], + [1, 2, 3, 4, 3], + [1, 2, 3, 4, 3, 2], + [1, 2, 3, 4, 3, 2, 1]} + sage: (s4*s2*s3*s4).kazhdan_lusztig_cell(side='two-sided') # long time (8 seconds) # optional - coxeter3 + {[2, 3, 1], + [2, 3, 1, 2], + [2, 3, 4, 1], + [2, 3, 4, 1, 2], + [2, 3, 4, 1, 2, 3], + [2, 3, 4, 1, 2, 3, 4], + [2, 3, 4, 3, 1], + [2, 3, 4, 3, 1, 2], + ... """ from sage.algebras.iwahori_hecke_algebra import IwahoriHeckeAlgebra from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing From 0137c82b840cc3a7f7fceaa28cd27875242bc11a Mon Sep 17 00:00:00 2001 From: Tianyuan Xu Date: Sat, 14 Aug 2021 14:56:08 -0600 Subject: [PATCH 097/511] doc string changes, more examples --- src/sage/categories/coxeter_groups.py | 82 +++++++++++++++++---------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index a87cee06315..e4cc7094cb0 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -692,11 +692,12 @@ def simple_projection(self, i, side='right', length_increasing=True): def kazhdan_lusztig_cells(self, side='left'): r""" Compute the left, right, or two-sided Kazhdan-Lusztig cells of - ``self`` by using + ``self`` if ``self`` is finite. + + The cells are computed by using :func:`kazhdan_lusztig_cell()`. - As detailed there, this function will be much more efficient if the - package ``coxeter3`` is installed, due to the method of computing - products in the `C^{\prime}` basis of the Iwahori--Hecke algebra. + As detailed there, installation of the optional package ``coxeter3`` is + strongly recommended (though not required) before using this function. EXAMPLES:: @@ -713,6 +714,11 @@ def kazhdan_lusztig_cells(self, side='left'): frozenset([[1, 3], [2, 1, 3]]), frozenset([[1], [2, 1], [3, 2, 1]]), frozenset([[]])]) + + TODO: do a permutation implementation of A3 and compute its + cells (so that people know that it's ok to not use the coxeter3 + implementation) + sage: W = CoxeterGroup('B4', implementation='coxeter3') # optional - coxeter3 sage: b4_cells = W.kazhdan_lusztig_cells() # long time (45 seconds) # optional - coxeter3 sage: len(b4_cells) # optional - coxeter3 @@ -2747,24 +2753,26 @@ def upper_covers(self, side='right', index_set=None): def kazhdan_lusztig_cell(self, side='left'): r""" Compute the left, right, or two-sided Kazhdan-Lusztig cell - containing the element ``self``. Computes left cells by default; use - the optional argument ``side`` to specify right or two-sided cells. - - Two elements `x,y` of a Coxeter group `W` are said lie in the same - left Kazhdan-Lusztig cell if there exist sequences `x=w_1, w_2, ..., - w_k=y` and `y=u_1, u_2, ..., u_l=x` such that for all `1 \leq i < k` - and all `1 \leq j < l`, there exist some Coxeter generators `s,t` - for which `C'_{w_{i+1}}` appears in `C'_sC'_{w_i}` and - `C'_{u_{j+1}}` appears in `C'_sC'_{u_j}` in the Hecke algebra of the - Coxeter group, where `C'` denotes the Kazhdan-Lusztig - `C^{\prime}`-basis. Right and two-sided Kazhdan-Lusztig cells of `W` - are defined similarly. + containing the element ``self`` depending on the specified + ``side``. + + Let `C'` denote the Kazhdan-Lusztig `C^{\prime}`-basis of the + Iwahori-Hecke algebra `H` of a Coxeter system `(W,S)`. Two elements + `x,y` of the Coxeter group `W` are said to lie in the same left + Kazhdan-Lusztig cell if there exist sequences `x=w_1, w_2, ..., + w_k=y` and `y=u_1, u_2, ..., u_l=x` such that for all `1 \leq i < + k` and all `1 \leq j < l`, there exist some Coxeter generators `s,t + \in S` for which `C'_{w_{i+1}}` appears in `C'_sC'_{w_i}` and + `C'_{u_{j+1}}` appears in `C'_sC'_{u_j}` in `H`. Right and + two-sided Kazhdan-Lusztig cells of `W` are defined similarly; see + [Lus2013]_. In this function, we compute products in the `C^{\prime}` basis by - using :class:`IwahoriHeckeAlgebra.Cp`. To use the direct algorithm - for computing such products detailed therein, the package - ``coxeter3`` must be installed; otherwise, this method will most - likely be computationally infeasible. + using :class:`IwahoriHeckeAlgebra.Cp`. As mentioned in that class, + installing the optional package ``coxeter3`` is strongly + recommended (though not required) before using this function, + because the package speeds up product computations that are + sometimes computationally infeasible without it. INPUT: @@ -2775,8 +2783,13 @@ def kazhdan_lusztig_cell(self, side='left'): EXAMPLES: - Some simple computations in type `A_3`; we use two different Coxeter - group implementations:: + We compute the left cell of the generator `s_1` in type `A_3` in + three different implementations of the Coxeter group. Note that the + choice of implementation affects the representation of elements in + the output cell but not the method used for the cell computation. + In particular, the cell computation uses the optional package + ``coxeter3`` in the background as long as it is installed, even in + the default (matrix) and 'permutation' implementations:: sage: W = CoxeterGroup('A3') # optional - coxeter3 sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 @@ -2790,19 +2803,30 @@ def kazhdan_lusztig_cell(self, side='left'): [-1 1 0] [ 0 1 0] [ 0 0 1]} + sage: W = CoxeterGroup('A3', implementation='permutation') # optional - coxeter3 sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 {(1,2,3,12)(4,5,10,11)(6,7,8,9), (1,2,10)(3,6,5)(4,7,8)(9,12,11), (1,7)(2,4)(5,6)(8,10)(11,12)} - sage: s1.kazhdan_lusztig_cell(side='right') # optional - coxeter3 - {(1,7)(2,4)(5,6)(8,10)(11,12), - (1,10,2)(3,5,6)(4,8,7)(9,11,12), - (1,12,3,2)(4,11,10,5)(6,9,8,7)} - Some slightly longer computations in type `B_4`, working directly - with reduced words using the ``coxeter3`` implementation:: + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 + sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 + TODO: add output + + Next, we compute a right cell and a two-sided cell in `A_3`:: + + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 + sage: w = s1*s3 + sage: w.kazhdan_lusztig_cell(side='right') # optional - coxeter3 + TODO: add output + sage: w.kazhdan_lusztig_cell(side='two-sided') # optional - coxeter3 + TODO: add output + + Some slightly longer computations in `B_4`:: sage: W = CoxeterGroup('B4', implementation='coxeter3') # optional - coxeter3 sage: s1,s2,s3,s4 = W.simple_reflections() # optional - coxeter3 @@ -2858,4 +2882,4 @@ def kazhdan_lusztig_cell(self, side='left'): queue.appendleft(y) g = DiGraph([list(vertices), list(edges)]) - return set(g.strongly_connected_component_containing_vertex(w)) \ No newline at end of file + return set(g.strongly_connected_component_containing_vertex(w)) From 35308531866b23360a29dbbd09d7bb02d6973c0c Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 14 Aug 2021 17:09:39 -0600 Subject: [PATCH 098/511] Complete docstrings --- src/sage/categories/coxeter_groups.py | 85 ++++++++++++++++----------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index e4cc7094cb0..12e09797a38 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -693,13 +693,16 @@ def kazhdan_lusztig_cells(self, side='left'): r""" Compute the left, right, or two-sided Kazhdan-Lusztig cells of ``self`` if ``self`` is finite. - + The cells are computed by using :func:`kazhdan_lusztig_cell()`. - As detailed there, installation of the optional package ``coxeter3`` is - strongly recommended (though not required) before using this function. + As detailed there, installation of the optional package ``coxeter3`` + is strongly recommended (though not required) before using this + function. - EXAMPLES:: + EXAMPLES: + + Compute the left cells in `A_3`:: sage: from sage.doctest.fixtures import reproducible_repr # optional - coxeter3 sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 @@ -715,9 +718,22 @@ def kazhdan_lusztig_cells(self, side='left'): frozenset([[1], [2, 1], [3, 2, 1]]), frozenset([[]])]) - TODO: do a permutation implementation of A3 and compute its - cells (so that people know that it's ok to not use the coxeter3 - implementation) + Note that the choice of implementation affects the representation of + elements in the output cell but not the method used for the cell + computation. In particular, the cell computation uses the optional + package ``coxeter3`` in the background as long as it is installed, + even in the default (matrix) and 'permutation' implementations:: + + sage: W = CoxeterGroup('A3', implementation='permutation') # optional - coxeter3 + sage: print(reproducible_repr(W.kazhdan_lusztig_cells())) # optional - coxeter3 + set([frozenset([()]), + frozenset([(1,10,2)(3,5,6)(4,8,7)(9,11,12), (1,4)(2,8)(3,5)(7,10)(9,11), (1,4,6)(2,3,11)(5,8,9)(7,10,12)]), + frozenset([(1,10,9,5)(2,6,8,12)(3,11,7,4), (1,3)(2,12)(4,10)(5,11)(6,8)(7,9)]), + frozenset([(1,11)(3,10)(4,9)(5,7)(6,12), (1,11,8)(2,7,5)(3,4,12)(6,9,10), (1,5,12)(2,9,4)(3,10,8)(6,7,11)]), + ... + frozenset([(1,9)(2,8)(3,7)(4,11)(5,10)(6,12)])]) + + Computing the left cells in `B_4` takes about 45 seconds:: sage: W = CoxeterGroup('B4', implementation='coxeter3') # optional - coxeter3 sage: b4_cells = W.kazhdan_lusztig_cells() # long time (45 seconds) # optional - coxeter3 @@ -729,6 +745,7 @@ def kazhdan_lusztig_cells(self, side='left'): frozenset([[1, 2, 3, 4, 3], [1, 2, 3], [2, 3, 4, 3], [2, 3], [3, 4, 3], [3], [4, 3]]), frozenset([[1, 2, 3, 4], [2, 3, 4], [3, 4], [4, 3, 4], [4]]), ... + frozenset([[]])]) TESTS:: @@ -740,7 +757,7 @@ def kazhdan_lusztig_cells(self, side='left'): """ if not self.coxeter_type().is_finite(): raise ValueError('the Coxeter group must be finite to compute Kazhdan--Lusztig cells') - + # The identity is its own left-, right-, and two-sided- cell. identity = frozenset([self.one()]) cells = {identity} @@ -749,7 +766,7 @@ def kazhdan_lusztig_cells(self, side='left'): if not any(w in c for c in cells): cell = w.kazhdan_lusztig_cell(side=side) cells.add(frozenset(cell)) - + return cells @cached_method @@ -817,7 +834,7 @@ def sign_representation(self, base_ring=None, side="twosided"): sage: W = WeylGroup(["A", 1, 1]) sage: W.sign_representation() Sign representation of Weyl Group of type ['A', 1, 1] (as a matrix group acting on the root space) over Integer Ring - + """ if base_ring is None: from sage.rings.integer_ring import ZZ @@ -2753,26 +2770,25 @@ def upper_covers(self, side='right', index_set=None): def kazhdan_lusztig_cell(self, side='left'): r""" Compute the left, right, or two-sided Kazhdan-Lusztig cell - containing the element ``self`` depending on the specified - ``side``. + containing the element ``self`` depending on the specified ``side``. Let `C'` denote the Kazhdan-Lusztig `C^{\prime}`-basis of the Iwahori-Hecke algebra `H` of a Coxeter system `(W,S)`. Two elements `x,y` of the Coxeter group `W` are said to lie in the same left Kazhdan-Lusztig cell if there exist sequences `x=w_1, w_2, ..., - w_k=y` and `y=u_1, u_2, ..., u_l=x` such that for all `1 \leq i < - k` and all `1 \leq j < l`, there exist some Coxeter generators `s,t - \in S` for which `C'_{w_{i+1}}` appears in `C'_sC'_{w_i}` and + w_k=y` and `y=u_1, u_2, ..., u_l=x` such that for all `1 \leq i < k` + and all `1 \leq j < l`, there exist some Coxeter generators `s,t \in + S` for which `C'_{w_{i+1}}` appears in `C'_sC'_{w_i}` and `C'_{u_{j+1}}` appears in `C'_sC'_{u_j}` in `H`. Right and two-sided Kazhdan-Lusztig cells of `W` are defined similarly; see [Lus2013]_. In this function, we compute products in the `C^{\prime}` basis by using :class:`IwahoriHeckeAlgebra.Cp`. As mentioned in that class, - installing the optional package ``coxeter3`` is strongly - recommended (though not required) before using this function, - because the package speeds up product computations that are - sometimes computationally infeasible without it. + installing the optional package ``coxeter3`` is strongly recommended + (though not required) before using this function, because the + package speeds up product computations that are sometimes + computationally infeasible without it. INPUT: @@ -2786,10 +2802,10 @@ def kazhdan_lusztig_cell(self, side='left'): We compute the left cell of the generator `s_1` in type `A_3` in three different implementations of the Coxeter group. Note that the choice of implementation affects the representation of elements in - the output cell but not the method used for the cell computation. - In particular, the cell computation uses the optional package + the output cell but not the method used for the cell computation. In + particular, the cell computation uses the optional package ``coxeter3`` in the background as long as it is installed, even in - the default (matrix) and 'permutation' implementations:: + the default (matrix) and 'permutation' implementations:: sage: W = CoxeterGroup('A3') # optional - coxeter3 sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 @@ -2803,28 +2819,26 @@ def kazhdan_lusztig_cell(self, side='left'): [-1 1 0] [ 0 1 0] [ 0 0 1]} - sage: W = CoxeterGroup('A3', implementation='permutation') # optional - coxeter3 sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 {(1,2,3,12)(4,5,10,11)(6,7,8,9), (1,2,10)(3,6,5)(4,7,8)(9,12,11), (1,7)(2,4)(5,6)(8,10)(11,12)} - - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 - sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 - TODO: add output + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 + sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 + {[1], [2, 1], [3, 2, 1]} Next, we compute a right cell and a two-sided cell in `A_3`:: - - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 + + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 sage: w = s1*s3 - sage: w.kazhdan_lusztig_cell(side='right') # optional - coxeter3 - TODO: add output - sage: w.kazhdan_lusztig_cell(side='two-sided') # optional - coxeter3 - TODO: add output + sage: w.kazhdan_lusztig_cell(side='right') # optional - coxeter3 + {[1, 3], [1, 3, 2]} + sage: w.kazhdan_lusztig_cell(side='two-sided') # optional - coxeter3 + {[1, 3], [1, 3, 2], [2, 1, 3], [2, 1, 3, 2]} Some slightly longer computations in `B_4`:: @@ -2848,6 +2862,7 @@ def kazhdan_lusztig_cell(self, side='left'): [2, 3, 4, 3, 1], [2, 3, 4, 3, 1, 2], ... + [4, 3, 4, 2, 3, 4, 1, 2, 3, 4]} """ from sage.algebras.iwahori_hecke_algebra import IwahoriHeckeAlgebra from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing From 7a73b82edb3ad184955829a73ec66ba74c7a9724 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 14 Aug 2021 17:14:13 -0600 Subject: [PATCH 099/511] Document 'side' arguments --- src/sage/categories/coxeter_groups.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 12e09797a38..12b4cfd1724 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -700,6 +700,11 @@ def kazhdan_lusztig_cells(self, side='left'): is strongly recommended (though not required) before using this function. + INPUT: + + - ``side`` -- ``'left'``, ``'right'``, or ``'two-sided'`` (default: + ``'left'``) + EXAMPLES: Compute the left cells in `A_3`:: @@ -2794,8 +2799,8 @@ def kazhdan_lusztig_cell(self, side='left'): - ``w`` -- an element of self. - - ``side`` -- string (default: ``'left'``); one of 'left', 'right', - or 'two-sided', corresponding to the kind of cell to compute. + - ``side`` -- ``'left'``, ``'right'``, or ``'two-sided'`` (default: + ``'left'``), corresponding to the kind of cell to compute. EXAMPLES: From 1070fd42ae2edd4d13c701bb976f42c3c9f9814f Mon Sep 17 00:00:00 2001 From: Tianyuan Xu Date: Sat, 14 Aug 2021 17:43:59 -0600 Subject: [PATCH 100/511] doc string changes to cells function --- src/sage/categories/coxeter_groups.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 12b4cfd1724..47e533dce90 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -707,7 +707,15 @@ def kazhdan_lusztig_cells(self, side='left'): EXAMPLES: - Compute the left cells in `A_3`:: + We compute the left cells in the Coxeter group of type `A_3` below. + Note that each Coxeter group may be created with multiple + implementations, namely, 'reflection' (default), 'permutation', + 'matrix', or 'coxeter3'. The choice of implementation affects the + representation of elements in the output cells but not the method + used for the cell computation. In particular, the cell computation + uses the optional package ``coxeter3`` in the background as long as + the package is installed, even if the group is not created with the + 'coxeter3' implementation. sage: from sage.doctest.fixtures import reproducible_repr # optional - coxeter3 sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 @@ -722,13 +730,7 @@ def kazhdan_lusztig_cells(self, side='left'): frozenset([[1, 3], [2, 1, 3]]), frozenset([[1], [2, 1], [3, 2, 1]]), frozenset([[]])]) - - Note that the choice of implementation affects the representation of - elements in the output cell but not the method used for the cell - computation. In particular, the cell computation uses the optional - package ``coxeter3`` in the background as long as it is installed, - even in the default (matrix) and 'permutation' implementations:: - + sage: W = CoxeterGroup('A3', implementation='permutation') # optional - coxeter3 sage: print(reproducible_repr(W.kazhdan_lusztig_cells())) # optional - coxeter3 set([frozenset([()]), @@ -2809,8 +2811,8 @@ def kazhdan_lusztig_cell(self, side='left'): choice of implementation affects the representation of elements in the output cell but not the method used for the cell computation. In particular, the cell computation uses the optional package - ``coxeter3`` in the background as long as it is installed, even in - the default (matrix) and 'permutation' implementations:: + ``coxeter3`` in the background as long as the package is installed, even in + the default ('reflection') and 'permutation' implementations:: sage: W = CoxeterGroup('A3') # optional - coxeter3 sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 From 8a3d7593ca30b6694cd15711bc88afa46468ebc4 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Sat, 14 Aug 2021 17:46:26 -0600 Subject: [PATCH 101/511] Format docstrings --- src/sage/categories/coxeter_groups.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 47e533dce90..b1c3aab33fb 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -730,7 +730,6 @@ def kazhdan_lusztig_cells(self, side='left'): frozenset([[1, 3], [2, 1, 3]]), frozenset([[1], [2, 1], [3, 2, 1]]), frozenset([[]])]) - sage: W = CoxeterGroup('A3', implementation='permutation') # optional - coxeter3 sage: print(reproducible_repr(W.kazhdan_lusztig_cells())) # optional - coxeter3 set([frozenset([()]), @@ -2811,8 +2810,9 @@ def kazhdan_lusztig_cell(self, side='left'): choice of implementation affects the representation of elements in the output cell but not the method used for the cell computation. In particular, the cell computation uses the optional package - ``coxeter3`` in the background as long as the package is installed, even in - the default ('reflection') and 'permutation' implementations:: + ``coxeter3`` in the background as long as the package is installed, + even in the default ('reflection') and 'permutation' + implementations:: sage: W = CoxeterGroup('A3') # optional - coxeter3 sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 From f0fb7e245bb0594bfccf27b50a62807d459f6ccd Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 16 Aug 2021 10:36:16 +1000 Subject: [PATCH 102/511] Adding back build/pkgs/sage_sws2rst/src file. --- build/pkgs/sage_sws2rst/src | 1 + 1 file changed, 1 insertion(+) create mode 120000 build/pkgs/sage_sws2rst/src diff --git a/build/pkgs/sage_sws2rst/src b/build/pkgs/sage_sws2rst/src new file mode 120000 index 00000000000..2de26d80e1e --- /dev/null +++ b/build/pkgs/sage_sws2rst/src @@ -0,0 +1 @@ +../../../pkgs/sage-sws2rst \ No newline at end of file From 67c7b3ab302e8d1db3091fda70f7153695020697 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 16 Aug 2021 11:27:48 +1000 Subject: [PATCH 103/511] Reviewer changes to improve speed and other various doc tweaks. --- src/sage/algebras/iwahori_hecke_algebra.py | 228 +++++++++++---------- src/sage/categories/coxeter_groups.py | 149 +++++++------- 2 files changed, 198 insertions(+), 179 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index c6628f341f4..4e64e3bfe90 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1862,9 +1862,9 @@ class Cp(_KLHeckeBasis): .. MATH:: \begin{aligned} - \overline{ C^{\prime}_w } &= C^{\prime}_w\\ + \overline{ C^{\prime}_w } &= C^{\prime}_w, \\ C^{\prime}_w &= q^{-\ell(w)/2} - \sum_{v \leq w} P_{v,w}(q) T_v + \sum_{v \leq w} P_{v,w}(q) T_v, \end{aligned} where `\leq` is the Bruhat order on the underlying Coxeter group and @@ -1891,8 +1891,8 @@ class Cp(_KLHeckeBasis): calculate certain `\mu`-coefficients quickly. If the above conditions are not all met, the function computes such products indirectly, by converting elements to the `T`-basis, computing products there, and - converting back. The indirect method can be prohibitively slow for more - complex calculations; the direct method is faster. + converting back. The indirect method can be prohibitively slow for + more complex calculations; the direct method is faster. EXAMPLES:: @@ -1984,44 +1984,42 @@ def __init__(self, IHAlgebra, prefix=None): r""" TESTS:: - sage: R = LaurentPolynomialRing(QQ, 'v') # optional - coxeter3 - sage: v = R.gen(0) # optional - coxeter3 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 - sage: Cp = H.Cp() # optional - coxeter3 - sage: Cp.delta == v + ~v # optional - coxeter3 + sage: R. = LaurentPolynomialRing(QQ) # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 + sage: Cp = H.Cp() # optional - coxeter3 + sage: Cp._delta == v + ~v # optional - coxeter3 True - sage: Cp._W_Coxeter3 == H._W # optional - coxeter3 + sage: Cp._W_Coxeter3 == H._W # optional - coxeter3 True - sage: H = IwahoriHeckeAlgebra(W, QQ(1)) # optional - coxeter3 - sage: Cp = H.Cp() # optional - coxeter3 - sage: Cp.delta == None # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, QQ(1)) # optional - coxeter3 + sage: Cp = H.Cp() # optional - coxeter3 + sage: Cp._W_Coxeter3 is None # optional - coxeter3 True """ super().__init__(IHAlgebra, prefix) - self.delta = None self._W_Coxeter3 = None # See if we meet the conditions to use the direct product_on_basis algorithm. - # If we do, both of these will be non-None. - + # To use v + ~v as the value delta, we need the standard or + # normalized presentations of the Hecke algebra. v = IHAlgebra.base_ring().gen(0) parameters = {IHAlgebra.q1(), IHAlgebra.q2()} - if v != IHAlgebra.base_ring().one() and (parameters == {v**2, -1} or parameters == {v, -1/v}): - # The following quantity delta is used in product computations. - # To use v+~v as its value we need the standard or normalized presentations of the Hecke algebra. - self.delta = v + ~v + if v == IHAlgebra.base_ring().one() or (parameters != {v**2, -1} and parameters != {v, -1/v}): + return - # check if products can be computed directly using ``coxeter3``: + # check if products can be computed directly using ``coxeter3`` try: from sage.libs.coxeter3.coxeter_group import CoxeterGroup as Coxeter3Group - if isinstance(IHAlgebra._W, Coxeter3Group): - self._W_Coxeter3 = IHAlgebra._W - else: - self._W_Coxeter3 = CoxeterGroup(IHAlgebra._W.coxeter_type(), implementation='coxeter3') except ImportError: - pass + return + + self._delta = v + ~v + if isinstance(IHAlgebra._W, Coxeter3Group): + self._W_Coxeter3 = IHAlgebra._W + else: + self._W_Coxeter3 = CoxeterGroup(IHAlgebra._W.coxeter_type(), implementation='coxeter3') def hash_involution_on_basis(self, w): r""" @@ -2046,8 +2044,8 @@ def hash_involution_on_basis(self, w): def product_on_basis(self, w1, w2): r""" - Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` in - the `C^{\prime}`-basis. + Return the expansion of `C^{\prime}_{w_1} \cdot C^{\prime}_{w_2}` + in the `C^{\prime}`-basis. If ``coxeter3`` is installed and the Iwahori--Hecke algebra is in the standard or normalized presentation, the product is computed @@ -2065,15 +2063,17 @@ def product_on_basis(self, w1, w2): .. MATH:: C^{\prime}_s \cdot C^{\prime}_w = \begin{cases} - (q+q^{-1})C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ - C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, - & \text{if } \ell(sw) = \ell(w)+1. - \end{cases} + (q+q^{-1})C^{\prime}_{w}, & \text{if } \ell(sw) = \ell(w)-1,\\ + C^{\prime}_{sw}+\sum_{v\leq w, sv \leq v} \mu(v,w)C^{\prime}_v, + & \text{if } \ell(sw) = \ell(w)+1. + \end{cases} + + \qquad\qquad C^{\prime}_w \cdot C^{\prime}_s = \begin{cases} - (q+q^{-1})C^{\prime}_{w}, & \text{if } \ell(ws) = \ell(w)-1,\\ - C^{\prime}_{ws}+\sum_{v\leq w, vs \leq v} \mu(v,w)C^{\prime}_v, - & \text{if } \ell(ws) = \ell(w)+1. + (q+q^{-1})C^{\prime}_{w}, & \text{if } \ell(ws) = \ell(w)-1,\\ + C^{\prime}_{ws}+\sum_{v\leq w, vs \leq v} \mu(v,w)C^{\prime}_v, + & \text{if } \ell(ws) = \ell(w)+1. \end{cases} In the above, `\leq` is the Bruhat order on the Coxeter group and @@ -2082,15 +2082,15 @@ def product_on_basis(self, w1, w2): method designates the computation of the `\mu`-coefficients to Sage's interface to Fokko du Cloux's ``coxeter3`` package, which is why the method requires the creation of the Coxeter group using the - 'coxeter3' implementation. + ``'coxeter3'`` implementation. ALGORITHM: The direct algorithm for computing `C^{\prime}_x \cdot C^{\prime}_y` runs in two steps as follows. - If `\ell(x) \leq \ell(y)`, we first decompose `C^{\prime}_x` into a - polynomial in the generators `C^{\prime}_s (s\in S)` and then + If `\ell(x) \leq \ell(y)`, we first decompose `C^{\prime}_x` into + a polynomial in the generators `C^{\prime}_s (s\in S)` and then multiply that polynomial with `C^{\prime}_y`. If `\ell(x) > \ell(y)`, we decompose `C^{\prime}_y` into a polynomial in `C^{\prime}_s (s\in S)` and multiply that polynomial with @@ -2103,7 +2103,8 @@ def product_on_basis(self, w1, w2): .. MATH:: - C^{\prime}_u = C^{\prime}_s \cdot C^{\prime}_{w} - \sum_{v\le u; sv< v} \mu(v,w) C^{\prime}_v + C^{\prime}_u = C^{\prime}_s \cdot C^{\prime}_{w} + - \sum_{v \le u; sv < v} \mu(v,w) C^{\prime}_v by the earlier formulas, where the element `w` and all elements `v`'s on the right side are lower than `u` in the Bruhat order; @@ -2116,7 +2117,8 @@ def product_on_basis(self, w1, w2): .. MATH:: - C^{\prime}_{121} = C^{\prime}_1 C^{\prime}_2 C^{\prime}_1 - C^{\prime}_1. + C^{\prime}_{121} = C^{\prime}_1 C^{\prime}_2 C^{\prime}_1 + - C^{\prime}_1. We note that the base cases `\ell(x)=1` or `\ell(x)=0` of the above induction occur when `x` is itself a Coxeter generator `s` or the @@ -2134,14 +2136,14 @@ def product_on_basis(self, w1, w2): sage: Cp.product_on_basis(W([1,2,1]), W([3,1,2])) # optional - coxeter3 (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] """ - if self.delta is None or self._W_Coxeter3 is None: + if self._W_Coxeter3 is None: # We do not meet the conditions to use the direct product # algorithm; fall back to conversion to/from the T-basis. return super().product_on_basis(w1, w2) # If self._W_Coxeter3 is not the underlying Coxeter group, we need # to convert elements first for this algorithm. - if (self._W_Coxeter3 != self.realization_of()._W): + if self._W_Coxeter3 != self.realization_of()._W: w1 = self._W_Coxeter3.from_reduced_word(w1.reduced_word()) w2 = self._W_Coxeter3.from_reduced_word(w2.reduced_word()) @@ -2149,99 +2151,103 @@ def product_on_basis(self, w1, w2): # generators C'_{s}. if len(w1) <= len(w2): side = 'left' - gen_expression = self.decompose_into_generators(w1) + gen_expression = self._decompose_into_generators(w1) other_element = self.monomial(w2) else: side = 'right' - gen_expression = self.decompose_into_generators(w2) + gen_expression = self._decompose_into_generators(w2) other_element = self.monomial(w1) - result = self(0) + # Multiplication: multiply the generators in each term of the above # polynomial onto other_element and add that summand onto result. + result = self.zero() for (p, coeff) in gen_expression.items(): summand = coeff * other_element - p_list = list(p) if side == 'right' else list(p)[::-1] - for s in p_list: - summand = self.product_with_generator(s, summand, side) + if side == 'right': + for s in p: + summand = self._product_with_generator(s, summand, side) + else: + for s in reversed(p): + summand = self._product_with_generator(s, summand, side) result += summand # Again, if self._W_Coxeter3 is not the underlying Coxeter group, # we need to convert the result. Specifically, make sure basis # elements appearing therein are actually indexed by elements of # the original underlying Coxeter group. - - if (self._W_Coxeter3 != self.realization_of()._W): + if self._W_Coxeter3 != self.realization_of()._W: _W = self.realization_of()._W - result = self.linear_combination((self(_W.from_reduced_word(w.reduced_word())), c) for (w, c) in result) + result = self._from_dict({_W.from_reduced_word(w.reduced_word()): c + for (w, c) in result}, remove_zeros=False) return result - def product_with_generator_on_basis(self, s, w, side='left'): + def _product_with_generator_on_basis(self, s, w, side='left'): r""" Compute the product of `C^{\prime}_s` and `C^{\prime}_w`, putting `C^{\prime}_s` on the given ``side``. INPUT: - - ``s`` -- integer in self.index_set() - - - ``w`` -- a word in self.coxeter_group() - + - ``s`` -- integer in ``self.index_set()`` + - ``w`` -- a word in ``self.coxeter_group()`` - ``side`` -- string; ``'left'`` or ``'right'`` EXAMPLES:: - sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 - sage: Cp.product_with_generator_on_basis(1, W([2,1]), 'left') # optional - coxeter3 + sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp = H.Cp() # optional - coxeter3 + sage: Cp._product_with_generator_on_basis(1, W([2,1]), 'left') # optional - coxeter3 Cp[1,2,1] + Cp[1] - sage: Cp.product_with_generator_on_basis(1, W([2,1]), 'right') # optional - coxeter3 + sage: Cp._product_with_generator_on_basis(1, W([2,1]), 'right') # optional - coxeter3 (v^-1+v)*Cp[2,1] - sage: Cp.product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') # optional - coxeter3 + sage: Cp._product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') # optional - coxeter3 Cp[1,2,1,3,2,1] + Cp[1,2,3,2] + Cp[1,3,2,1] """ # use the product formula described in the class' documentation if w.has_descent(s, side=side): - return self.delta * self.monomial(w) - else: - element = self(0) - between = self._W_Coxeter3.bruhat_interval([], w) - for x in between: - # Get (coxeter3-implemented) group element corresponding to x - x_elt = self._W_Coxeter3(x) - if x_elt.has_descent(s, side=side): - # Compute mu-coefficient via coxeter3 - element += x.mu_coefficient(w) * self.monomial(x_elt) - longer_word = self._W_Coxeter3([s]) * w if side == 'left' else w * self._W_Coxeter3([s]) - return self.monomial(longer_word) + element - - def product_with_generator(self, s, x, side='left'): + return self._from_dict({w: self._delta}, remove_zeros=False) + + element = {} + between = self._W_Coxeter3.bruhat_interval([], w) + R = self.base_ring() + for x in between: + # Get (coxeter3-implemented) group element corresponding to x + x_elt = self._W_Coxeter3(x) + if x_elt.has_descent(s, side=side): + # Compute mu-coefficient via coxeter3 + coeff = R(x.mu_coefficient(w)) + if coeff: + element[x_elt] = coeff + longer_word = self._W_Coxeter3([s]) * w if side == 'left' else w * self._W_Coxeter3([s]) + element[longer_word] = R.one() + return self._from_dict(element, remove_zeros=False) + + def _product_with_generator(self, s, x, side='left'): r""" - Compute the product of `C^{\prime}_s` with any linear combination of - `C^{\prime}`-basis elements. + Compute the product of `C^{\prime}_s` with any linear + combination of `C^{\prime}`-basis elements. INPUT: - - ``s`` -- integer in self.index_set() - - - ``x`` -- any element of self - + - ``s`` -- integer in ``self.index_set()`` + - ``x`` -- any element of ``self`` - ``side`` -- string; ``'left'`` or ``'right'`` EXAMPLES:: sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 - sage: Cp.product_with_generator(1, Cp[1]+Cp[2], 'left') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp = H.Cp() # optional - coxeter3 + sage: Cp._product_with_generator(1, Cp[1]+Cp[2], 'left') # optional - coxeter3 Cp[1,2] + (v^-1+v)*Cp[1] - sage: Cp.product_with_generator(1, Cp[1]+Cp[2], 'right') # optional - coxeter3 + sage: Cp._product_with_generator(1, Cp[1]+Cp[2], 'right') # optional - coxeter3 Cp[2,1] + (v^-1+v)*Cp[1] """ - return self.linear_combination((self.product_with_generator_on_basis(s, w, side), coeff) for (w, coeff) in x) + return self.linear_combination((self._product_with_generator_on_basis(s, w, side), coeff) for (w, coeff) in x) - def decompose_into_generators(self, u): + def _decompose_into_generators(self, u): r""" Decompose `C^{\prime}_u` into a polynomial in the KL generators `C^{\prime}_s`; see the ALGORITHM section of @@ -2250,40 +2256,38 @@ def decompose_into_generators(self, u): OUTPUT: A dictionary keyed by tuples with integer values. Each entry - represents a term, where the tuple represents a monomial term in the - KL generators and the value represents the coefficient of that term. - For example, an item `(1,2): 3` stands for `3 \cdot - C^{\prime}_1C^{\prime}_2`. + represents a term, where the tuple represents a monomial term + in the KL generators and the value represents the coefficient + of that term. For example, an item `(1,2): 3` stands for + `3 \cdot C^{\prime}_1 C^{\prime}_2`. - EXAMPLES: - - :: + EXAMPLES:: - sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 + sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 When `u` is itself a generator `s`, the decomposition is trivial:: - sage: Cp.decompose_into_generators(W([1])) # optional - coxeter3 + sage: Cp._decompose_into_generators(W([1])) # optional - coxeter3 {(1,): 1} Another example, where `C^{\prime}_u` happens to be a monomial (e.g., `C'_{21} = C'_2 C'_1`):: - sage: Cp.decompose_into_generators(W([2,1])) # optional - coxeter3 + sage: Cp._decompose_into_generators(W([2,1])) # optional - coxeter3 {(2, 1): 1} In more general situations the sum is a polynomial (e.g., - `C'_{121}=C'_1 C'_2 C'_1 - C'_1)`:: + `C'_{121} = C'_1 C'_2 C'_1 - C'_1)`:: - sage: Cp.decompose_into_generators(W([1,2,1])) # optional - coxeter3 + sage: Cp._decompose_into_generators(W([1,2,1])) # optional - coxeter3 {(1,): -1, (1, 2, 1): 1} - sage: Cp.decompose_into_generators(W([1,2,3,1,2])) # optional - coxeter3 + sage: Cp._decompose_into_generators(W([1,2,3,1,2])) # optional - coxeter3 {(1,): 1, (1, 2, 1): -1, (1, 2, 1, 3, 2): 1, (1, 3, 2): -1} """ # l(y) = 0 or 1 - if len(u) == 0: + if not u: return {(): 1} if len(u) == 1: return {(u[0],): 1} @@ -2293,21 +2297,25 @@ def decompose_into_generators(self, u): w = u[1:] # so CpC_s * CpC_w = CpC_u + lower order terms # get the lower order terms ("sum_term") - sum_term = self(0) + sum_term = {} between = self._W_Coxeter3.bruhat_interval([], w) + R = self.base_ring() for v in between: # Get (coxeter3-implemented) group element corresponding to v v_elt = self._W_Coxeter3(v) if v_elt.has_left_descent(s): # Compute mu-coefficient via coxeter3 - sum_term += self.base_ring()(v.mu_coefficient(w)) * self.monomial(v_elt) + coeff = R(v.mu_coefficient(w)) + if coeff: + sum_term[v_elt] = coeff # recursion: decompose C'_s * C'_w and the lower order terms - result = {(s,) + gens: coeff for (gens, coeff) in self.decompose_into_generators(w).items()} - for (z, c1) in sum_term: + result = {(s,) + gens: coeff for (gens, coeff) in self._decompose_into_generators(w).items()} + zero = R.zero() + for (z, c1) in sum_term.items(): # Subtract off each term from sum_term. - for (gens, c2) in self.decompose_into_generators(z).items(): - result[gens] = result.get(gens, 0) - c1*c2 + for (gens, c2) in self._decompose_into_generators(z).items(): + result[gens] = result.get(gens, zero) - c1 * c2 return result diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index b1c3aab33fb..19be6f43df2 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -694,16 +694,16 @@ def kazhdan_lusztig_cells(self, side='left'): Compute the left, right, or two-sided Kazhdan-Lusztig cells of ``self`` if ``self`` is finite. - The cells are computed by using - :func:`kazhdan_lusztig_cell()`. + The cells are computed by using :func:`kazhdan_lusztig_cell() + `. + As detailed there, installation of the optional package ``coxeter3`` - is strongly recommended (though not required) before using this - function. + is recommended (though not required) before using this function. INPUT: - - ``side`` -- ``'left'``, ``'right'``, or ``'two-sided'`` (default: - ``'left'``) + - ``side`` -- (default: ``'left'``) either ``'left'``, + ``'right'``, or ``'two-sided'`` EXAMPLES: @@ -717,41 +717,60 @@ def kazhdan_lusztig_cells(self, side='left'): the package is installed, even if the group is not created with the 'coxeter3' implementation. - sage: from sage.doctest.fixtures import reproducible_repr # optional - coxeter3 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: print(reproducible_repr(W.kazhdan_lusztig_cells())) # optional - coxeter3 - set([frozenset([[1, 2, 1, 3, 2, 1]]), - frozenset([[1, 2, 1, 3, 2], [1, 2, 3, 2], [2, 3, 2]]), - frozenset([[1, 2, 1, 3], [1, 2, 3, 2, 1], [2, 3, 2, 1]]), - frozenset([[1, 2, 1], [1, 3, 2, 1], [2, 1, 3, 2, 1]]), - frozenset([[1, 2, 3], [2, 3], [3]]), - frozenset([[1, 2], [2], [3, 2]]), - frozenset([[1, 3, 2], [2, 1, 3, 2]]), - frozenset([[1, 3], [2, 1, 3]]), - frozenset([[1], [2, 1], [3, 2, 1]]), - frozenset([[]])]) - sage: W = CoxeterGroup('A3', implementation='permutation') # optional - coxeter3 - sage: print(reproducible_repr(W.kazhdan_lusztig_cells())) # optional - coxeter3 - set([frozenset([()]), - frozenset([(1,10,2)(3,5,6)(4,8,7)(9,11,12), (1,4)(2,8)(3,5)(7,10)(9,11), (1,4,6)(2,3,11)(5,8,9)(7,10,12)]), - frozenset([(1,10,9,5)(2,6,8,12)(3,11,7,4), (1,3)(2,12)(4,10)(5,11)(6,8)(7,9)]), - frozenset([(1,11)(3,10)(4,9)(5,7)(6,12), (1,11,8)(2,7,5)(3,4,12)(6,9,10), (1,5,12)(2,9,4)(3,10,8)(6,7,11)]), - ... - frozenset([(1,9)(2,8)(3,7)(4,11)(5,10)(6,12)])]) + :: + + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: KL_cells = W.kazhdan_lusztig_cells() # optional - coxeter3 + sage: set([tuple(sorted(C)) for C in KL_cells]) # optional - coxeter3 + {([],), + ([1], [2, 1], [3, 2, 1]), + ([1, 2], [2], [3, 2]), + ([1, 2, 1], [1, 3, 2, 1], [2, 1, 3, 2, 1]), + ([1, 2, 1, 3], [1, 2, 3, 2, 1], [2, 3, 2, 1]), + ([1, 2, 1, 3, 2], [1, 2, 3, 2], [2, 3, 2]), + ([1, 2, 1, 3, 2, 1],), + ([1, 2, 3], [2, 3], [3]), + ([1, 3], [2, 1, 3]), + ([1, 3, 2], [2, 1, 3, 2])} + sage: len(KL_cells) + 10 - Computing the left cells in `B_4` takes about 45 seconds:: + sage: W = CoxeterGroup('A3', implementation='permutation') # optional - coxeter3 + sage: len(W.kazhdan_lusztig_cells()) # optional - coxeter3 + 10 - sage: W = CoxeterGroup('B4', implementation='coxeter3') # optional - coxeter3 - sage: b4_cells = W.kazhdan_lusztig_cells() # long time (45 seconds) # optional - coxeter3 - sage: len(b4_cells) # optional - coxeter3 - 50 - sage: print(reproducible_repr(b4_cells)) # optional - coxeter3 - set([frozenset([[1, 2, 3, 4, 3, 2, 1], [1], [2, 1], [2, 3, 4, 3, 2, 1], [3, 2, 1], [3, 4, 3, 2, 1], [4, 3, 2, 1]]), - frozenset([[1, 2, 3, 4, 3, 2], [1, 2], [2, 3, 4, 3, 2], [2], [3, 2], [3, 4, 3, 2], [4, 3, 2]]), - frozenset([[1, 2, 3, 4, 3], [1, 2, 3], [2, 3, 4, 3], [2, 3], [3, 4, 3], [3], [4, 3]]), - frozenset([[1, 2, 3, 4], [2, 3, 4], [3, 4], [4, 3, 4], [4]]), - ... - frozenset([[]])]) + Computing the two sided cells in `B_3`:: + + sage: W = CoxeterGroup('B3', implementation='coxeter3') # optional - coxeter3 + sage: b3_cells = W.kazhdan_lusztig_cells('two-sided') # optional - coxeter3 + sage: len(b3_cells) # optional - coxeter3 + 6 + sage: set([tuple(sorted(C)) for C in W.kazhdan_lusztig_cells()]) # optional - coxeter3 + {([],), + ([1], [1, 2, 3, 2, 1], [2, 1], [2, 3, 2, 1], [3, 2, 1]), + ([1, 2], [1, 2, 3, 2], [2], [2, 3, 2], [3, 2]), + ([1, 2, 3], [2, 3], [3], [3, 2, 3]), + ([2, 1, 2], [2, 3, 2, 1, 2], [3, 2, 1, 2]), + ([2, 1, 2, 3], [2, 3, 2, 1, 2, 3], [3, 2, 1, 2, 3]), + ([2, 1, 2, 3, 2], [2, 3, 2, 1, 2, 3, 2], [3, 2, 1, 2, 3, 2]), + ([2, 1, 2, 3, 2, 1], + [2, 3, 2, 1, 2, 3, 2, 1], + [3, 2, 1, 2, 3, 2, 1], + [3, 2, 3, 2, 1, 2]), + ([2, 3, 1], [3, 1], [3, 2, 3, 1]), + ([2, 3, 1, 2], [3, 1, 2], [3, 2, 3, 1, 2]), + ([2, 3, 1, 2, 3], [3, 1, 2, 3], [3, 2, 3, 1, 2, 3]), + ([2, 3, 1, 2, 3, 2], + [3, 1, 2, 3, 2], + [3, 2, 3, 1, 2, 3, 2], + [3, 2, 3, 2], + [3, 2, 3, 2, 1, 2, 3, 2]), + ([2, 3, 1, 2, 3, 2, 1], + [3, 1, 2, 3, 2, 1], + [3, 2, 3, 1, 2, 3, 2, 1], + [3, 2, 3, 2, 1], + [3, 2, 3, 2, 1, 2, 3]), + ([3, 2, 3, 2, 1, 2, 3, 2, 1],)} TESTS:: @@ -2781,13 +2800,13 @@ def kazhdan_lusztig_cell(self, side='left'): Let `C'` denote the Kazhdan-Lusztig `C^{\prime}`-basis of the Iwahori-Hecke algebra `H` of a Coxeter system `(W,S)`. Two elements `x,y` of the Coxeter group `W` are said to lie in the same left - Kazhdan-Lusztig cell if there exist sequences `x=w_1, w_2, ..., - w_k=y` and `y=u_1, u_2, ..., u_l=x` such that for all `1 \leq i < k` - and all `1 \leq j < l`, there exist some Coxeter generators `s,t \in - S` for which `C'_{w_{i+1}}` appears in `C'_sC'_{w_i}` and - `C'_{u_{j+1}}` appears in `C'_sC'_{u_j}` in `H`. Right and - two-sided Kazhdan-Lusztig cells of `W` are defined similarly; see - [Lus2013]_. + Kazhdan-Lusztig cell if there exist sequences `x = w_1, w_2, \ldots, + w_k = y` and `y = u_1, u_2, \ldots, u_l = x` such that for all + `1 \leq i < k` and all `1 \leq j < l`, there exist some Coxeter + generators `s,t \in S` for which `C'_{w_{i+1}}` appears in + `C'_s C'_{w_i}` and `C'_{u_{j+1}}` appears in `C'_s C'_{u_j}` + in `H`. Right and two-sided Kazhdan-Lusztig cells of `W` are + defined similarly; see [Lus2013]_. In this function, we compute products in the `C^{\prime}` basis by using :class:`IwahoriHeckeAlgebra.Cp`. As mentioned in that class, @@ -2798,10 +2817,10 @@ def kazhdan_lusztig_cell(self, side='left'): INPUT: - - ``w`` -- an element of self. + - ``w`` -- an element of ``self`` - - ``side`` -- ``'left'``, ``'right'``, or ``'two-sided'`` (default: - ``'left'``), corresponding to the kind of cell to compute. + - ``side`` -- (default: ``'left'``) the kind of cell to compute; + must be either ``'left'``, ``'right'``, or ``'two-sided'`` EXAMPLES: @@ -2811,40 +2830,31 @@ def kazhdan_lusztig_cell(self, side='left'): the output cell but not the method used for the cell computation. In particular, the cell computation uses the optional package ``coxeter3`` in the background as long as the package is installed, - even in the default ('reflection') and 'permutation' - implementations:: + even in the different implementations implementations:: - sage: W = CoxeterGroup('A3') # optional - coxeter3 + sage: W = WeylGroup('A3', prefix='s') # optional - coxeter3 sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 - {[-1 1 0] - [-1 0 1] - [-1 0 0], - [-1 1 0] - [-1 0 1] - [ 0 0 1], - [-1 1 0] - [ 0 1 0] - [ 0 0 1]} + {s3*s2*s1, s2*s1, s1} sage: W = CoxeterGroup('A3', implementation='permutation') # optional - coxeter3 sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 {(1,2,3,12)(4,5,10,11)(6,7,8,9), (1,2,10)(3,6,5)(4,7,8)(9,12,11), (1,7)(2,4)(5,6)(8,10)(11,12)} - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 - sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 + sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 {[1], [2, 1], [3, 2, 1]} Next, we compute a right cell and a two-sided cell in `A_3`:: - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 sage: w = s1*s3 - sage: w.kazhdan_lusztig_cell(side='right') # optional - coxeter3 + sage: w.kazhdan_lusztig_cell(side='right') # optional - coxeter3 {[1, 3], [1, 3, 2]} - sage: w.kazhdan_lusztig_cell(side='two-sided') # optional - coxeter3 + sage: w.kazhdan_lusztig_cell(side='two-sided') # optional - coxeter3 {[1, 3], [1, 3, 2], [2, 1, 3], [2, 1, 3, 2]} Some slightly longer computations in `B_4`:: @@ -2868,7 +2878,7 @@ def kazhdan_lusztig_cell(self, side='left'): [2, 3, 4, 1, 2, 3, 4], [2, 3, 4, 3, 1], [2, 3, 4, 3, 1, 2], - ... + ... [4, 3, 4, 2, 3, 4, 1, 2, 3, 4]} """ from sage.algebras.iwahori_hecke_algebra import IwahoriHeckeAlgebra @@ -2905,3 +2915,4 @@ def kazhdan_lusztig_cell(self, side='left'): g = DiGraph([list(vertices), list(edges)]) return set(g.strongly_connected_component_containing_vertex(w)) + From 3cff1f67b580ef0e24f12a8a48c735f2050d20be Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 16 Aug 2021 11:46:44 +1000 Subject: [PATCH 104/511] More reviewer changes to make tests and all test pass when coxeter3 is not installed. --- src/sage/algebras/iwahori_hecke_algebra.py | 1 - src/sage/categories/coxeter_groups.py | 82 +++++++++++++++------- 2 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 4e64e3bfe90..37bc7a2c789 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -37,7 +37,6 @@ from sage.combinat.root_system.coxeter_group import CoxeterGroup from sage.combinat.family import Family from sage.combinat.free_module import CombinatorialFreeModule -from sage.libs.coxeter3.coxeter_group import CoxeterGroup as Coxeter3Group def normalized_laurent_polynomial(R, p): diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 19be6f43df2..a2fc2dda186 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -698,7 +698,8 @@ def kazhdan_lusztig_cells(self, side='left'): `. As detailed there, installation of the optional package ``coxeter3`` - is recommended (though not required) before using this function. + is recommended (though not required) before using this function + as it speeds up the computation. INPUT: @@ -707,21 +708,48 @@ def kazhdan_lusztig_cells(self, side='left'): EXAMPLES: - We compute the left cells in the Coxeter group of type `A_3` below. - Note that each Coxeter group may be created with multiple + We compute the right cells in the Coxeter group of type `A_2` + below. Note that each Coxeter group may be created with multiple implementations, namely, 'reflection' (default), 'permutation', 'matrix', or 'coxeter3'. The choice of implementation affects the representation of elements in the output cells but not the method - used for the cell computation. In particular, the cell computation - uses the optional package ``coxeter3`` in the background as long as - the package is installed, even if the group is not created with the - 'coxeter3' implementation. + used for the cell computation. + + sage: W = CoxeterGroup('A2') + sage: KL_cells = W.kazhdan_lusztig_cells(side='right') + sage: set([tuple(sorted(C, key=lambda w: w.reduced_word())) + ....: for C in KL_cells]) + {( + [-1 1] [ 0 -1] + [ 0 1], [ 1 -1] + ), + ( + [ 0 -1] + [-1 0] + ), + ( + [1 0] + [0 1] + ), + ( + [ 1 0] [-1 1] + [ 1 -1], [-1 0] + )} + sage: len(KL_cells) + 4 - :: + sage: W = CoxeterGroup('A2', implementation='permutation') + sage: len(W.kazhdan_lusztig_cells(side='right')) + 4 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: KL_cells = W.kazhdan_lusztig_cells() # optional - coxeter3 - sage: set([tuple(sorted(C)) for C in KL_cells]) # optional - coxeter3 + We compute the left cells in the Coxeter group of type `A_3` + below. If the optional package ``coxeter3`` is installed, it + runs in the background even if the group is not created with + the ``'coxeter3'`` implementation. :: + + sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 + sage: KL_cells = W.kazhdan_lusztig_cells() # optional - coxeter3 + sage: set([tuple(sorted(C)) for C in KL_cells]) # optional - coxeter3 {([],), ([1], [2, 1], [3, 2, 1]), ([1, 2], [2], [3, 2]), @@ -732,7 +760,7 @@ def kazhdan_lusztig_cells(self, side='left'): ([1, 2, 3], [2, 3], [3]), ([1, 3], [2, 1, 3]), ([1, 3, 2], [2, 1, 3, 2])} - sage: len(KL_cells) + sage: len(KL_cells) # optional - coxeter3 10 sage: W = CoxeterGroup('A3', implementation='permutation') # optional - coxeter3 @@ -2810,8 +2838,8 @@ def kazhdan_lusztig_cell(self, side='left'): In this function, we compute products in the `C^{\prime}` basis by using :class:`IwahoriHeckeAlgebra.Cp`. As mentioned in that class, - installing the optional package ``coxeter3`` is strongly recommended - (though not required) before using this function, because the + installing the optional package ``coxeter3`` is recommended + (though not required) before using this function because the package speeds up product computations that are sometimes computationally infeasible without it. @@ -2827,21 +2855,23 @@ def kazhdan_lusztig_cell(self, side='left'): We compute the left cell of the generator `s_1` in type `A_3` in three different implementations of the Coxeter group. Note that the choice of implementation affects the representation of elements in - the output cell but not the method used for the cell computation. In - particular, the cell computation uses the optional package - ``coxeter3`` in the background as long as the package is installed, - even in the different implementations implementations:: + the output cell but not the method used for the cell computation. - sage: W = WeylGroup('A3', prefix='s') # optional - coxeter3 - sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 - sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 - {s3*s2*s1, s2*s1, s1} - sage: W = CoxeterGroup('A3', implementation='permutation') # optional - coxeter3 - sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 - sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 + sage: W = CoxeterGroup('A3', implementation='permutation') + sage: s1,s2,s3 = W.simple_reflections() + sage: s1.kazhdan_lusztig_cell() {(1,2,3,12)(4,5,10,11)(6,7,8,9), (1,2,10)(3,6,5)(4,7,8)(9,12,11), (1,7)(2,4)(5,6)(8,10)(11,12)} + + The cell computation uses the optional package ``coxeter3`` in + the background if available to speed up the computation, + even in the different implementations implementations:: + + sage: W = WeylGroup('A3', prefix='s') # optional - coxeter3 + sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 + sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 + {s3*s2*s1, s2*s1, s1} sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 sage: s1.kazhdan_lusztig_cell() # optional - coxeter3 @@ -2851,7 +2881,7 @@ def kazhdan_lusztig_cell(self, side='left'): sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 sage: s1,s2,s3 = W.simple_reflections() # optional - coxeter3 - sage: w = s1*s3 + sage: w = s1 * s3 # optional - coxeter3 sage: w.kazhdan_lusztig_cell(side='right') # optional - coxeter3 {[1, 3], [1, 3, 2]} sage: w.kazhdan_lusztig_cell(side='two-sided') # optional - coxeter3 From 901699badeb305cdfbbfd52cc8427a3ea53512b8 Mon Sep 17 00:00:00 2001 From: Chase Meadors Date: Mon, 16 Aug 2021 17:24:30 -0600 Subject: [PATCH 105/511] Fix kazhdan_lusztig_cell[s] documentation --- src/sage/categories/coxeter_groups.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index a2fc2dda186..70a20541ed7 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -713,7 +713,7 @@ def kazhdan_lusztig_cells(self, side='left'): implementations, namely, 'reflection' (default), 'permutation', 'matrix', or 'coxeter3'. The choice of implementation affects the representation of elements in the output cells but not the method - used for the cell computation. + used for the cell computation:: sage: W = CoxeterGroup('A2') sage: KL_cells = W.kazhdan_lusztig_cells(side='right') @@ -745,7 +745,7 @@ def kazhdan_lusztig_cells(self, side='left'): We compute the left cells in the Coxeter group of type `A_3` below. If the optional package ``coxeter3`` is installed, it runs in the background even if the group is not created with - the ``'coxeter3'`` implementation. :: + the ``'coxeter3'`` implementation:: sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 sage: KL_cells = W.kazhdan_lusztig_cells() # optional - coxeter3 @@ -2855,7 +2855,7 @@ def kazhdan_lusztig_cell(self, side='left'): We compute the left cell of the generator `s_1` in type `A_3` in three different implementations of the Coxeter group. Note that the choice of implementation affects the representation of elements in - the output cell but not the method used for the cell computation. + the output cell but not the method used for the cell computation:: sage: W = CoxeterGroup('A3', implementation='permutation') sage: s1,s2,s3 = W.simple_reflections() From cca4acd6e49c999adb734a2a1b91dd51036a7acd Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sat, 28 Aug 2021 23:03:36 +0800 Subject: [PATCH 106/511] EllipticCurveIsogeny.is_normalized: remove obsolete algorithm --- .../elliptic_curves/ell_curve_isogeny.py | 95 ++----------------- 1 file changed, 9 insertions(+), 86 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index ebbd2d2fc0c..774e26a8281 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -3139,7 +3139,7 @@ def switch_sign(self): """ self.set_post_isomorphism(WeierstrassIsomorphism(self.__E2, (-1,0,-self.__E2.a1(),-self.__E2.a3()))) - def is_normalized(self, via_formal=True, check_by_pullback=True): + def is_normalized(self, via_formal=None, check_by_pullback=None): r""" Return whether this isogeny is normalized. @@ -3152,14 +3152,10 @@ def is_normalized(self, via_formal=True, check_by_pullback=True): differentials on `E` and `E_2` corresponding to the given equation. - INPUT: - - - ``via_formal`` - (default: ``True``) If ``True`` it simply - checks if the leading term of the formal series is - 1. Otherwise it uses a deprecated algorithm involving the - second optional argument. + ALGORITHM: - - ``check_by_pullback`` - (default:``True``) Deprecated. + The method checks if the leading term of the formal series + associated to this isogeny equals 1. EXAMPLES:: @@ -3220,84 +3216,11 @@ def is_normalized(self, via_formal=True, check_by_pullback=True): sage: phi.is_normalized() True """ - # easy algorithm using the formal expansion. - if via_formal: - phi_formal = self.formal(prec=5) - return phi_formal[1] == 1 - - # this is the old algorithm. it should be deprecated. - check_prepost_isomorphism = False - - f_normalized = True - - if (check_by_pullback): - - (Xmap, Ymap) = self.rational_maps() - - E1 = self.__E1 - E2 = self.__E2 - - a1 = E1.a1() - a3 = E1.a3() - - a1pr = E2.a1() - a3pr = E2.a3() - - x, y = self.__mpoly_ring.gens() - - Xmap_pr = Xmap.derivative(x) - - domain_inv_diff = 1/(2*y + a1*x + a3) - codomain_inv_diff = Xmap_pr/(2*Ymap + a1pr*Xmap + a3pr) - - inv_diff_quo = domain_inv_diff/codomain_inv_diff - - if (1 == inv_diff_quo): - f_normalized = True - else: - # For some reason, in certain cases, when the isogeny - # is pre or post composed with a translation the - # resulting rational functions are too complicated for - # sage to simplify down to a constant in this case, we - # do some cheating by checking if the post-composition - # by isogeny has a non 1 scaling factor - if ( inv_diff_quo.numerator().is_constant() and (inv_diff_quo.denominator().is_constant) ): - f_normalized = False - else: - check_prepost_isomorphism = True - else: - check_prepost_isomorphism = True - - # If we skip checking by the pullback of the invariant - # differential OR if that was inconclusive We explicitly check - # if there is a post isomorphism and if it has a non 1 scaling - # factor or if it is a just a translation. NOTE: This only - # works because we are using algorithms for calculating the - # isogenies that calculate a separable normalized isogeny, if - # this changes, this check will no longer be correct. - # - if (check_prepost_isomorphism): - post_isom = self.__post_isomorphism - if (post_isom is not None): - if (1 == self.__base_field(post_isom.u)): - f_post_normalized = True - else: - f_post_normalized = False - else: - f_post_normalized = True - - pre_isom = self.__pre_isomorphism - if (pre_isom is not None): - if (1 == self.__base_field(pre_isom.u)): - f_pre_normalized = True - else: - f_pre_normalized = False - else: - f_pre_normalized = True - - f_normalized = f_pre_normalized and f_post_normalized - - return f_normalized + if via_formal is not None or check_by_pullback is not None: + from sage.misc.superseded import deprecation + deprecation(32430, 'The "via_formal" and "check_by_pullback" arguments are obsolete, have no effect, and will be removed at some point.') + phi_formal = self.formal(prec=5) + return phi_formal[1] == 1 def dual(self): r""" From 7a41934e686072fe61fbc4eca16f07a6a8ed2f8f Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Tue, 31 Aug 2021 11:20:33 +0800 Subject: [PATCH 107/511] call .shift() in __{l,r}shift__ to fix #32440 --- .../rings/laurent_series_ring_element.pyx | 6 +++ src/sage/rings/power_series_ring_element.pyx | 39 +++++++++++++++++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index f0010cb2e27..b9f09471f39 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -1753,6 +1753,12 @@ cdef class LaurentSeries(AlgebraElement): Traceback (most recent call last): ... TypeError: self is not a power series + + Test for :trac:`32440`:: + + sage: L. = LaurentSeriesRing(QQ, implementation='pari') + sage: (x + O(x^3)).power_series() + x + O(x^3) """ if self.__n < 0: if self.__u.is_zero() and self.__u.prec() >= - self.__n: diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index a021390d012..4a2595b13b0 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -1190,13 +1190,46 @@ cdef class PowerSeries(AlgebraElement): - Robert Bradshaw (2007-04-18) """ - return self._parent(self.polynomial().shift(n), self._prec + n) + if not n: + return self + prec = max(0, self.prec() + Integer(n)) + return self._parent(self.polynomial().shift(n), prec) def __lshift__(self, n): - return self.parent()(self.polynomial() << n, self.prec()) + """ + Left-shift this power series by `n`, i.e., multiply by `t^n`. + + EXAMPLES:: + + sage: R. = PowerSeriesRing(QQ, implementation='pari') + sage: f = exp(x) + O(x^7); f + 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + 1/720*x^6 + O(x^7) + sage: f << 2 + x^2 + x^3 + 1/2*x^4 + 1/6*x^5 + 1/24*x^6 + 1/120*x^7 + 1/720*x^8 + O(x^9) + sage: (f << 99) >> 99 + 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + 1/720*x^6 + O(x^7) + """ + return self.shift(n) def __rshift__(self, n): - return self.parent()(self.polynomial() >> n, self.prec()) + """ + Right-shift this power series by `n`, i.e., divide by `t^n`. + Terms below `t^n` are discarded. + + EXAMPLES:: + + sage: R. = PowerSeriesRing(QQ, implementation='pari') + sage: f = exp(x) + O(x^7) + sage: f >> 3 + 1/6 + 1/24*x + 1/120*x^2 + 1/720*x^3 + O(x^4) + sage: f >> 7 + O(x^0) + sage: f >> 99 + O(x^0) + sage: (f >> 99) << 99 + O(x^99) + """ + return self.shift(-n) def is_monomial(self): """ From a824ddae9186552f8e02aa626652919834825990 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Tue, 31 Aug 2021 19:44:17 +0800 Subject: [PATCH 108/511] doc tweaks --- src/sage/rings/power_series_ring_element.pyx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 4a2595b13b0..9142daa13b3 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -1160,17 +1160,18 @@ cdef class PowerSeries(AlgebraElement): def shift(self, n): r""" - Return this power series multiplied by the power `t^n`. If - `n` is negative, terms below `t^n` will be - discarded. Does not change this power series. + Return this power series multiplied by the power `t^n`. + + If `n` is negative, terms below `t^{-n}` are discarded. + + This power series is left unchanged. .. NOTE:: Despite the fact that higher order terms are printed to the right in a power series, right shifting decreases the - powers of `t`, while left shifting increases - them. This is to be consistent with polynomials, integers, - etc. + powers of `t`, while left shifting increases them. + This is to be consistent with polynomials, integers, etc. EXAMPLES:: @@ -1214,6 +1215,7 @@ cdef class PowerSeries(AlgebraElement): def __rshift__(self, n): """ Right-shift this power series by `n`, i.e., divide by `t^n`. + Terms below `t^n` are discarded. EXAMPLES:: From 834500a167e98e01292f0be9557f47ab667378de Mon Sep 17 00:00:00 2001 From: Charles Bouillaguet Date: Wed, 1 Sep 2021 09:21:11 +0200 Subject: [PATCH 109/511] Do not access M4RI internal Remove references to the rows[...] array and use mzd_row() instead. The rows[...] array may disappear in the future. --- src/sage/libs/m4ri.pxd | 4 ++-- src/sage/matrix/matrix_mod2_dense.pyx | 6 ++++-- src/sage/modules/vector_mod2_dense.pyx | 13 +++++++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/sage/libs/m4ri.pxd b/src/sage/libs/m4ri.pxd index cae979eb618..a9c6c792c05 100644 --- a/src/sage/libs/m4ri.pxd +++ b/src/sage/libs/m4ri.pxd @@ -11,8 +11,6 @@ cdef extern from "m4ri/m4ri.h": rci_t nrows rci_t ncols wi_t width - int offset - m4ri_word **rows ctypedef struct mzp_t: rci_t *values @@ -88,6 +86,8 @@ cdef extern from "m4ri/m4ri.h": # Row/Column Based IO ##################### + cdef m4ri_word *mzd_row(mzd_t *, rci_t) + cdef void mzd_row_swap(mzd_t *, rci_t, rci_t) cdef void mzd_col_swap(mzd_t *, rci_t, rci_t) diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 8f1374eb39f..00f5a2e0ab9 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -1214,17 +1214,19 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse cdef m4ri_word mask = 0 # Original code, before adding the ``nonzero`` option. + cdef m4ri_word *row if not nonzero: if density == 1: assert(sizeof(m4ri_word) == 8) mask = __M4RI_LEFT_BITMASK(self._entries.ncols % m4ri_radix) for i from 0 <= i < self._nrows: + row = mzd_row(self._entries, i) for j from 0 <= j < self._entries.width: # for portability we get 32-bit twice rather than 64-bit once low = gmp_urandomb_ui(rstate.gmp_state, 32) high = gmp_urandomb_ui(rstate.gmp_state, 32) - self._entries.rows[i][j] = m4ri_swap_bits( ((high)<<32) | (low) ) - self._entries.rows[i][self._entries.width - 1] &= mask + row[j] = m4ri_swap_bits( ((high)<<32) | (low) ) + row[self._entries.width - 1] &= mask else: nc = self._ncols num_per_row = int(density * nc) diff --git a/src/sage/modules/vector_mod2_dense.pyx b/src/sage/modules/vector_mod2_dense.pyx index 3c08d14f2d7..f996d1e821e 100644 --- a/src/sage/modules/vector_mod2_dense.pyx +++ b/src/sage/modules/vector_mod2_dense.pyx @@ -344,8 +344,9 @@ cdef class Vector_mod2_dense(free_module_element.FreeModuleElement): """ cdef int i cdef int res = 0 + cdef m4ri_word *row = mzd_row(self._entries, 0) for i from 0 <= i < self._entries.width: - res += Integer(self._entries.rows[0][i]).popcount() + res += Integer(row[i]).popcount() return res @@ -386,9 +387,10 @@ cdef class Vector_mod2_dense(free_module_element.FreeModuleElement): n = IntegerMod_int.__new__(IntegerMod_int) IntegerMod_abstract.__init__(n, self.base_ring()) n.ivalue = 0 - + cdef m4ri_word *lrow = mzd_row(self._entries, 0) + cdef m4ri_word *rrow = mzd_row(r._entries, 0) for i from 0 <= i < self._entries.width: - tmp ^= self._entries.rows[0][i] & r._entries.rows[0][i] + tmp ^= lrow[i] & rrow[i] for i in range(64): n.ivalue ^= (tmp & 1) @@ -411,8 +413,11 @@ cdef class Vector_mod2_dense(free_module_element.FreeModuleElement): r = right z = self._new_c() cdef Py_ssize_t i + cdef m4ri_word *lrow = mzd_row(self._entries, 0) + cdef m4ri_word *rrow = mzd_row(r._entries, 0) + cdef m4ri_word *zrow = mzd_row(z._entries, 0) for i from 0 <= i < self._entries.width: - z._entries.rows[0][i] = (self._entries.rows[0][i] & r._entries.rows[0][i]) + zrow[i] = (lrow[i] & rrow[i]) return z cpdef _lmul_(self, Element left): From 59a7af40f70b2ecbb28e89b82d51e694e512e709 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Wed, 1 Sep 2021 18:38:40 +0800 Subject: [PATCH 110/511] fix doctest formatting --- src/sage/schemes/elliptic_curves/ell_curve_isogeny.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index ebbd2d2fc0c..2f023494dc3 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -3391,7 +3391,7 @@ def dual(self): sage: phi.dual() Isogeny of degree 7 from Elliptic Curve defined by y^2 + x*y = x^3 + 84*x + 34 over Finite Field of size 103 to Elliptic Curve defined by y^2 + x*y = x^3 + x + 102 over Finite Field of size 103 - Check that :trac:`17293` is fixed: + Check that :trac:`17293` is fixed:: sage: k. = QuadraticField(2) sage: E = EllipticCurve(k, [-3*s*(4 + 5*s), 2*s*(2 + 14*s + 11*s^2)]) From 3a9e585cdecd3bfc9445c70741a342cf08fe604a Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sat, 4 Sep 2021 09:13:44 +0800 Subject: [PATCH 111/511] probably no need to warn after >10 years of deprecation --- src/sage/schemes/elliptic_curves/ell_curve_isogeny.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 774e26a8281..34f9f424ab0 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -3139,7 +3139,7 @@ def switch_sign(self): """ self.set_post_isomorphism(WeierstrassIsomorphism(self.__E2, (-1,0,-self.__E2.a1(),-self.__E2.a3()))) - def is_normalized(self, via_formal=None, check_by_pullback=None): + def is_normalized(self): r""" Return whether this isogeny is normalized. @@ -3216,9 +3216,6 @@ def is_normalized(self, via_formal=None, check_by_pullback=None): sage: phi.is_normalized() True """ - if via_formal is not None or check_by_pullback is not None: - from sage.misc.superseded import deprecation - deprecation(32430, 'The "via_formal" and "check_by_pullback" arguments are obsolete, have no effect, and will be removed at some point.') phi_formal = self.formal(prec=5) return phi_formal[1] == 1 From e470cf8f99ad7d9f38a5bdebbf7313dfcc0d1e10 Mon Sep 17 00:00:00 2001 From: Marius Gerbershagen Date: Tue, 3 Aug 2021 19:41:36 +0200 Subject: [PATCH 112/511] libs: ecl: simplify conversion of unicode strings to and from ecl The new method is both simpler and faster than the old one. --- src/sage/libs/ecl.pxd | 10 ++++++++++ src/sage/libs/ecl.pyx | 22 ++++------------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/sage/libs/ecl.pxd b/src/sage/libs/ecl.pxd index 43a41c0c97b..9c6fa118c5d 100644 --- a/src/sage/libs/ecl.pxd +++ b/src/sage/libs/ecl.pxd @@ -36,6 +36,7 @@ cdef extern from "ecl/ecl.h": ctypedef cl_fixnum cl_narg ctypedef void *cl_object ctypedef unsigned long int cl_index + ctypedef int ecl_character ctypedef enum ecl_option: ECL_OPT_INCREMENTAL_GC = 0, @@ -108,6 +109,7 @@ cdef extern from "ecl/ecl.h": # ECL numeric type conversion + cl_object ecl_make_fixnum(cl_fixnum i) cl_object ecl_make_integer(cl_fixnum i) cl_object ecl_make_unsigned_integer(cl_index i) cl_fixnum ecl_fixint "fixint" (cl_object x) @@ -141,6 +143,10 @@ cdef extern from "ecl/ecl.h": cl_object ecl_cstring_to_base_string_or_nil(char *s) cl_object si_coerce_to_base_string(cl_object x) cl_object si_base_string_p(cl_object x) + cl_object cl_make_string(cl_narg narg, cl_object o, ...) + ecl_character ecl_char(cl_object s, cl_index i) + ecl_character ecl_char_set(cl_object s, cl_index i, ecl_character c) + # S-expr evaluation and function calls @@ -159,3 +165,7 @@ cdef extern from "ecl/ecl.h": # symbols cl_object ecl_make_symbol(const char *name, const char *package) + + # sequences + + cl_fixnum ecl_length(cl_object x) diff --git a/src/sage/libs/ecl.pyx b/src/sage/libs/ecl.pyx index 57d5fdd9108..91911c598d2 100644 --- a/src/sage/libs/ecl.pyx +++ b/src/sage/libs/ecl.pyx @@ -235,8 +235,6 @@ def init_ecl(): """ global list_of_objects global read_from_string_clobj - global make_unicode_string_clobj - global unicode_string_codepoints_clobj global conditions_to_handle_clobj global ecl_has_booted cdef char *argv[1] @@ -291,26 +289,13 @@ def init_ecl(): conditions_to_handle_clobj=ecl_list1(ecl_make_symbol(b"SERIOUS-CONDITION", b"COMMON-LISP")) insert_node_after(list_of_objects,conditions_to_handle_clobj) - cl_eval(string_to_object(b""" - (defun sage-make-unicode-string (codepoints) - (map 'string #'code-char codepoints)) - """)) - make_unicode_string_clobj = cl_eval(string_to_object(b"#'sage-make-unicode-string")) - - cl_eval(string_to_object(b""" - (defun sage-unicode-string-codepoints (s) - (map 'list #'char-code s)) - """)) - unicode_string_codepoints_clobj = cl_eval(string_to_object(b"#'sage-unicode-string-codepoints")) - ecl_has_booted = 1 cdef ecl_string_to_python(cl_object s): if bint_base_string_p(s): return char_to_str(ecl_base_string_pointer_safe(s)) else: - s = cl_funcall(2, unicode_string_codepoints_clobj, s) - return ''.join(chr(code) for code in ecl_to_python(s)) + return ''.join(chr(ecl_char(s, i)) for i in range(ecl_length(s))) cdef cl_object ecl_safe_eval(cl_object form) except NULL: """ @@ -455,8 +440,9 @@ cdef cl_object python_to_ecl(pyobj, bint read_strings) except NULL: try: s = str_to_bytes(pyobj, 'ascii') except UnicodeEncodeError: - o = cl_funcall(2, make_unicode_string_clobj, - python_to_ecl([ord(c) for c in pyobj], read_strings)) + o = cl_make_string(1, ecl_make_fixnum(len(pyobj))) + for i in range(len(pyobj)): + ecl_char_set(o, i, ord(pyobj[i])) else: o = ecl_cstring_to_base_string_or_nil(s) From 9c2da2dc7b76c0d79c5a3b84343a865864b9a5a3 Mon Sep 17 00:00:00 2001 From: Marius Gerbershagen Date: Sun, 8 Aug 2021 20:19:04 +0200 Subject: [PATCH 113/511] libs: ecl: simplify conversion of lists and tuples By building the Lisp list in reverse, the code becomes shorter and more efficient. --- src/sage/libs/ecl.pyx | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/sage/libs/ecl.pyx b/src/sage/libs/ecl.pyx index 91911c598d2..d9c995662cf 100644 --- a/src/sage/libs/ecl.pyx +++ b/src/sage/libs/ecl.pyx @@ -468,27 +468,17 @@ cdef cl_object python_to_ecl(pyobj, bint read_strings) except NULL: elif isinstance(pyobj,EclObject): return (pyobj).obj elif isinstance(pyobj, list): - if not pyobj: - return Cnil - else: - L = cl_cons(python_to_ecl(pyobj[0], read_strings),Cnil) - ptr = L - for a in pyobj[1:]: - cl_rplacd(ptr, cl_cons(python_to_ecl(a, read_strings), Cnil)) - ptr = cl_cdr(ptr) - return L + L = Cnil + for i in range(len(pyobj)-1,-1,-1): + L = cl_cons(python_to_ecl(pyobj[i], read_strings), L) + return L elif isinstance(pyobj, tuple): if not pyobj: return Cnil - elif len(pyobj) == 1: - return python_to_ecl(pyobj[0], read_strings) else: - L = cl_cons(python_to_ecl(pyobj[0], read_strings), Cnil) - ptr = L - for a in pyobj[1:-1]: - cl_rplacd(ptr, cl_cons(python_to_ecl(a, read_strings), Cnil)) - ptr = cl_cdr(ptr) - cl_rplacd(ptr, python_to_ecl(pyobj[-1], read_strings)) + L = python_to_ecl(pyobj[-1], read_strings) + for i in range(len(pyobj)-2,-1,-1): + L = cl_cons(python_to_ecl(pyobj[i], read_strings), L) return L else: raise TypeError("Unimplemented type for python_to_ecl") From cf49bfe8f0e940183b9f08c37c3dec7dd92445ff Mon Sep 17 00:00:00 2001 From: Marius Gerbershagen Date: Sun, 8 Aug 2021 20:23:47 +0200 Subject: [PATCH 114/511] libs: ecl: remove deprecated Cnil/Ct names --- src/sage/libs/ecl.pxd | 4 ++-- src/sage/libs/ecl.pyx | 38 +++++++++++++++++++------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/sage/libs/ecl.pxd b/src/sage/libs/ecl.pxd index 9c6fa118c5d..19472171403 100644 --- a/src/sage/libs/ecl.pxd +++ b/src/sage/libs/ecl.pxd @@ -73,8 +73,8 @@ cdef extern from "ecl/ecl.h": # predefined symbols - cl_object Cnil - cl_object Ct + cl_object ECL_NIL + cl_object ECL_T cl_fixnum MOST_POSITIVE_FIXNUM cl_fixnum MOST_NEGATIVE_FIXNUM diff --git a/src/sage/libs/ecl.pyx b/src/sage/libs/ecl.pyx index d9c995662cf..05c78c06e5a 100644 --- a/src/sage/libs/ecl.pyx +++ b/src/sage/libs/ecl.pyx @@ -30,20 +30,20 @@ from cpython.object cimport Py_EQ, Py_NE #it would be preferrable to let bint_symbolp wrap an efficient macro #but the macro provided in object.h doesn't seem to work cdef bint bint_symbolp(cl_object obj): - return not(cl_symbolp(obj) == Cnil) + return not(cl_symbolp(obj) == ECL_NIL) #these type predicates are only provided in "cl_*" form, so we wrap them #with the proper type cast. cdef bint bint_numberp(cl_object obj): - return not(cl_numberp(obj) == Cnil) + return not(cl_numberp(obj) == ECL_NIL) cdef bint bint_integerp(cl_object obj): - return not(cl_integerp(obj) == Cnil) + return not(cl_integerp(obj) == ECL_NIL) cdef bint bint_rationalp(cl_object obj): - return not(cl_rationalp(obj) == Cnil) + return not(cl_rationalp(obj) == ECL_NIL) cdef bint bint_base_string_p(cl_object obj): - return not(si_base_string_p(obj) == Cnil) + return not(si_base_string_p(obj) == ECL_NIL) cdef extern from "eclsig.h": int ecl_sig_on() except 0 @@ -84,7 +84,7 @@ cdef cl_object insert_node_after(cl_object node,cl_object value): next=cl_cadr(node) newnode=cl_cons(value,cl_cons(next,node)) cl_rplaca(cl_cdr(node),newnode) - if next != Cnil: + if next != ECL_NIL: cl_rplacd(cl_cdr(next),newnode) return newnode @@ -92,9 +92,9 @@ cdef void remove_node(cl_object node): cdef cl_object next, prev next=cl_cadr(node) prev=cl_cddr(node) - if next != Cnil: + if next != ECL_NIL: cl_rplacd(cl_cdr(next),prev) - if prev != Cnil: + if prev != ECL_NIL: cl_rplaca(cl_cdr(prev),next) # our global list of pointers. This will be a pointer to a sentinel node, @@ -271,7 +271,7 @@ def init_ecl(): #initialise list of objects and bind to global variable # *SAGE-LIST-OF-OBJECTS* to make it rooted in the reachable tree for the GC - list_of_objects=cl_cons(Cnil,cl_cons(Cnil,Cnil)) + list_of_objects=cl_cons(ECL_NIL,cl_cons(ECL_NIL,ECL_NIL)) cl_set(string_to_object(b"*SAGE-LIST-OF-OBJECTS*"), list_of_objects) cl_eval(string_to_object(b""" @@ -406,7 +406,7 @@ def print_objects(): print(ecl_string_to_python(s)) c = cl_cadr(c) - if c == Cnil: + if c == ECL_NIL: break cdef cl_object python_to_ecl(pyobj, bint read_strings) except NULL: @@ -422,11 +422,11 @@ cdef cl_object python_to_ecl(pyobj, bint read_strings) except NULL: if isinstance(pyobj,bool): if pyobj: - return Ct + return ECL_T else: - return Cnil + return ECL_NIL elif pyobj is None: - return Cnil + return ECL_NIL elif isinstance(pyobj,long): if pyobj >= MOST_NEGATIVE_FIXNUM and pyobj <= MOST_POSITIVE_FIXNUM: return ecl_make_integer(pyobj) @@ -468,13 +468,13 @@ cdef cl_object python_to_ecl(pyobj, bint read_strings) except NULL: elif isinstance(pyobj,EclObject): return (pyobj).obj elif isinstance(pyobj, list): - L = Cnil + L = ECL_NIL for i in range(len(pyobj)-1,-1,-1): L = cl_cons(python_to_ecl(pyobj[i], read_strings), L) return L elif isinstance(pyobj, tuple): if not pyobj: - return Cnil + return ECL_NIL else: L = python_to_ecl(pyobj[-1], read_strings) for i in range(len(pyobj)-2,-1,-1): @@ -489,7 +489,7 @@ cdef ecl_to_python(cl_object o): cdef Integer N # conversions from an ecl object to a python object. - if o == Cnil: + if o == ECL_NIL: return None elif bint_fixnump(o): # Sage specific conversion @@ -509,11 +509,11 @@ cdef ecl_to_python(cl_object o): # Python conversion # Since Sage mainly uses mpfr, perhaps "double is not an appropriate return type return ecl_to_double(o) - elif o == Ct: + elif o == ECL_T: return True elif bint_consp(o): L=[] - while o != Cnil: + while o != ECL_NIL: L.append(ecl_to_python(cl_car(o))) o = cl_cdr(o) if not(bint_listp(o)): @@ -1337,7 +1337,7 @@ cdef class EclListIterator: self.current = self.current.cdr() else: r = self.current - self.current = ecl_wrap(Cnil) + self.current = ecl_wrap(ECL_NIL) return r #input: a cl-object. Output: EclObject wrapping that. From cd63d838a25adbd8dbf61d7869e049c7e88cfe49 Mon Sep 17 00:00:00 2001 From: Marius Gerbershagen Date: Wed, 1 Sep 2021 09:13:31 +0200 Subject: [PATCH 115/511] libs: ecl: fix cl_boot invocation We shouldn't stack allocate this parameter because it becomes invalid once the scope leaves init_ecl, leading to crashes if `(ext:command-args)` is called in Lisp. --- src/sage/libs/ecl.pyx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/libs/ecl.pyx b/src/sage/libs/ecl.pyx index 05c78c06e5a..fc641932969 100644 --- a/src/sage/libs/ecl.pyx +++ b/src/sage/libs/ecl.pyx @@ -109,6 +109,8 @@ cdef cl_object unicode_string_codepoints_clobj cdef bint ecl_has_booted = 0 +cdef char *argv = "sage" #we need a dummy argv for cl_boot (we just don't give any parameters) + # ECL signal handling def test_sigint_before_ecl_sig_on(): @@ -237,7 +239,7 @@ def init_ecl(): global read_from_string_clobj global conditions_to_handle_clobj global ecl_has_booted - cdef char *argv[1] + global argv cdef sigaction_t sage_action[32] cdef int i @@ -247,9 +249,6 @@ def init_ecl(): #we keep our own GMP memory functions. ECL should not claim them ecl_set_option(ECL_OPT_SET_GMP_MEMORY_FUNCTIONS,0); - #we need a dummy argv for cl_boot (we just don't give any parameters) - argv[0]="sage" - #get all the signal handlers before initializing Sage so we can #put them back afterwards. for i in range(1,32): @@ -257,7 +256,7 @@ def init_ecl(): #initialize ECL ecl_set_option(ECL_OPT_SIGNAL_HANDLING_THREAD, 0) - safe_cl_boot(1, argv) + safe_cl_boot(1, &argv) #save signal handler from ECL sigaction(SIGINT, NULL, &ecl_sigint_handler) From 475e60598370ccf3196f13b2a7f9722fcc69e56c Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 5 Sep 2021 12:01:45 +0200 Subject: [PATCH 116/511] trac #17537: geodesic closure in Cython --- src/sage/graphs/convexity_properties.pyx | 203 ++++++++++++++++++++++- src/sage/graphs/graph.py | 4 +- 2 files changed, 201 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/convexity_properties.pyx b/src/sage/graphs/convexity_properties.pyx index 3fea9e872d1..ca73f4b21e2 100644 --- a/src/sage/graphs/convexity_properties.pyx +++ b/src/sage/graphs/convexity_properties.pyx @@ -1,3 +1,4 @@ +# cython: binding=True r""" Convexity properties of graphs @@ -11,6 +12,7 @@ the following methods: :meth:`ConvexityProperties.hull` | Return the convex hull of a set of vertices :meth:`ConvexityProperties.hull_number` | Compute the hull number of a graph and a corresponding generating set + :meth:`geodetic_closure`| Return the geodetic closure of a set of vertices These methods can be used through the :class:`ConvexityProperties` object returned by :meth:`Graph.convexity_properties`. @@ -23,12 +25,16 @@ Methods ------- """ -############################################################################## +# **************************************************************************** # Copyright (C) 2011 Nathann Cohen -# Distributed under the terms of the GNU General Public License (GPL) -# The full text of the GPL is available at: -# http://www.gnu.org/licenses/ -############################################################################## +# 2021 David Coudert +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.data_structures.binary_matrix cimport * from sage.numerical.backends.generic_backend cimport GenericBackend @@ -36,6 +42,13 @@ from sage.numerical.backends.generic_backend import get_solver from sage.graphs.distances_all_pairs cimport c_distances_all_pairs from cysignals.memory cimport sig_free from cysignals.signals cimport sig_on, sig_off +from memory_allocator cimport MemoryAllocator +from libc.stdint cimport uint32_t +from sage.graphs.base.static_sparse_graph cimport (short_digraph, + init_short_digraph, + free_short_digraph, + out_degree, + simple_BFS) cdef class ConvexityProperties: r""" @@ -476,3 +489,183 @@ cdef class ConvexityProperties: constraint.append(i) return self._integers_to_vertices(constraint) + + +def geodetic_closure(G, S): + r""" + Return the geodetic closure of the set of vertices `S` in `G`. + + The geodetic closure `g(S)` of a subset of vertices `S` of a graph `G` is in + [HLT1993]_ as the set of all vertices that lie on a shortest `u-v` path for + any pair of vertices `u,v \in S`. We assume that `g(\emptyset) = \emptyset` + and that `g(\{u\}) = \{u\}` for any `u` in `G`. + + .. WARNING:: + + This operation is **not** a closure function. Indeed, a closure function + must satisfy the property that `f(f(X))` should be equal to `f(X)`, + which is not always the case here. The term ``closure`` is used here to + follow the terminology of the domain. See for instance [HLT1993]_. + + Here, we implement a simple algorithm to determine this set. Roughly, for + each vertex `u \in S`, the algorithm first performs a breadth first search + from `u` to get distances, and then identifies the vertices of `G` lying on + a shortest path from `u` to any `v\in S` using a reversal traversal from + vertices in `S`. This algorithm has time complexity in `O(|S|(n + m))` and + space complexity in `O(n + m)`. + + INPUT: + + - ``G`` -- a Sage graph + + - ``S`` -- a subset of vertices of `G` + + EXAMPLES: + + The vertices of the Petersen graph can be obtained by a geodetic closure of + four of its vertices:: + + sage: from sage.graphs.convexity_properties import geodetic_closure + sage: G = graphs.PetersenGraph() + sage: geodetic_closure(G, [0, 2, 8, 9]) + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + The vertices of a 2D grid can be obtained by a geodetic closure of + two vertices:: + + sage: G = graphs.Grid2dGraph(4, 4) + sage: c = G.geodetic_closure([(0, 0), (3, 3)]) + sage: len(c) == G.order() + True + + If two vertices belong to different connected components of a graph, their + geodetic closure is trivial:: + + sage: G = Graph([(0, 1), (2, 3)]) + sage: geodetic_closure(G, [0, 2]) + [0, 2] + + The geodetic closure does not satisfy the closure function property that + `f(f(X))` should be equal to `f(X)`:: + + sage: G = graphs.DiamondGraph() + sage: G.subdivide_edge((1, 2), 1) + sage: geodetic_closure(G, [0, 3]) + [0, 1, 2, 3] + sage: geodetic_closure(G, geodetic_closure(G, [0, 3])) + [0, 1, 2, 3, 4] + + TESTS:: + + sage: G = graphs.DiamondGraph() + sage: geodetic_closure(G, []) + [] + sage: geodetic_closure(G, [1]) + [1] + sage: S = geodetic_closure(G, list(G)) + sage: all(u in G for u in S) and len(S) == G.order() + True + sage: S = geodetic_closure(G, G) + sage: all(u in G for u in S) and len(S) == G.order() + True + sage: geodetic_closure(G, [1, 'foo']) + Traceback (most recent call last): + ... + ValueError: S is not a subset of vertices of the graph + """ + S = list(S) + if not S: + return [] + elif any(v not in G for v in S): + raise ValueError("S is not a subset of vertices of the graph") + elif len(S) == 1 or len(S) == G.order(): + return S + elif not G.is_connected(): + L = [] + for g in G.connected_components_subgraphs(): + Sg = [u for u in S if u in g] + L.extend(geodetic_closure(g, Sg)) + return L + + cdef int n = G.order() + cdef int nS = len(S) + cdef list int_to_vertex = list(G) + cdef dict vertex_to_int = {u: i for i, u in enumerate(int_to_vertex)} + cdef list S_int = [vertex_to_int[u] for u in S] + + # Copy the graph has a short digraph + cdef short_digraph sd + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) + + # Allocate some data structures + cdef MemoryAllocator mem = MemoryAllocator() + cdef uint32_t * distances = mem.malloc(n * sizeof(uint32_t)) + cdef uint32_t * waiting_list = mem.malloc(n * sizeof(uint32_t)) + if not distances or not waiting_list: + free_short_digraph(sd) + raise MemoryError() + cdef bitset_t seen + cdef bitset_t visited + cdef bitset_t closure + bitset_init(seen, n) + bitset_init(visited, n) + bitset_init(closure, n) + + cdef int ui, vi, xi, yi, i_begin, i_end, i, j, k + + # Vertices in S are in the closure + bitset_clear(closure) + for ui in S_int: + bitset_add(closure, ui) + + # We now explore geodesics between vertices in S, and we avoid visiting + # twice the geodesics between u and v + for i in range(nS - 1): + ui = S_int[i] + + # Compute distances from ui using BFS + _ = simple_BFS(sd, ui, distances, NULL, waiting_list, seen) + + # Perform a reverse BFS from vertices in S, following only vertices + # along a shortest path from ui to identify vertices of the geodetic + # closure. + bitset_clear(visited) + i_begin = 0 + i_end = 0 + for j in range(i + 1, nS): + vi = S_int[j] + if not bitset_in(seen, vi) or bitset_in(visited, vi): + # vi is not reachable from ui using BFS or has already been + # considered for the geodetic closure from ui + continue + + # We explore all vertices on a shortest path from ui to vi + waiting_list[i_end] = vi + i_end += 1 + bitset_add(visited, vi) + + while i_begin < i_end: + xi = waiting_list[i_begin] + i_begin += 1 + + for k in range(out_degree(sd, xi)): + yi = sd.neighbors[xi][k] + if distances[xi] == distances[yi] + 1: + # yi in on a shortest path to ui + if not bitset_in(visited, yi): + waiting_list[i_end] = yi + i_end += 1 + bitset_add(visited, yi) + + # Now, visited contains all vertices on geodesics from ui to any other + # vertex in S + bitset_union(closure, closure, visited) + + cdef list ret = [int_to_vertex[ui] for ui in range(n) if bitset_in(closure, ui)] + + bitset_free(seen) + bitset_free(visited) + bitset_free(closure) + free_short_digraph(sd) + + return ret diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index b1fbb941e84..6022024ae19 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -9389,6 +9389,7 @@ def bipartite_double(self, extended=False): from sage.graphs.connectivity import is_triconnected from sage.graphs.comparability import is_comparability from sage.graphs.comparability import is_permutation + from sage.graphs.convexity_properties import geodetic_closure from sage.graphs.domination import is_dominating from sage.graphs.domination import is_redundant from sage.graphs.domination import private_neighbors @@ -9441,7 +9442,8 @@ def bipartite_double(self, extended=False): "edge_isoperimetric_number" : "Expansion properties", "vertex_isoperimetric_number" : "Expansion properties", "fractional_chromatic_number" : "Coloring", - "fractional_chromatic_index" : "Coloring" + "fractional_chromatic_index" : "Coloring", + "geodetic_closure" : "Leftovers" } __doc__ = __doc__.replace("{INDEX_OF_METHODS}",gen_thematic_rest_table_index(Graph,_additional_categories)) From 8bac3324636f074cd6439b962d86e5592c866f45 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 5 Sep 2021 12:17:01 +0200 Subject: [PATCH 117/511] trac #17537: prevent calling this method on digraphs --- src/sage/graphs/convexity_properties.pyx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/graphs/convexity_properties.pyx b/src/sage/graphs/convexity_properties.pyx index ca73f4b21e2..19c1224cab3 100644 --- a/src/sage/graphs/convexity_properties.pyx +++ b/src/sage/graphs/convexity_properties.pyx @@ -572,7 +572,13 @@ def geodetic_closure(G, S): Traceback (most recent call last): ... ValueError: S is not a subset of vertices of the graph + sage: geodetic_closure(digraphs.Path(3), [0, 1]) + Traceback (most recent call last): + ... + NotImplementedError: the geodetic closure of digraphs has not been implemented yet """ + if G.is_directed(): + raise NotImplementedError("the geodetic closure of digraphs has not been implemented yet") S = list(S) if not S: return [] From 0bdb8f13163501d6c82e392e02df0f29a953bdd4 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Fri, 10 Sep 2021 10:51:45 +0800 Subject: [PATCH 118/511] kernel polynomial is not used anymore in _richcmp_ --- src/sage/schemes/elliptic_curves/ell_curve_isogeny.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index ebbd2d2fc0c..36876f5260e 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -1228,10 +1228,11 @@ def __hash__(self): def _richcmp_(self, other, op): r""" - Function that implements comparisons between isogeny objects. + Compare :class:`EllipticCurveIsogeny` objects. - This function works by comparing the underlying kernel - objects. + ALGORITHM: + + This method compares domains, codomains, and :meth:`rational_maps`. EXAMPLES:: @@ -1256,9 +1257,6 @@ def _richcmp_(self, other, op): sage: phi.dual() == psi.dual() True """ - if (self.__kernel_polynomial is None): - self.__init_kernel_polynomial() - # We cannot just compare kernel polynomials, as was done until # Trac #11327, as then phi and -phi compare equal, and # similarly with phi and any composition of phi with an From ead071d9b09047a6f0d867ed9be21b85d0e9b854 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Wed, 8 Sep 2021 16:43:18 +0800 Subject: [PATCH 119/511] make sure multiplication_by_m_isogeny picks the correct isomorphism --- .../schemes/elliptic_curves/ell_generic.py | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index 912496bca28..2c1300ed77a 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -2150,7 +2150,7 @@ def multiplication_by_m(self, m, x_only=False): def multiplication_by_m_isogeny(self, m): r""" Return the ``EllipticCurveIsogeny`` object associated to the - multiplication-by-`m` map on self. + multiplication-by-`m` map on this elliptic curve. The resulting isogeny will have the associated rational maps (i.e. those returned by @@ -2169,7 +2169,7 @@ def multiplication_by_m_isogeny(self, m): OUTPUT: - An ``EllipticCurveIsogeny`` object associated to the - multiplication-by-`m` map on self. + multiplication-by-`m` map on this elliptic curve. EXAMPLES:: @@ -2177,6 +2177,29 @@ def multiplication_by_m_isogeny(self, m): sage: E.multiplication_by_m_isogeny(7) Isogeny of degree 49 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field + TESTS: + + Tests for :trac:`32490`:: + + sage: E = EllipticCurve(QQbar, [1,0]) + sage: E.multiplication_by_m_isogeny(1).rational_maps() + (x, y) + + :: + + sage: E = EllipticCurve_from_j(GF(31337).random_element()) + sage: P = E.random_point() + sage: [E.multiplication_by_m_isogeny(m)(P) == m*P for m in (1,2,3,5,7,9)] + [True, True, True, True, True, True] + + :: + + sage: E = EllipticCurve('99.a1') + sage: E.multiplication_by_m_isogeny(5) + Isogeny of degree 25 from Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 17*x + 30 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 17*x + 30 over Rational Field + sage: E.multiplication_by_m_isogeny(2).rational_maps() + ((1/4*x^4 + 33/4*x^2 - 121/2*x + 363/4)/(x^3 - 3/4*x^2 - 33/2*x + 121/4), + (-1/256*x^7 + 1/128*x^6*y - 7/256*x^6 - 3/256*x^5*y - 105/256*x^5 - 165/256*x^4*y + 1255/256*x^4 + 605/128*x^3*y - 473/64*x^3 - 1815/128*x^2*y - 10527/256*x^2 + 2541/128*x*y + 4477/32*x - 1331/128*y - 30613/256)/(1/16*x^6 - 3/32*x^5 - 519/256*x^4 + 341/64*x^3 + 1815/128*x^2 - 3993/64*x + 14641/256)) """ mx, my = self.multiplication_by_m(m) @@ -2184,7 +2207,13 @@ def multiplication_by_m_isogeny(self, m): phi = self.isogeny(torsion_poly, codomain=self) phi._EllipticCurveIsogeny__initialize_rational_maps(precomputed_maps=(mx, my)) - return phi + # trac 32490: using codomain=self can give a wrong isomorphism + for aut in self.automorphisms(): + psi = aut * phi + if psi.rational_maps() == (mx, my): + return psi + + assert False, 'bug in multiplication_by_m_isogeny()' def isomorphism_to(self, other): """ From 2576f86d5b782b81746f5e8a961d848d5757082f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 12:08:18 -0700 Subject: [PATCH 120/511] build/make/Makefile.in: If a script package has no spkg-install, run "sage -info" and exit with error --- build/make/Makefile.in | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/build/make/Makefile.in b/build/make/Makefile.in index bd8ca2a99da..5191d4da759 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -630,7 +630,8 @@ $$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2): $(3) $(1): $$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2) $(1)-$(4)-no-deps: - $(AM_V_at)cd '$$(SAGE_ROOT)/build/pkgs/$(1)' && \ + @if [ -x '$$(SAGE_ROOT)/build/pkgs/$(1)/spkg-install' ]; then \ + $(AM_V_at)cd '$$(SAGE_ROOT)/build/pkgs/$(1)' && \ . '$$(SAGE_ROOT)/src/bin/sage-src-env-config' && \ . '$$(SAGE_ROOT)/src/bin/sage-env-config' && \ . '$$(SAGE_ROOT)/src/bin/sage-env' && \ @@ -638,8 +639,20 @@ $(1)-$(4)-no-deps: . '$$(SAGE_ROOT)/build/bin/sage-build-env' && \ SAGE_SPKG_WHEELS=$$($(4))/var/lib/sage/wheels \ SAGE_INST_LOCAL=$$($(4)) \ - sage-logger -p '$$(SAGE_ROOT)/build/pkgs/$(1)/spkg-install' '$$(SAGE_LOGS)/$(1)-$(2).log' - touch "$$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2)" + sage-logger -p '$$(SAGE_ROOT)/build/pkgs/$(1)/spkg-install' '$$(SAGE_LOGS)/$(1)-$(2).log' && \ + touch "$$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2)"; \ + else \ + echo; \ + echo "Error: $(1) is a dummy script package that the Sage distribution uses"; \ + echo "to provide information about equivalent system packages."; \ + echo "It cannot be installed using the Sage distribution."; \ + echo "Please install it manually, for example using the system packages"; \ + echo "recommended at the end of a run of './configure'"; \ + echo "See below for package-specific information."; \ + echo; \ + $$(SAGE_ROOT)/build/bin/sage-spkg-info $(1); \ + exit 1; \ + fi $(1)-no-deps: $(1)-$(4)-no-deps From feb8de7542cc2d97c1b43f114dc2d96db313a22d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 12:08:41 -0700 Subject: [PATCH 121/511] build/pkgs/: Remove spkg-install scripts for dummy script packages --- build/pkgs/graphviz/spkg-install | 4 ---- build/pkgs/libxml2/spkg-install | 4 ---- build/pkgs/llvm/spkg-install | 4 ---- build/pkgs/pandoc/spkg-install | 5 ----- build/pkgs/perl_cpan_polymake_prereq/spkg-install | 6 ------ 5 files changed, 23 deletions(-) delete mode 100755 build/pkgs/graphviz/spkg-install delete mode 100755 build/pkgs/libxml2/spkg-install delete mode 100755 build/pkgs/llvm/spkg-install delete mode 100755 build/pkgs/pandoc/spkg-install delete mode 100755 build/pkgs/perl_cpan_polymake_prereq/spkg-install diff --git a/build/pkgs/graphviz/spkg-install b/build/pkgs/graphviz/spkg-install deleted file mode 100755 index aeb51456c5d..00000000000 --- a/build/pkgs/graphviz/spkg-install +++ /dev/null @@ -1,4 +0,0 @@ -#! /usr/bin/env bash -echo Error: graphviz is not installed as a system package. -echo Please install the system package recommended by ./configure -exit 1 diff --git a/build/pkgs/libxml2/spkg-install b/build/pkgs/libxml2/spkg-install deleted file mode 100755 index f61a49e9072..00000000000 --- a/build/pkgs/libxml2/spkg-install +++ /dev/null @@ -1,4 +0,0 @@ -#! /usr/bin/env bash -echo Error: libxml2 is not installed. -echo Please install it, for example using the system packages recommended by ./configure -exit 1 diff --git a/build/pkgs/llvm/spkg-install b/build/pkgs/llvm/spkg-install deleted file mode 100755 index 4233e976c04..00000000000 --- a/build/pkgs/llvm/spkg-install +++ /dev/null @@ -1,4 +0,0 @@ -#! /usr/bin/env bash -echo Error: llvm is not installed. -echo Please install it, for example using the system packages recommended by ./configure -exit 1 diff --git a/build/pkgs/pandoc/spkg-install b/build/pkgs/pandoc/spkg-install deleted file mode 100755 index 45fa6a3e0a9..00000000000 --- a/build/pkgs/pandoc/spkg-install +++ /dev/null @@ -1,5 +0,0 @@ -#! /usr/bin/env bash -echo Error: pandoc, a prerequisite of rst2ipynb, is not installed. -echo Please install it manually, for example using the system packages -echo recommended by ./configure. -exit 1 diff --git a/build/pkgs/perl_cpan_polymake_prereq/spkg-install b/build/pkgs/perl_cpan_polymake_prereq/spkg-install deleted file mode 100755 index 44bb1e1a6ef..00000000000 --- a/build/pkgs/perl_cpan_polymake_prereq/spkg-install +++ /dev/null @@ -1,6 +0,0 @@ -#! /usr/bin/env bash -echo Error: The Perl prerequisites of the package polymake are not installed. -echo Please install CPAN packages $(cat distros/cpan.txt) -echo manually, either using the system packages recommended by ./configure -echo or directly from CPAN. -exit 1 From 8f782c01dbc947dcf386303444402b280346f14c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 12:22:33 -0700 Subject: [PATCH 122/511] .github/workflows/tox-{optional,experimental}.yml: Do not try to test dummy script packages --- .github/workflows/tox-experimental.yml | 8 ++++++-- .github/workflows/tox-optional.yml | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tox-experimental.yml b/.github/workflows/tox-experimental.yml index 862f00476e9..674a43f7fdf 100644 --- a/.github/workflows/tox-experimental.yml +++ b/.github/workflows/tox-experimental.yml @@ -47,7 +47,9 @@ jobs: TOX_ENV: docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-tox-docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} DOCKER_TARGETS: configured with-targets with-targets-optional - TARGETS_OPTIONAL: "$( echo $(PATH=build/bin:$PATH build/bin/sage-package list :experimental: | grep -v database_stein_watkins\\$ | grep -v polytopes_db_4d | grep '^[${{ matrix.targets_pattern }}]' ) )" + # Test all non-dummy experimental packages, but do not test huge packages + # and do not test packages that require external software + TARGETS_OPTIONAL: "$( echo $(export PATH=build/bin:$PATH && sage-package list :experimental: --has-file spkg-install.in && sage-package list :experimental: --has-file spkg-install && sage-package list :experimental: --has-file requirements.txt | grep -v ^_ | grep -v database_stein_watkins\\$ | grep -v polytopes_db_4d | grep -v cplex | grep -v gurobi | grep '^[${{ matrix.targets_pattern }}]' ) )" steps: - uses: actions/checkout@v2 with: @@ -146,7 +148,9 @@ jobs: env: TOX_ENV: local-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-tox-local-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }}-${{ matrix.os }}-xcode_${{ matrix.xcode_version_factor }} - TARGETS_OPTIONAL: "$( echo $(PATH=build/bin:$PATH build/bin/sage-package list :experimental: | grep -v database_stein_watkins\\$ | grep -v polytopes_db_4d | grep '^[${{ matrix.targets_pattern }}]' ) )" + # Test all non-dummy experimental packages, but do not test huge packages + # and do not test packages that require external software + TARGETS_OPTIONAL: "$( echo $(export PATH=build/bin:$PATH && sage-package list :experimental: --has-file spkg-install.in && sage-package list :experimental: --has-file spkg-install && sage-package list :experimental: --has-file requirements.txt | grep -v ^_ | grep -v database_stein_watkins\\$ | grep -v polytopes_db_4d | grep -v cplex | grep -v gurobi | grep '^[${{ matrix.targets_pattern }}]' ) )" steps: - uses: actions/checkout@v2 - name: Select Xcode version diff --git a/.github/workflows/tox-optional.yml b/.github/workflows/tox-optional.yml index 279c6d23feb..72aec6cb82a 100644 --- a/.github/workflows/tox-optional.yml +++ b/.github/workflows/tox-optional.yml @@ -47,9 +47,9 @@ jobs: TOX_ENV: docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-tox-docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} DOCKER_TARGETS: configured with-targets with-targets-optional - # Test all optional packages, but do not test huge packages, + # Test all non-dummy optional packages, but do not test huge packages # and do not test packages that require external software - TARGETS_OPTIONAL: "$( echo $(PATH=build/bin:$PATH build/bin/sage-package list :optional: | grep -v database_stein_watkins\\$ | grep -v polytopes_db_4d | grep -v cplex | grep -v gurobi | grep '^[${{ matrix.targets_pattern }}]' ) )" + TARGETS_OPTIONAL: "$( echo $(export PATH=build/bin:$PATH && (sage-package list :optional: --has-file spkg-install.in && sage-package list :optional: --has-file spkg-install && sage-package list :optional: --has-file requirements.txt) | grep -v ^_ | grep -v database_stein_watkins\\$ | grep -v polytopes_db_4d | grep -v cplex | grep -v gurobi | grep '^[${{ matrix.targets_pattern }}]' ) )" steps: - uses: actions/checkout@v2 with: @@ -148,9 +148,9 @@ jobs: env: TOX_ENV: local-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-tox-local-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }}-${{ matrix.os }}-xcode_${{ matrix.xcode_version_factor }} - # Test all optional packages, but do not test huge packages + # Test all non-dummy optional packages, but do not test huge packages # and do not test packages that require external software - TARGETS_OPTIONAL: "$( echo $(PATH=build/bin:$PATH build/bin/sage-package list :optional: | grep -v database_stein_watkins\\$ | grep -v polytopes_db_4d | grep -v cplex | grep -v gurobi | grep '^[${{ matrix.targets_pattern }}]' ) )" + TARGETS_OPTIONAL: "$( echo $(export PATH=build/bin:$PATH && (sage-package list :optional: --has-file spkg-install.in && sage-package list :optional: --has-file spkg-install && sage-package list :optional: --has-file requirements.txt) | grep -v ^_ | grep -v database_stein_watkins\\$ | grep -v polytopes_db_4d | grep -v cplex | grep -v gurobi | grep '^[${{ matrix.targets_pattern }}]' ) )" steps: - uses: actions/checkout@v2 - name: Select Xcode version From 4b292bef2d14ad14c71baf0cba22d07d7a5b55d7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 19 Sep 2021 21:14:58 -0700 Subject: [PATCH 123/511] build/pkgs/perl_mongodb/spkg-install: Remove --- build/pkgs/perl_mongodb/spkg-install | 6 ------ 1 file changed, 6 deletions(-) delete mode 100755 build/pkgs/perl_mongodb/spkg-install diff --git a/build/pkgs/perl_mongodb/spkg-install b/build/pkgs/perl_mongodb/spkg-install deleted file mode 100755 index 7f087781bb9..00000000000 --- a/build/pkgs/perl_mongodb/spkg-install +++ /dev/null @@ -1,6 +0,0 @@ -#! /usr/bin/env bash -echo Error: The optional prerequisite perl_mongodb of the package polymake are not installed. -echo Please install CPAN package $(cat distros/cpan.txt) -echo manually, either using the system package recommended by ./configure -echo or directly from CPAN. -exit 1 From a7b63520b3cc2daa5a7da2f6b7218f40211d92fc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 19 Sep 2021 21:22:42 -0700 Subject: [PATCH 124/511] build/bin/sage-spkg-info: Fix display of system packages --- build/bin/sage-spkg-info | 1 + 1 file changed, 1 insertion(+) diff --git a/build/bin/sage-spkg-info b/build/bin/sage-spkg-info index e9152065dc0..79de53afbee 100755 --- a/build/bin/sage-spkg-info +++ b/build/bin/sage-spkg-info @@ -57,6 +57,7 @@ if [ $have_repology = yes ]; then systems="$systems repology" fi for system in $systems; do + system_package_file="$PKG_DISTROS"/$system.txt system_packages="$(echo $(sed 's/#.*//;' $system_package_file))" case $system in debian) From 7b7f6ad24620b744d4decd6dcf648bd479762948 Mon Sep 17 00:00:00 2001 From: Christian Wuthrich Date: Tue, 21 Sep 2021 15:10:33 +0100 Subject: [PATCH 125/511] trac 32258: typos --- src/sage/schemes/elliptic_curves/padic_lseries.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index 72250f3ed6b..d462d6c7151 100644 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -842,7 +842,7 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): sage: lp.series(6) 2^2 + 2^6 + O(2^7) + (2 + O(2^4))*T + O(2^3)*T^2 + (2^2 + O(2^3))*T^3 + (2 + O(2^2))*T^4 + O(T^5) - Check that twists by odd Teichmuller charachters are ok (:trac:`32258`):: + Check that twists by odd Teichmuller characters are ok (:trac:`32258`):: sage: E = EllipticCurve("443c1") sage: lp = E.padic_lseries(17, implementation="num") @@ -1313,7 +1313,7 @@ def series(self, n=3, quadratic_twist=+1, prec=5, eta=0): j += 1 L = R(bj, prec) L /= self._quotient_of_periods_to_twist(D) - if si == +1 : + if si == +1: L /= self._E.real_components() self._set_series_in_cache(n, prec, quadratic_twist, eta, L) return L From e65b3092f97226196a5ea2de1b46508371745d00 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 21 Sep 2021 16:07:22 -0700 Subject: [PATCH 126/511] bootstrap: Do not provide ./configure --enable-SPKG options for dummy optional packages --- bootstrap | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bootstrap b/bootstrap index 1ee0c6b9ab2..0feb5191eca 100755 --- a/bootstrap +++ b/bootstrap @@ -97,8 +97,13 @@ AS_VAR_SET_IF([SAGE_ENABLE_$pkgname], [], [AS_VAR_SET([SAGE_ENABLE_$pkgname], [y case "$pkgname" in _*) ;; *) spkg_configures="$spkg_configures -AC_SUBST(SAGE_ENABLE_$pkgname, [if_installed]) -SAGE_SPKG_ENABLE([$pkgname], [$pkgtype], [$(head -n1 build/pkgs/$pkgname/SPKG.rst 2>/dev/null || echo $pkgname)])" ;; +AC_SUBST(SAGE_ENABLE_$pkgname, [if_installed])" + if [ -f build/pkgs/$pkgname/spkg-install -o -f build/pkgs/$pkgname/spkg-install.in ]; then + # Trac #31163: Not just an optional dummy package + spkg_configures="$spkg_configures +SAGE_SPKG_ENABLE([$pkgname], [$pkgtype], [$(head -n1 build/pkgs/$pkgname/SPKG.rst 2>/dev/null || echo $pkgname)])" + fi + ;; esac fi done From b485d469cb1f61774b3f098b1e4277e66bd712fd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 21 Sep 2021 16:35:13 -0700 Subject: [PATCH 127/511] m4/sage_spkg_collect.m4: Do not advertise dummy optional packages as installable --- m4/sage_spkg_collect.m4 | 69 ++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/m4/sage_spkg_collect.m4 b/m4/sage_spkg_collect.m4 index 1ab62d6fa47..d18ae090743 100644 --- a/m4/sage_spkg_collect.m4 +++ b/m4/sage_spkg_collect.m4 @@ -146,6 +146,35 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do in_sdist=no + dnl Determine package source + dnl + if test -f "$DIR/requirements.txt"; then + SPKG_SOURCE=pip + # Since pip packages are downloaded and installed by pip, we don't + # include them in the source tarball. At the time of this writing, + # all pip packages are optional. + in_sdist=no + elif test ! -f "$DIR/checksums.ini"; then + if test -f "$DIR/spkg-install"; then + SPKG_SOURCE=script + else + dnl a dummy script package + SPKG_SOURCE=none + fi + # We assume that either (a) the sources for an optional script + # package will be downloaded by the script, or (b) that a + # standard script package's sources are already a part of the + # sage repository (and thus the release tarball). As a result, + # we don't need to download the sources, which is what + # "in_sdist" really means. At the time of this writing, the + # only standard script packages are sage_conf and sagelib. + # The sources of these packages are in subdirectories of + # $SAGE_ROOT/pkgs. + in_sdist=no + else + SPKG_SOURCE=normal + fi + dnl Write out information about the installation tree, using the name of the tree prefix dnl variable (SAGE_LOCAL or SAGE_VENV). The makefile variable of SPKG is called "trees_SPKG", dnl note plural, for possible future extension in which an SPKG would be installed into several @@ -177,7 +206,11 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do AS_VAR_IF([SAGE_ENABLE_]${SPKG_NAME}, [yes], [ message="$SPKG_TYPE, will be installed as an SPKG" ], [ - message="$SPKG_TYPE, use \"$srcdir/configure --enable-$SPKG_NAME\" to install" + message="$SPKG_TYPE" + AS_VAR_IF([SPKG_SOURCE], [none], [], [ + dnl Non-dummy optional/experimental package, advertise how to install + message="$message, use \"$srcdir/configure --enable-$SPKG_NAME\" to install" + ]) SAGE_NEED_SYSTEM_PACKAGES_VAR=SAGE_NEED_SYSTEM_PACKAGES_OPTIONAL ]) ;; @@ -228,8 +261,12 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do AS_VAR_IF([sage_spkg_install], [no], [ dnl We will use the system package (or not required for this platform.) SAGE_DUMMY_PACKAGES="${SAGE_DUMMY_PACKAGES} \\$(printf '\n ')${SPKG_NAME}" - AS_VAR_IF([sage_require], [yes], [ message="using system package; SPKG will not be installed" - ], [ message="not required on your platform; SPKG will not be installed" + AS_VAR_IF([sage_require], [yes], [ message="using system package" + ], [ message="not required on your platform" + ]) + dnl Trac #31163: Only talk about the SPKG if there is an SPKG + AS_VAR_IF([SPKG_SOURCE], [none], [], [ + message="$message; SPKG will not be installed" ]) ], [ dnl We will not use the system package. @@ -267,30 +304,6 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do ;; esac - # Determine package source - # - if test -f "$DIR/requirements.txt"; then - SPKG_SOURCE=pip - # Since pip packages are downloaded and installed by pip, we don't - # include them in the source tarball. At the time of this writing, - # all pip packages are optional. - in_sdist=no - elif test ! -f "$DIR/checksums.ini"; then - SPKG_SOURCE=script - # We assume that either (a) the sources for an optional script - # package will be downloaded by the script, or (b) that a - # standard script package's sources are already a part of the - # sage repository (and thus the release tarball). As a result, - # we don't need to download the sources, which is what - # "in_sdist" really means. At the time of this writing, the - # only standard script packages are sage_conf and sagelib. - # The sources of these packages are in subdirectories of - # $SAGE_ROOT/pkgs. - in_sdist=no - else - SPKG_SOURCE=normal - fi - if test "$in_sdist" = yes; then SAGE_SDIST_PACKAGES="${SAGE_SDIST_PACKAGES} \\$(printf '\n ')${SPKG_NAME}" fi @@ -338,7 +351,7 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do pip) SAGE_PIP_PACKAGES="${SAGE_PIP_PACKAGES} \\$(printf '\n ')${SPKG_NAME}" ;; - script) + script|none) SAGE_SCRIPT_PACKAGES="${SAGE_SCRIPT_PACKAGES} \\$(printf '\n ')${SPKG_NAME}" ;; normal) From 9fa072e89a176420d18f99fb0d00a08318ec87e7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 22 Sep 2021 18:53:25 -0700 Subject: [PATCH 128/511] build/pkgs/mpir: Remove --- build/make/Makefile.in | 2 +- build/pkgs/cddlib/spkg-configure.m4 | 2 +- build/pkgs/ecl/spkg-configure.m4 | 2 +- build/pkgs/ecm/spkg-configure.m4 | 2 +- build/pkgs/fflas_ffpack/spkg-configure.m4 | 2 +- build/pkgs/givaro/spkg-configure.m4 | 2 +- build/pkgs/glpk/spkg-configure.m4 | 2 +- build/pkgs/gmp/spkg-configure.m4 | 26 +- build/pkgs/igraph/spkg-configure.m4 | 2 +- build/pkgs/iml/spkg-configure.m4 | 2 +- build/pkgs/isl/spkg-configure.m4 | 2 +- build/pkgs/lrslib/spkg-configure.m4 | 2 +- build/pkgs/mpfr/spkg-configure.m4 | 2 +- build/pkgs/mpir/SPKG.rst | 44 --- build/pkgs/mpir/checksums.ini | 4 - build/pkgs/mpir/dependencies | 5 - build/pkgs/mpir/distros/conda.txt | 1 - build/pkgs/mpir/distros/freebsd.txt | 1 - build/pkgs/mpir/distros/homebrew.txt | 1 - build/pkgs/mpir/distros/opensuse.txt | 1 - build/pkgs/mpir/distros/repology.txt | 1 - build/pkgs/mpir/package-version.txt | 1 - build/pkgs/mpir/patches/ticket-25858.patch | 144 --------- build/pkgs/mpir/spkg-check.in | 6 - build/pkgs/mpir/spkg-configure.m4 | 74 ----- build/pkgs/mpir/spkg-install.in | 322 --------------------- build/pkgs/mpir/spkg-src | 43 --- build/pkgs/mpir/type | 1 - build/pkgs/ntl/spkg-configure.m4 | 2 +- build/pkgs/pari/spkg-configure.m4 | 2 +- build/pkgs/ppl/spkg-configure.m4 | 2 +- build/pkgs/yasm/spkg-configure.m4 | 4 +- build/pkgs/zn_poly/spkg-configure.m4 | 2 +- 33 files changed, 40 insertions(+), 671 deletions(-) delete mode 100644 build/pkgs/mpir/SPKG.rst delete mode 100644 build/pkgs/mpir/checksums.ini delete mode 100644 build/pkgs/mpir/dependencies delete mode 100644 build/pkgs/mpir/distros/conda.txt delete mode 100644 build/pkgs/mpir/distros/freebsd.txt delete mode 100644 build/pkgs/mpir/distros/homebrew.txt delete mode 100644 build/pkgs/mpir/distros/opensuse.txt delete mode 100644 build/pkgs/mpir/distros/repology.txt delete mode 100644 build/pkgs/mpir/package-version.txt delete mode 100644 build/pkgs/mpir/patches/ticket-25858.patch delete mode 100644 build/pkgs/mpir/spkg-check.in delete mode 100644 build/pkgs/mpir/spkg-configure.m4 delete mode 100644 build/pkgs/mpir/spkg-install.in delete mode 100755 build/pkgs/mpir/spkg-src delete mode 100644 build/pkgs/mpir/type diff --git a/build/make/Makefile.in b/build/make/Makefile.in index bd8ca2a99da..82252009582 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -32,7 +32,7 @@ SPKG_INST_RELDIR = var/lib/sage/installed # Aliases for mutually exclusive standard packages selected at configure time TOOLCHAIN = @SAGE_TOOLCHAIN@ PYTHON = python3 -MP_LIBRARY = @SAGE_MP_LIBRARY@ +MP_LIBRARY = gmp BLAS = @SAGE_BLAS@ # pkgconfig files generated/installed at build time diff --git a/build/pkgs/cddlib/spkg-configure.m4 b/build/pkgs/cddlib/spkg-configure.m4 index aa313498737..ad227f032ed 100644 --- a/build/pkgs/cddlib/spkg-configure.m4 +++ b/build/pkgs/cddlib/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([cddlib], [ - SAGE_SPKG_DEPCHECK([gmp mpir], [ + SAGE_SPKG_DEPCHECK([gmp], [ dnl The sage library uses BOTH cddexec and cddexec_gmp. dnl These two executables were introduced in cddlib-094j. AC_CHECK_PROGS([CDDEXEC], [cddexec]) diff --git a/build/pkgs/ecl/spkg-configure.m4 b/build/pkgs/ecl/spkg-configure.m4 index 9fd61393b31..ae1e0ac5e1a 100644 --- a/build/pkgs/ecl/spkg-configure.m4 +++ b/build/pkgs/ecl/spkg-configure.m4 @@ -3,7 +3,7 @@ SAGE_SPKG_CONFIGURE([ecl], [ # Default to installing the SPKG sage_spkg_install_ecl=yes - SAGE_SPKG_DEPCHECK([gcc gc gmp mpir], [ + SAGE_SPKG_DEPCHECK([gcc gc gmp], [ AC_PATH_PROG([ECL_CONFIG], [ecl-config]) AS_IF([test x$ECL_CONFIG != x], [ # "CPPFLAGS" is not a typo, the --cflags output from diff --git a/build/pkgs/ecm/spkg-configure.m4 b/build/pkgs/ecm/spkg-configure.m4 index ada5f34b0d9..e62c21cb32e 100644 --- a/build/pkgs/ecm/spkg-configure.m4 +++ b/build/pkgs/ecm/spkg-configure.m4 @@ -2,7 +2,7 @@ SAGE_SPKG_CONFIGURE([ecm], [ m4_pushdef([SAGE_ECM_MINVER],[7.0.4]) AC_REQUIRE([SAGE_SPKG_CONFIGURE_GMP]) AC_MSG_CHECKING([installing gmp/mpir? ]) - if test x$sage_spkg_install_mpir = xyes -o x$sage_spkg_install_gmp = xyes; then + if test x$sage_spkg_install_gmp = xyes; then AC_MSG_RESULT([yes; install ecm as well]) sage_spkg_install_ecm=yes else diff --git a/build/pkgs/fflas_ffpack/spkg-configure.m4 b/build/pkgs/fflas_ffpack/spkg-configure.m4 index f85295a7767..f107ff5cf15 100644 --- a/build/pkgs/fflas_ffpack/spkg-configure.m4 +++ b/build/pkgs/fflas_ffpack/spkg-configure.m4 @@ -1,7 +1,7 @@ SAGE_SPKG_CONFIGURE([fflas_ffpack], [ # fflas-lapack uses whatever multi-precision library givaro uses, # either gmp or mpir. - SAGE_SPKG_DEPCHECK([atlas givaro gmp mpir openblas], [ + SAGE_SPKG_DEPCHECK([atlas givaro gmp openblas], [ # If our dependencies come from the system, then we can use # the system fflas-ffpack, too. Use pkg-config to find a # recentish version, if there is one. diff --git a/build/pkgs/givaro/spkg-configure.m4 b/build/pkgs/givaro/spkg-configure.m4 index 6afb9e95599..7eb91edfd00 100644 --- a/build/pkgs/givaro/spkg-configure.m4 +++ b/build/pkgs/givaro/spkg-configure.m4 @@ -1,6 +1,6 @@ SAGE_SPKG_CONFIGURE([givaro], [ m4_pushdef([SAGE_GIVARO_MINVER],["40101"]) - SAGE_SPKG_DEPCHECK([gmp mpir], [ + SAGE_SPKG_DEPCHECK([gmp], [ AC_PATH_PROG([GIVAROCONFIG], [givaro-config]) AS_IF([test x$GIVAROCONFIG = x], [ AC_MSG_NOTICE([givaro-config not found. Installing givaro]) diff --git a/build/pkgs/glpk/spkg-configure.m4 b/build/pkgs/glpk/spkg-configure.m4 index d23ab9cc59f..6fb7d64aa44 100644 --- a/build/pkgs/glpk/spkg-configure.m4 +++ b/build/pkgs/glpk/spkg-configure.m4 @@ -1,6 +1,6 @@ SAGE_SPKG_CONFIGURE([glpk], [ m4_pushdef([SAGE_GLPK_MINVER],["4.63"]) - SAGE_SPKG_DEPCHECK([gmp mpir zlib], [ + SAGE_SPKG_DEPCHECK([gmp zlib], [ AC_PATH_PROG([GLPSOL], [glpsol]) AS_IF([test x$GLPSOL = x], [ AC_MSG_NOTICE([glpsol not found. Installing glpk]) diff --git a/build/pkgs/gmp/spkg-configure.m4 b/build/pkgs/gmp/spkg-configure.m4 index 9f5ffea5aa2..61d7c5f3b2f 100644 --- a/build/pkgs/gmp/spkg-configure.m4 +++ b/build/pkgs/gmp/spkg-configure.m4 @@ -1,8 +1,26 @@ SAGE_SPKG_CONFIGURE([gmp], [ - AC_REQUIRE([SAGE_SPKG_CONFIGURE_MPIR]) - if test x"$with_mp" = xgmp -o x"$_sage_spkg_install_gmp" = xyes; then - if test x"$SAGE_MP_LIBRARY" = xgmp; then - sage_spkg_install_gmp=yes + sage_spkg_install_gmp=no + AC_CHECK_HEADER(gmp.h, [], [sage_spkg_install_gmp=yes]) + AC_CHECK_HEADER(gmpxx.h, [], [sage_spkg_install_gmp=yes]) + dnl mpq_cmp_z appeared in GMP 6.1.0 and is used by pynac + AC_SEARCH_LIBS([__gmpq_cmp_z], [gmp], [], + [sage_spkg_install_gmp=yes]) +], [], [], [ + if test x$sage_spkg_install_gmp = xyes; then + AC_SUBST(SAGE_GMP_PREFIX, ['$SAGE_LOCAL']) + AC_SUBST(SAGE_GMP_INCLUDE, ['$SAGE_LOCAL/include']) + else + dnl If found, we want to get the absolute path to where we + dnl found it for use with some packages (e.g. iml) that need + dnl this information at configure time + AX_ABSOLUTE_HEADER([gmp.h]) + if test x$gl_cv_absolute_gmp_h = x; then + AC_MSG_ERROR(m4_normalize([ + failed to find absolute path to gmp.h despite it being reported + found + ])) fi + AC_SUBST(SAGE_GMP_INCLUDE, [`AS_DIRNAME($gl_cv_absolute_gmp_h)`]) + AC_SUBST(SAGE_GMP_PREFIX, ['']) fi ]) diff --git a/build/pkgs/igraph/spkg-configure.m4 b/build/pkgs/igraph/spkg-configure.m4 index a292b33d8a7..ed604d599f9 100644 --- a/build/pkgs/igraph/spkg-configure.m4 +++ b/build/pkgs/igraph/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([igraph], [ -SAGE_SPKG_DEPCHECK([glpk atlas openblas gmp mpir], [ +SAGE_SPKG_DEPCHECK([glpk atlas openblas gmp], [ dnl check for igraph with pkg-config PKG_CHECK_MODULES([IGRAPH], [igraph >= 0.8.3], [], [ sage_spkg_install_igraph=yes]) diff --git a/build/pkgs/iml/spkg-configure.m4 b/build/pkgs/iml/spkg-configure.m4 index ea78a6bbdcd..efab2c105c6 100644 --- a/build/pkgs/iml/spkg-configure.m4 +++ b/build/pkgs/iml/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([iml], [ - SAGE_SPKG_DEPCHECK([gmp mpir openblas], [ + SAGE_SPKG_DEPCHECK([gmp openblas], [ AC_CHECK_HEADER([iml.h], [ AC_SEARCH_LIBS([nonsingSolvLlhsMM], [iml], [], [sage_spkg_install_iml=yes]) diff --git a/build/pkgs/isl/spkg-configure.m4 b/build/pkgs/isl/spkg-configure.m4 index 9394030dbc1..1b16f70870b 100644 --- a/build/pkgs/isl/spkg-configure.m4 +++ b/build/pkgs/isl/spkg-configure.m4 @@ -1,7 +1,7 @@ SAGE_SPKG_CONFIGURE([isl], [ AC_REQUIRE([SAGE_SPKG_CONFIGURE_GMP]) AC_MSG_CHECKING([installing gmp/mpir? ]) - if test x$sage_spkg_install_mpir = xyes -o x$sage_spkg_install_gmp = xyes; then + if test x$sage_spkg_install_gmp = xyes; then AC_MSG_RESULT([yes; install isl as well]) sage_spkg_install_isl=yes else diff --git a/build/pkgs/lrslib/spkg-configure.m4 b/build/pkgs/lrslib/spkg-configure.m4 index 860cca451e0..0297f7118e3 100644 --- a/build/pkgs/lrslib/spkg-configure.m4 +++ b/build/pkgs/lrslib/spkg-configure.m4 @@ -1,6 +1,6 @@ SAGE_SPKG_CONFIGURE([lrslib], [ dnl System lrslib may already be 7.x, which may be compiled with FLINT - SAGE_SPKG_DEPCHECK([gmp mpir flint], [ + SAGE_SPKG_DEPCHECK([gmp flint], [ AC_CHECK_PROGS([LRSNASH], [lrsnash]) AS_IF([test -z "$LRSNASH"], [ sage_spkg_install_lrslib=yes diff --git a/build/pkgs/mpfr/spkg-configure.m4 b/build/pkgs/mpfr/spkg-configure.m4 index 0c15b56df43..2300be67076 100644 --- a/build/pkgs/mpfr/spkg-configure.m4 +++ b/build/pkgs/mpfr/spkg-configure.m4 @@ -1,7 +1,7 @@ SAGE_SPKG_CONFIGURE([mpfr], [ AC_REQUIRE([SAGE_SPKG_CONFIGURE_GMP]) AC_MSG_CHECKING([installing gmp/mpir? ]) - if test x$sage_spkg_install_mpir = xyes -o x$sage_spkg_install_gmp = xyes; then + if test x$sage_spkg_install_gmp = xyes; then AC_MSG_RESULT([yes; install mpfr as well]) sage_spkg_install_mpfr=yes else diff --git a/build/pkgs/mpir/SPKG.rst b/build/pkgs/mpir/SPKG.rst deleted file mode 100644 index a03133b1f6c..00000000000 --- a/build/pkgs/mpir/SPKG.rst +++ /dev/null @@ -1,44 +0,0 @@ -mpir: Multiple precision integers and rationals (fork of GMP) -============================================================= - -Description ------------ - -Multiple Precision Integers and Rationals. - -MPIR is an open source multiprecision integer library derived from -version 5.0.1 of the GMP (GNU Multi Precision) project (which was -licensed LGPL v2+). - -See http://www.mpir.org - -License -------- - -- LGPL V3+ - - -Upstream Contact ----------------- - -- The Google group mpir-devel -- thempirteam@googlemail.com - -Dependencies ------------- - -- iconv -- GNU patch - - -Special Update/Build Instructions ---------------------------------- - -- TODO: -- Perhaps also modify CXXFLAGS (and/or CPPFLAGS). -- We currently don't use anything of GMP's/MPIR's CC setting, and - matching with the current compiler (``$CC``) is perhaps suboptimal. -- Remove some files / directories not needed for Sage from upstream: -- build.vc\* directories (Microsoft Visual C build files) -- 3.0.0-644faf502c56f97d9accd301965fc57d6ec70868 - was created by running the spkg-src script. diff --git a/build/pkgs/mpir/checksums.ini b/build/pkgs/mpir/checksums.ini deleted file mode 100644 index d482fd960d9..00000000000 --- a/build/pkgs/mpir/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=mpir-VERSION.tar.bz2 -sha1=30044be9f48ce15ddfc8871bde14e363fe2f46ea -md5=55e9e31d6371b30dd046f16333c84499 -cksum=1799000157 diff --git a/build/pkgs/mpir/dependencies b/build/pkgs/mpir/dependencies deleted file mode 100644 index 8ca2e8756c8..00000000000 --- a/build/pkgs/mpir/dependencies +++ /dev/null @@ -1,5 +0,0 @@ -| yasm - ----------- -All lines of this file are ignored except the first. -It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/mpir/distros/conda.txt b/build/pkgs/mpir/distros/conda.txt deleted file mode 100644 index bef94785573..00000000000 --- a/build/pkgs/mpir/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -mpir diff --git a/build/pkgs/mpir/distros/freebsd.txt b/build/pkgs/mpir/distros/freebsd.txt deleted file mode 100644 index 75bf5706674..00000000000 --- a/build/pkgs/mpir/distros/freebsd.txt +++ /dev/null @@ -1 +0,0 @@ -math/mpir diff --git a/build/pkgs/mpir/distros/homebrew.txt b/build/pkgs/mpir/distros/homebrew.txt deleted file mode 100644 index bef94785573..00000000000 --- a/build/pkgs/mpir/distros/homebrew.txt +++ /dev/null @@ -1 +0,0 @@ -mpir diff --git a/build/pkgs/mpir/distros/opensuse.txt b/build/pkgs/mpir/distros/opensuse.txt deleted file mode 100644 index 16b5b660968..00000000000 --- a/build/pkgs/mpir/distros/opensuse.txt +++ /dev/null @@ -1 +0,0 @@ -libmpir-devel diff --git a/build/pkgs/mpir/distros/repology.txt b/build/pkgs/mpir/distros/repology.txt deleted file mode 100644 index bef94785573..00000000000 --- a/build/pkgs/mpir/distros/repology.txt +++ /dev/null @@ -1 +0,0 @@ -mpir diff --git a/build/pkgs/mpir/package-version.txt b/build/pkgs/mpir/package-version.txt deleted file mode 100644 index 27bffd152e1..00000000000 --- a/build/pkgs/mpir/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -3.0.0-644faf502c56f97d9accd301965fc57d6ec70868.p0 diff --git a/build/pkgs/mpir/patches/ticket-25858.patch b/build/pkgs/mpir/patches/ticket-25858.patch deleted file mode 100644 index e4aa2fd0db4..00000000000 --- a/build/pkgs/mpir/patches/ticket-25858.patch +++ /dev/null @@ -1,144 +0,0 @@ -Add support for Celeron/Pentium CPUs that use the Haswell microarchitecture but -without various extended instruction sets -https://trac.sagemath.org/ticket/25858 -diff -ru a/configure b/configure ---- a/configure 2018-07-13 14:49:36.839366500 +0200 -+++ b/configure 2018-07-13 15:08:51.229370000 +0200 -@@ -4585,7 +4585,7 @@ - # mode, in case -m32 has failed not because it's an old gcc, but because - # it's a dual 32/64-bit gcc without a 32-bit libc, or whatever. - # -- i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | prescott-*-* | core-*-* | athlon-*-* | viac3*-*-* | x86_64-*-* | netburst-*-* | netburstlahf-*-* | k8-*-* | k10-*-* | k102-*-* | k103-*-* | core2-*-* | penryn-*-* | nehalem-*-* | westmere-*-* | sandybridge-*-* | atom-*-* | nano-*-* | bobcat-*-* | bulldozer-*-* | piledriver-*-* | ivybridge-*-* | haswell-*-* | broadwell-*-* | skylake-*-* | skylakeavx-*-*) -+ i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | prescott-*-* | core-*-* | athlon-*-* | viac3*-*-* | x86_64-*-* | netburst-*-* | netburstlahf-*-* | k8-*-* | k10-*-* | k102-*-* | k103-*-* | core2-*-* | penryn-*-* | nehalem-*-* | westmere-*-* | sandybridge-*-* | atom-*-* | nano-*-* | bobcat-*-* | bulldozer-*-* | piledriver-*-* | ivybridge-*-* | haswell-*-* | haswellavx-*-* | broadwell-*-* | skylake-*-* | skylakeavx-*-*) - abilist="32" - cclist="gcc icc cc" - gcc_cflags="-O2 $fomit_frame_pointer" -@@ -4761,7 +4761,11 @@ - gcc_cflags_cpu="-mtune=corei7 -mtune=core2 -mtune=nocona -mtune=pentium3 -mcpu=pentiumpro -mcpu=i486 -m486" - gcc_cflags_arch="-march=corei7 -march=core2 -march=nocona -march=pentium3 -march=pentiumpro -march=pentium" - ;; -- sandybridge | ivybridge | haswell) -+ haswell) -+ gcc_cflags_cpu="-mtune=corei7 -mtune=corei7 -mtune=core2 -mtune=nocona -mtune=pentium3 -mcpu=pentiumpro -mcpu=i486 -m486" -+ gcc_cflags_arch="-march=corei7 -march=corei7 -march=core2 -march=nocona -march=pentium3 -march=pentiumpro -march=pentium" -+ ;; -+ sandybridge | ivybridge | haswellavx) - gcc_cflags_cpu="-mtune=corei7-avx -mtune=corei7 -mtune=core2 -mtune=nocona -mtune=pentium3 -mcpu=pentiumpro -mcpu=i486 -m486" - gcc_cflags_arch="-march=corei7-avx -march=corei7 -march=core2 -march=nocona -march=pentium3 -march=pentiumpro -march=pentium" - ;; -@@ -4800,7 +4804,7 @@ - k8 | bobcat) path="x86/k7/mmx/k8 x86/k7/mmx x86/k7 x86" ;; - core2 | penryn) path="x86/core2 x86" ;; - i786 | pentium4) path="x86/pentium4/sse2 x86/pentium4/mmx x86/pentium4 x86" ;; -- nehalem | westmere | sandybridge | ivybridge | haswell | skylake | skylakeavx | broadwell) path="x86/nehalem x86" ;; -+ nehalem | westmere | sandybridge | ivybridge | haswell | haswellavx | skylake | skylakeavx | broadwell) path="x86/nehalem x86" ;; - prescott | netburst | netburstlahf) path="x86/pentium4/sse2 x86/pentium4/mmx x86/pentium4 x86" ;; - # VIA/Centaur processors, sold as CyrixIII and C3. - nano | viac32) path="x86/p6/p3mmx x86/p6/mmx x86/p6 x86";; -@@ -4842,7 +4846,7 @@ - fi - - case $host in -- x86_64-*-* | netburst-*-* | netburstlahf-*-* | k8-*-* | k10-*-* | k102-*-* | k103-*-* | core2-*-* | penryn-*-* | nehalem-*-* | westmere-*-* | sandybridge-*-* | atom-*-* | nano-*-* | bobcat-*-* | bulldozer-*-* | piledriver-*-* | ivybridge-*-* | haswell-*-* | broadwell-*-* | skylake-*-* | skylakeavx-*-*) -+ x86_64-*-* | netburst-*-* | netburstlahf-*-* | k8-*-* | k10-*-* | k102-*-* | k103-*-* | core2-*-* | penryn-*-* | nehalem-*-* | westmere-*-* | sandybridge-*-* | atom-*-* | nano-*-* | bobcat-*-* | bulldozer-*-* | piledriver-*-* | ivybridge-*-* | haswell-*-* | haswellavx-*-* | broadwell-*-* | skylake-*-* | skylakeavx-*-*) - abilist="64 32" - cclist_64="gcc cc" - gcc_64_cflags="-m64" -@@ -4901,10 +4905,12 @@ - path_64="x86_64w/sandybridge/ivybridge x86_64w/sandybridge x86_64w" ;; - haswell-pc-msys|haswell-w64-mingw*|haswell-*-cygwin*) - path_64="x86_64w/haswell x86_64w/sandybridge x86_64w" ;; -+ haswellavx-pc-msys|haswellavx-w64-mingw*|haswellavx-*-cygwin*) -+ path_64="x86_64w/haswell/avx x86_64w/haswell x86_64w/sandybridge x86_64w" ;; - skylake-pc-msys|skylake-w64-mingw*|skylake-*-cygwin*) - path_64="x86_64w/skylake x86_64w/sandybridge x86_64w" ;; - skylakeavx-pc-msys|skylakeavx-w64-mingw*|skylakeavx-*-cygwin*) -- path_64="x86_64w/skylakeavx x86_64w/skylake x86_64w/haswell x86_64w/sandybridge x86_64w" ;; -+ path_64="x86_64w/skylake/avx x86_64w/skylake x86_64w/haswell x86_64w/sandybridge x86_64w" ;; - broadwell-pc-msys|broadwell-w64-mingw*|broadwell-*-cygwin*) - path_64="x86_64w/haswell/broadwell x86_64w/haswell/avx x86_64w/haswell x86_64w/sandybridge x86_64w" ;; - atom-pc-msys|atom-w64-mingw*|atom-*-cygwin*) -@@ -4945,6 +4951,8 @@ - ivybridge-*-*) - path_64="x86_64/sandybridge/ivybridge x86_64/sandybridge x86_64/nehalem x86_64/core2 x86_64" ;; - haswell-*-*) -+ path_64="x86_64/haswell x86_64/sandybridge x86_64" ;; -+ haswellavx-*-*) - path_64="x86_64/haswell/avx x86_64/haswell x86_64/sandybridge x86_64" ;; - broadwell-*-*) - path_64="x86_64/haswell/broadwell x86_64/haswell/avx x86_64/haswell x86_64/sandybridge x86_64" ;; -@@ -10775,7 +10783,7 @@ - # enough assembler. - # - case $host in -- i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | prescott-*-* | core-*-* | athlon-*-* | viac3*-*-* | x86_64-*-* | netburst-*-* | netburstlahf-*-* | k8-*-* | k10-*-* | k102-*-* | k103-*-* | core2-*-* | penryn-*-* | nehalem-*-* | westmere-*-* | sandybridge-*-* | atom-*-* | nano-*-* | bobcat-*-* | bulldozer-*-* | piledriver-*-* | ivybridge-*-* | haswell-*-* | broadwell-*-* | skylake-*-* | skylakeavx-*-*) -+ i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | prescott-*-* | core-*-* | athlon-*-* | viac3*-*-* | x86_64-*-* | netburst-*-* | netburstlahf-*-* | k8-*-* | k10-*-* | k102-*-* | k103-*-* | core2-*-* | penryn-*-* | nehalem-*-* | westmere-*-* | sandybridge-*-* | atom-*-* | nano-*-* | bobcat-*-* | bulldozer-*-* | piledriver-*-* | ivybridge-*-* | haswell-*-* | haswellavx-*-* | broadwell-*-* | skylake-*-* | skylakeavx-*-*) - if test "$ABI" = 32; then - case "$path $fat_path" in - *mmx*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the assembler knows about MMX instructions" >&5 -@@ -25885,7 +25867,7 @@ - ;; - esac - ;; -- i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | prescott-*-* | core-*-* | athlon-*-* | viac3*-*-* | x86_64-*-* | netburst-*-* | netburstlahf-*-* | k8-*-* | k10-*-* | k102-*-* | k103-*-* | core2-*-* | penryn-*-* | nehalem-*-* | westmere-*-* | sandybridge-*-* | atom-*-* | nano-*-* | bobcat-*-* | bulldozer-*-* | piledriver-*-* | ivybridge-*-* | haswell-*-* | broadwell-*-* | skylake-*-* | skylakeavx-*-*) -+ i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | prescott-*-* | core-*-* | athlon-*-* | viac3*-*-* | x86_64-*-* | netburst-*-* | netburstlahf-*-* | k8-*-* | k10-*-* | k102-*-* | k103-*-* | core2-*-* | penryn-*-* | nehalem-*-* | westmere-*-* | sandybridge-*-* | atom-*-* | nano-*-* | bobcat-*-* | bulldozer-*-* | piledriver-*-* | ivybridge-*-* | haswell-*-* | haswellavx-*-* | broadwell-*-* | skylake-*-* | skylakeavx-*-*) - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the .align directive accepts an 0x90 fill in .text" >&5 - $as_echo_n "checking if the .align directive accepts an 0x90 fill in .text... " >&6; } -diff -ru a/cpuid.c b/cpuid.c ---- a/cpuid.c 2018-07-13 14:49:31.111368100 +0200 -+++ b/cpuid.c 2018-07-13 15:08:45.680372700 +0200 -@@ -174,12 +174,16 @@ CPUVEC_SETUP_x86_64; - if (model == 54){ CPUIS(atom);break;}//DualCore Intel Atom D2700, 2133 MHz (16 x 133) (Cedarview, Saltwell core) 32nm - if (model == 55){ CPUIS(atom);break;} - if (model == 58){ CPUIS(ivybridge);break;} -- if (model == 60){ CPUIS(haswell);break;} -+ if (model == 60){ -+ int feat = ((int *)features)[2]; -+ if (feat & FEAT_HAS_AVX) { CPUIS(haswellavx);break; } /* Core i Haswell */ -+ else { CPUIS(haswell);break; } /* Celeron/Pentium Haswell without AVX */ -+ } - if (model == 61){ CPUIS(broadwell);break;} - if (model == 62){ CPUIS(ivybridge);break;} -- if (model == 63){ CPUIS(haswell);break;} -- if (model == 69){ CPUIS(haswell);break;} -- if (model == 70){ CPUIS(haswell);break;} -+ if (model == 63){ CPUIS(haswellavx);break;} -+ if (model == 69){ CPUIS(haswellavx);break;} -+ if (model == 70){ CPUIS(haswellavx);break;} - if (model == 71){ CPUIS(broadwell);break;} - if (model == 78){ CPUIS(skylakeavx);break;} - if (model == 79){ CPUIS(broadwell);break;} -diff -ru a/mpn/x86/fat/fat.c b/mpn/x86/fat/fat.c ---- a/mpn/x86/fat/fat.c 2018-07-13 14:49:31.111368100 +0200 -+++ b/mpn/x86/fat/fat.c 2018-07-13 15:08:45.680372700 +0200 -@@ -109,6 +109,7 @@ - #define CPUSETUP_sandybridge CPUVEC_SETUP_nehalem - #define CPUSETUP_ivybridge CPUVEC_SETUP_nehalem - #define CPUSETUP_haswell CPUVEC_SETUP_nehalem -+#define CPUSETUP_haswellavx CPUVEC_SETUP_nehalem - #define CPUSETUP_broadwell CPUVEC_SETUP_nehalem - #define CPUSETUP_skylake CPUVEC_SETUP_nehalem - #define CPUSETUP_skylakeavx CPUVEC_SETUP_nehalem -diff -ru a/mpn/x86_64/fat/fat.c b/mpn/x86_64/fat/fat.c ---- a/mpn/x86_64/fat/fat.c 2018-07-13 14:49:32.356372900 +0200 -+++ b/mpn/x86_64/fat/fat.c 2018-07-13 15:08:46.992374500 +0200 -@@ -103,6 +103,7 @@ - #define CPUSETUP_sandybridge CPUVEC_SETUP_sandybridge - #define CPUSETUP_ivybridge CPUVEC_SETUP_sandybridge;CPUVEC_SETUP_sandybridge_ivybridge - #define CPUSETUP_haswell CPUVEC_SETUP_haswell -+#define CPUSETUP_haswellavx CPUVEC_SETUP_haswell;CPUVEC_SETUP_haswell_avx - #define CPUSETUP_broadwell CPUVEC_SETUP_haswell;CPUVEC_SETUP_haswell_broadwell - #define CPUSETUP_skylake CPUVEC_SETUP_skylake - #define CPUSETUP_skylakeavx CPUVEC_SETUP_skylake;CPUVEC_SETUP_skylake_avx -diff -ru a/mpn/x86_64w/fat/fat.c b/mpn/x86_64w/fat/fat.c ---- a/mpn/x86_64w/fat/fat.c 2018-07-13 14:49:28.284367600 +0200 -+++ b/mpn/x86_64w/fat/fat.c 2018-07-13 15:08:43.058372800 +0200 -@@ -103,6 +103,7 @@ - #define CPUSETUP_sandybridge CPUVEC_SETUP_sandybridge - #define CPUSETUP_ivybridge CPUVEC_SETUP_sandybridge - #define CPUSETUP_haswell CPUVEC_SETUP_haswell -+#define CPUSETUP_haswellavx CPUVEC_SETUP_haswell;CPUVEC_SETUP_haswell_avx - #define CPUSETUP_broadwell CPUVEC_SETUP_haswell;CPUVEC_SETUP_haswell_broadwell - #define CPUSETUP_skylake CPUVEC_SETUP_skylake - #define CPUSETUP_skylakeavx CPUVEC_SETUP_skylake;CPUVEC_SETUP_skylake_avx diff --git a/build/pkgs/mpir/spkg-check.in b/build/pkgs/mpir/spkg-check.in deleted file mode 100644 index 4727de00ffe..00000000000 --- a/build/pkgs/mpir/spkg-check.in +++ /dev/null @@ -1,6 +0,0 @@ -cd src - -# We don't have to set up any environment variables here since the -# Makefiles already have them from 'configure'. - -$MAKE check diff --git a/build/pkgs/mpir/spkg-configure.m4 b/build/pkgs/mpir/spkg-configure.m4 deleted file mode 100644 index fd167864ee7..00000000000 --- a/build/pkgs/mpir/spkg-configure.m4 +++ /dev/null @@ -1,74 +0,0 @@ -SAGE_SPKG_CONFIGURE([mpir], [ -dnl Implement cases for what to do on different options here - _sage_spkg_install_gmp=no - case "$with_mp" in - system) - AC_CHECK_HEADER(gmp.h, [], [_sage_spkg_install_gmp=yes]) - AC_CHECK_HEADER(gmpxx.h, [], [_sage_spkg_install_gmp=yes]) - dnl mpq_cmp_z appeared in GMP 6.1.0 and is used by pynac - AC_SEARCH_LIBS([__gmpq_cmp_z], [gmp], [], - [_sage_spkg_install_gmp=yes]) - SAGE_MP_LIBRARY=gmp - ;; - mpir) - sage_spkg_install_mpir=yes - SAGE_MP_LIBRARY=mpir - ;; - gmp) - _sage_spkg_install_gmp=yes - SAGE_MP_LIBRARY=gmp - ;; - esac -], [], [ - AC_ARG_WITH([mp], - [AS_HELP_STRING([--with-mp=system], - [use the system GMP as multiprecision library, if possible (default)]) -dnl Not indented because whitespace ends up in the help text -AS_HELP_STRING([--with-mp=mpir], - [use the Sage SPKG for MPIR as multiprecision library]) -AS_HELP_STRING([--with-mp=gmp], - [use the Sage SPKG for GMP as multiprecision library])]) - -dnl Just parse the options here - case "$with_mp" in - system) ;; - MPIR|mpir) with_mp=mpir;; - GMP|gmp) with_mp=gmp;; - "") with_mp=system;; - *) - AC_MSG_ERROR([allowed values for --with-mp are system, mpir, or gmp]);; - esac - -dnl Set SAGE_MP_LIBRARY depending on the with_mp option - case "$with_mp" in - mpir) - SAGE_MP_LIBRARY=mpir - ;; - gmp|system) - SAGE_MP_LIBRARY=gmp - ;; - esac - - AC_SUBST([SAGE_MP_LIBRARY], [$SAGE_MP_LIBRARY]) -], [ - if test x$sage_spkg_install_mpir = xyes -o x$_sage_spkg_install_gmp = xyes; then - AC_SUBST(SAGE_GMP_PREFIX, ['$SAGE_LOCAL']) - AC_SUBST(SAGE_GMP_INCLUDE, ['$SAGE_LOCAL/include']) - AC_MSG_RESULT([using $SAGE_MP_LIBRARY SPKG (via --with-mp=$SAGE_MP_LIBRARY)]) - else - dnl If found, we want to get the absolute path to where we - dnl found it for use with some packages (e.g. iml) that need - dnl this information at configure time - AX_ABSOLUTE_HEADER([gmp.h]) - if test x$gl_cv_absolute_gmp_h = x; then - AC_MSG_ERROR(m4_normalize([ - failed to find absolute path to gmp.h despite it being reported - found - ])) - fi - AC_SUBST(SAGE_GMP_INCLUDE, [`AS_DIRNAME($gl_cv_absolute_gmp_h)`]) - AC_SUBST(SAGE_GMP_PREFIX, ['']) - AC_MSG_RESULT([using GMP-compatible library from the system]) - fi -]) - diff --git a/build/pkgs/mpir/spkg-install.in b/build/pkgs/mpir/spkg-install.in deleted file mode 100644 index 01070d1dc3e..00000000000 --- a/build/pkgs/mpir/spkg-install.in +++ /dev/null @@ -1,322 +0,0 @@ -cd src - -############################################################################### -# Previous MPIR installations are only removed after a *successful* (re)build, -# before installing the new one. (Done below.) -############################################################################### - -############################################################################### -# Find out the machine type -############################################################################### - -MACHINE_TYPE_MPIR=$(bash ./config.guess) -if [ $? -ne 0 ]; then - echo >&2 "Error: failed to determine the machine type (mpir-extended)" - exit 1 -fi - -# This is the vanilla config.guess (renamed to configfsf.guess in -# MPIR) file instead of MPIR's version. It is used when -# SAGE_FAT_BINARY is set. -MACHINE_TYPE_DEFAULT=$(bash ./configfsf.guess) -if [ $? -ne 0 ]; then - echo >&2 "Error: failed to determine the machine type (default)" - exit 1 -fi - -echo "Machine type (default): $MACHINE_TYPE_DEFAULT" -echo "Machine type (mpir): $MACHINE_TYPE_MPIR" - -############################################################################### -# Set up environment variables: -############################################################################### - -user_cflags=$CFLAGS # Save them. 'sage-env' sets CC, but not CFLAGS. -required_cflags="" # Additional mandatory settings required by Sage, accumulated below. -user_ldflags=$LDFLAGS # Save them. -required_ldflags="" # Additional mandatory settings required by Sage, accumulated below. -user_abi=$ABI # Just save it. -# In case we changed CPPFLAGS or CXXFLAGS, too, we should save the user's here as well. -# We don't have to add (e.g.) '-m64' to CFLAGS/CPPFLAGS/CXXFLAGS/LDFLAGS, since -# MPIR's 'configure' is smart enough to add it if necessary or appropriate. - - -if [ -z "$CFLAG32" ]; then - CFLAG32="-m32" # Only used in this script, no need to export it. -fi -if [ -z "$CFLAG64" ]; then - CFLAG64="-m64" # Only used in this script, no need to export it. -fi - - -case "$UNAME" in - SunOS) - true;; # Auto-detect ABI - Darwin) - # In some cases (see SAGE_ROOT/spkg/bin/sage-env), on Darwin, - # CC might be set to clang, but MPIR doesn't seem to build - # with clang. - CLANG=`command -v clang` - GCC=`command -v gcc` - if [ -n "$CC" ] && [ "$CC" = "$CLANG" ] && [ -n "$GCC" ] ; then - export CC="$GCC" - fi - # Do not set ABI=32 on MacOS X 10.6 (Darwin 10) and later, since - # there everything defaults to 64-bit: - if [ "`uname -r | sed 's/\..*//'`" -lt 10 ]; then - # Assume MacOS X 10.4 or 10.5 (Darwin 8 or 9); also, PPC CPUs - # are only supported by these, not later versions. - echo "Building a 32-bit version of MPIR, which is the only supported option." - ABI=32 - case "`uname -m`" in - ppc|ppc64|[Pp]ower*) # Apple's 'uname' returns strange strings - # The Darwin assembler rejects code using an - # extended instruction set by default (cf. #8664): - required_cflags="$required_cflags -Wa,-force_cpusubtype_ALL" - ;; - esac - else - # Darwin 10 (MacOS X 10.6) or later. - # We don't have to set ABI here. - echo "Building a 64-bit version of MPIR, which is the default." - fi - ;; # Darwin - Linux) - # MPIR fails to build on 32-bit operating systems running on - # 64-bit CPUs if CFLAGS happen to contain '-m32' and ABI is - # *not* set, so we set it here if necessary: - # (Cf. http://groups.google.com/group/mpir-devel/browse_thread/thread/46ccdc5dfc3485cd#) - # Note: This code snippet could in principle be moved out of the - # Linux branch, but since we already set ABI for other - # OSs above (and print an according message), it's here. - if [ -z "$ABI" ]; then - echo "int main(){return 0;}" > foo.c - # Try building and running a 64-bit executable: - # (Building usually succeeds even on 32-bit systems, unless e.g. a 32-bit - # CPU is explicitly selected by CFLAGS, while running does not.) - if $CC $CFLAGS $CFLAG64 -o foo foo.c 2>/dev/null && ./foo 2>/dev/null; then - # We can run 64-bit executables. - # Setting ABI=64 shouldn't be necessary, but shouldn't hurt either. - echo "Building a 64-bit version of MPIR." - case "`uname -m`" in - ppc*) ABI=mode64;; - *) ABI=64;; - esac - elif $CC $CFLAGS $CFLAG32 -o foo foo.c 2>/dev/null && ./foo 2>/dev/null; then - # We're on a 32-bit OS which cannot run 64-bit executables. - echo "Building a 32-bit version of MPIR." - ABI=32 - else - # It seems the compiler does not support -m32 nor -m64 (e.g. - # GCC on Itanium rejects both); do not set ABI at all. - echo "Your compiler does not support '$CFLAG32' nor '$CFLAG64'. Leaving ABI unset." - fi - rm -f foo foo.c - fi - ;; # Linux - CYGWIN) - if uname -a | grep x86_64 ; then - ABI=64 - else - ABI=32 - fi - ;; - *) # e.g. AIX or HP-UX - echo >&2 "Warning: Your platform ($UNAME) isn't yet explicitly supported" \ - "by this MPIR spkg, i.e., by Sage's part of it." -esac - -# MPIR 2.7.2 does not know about ppc64le and confuses it with plain -# ppc64. We need to disable specific powerpc64 assembly. -if [ "`uname -m`" = ppc64le ]; then - export MPN_PATH=generic -fi - -# Workaround old GNU as version by disabling assembly use. -if [ "$UNAME" = Linux ]; then - as_version=`$AS --version | head -1 | awk 'NF>1{print $NF}'` - as_version_major=${as_version%%.*} - as_version_rest=${as_version#*.} - as_version_minor=${as_version_rest%%.*} - if [ $as_version_major -lt 2 ] || \ - [ $as_version_major -eq 2 -a $as_version_minor -lt 24 ]; then - echo "Disable use of assembly because of GNU as <= 2.23." - export MPN_PATH=generic - if [ "$SAGE_FAT_BINARY" = "yes" ]; then - echo "Cannot build with SAGE_FAT_BINARY=yes." - exit 1 - fi - fi -fi - -# Work around a bug in GCC 4.7.0 which breaks the build on Itanium CPUs. -# See #12765, #12751, and http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48496 -if [ "`uname -m`" = ia64 ] && [ "`testcc.sh $CC`" = GCC ] ; then - gcc_version=`$CC -dumpversion` - case "$gcc_version" in - 4.7.0) - required_cflags="$required_cflags -O0 -finline-functions -fschedule-insns" - echo >&2 "Warning: Disabling almost all optimization due to a bug in GCC 4.7.0" - echo >&2 " on Itanium, which otherwise would break the build." - echo >&2 " See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48496" - echo >&2 " for current status and further details." - ;; - esac -fi - -export ABI CFLAGS CXXFLAGS LDFLAGS # Partially redundant, but safe(r). -# We don't export CPPFLAGS here, since we don't (have to) modify them. - -############################################################################### -# Now configure MPIR, eventually modifying CFLAGS [further]: -############################################################################### - -MPIR_CONFIGURE="--enable-shared $MPIR_CONFIGURE" -MPIR_CONFIGURE="--enable-gmpcompat $MPIR_CONFIGURE" - -# Fake yasm installation on non-x86[_64] system. -# It is not installed but not needed. -case `uname -m` in - i[3456]86|x86_64|amd64) - ;; - *) # Anything else - echo "Disabling check for yasm on non-x86[_64] system." - MPIR_CONFIGURE="--with-yasm=/bin/true $MPIR_CONFIGURE" - ;; -esac - -# Also build the static library to be used by e.g. ECM -# unless we are on Cygwin where we can only build a shared -# or a static library but not both: -if [ "$UNAME" = "CYGWIN" ]; then - echo "Building MPIR with the C++ interface and (only) shared libraries." - MPIR_CONFIGURE="--enable-cxx $MPIR_CONFIGURE --disable-static" -else - echo "Building MPIR with the C++ interface and (also) static libraries." - MPIR_CONFIGURE="--enable-cxx --enable-static $MPIR_CONFIGURE" -fi - -# If SAGE_FAT_BINARY is enabled, then add --enable-fat to configure -# options on Linux x86 systems. On other systems, fat binaries are not -# supported. There, we specify a build architecture which doesn't -# have a CPU name in it. -if [ "$SAGE_FAT_BINARY" = "yes" ]; then - case "$UNAME-`uname -m`" in - Linux-i[3456]86) - echo "** Building with \"fat binary\" support for 32-bit CPUs **" - MPIR_CONFIGURE="--enable-fat $MPIR_CONFIGURE" - ;; - Linux-x86_64|Linux-amd64) - echo "** Building with \"fat binary\" support for 64-bit CPUs **" - MPIR_CONFIGURE="--enable-fat $MPIR_CONFIGURE" - ;; - *) # Anything else - echo "** Building a generic binary (not assuming any specific CPU) **" - MPIR_CONFIGURE="--build=$MACHINE_TYPE_DEFAULT $MPIR_CONFIGURE" - ;; - esac -fi - - -# Pre-configure MPIR to get the settings it would use if CFLAGS were empty: -echo "------------------------------------------------------------------------" -echo "Configuring MPIR with empty CFLAGS to determine the defaults:" -(unset CFLAGS CPPFLAGS CXXFLAGS && ./configure $MPIR_CONFIGURE) -if [ $? -ne 0 ]; then - echo >&2 "Error configuring MPIR (with CFLAGS unset)." - echo >&2 "Consult `pwd`/config.log for for details." - exit 1 -fi - - -# Read MPIR-selected flags from Makefile -mpir_cc=`sed -n 's/^CC *= *//p' Makefile` -mpir_cflags=`sed -n 's/^CFLAGS *= *//p' Makefile` -if [ -z "$mpir_cc" ]; then - echo >&2 "Error: failed to determine \$CC from Makefile" - echo >&2 "Please report this to " - exit 1 -fi -echo "------------------------------------------------------------------------" -echo "Settings chosen by MPIR when configuring with CFLAGS unset:" -echo " CC: $mpir_cc" -echo " CFLAGS: $mpir_cflags" -echo "Settings added by Sage to build MPIR, taking into account SAGE_DEBUG etc.:" -echo " CFLAGS: $required_cflags" # Might be empty. -echo " LDFLAGS: $required_ldflags" # Might be empty. -echo " ABI: $ABI" # Might be empty, or the one specified by the user. -echo "Settings from the \"global\" environment:" -echo " CC: $CC" # Set by Sage, maybe overridden by the user. -echo " CFLAGS: $user_cflags" -echo " LDFLAGS: $user_ldflags" -echo " ABI: $user_abi" -echo " (CPP, CPPFLAGS, CXX and CXXFLAGS are listed below; these don't get modified.)" - -# Finally: use MPIR's flags, plus those required by Sage for the -# package to build properly, plus those specified by the user. -CFLAGS="$mpir_cflags $required_cflags $user_cflags" -LDFLAGS="$required_ldflags $user_ldflags" - -echo "Finally using the following settings:" -echo " CC=$CC" -echo " CFLAGS=$CFLAGS" -echo " CPP=$CPP" -echo " CPPFLAGS=$CPPFLAGS" -echo " CXX=$CXX" -echo " CXXFLAGS=$CXXFLAGS" -echo " LDFLAGS=$LDFLAGS" -echo " ABI=$ABI" -echo "(These settings may still get overridden by 'configure' or Makefiles.)" - -############################################################################### -# Now really configure MPIR with proper settings: -############################################################################### - -# We also add '--libdir="$SAGE_LOCAL/lib"' below, since newer autotools may -# otherwise put the libraries into .../lib64 on 64-bit systems (cf. #12131). - -echo "------------------------------------------------------------------------" -echo "Configuring MPIR with the following options:" -echo " --prefix=\"$SAGE_LOCAL\" --libdir=\"$SAGE_LOCAL/lib\" $MPIR_CONFIGURE" -echo "You can set MPIR_CONFIGURE to pass additional parameters." - -# Clear the cache of the previous configure run -find . -name config.cache -exec rm -f {} \; - -sdh_configure $MPIR_CONFIGURE - -############################################################################### -# Now build MPIR: -############################################################################### - -sdh_make -echo "Build succeeded." - -############################################################################### -# Remove previous installation (if any), *after* a successful build: -############################################################################### - -echo "Removing old GMP/MPIR headers..." -rm -f "$SAGE_LOCAL"/include/{gmp,mpir}*.h - -# Do NOT delete old GMP/MPIR shared libraries as Sage's versions of libraries -# used by GCC might still refer to them, such that their deletion would break -# GCC inside Sage. (We could perhaps remove libmpir* though.) -if false; then - echo "Removing old GMP/MPIR libraries..." - rm -f "$SAGE_LOCAL"/lib/lib{gmp,mpir}* -else - echo "Not removing old GMP/MPIR shared libraries, as other libraries" - echo "and executables might still refer to them:" - ls -l "$SAGE_LOCAL"/lib/lib{gmp,mpir}* - echo "(Libraries with the same version number will get updated though.)" -fi - -# Mark GMP as not installed (since we will overwrite it) -rm -f "$SAGE_SPKG_INST"/gmp-* - -############################################################################### -# Now install MPIR: -############################################################################### - -sdh_make_install diff --git a/build/pkgs/mpir/spkg-src b/build/pkgs/mpir/spkg-src deleted file mode 100755 index 8dde1a84941..00000000000 --- a/build/pkgs/mpir/spkg-src +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash - -set -e - -if [ -z "$SAGE_DISTFILES" ]; then - echo >&2 "SAGE_DISTFILES undefined ... exiting" - echo >&2 "Maybe run 'sage --sh'?" - exit 1 -fi - -set -e - -PACKAGEVERSION=`cat $SAGE_ROOT/build/pkgs/mpir/package-version.txt` -MPIRVERSION=mpir-`echo $PACKAGEVERSION | sed 's/-.*//'` -TARBALLVERSION="mpir-$PACKAGEVERSION" - -# Get the sources -cd "$SAGE_DISTFILES" -rm -rf mpir -git clone https://github.com/wbhart/mpir.git mpir -cd mpir -git checkout 644faf502c56f97d9accd301965fc57d6ec70868 - -# Add auto-generated files -./autogen.sh - -# Create the tarball -./configure -make dist-bzip2 - -# Unpack the tarball, remove some unwanted stuff -tar xjf $MPIRVERSION.tar.bz2 -find $MPIRVERSION -name 'build.vc*' -prune -exec rm -r {} \; - -# Repackage the tarball and put it in SAGE_DISTFILES -mv $MPIRVERSION $TARBALLVERSION -tar c $TARBALLVERSION | bzip2 --best >../$TARBALLVERSION.tar.bz2 -sage-package fix-checksum mpir - -# Cleanup -cd "$SAGE_DISTFILES" -rm -rf mpir -echo "New MPIR tarball is ready in $SAGE_DISTFILES/$TARBALLVERSION.tar.bz2" diff --git a/build/pkgs/mpir/type b/build/pkgs/mpir/type deleted file mode 100644 index a6a7b9cd726..00000000000 --- a/build/pkgs/mpir/type +++ /dev/null @@ -1 +0,0 @@ -standard diff --git a/build/pkgs/ntl/spkg-configure.m4 b/build/pkgs/ntl/spkg-configure.m4 index ba019d712de..f27ebc1bba7 100644 --- a/build/pkgs/ntl/spkg-configure.m4 +++ b/build/pkgs/ntl/spkg-configure.m4 @@ -1,7 +1,7 @@ SAGE_SPKG_CONFIGURE([ntl], [ m4_pushdef(SAGE_NTL_VERSION_MAJOR, [10]) m4_pushdef(SAGE_NTL_VERSION_MINOR, [3]) - SAGE_SPKG_DEPCHECK([gmp mpir gcc], [ + SAGE_SPKG_DEPCHECK([gmp gcc], [ AC_CHECK_HEADER([NTL/ZZ.h], [], [sage_spkg_install_ntl=yes]) AC_MSG_CHECKING([whether we can link a program using NTL]) NTL_SAVED_LIBS=$LIBS diff --git a/build/pkgs/pari/spkg-configure.m4 b/build/pkgs/pari/spkg-configure.m4 index 0baf6e427b6..9721849e7ba 100644 --- a/build/pkgs/pari/spkg-configure.m4 +++ b/build/pkgs/pari/spkg-configure.m4 @@ -1,7 +1,7 @@ SAGE_SPKG_CONFIGURE([pari], [ dnl See gp_version below on how the version is computed from MAJV.MINV.PATCHV m4_pushdef([SAGE_PARI_MINVER],["134401"]) - SAGE_SPKG_DEPCHECK([gmp mpir readline], [ + SAGE_SPKG_DEPCHECK([gmp readline], [ AC_PATH_PROG([GP], [gp]) if test x$GP = x; then dnl GP test AC_MSG_NOTICE([gp is not found]) diff --git a/build/pkgs/ppl/spkg-configure.m4 b/build/pkgs/ppl/spkg-configure.m4 index d2538903714..2f986f12168 100644 --- a/build/pkgs/ppl/spkg-configure.m4 +++ b/build/pkgs/ppl/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([ppl], [ - SAGE_SPKG_DEPCHECK([gcc glpk gmp mpir], [ + SAGE_SPKG_DEPCHECK([gcc glpk gmp], [ # If our dependencies come from the system, then we can use the # system ppl, too. This macro works sort-of like the # PKG_CHECK_MODULES macro, defining e.g. PPL_CFLAGS when a diff --git a/build/pkgs/yasm/spkg-configure.m4 b/build/pkgs/yasm/spkg-configure.m4 index bc85c7ce45c..738443a3a1d 100644 --- a/build/pkgs/yasm/spkg-configure.m4 +++ b/build/pkgs/yasm/spkg-configure.m4 @@ -12,8 +12,8 @@ SAGE_SPKG_CONFIGURE( AC_MSG_RESULT($ac_cv_path_YASM)], [dnl REQUIRED-CHECK AS_CASE("$host_cpu", [i@<:@0-9@:>@86|x86_64|amd64], [], [sage_require_yasm=no]) - AC_REQUIRE([SAGE_SPKG_CONFIGURE_MPIR]) - AS_IF([test x$sage_spkg_install_mpir = xno], [ + AC_REQUIRE([SAGE_SPKG_CONFIGURE_GMP]) + AS_IF([test x$sage_spkg_install_gmp = xno], [ sage_require_yasm=no ]) ] diff --git a/build/pkgs/zn_poly/spkg-configure.m4 b/build/pkgs/zn_poly/spkg-configure.m4 index ba3fd95a96a..c3e47c7621b 100644 --- a/build/pkgs/zn_poly/spkg-configure.m4 +++ b/build/pkgs/zn_poly/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([zn_poly], [ - SAGE_SPKG_DEPCHECK([gmp mpir], [ + SAGE_SPKG_DEPCHECK([gmp], [ AC_CHECK_HEADER([zn_poly/zn_poly.h], [ AC_SEARCH_LIBS([zn_mod_init], [zn_poly], [ ], [sage_spkg_install_zn_poly=yes]) From 81331d7af671345c3159662bc113b094b8660423 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 22 Sep 2021 18:54:14 -0700 Subject: [PATCH 129/511] build/pkgs/yasm: Remove (was mpir dependency) --- build/pkgs/yasm/SPKG.rst | 41 --------------------------- build/pkgs/yasm/checksums.ini | 4 --- build/pkgs/yasm/dependencies | 1 - build/pkgs/yasm/distros/alpine.txt | 1 - build/pkgs/yasm/distros/conda.txt | 1 - build/pkgs/yasm/distros/cygwin.txt | 1 - build/pkgs/yasm/distros/debian.txt | 1 - build/pkgs/yasm/distros/fedora.txt | 1 - build/pkgs/yasm/distros/freebsd.txt | 1 - build/pkgs/yasm/distros/homebrew.txt | 1 - build/pkgs/yasm/distros/macports.txt | 1 - build/pkgs/yasm/distros/opensuse.txt | 1 - build/pkgs/yasm/distros/repology.txt | 1 - build/pkgs/yasm/distros/slackware.txt | 1 - build/pkgs/yasm/distros/void.txt | 1 - build/pkgs/yasm/package-version.txt | 1 - build/pkgs/yasm/spkg-check.in | 5 ---- build/pkgs/yasm/spkg-configure.m4 | 20 ------------- build/pkgs/yasm/spkg-install.in | 5 ---- build/pkgs/yasm/type | 1 - 20 files changed, 90 deletions(-) delete mode 100644 build/pkgs/yasm/SPKG.rst delete mode 100644 build/pkgs/yasm/checksums.ini delete mode 100644 build/pkgs/yasm/dependencies delete mode 100644 build/pkgs/yasm/distros/alpine.txt delete mode 100644 build/pkgs/yasm/distros/conda.txt delete mode 100644 build/pkgs/yasm/distros/cygwin.txt delete mode 100644 build/pkgs/yasm/distros/debian.txt delete mode 100644 build/pkgs/yasm/distros/fedora.txt delete mode 100644 build/pkgs/yasm/distros/freebsd.txt delete mode 100644 build/pkgs/yasm/distros/homebrew.txt delete mode 100644 build/pkgs/yasm/distros/macports.txt delete mode 100644 build/pkgs/yasm/distros/opensuse.txt delete mode 100644 build/pkgs/yasm/distros/repology.txt delete mode 100644 build/pkgs/yasm/distros/slackware.txt delete mode 100644 build/pkgs/yasm/distros/void.txt delete mode 100644 build/pkgs/yasm/package-version.txt delete mode 100644 build/pkgs/yasm/spkg-check.in delete mode 100644 build/pkgs/yasm/spkg-configure.m4 delete mode 100644 build/pkgs/yasm/spkg-install.in delete mode 100644 build/pkgs/yasm/type diff --git a/build/pkgs/yasm/SPKG.rst b/build/pkgs/yasm/SPKG.rst deleted file mode 100644 index 0e1de168678..00000000000 --- a/build/pkgs/yasm/SPKG.rst +++ /dev/null @@ -1,41 +0,0 @@ -yasm: An assembler for the x86 and AMD64 instruction sets -========================================================= - -Description ------------ - -Yasm is a complete rewrite of the NASM assembler under the “new” BSD -License (some portions are under other licenses, see COPYING for -details). - -Yasm currently supports the x86 and AMD64 instruction sets, accepts NASM -and GAS assembler syntaxes, outputs binary, ELF32, ELF64, 32 and 64-bit -Mach-O, RDOFF2, COFF, Win32, and Win64 object formats, and generates -source debugging information in STABS, DWARF 2, and CodeView 8 formats. - -Yasm can be easily integrated into Visual Studio 2005/2008 and 2010 for -assembly of NASM or GAS syntax code into Win32 or Win64 object files. - -See https://yasm.tortall.net - -License -------- - -Yasm is licensed under the 2-clause and 3-clause “revised” BSD licenses, -with one exception: the Bit::Vector module used by the mainline version -of Yasm to implement its large integer and machine-independent floating -point support is triple-licensed under the Artistic license, GPL, and -LGPL. The “yasm-nextgen” codebase uses a different BSD-licensed -implementation and is thus entirely under BSD-equivalent licenses. The -full text of the licenses are provided in the Yasm source distribution. - - -Upstream Contact ----------------- - -- https://yasm.tortall.net - -Dependencies ------------- - -- none diff --git a/build/pkgs/yasm/checksums.ini b/build/pkgs/yasm/checksums.ini deleted file mode 100644 index 5889d0ce114..00000000000 --- a/build/pkgs/yasm/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=yasm-VERSION.tar.gz -sha1=b7574e9f0826bedef975d64d3825f75fbaeef55e -md5=fc9e586751ff789b34b1f21d572d96af -cksum=3388492465 diff --git a/build/pkgs/yasm/dependencies b/build/pkgs/yasm/dependencies deleted file mode 100644 index 2f9f3849682..00000000000 --- a/build/pkgs/yasm/dependencies +++ /dev/null @@ -1 +0,0 @@ -# no dependencies diff --git a/build/pkgs/yasm/distros/alpine.txt b/build/pkgs/yasm/distros/alpine.txt deleted file mode 100644 index eff8d5c7abd..00000000000 --- a/build/pkgs/yasm/distros/alpine.txt +++ /dev/null @@ -1 +0,0 @@ -yasm diff --git a/build/pkgs/yasm/distros/conda.txt b/build/pkgs/yasm/distros/conda.txt deleted file mode 100644 index eff8d5c7abd..00000000000 --- a/build/pkgs/yasm/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -yasm diff --git a/build/pkgs/yasm/distros/cygwin.txt b/build/pkgs/yasm/distros/cygwin.txt deleted file mode 100644 index eff8d5c7abd..00000000000 --- a/build/pkgs/yasm/distros/cygwin.txt +++ /dev/null @@ -1 +0,0 @@ -yasm diff --git a/build/pkgs/yasm/distros/debian.txt b/build/pkgs/yasm/distros/debian.txt deleted file mode 100644 index eff8d5c7abd..00000000000 --- a/build/pkgs/yasm/distros/debian.txt +++ /dev/null @@ -1 +0,0 @@ -yasm diff --git a/build/pkgs/yasm/distros/fedora.txt b/build/pkgs/yasm/distros/fedora.txt deleted file mode 100644 index eff8d5c7abd..00000000000 --- a/build/pkgs/yasm/distros/fedora.txt +++ /dev/null @@ -1 +0,0 @@ -yasm diff --git a/build/pkgs/yasm/distros/freebsd.txt b/build/pkgs/yasm/distros/freebsd.txt deleted file mode 100644 index d04eee4fbc4..00000000000 --- a/build/pkgs/yasm/distros/freebsd.txt +++ /dev/null @@ -1 +0,0 @@ -devel/yasm diff --git a/build/pkgs/yasm/distros/homebrew.txt b/build/pkgs/yasm/distros/homebrew.txt deleted file mode 100644 index eff8d5c7abd..00000000000 --- a/build/pkgs/yasm/distros/homebrew.txt +++ /dev/null @@ -1 +0,0 @@ -yasm diff --git a/build/pkgs/yasm/distros/macports.txt b/build/pkgs/yasm/distros/macports.txt deleted file mode 100644 index eff8d5c7abd..00000000000 --- a/build/pkgs/yasm/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -yasm diff --git a/build/pkgs/yasm/distros/opensuse.txt b/build/pkgs/yasm/distros/opensuse.txt deleted file mode 100644 index eff8d5c7abd..00000000000 --- a/build/pkgs/yasm/distros/opensuse.txt +++ /dev/null @@ -1 +0,0 @@ -yasm diff --git a/build/pkgs/yasm/distros/repology.txt b/build/pkgs/yasm/distros/repology.txt deleted file mode 100644 index eff8d5c7abd..00000000000 --- a/build/pkgs/yasm/distros/repology.txt +++ /dev/null @@ -1 +0,0 @@ -yasm diff --git a/build/pkgs/yasm/distros/slackware.txt b/build/pkgs/yasm/distros/slackware.txt deleted file mode 100644 index eff8d5c7abd..00000000000 --- a/build/pkgs/yasm/distros/slackware.txt +++ /dev/null @@ -1 +0,0 @@ -yasm diff --git a/build/pkgs/yasm/distros/void.txt b/build/pkgs/yasm/distros/void.txt deleted file mode 100644 index eff8d5c7abd..00000000000 --- a/build/pkgs/yasm/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -yasm diff --git a/build/pkgs/yasm/package-version.txt b/build/pkgs/yasm/package-version.txt deleted file mode 100644 index 05749212e36..00000000000 --- a/build/pkgs/yasm/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -1.3.0.p0 diff --git a/build/pkgs/yasm/spkg-check.in b/build/pkgs/yasm/spkg-check.in deleted file mode 100644 index ae888d81474..00000000000 --- a/build/pkgs/yasm/spkg-check.in +++ /dev/null @@ -1,5 +0,0 @@ -cd src - -# -j1 needed to avoid a possible race condition in the tests -# see https://trac.sagemath.org/ticket/23217 -$MAKE -j1 check diff --git a/build/pkgs/yasm/spkg-configure.m4 b/build/pkgs/yasm/spkg-configure.m4 deleted file mode 100644 index 738443a3a1d..00000000000 --- a/build/pkgs/yasm/spkg-configure.m4 +++ /dev/null @@ -1,20 +0,0 @@ -SAGE_SPKG_CONFIGURE( - [yasm], - # Yasm is only needed on x86(_64) systems; check also for system yasm which - # must support "adox" (new Skylake instruction) - [AC_MSG_CHECKING([for yasm supporting the adox instruction]) - AC_PATH_PROGS_FEATURE_CHECK([YASM], [yasm], - [[{ echo "BITS 64"; echo "adox rax, rax"; } | ${ac_path_YASM} - -o /dev/null >/dev/null 2>/dev/null && - ac_cv_path_YASM=${ac_path_YASM} && - ac_path_YASM_found=: - ]], - [sage_spkg_install_yasm=yes; ac_cv_path_YASM=no]) - AC_MSG_RESULT($ac_cv_path_YASM)], - [dnl REQUIRED-CHECK - AS_CASE("$host_cpu", [i@<:@0-9@:>@86|x86_64|amd64], [], [sage_require_yasm=no]) - AC_REQUIRE([SAGE_SPKG_CONFIGURE_GMP]) - AS_IF([test x$sage_spkg_install_gmp = xno], [ - sage_require_yasm=no - ]) - ] -) diff --git a/build/pkgs/yasm/spkg-install.in b/build/pkgs/yasm/spkg-install.in deleted file mode 100644 index a863950189e..00000000000 --- a/build/pkgs/yasm/spkg-install.in +++ /dev/null @@ -1,5 +0,0 @@ -cd src - -sdh_configure -sdh_make -sdh_make_install diff --git a/build/pkgs/yasm/type b/build/pkgs/yasm/type deleted file mode 100644 index a6a7b9cd726..00000000000 --- a/build/pkgs/yasm/type +++ /dev/null @@ -1 +0,0 @@ -standard From fabdbb3144335ee7fb33957f78d4591b2c176e42 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 22 Sep 2021 20:34:00 -0700 Subject: [PATCH 130/511] build/pkgs/*/SPKG.rst: Clear out redundant 'Dependencies' sections --- build/pkgs/arb/SPKG.rst | 11 ----------- build/pkgs/cddlib/SPKG.rst | 5 ----- build/pkgs/cocoalib/SPKG.rst | 11 ----------- build/pkgs/e_antic/SPKG.rst | 7 ------- build/pkgs/ecm/SPKG.rst | 12 ++---------- build/pkgs/fflas_ffpack/spkg-configure.m4 | 2 -- build/pkgs/flint/SPKG.rst | 7 ------- build/pkgs/gcc/SPKG.rst | 14 -------------- 8 files changed, 2 insertions(+), 67 deletions(-) diff --git a/build/pkgs/arb/SPKG.rst b/build/pkgs/arb/SPKG.rst index 404b21eb1db..cff49ddb95b 100644 --- a/build/pkgs/arb/SPKG.rst +++ b/build/pkgs/arb/SPKG.rst @@ -25,14 +25,3 @@ Upstream Contact - https://arblib.org/ - http://github.com/fredrik-johansson/arb/ - -Dependencies ------------- - -- FLINT -- MPIR or GMP -- MPFR - - -Special Update/Build Instructions ---------------------------------- diff --git a/build/pkgs/cddlib/SPKG.rst b/build/pkgs/cddlib/SPKG.rst index 89915efe311..6ab9a303cdd 100644 --- a/build/pkgs/cddlib/SPKG.rst +++ b/build/pkgs/cddlib/SPKG.rst @@ -31,8 +31,3 @@ Upstream Contact ---------------- https://github.com/cddlib/cddlib - -Dependencies ------------- - -- gmp (or its fork mpir) diff --git a/build/pkgs/cocoalib/SPKG.rst b/build/pkgs/cocoalib/SPKG.rst index 3afd8a68286..783c6cc7126 100644 --- a/build/pkgs/cocoalib/SPKG.rst +++ b/build/pkgs/cocoalib/SPKG.rst @@ -19,14 +19,3 @@ Upstream Contact - Email: cocoa@dima.unige.it - Website: http://cocoa.dima.unige.it/ - Releases: http://cocoa.dima.unige.it/cocoalib/ - -Dependencies ------------- - -- GMP/MPIR - - -Special Update/Build Instructions ---------------------------------- - -None. diff --git a/build/pkgs/e_antic/SPKG.rst b/build/pkgs/e_antic/SPKG.rst index 32dfecbef0b..005a25b7e13 100644 --- a/build/pkgs/e_antic/SPKG.rst +++ b/build/pkgs/e_antic/SPKG.rst @@ -19,10 +19,3 @@ Upstream Contact ---------------- - https://github.com/videlec/e-antic - -Dependencies ------------- - -- GMP/MPIR -- FLINT -- ARB diff --git a/build/pkgs/ecm/SPKG.rst b/build/pkgs/ecm/SPKG.rst index f8d0e352e56..2d88c659ae1 100644 --- a/build/pkgs/ecm/SPKG.rst +++ b/build/pkgs/ecm/SPKG.rst @@ -19,13 +19,6 @@ Upstream Contact - ecm-discuss@lists.gforge.inria.fr (requires subscription) -Dependencies ------------- - -- GMP/MPIR (Note: Python is \*not\* required for ordinary builds.) -- GNU patch - - Special Update/Build Instructions --------------------------------- @@ -47,11 +40,10 @@ Special Update/Build Instructions Note that this doesn't affect the packages' selection of processor- specific optimized [assembly] code. 'spkg-install' already reads the settings from Sage's and also a - system-wide GMP / MPIR now, but doesn't (yet) use all of them. + system-wide GMP now, but doesn't (yet) use all of them. If SAGE_FAT_BINARY="yes", we should avoid too specific settings of "-mcpu=...", and perhaps pass a more generic "--host=..." to - 'configure'. (MPIR honors '--enable-fat' to some extent, but this - option isn't used on anything other than x86 / x86_64.) + 'configure'. - We currently work around a linker bug on MacOS X 10.5 PPC (with GCC 4.2.1) which breaks 'configure' if debug symbols are enabled. diff --git a/build/pkgs/fflas_ffpack/spkg-configure.m4 b/build/pkgs/fflas_ffpack/spkg-configure.m4 index f107ff5cf15..6f6221cbb4f 100644 --- a/build/pkgs/fflas_ffpack/spkg-configure.m4 +++ b/build/pkgs/fflas_ffpack/spkg-configure.m4 @@ -1,6 +1,4 @@ SAGE_SPKG_CONFIGURE([fflas_ffpack], [ - # fflas-lapack uses whatever multi-precision library givaro uses, - # either gmp or mpir. SAGE_SPKG_DEPCHECK([atlas givaro gmp openblas], [ # If our dependencies come from the system, then we can use # the system fflas-ffpack, too. Use pkg-config to find a diff --git a/build/pkgs/flint/SPKG.rst b/build/pkgs/flint/SPKG.rst index 146c6ac1c82..f91de70d1ff 100644 --- a/build/pkgs/flint/SPKG.rst +++ b/build/pkgs/flint/SPKG.rst @@ -21,10 +21,3 @@ Upstream Contact - flint-devel Gougle Group (http://groups.google.co.uk/group/flint-devel) - William Hart - -Dependencies ------------- - -- MPIR -- MPFR -- NTL diff --git a/build/pkgs/gcc/SPKG.rst b/build/pkgs/gcc/SPKG.rst index 6004b986078..1f5684b86b2 100644 --- a/build/pkgs/gcc/SPKG.rst +++ b/build/pkgs/gcc/SPKG.rst @@ -16,17 +16,3 @@ Upstream Contact ---------------- https://gcc.gnu.org/ - -Dependencies ------------- - -- zlib -- MPIR -- MPFR -- MPC - - -Special Update/Build Instructions ---------------------------------- - -None. From 724c3ffd97682ced5521000df878a426a4901bd3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 22 Sep 2021 21:13:30 -0700 Subject: [PATCH 131/511] src/doc/en/developer/portability_testing.rst: Remove references to package yasm --- src/doc/en/developer/portability_testing.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 204c173dc52..e6a61ebeb58 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -220,10 +220,10 @@ Using Sage's database of equivalent distribution packages At the end of the ``./configure`` run, Sage issued a message like the following:: - configure: notice: the following SPKGs did not find equivalent system packages: arb boost boost_cropped bzip2 ... yasm zeromq zlib + configure: notice: the following SPKGs did not find equivalent system packages: arb boost_cropped bzip2 ... zeromq zlib checking for the package system in use... debian configure: hint: installing the following system packages is recommended and may avoid building some of the above SPKGs from source: - configure: $ sudo apt-get install libflint-arb-dev ... yasm libzmq3-dev libz-dev + configure: $ sudo apt-get install libflint-arb-dev ... libzmq3-dev libz-dev configure: After installation, re-run configure using: configure: $ ./config.status --recheck && ./config.status @@ -248,7 +248,7 @@ system, in particular a list of installed packages and their versions. Let us install a subset of these packages:: - root@39d693b2a75d:/sage# apt-get install libbz2-dev bzip2 yasm libz-dev + root@39d693b2a75d:/sage# apt-get install libbz2-dev bzip2 libz-dev Reading package lists... Done ... Setting up zlib1g-dev:amd64 (1:1.2.11.dfsg-0ubuntu2) ... @@ -285,8 +285,8 @@ have no access to the worktree:: root@73987568712c:/# cd sage root@73987568712c:/sage# command -v gcc /usr/bin/gcc - root@73987568712c:/sage# command -v yasm - /usr/bin/yasm + root@73987568712c:/sage# command -v bunzip2 + /usr/bin/bunzip2 root@73987568712c:/sage# ^D [mkoeppe@sage worktree-ubuntu-latest]$ @@ -337,7 +337,7 @@ image...:: Then, to install system packages...:: ... - RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -qqq --no-install-recommends --yes binutils make m4 perl python3 ... yasm libzmq3-dev libz-dev && apt-get clean + RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -qqq --no-install-recommends --yes binutils make m4 perl python3 ... libzmq3-dev libz-dev && apt-get clean Then, to bootstrap and configure...:: @@ -852,10 +852,10 @@ an isolated copy of Homebrew with all prerequisites for bootstrapping:: checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes ... - configure: notice: the following SPKGs did not find equivalent system packages: arb cbc cliquer ... tachyon xz yasm zeromq + configure: notice: the following SPKGs did not find equivalent system packages: arb cbc cliquer ... tachyon xz zeromq checking for the package system in use... homebrew configure: hint: installing the following system packages is recommended and may avoid building some of the above SPKGs from source: - configure: $ brew install cmake gcc gsl mpfi ninja openblas gpatch r readline xz yasm zeromq + configure: $ brew install cmake gcc gsl mpfi ninja openblas gpatch r readline xz zeromq ... sage-logger -p 'sage-spkg -y -o lrslib-062+autotools-2017-03-03.p1' '.../worktree-local/logs/pkgs/lrslib-062+autotools-2017-03-03.p1.log' [lrslib-062+autotools-2017-03-03.p1] installing. Log file: .../worktree-local/logs/pkgs/lrslib-062+autotools-2017-03-03.p1.log From 519dc83bc151b00a07d7e534d392f1139c615696 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 22 Sep 2021 21:16:16 -0700 Subject: [PATCH 132/511] m4/sage_spkg_configure.m4: In documentation, do not use yasm as an example --- m4/sage_spkg_configure.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/m4/sage_spkg_configure.m4 b/m4/sage_spkg_configure.m4 index d8b64f831fb..76d5f4b8e2b 100644 --- a/m4/sage_spkg_configure.m4 +++ b/m4/sage_spkg_configure.m4 @@ -29,8 +29,8 @@ # # - REQUIRED-CHECK - this checks whether or not the package is a required # dependency of Sage at all, depending typically on the platform. Some -# packages (e.g. yasm, among others) are only dependencies on certain -# platforms, and otherwise do not need to be checked for at all. If +# packages (e.g. sqlite) are only dependencies in some circumstances +# and otherwise do not need to be checked for at all. If # a REQUIRED-CHECK determines that the package is not required it sets # sage_require_="no". # From 01406bfea4ce7469c1d6520713f5952b6f133d2a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 22 Sep 2021 21:20:28 -0700 Subject: [PATCH 133/511] build/pkgs/*/SPKG.rst: Clear out more redundant 'Dependencies' sections --- build/pkgs/gfan/SPKG.rst | 7 ------- build/pkgs/givaro/SPKG.rst | 6 ------ build/pkgs/glpk/SPKG.rst | 7 ------- 3 files changed, 20 deletions(-) diff --git a/build/pkgs/gfan/SPKG.rst b/build/pkgs/gfan/SPKG.rst index 58faef4f8f7..d2416f4a4d0 100644 --- a/build/pkgs/gfan/SPKG.rst +++ b/build/pkgs/gfan/SPKG.rst @@ -36,13 +36,6 @@ Anders Nedergaard Jensen https://users-math.au.dk/jensen/software/gfan/gfan.html -Dependencies ------------- - -- GMP/MPIR -- CDDLIB - - Special Update/Build Instructions --------------------------------- diff --git a/build/pkgs/givaro/SPKG.rst b/build/pkgs/givaro/SPKG.rst index fe64ba38237..1dcb4e45412 100644 --- a/build/pkgs/givaro/SPKG.rst +++ b/build/pkgs/givaro/SPKG.rst @@ -28,9 +28,3 @@ Upstream Contact ---------------- - Clement Pernet - -Dependencies ------------- - -- GNU patch -- GMP/MPIR diff --git a/build/pkgs/glpk/SPKG.rst b/build/pkgs/glpk/SPKG.rst index 75acbf1c1f2..4cabfae0ba1 100644 --- a/build/pkgs/glpk/SPKG.rst +++ b/build/pkgs/glpk/SPKG.rst @@ -36,13 +36,6 @@ GLPK is currently being maintained by: http://www.gnu.org/software/glpk/#maintainer -Dependencies ------------- - -- GMP/MPIR -- zlib - - Special Update/Build Instructions --------------------------------- From 205931c51add322c179185787fd90905f66f5f68 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 22 Sep 2021 21:27:02 -0700 Subject: [PATCH 134/511] src/doc/en/installation/source.rst: Remove doc of envvar SAGE_MP_LIBRARY --- src/doc/en/installation/source.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index 0b30005d755..d73e3b2ea60 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -1283,11 +1283,6 @@ Here are some of the more commonly used variables affecting the build process: Environment variables dealing with specific Sage packages: -- :envvar:`SAGE_MP_LIBRARY` - to use an alternative library in place of ``MPIR`` - for multiprecision integer arithmetic. Supported values are - - ``MPIR`` (default choice), ``GMP``. - - :envvar:`SAGE_ATLAS_ARCH` - if you are compiling ATLAS (in particular, if :envvar:`SAGE_ATLAS_LIB` is not set), you can use this environment variable to set a particular architecture and instruction set extension, From e7fdb3578039895ff83e372ec511363b67b3e584 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 22 Sep 2021 21:28:21 -0700 Subject: [PATCH 135/511] src/doc/en/installation/source.rst: Remove use of mpir as an example package --- src/doc/en/installation/source.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index d73e3b2ea60..e28bf58bb14 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -1125,8 +1125,8 @@ Here are some of the more commonly used variables affecting the build process: An entry ``package-name`` means to run the test suite for the named package regardless of the setting of :envvar:`SAGE_CHECK`. An entry ``!package-name`` means to skip its test suite. - So if this is set to ``mpir,!python3``, then always run the test suite for - MPIR, but always skip the test suite for Python 3. + So if this is set to ``ppl,!python3``, then always run the test suite for + PPL, but always skip the test suite for Python 3. .. note:: From 1eb83e30878c74b245547c22b6e165d4acf0595e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 22 Sep 2021 21:39:29 -0700 Subject: [PATCH 136/511] build/pkgs/ratpoints/SPKG.rst: Remove redundant 'Dependencies' section --- build/pkgs/ratpoints/SPKG.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/build/pkgs/ratpoints/SPKG.rst b/build/pkgs/ratpoints/SPKG.rst index 34616de3437..6607094bec9 100644 --- a/build/pkgs/ratpoints/SPKG.rst +++ b/build/pkgs/ratpoints/SPKG.rst @@ -19,16 +19,6 @@ Upstream Contact - Email: Michael.Stoll@uni-bayreuth.de - Website: http://www.mathe2.uni-bayreuth.de/stoll/programs/ -Dependencies ------------- - -- GMP/MPIR -- (GNU) patch - - -Special Update/Build Instructions ---------------------------------- - Note on SSE2 instructions ~~~~~~~~~~~~~~~~~~~~~~~~~ From f883ea4c76e96fdbf0cbf8028fd65ce4513a786d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 23 Sep 2021 07:43:19 -0700 Subject: [PATCH 137/511] Integer.binomial: Add algorithm='gmp', keep 'mpir' as an alias --- src/sage/arith/misc.py | 8 ++++---- src/sage/rings/integer.pyx | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 83f3a957d17..039e1fcae3f 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -2242,7 +2242,7 @@ def rational_reconstruction(a, m, algorithm='fast'): - ``algorithm`` -- (default: 'fast') - - ``'fast'`` - a fast implementation using direct MPIR calls + - ``'fast'`` - a fast implementation using direct GMP library calls in Cython. OUTPUT: @@ -3433,10 +3433,10 @@ def binomial(x, m, **kwds): 1/6*x^3 - 1/2*x^2 + 1/3*x If `x \in \ZZ`, there is an optional 'algorithm' parameter, which - can be 'mpir' (faster for small values) or 'pari' (faster for - large values):: + can be 'gmp' (faster for small values; alias: 'mpir') or + 'pari' (faster for large values):: - sage: a = binomial(100, 45, algorithm='mpir') + sage: a = binomial(100, 45, algorithm='gmp') sage: b = binomial(100, 45, algorithm='pari') sage: a == b True diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 12f4124655c..b864dfe8857 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -6787,7 +6787,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): """ return self - def binomial(self, m, algorithm='mpir'): + def binomial(self, m, algorithm='gmp'): """ Return the binomial coefficient "self choose m". @@ -6795,9 +6795,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): - ``m`` -- an integer - - ``algorithm`` -- ``'mpir'`` (default) or ``'pari'``; ``'mpir'`` is - faster for small ``m``, and ``'pari'`` tends to be faster for - large ``m`` + - ``algorithm`` -- ``'gmp'`` (default), ``'mpir'`` (an alias for + ``gmp``), or ``'pari'``; ``'gmp'`` is faster for small ``m``, + and ``'pari'`` tends to be faster for large ``m`` OUTPUT: @@ -6878,7 +6878,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return self # now call the various backend - if algorithm == 'mpir': + if algorithm == 'gmp' or algorithm == 'mpir': x = PY_NEW(Integer) if mpz_fits_ulong_p(mm.value): sig_on() @@ -6890,7 +6890,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): elif algorithm == 'pari': return the_integer_ring(self.__pari__().binomial(mm)) else: - raise ValueError("algorithm must be one of: 'pari', 'mpir'") + raise ValueError("algorithm must be one of: 'pari' or 'gmp' (alias: 'mpir')") cdef int mpz_set_str_python(mpz_ptr z, char* s, int base) except -1: From 1647e2f9ce387e40273b2cb42b46b7f6de378562 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 23 Sep 2021 09:23:00 -0700 Subject: [PATCH 138/511] src/sage/rings/integer.pyx: Rewrite a doctest so it works with gmp, mpir, 64bit, 32bit --- src/sage/rings/integer.pyx | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index b864dfe8857..5dd604e7a87 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -6424,17 +6424,14 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): TESTS:: - sage: 1 << (2^60) # optional - mpir - Traceback (most recent call last): - ... - MemoryError: failed to allocate ... bytes # 64-bit - OverflowError: Python int too large to convert to C long # 32-bit - - sage: 1 << (2^60) # optional - gmp - Traceback (most recent call last): - ... - RuntimeError: Aborted # 64-bit - OverflowError: Python int too large to convert to C long # 32-bit + sage: try: + ....: print('Possible error output from gmp') + ....: 1 << (2^60) + ....: except (MemoryError, OverflowError, RuntimeError): + ....: pass + ....: else: + ....: print("Failed to raise exception") + Possible error output from gmp... """ cdef long n From 34526ca3ce293701c88607ec385a35b9d8a33e27 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 23 Sep 2021 09:29:53 -0700 Subject: [PATCH 139/511] build/pkgs/*/SPKG.rst: Remove some more redundant 'Dependencies' sections --- build/pkgs/latte_int/SPKG.rst | 5 ----- build/pkgs/ppl/SPKG.rst | 17 ----------------- build/pkgs/singular/SPKG.rst | 10 ---------- 3 files changed, 32 deletions(-) diff --git a/build/pkgs/latte_int/SPKG.rst b/build/pkgs/latte_int/SPKG.rst index 7f97ded201b..9bd0480ce25 100644 --- a/build/pkgs/latte_int/SPKG.rst +++ b/build/pkgs/latte_int/SPKG.rst @@ -17,8 +17,3 @@ Upstream Contact ---------------- Matthias Köppe, UC Davis, CA, USA - -Dependencies ------------- - -GMP (MPIR), 4ti2, NTL, cddlib. diff --git a/build/pkgs/ppl/SPKG.rst b/build/pkgs/ppl/SPKG.rst index 90f9f264b8e..53f1e8df54e 100644 --- a/build/pkgs/ppl/SPKG.rst +++ b/build/pkgs/ppl/SPKG.rst @@ -41,20 +41,3 @@ Core Development Team - Roberto Bagnara (University of Parma) - Patricia M. Hill (University of Parma) - Enea Zaffanella (University of Parma) - -Dependencies ------------- - -- gmp (or mpir) - - -Special Update/Build Instructions ---------------------------------- - -Patches -~~~~~~~ - -- ptrdiff_t-ppl-1.1.patch: Fixes to compile with gcc 4.9; C++ name - lookup issue. - -- weak.patch: disable use of weak symbols on Cygwin64. diff --git a/build/pkgs/singular/SPKG.rst b/build/pkgs/singular/SPKG.rst index eed2b57980d..f8bf274b4e2 100644 --- a/build/pkgs/singular/SPKG.rst +++ b/build/pkgs/singular/SPKG.rst @@ -20,16 +20,6 @@ libsingular-devel@mathematik.uni-kl.de https://www.singular.uni-kl.de/ -Dependencies ------------- - -- GNU patch -- readline -- GMP/MPIR -- MPFR -- NTL -- FLINT - Special Update/Build Instructions --------------------------------- From b8bfd454514fa8251a9eb9e59b3d84c7f95f880e Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 23 Sep 2021 10:55:05 -0700 Subject: [PATCH 140/511] trac 32555: preface indented block in documentation with :: --- src/doc/en/developer/portability_testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 204c173dc52..fee2e78f882 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -707,7 +707,7 @@ other prerequisites installed in your system. See ``build/pkgs/_bootstrap/distros/*.txt`` for a list of system packages that provide these prerequisites. -We start by creating a fresh (distclean) git worktree. +We start by creating a fresh (distclean) git worktree:: [mkoeppe@sage sage] git worktree add worktree-local [mkoeppe@sage sage] cd worktree-local From e3ff6aa5aacc6cde5ea466322878a69437b2b376 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 23 Sep 2021 15:24:02 -0700 Subject: [PATCH 141/511] trac 32549: misc small changes, plus don't include mpir in sdist --- COPYING.txt | 1 - build/pkgs/ecm/spkg-configure.m4 | 2 +- build/pkgs/gdb/SPKG.rst | 11 ----------- build/pkgs/isl/spkg-configure.m4 | 2 +- build/pkgs/mpfr/spkg-configure.m4 | 2 +- m4/sage_spkg_collect.m4 | 8 -------- 6 files changed, 3 insertions(+), 23 deletions(-) diff --git a/COPYING.txt b/COPYING.txt index 2da3a8e492c..7ce750a1aa9 100644 --- a/COPYING.txt +++ b/COPYING.txt @@ -86,7 +86,6 @@ mistune Modified BSD mpc LGPLv3+ mpfi COPYING is GPLv2, source files state LGPLv2.1+ mpfr LGPLv3+ -mpir LGPLv3+ mpmath Modified BSD networkx Modified BSD ntl GPLv2+ diff --git a/build/pkgs/ecm/spkg-configure.m4 b/build/pkgs/ecm/spkg-configure.m4 index e62c21cb32e..d5302a89fb0 100644 --- a/build/pkgs/ecm/spkg-configure.m4 +++ b/build/pkgs/ecm/spkg-configure.m4 @@ -1,7 +1,7 @@ SAGE_SPKG_CONFIGURE([ecm], [ m4_pushdef([SAGE_ECM_MINVER],[7.0.4]) AC_REQUIRE([SAGE_SPKG_CONFIGURE_GMP]) - AC_MSG_CHECKING([installing gmp/mpir? ]) + AC_MSG_CHECKING([installing gmp? ]) if test x$sage_spkg_install_gmp = xyes; then AC_MSG_RESULT([yes; install ecm as well]) sage_spkg_install_ecm=yes diff --git a/build/pkgs/gdb/SPKG.rst b/build/pkgs/gdb/SPKG.rst index b89773fe676..0716ac53fad 100644 --- a/build/pkgs/gdb/SPKG.rst +++ b/build/pkgs/gdb/SPKG.rst @@ -19,17 +19,6 @@ Upstream Contact http://www.gnu.org/software/gdb/ -Dependencies ------------- - -- python -- mpc -- mpfr -- ppl -- gmp/mpir -- makeinfo (external) - - Special Update/Build Instructions --------------------------------- diff --git a/build/pkgs/isl/spkg-configure.m4 b/build/pkgs/isl/spkg-configure.m4 index 1b16f70870b..d7bbef80c6b 100644 --- a/build/pkgs/isl/spkg-configure.m4 +++ b/build/pkgs/isl/spkg-configure.m4 @@ -1,6 +1,6 @@ SAGE_SPKG_CONFIGURE([isl], [ AC_REQUIRE([SAGE_SPKG_CONFIGURE_GMP]) - AC_MSG_CHECKING([installing gmp/mpir? ]) + AC_MSG_CHECKING([installing gmp? ]) if test x$sage_spkg_install_gmp = xyes; then AC_MSG_RESULT([yes; install isl as well]) sage_spkg_install_isl=yes diff --git a/build/pkgs/mpfr/spkg-configure.m4 b/build/pkgs/mpfr/spkg-configure.m4 index 2300be67076..f64ede4b750 100644 --- a/build/pkgs/mpfr/spkg-configure.m4 +++ b/build/pkgs/mpfr/spkg-configure.m4 @@ -1,6 +1,6 @@ SAGE_SPKG_CONFIGURE([mpfr], [ AC_REQUIRE([SAGE_SPKG_CONFIGURE_GMP]) - AC_MSG_CHECKING([installing gmp/mpir? ]) + AC_MSG_CHECKING([installing gmp? ]) if test x$sage_spkg_install_gmp = xyes; then AC_MSG_RESULT([yes; install mpfr as well]) sage_spkg_install_mpfr=yes diff --git a/m4/sage_spkg_collect.m4 b/m4/sage_spkg_collect.m4 index 1ab62d6fa47..c364ab62b72 100644 --- a/m4/sage_spkg_collect.m4 +++ b/m4/sage_spkg_collect.m4 @@ -259,14 +259,6 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do AS_VAR_POPDEF([sage_require])dnl AS_VAR_POPDEF([sage_spkg_install])dnl - # Packages that should be included in the source distribution - # This includes all standard packages and two special cases - case "$SPKG_NAME" in - mpir) - in_sdist=yes - ;; - esac - # Determine package source # if test -f "$DIR/requirements.txt"; then From ccd0ff5770e18037d638e31c2cf67fdbd3f21b22 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sun, 26 Sep 2021 10:03:10 +0100 Subject: [PATCH 142/511] use SAGE_SPKG_DEPCHECK --- build/pkgs/ecm/spkg-configure.m4 | 10 ++-------- build/pkgs/isl/spkg-configure.m4 | 10 ++-------- build/pkgs/mpc/spkg-configure.m4 | 10 ++-------- build/pkgs/mpfi/spkg-configure.m4 | 15 ++------------- build/pkgs/mpfr/spkg-configure.m4 | 10 ++-------- 5 files changed, 10 insertions(+), 45 deletions(-) diff --git a/build/pkgs/ecm/spkg-configure.m4 b/build/pkgs/ecm/spkg-configure.m4 index d5302a89fb0..d456f1d8f2c 100644 --- a/build/pkgs/ecm/spkg-configure.m4 +++ b/build/pkgs/ecm/spkg-configure.m4 @@ -1,12 +1,6 @@ SAGE_SPKG_CONFIGURE([ecm], [ m4_pushdef([SAGE_ECM_MINVER],[7.0.4]) - AC_REQUIRE([SAGE_SPKG_CONFIGURE_GMP]) - AC_MSG_CHECKING([installing gmp? ]) - if test x$sage_spkg_install_gmp = xyes; then - AC_MSG_RESULT([yes; install ecm as well]) - sage_spkg_install_ecm=yes - else - AC_MSG_RESULT([no. ]) + SAGE_SPKG_DEPCHECK([gmp], [ AC_CHECK_HEADER(ecm.h, [ AX_ABSOLUTE_HEADER([ecm.h]) if test x$gl_cv_absolute_ecm_h = x; then @@ -38,6 +32,6 @@ SAGE_SPKG_CONFIGURE([ecm], [ AS_IF([test -z "$ac_cv_ECM"], [sage_spkg_install_ecm=yes]) AS_IF([test -z "$ac_cv_ECMBIN"], [sage_spkg_install_ecm=yes]) ], [sage_spkg_install_ecm=yes]) - fi + ]) m4_popdef([SAGE_ECM_MINVER]) ]) diff --git a/build/pkgs/isl/spkg-configure.m4 b/build/pkgs/isl/spkg-configure.m4 index d7bbef80c6b..db2b400b6e3 100644 --- a/build/pkgs/isl/spkg-configure.m4 +++ b/build/pkgs/isl/spkg-configure.m4 @@ -1,13 +1,7 @@ SAGE_SPKG_CONFIGURE([isl], [ - AC_REQUIRE([SAGE_SPKG_CONFIGURE_GMP]) - AC_MSG_CHECKING([installing gmp? ]) - if test x$sage_spkg_install_gmp = xyes; then - AC_MSG_RESULT([yes; install isl as well]) - sage_spkg_install_isl=yes - else - AC_MSG_RESULT([no]) + SAGE_SPKG_DEPCHECK([gmp], [ PKG_CHECK_MODULES([ISL], [isl >= 0.20], [], [ sage_spkg_install_isl=yes]) - fi + ]) ]) diff --git a/build/pkgs/mpc/spkg-configure.m4 b/build/pkgs/mpc/spkg-configure.m4 index 32aca4ada1b..1e8c475e1ff 100644 --- a/build/pkgs/mpc/spkg-configure.m4 +++ b/build/pkgs/mpc/spkg-configure.m4 @@ -1,15 +1,9 @@ SAGE_SPKG_CONFIGURE([mpc], [ - AC_REQUIRE([SAGE_SPKG_CONFIGURE_MPFR]) - AC_MSG_CHECKING([installing mpfr? ]) - if test x$sage_spkg_install_mpfr = xyes; then - AC_MSG_RESULT([yes; install mpc as well]) - sage_spkg_install_mpc=yes - else - AC_MSG_RESULT([no]) + SAGE_SPKG_DEPCHECK([mpfr], [ AC_CHECK_HEADER(mpc.h, [], [sage_spkg_install_mpc=yes]) dnl mpc_cmp_abs appeared in MPC 1.1.0 AC_SEARCH_LIBS([mpc_cmp_abs], [mpc], [], [sage_spkg_install_mpc=yes]) - fi + ]) ], [], [], [ if test x$sage_spkg_install_mpc = xyes; then AC_SUBST(SAGE_MPC_PREFIX, ['$SAGE_LOCAL']) diff --git a/build/pkgs/mpfi/spkg-configure.m4 b/build/pkgs/mpfi/spkg-configure.m4 index 0cdb10a920e..4542dce794a 100644 --- a/build/pkgs/mpfi/spkg-configure.m4 +++ b/build/pkgs/mpfi/spkg-configure.m4 @@ -1,17 +1,7 @@ SAGE_SPKG_CONFIGURE([mpfi], [ - AC_REQUIRE([SAGE_SPKG_CONFIGURE_MPFR]) - AC_MSG_CHECKING([installing mpfr? ]) - if test x$sage_spkg_install_mpfr = xyes; then - AC_MSG_RESULT([yes; install mpfi as well]) - sage_spkg_install_mpfi=yes - else - AC_MSG_RESULT([no]) - fi - m4_pushdef(SAGE_MPFI_VERSION_MAJOR, [1]) m4_pushdef(SAGE_MPFI_VERSION_MINOR, [5]) - - if test x$sage_spkg_install_mpfi != xyes; then + SAGE_SPKG_DEPCHECK([mpfr], [ AC_CHECK_HEADER([mpfi.h], [], [sage_spkg_install_mpfi=yes]) AC_SEARCH_LIBS([mpfi_diam_abs], [mpfi], [ AC_LANG_PUSH(C) @@ -31,9 +21,8 @@ SAGE_SPKG_CONFIGURE([mpfi], [ sage_spkg_install_mpfi=yes], [AC_MSG_RESULT([cross compiling. assume yes])]) AC_LANG_POP(C)], [sage_spkg_install_mpfi=yes]) - fi + ]) m4_popdef([SAGE_MPFI_VERSION_MAJOR]) m4_popdef([SAGE_MPFI_VERSION_MINOR]) ]) - diff --git a/build/pkgs/mpfr/spkg-configure.m4 b/build/pkgs/mpfr/spkg-configure.m4 index f64ede4b750..47056d06c09 100644 --- a/build/pkgs/mpfr/spkg-configure.m4 +++ b/build/pkgs/mpfr/spkg-configure.m4 @@ -1,15 +1,9 @@ SAGE_SPKG_CONFIGURE([mpfr], [ - AC_REQUIRE([SAGE_SPKG_CONFIGURE_GMP]) - AC_MSG_CHECKING([installing gmp? ]) - if test x$sage_spkg_install_gmp = xyes; then - AC_MSG_RESULT([yes; install mpfr as well]) - sage_spkg_install_mpfr=yes - else - AC_MSG_RESULT([no]) + SAGE_SPKG_DEPCHECK([gmp], [ AC_CHECK_HEADER(mpfr.h, [], [sage_spkg_install_mpfr=yes]) dnl mpfr_free_pool appeared in r11922 (Dec 2017) on MPFR svn AC_SEARCH_LIBS([mpfr_free_pool], [mpfr], [], [sage_spkg_install_mpfr=yes]) - fi + ]) ], [], [], [ if test x$sage_spkg_install_mpfr = xyes; then AC_SUBST(SAGE_MPFR_PREFIX, ['$SAGE_LOCAL']) From e400f0e29e1002c273df6e9dd7a518bf845e3b16 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sun, 26 Sep 2021 10:47:46 +0100 Subject: [PATCH 143/511] makes gmp test unconditional, remove mpir test --- src/sage/ext/memory.pyx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/sage/ext/memory.pyx b/src/sage/ext/memory.pyx index ab29f81c0c3..1de6dedab82 100644 --- a/src/sage/ext/memory.pyx +++ b/src/sage/ext/memory.pyx @@ -6,13 +6,7 @@ TESTS: Check that a ``MemoryError`` is raised if we try to allocate a ridiculously large integer, see :trac:`15363`:: - sage: 2^(2^63-2) # optional - mpir - Traceback (most recent call last): - ... - OverflowError: exponent must be at most 2147483647 # 32-bit - MemoryError: failed to allocate 1152921504606847008 bytes # 64-bit - - sage: 2^(2^63-3) # optional - gmp + sage: 2^(2^63-3) Traceback (most recent call last): ... OverflowError: exponent must be at most 2147483647 # 32-bit From 07da6c3872534e01975d3d90affc102a19a8169d Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sun, 26 Sep 2021 10:48:27 +0100 Subject: [PATCH 144/511] fix mpir mentions in FAQs and source comments --- build/pkgs/ppl/spkg-install.in | 2 +- src/doc/en/faq/faq-general.rst | 8 ++++---- src/doc/en/faq/faq-usage.rst | 16 +--------------- src/doc/it/faq/faq-general.rst | 8 ++++---- src/doc/it/faq/faq-usage.rst | 14 -------------- src/sage/all.py | 2 +- 6 files changed, 11 insertions(+), 39 deletions(-) diff --git a/build/pkgs/ppl/spkg-install.in b/build/pkgs/ppl/spkg-install.in index aed909ced26..bc570b95cfc 100644 --- a/build/pkgs/ppl/spkg-install.in +++ b/build/pkgs/ppl/spkg-install.in @@ -1,4 +1,4 @@ -# Make sure that we prefer Sage's mpir library over system-wide gmp/mpir installs +# Make sure that we prefer Sage's gmp library over system-wide gmp installs export CXXFLAGS="$CXXFLAGS -I$SAGE_LOCAL/include" cd src diff --git a/src/doc/en/faq/faq-general.rst b/src/doc/en/faq/faq-general.rst index 53fa60f5c96..bcfc15e6137 100644 --- a/src/doc/en/faq/faq-general.rst +++ b/src/doc/en/faq/faq-general.rst @@ -22,10 +22,10 @@ number theory, but throughout the mathematical sciences. Sage builds upon and extends functionalities of many underlying packages. Even from early on, when Sage was primarily used for number theory, this included -`Givaro `_, -`MPIR `_, -`NTL `_, -`Pari/GP `_, +`Givaro `_, +`GMP `_, +`NTL `_, +`Pari/GP `_, and many others too numerous to list here. Students, teachers, professors, researchers throughout the world use Sage because they require a comprehensive free open source mathematics package that diff --git a/src/doc/en/faq/faq-usage.rst b/src/doc/en/faq/faq-usage.rst index 5da1732f538..2b9c308d402 100644 --- a/src/doc/en/faq/faq-usage.rst +++ b/src/doc/en/faq/faq-usage.rst @@ -180,21 +180,7 @@ Since release 9.0 from January 2020, SageMath is running on top of Python 3. I downloaded a Sage binary and it crashes on startup with "Illegal instruction". What can I do? """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -One way to fix this is to build Sage entirely from source. Another -option is to fix your Sage installation by rebuilding MPIR and ATLAS -by typing the following from the ``SAGE_ROOT`` of your Sage -installation directory and wait about 15 to 20 minutes - -.. CODE-BLOCK:: shell-session - - $ rm spkg/installed/mpir* spkg/installed/atlas* - $ make - -It is possible that the binaries have been built for a newer -architecture than what you have. Nobody has yet figured out how to -build Sage in such a way that MPIR and ATLAS work on all -hardware. This will eventually get fixed. Any help is appreciated. - +One way to fix this is to build Sage entirely from source. I used XXX to install Sage X.Y and that version is giving lots of errors. What can I do? """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" diff --git a/src/doc/it/faq/faq-general.rst b/src/doc/it/faq/faq-general.rst index 298178d1337..a8d81d4605a 100644 --- a/src/doc/it/faq/faq-general.rst +++ b/src/doc/it/faq/faq-general.rst @@ -21,10 +21,10 @@ dei Numeri, ma da ricercatori in tutte le scienze matematiche. Sage si avvale ed estende le funzionalità di molti dei pacchetti inglobati. Anche dal principio, quando Sage veiniva usato principalmente per la Teoria dei Numeri, includeva: -`Givaro `_, -`MPIR `_, -`NTL `_, -`Pari/GP `_, +`Givaro `_, +`GMP `_, +`NTL `_, +`Pari/GP `_, e molti altri troppo numerosi per essere elencati qui. Studenti, insegnanti, professori universitari, ricercatori di tutto il mondo usano Sage perché vogliono un pacchetto open-source comprensivo per la matematica che offra calcolo sia diff --git a/src/doc/it/faq/faq-usage.rst b/src/doc/it/faq/faq-usage.rst index 5267c991c94..1f3a223d902 100644 --- a/src/doc/it/faq/faq-usage.rst +++ b/src/doc/it/faq/faq-usage.rst @@ -160,20 +160,6 @@ Ho scaricato il binario di Sage e va in crash quando lo lancio, con il messaggio """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Un modo di risolvere è compilare Sage interamente dal codice sorgente. -Un'altra possibilità è correggere la tua installazione di Sage con la -ricompilazione dei componenti MPIR e ATLAS (richiede da 15 a 20 minuti), -da effettuarsi da riga di comando a partire dalla cartella -``SAGE_ROOT`` della tua installazione con le 2 istruzioni:: - - rm spkg/installed/mpir* spkg/installed/atlas* - make - -È possibile che i binari siano stati compilati per un'architettura più -recente di quella della tua macchina. Nessuno ha ancora trovato un -modo di compilare Sage in maniera che MPIR ed ATLAS funzionino su -qualunque hardware. Questo sarà prima o poi risolto. -Qualunque aiuto in tal senso sarà apprezzato. - Ho usato Debian/Ubuntu per installare la versione 3.0.5 di Sage ed essa sta dando un sacco di errori. Cosa posso fare? """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" diff --git a/src/sage/all.py b/src/sage/all.py index 5d4d8a77d78..4cb8fd75c7d 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -283,7 +283,7 @@ def quit_sage(verbose=True): import sage.libs.flint.flint sage.libs.flint.flint.free_flint_stack() - # Free globally allocated mpir integers. + # Free globally allocated gmp integers. import sage.rings.integer sage.rings.integer.free_integer_pool() import sage.algebras.quatalg.quaternion_algebra_element From 8c071a8daa50bf21d6dc4cab6d56eadcdec92f1d Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sun, 26 Sep 2021 20:04:18 +0100 Subject: [PATCH 145/511] https-fy consistently --- src/doc/en/faq/faq-general.rst | 4 +--- src/doc/it/faq/faq-general.rst | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/doc/en/faq/faq-general.rst b/src/doc/en/faq/faq-general.rst index bcfc15e6137..462fe69e617 100644 --- a/src/doc/en/faq/faq-general.rst +++ b/src/doc/en/faq/faq-general.rst @@ -181,8 +181,6 @@ Why did you write Sage from scratch, instead of using other existing software an Sage was not written from scratch. Most of its underlying mathematics functionalities are made possible through FOSS projects such as -* `ATLAS `_ --- Automatically Tuned - Linear Algebra Software. * `BLAS `_ --- Basic Linear Algebra Subprograms. * `ECL `_ --- Embeddable Common-Lisp system @@ -199,7 +197,7 @@ functionalities are made possible through FOSS projects such as * `NumPy and SciPy `_ --- numerical linear algebra and other numerical computing capabilities for Python. * `OpenBLAS `_ --- an optimized BLAS library. -* `Pari/GP `_ --- a computer algebra +* `Pari/GP `_ --- a computer algebra system for fast computations in number theory. * `Pynac `_ --- a modified version of GiNaC that replaces the dependency on CLN by Python. diff --git a/src/doc/it/faq/faq-general.rst b/src/doc/it/faq/faq-general.rst index a8d81d4605a..39ae0070bf9 100644 --- a/src/doc/it/faq/faq-general.rst +++ b/src/doc/it/faq/faq-general.rst @@ -168,9 +168,6 @@ Perché avete scritto Sage da zero, invece di usare software e librerie preesist Sage non è stato scritto da zero. La maggior parte delle sue funzionalità sono realizzate attraverso progetti FOSS come -* `ATLAS `_ --- libreria software per Algebra - Lineare ottimizzata automaticamente. - * `BLAS `_ --- sottoprogrammi per Algebra Lineare di base. @@ -188,7 +185,7 @@ realizzate attraverso progetti FOSS come * `NumPy `_ --- algebra lineare numerica ed altre funzioni di calcolo numerico per Python. -* `Pari/GP `_ --- software matematico per +* `Pari/GP `_ --- software matematico per calcolo veloce in Teoria dei Numeri. * `Pynac `_ --- versione modificata di GiNaC che From d22bd25f79a08712e03f2ebc8d0e2ff5872a38d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 27 Sep 2021 18:33:38 +0200 Subject: [PATCH 146/511] remove another set of #py2 doctest tags --- src/sage/misc/abstract_method.py | 4 +-- src/sage/misc/bindable_class.py | 12 --------- src/sage/misc/c3_controlled.pyx | 8 +----- src/sage/misc/classcall_metaclass.pyx | 4 +-- src/sage/misc/functional.py | 4 +-- src/sage/misc/lazy_import.pyx | 26 ++++--------------- src/sage/misc/remote_file.py | 3 +-- src/sage/misc/rest_index_of_methods.py | 4 +-- src/sage/misc/sage_eval.py | 11 ++++---- src/sage/misc/sagedoc.py | 7 +---- src/sage/misc/sageinspect.py | 34 +++++++------------------ src/sage/modules/with_basis/morphism.py | 9 ++----- 12 files changed, 28 insertions(+), 98 deletions(-) diff --git a/src/sage/misc/abstract_method.py b/src/sage/misc/abstract_method.py index fdfde979b96..49dc59ba9fa 100644 --- a/src/sage/misc/abstract_method.py +++ b/src/sage/misc/abstract_method.py @@ -125,9 +125,7 @@ def abstract_method(f=None, optional=False): The syntax ``@abstract_method`` w.r.t. @abstract_method(optional = True) is achieved by a little trick which we test here:: - sage: abstract_method(optional = True) # py2 - at ...> - sage: abstract_method(optional = True) # py3 + sage: abstract_method(optional = True) . at ...> sage: abstract_method(optional = True)(banner) diff --git a/src/sage/misc/bindable_class.py b/src/sage/misc/bindable_class.py index bf56d7272b8..c776faf7257 100644 --- a/src/sage/misc/bindable_class.py +++ b/src/sage/misc/bindable_class.py @@ -210,18 +210,6 @@ class BoundClass(functools.partial): sage: g() 8 - The following has incorrect syntax and thus a ``DeprecationWarning``:: - - sage: class mypartial(functools.partial): - ....: def __init__(self, f, i, j): - ....: functools.partial.__init__(self, f, i, j) - sage: g = mypartial(f, 2, 3) # py2; on Python 3 this is an error - Traceback (most recent call last): - ... - DeprecationWarning: object.__init__() takes no parameters - sage: g() - 8 - The following has correct syntax and no ``DeprecationWarning``:: sage: class mynewpartial(functools.partial): diff --git a/src/sage/misc/c3_controlled.pyx b/src/sage/misc/c3_controlled.pyx index d2ca1fe5784..3e70e529ad2 100644 --- a/src/sage/misc/c3_controlled.pyx +++ b/src/sage/misc/c3_controlled.pyx @@ -70,13 +70,7 @@ algorithm easily fails if the order of the bases is not chosen consistently (here for ``A2`` w.r.t. ``A1``):: sage: class B6(A1,A2): pass - sage: class B7(B6,A5): pass # py2 - Traceback (most recent call last): - ... - TypeError: Error when calling the metaclass bases - Cannot create a consistent method resolution - order (MRO) for bases ... - sage: class B7(B6,A5): pass # py3 + sage: class B7(B6,A5): pass Traceback (most recent call last): ... TypeError: Cannot create a consistent method resolution diff --git a/src/sage/misc/classcall_metaclass.pyx b/src/sage/misc/classcall_metaclass.pyx index eb8f75a5094..464a3ea93ec 100644 --- a/src/sage/misc/classcall_metaclass.pyx +++ b/src/sage/misc/classcall_metaclass.pyx @@ -391,9 +391,7 @@ cdef class ClasscallMetaclass(NestedClassMetaclass): sage: bind = obj.Inner calling __classget__(, <__main__.Outer object at 0x...>, ) - sage: bind # py2 - - sage: bind # py3 + sage: bind functools.partial(, <__main__.Outer object at 0x...>) """ if cls.classget: diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index c1f895c217c..45d74ea749a 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -809,9 +809,7 @@ def xinterval(a, b): EXAMPLES:: - sage: I = xinterval(2,5); I # py2 - xrange(2, 6) - sage: I = xinterval(2,5); I # py3 + sage: I = xinterval(2,5); I range(2, 6) sage: 5 in I True diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 7e8b731965a..bccb7c7568f 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -466,13 +466,9 @@ cdef class LazyImport(object): sage: Foo().my_method() <__main__.Foo object at ...> - sage: Foo.my_method # py2 - - sage: Foo.my_method # py3 + sage: Foo.my_method - sage: Foo().my_method # py2 - > - sage: Foo().my_method # py3 + sage: Foo().my_method > When a :class:`LazyImport` method is a method (or attribute) @@ -498,9 +494,7 @@ cdef class LazyImport(object): We access the ``plot`` method:: - sage: Bar.plot # py2 - - sage: Bar.plot # py3 + sage: Bar.plot Now ``plot`` has been replaced in the dictionary of ``Foo``:: @@ -823,12 +817,7 @@ cdef class LazyImport(object): sage: sage.all.foo = 10 sage: lazy_import('sage.all', 'foo') - sage: oct(foo) # py2 - doctest:warning...: - DeprecationWarning: use the method .oct instead - See https://trac.sagemath.org/26756 for details. - '12' - sage: oct(foo) # py3 + sage: oct(foo) '0o12' """ return self.get_object().__oct__() @@ -839,12 +828,7 @@ cdef class LazyImport(object): sage: sage.all.foo = 10 sage: lazy_import('sage.all', 'foo') - sage: hex(foo) # py2 - doctest:warning...: - DeprecationWarning: use the method .hex instead - See https://trac.sagemath.org/26756 for details. - 'a' - sage: hex(foo) # py3 + sage: hex(foo) '0xa' """ return self.get_object().__hex__() diff --git a/src/sage/misc/remote_file.py b/src/sage/misc/remote_file.py index ec8b1194b4e..092640cc9e6 100644 --- a/src/sage/misc/remote_file.py +++ b/src/sage/misc/remote_file.py @@ -38,8 +38,7 @@ def get_remote_file(filename, verbose=True): # IMPORTANT -- urllib takes a long time to load, # so do not import it in the module scope. - # import compatible with py2 and py3 - req = Request(filename, headers={"User-Agent":"sage-doctest"}) + req = Request(filename, headers={"User-Agent": "sage-doctest"}) if verbose: print("Loading started") diff --git a/src/sage/misc/rest_index_of_methods.py b/src/sage/misc/rest_index_of_methods.py index 337d91c554f..b059887b014 100644 --- a/src/sage/misc/rest_index_of_methods.py +++ b/src/sage/misc/rest_index_of_methods.py @@ -233,9 +233,7 @@ def list_of_subfunctions(root, only_local_functions=True): sage: class A: ....: x = staticmethod(Graph.order) - sage: list_of_subfunctions(A) # py2 - ([], {: 'x'}) - sage: list_of_subfunctions(A) # py3 + sage: list_of_subfunctions(A) ([], {: 'x'}) diff --git a/src/sage/misc/sage_eval.py b/src/sage/misc/sage_eval.py index d5ddf7085bb..b1700ab393d 100644 --- a/src/sage/misc/sage_eval.py +++ b/src/sage/misc/sage_eval.py @@ -2,17 +2,18 @@ Evaluating a String in Sage """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from copy import copy import sage.repl.preparse as preparser + def sage_eval(source, locals=None, cmds='', preparse=True): r""" Obtain a Sage object from the input string by evaluating it using @@ -90,9 +91,7 @@ def sage_eval(source, locals=None, cmds='', preparse=True): :: sage: x = 5 - sage: eval('4/3 + x', {'x': 25}) # py2 - 26 - sage: eval('4//3 + x', {'x': 25}) # py3 + sage: eval('4//3 + x', {'x': 25}) 26 sage: sage_eval('4/3 + x', locals={'x': 25}) 79/3 diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index 01e4ec4bcc1..93fa01cb5cc 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -1052,12 +1052,7 @@ def search_src(string, extra1='', extra2='', extra3='', extra4='', The following produces an error because the string 'fetch(' is a malformed regular expression:: - sage: print(search_src(" fetch(", "def", interact=False)) # py2 - Traceback (most recent call last): - ... - error: unbalanced parenthesis - - sage: print(search_src(" fetch(", "def", interact=False)) # py3 + sage: print(search_src(" fetch(", "def", interact=False)) Traceback (most recent call last): ... error: missing ), unterminated subpattern at position 6 diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 72c9cdf1d22..db5013337a3 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -334,11 +334,8 @@ def _extract_embedded_signature(docstring, name): ... sage: _extract_embedded_signature(MainClass.NestedClass.NestedSubClass.dummy.__doc__, 'dummy')[1] ArgSpec(args=['self', 'x', 'r'], varargs='args', keywords='kwds', defaults=((1, 2, 3.4),)) - sage: _extract_embedded_signature(range.__call__.__doc__, '__call__') # py2 - ('x.__call__(...) <==> x(...)', None) - sage: _extract_embedded_signature(range.__call__.__doc__, '__call__') # py3 + sage: _extract_embedded_signature(range.__call__.__doc__, '__call__') ('Call self as a function.', None) - """ # If there is an embedded signature, it is in the first line L = docstring.split(os.linesep, 1) @@ -502,14 +499,10 @@ def visit_Name(self, node): sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit_Name(ast.parse(x).body[0].value) - sage: [vis(n) for n in ['True', 'False', 'None', 'foo', 'bar']] # py2 - [True, False, None, 'foo', 'bar'] - sage: [type(vis(n)) for n in ['True', 'False', 'None', 'foo', 'bar']] # py2 - [, , , , ] - sage: [vis(n) for n in ['foo', 'bar']] # py3 + sage: [vis(n) for n in ['foo', 'bar']] ['foo', 'bar'] - sage: [type(vis(n)) for n in ['foo', 'bar']] # py3 - [, ] + sage: [type(vis(n)) for n in ['foo', 'bar']] + [, ] """ return node.id @@ -587,9 +580,7 @@ def visit_Num(self, node): sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit_Num(ast.parse(x).body[0].value) - sage: [vis(n) for n in ['123', '0.0', str(-pi.n())]] # py2 - [123, 0.0, -3.14159265358979] - sage: [vis(n) for n in ['123', '0.0']] # py3 + sage: [vis(n) for n in ['123', '0.0']] [123, 0.0] .. NOTE:: @@ -809,9 +800,7 @@ def visit_BinOp(self, node): sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit(ast.parse(x).body[0].value) - sage: [vis(d) for d in ['(3+(2*4))', '7|8', '5^3', '7/3', '7//3', '3<<4']] #indirect doctest # py2 - [11, 15, 6, 2, 2, 48] - sage: [vis(d) for d in ['(3+(2*4))', '7|8', '5^3', '7/3', '7//3', '3<<4']] #indirect doctest # py3 + sage: [vis(d) for d in ['(3+(2*4))', '7|8', '5^3', '7/3', '7//3', '3<<4']] #indirect doctest [11, 15, 6, 2.3333333333333335, 2, 48] """ op = node.op.__class__.__name__ @@ -1119,8 +1108,7 @@ def _sage_getargspec_from_ast(source): sage: from_ast(s) ArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, keywords=None, defaults=(2, {'a': [4, 5.5, False]}, (None, True))) sage: context = {} - sage: exec compile(s, '', 'single') in context # py2 - sage: exec(compile(s, '', 'single'), context) # py3 + sage: exec(compile(s, '', 'single'), context) sage: inspect.getargspec(context['f']) ArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, keywords=None, defaults=(2, {'a': [4, 5.5, False]}, (None, True))) sage: from_ast(s) == inspect.getargspec(context['f']) @@ -1207,12 +1195,8 @@ def _sage_getargspec_cython(source): Some input that is malformed in Python 2 but well formed in Cython or Python 3 is correctly parsed:: - sage: def dummy_python(self, *args, x=1): pass # py2 - Traceback (most recent call last): - ... - SyntaxError: invalid syntax - sage: def dummy_python(self, *args, x=1): pass # py3 - sage: sgc("def dummy_python(self, *args, x=1): pass") # py3 + sage: def dummy_python(self, *args, x=1): pass + sage: sgc("def dummy_python(self, *args, x=1): pass") ArgSpec(args=['self', 'x'], varargs='args', keywords=None, defaults=(1,)) sage: cython("def dummy_cython(self, *args, x=1): pass") sage: sgc("def dummy_cython(self, *args, x=1): pass") diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index 6658aa547ac..184b09a94e3 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -1312,16 +1312,11 @@ def __init__(self, domain, matrix, codomain=None, category=None, side="left"): True sage: TestSuite(phi).run(skip=["_test_pickling"]) - Pickling fails (:trac:`17957`) because ``phi._on_basis`` is - currently a ``dict.__getitem__`` which is not picklable in Python 2:: + Pickling works (:trac:`17957`) in Python 3:: sage: phi._on_basis - sage: dumps(phi._on_basis) # py2 - Traceback (most recent call last): - ... - TypeError: expected string or Unicode object, NoneType found - sage: loads(dumps(phi)) == phi # py3 + sage: loads(dumps(phi)) == phi True The matrix is stored in the morphism, as if it was for an From b550c3bcc97bd0ba9508eb09c08975b43b4a0015 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Mon, 27 Sep 2021 18:42:29 +0200 Subject: [PATCH 147/511] #32574 missing factorial factor in RBF/CBF zetaderiv --- src/sage/rings/complex_arb.pyx | 4 +++- src/sage/rings/real_arb.pyx | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index 2fc0a3bb420..9b63bf28c01 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -3643,11 +3643,13 @@ cdef class ComplexBall(RingElement): sage: CBF(1/2, 3).zetaderiv(1) [0.191759884092721...] + [-0.073135728865928...]*I + sage: CBF(2).zetaderiv(3) + [-6.0001458028430...] """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing Pol = PolynomialRing(self._parent, 'x') ser = Pol([self, 1])._zeta_series(k + 1) - return ser[k] + return ser[k]*ZZ.coerce(k).factorial() def lambert_w(self, branch=0): r""" diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 66a9d7bda06..fe6fda6e3b1 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -3605,11 +3605,13 @@ cdef class RealBall(RingElement): sage: RBF(1/2).zetaderiv(1) [-3.92264613920915...] + sage: RBF(2).zetaderiv(3) + [-6.0001458028430...] """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing Pol = PolynomialRing(self._parent.complex_field(), 'x') ser = Pol([self, 1])._zeta_series(k + 1) - return ser[k].real() + return ser[k].real()*ZZ.coerce(k).factorial() def lambert_w(self): r""" From b3f7d3426499114eed31882f06bdc6cc3b7053f1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 27 Sep 2021 13:49:19 -0700 Subject: [PATCH 148/511] .gitignore: Add /venv --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cf553895adb..91838a1627c 100644 --- a/.gitignore +++ b/.gitignore @@ -182,6 +182,7 @@ src/*.egg-info/ /src/bin/sage-src-env-config # Virtual environments +/venv src/.env src/.venv src/env/ From adae38e04c37dcdbbb9730e974e5eb0c162ec8da Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 27 Sep 2021 14:24:26 -0700 Subject: [PATCH 149/511] trac 32575: Sphinx's install-requires.txt: allow version 4.2 --- build/pkgs/sphinx/install-requires.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/sphinx/install-requires.txt b/build/pkgs/sphinx/install-requires.txt index 2d146f2fe48..0c661b6c6c1 100644 --- a/build/pkgs/sphinx/install-requires.txt +++ b/build/pkgs/sphinx/install-requires.txt @@ -1 +1 @@ -sphinx >=4, <4.2 +sphinx >=4, <4.3 From 5ac0f28559ab278a19833beb28761207fa1a2174 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Tue, 28 Sep 2021 16:54:39 +0200 Subject: [PATCH 150/511] Allow for coordinate changes in curve plots (Trac #32578) --- src/sage/manifolds/differentiable/curve.py | 34 ++++++++++++---------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/sage/manifolds/differentiable/curve.py b/src/sage/manifolds/differentiable/curve.py index 7eb04fc8125..5b12e9d0469 100644 --- a/src/sage/manifolds/differentiable/curve.py +++ b/src/sage/manifolds/differentiable/curve.py @@ -805,6 +805,23 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, g = c.plot(color='green', style=':', thickness=3, aspect_ratio=1) sphinx_plot(g) + Cardioid defined in terms of polar coordinates and plotted with respect + to Cartesian coordinates, as an example of use of the optional argument + ``chart``:: + + sage: E. = EuclideanSpace(coordinates='polar') + sage: c = E.curve((1 + cos(ph), ph), (ph, 0, 2*pi)) + sage: c.plot(chart=E.cartesian_coordinates(), aspect_ratio=1) + Graphics object consisting of 1 graphics primitive + + .. PLOT:: + + E = EuclideanSpace(2, coordinates='polar') + r, ph = E.polar_coordinates()[:] + c = E.curve((1 + cos(ph), ph), (ph, 0, 2*pi)) + g = c.plot(chart=E.cartesian_coordinates(), aspect_ratio=1) + sphinx_plot(g) + Plot via a mapping to another manifold: loxodrome of a sphere viewed in `\RR^3`:: @@ -925,21 +942,8 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, # # The coordinate expression of the effective curve # - canon_chart = self._domain.canonical_chart() - transf = None - for chart_pair in eff_curve._coord_expression: - if chart_pair == (canon_chart, chart): - transf = eff_curve._coord_expression[chart_pair] - break - else: - # Search for a subchart - for chart_pair in eff_curve._coord_expression: - for schart in chart._subcharts: - if chart_pair == (canon_chart, schart): - transf = eff_curve._coord_expression[chart_pair] - if transf is None: - raise ValueError("No expression has been found for " + - "{} in terms of {}".format(self, chart)) + transf = eff_curve.coord_functions(chart1=self._domain.canonical_chart(), + chart2=chart) # # List of points for the plot curve # From 1c1e0a59dd103fa403d3ec6c7d12ab51d6867254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 28 Sep 2021 18:37:22 +0200 Subject: [PATCH 151/511] fix doctest --- src/sage/misc/sagedoc.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index 93fa01cb5cc..e3821e84e76 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -1101,8 +1101,7 @@ def search_src(string, extra1='', extra2='', extra3='', extra4='', misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines()) # random # long time misc/sagedoc.py:... len(search_src("matrix", module="sage.calculus", interact=False).splitlines()) # random misc/sagedoc.py:... len(search_src("matrix", path_re="calc", interact=False).splitlines()) > 15 - misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False)) # py2 - misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False)) # py3 + misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False)) misc/sagedoc.py:... print(search_src(r" fetch\(", "def", interact=False)) # random # long time misc/sagedoc.py:... print(search_src(r" fetch\(", "def", "pyx", interact=False)) # random # long time misc/sagedoc.py:... s = search_src('Matrix', path_re='matrix', interact=False); s.find('x') > 0 From 6f94502ec4378e9998b9ebf7e52490b6106bee85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 28 Sep 2021 18:56:20 +0200 Subject: [PATCH 152/511] some fixes for the relint linter --- src/.relint.yml | 3 ++- src/doc/en/thematic_tutorials/sandpile.rst | 2 +- src/sage/algebras/commutative_dga.py | 3 --- src/sage/all.py | 7 ------- src/sage/modules/with_basis/representation.py | 11 +++++------ src/sage/rings/finite_rings/integer_mod.pyx | 2 +- src/sage/rings/polynomial/omega.py | 14 ++++---------- src/sage/schemes/projective/projective_space.py | 2 +- 8 files changed, 14 insertions(+), 30 deletions(-) diff --git a/src/.relint.yml b/src/.relint.yml index cb1a1e5eac2..9377bc16114 100644 --- a/src/.relint.yml +++ b/src/.relint.yml @@ -14,7 +14,8 @@ - name: 'foreign_latex: foreign commands in LaTeX' hint: | use equivalent LaTeX commands instead of plain TeX commands such as \over, \choose, etc. - pattern: '(\\choose|\\over[^l]|\\atop|\\above|\\overwithdelims|\\atopwithdelims|\\abovewithdelims)' + pattern: '(\\choose|\\atop|\\above|\\overwithdelims|\\atopwithdelims|\\abovewithdelims)' + # \over appears in bad latex code coming from Fricas and Maxima - name: 'blocks: wrong syntax for blocks (INPUT, OUTPUT, EXAMPLES, NOTE, etc.)' hint: | diff --git a/src/doc/en/thematic_tutorials/sandpile.rst b/src/doc/en/thematic_tutorials/sandpile.rst index 7dd7091415a..ebfa825cbde 100644 --- a/src/doc/en/thematic_tutorials/sandpile.rst +++ b/src/doc/en/thematic_tutorials/sandpile.rst @@ -4988,7 +4988,7 @@ Other [ 0 -1 1650 -1649] [ 0 0 -1658 1658] - NOTES: + NOTE: The algorithm is due to John Wilmes. diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index a5e5404bf9f..2d11ee6e280 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -99,7 +99,6 @@ from sage.rings.quotient_ring import QuotientRing_nc from sage.rings.quotient_ring_element import QuotientRingElement from sage.misc.cachefunc import cached_function -from sage.misc.superseded import deprecated_function_alias def sorting_keys(element): @@ -1535,8 +1534,6 @@ def homogeneous_parts(self): res[deg] = term return {i: res[i] for i in sorted(res.keys())} - homogenous_parts = deprecated_function_alias(30585, homogeneous_parts) - def dict(self): r""" A dictionary that determines the element. diff --git a/src/sage/all.py b/src/sage/all.py index 4fa89329e81..e7167449434 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -31,13 +31,6 @@ sage: [inspect.getmodule(f).__name__ for f in frames if is_not_allowed(f)] [] -Check that the Sage Notebook is not imported at startup (see :trac:`15335`):: - - sage: sagenb - Traceback (most recent call last): - ... - NameError: name 'sagenb' is not defined - Check lazy import of ``interacts``:: sage: type(interacts) diff --git a/src/sage/modules/with_basis/representation.py b/src/sage/modules/with_basis/representation.py index a767525664b..e6f97d219a5 100644 --- a/src/sage/modules/with_basis/representation.py +++ b/src/sage/modules/with_basis/representation.py @@ -7,13 +7,13 @@ - Siddharth Singh (2020-03-21): Signed Representation """ -#################################################################################### +############################################################################## # Copyright (C) 2015 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # The full text of the GPL is available at: # http://www.gnu.org/licenses/ -#################################################################################### +############################################################################## from sage.misc.abstract_method import abstract_method from sage.structure.element import Element @@ -154,7 +154,7 @@ def twisted_invariant_module(self, chi, G=None, **kwargs): Create the isotypic component of the action of ``G`` on ``self`` with irreducible character given by ``chi``. - .. SEEALSO: + .. SEEALSO:: - :class:`~sage.modules.with_basis.invariant.FiniteDimensionalTwistedInvariantModule` @@ -1026,7 +1026,7 @@ class SignRepresentationCoxeterGroup(SignRepresentation_abstract): def _default_sign(self, elem): """ Return the sign of the element - + INPUT: - ``elem`` -- the element of the group @@ -1039,5 +1039,4 @@ def _default_sign(self, elem): sage: V._default_sign(elem) 1 """ - return -1 if elem.length() % 2 == 1 else 1 - + return -1 if elem.length() % 2 else 1 diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index 4089c437934..ab92c9a8ecb 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -1347,7 +1347,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): The 'extend' option is not implemented (yet). - NOTES: + NOTE: - If `n = 0`: diff --git a/src/sage/rings/polynomial/omega.py b/src/sage/rings/polynomial/omega.py index 2406e0e0197..97b97d4fe8c 100644 --- a/src/sage/rings/polynomial/omega.py +++ b/src/sage/rings/polynomial/omega.py @@ -36,25 +36,20 @@ - Daniel Krenn is supported by the Austrian Science Fund (FWF): P 24644-N26. - Functions ========= """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 Daniel Krenn # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** - - +# https://www.gnu.org/licenses/ +# **************************************************************************** import operator from sage.misc.cachefunc import cached_function -from sage.misc.superseded import deprecated_function_alias def MacMahonOmega(var, expression, denominator=None, op=operator.ge, @@ -595,6 +590,7 @@ def subs_power(expression, var, exponent): divisible by ``exponent``. """ p = tuple(var.dict().popitem()[0]).index(1) # var is the p-th generator + def subs_e(e): e = list(e) assert e[p] % exponent == 0 @@ -984,5 +980,3 @@ def homogeneous_symmetric_function(j, x): return sum(prod(xx**pp for xx, pp in zip(x, p)) for p in IntegerVectors(j, length=len(x))) - -homogenous_symmetric_function = deprecated_function_alias(30585, homogeneous_symmetric_function) diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 14bf23cac43..c8a93db5b06 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -1531,7 +1531,7 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): Return a PGL element sending ``plane_1`` to ``plane_2``. ``plane_1`` and ``plane_2`` must be hyperplanes (subschemes of - codimension 1, each defined by a single linear homogenous equation). + codimension 1, each defined by a single linear homogeneous equation). INPUT: From c2afe429b00d3229a65edb7c0c12324f9242eb0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 28 Sep 2021 20:23:30 +0200 Subject: [PATCH 153/511] more fixes for relint --- src/sage/misc/latex_macros.py | 5 +---- src/sage/symbolic/ginac/inifcns_comb.cpp | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/sage/misc/latex_macros.py b/src/sage/misc/latex_macros.py index 21b7fab46b4..24d2eee43cb 100644 --- a/src/sage/misc/latex_macros.py +++ b/src/sage/misc/latex_macros.py @@ -16,10 +16,7 @@ LaTeX macros is used in the file ``sage.docs.conf`` to add to the preambles of both the LaTeX file used to build the PDF version of the documentation -and the LaTeX file used to build the HTML version. The list of -MathJax macros is used in the file -``sagenb/notebook/tutorial.py`` to define MathJax macros for use -in the live documentation (and also in the notebook). +and the LaTeX file used to build the HTML version. Any macro defined here may be used in docstrings or in the tutorial (or other pieces of documentation). In a docstring, for example, diff --git a/src/sage/symbolic/ginac/inifcns_comb.cpp b/src/sage/symbolic/ginac/inifcns_comb.cpp index 2f34fe76700..f31ea4f14e4 100644 --- a/src/sage/symbolic/ginac/inifcns_comb.cpp +++ b/src/sage/symbolic/ginac/inifcns_comb.cpp @@ -126,9 +126,9 @@ static ex binomial_imag_part(const ex & x, const ex & y) static void binomial_print_latex(const ex & x, const ex & y, const print_context & c) { - c.s<<"{"; + c.s<<"\\binom{"; x.print(c); - c.s<<" \\choose "; + c.s<<"}{"; y.print(c); c.s<<"}"; } From 86bef1c6d47908d5e1a1f8015ba6e804a360302c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 28 Sep 2021 20:29:25 +0200 Subject: [PATCH 154/511] one more fix --- src/sage/cpython/cython_metaclass.pyx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sage/cpython/cython_metaclass.pyx b/src/sage/cpython/cython_metaclass.pyx index 11294c2bb97..530ff083d4f 100644 --- a/src/sage/cpython/cython_metaclass.pyx +++ b/src/sage/cpython/cython_metaclass.pyx @@ -30,9 +30,6 @@ metaclass: from foo import MyMetaclass return MyMetaclass -The above ``__getmetaclass__`` method is analogous to -``__metaclass__ = MyMetaclass`` in Python 2. - .. WARNING:: ``__getmetaclass__`` must be defined as an ordinary method taking a From e0782b169e48ef67a7b075f25b42dbc2feedc46f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 28 Sep 2021 20:36:56 +0200 Subject: [PATCH 155/511] another fix --- src/.relint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/.relint.yml b/src/.relint.yml index 9377bc16114..9d12054b982 100644 --- a/src/.relint.yml +++ b/src/.relint.yml @@ -8,7 +8,7 @@ # ifilter, imap, izip # __metaclass__ Hint: # update raise statements # except Exception, var Hint: # sagenb # six is no longer allowed - pattern: '(import.*[, ]ifilter|import.*[, ]imap|import.*[, ]izip|^\s*raise\s*[A-Za-z]*Error\s*,|__metaclass__|except\s*[A-Za-z]\s*,|sagenb|import six|from six import)' + pattern: '(import.*[, ]ifilter|import.*[, ]imap|import.*[, ]izip|^\s*raise\s*[A-Za-z]*Error\s*,|__metaclass__|except\s*[A-Za-z]\s*,|[^_]sagenb|import six|from six import)' filePattern: .*[.](py|pyx|rst) - name: 'foreign_latex: foreign commands in LaTeX' From fc4b641f651968af7fd8c4accb5841021ea0390c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 13:37:45 -0700 Subject: [PATCH 156/511] configure.ac: Remove conveniene symlinks before (re)creating them --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index 48600bea7b5..f6078401bf8 100644 --- a/configure.ac +++ b/configure.ac @@ -507,6 +507,7 @@ AC_CONFIG_COMMANDS(links, [ SYMLINK="${ac_top_build_prefix}prefix" AS_IF([test -L "$SYMLINK" -o ! -e "$SYMLINK"], [ AC_MSG_NOTICE([creating convenience symlink $SYMLINK -> $SAGE_LOCAL]) + rm -f "$SYMLINK" ln -sf "$SAGE_LOCAL" "$SYMLINK" ], [ AC_MSG_NOTICE([cannot create convenience symlink $SYMLINK -> $SAGE_LOCAL because the file exists and is not a symlink; this is harmless]) @@ -514,6 +515,7 @@ AC_CONFIG_COMMANDS(links, [ SYMLINK="${ac_top_build_prefix}venv" AS_IF([test -L "$SYMLINK" -o ! -e "$SYMLINK"], [ AC_MSG_NOTICE([creating convenience symlink $SYMLINK -> $SAGE_VENV]) + rm -f "$SYMLINK" ln -sf "$SAGE_VENV" "$SYMLINK" ], [ AC_MSG_NOTICE([cannot create convenience symlink $SYMLINK -> $SAGE_VENV because the file exists and is not a symlink; this is harmless]) From 8bcbf1d919d7d90cefe1442a23aaa66df4ecd2d3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 15:21:42 -0700 Subject: [PATCH 157/511] Makefile (distclean): Remove convenience symlinks prefix, venv --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 567bffbffd0..444e4f9e4ad 100644 --- a/Makefile +++ b/Makefile @@ -109,6 +109,7 @@ distclean: build-clean @echo "Deleting all remaining output from build system ..." rm -rf local rm -f src/bin/sage-env-config + rm -f prefix venv # Delete all auto-generated files which are distributed as part of the # source tarball From 2f16dc0cb5779eeae667697d3c41137fcde507c3 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 29 Sep 2021 11:24:27 +0200 Subject: [PATCH 158/511] improve initialization of mset --- src/sage/combinat/combination.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index 674c2c96ba2..44563d589b7 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -157,16 +157,22 @@ class of combinations of ``mset`` of size ``k``. [[], [(0, 0)], [(0, 1)], [(0, 0), (0, 1)]] """ # Check to see if everything in mset is unique + is_unique = False if isinstance(mset, (int, Integer)): mset = list(range(mset)) + is_unique = True + elif isinstance(mset, range): + mset = list(mset) + is_unique = True else: mset = list(mset) + for i, e in enumerate(mset): + if mset.index(e) != i: + break + else: + is_unique = True - d = {} - for i in mset: - d[mset.index(i)] = 1 - - if len(d) == len(mset): + if is_unique: if k is None: return Combinations_set(mset) else: From c30b3a3bb1698dbb800a23a479bade0384d5faab Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 29 Sep 2021 11:43:13 +0200 Subject: [PATCH 159/511] improve cardinality for combinations over non-multi-set --- src/sage/combinat/combination.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index 44563d589b7..3fed5ab8c9c 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -30,6 +30,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.structure.parent import Parent from sage.misc.persist import register_unpickle_override +from sage.functions.other import binomial def Combinations(mset, k=None): @@ -320,6 +321,17 @@ def rank(self, x): r += rank(x, n) return r + def cardinality(self): + """ + Return the size of Combinations(set). + + EXAMPLES:: + + sage: Combinations(range(16000)).cardinality() == 2^16000 + True + """ + return 2**len(self.mset) + class Combinations_msetk(Parent): def __init__(self, mset, k): @@ -521,6 +533,17 @@ def rank(self, x): x = [self.mset.index(_) for _ in x] return rank(x, len(self.mset)) + def cardinality(self): + """ + Return the size of combinations(set, k). + + EXAMPLES:: + + sage: Combinations(range(16000), 5).cardinality() + 8732673194560003200 + """ + return binomial(len(self.mset), self.k) + def rank(comb, n, check=True): """ From a3d61ef2a307e365e39d109f51006582eb8deba1 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 29 Sep 2021 21:22:47 +0200 Subject: [PATCH 160/511] do not overwrite binomial import --- src/sage/combinat/combination.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index 3fed5ab8c9c..6e3dc71da83 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -30,7 +30,6 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.structure.parent import Parent from sage.misc.persist import register_unpickle_override -from sage.functions.other import binomial def Combinations(mset, k=None): From dcb4a08a1d5e5e2363c4b6e2f2f3d852efd3aae0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Sep 2021 15:24:23 -0700 Subject: [PATCH 161/511] configure.ac: Indicate default in help string for --with-sage-venv --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f6078401bf8..6f59a5ea128 100644 --- a/configure.ac +++ b/configure.ac @@ -84,7 +84,7 @@ SAGE_SRC="$SAGE_ROOT/src" SAGE_SPKG_INST="$SAGE_LOCAL/var/lib/sage/installed" AC_ARG_WITH([sage-venv], - [AS_HELP_STRING([--with-sage-venv={auto,yes,no,SAGE_VENV}], + [AS_HELP_STRING([--with-sage-venv={auto (default),yes,no,SAGE_VENV}], [put Python packages into an installation hierarchy separate from prefix])], [SAGE_VENV="$withval"], [SAGE_VENV="auto"]) From 7a63b9c782df73f271c8455f5c613d5133bac67e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Sep 2021 19:01:26 -0700 Subject: [PATCH 162/511] sage.modules.fg_pid: Replace .all imports by more specific imports --- src/sage/modules/fg_pid/fgp_element.py | 4 +++- src/sage/modules/fg_pid/fgp_module.py | 9 +++++---- src/sage/modules/fg_pid/fgp_morphism.py | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/sage/modules/fg_pid/fgp_element.py b/src/sage/modules/fg_pid/fgp_element.py index f6f03acd16c..c8174017343 100644 --- a/src/sage/modules/fg_pid/fgp_element.py +++ b/src/sage/modules/fg_pid/fgp_element.py @@ -448,7 +448,9 @@ def additive_order(self): I = Q.invariants() v = self.vector() - from sage.rings.all import infinity, Mod, Integer + from sage.rings.infinity import infinity + from sage.rings.finite_rings.integer_mod import Mod + from sage.rings.integer import Integer from sage.arith.all import lcm n = Integer(1) for i, a in enumerate(I): diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index 009d8679e21..bb2bd6e7148 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -215,8 +215,9 @@ from sage.structure.sequence import Sequence from .fgp_element import DEBUG, FGP_Element from .fgp_morphism import FGP_Morphism, FGP_Homset -from sage.rings.all import Integer, ZZ -from sage.arith.all import lcm +from sage.rings.integer_ring import ZZ +from sage.rings.integer import Integer +from sage.arith.functions import lcm from sage.misc.cachefunc import cached_method from sage.matrix.constructor import matrix @@ -1223,7 +1224,7 @@ def gens_vector(self, x, reduce=False): """ x = self(x) v = x.vector() * self.smith_to_gens() - from sage.rings.all import infinity + from sage.rings.infinity import infinity if reduce and self.base_ring() == ZZ: orders = [g.order() for g in self.gens()] v = v.parent()([v[i] if orders[i] == infinity @@ -1740,7 +1741,7 @@ def cardinality(self): return self.__cardinality except AttributeError: pass - from sage.rings.all import infinity + from sage.rings.infinity import infinity from sage.misc.misc_c import prod v = self.invariants() self.__cardinality = infinity if 0 in v else prod(v) diff --git a/src/sage/modules/fg_pid/fgp_morphism.py b/src/sage/modules/fg_pid/fgp_morphism.py index 2bca2484d8a..8eaf32ed7bd 100644 --- a/src/sage/modules/fg_pid/fgp_morphism.py +++ b/src/sage/modules/fg_pid/fgp_morphism.py @@ -507,10 +507,10 @@ def __init__(self, X, Y, category=None): if category is None: from sage.modules.free_module import is_FreeModule if is_FreeModule(X) and is_FreeModule(Y): - from sage.all import FreeModules + from sage.categories.all import FreeModules category = FreeModules(X.base_ring()) else: - from sage.all import Modules + from sage.categories.all import Modules category = Modules(X.base_ring()) Homset.__init__(self, X, Y, category) From 245d72695aed5fb297ed2db1f3e435ef9a88d94b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 23:32:46 -0700 Subject: [PATCH 163/511] src/sage/structure/sage_object.pyx: Replace import from sage.misc.all by more specific import --- src/sage/structure/sage_object.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/structure/sage_object.pyx b/src/sage/structure/sage_object.pyx index 7ebf2734e9f..8c05c347491 100644 --- a/src/sage/structure/sage_object.pyx +++ b/src/sage/structure/sage_object.pyx @@ -645,7 +645,7 @@ cdef class SageObject: remote Sage session, and get it back. """ tester = self._tester(**options) - from sage.misc.all import loads, dumps + from sage.misc.persist import loads, dumps tester.assertEqual(loads(dumps(self)), self) ############################################################################# From 5f1c296b11a43a6805ebf4c568442717c3649608 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Sep 2021 19:00:37 -0700 Subject: [PATCH 164/511] src/sage/misc/sage_unittest.py: Import loads, dumps from sage.misc.persist --- src/sage/misc/sage_unittest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/sage_unittest.py b/src/sage/misc/sage_unittest.py index 18827dfd118..c6c6d2741dc 100644 --- a/src/sage/misc/sage_unittest.py +++ b/src/sage/misc/sage_unittest.py @@ -610,7 +610,7 @@ def _test_pickling(self, **options): :func:`dumps`, :func:`loads` """ tester = instance_tester(self, **options) - from sage.misc.all import loads, dumps + from sage.misc.persist import loads, dumps tester.assertEqual(loads(dumps(self._instance)), self._instance) def _test_new(self, **options): From e251555a862c5089707dd906eccb20ecee49fe3f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 23:30:00 -0700 Subject: [PATCH 165/511] src/sage/geometry/polyhedron/backend_cdd_rdf.py: Split out from src/sage/geometry/polyhedron/backend_cdd.py --- src/sage/geometry/polyhedron/backend_cdd.py | 210 +--------------- .../geometry/polyhedron/backend_cdd_rdf.py | 227 ++++++++++++++++++ 2 files changed, 229 insertions(+), 208 deletions(-) create mode 100644 src/sage/geometry/polyhedron/backend_cdd_rdf.py diff --git a/src/sage/geometry/polyhedron/backend_cdd.py b/src/sage/geometry/polyhedron/backend_cdd.py index d839bc3ca5e..a8409e58a4f 100644 --- a/src/sage/geometry/polyhedron/backend_cdd.py +++ b/src/sage/geometry/polyhedron/backend_cdd.py @@ -21,7 +21,6 @@ from .base import Polyhedron_base from .base_QQ import Polyhedron_QQ -from .base_RDF import Polyhedron_RDF class Polyhedron_cdd(Polyhedron_base): @@ -460,210 +459,5 @@ def __init__(self, parent, Vrep, Hrep, **kwds): Polyhedron_cdd.__init__(self, parent, Vrep, Hrep, **kwds) -class Polyhedron_RDF_cdd(Polyhedron_cdd, Polyhedron_RDF): - """ - Polyhedra over RDF with cdd - - INPUT: - - - ``ambient_dim`` -- integer. The dimension of the ambient space. - - - ``Vrep`` -- a list ``[vertices, rays, lines]`` or ``None``. - - - ``Hrep`` -- a list ``[ieqs, eqns]`` or ``None``. - - EXAMPLES:: - - sage: from sage.geometry.polyhedron.parent import Polyhedra - sage: parent = Polyhedra(RDF, 2, backend='cdd') - sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_RDF_cdd - sage: Polyhedron_RDF_cdd(parent, [ [(1,0),(0,1),(0,0)], [], []], None, verbose=False) - A 2-dimensional polyhedron in RDF^2 defined as the convex hull of 3 vertices - - TESTS: - - Checks that :trac:`24877` is fixed:: - - sage: n1 = 1045602428815736513789288687833080060779 - sage: n2 = 76591188009721216624438400001815308369088648782156930777145 - sage: n3 = 141046287872967162025203834781636948939209065735662536571684677443277621519222367249160281646288602157866548267640061850035 - sage: n4 = 169296796161110084211548448622149955145002732358082778064645608216077666698460018565094060494217 - sage: verts = [[159852/261157, 227425/261157], - ....: [9/10, 7/10], - ....: [132/179, 143/179], - ....: [8/11, -59/33], - ....: [174/167, 95/167], - ....: [3/2, -1/2], - ....: [-1162016360399650274197433414376009691155/n1, - ....: 1626522696050475596930360993440360903664/n1], - ....: [-112565666321600055047037445519656973805313121630809713051718/n2, - ....: -15318574020578896781701071673537253327221557273483622682053/n2], - ....: [-222823992658914823798345935660863293259608796350232624336738123149601409997996952470726909468671437285720616325991022633438/n3, - ....: (-20857694835570598502487921801401627779907095024585170129381924208334510445828894861553290291713792691651471189597832832973*5)/n3], - ....: [-100432602675156818915933977983765863676402454634873648118147187022041830166292457614016362515164/n4, - ....: -429364759737031049317769174492863890735634068814210512342503744054527903830844433491149538512537/n4]] - sage: P = Polyhedron(verts, base_ring=RDF) - sage: len(P.faces(1)) - 10 - sage: P.n_vertices() - 10 - sage: P.n_facets() - 10 - - Check that :trac:`19803` is fixed:: - - sage: from sage.geometry.polyhedron.parent import Polyhedra - sage: P_cdd = Polyhedra(RDF, 3, 'cdd') - sage: P_cdd([[],[],[]], None) - The empty polyhedron in RDF^3 - sage: Polyhedron(vertices=[], backend='cdd', base_ring=RDF) - The empty polyhedron in RDF^0 - """ - _cdd_type = 'real' - - _cdd_executable = 'cddexec' - - def __init__(self, parent, Vrep, Hrep, **kwds): - """ - The Python constructor. - - See :class:`Polyhedron_base` for a description of the input - data. - - TESTS:: - - sage: p = Polyhedron(backend='cdd', base_ring=RDF) - sage: type(p) - - sage: TestSuite(p).run() - """ - Polyhedron_cdd.__init__(self, parent, Vrep, Hrep, **kwds) - - def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep, verbose=False): - """ - Construct polyhedron from Vrepresentation and Hrepresentation data. - - See :class:`Polyhedron_base` for a description of ``Vrep`` and ``Hrep``. - - .. NOTE:: - - The representation is assumed to be correct. - - As long as cdd can obtain a consistent object with Vrepresentation - or Hrepresentation no warning is raised. Consistency is checked by - comparing the output length of Vrepresentation and Hrepresentation - with the input. - - In comparison, the "normal" initialization from Vrepresentation over RDF - expects the output length to be consistent with the computed length - when re-feeding cdd the outputted Hrepresentation. - - EXAMPLES:: - - sage: from sage.geometry.polyhedron.parent import Polyhedra_RDF_cdd - sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_RDF_cdd - sage: parent = Polyhedra_RDF_cdd(RDF, 1, 'cdd') - sage: Vrep = [[[0.0], [1.0]], [], []] - sage: Hrep = [[[0.0, 1.0], [1.0, -1.0]], []] - sage: p = Polyhedron_RDF_cdd(parent, Vrep, Hrep, - ....: Vrep_minimal=True, Hrep_minimal=True) # indirect doctest - sage: p - A 1-dimensional polyhedron in RDF^1 defined as the convex hull of 2 vertices - - TESTS: - - Test that :trac:`29568` is fixed:: - - sage: P = polytopes.buckyball(exact=False) - sage: Q = P + P.center() - sage: P.is_combinatorially_isomorphic(Q) - True - sage: R = 2*P - sage: P.is_combinatorially_isomorphic(R) - True - - The polyhedron with zero inequalities works correctly; see :trac:`29899`:: - - sage: Vrep = [[], [], [[1.0]]] - sage: Hrep = [[], []] - sage: p = Polyhedron_RDF_cdd(parent, Vrep, Hrep, - ....: Vrep_minimal=True, Hrep_minimal=True) # indirect doctest - sage: p - A 1-dimensional polyhedron in RDF^1 defined as the convex hull of 1 vertex and 1 line - - Test that :trac:`30330` is fixed:: - - sage: P1 = polytopes.regular_polygon(5, exact=False) - sage: P2 = Polyhedron() - sage: P1*P2 - The empty polyhedron in RDF^2 - """ - def parse_Vrep(intro, data): - count = int(data[0][0]) - if count != len(vertices) + len(rays) + len(lines): - # Upstream claims that nothing can be done about these - # cases/that they are features not bugs. Imho, cddlib is - # not really suitable for automatic parsing of its output, - # the implementation backed by doubles has not really been - # optimized for numerical stability, and makes some - # somewhat random numerical choices. (But I am not an - # expert in that field by any means.) See also - # https://github.com/cddlib/cddlib/pull/7. - from warnings import warn - warn("This polyhedron data is numerically complicated; cdd could not convert between the inexact V and H representation without loss of data. The resulting object might show inconsistencies.") - - def parse_Hrep(intro, data): - count = int(data[0][0]) - infinite_count = len([d for d in data[1:] if d[0] == '1' and all(c == '0' for c in d[1:])]) - if count - infinite_count != len(ieqs) + len(eqns): - # Upstream claims that nothing can be done about these - # cases/that they are features not bugs. Imho, cddlib is - # not really suitable for automatic parsing of its output, - # the implementation backed by doubles has not really been - # optimized for numerical stability, and makes some - # somewhat random numerical choices. (But I am not an - # expert in that field by any means.) - from warnings import warn - warn("This polyhedron data is numerically complicated; cdd could not convert between the inexact V and H representation without loss of data. The resulting object might show inconsistencies.") - - def try_init(rep): - if rep == "Vrep": - from .cdd_file_format import cdd_Vrepresentation - s = cdd_Vrepresentation(self._cdd_type, vertices, rays, lines) - else: - # We have to add a trivial inequality, in case the polyhedron is the universe. - new_ieqs = ieqs + ((1,) + tuple(0 for _ in range(self.ambient_dim())),) - - from .cdd_file_format import cdd_Hrepresentation - s = cdd_Hrepresentation(self._cdd_type, new_ieqs, eqns) - - s = self._run_cdd(s, '--redcheck', verbose=verbose) - s = self._run_cdd(s, '--repall', verbose=verbose) - Polyhedron_cdd._parse_block(s.splitlines(), 'V-representation', parse_Vrep) - Polyhedron_cdd._parse_block(s.splitlines(), 'H-representation', parse_Hrep) - self._init_from_cdd_output(s) - - from warnings import catch_warnings, simplefilter - - vertices, rays, lines = (tuple(x) for x in Vrep) - ieqs, eqns = (tuple(x) for x in Hrep) - - if not (vertices or rays or lines): - # cdd refuses to handle empty polyhedra. - self._init_empty_polyhedron() - return - - # We prefer the shorter representation. - # Note that for the empty polyhedron we prefer Hrepresentation. - prim = "Hrep" if len(ieqs) <= len(vertices) + len(rays) else "Vrep" - sec = "Vrep" if len(ieqs) <= len(vertices) + len(rays) else "Hrep" - - with catch_warnings(): - # Raise an error and try the other representation in case of - # numerical inconsistency. - simplefilter("error") - try: - try_init(prim) - except UserWarning: - simplefilter("once") # Only print the first warning. - try_init(sec) +from sage.misc.lazy_import import lazy_import +lazy_import('sage.geometry.polyhedron.backend_cdd_rdf', 'Polyhedron_RDF_cdd') diff --git a/src/sage/geometry/polyhedron/backend_cdd_rdf.py b/src/sage/geometry/polyhedron/backend_cdd_rdf.py new file mode 100644 index 00000000000..e180448e1ad --- /dev/null +++ b/src/sage/geometry/polyhedron/backend_cdd_rdf.py @@ -0,0 +1,227 @@ +r""" +The cdd backend for polyhedral computations, floating point version +""" +# **************************************************************************** +# Copyright (C) 2011-2014 Volker Braun +# 2018 Timo Kaufmann +# 2018 Julian Rüth +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + + +from .backend_cdd import Polyhedron_cdd +from .base_RDF import Polyhedron_RDF + + +class Polyhedron_RDF_cdd(Polyhedron_cdd, Polyhedron_RDF): + """ + Polyhedra over RDF with cdd + + INPUT: + + - ``ambient_dim`` -- integer. The dimension of the ambient space. + + - ``Vrep`` -- a list ``[vertices, rays, lines]`` or ``None``. + + - ``Hrep`` -- a list ``[ieqs, eqns]`` or ``None``. + + EXAMPLES:: + + sage: from sage.geometry.polyhedron.parent import Polyhedra + sage: parent = Polyhedra(RDF, 2, backend='cdd') + sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_RDF_cdd + sage: Polyhedron_RDF_cdd(parent, [ [(1,0),(0,1),(0,0)], [], []], None, verbose=False) + A 2-dimensional polyhedron in RDF^2 defined as the convex hull of 3 vertices + + TESTS: + + Checks that :trac:`24877` is fixed:: + + sage: n1 = 1045602428815736513789288687833080060779 + sage: n2 = 76591188009721216624438400001815308369088648782156930777145 + sage: n3 = 141046287872967162025203834781636948939209065735662536571684677443277621519222367249160281646288602157866548267640061850035 + sage: n4 = 169296796161110084211548448622149955145002732358082778064645608216077666698460018565094060494217 + sage: verts = [[159852/261157, 227425/261157], + ....: [9/10, 7/10], + ....: [132/179, 143/179], + ....: [8/11, -59/33], + ....: [174/167, 95/167], + ....: [3/2, -1/2], + ....: [-1162016360399650274197433414376009691155/n1, + ....: 1626522696050475596930360993440360903664/n1], + ....: [-112565666321600055047037445519656973805313121630809713051718/n2, + ....: -15318574020578896781701071673537253327221557273483622682053/n2], + ....: [-222823992658914823798345935660863293259608796350232624336738123149601409997996952470726909468671437285720616325991022633438/n3, + ....: (-20857694835570598502487921801401627779907095024585170129381924208334510445828894861553290291713792691651471189597832832973*5)/n3], + ....: [-100432602675156818915933977983765863676402454634873648118147187022041830166292457614016362515164/n4, + ....: -429364759737031049317769174492863890735634068814210512342503744054527903830844433491149538512537/n4]] + sage: P = Polyhedron(verts, base_ring=RDF) + sage: len(P.faces(1)) + 10 + sage: P.n_vertices() + 10 + sage: P.n_facets() + 10 + + Check that :trac:`19803` is fixed:: + + sage: from sage.geometry.polyhedron.parent import Polyhedra + sage: P_cdd = Polyhedra(RDF, 3, 'cdd') + sage: P_cdd([[],[],[]], None) + The empty polyhedron in RDF^3 + sage: Polyhedron(vertices=[], backend='cdd', base_ring=RDF) + The empty polyhedron in RDF^0 + """ + _cdd_type = 'real' + + _cdd_executable = 'cddexec' + + def __init__(self, parent, Vrep, Hrep, **kwds): + """ + The Python constructor. + + See :class:`Polyhedron_base` for a description of the input + data. + + TESTS:: + + sage: p = Polyhedron(backend='cdd', base_ring=RDF) + sage: type(p) + + sage: TestSuite(p).run() + """ + Polyhedron_cdd.__init__(self, parent, Vrep, Hrep, **kwds) + + def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep, verbose=False): + """ + Construct polyhedron from Vrepresentation and Hrepresentation data. + + See :class:`Polyhedron_base` for a description of ``Vrep`` and ``Hrep``. + + .. NOTE:: + + The representation is assumed to be correct. + + As long as cdd can obtain a consistent object with Vrepresentation + or Hrepresentation no warning is raised. Consistency is checked by + comparing the output length of Vrepresentation and Hrepresentation + with the input. + + In comparison, the "normal" initialization from Vrepresentation over RDF + expects the output length to be consistent with the computed length + when re-feeding cdd the outputted Hrepresentation. + + EXAMPLES:: + + sage: from sage.geometry.polyhedron.parent import Polyhedra_RDF_cdd + sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_RDF_cdd + sage: parent = Polyhedra_RDF_cdd(RDF, 1, 'cdd') + sage: Vrep = [[[0.0], [1.0]], [], []] + sage: Hrep = [[[0.0, 1.0], [1.0, -1.0]], []] + sage: p = Polyhedron_RDF_cdd(parent, Vrep, Hrep, + ....: Vrep_minimal=True, Hrep_minimal=True) # indirect doctest + sage: p + A 1-dimensional polyhedron in RDF^1 defined as the convex hull of 2 vertices + + TESTS: + + Test that :trac:`29568` is fixed:: + + sage: P = polytopes.buckyball(exact=False) + sage: Q = P + P.center() + sage: P.is_combinatorially_isomorphic(Q) + True + sage: R = 2*P + sage: P.is_combinatorially_isomorphic(R) + True + + The polyhedron with zero inequalities works correctly; see :trac:`29899`:: + + sage: Vrep = [[], [], [[1.0]]] + sage: Hrep = [[], []] + sage: p = Polyhedron_RDF_cdd(parent, Vrep, Hrep, + ....: Vrep_minimal=True, Hrep_minimal=True) # indirect doctest + sage: p + A 1-dimensional polyhedron in RDF^1 defined as the convex hull of 1 vertex and 1 line + + Test that :trac:`30330` is fixed:: + + sage: P1 = polytopes.regular_polygon(5, exact=False) + sage: P2 = Polyhedron() + sage: P1*P2 + The empty polyhedron in RDF^2 + """ + def parse_Vrep(intro, data): + count = int(data[0][0]) + if count != len(vertices) + len(rays) + len(lines): + # Upstream claims that nothing can be done about these + # cases/that they are features not bugs. Imho, cddlib is + # not really suitable for automatic parsing of its output, + # the implementation backed by doubles has not really been + # optimized for numerical stability, and makes some + # somewhat random numerical choices. (But I am not an + # expert in that field by any means.) See also + # https://github.com/cddlib/cddlib/pull/7. + from warnings import warn + warn("This polyhedron data is numerically complicated; cdd could not convert between the inexact V and H representation without loss of data. The resulting object might show inconsistencies.") + + def parse_Hrep(intro, data): + count = int(data[0][0]) + infinite_count = len([d for d in data[1:] if d[0] == '1' and all(c == '0' for c in d[1:])]) + if count - infinite_count != len(ieqs) + len(eqns): + # Upstream claims that nothing can be done about these + # cases/that they are features not bugs. Imho, cddlib is + # not really suitable for automatic parsing of its output, + # the implementation backed by doubles has not really been + # optimized for numerical stability, and makes some + # somewhat random numerical choices. (But I am not an + # expert in that field by any means.) + from warnings import warn + warn("This polyhedron data is numerically complicated; cdd could not convert between the inexact V and H representation without loss of data. The resulting object might show inconsistencies.") + + def try_init(rep): + if rep == "Vrep": + from .cdd_file_format import cdd_Vrepresentation + s = cdd_Vrepresentation(self._cdd_type, vertices, rays, lines) + else: + # We have to add a trivial inequality, in case the polyhedron is the universe. + new_ieqs = ieqs + ((1,) + tuple(0 for _ in range(self.ambient_dim())),) + + from .cdd_file_format import cdd_Hrepresentation + s = cdd_Hrepresentation(self._cdd_type, new_ieqs, eqns) + + s = self._run_cdd(s, '--redcheck', verbose=verbose) + s = self._run_cdd(s, '--repall', verbose=verbose) + Polyhedron_cdd._parse_block(s.splitlines(), 'V-representation', parse_Vrep) + Polyhedron_cdd._parse_block(s.splitlines(), 'H-representation', parse_Hrep) + self._init_from_cdd_output(s) + + from warnings import catch_warnings, simplefilter + + vertices, rays, lines = (tuple(x) for x in Vrep) + ieqs, eqns = (tuple(x) for x in Hrep) + + if not (vertices or rays or lines): + # cdd refuses to handle empty polyhedra. + self._init_empty_polyhedron() + return + + # We prefer the shorter representation. + # Note that for the empty polyhedron we prefer Hrepresentation. + prim = "Hrep" if len(ieqs) <= len(vertices) + len(rays) else "Vrep" + sec = "Vrep" if len(ieqs) <= len(vertices) + len(rays) else "Hrep" + + with catch_warnings(): + # Raise an error and try the other representation in case of + # numerical inconsistency. + simplefilter("error") + try: + try_init(prim) + except UserWarning: + simplefilter("once") # Only print the first warning. + try_init(sec) From 1b0a5ab028885616c12adec26ffa6524c7ccbe46 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Sep 2021 15:09:07 -0700 Subject: [PATCH 166/511] src/sage/modules/vector_space_morphism.py: Do not fail if sage.symbol is not present --- src/sage/modules/vector_space_morphism.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/vector_space_morphism.py b/src/sage/modules/vector_space_morphism.py index 7c2104b1f17..1a1fde6eb5a 100644 --- a/src/sage/modules/vector_space_morphism.py +++ b/src/sage/modules/vector_space_morphism.py @@ -688,8 +688,10 @@ def linear_transformation(arg0, arg1=None, arg2=None, side='left'): from sage.modules.module import is_VectorSpace from sage.modules.free_module import VectorSpace from sage.categories.homset import Hom - from sage.symbolic.ring import SR - from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense + try: + from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense + except ImportError: + Vector_callable_symbolic_dense = () if not side in ['left', 'right']: raise ValueError("side must be 'left' or 'right', not {0}".format(side)) @@ -734,6 +736,7 @@ def linear_transformation(arg0, arg1=None, arg2=None, side='left'): elif isinstance(arg2, (list, tuple)): pass elif isinstance(arg2, Vector_callable_symbolic_dense): + from sage.symbolic.ring import SR args = arg2.parent().base_ring()._arguments exprs = arg2.change_ring(SR) m = len(args) From 83b5038c1a34c3a9cbfa4607e7c4c0c7a2c2f510 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 15:46:21 -0700 Subject: [PATCH 167/511] src/sage/modules/free_module_element.pyx: Move import from sage.misc.derivative into method --- src/sage/modules/free_module_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index 2075d07c0ae..21d898c117c 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -123,7 +123,6 @@ from sage.rings.infinity import Infinity, AnInfinity from sage.rings.integer_ring import ZZ from sage.rings.real_double import RDF from sage.rings.complex_double import CDF -from sage.misc.derivative import multi_derivative from sage.rings.ring cimport Ring from sage.rings.integer cimport Integer, smallInteger @@ -3968,6 +3967,7 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: v.derivative(x,x) (0, 0, 2) """ + from sage.misc.derivative import multi_derivative return multi_derivative(self, args) diff = derivative From acca6c2219955e585fa1426e22486fe01a03f760 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 19:06:50 -0700 Subject: [PATCH 168/511] src/sage/matrix/matrix2.pyx: Move import from sage.misc.derivative into method --- src/sage/matrix/matrix2.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index d4a8ec9d3a1..00e806b190c 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -94,7 +94,6 @@ from sage.rings.complex_double import CDF from sage.rings.real_mpfr import RealField from sage.rings.complex_mpfr import ComplexField from sage.rings.finite_rings.integer_mod_ring import IntegerModRing -from sage.misc.derivative import multi_derivative from sage.arith.numerical_approx cimport digits_to_bits from copy import copy @@ -15123,6 +15122,7 @@ cdef class Matrix(Matrix1): sage: v.derivative(x,x) (0, 0, 2) """ + from sage.misc.derivative import multi_derivative return multi_derivative(self, args) def exp(self): From 27bc041532bdeadd69f5285e0991fecad9da5022 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 30 Sep 2021 15:49:35 +0200 Subject: [PATCH 169/511] update memory_allocator to fix test failures on 32bit --- build/pkgs/memory_allocator/checksums.ini | 6 +++--- build/pkgs/memory_allocator/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/memory_allocator/checksums.ini b/build/pkgs/memory_allocator/checksums.ini index f7efcd9b150..fe48843d873 100644 --- a/build/pkgs/memory_allocator/checksums.ini +++ b/build/pkgs/memory_allocator/checksums.ini @@ -1,5 +1,5 @@ tarball=memory_allocator-VERSION.tar.gz -sha1=0e9256d307957e84eaba408f190cafc04d5c246a -md5=1ce1fb6dc5972017a26ee82c4371b180 -cksum=2493862442 +sha1=7721219be84207f6112e118fc79af0c2729fca34 +md5=868753a09c44194cba303db89cca4396 +cksum=16627262 upstream_url=https://pypi.io/packages/source/m/memory_allocator/memory_allocator-VERSION.tar.gz diff --git a/build/pkgs/memory_allocator/package-version.txt b/build/pkgs/memory_allocator/package-version.txt index 6e8bf73aa55..17e51c385ea 100644 --- a/build/pkgs/memory_allocator/package-version.txt +++ b/build/pkgs/memory_allocator/package-version.txt @@ -1 +1 @@ -0.1.0 +0.1.1 From 007683ecb8888463567345097d8ff88483766487 Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Thu, 30 Sep 2021 16:44:08 +0200 Subject: [PATCH 170/511] #32598 : use pytest instead of nose for selftests --- build/pkgs/cvxopt/dependencies | 2 +- build/pkgs/cvxopt/spkg-check.in | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/build/pkgs/cvxopt/dependencies b/build/pkgs/cvxopt/dependencies index 8930227ba65..9a585f3b003 100644 --- a/build/pkgs/cvxopt/dependencies +++ b/build/pkgs/cvxopt/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) numpy $(BLAS) gsl glpk suitesparse | $(PYTHON_TOOLCHAIN) pkgconfig nose matplotlib +$(PYTHON) numpy $(BLAS) gsl glpk suitesparse | $(PYTHON_TOOLCHAIN) pkgconfig pytest matplotlib matplotlib is needed to test cvxopt (i.e., if SAGE_CHECK=yes). See #12742. diff --git a/build/pkgs/cvxopt/spkg-check.in b/build/pkgs/cvxopt/spkg-check.in index e251b2cbb6f..8b3f5031762 100644 --- a/build/pkgs/cvxopt/spkg-check.in +++ b/build/pkgs/cvxopt/spkg-check.in @@ -1,8 +1,3 @@ cd src -if ! command -v nosetests ; then - echo >&2 'Testing cvxopt requires the package nose to be installed' - exit 1 -fi - -nosetests +pytest From 67ceb09c9d3dce0ee34d7a50423484b3bc5c0b68 Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Thu, 30 Sep 2021 16:51:23 +0200 Subject: [PATCH 171/511] #32597 : use pytest instead of nose for networkx selftests --- build/pkgs/networkx/dependencies | 2 +- build/pkgs/networkx/spkg-check.in | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/build/pkgs/networkx/dependencies b/build/pkgs/networkx/dependencies index 3d0462a6697..2a20cb459ba 100644 --- a/build/pkgs/networkx/dependencies +++ b/build/pkgs/networkx/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) decorator | $(PYTHON_TOOLCHAIN) scipy $(and $(filter-out no,$(SAGE_CHECK_networkx)), nose pytest) +$(PYTHON) decorator | $(PYTHON_TOOLCHAIN) scipy $(and $(filter-out no,$(SAGE_CHECK_networkx)), pytest) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/networkx/spkg-check.in b/build/pkgs/networkx/spkg-check.in index 60868aaefc5..8b3f5031762 100644 --- a/build/pkgs/networkx/spkg-check.in +++ b/build/pkgs/networkx/spkg-check.in @@ -1,8 +1,3 @@ cd src -if ! command -v nosetests ; then - echo >&2 'Testing networkx requires the package nose to be installed' - exit 1 -fi - -nosetests networkx -v +pytest From 2586c1e9f11d627ea2c7d440ea359e8ac964dd4b Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Thu, 30 Sep 2021 17:15:00 +0200 Subject: [PATCH 172/511] #32598 : conditional dependency on pytest for cvxopt --- build/pkgs/cvxopt/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/cvxopt/dependencies b/build/pkgs/cvxopt/dependencies index 9a585f3b003..2354fdb1c1e 100644 --- a/build/pkgs/cvxopt/dependencies +++ b/build/pkgs/cvxopt/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) numpy $(BLAS) gsl glpk suitesparse | $(PYTHON_TOOLCHAIN) pkgconfig pytest matplotlib +$(PYTHON) numpy $(BLAS) gsl glpk suitesparse | $(PYTHON_TOOLCHAIN) pkgconfig matplotlib $(and $(filter-out no,$(SAGE_CHECK_cvxopt)), pytest) matplotlib is needed to test cvxopt (i.e., if SAGE_CHECK=yes). See #12742. From 8e27fdcd555117075d19e1ed7bf502758495cbc6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 23:32:20 -0700 Subject: [PATCH 173/511] src/sage/structure/sequence.py: Do not fail if polynomial rings cannot be imported --- src/sage/structure/sequence.py | 41 ++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/sage/structure/sequence.py b/src/sage/structure/sequence.py index 0c8440da8e0..29d960e4d27 100644 --- a/src/sage/structure/sequence.py +++ b/src/sage/structure/sequence.py @@ -213,15 +213,19 @@ def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=Non ... TypeError: unable to convert a to an element of Integer Ring """ - from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal - - if isinstance(x, Sequence_generic) and universe is None: - universe = x.universe() - x = list(x) - - if isinstance(x, MPolynomialIdeal) and universe is None: - universe = x.ring() - x = x.gens() + if universe is None: + if isinstance(x, Sequence_generic): + universe = x.universe() + x = list(x) + else: + try: + from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal + except ImportError: + pass + else: + if isinstance(x, MPolynomialIdeal): + universe = x.ring() + x = x.gens() if universe is None: orig_x = x @@ -248,15 +252,18 @@ def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=Non if universe is None: # no type errors raised. universe = sage.structure.element.parent(x[len(x)-1]) - from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence - from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid - from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing - from sage.rings.quotient_ring import is_QuotientRing - - if is_MPolynomialRing(universe) or isinstance(universe, BooleanMonomialMonoid) or (is_QuotientRing(universe) and is_MPolynomialRing(universe.cover_ring())): - return PolynomialSequence(x, universe, immutable=immutable, cr=cr, cr_str=cr_str) + try: + from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence + from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid + from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing + from sage.rings.quotient_ring import is_QuotientRing + except ImportError: + pass else: - return Sequence_generic(x, universe, check, immutable, cr, cr_str, use_sage_types) + if is_MPolynomialRing(universe) or isinstance(universe, BooleanMonomialMonoid) or (is_QuotientRing(universe) and is_MPolynomialRing(universe.cover_ring())): + return PolynomialSequence(x, universe, immutable=immutable, cr=cr, cr_str=cr_str) + + return Sequence_generic(x, universe, check, immutable, cr, cr_str, use_sage_types) class Sequence_generic(sage.structure.sage_object.SageObject, list): From b43a50c3f52ab9ddc652ce0a410baf21323f169c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 11:49:06 -0700 Subject: [PATCH 174/511] src/sage/sets/condition_set.py: Do not fail if sage.symbolic cannot be imported --- src/sage/sets/condition_set.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sage/sets/condition_set.py b/src/sage/sets/condition_set.py index 757014ace6c..b9373e65fad 100644 --- a/src/sage/sets/condition_set.py +++ b/src/sage/sets/condition_set.py @@ -19,9 +19,12 @@ from sage.categories.enumerated_sets import EnumeratedSets from sage.misc.cachefunc import cached_method from sage.misc.misc import _stable_uniq -from sage.symbolic.expression import is_Expression -from sage.symbolic.callable import is_CallableSymbolicExpression -from sage.symbolic.ring import SR + +try: + from sage.symbolic.expression import is_Expression + from sage.symbolic.callable import is_CallableSymbolicExpression +except ImportError: + is_CallableSymbolicExpression = is_Expression = lambda x: False from .set import Set, Set_base, Set_boolean_operators, Set_add_sub_operators @@ -169,6 +172,7 @@ def __classcall_private__(cls, universe, *predicates, vars=None, names=None, cat if names is None: raise TypeError('use callable symbolic expressions or provide variable names') if vars is None: + from sage.symbolic.ring import SR vars = tuple(SR.var(name) for name in names) callable_symbolic_predicates.append(predicate.function(*vars)) else: From 4e2f0ab62ea50af638d3679a8ad61350f218a4d2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 17:01:21 -0700 Subject: [PATCH 175/511] src/sage/arith/misc.py: move pari/flint imports into methods --- src/sage/arith/misc.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 039e786aff7..3bf42a46daa 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -19,10 +19,6 @@ from sage.misc.misc import powerset from sage.misc.misc_c import prod -from sage.libs.pari.all import pari -from sage.libs.flint.arith import (bernoulli_number as flint_bernoulli, - dedekind_sum as flint_dedekind_sum) - from sage.structure.element import parent from sage.structure.coerce import py_scalar_to_element @@ -266,6 +262,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 y = pari(z) f = y.algdep(degree) @@ -366,8 +363,10 @@ def bernoulli(n, algorithm='default', num_threads=1): if n >= 100000: from warnings import warn warn("flint is known to not be accurate for large Bernoulli numbers") + from sage.libs.flint.arith import bernoulli_number as flint_bernoulli return flint_bernoulli(n) elif algorithm == 'pari': + from sage.libs.pari.all import pari x = pari(n).bernfrac() # Use the PARI C library return Rational(x) elif algorithm == 'gap': @@ -465,6 +464,7 @@ def factorial(n, algorithm='gmp'): if algorithm == 'gmp': return ZZ(n).factorial() elif algorithm == 'pari': + from sage.libs.pari.all import pari return pari.factorial(n) else: raise ValueError('unknown algorithm') @@ -4160,6 +4160,7 @@ def nth_prime(n): """ if n <= 0: raise ValueError("nth prime meaningless for non-positive n (=%s)" % n) + from sage.libs.pari.all import pari return ZZ(pari.prime(n)) @@ -5872,6 +5873,7 @@ def dedekind_sum(p, q, algorithm='default'): - :wikipedia:`Dedekind\_sum` """ if algorithm == 'default' or algorithm == 'flint': + from sage.libs.flint.arith import dedekind_sum as flint_dedekind_sum return flint_dedekind_sum(p, q) if algorithm == 'pari': From 5145d43c5646f414f152e063fbbabed8854e2300 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 17:02:07 -0700 Subject: [PATCH 176/511] src/sage/arith/misc.py: Use sage.rings.abc instead of importing element classes RealNumber, ComplexNumber --- src/sage/arith/misc.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 3bf42a46daa..b235cd552b1 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -26,8 +26,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer, GCD_list from sage.rings.rational import Rational -from sage.rings.real_mpfr import RealNumber -from sage.rings.complex_mpfr import ComplexNumber +from sage.rings.abc import RealField, ComplexField from sage.rings.fast_arith import arith_int, arith_llong, prime_range @@ -203,7 +202,7 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, return None return z.denominator()*x - z.numerator() - if isinstance(z, (RealNumber, ComplexNumber)): + if isinstance(z.parent(), (RealField, ComplexField)): log2_10 = math.log(10,2) @@ -3609,7 +3608,7 @@ def binomial(x, m, **kwds): return P(x.binomial(m, **kwds)) # case 3: rational, real numbers, complex numbers -> use pari - if isinstance(x, (Rational, RealNumber, ComplexNumber)): + if isinstance(x, Rational) or isinstance(P, (RealField, ComplexField)): return P(x.__pari__().binomial(m)) # case 4: naive method From 5e5843a0c0703f0cb83c51b14c9aec8bc1450460 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 21:12:55 -0700 Subject: [PATCH 177/511] sage.arith.misc: Fixup --- src/sage/arith/misc.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index b235cd552b1..ddb143505b7 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -216,7 +216,7 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, if use_bits is not None: prec = int(use_bits) - is_complex = isinstance(z, ComplexNumber) + is_complex = isinstance(z.parent(), ComplexField) n = degree+1 from sage.matrix.all import matrix M = matrix(ZZ, n, n+1+int(is_complex)) @@ -3030,6 +3030,7 @@ def __call__(self, n): return ZZ(0) if n<=2: return ZZ(1) + from sage.libs.pari.all import pari return ZZ(pari(n).eulerphi()) def plot(self, xmin=1, xmax=50, pointsize=30, rgbcolor=(0,0,1), join=True, @@ -4100,6 +4101,7 @@ def primitive_root(n, check=True): sage: primitive_root(mpz(-46)) 5 """ + from sage.libs.pari.all import pari if not check: return ZZ(pari(n).znprimroot()) n = ZZ(n).abs() @@ -4278,6 +4280,7 @@ def __call__(self, n): # Use fast PARI algorithm if n == 0: return ZZ.zero() + from sage.libs.pari.all import pari return ZZ(pari(n).moebius()) @@ -4363,6 +4366,8 @@ 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 + if step == 1: v = pari('vector(%s, i, moebius(i-1+%s))'%( stop-start, start)) @@ -4492,6 +4497,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 return ZZ(pari(m).numdiv()) @@ -4566,6 +4572,7 @@ def hilbert_symbol(a, b, p, algorithm="pari"): if algorithm == "pari": if p == -1: p = 0 + from sage.libs.pari.all import pari return ZZ(pari(a).hilbert(b, p)) elif algorithm == 'direct': From 5ec8fa8ff28f6328b49f29a81168b02af7b8c2ae Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 15:18:22 -0700 Subject: [PATCH 178/511] src/sage/geometry/polyhedron/backend_cdd.py: Make Polyhedron_RDF_cdd a deprecated lazy_import --- src/sage/geometry/polyhedron/backend_cdd.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_cdd.py b/src/sage/geometry/polyhedron/backend_cdd.py index a8409e58a4f..0b99d0e6c23 100644 --- a/src/sage/geometry/polyhedron/backend_cdd.py +++ b/src/sage/geometry/polyhedron/backend_cdd.py @@ -22,6 +22,9 @@ from .base import Polyhedron_base from .base_QQ import Polyhedron_QQ +from sage.misc.lazy_import import lazy_import +lazy_import('sage.geometry.polyhedron.backend_cdd_rdf', 'Polyhedron_RDF_cdd', deprecation=32592) + class Polyhedron_cdd(Polyhedron_base): r""" @@ -457,7 +460,3 @@ def __init__(self, parent, Vrep, Hrep, **kwds): sage: TestSuite(p).run() """ Polyhedron_cdd.__init__(self, parent, Vrep, Hrep, **kwds) - - -from sage.misc.lazy_import import lazy_import -lazy_import('sage.geometry.polyhedron.backend_cdd_rdf', 'Polyhedron_RDF_cdd') From 7f317f128d20b1148f9e327e22254fb15fb477c5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 15:19:18 -0700 Subject: [PATCH 179/511] src/sage/geometry/polyhedron/parent.py: Use lazy_import for Polyhedron_RDF_cdd --- src/sage/geometry/polyhedron/parent.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 7f14eb0766e..002c93e9dfb 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -1127,7 +1127,8 @@ def _make_Line(self, polyhedron, data): -from sage.geometry.polyhedron.backend_cdd import Polyhedron_QQ_cdd, Polyhedron_RDF_cdd +from sage.geometry.polyhedron.backend_cdd import Polyhedron_QQ_cdd +lazy_import('sage.geometry.polyhedron.backend_cdd_rdf', Polyhedron_RDF_cdd) from sage.geometry.polyhedron.backend_ppl import Polyhedron_ZZ_ppl, Polyhedron_QQ_ppl from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz, Polyhedron_ZZ_normaliz, Polyhedron_QQ_normaliz from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake From 4ec38291bd3b7a53e44db4245ecd37f502f2f6c9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 15:24:25 -0700 Subject: [PATCH 180/511] src/sage/geometry/polyhedron/backend_cdd_rdf.py: Update imports in doctests --- src/sage/geometry/polyhedron/backend_cdd_rdf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_cdd_rdf.py b/src/sage/geometry/polyhedron/backend_cdd_rdf.py index e180448e1ad..2f3795a4b0f 100644 --- a/src/sage/geometry/polyhedron/backend_cdd_rdf.py +++ b/src/sage/geometry/polyhedron/backend_cdd_rdf.py @@ -34,7 +34,7 @@ class Polyhedron_RDF_cdd(Polyhedron_cdd, Polyhedron_RDF): sage: from sage.geometry.polyhedron.parent import Polyhedra sage: parent = Polyhedra(RDF, 2, backend='cdd') - sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_RDF_cdd + sage: from sage.geometry.polyhedron.backend_cdd_rdf import Polyhedron_RDF_cdd sage: Polyhedron_RDF_cdd(parent, [ [(1,0),(0,1),(0,0)], [], []], None, verbose=False) A 2-dimensional polyhedron in RDF^2 defined as the convex hull of 3 vertices @@ -119,7 +119,7 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep, verbose=Fal EXAMPLES:: sage: from sage.geometry.polyhedron.parent import Polyhedra_RDF_cdd - sage: from sage.geometry.polyhedron.backend_cdd import Polyhedron_RDF_cdd + sage: from sage.geometry.polyhedron.backend_cdd_rdf import Polyhedron_RDF_cdd sage: parent = Polyhedra_RDF_cdd(RDF, 1, 'cdd') sage: Vrep = [[[0.0], [1.0]], [], []] sage: Hrep = [[[0.0, 1.0], [1.0, -1.0]], []] From 9cd6a30daa0987acdf27d15bce672c568324d579 Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Thu, 30 Sep 2021 16:59:21 +0200 Subject: [PATCH 181/511] #32595 : remove nose spkg --- build/pkgs/nose/SPKG.rst | 34 ---------------------------- build/pkgs/nose/checksums.ini | 4 ---- build/pkgs/nose/dependencies | 5 ---- build/pkgs/nose/distros/conda.txt | 1 - build/pkgs/nose/distros/macports.txt | 1 - build/pkgs/nose/distros/repology.txt | 2 -- build/pkgs/nose/install-requires.txt | 1 - build/pkgs/nose/package-version.txt | 1 - build/pkgs/nose/spkg-check.in | 5 ---- build/pkgs/nose/spkg-install.in | 6 ----- build/pkgs/nose/type | 1 - 11 files changed, 61 deletions(-) delete mode 100644 build/pkgs/nose/SPKG.rst delete mode 100644 build/pkgs/nose/checksums.ini delete mode 100644 build/pkgs/nose/dependencies delete mode 100644 build/pkgs/nose/distros/conda.txt delete mode 100644 build/pkgs/nose/distros/macports.txt delete mode 100644 build/pkgs/nose/distros/repology.txt delete mode 100644 build/pkgs/nose/install-requires.txt delete mode 100644 build/pkgs/nose/package-version.txt delete mode 100644 build/pkgs/nose/spkg-check.in delete mode 100644 build/pkgs/nose/spkg-install.in delete mode 100644 build/pkgs/nose/type diff --git a/build/pkgs/nose/SPKG.rst b/build/pkgs/nose/SPKG.rst deleted file mode 100644 index 49f74660ac7..00000000000 --- a/build/pkgs/nose/SPKG.rst +++ /dev/null @@ -1,34 +0,0 @@ -nose: Python unit testing framework -=================================== - -Description ------------ - -nose extends the test loading and running features of unittest, making -it easier to write, find and run tests. - -License -------- - -GNU LGPL - - -Upstream Contact ----------------- - -Author: Jason Pellerin Home Page: http://readthedocs.org/docs/nose/ - - see also https://github.com/nose-devs/nose - -Dependencies ------------- - -- setuptools / distribute -- Python -- GNU patch (shipped with Sage) - - -Special Update/Build Instructions ---------------------------------- - -None. diff --git a/build/pkgs/nose/checksums.ini b/build/pkgs/nose/checksums.ini deleted file mode 100644 index b9477e8524b..00000000000 --- a/build/pkgs/nose/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=nose-VERSION.tar.gz -sha1=97f2a04c9d43b29ddf4794a1a1d1ba803f1074c6 -md5=4d3ad0ff07b61373d2cefc89c5d0b20b -cksum=3318391794 diff --git a/build/pkgs/nose/dependencies b/build/pkgs/nose/dependencies deleted file mode 100644 index 15df0c4d6d8..00000000000 --- a/build/pkgs/nose/dependencies +++ /dev/null @@ -1,5 +0,0 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) - ----------- -All lines of this file are ignored except the first. -It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/nose/distros/conda.txt b/build/pkgs/nose/distros/conda.txt deleted file mode 100644 index f3c7e8e6ffb..00000000000 --- a/build/pkgs/nose/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -nose diff --git a/build/pkgs/nose/distros/macports.txt b/build/pkgs/nose/distros/macports.txt deleted file mode 100644 index a29026eec2b..00000000000 --- a/build/pkgs/nose/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -py-nose diff --git a/build/pkgs/nose/distros/repology.txt b/build/pkgs/nose/distros/repology.txt deleted file mode 100644 index 4ebae104fde..00000000000 --- a/build/pkgs/nose/distros/repology.txt +++ /dev/null @@ -1,2 +0,0 @@ -nose -python:nose diff --git a/build/pkgs/nose/install-requires.txt b/build/pkgs/nose/install-requires.txt deleted file mode 100644 index 2e10ae2a3b2..00000000000 --- a/build/pkgs/nose/install-requires.txt +++ /dev/null @@ -1 +0,0 @@ -nose >=1.3.7 diff --git a/build/pkgs/nose/package-version.txt b/build/pkgs/nose/package-version.txt deleted file mode 100644 index 3336003dccd..00000000000 --- a/build/pkgs/nose/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -1.3.7 diff --git a/build/pkgs/nose/spkg-check.in b/build/pkgs/nose/spkg-check.in deleted file mode 100644 index 9bfbe9f31ab..00000000000 --- a/build/pkgs/nose/spkg-check.in +++ /dev/null @@ -1,5 +0,0 @@ -cd src - -python3 setup.py build_tests - -python3 selftest.py diff --git a/build/pkgs/nose/spkg-install.in b/build/pkgs/nose/spkg-install.in deleted file mode 100644 index fe7461d2f8b..00000000000 --- a/build/pkgs/nose/spkg-install.in +++ /dev/null @@ -1,6 +0,0 @@ -cd src - -# Install new version -echo "Installing nose..." -sdh_pip_install . -echo diff --git a/build/pkgs/nose/type b/build/pkgs/nose/type deleted file mode 100644 index a6a7b9cd726..00000000000 --- a/build/pkgs/nose/type +++ /dev/null @@ -1 +0,0 @@ -standard From 53fa1c7ebf4e1e2b0677eafbcc5d87785342dc9b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 15:38:23 -0700 Subject: [PATCH 182/511] .github/workflows/ci-cygwin-minimal.yml: Remove nose --- .github/workflows/ci-cygwin-minimal.yml | 2 +- .github/workflows/ci-cygwin-standard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-cygwin-minimal.yml b/.github/workflows/ci-cygwin-minimal.yml index 8c2a7d2213f..9e847e74740 100644 --- a/.github/workflows/ci-cygwin-minimal.yml +++ b/.github/workflows/ci-cygwin-minimal.yml @@ -84,7 +84,7 @@ jobs: cygwin-stage-i-b: env: STAGE: i-b - TARGETS: cython setuptools_scm kiwisolver dateutil cycler pyparsing nose certifi pkgconfig pplpy + TARGETS: cython setuptools_scm kiwisolver dateutil cycler pyparsing certifi pkgconfig pplpy LOCAL_ARTIFACT_NAME: sage-local-commit-${{ github.sha }}-cygwin-${{ matrix.pkgs }} LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-cygwin-${{ matrix.pkgs }} diff --git a/.github/workflows/ci-cygwin-standard.yml b/.github/workflows/ci-cygwin-standard.yml index a27118d7f17..cbbe0f46a8b 100644 --- a/.github/workflows/ci-cygwin-standard.yml +++ b/.github/workflows/ci-cygwin-standard.yml @@ -84,7 +84,7 @@ jobs: cygwin-stage-i-b: env: STAGE: i-b - TARGETS: cython setuptools_scm kiwisolver dateutil cycler pyparsing nose certifi pkgconfig pplpy + TARGETS: cython setuptools_scm kiwisolver dateutil cycler pyparsing certifi pkgconfig pplpy LOCAL_ARTIFACT_NAME: sage-local-commit-${{ github.sha }}-cygwin-${{ matrix.pkgs }} LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-cygwin-${{ matrix.pkgs }} From 0dba8bca20f6fcd20631e4252791427e45d4d8ea Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 15:39:33 -0700 Subject: [PATCH 183/511] build/pkgs/pkgconfig/SPKG.rst: Remove outdated info --- build/pkgs/pkgconfig/SPKG.rst | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/build/pkgs/pkgconfig/SPKG.rst b/build/pkgs/pkgconfig/SPKG.rst index cd737e14763..3c5d61a167a 100644 --- a/build/pkgs/pkgconfig/SPKG.rst +++ b/build/pkgs/pkgconfig/SPKG.rst @@ -17,16 +17,3 @@ Upstream Contact ---------------- https://github.com/matze/pkgconfig - -Dependencies ------------- - -- Python 2.6+ - - -Special Update/Build Instructions ---------------------------------- - -Standard setup.py - -- remove_nose.patch: Remove the nose dependency (not actually used) From e5bde3ffd7dee5f2119e40b7e448857b71efb128 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 15:41:41 -0700 Subject: [PATCH 184/511] build/bin/write-dockerfile.sh: Update SAGE_CHECK_PACKAGES for removed packages --- build/bin/write-dockerfile.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/bin/write-dockerfile.sh b/build/bin/write-dockerfile.sh index 05cfe124966..aa7050b203b 100755 --- a/build/bin/write-dockerfile.sh +++ b/build/bin/write-dockerfile.sh @@ -219,7 +219,7 @@ ARG NUMPROC=8 ENV MAKE="make -j\${NUMPROC}" ARG USE_MAKEFLAGS="-k V=0" ENV SAGE_CHECK=warn -ENV SAGE_CHECK_PACKAGES="!cython,!r,!python3,!python2,!nose,!pathpy,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" +ENV SAGE_CHECK_PACKAGES="!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" #:toolchain: $RUN make \${USE_MAKEFLAGS} base-toolchain $ENDRUN @@ -228,7 +228,7 @@ ARG NUMPROC=8 ENV MAKE="make -j\${NUMPROC}" ARG USE_MAKEFLAGS="-k V=0" ENV SAGE_CHECK=warn -ENV SAGE_CHECK_PACKAGES="!gfan,!cython,!r,!python3,!python2,!nose,!pathpy,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" +ENV SAGE_CHECK_PACKAGES="!gfan,!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" #:make: ARG TARGETS_PRE="all-sage-local" $RUN make SAGE_SPKG="sage-spkg -y -o" \${USE_MAKEFLAGS} \${TARGETS_PRE} $ENDRUN @@ -238,7 +238,7 @@ ARG NUMPROC=8 ENV MAKE="make -j\${NUMPROC}" ARG USE_MAKEFLAGS="-k V=0" ENV SAGE_CHECK=warn -ENV SAGE_CHECK_PACKAGES="!gfan,!cython,!r,!python3,!python2,!nose,!pathpy,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" +ENV SAGE_CHECK_PACKAGES="!gfan,!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" ADD src src ARG TARGETS="build" $RUN make SAGE_SPKG="sage-spkg -y -o" \${USE_MAKEFLAGS} \${TARGETS} $ENDRUN @@ -248,7 +248,7 @@ ARG NUMPROC=8 ENV MAKE="make -j\${NUMPROC}" ARG USE_MAKEFLAGS="-k V=0" ENV SAGE_CHECK=warn -ENV SAGE_CHECK_PACKAGES="!gfan,!cython,!r,!python3,!python2,!nose,!pathpy,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" +ENV SAGE_CHECK_PACKAGES="!gfan,!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" ARG TARGETS_OPTIONAL="ptest" $RUN make SAGE_SPKG="sage-spkg -y -o" \${USE_MAKEFLAGS} \${TARGETS_OPTIONAL} || echo "(error ignored)" $ENDRUN From 9e5e095234d21c4e73f26d2bde11429ab30cfc8c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 15:45:11 -0700 Subject: [PATCH 185/511] tox.ini: Update SAGE_CHECK_PACKAGES for removed packages --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 9bd5ece819d..d565133513b 100644 --- a/tox.ini +++ b/tox.ini @@ -577,8 +577,8 @@ commands = local: config*) ;; \ local: *) make -k V=0 base-toolchain ;; \ local: esac && \ - local: make -k V=0 SAGE_CHECK=warn SAGE_CHECK_PACKAGES="!cython,!r,!python3,!nose,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" {env:TARGETS_PRE:} {posargs:build} && \ - local: ( [ -z "{env:TARGETS_OPTIONAL:}" ] || make -k V=0 SAGE_CHECK=warn SAGE_CHECK_PACKAGES="!cython,!r,!python3,!nose,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" {env:TARGETS_OPTIONAL:} || echo "(error ignored)" ) ' + local: make -k V=0 SAGE_CHECK=warn SAGE_CHECK_PACKAGES="!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" {env:TARGETS_PRE:} {posargs:build} && \ + local: ( [ -z "{env:TARGETS_OPTIONAL:}" ] || make -k V=0 SAGE_CHECK=warn SAGE_CHECK_PACKAGES="!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" {env:TARGETS_OPTIONAL:} || echo "(error ignored)" ) ' [testenv:check_configure] ## Test that configure behaves properly From b3fcbd895c490dc48e8b0d33c3d11811881e3461 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 17:48:48 -0700 Subject: [PATCH 186/511] build/pkgs/symengine[_py]: Update to 0.8.1 --- build/pkgs/symengine/checksums.ini | 6 +++--- build/pkgs/symengine/package-version.txt | 2 +- build/pkgs/symengine_py/checksums.ini | 6 +++--- build/pkgs/symengine_py/package-version.txt | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/pkgs/symengine/checksums.ini b/build/pkgs/symengine/checksums.ini index b5600d35000..712c4eddb90 100644 --- a/build/pkgs/symengine/checksums.ini +++ b/build/pkgs/symengine/checksums.ini @@ -1,5 +1,5 @@ tarball=symengine-VERSION.tar.gz -sha1=a4d30b3c417c3939383384b95c8b3c248e4e413e -md5=72b8f1442fd3084c96e59d9fe87eec1a -cksum=3356860163 +sha1=87a0104d8682cb2f192d8b4bf3435a514bdb6f4c +md5=967b913b365eda9fb30ecb3f1ded46f2 +cksum=2359123828 upstream_url=https://github.com/symengine/symengine/releases/download/vVERSION/symengine-VERSION.tar.gz diff --git a/build/pkgs/symengine/package-version.txt b/build/pkgs/symengine/package-version.txt index faef31a4357..6f4eebdf6f6 100644 --- a/build/pkgs/symengine/package-version.txt +++ b/build/pkgs/symengine/package-version.txt @@ -1 +1 @@ -0.7.0 +0.8.1 diff --git a/build/pkgs/symengine_py/checksums.ini b/build/pkgs/symengine_py/checksums.ini index 00b39b8e687..3b0db282ffa 100644 --- a/build/pkgs/symengine_py/checksums.ini +++ b/build/pkgs/symengine_py/checksums.ini @@ -1,5 +1,5 @@ tarball=symengine.py-VERSION.tar.gz -sha1=8535fea222d85c5afefc5122dd5d43d91aa4ebb0 -md5=0167a0081410be856edc8ee245005576 -cksum=4011943203 +sha1=16da67020baf6ab95cd517f58618fa7af1c8fc5e +md5=1c365dd039f8568b732c39fa4c9a7cf4 +cksum=3244910588 upstream_url=https://github.com/symengine/symengine.py/archive/vVERSION.tar.gz diff --git a/build/pkgs/symengine_py/package-version.txt b/build/pkgs/symengine_py/package-version.txt index 5d8391e20f4..6f4eebdf6f6 100644 --- a/build/pkgs/symengine_py/package-version.txt +++ b/build/pkgs/symengine_py/package-version.txt @@ -1 +1 @@ -0.7.0.post2 +0.8.1 From c4faa5fe075435c45a2e2456a687bb442acd009c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 18:07:03 -0700 Subject: [PATCH 187/511] build/pkgs/symengine/patches/1749.patch: Remove --- build/pkgs/symengine/patches/1749.patch | 44 ------------------------- 1 file changed, 44 deletions(-) delete mode 100644 build/pkgs/symengine/patches/1749.patch diff --git a/build/pkgs/symengine/patches/1749.patch b/build/pkgs/symengine/patches/1749.patch deleted file mode 100644 index 40ff66b1856..00000000000 --- a/build/pkgs/symengine/patches/1749.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 713c096527291b24a8bee47895859f202b6eaa92 Mon Sep 17 00:00:00 2001 -From: Isuru Fernando -Date: Sat, 20 Mar 2021 13:33:17 -0500 -Subject: [PATCH] Check for flint-arb - ---- - cmake/FindARB.cmake | 2 +- - cmake/LibFindMacros.cmake | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/cmake/FindARB.cmake b/cmake/FindARB.cmake -index 770da3133..281c5beae 100644 ---- a/cmake/FindARB.cmake -+++ b/cmake/FindARB.cmake -@@ -1,7 +1,7 @@ - include(LibFindMacros) - - libfind_include(arb.h arb) --libfind_library(arb arb) -+libfind_library(arb arb flint-arb) - - set(ARB_LIBRARIES ${ARB_LIBRARY}) - set(ARB_INCLUDE_DIRS ${ARB_INCLUDE_DIR}) -diff --git a/cmake/LibFindMacros.cmake b/cmake/LibFindMacros.cmake -index 68fcaa426..06aa3f5ba 100644 ---- a/cmake/LibFindMacros.cmake -+++ b/cmake/LibFindMacros.cmake -@@ -28,7 +28,7 @@ function (libfind_library libname pkg) - - find_library(${LIBNAME}_LIBRARY - NAMES -- ${libname} -+ ${libname} ${ARGN} - ) - - if (NOT TARGET ${libname}) -@@ -42,6 +42,6 @@ function (libfind_include HEADER pkg) - - find_path(${PKG}_INCLUDE_DIR - NAMES -- ${HEADER} -+ ${HEADER} ${ARGN} - ) - endfunction() From f929448e8e1effe764fc557c78706aefd72cf0f7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 18:07:34 -0700 Subject: [PATCH 188/511] build/pkgs/symengine_py: Switch from nose to pytest --- build/pkgs/symengine_py/dependencies | 2 +- build/pkgs/symengine_py/spkg-check.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/symengine_py/dependencies b/build/pkgs/symengine_py/dependencies index 1b773295978..a48b85c68e8 100644 --- a/build/pkgs/symengine_py/dependencies +++ b/build/pkgs/symengine_py/dependencies @@ -1,4 +1,4 @@ -symengine $(PYTHON) | cmake cython $(PYTHON_TOOLCHAIN) $(and $(filter-out no,$(SAGE_CHECK_symengine_py)), nose) +symengine $(PYTHON) | cmake cython $(PYTHON_TOOLCHAIN) $(and $(filter-out no,$(SAGE_CHECK_symengine_py)), pytest) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/symengine_py/spkg-check.in b/build/pkgs/symengine_py/spkg-check.in index fba8e388486..ac32958383b 100644 --- a/build/pkgs/symengine_py/spkg-check.in +++ b/build/pkgs/symengine_py/spkg-check.in @@ -1,3 +1,3 @@ cd src -nosetests symengine/tests -v +python3 -m pytest -s -v symengine/tests/test_*.py From 8f1b81693da0065a9daa12bd9c4b98edc601a583 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 21:05:29 -0700 Subject: [PATCH 189/511] build/pkgs/perl_cpan_polymake_prereq/distros: Add info for Term::ReadKey --- build/pkgs/perl_cpan_polymake_prereq/distros/cpan.txt | 1 + build/pkgs/perl_cpan_polymake_prereq/distros/fedora.txt | 1 + build/pkgs/perl_cpan_polymake_prereq/distros/freebsd.txt | 1 + build/pkgs/perl_cpan_polymake_prereq/distros/gentoo.txt | 1 + 4 files changed, 4 insertions(+) diff --git a/build/pkgs/perl_cpan_polymake_prereq/distros/cpan.txt b/build/pkgs/perl_cpan_polymake_prereq/distros/cpan.txt index fbd93fc89a2..131aebf6d3d 100644 --- a/build/pkgs/perl_cpan_polymake_prereq/distros/cpan.txt +++ b/build/pkgs/perl_cpan_polymake_prereq/distros/cpan.txt @@ -4,3 +4,4 @@ XML::LibXSLT File::Slurp JSON SVG +Term::ReadKey diff --git a/build/pkgs/perl_cpan_polymake_prereq/distros/fedora.txt b/build/pkgs/perl_cpan_polymake_prereq/distros/fedora.txt index 89a8a7622bf..c7390e63993 100644 --- a/build/pkgs/perl_cpan_polymake_prereq/distros/fedora.txt +++ b/build/pkgs/perl_cpan_polymake_prereq/distros/fedora.txt @@ -2,6 +2,7 @@ perl-ExtUtils-Embed perl-File-Slurp perl-JSON perl-Term-ReadLine-Gnu +perl-Term-ReadKey perl-XML-Writer perl-XML-LibXML perl-XML-LibXSLT diff --git a/build/pkgs/perl_cpan_polymake_prereq/distros/freebsd.txt b/build/pkgs/perl_cpan_polymake_prereq/distros/freebsd.txt index 9b2b62bccd9..43a596433c9 100644 --- a/build/pkgs/perl_cpan_polymake_prereq/distros/freebsd.txt +++ b/build/pkgs/perl_cpan_polymake_prereq/distros/freebsd.txt @@ -4,3 +4,4 @@ textproc/p5-XML-LibXSLT devel/p5-File-Slurp converters/p5-JSON textproc/p5-SVG +devel/p5-Term-ReadKey diff --git a/build/pkgs/perl_cpan_polymake_prereq/distros/gentoo.txt b/build/pkgs/perl_cpan_polymake_prereq/distros/gentoo.txt index 67835e72530..b4803c6fdac 100644 --- a/build/pkgs/perl_cpan_polymake_prereq/distros/gentoo.txt +++ b/build/pkgs/perl_cpan_polymake_prereq/distros/gentoo.txt @@ -3,5 +3,6 @@ XML-LibXML XML-LibXSLT File-Slurp dev-perl/Term-ReadLine-Gnu +dev-perl/TermReadKey JSON SVG From 654e6ea327c74225ecc5633e074285517bf0f038 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 21:06:20 -0700 Subject: [PATCH 190/511] build/pkgs/{perl_term_readline_gnu,polymake}: Change from experimental to optional --- build/pkgs/perl_term_readline_gnu/type | 2 +- build/pkgs/polymake/type | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/perl_term_readline_gnu/type b/build/pkgs/perl_term_readline_gnu/type index 9839eb20815..134d9bc32d5 100644 --- a/build/pkgs/perl_term_readline_gnu/type +++ b/build/pkgs/perl_term_readline_gnu/type @@ -1 +1 @@ -experimental +optional diff --git a/build/pkgs/polymake/type b/build/pkgs/polymake/type index 9839eb20815..134d9bc32d5 100644 --- a/build/pkgs/polymake/type +++ b/build/pkgs/polymake/type @@ -1 +1 @@ -experimental +optional From bcfe1634895aa509599ed5d0ddb214703c9cff3c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 21:06:35 -0700 Subject: [PATCH 191/511] build/pkgs/polymake: Update to 4.5 --- build/pkgs/polymake/checksums.ini | 6 +++--- build/pkgs/polymake/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/polymake/checksums.ini b/build/pkgs/polymake/checksums.ini index e059b0e2bbd..081ea86bc52 100644 --- a/build/pkgs/polymake/checksums.ini +++ b/build/pkgs/polymake/checksums.ini @@ -1,5 +1,5 @@ tarball=polymake-VERSION-minimal.tar.bz2 -sha1=5370b16300ff8aed4eb5fa6bb5232d25935e6303 -md5=8f6a8e87e3b8bf5ccf22f26790a4dd1a -cksum=1398515202 +sha1=d50dff3f2124a22563cc468f104c360b81a2c59d +md5=8785d6fca67ef7becad6600dad0fefaf +cksum=1451222436 upstream_url=https://polymake.org/lib/exe/fetch.php/download/polymake-VERSION-minimal.tar.bz2 diff --git a/build/pkgs/polymake/package-version.txt b/build/pkgs/polymake/package-version.txt index 515be8f918d..4caecc733e6 100644 --- a/build/pkgs/polymake/package-version.txt +++ b/build/pkgs/polymake/package-version.txt @@ -1 +1 @@ -4.4 +4.5 From 9d2674b8d443f0524f60f0777c59775cc6fb658e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 21:24:39 -0700 Subject: [PATCH 192/511] src/sage/interfaces/polymake.py: Mark some more doctests '# optional - polymake_expect' --- src/sage/interfaces/polymake.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index 8ac83e87ad6..06092472a17 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -2174,17 +2174,17 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if work in an interactive session and often in doc tests, too. However, sometimes it hangs, and therefore we remove it from the tests, for now:: - sage: c = polymake.cube(15) # optional - polymake - sage: polymake.eval('print {}->F_VECTOR;'.format(c.name()), timeout=1) # not tested # optional - polymake + sage: c = polymake.cube(15) # optional - polymake_expect + sage: polymake.eval('print {}->F_VECTOR;'.format(c.name()), timeout=1) # not tested # optional - polymake_expect Traceback (most recent call last): ... RuntimeError: Polymake fails to respond timely We verify that after the timeout, polymake is still able to give answers:: - sage: c # optional - polymake + sage: c # optional - polymake_expect cube of dimension 15 - sage: c.N_VERTICES # optional - polymake + sage: c.N_VERTICES # optional - polymake_expect 32768 Note, however, that the recovery after a timeout is not perfect. From 9e74b6a96bbd946a6944a5e078e411dc0a412cf3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 18:31:15 -0700 Subject: [PATCH 193/511] sage.rings.abc: Add IntegerModRing, Order; use them in sage.matrix, sage.modules --- src/sage/matrix/matrix0.pyx | 4 ++-- src/sage/modules/free_module.py | 6 +++--- src/sage/rings/abc.pyx | 15 +++++++++++++++ src/sage/rings/finite_rings/integer_mod_ring.py | 2 +- src/sage/rings/number_field/order.py | 3 ++- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/sage/matrix/matrix0.pyx b/src/sage/matrix/matrix0.pyx index 41b8da5f415..92c87e3a2ec 100644 --- a/src/sage/matrix/matrix0.pyx +++ b/src/sage/matrix/matrix0.pyx @@ -44,7 +44,7 @@ from sage.categories.integral_domains import IntegralDomains from sage.rings.ring cimport CommutativeRing from sage.rings.ring import is_Ring -from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing +import sage.rings.abc from sage.rings.integer_ring import is_IntegerRing import sage.modules.free_module @@ -5749,7 +5749,7 @@ cdef class Matrix(sage.structure.element.Matrix): R = self.base_ring() if algorithm is None and R in _Fields: return ~self - elif algorithm is None and is_IntegerModRing(R): + elif algorithm is None and isinstance(R, sage.rings.abc.IntegerModRing): # Finite fields are handled above. # This is "easy" in that we either get an error or # the right answer. Note that of course there diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 57c10114174..4ff7ec743a1 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -172,7 +172,7 @@ import sage.rings.ring as ring import sage.rings.integer_ring import sage.rings.rational_field -import sage.rings.finite_rings.integer_mod_ring +import sage.rings.abc import sage.rings.infinity import sage.rings.integer from sage.categories.principal_ideal_domains import PrincipalIdealDomains @@ -253,7 +253,7 @@ def create_object(self, version, key): elif base_ring in PrincipalIdealDomains(): return FreeModule_ambient_pid(base_ring, rank, sparse=sparse) - elif isinstance(base_ring, sage.rings.number_field.order.Order) \ + elif isinstance(base_ring, sage.rings.abc.Order) \ and base_ring.is_maximal() and base_ring.class_number() == 1: return FreeModule_ambient_pid(base_ring, rank, sparse=sparse) @@ -7434,7 +7434,7 @@ def element_class(R, is_sparse): elif sage.rings.rational_field.is_RationalField(R) and not is_sparse: from .vector_rational_dense import Vector_rational_dense return Vector_rational_dense - elif sage.rings.finite_rings.integer_mod_ring.is_IntegerModRing(R) and not is_sparse: + elif isinstance(R, sage.rings.abc.IntegerModRing) and not is_sparse: from .vector_mod2_dense import Vector_mod2_dense if R.order() == 2: return Vector_mod2_dense diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index c65e03d9ed0..147dcb4f089 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -32,3 +32,18 @@ cdef class ComplexDoubleField(Field): """ pass + + +class IntegerModRing: + r""" + Abstract base class for :class:`~sage.rings.finite_rings.integer_mod_ring.IntegerModRing_generic`. + """ + + pass + +class Order: + r""" + Abstract base class for :class:`~sage.rings.number_field.order.Order`. + """ + + pass diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index c704b2a2eb7..c225d412a11 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -297,7 +297,7 @@ def _unit_gens_primepowercase(p, r): @richcmp_method -class IntegerModRing_generic(quotient_ring.QuotientRing_generic): +class IntegerModRing_generic(quotient_ring.QuotientRing_generic, IntegerModRing): """ The ring of integers modulo `N`. diff --git a/src/sage/rings/number_field/order.py b/src/sage/rings/number_field/order.py index 56ef3d550bb..ec128df7834 100644 --- a/src/sage/rings/number_field/order.py +++ b/src/sage/rings/number_field/order.py @@ -47,6 +47,7 @@ from sage.rings.ring import IntegralDomain from sage.structure.sequence import Sequence from sage.rings.integer_ring import ZZ +import sage.rings.abc from sage.structure.element import is_Element from .number_field_element import OrderElement_absolute, OrderElement_relative @@ -126,7 +127,7 @@ def EquationOrder(f, names, **kwds): return K.order(K.gens()) -class Order(IntegralDomain): +class Order(IntegralDomain, sage.rings.abc.Order): r""" An order in a number field. From 8ef2b356025c3bc055f3bed1d63bce65956cb221 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 19:08:25 -0700 Subject: [PATCH 194/511] sage.structure, sage.rings, sage.matrix: Use sage.rings.abc for IntegerModRing --- src/sage/matrix/matrix2.pyx | 9 +++++---- src/sage/matrix/matrix_space.py | 4 ++-- src/sage/rings/finite_rings/finite_field_base.pyx | 4 ++-- src/sage/structure/parent.pyx | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index d4a8ec9d3a1..74e01aa7241 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -95,6 +95,7 @@ from sage.rings.real_mpfr import RealField from sage.rings.complex_mpfr import ComplexField from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.misc.derivative import multi_derivative +import sage.rings.abc from sage.arith.numerical_approx cimport digits_to_bits from copy import copy @@ -822,8 +823,7 @@ cdef class Matrix(Matrix1): if not K.is_integral_domain(): # The non-integral-domain case is handled almost entirely # separately. - from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing - if is_IntegerModRing(K): + if isinstance(K, sage.rings.abc.IntegerModRing): from sage.libs.pari import pari A = pari(self.lift()) b = pari(B).lift() @@ -1985,7 +1985,6 @@ cdef class Matrix(Matrix1): sage: A.determinant() == B.determinant() True """ - from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing from sage.symbolic.ring import is_SymbolicExpressionRing cdef Py_ssize_t n @@ -2031,7 +2030,7 @@ cdef class Matrix(Matrix1): return d # Special case for Z/nZ or GF(p): - if is_IntegerModRing(R) and self.is_dense(): + if isinstance(R, sage.rings.abc.IntegerModRing) and self.is_dense(): import sys # If the characteristic is prime and smaller than a machine # word, use PARI. @@ -14723,6 +14722,8 @@ cdef class Matrix(Matrix1): for i from 0 <= i < size: PyList_Append(M,f(PyList_GET_ITEM(L,i))) + from sage.rings.finite_rings.integer_mod_ring import IntegerModRing + return MatrixSpace(IntegerModRing(2), nrows=self._nrows,ncols=self._ncols).matrix(M) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 47766db0c46..eabba820926 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -236,7 +236,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): except ImportError: pass - if sage.rings.finite_rings.integer_mod_ring.is_IntegerModRing(R): + if isinstance(R, sage.rings.abc.IntegerModRing): from . import matrix_modn_dense_double, matrix_modn_dense_float if R.order() < matrix_modn_dense_float.MAX_MODULUS: return matrix_modn_dense_float.Matrix_modn_dense_float @@ -326,7 +326,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): if implementation is not None: raise ValueError("cannot choose an implementation for sparse matrices") - if sage.rings.finite_rings.integer_mod_ring.is_IntegerModRing(R) and R.order() < matrix_modn_sparse.MAX_MODULUS: + if isinstance(R, sage.rings.abc.IntegerModRing) and R.order() < matrix_modn_sparse.MAX_MODULUS: return matrix_modn_sparse.Matrix_modn_sparse if sage.rings.rational_field.is_RationalField(R): diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index 91f69730fee..f3183df44aa 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -40,6 +40,7 @@ from sage.misc.persist import register_unpickle_override from sage.misc.cachefunc import cached_method from sage.misc.prandom import randrange from sage.rings.integer cimport Integer +import sage.rings.abc from sage.misc.superseded import deprecation_cython as deprecation # Copied from sage.misc.fast_methods, used in __hash__() below. @@ -1342,10 +1343,9 @@ cdef class FiniteField(Field): False """ from sage.rings.integer_ring import ZZ - from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing if R is int or R is long or R is ZZ: return True - if is_IntegerModRing(R) and self.characteristic().divides(R.characteristic()): + if isinstance(R, sage.rings.abc.IntegerModRing) and self.characteristic().divides(R.characteristic()): return R.hom((self.one(),), check=False) if is_FiniteField(R): if R is self: diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 4559972c94f..9d7527b913a 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -2642,8 +2642,8 @@ cdef class Parent(sage.structure.category_object.CategoryObject): elif self_on_left and op is operator.pow: S_is_int = parent_is_integers(S) if not S_is_int: - from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing - if is_IntegerModRing(S): + from sage.rings.abc import IntegerModRing + if isinstance(S, IntegerModRing): # We allow powering by an IntegerMod by treating it # as an integer. # From 335cd3e8f0b6b16195c5b59cfa806582b61248fa Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 30 Sep 2021 21:45:17 -0700 Subject: [PATCH 195/511] Replace all uses of is_IntegerModRing by isinstance(..., sage.rings.abc.IntegerModRing) --- src/sage/libs/singular/ring.pyx | 4 ++-- src/sage/matrix/matrix_rational_dense.pyx | 4 ++-- src/sage/rings/polynomial/multi_polynomial_ideal.py | 4 ++-- src/sage/rings/polynomial/multi_polynomial_libsingular.pyx | 4 ++-- src/sage/rings/polynomial/polynomial_element.pyx | 5 ++--- src/sage/rings/polynomial/polynomial_ring_constructor.py | 4 ++-- src/sage/rings/polynomial/polynomial_singular_interface.py | 6 +++--- src/sage/schemes/elliptic_curves/constructor.py | 4 ++-- src/sage/schemes/elliptic_curves/ell_generic.py | 4 ++-- src/sage/symbolic/ring.pyx | 4 ++-- 10 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/sage/libs/singular/ring.pyx b/src/sage/libs/singular/ring.pyx index 63b63070cd2..2f9ece4d055 100644 --- a/src/sage/libs/singular/ring.pyx +++ b/src/sage/libs/singular/ring.pyx @@ -31,7 +31,7 @@ from sage.libs.singular.decl cimport rDefault, GFInfo, ZnmInfo, nInitChar, AlgEx from sage.rings.integer cimport Integer from sage.rings.integer_ring cimport IntegerRing_class from sage.rings.integer_ring import ZZ -from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing +import sage.rings.abc from sage.rings.number_field.number_field_base cimport NumberField from sage.rings.rational_field import RationalField from sage.rings.finite_rings.finite_field_base import FiniteField as FiniteField_generic @@ -324,7 +324,7 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: _ring = rDefault (_cf ,nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) - elif is_IntegerModRing(base_ring): + elif isinstance(base_ring, sage.rings.abc.IntegerModRing): ch = base_ring.characteristic() if ch < 2: diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index d67529c0a7e..3432de8c349 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -109,7 +109,7 @@ from sage.rings.integer cimport Integer from sage.rings.ring import is_Ring from sage.rings.integer_ring import ZZ, is_IntegerRing from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing +import sage.rings.abc from sage.rings.rational_field import QQ from sage.arith.all import gcd @@ -1487,7 +1487,7 @@ cdef class Matrix_rational_dense(Matrix_dense): return A from .matrix_modn_dense_double import MAX_MODULUS - if is_IntegerModRing(R) and R.order() < MAX_MODULUS: + if isinstance(R, sage.rings.abc.IntegerModRing) and R.order() < MAX_MODULUS: b = R.order() A, d = self._clear_denom() if not b.gcd(d).is_one(): diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index da88a329bc6..65e5e7ee7a1 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -249,6 +249,7 @@ from sage.misc.method_decorator import MethodDecorator from sage.rings.integer_ring import ZZ +import sage.rings.abc import sage.rings.polynomial.toy_buchberger as toy_buchberger import sage.rings.polynomial.toy_variety as toy_variety import sage.rings.polynomial.toy_d_basis as toy_d_basis @@ -4288,7 +4289,6 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal sage: I.groebner_basis('magma:GroebnerBasis') # optional - magma [a + (-60)*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 + (-79/7)*c^2 + 3/7*c, c^4 + (-10/21)*c^3 + 1/84*c^2 + 1/84*c] """ - from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -4331,7 +4331,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal deg_bound=deg_bound, mult_bound=mult_bound, prot=prot, *args, **kwds)] elif (R.term_order().is_global() - and is_IntegerModRing(B) + and isinstance(B, sage.rings.abc.IntegerModRing) and not B.is_field()): verbose("Warning: falling back to very slow toy implementation.", level=0) diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index ec706f3129d..9380bffc850 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -221,6 +221,7 @@ from sage.rings.polynomial.polydict cimport ETuple from sage.rings.polynomial.polynomial_ring import is_PolynomialRing # base ring imports +import sage.rings.abc from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn from sage.rings.rational cimport Rational from sage.rings.rational_field import QQ @@ -229,7 +230,6 @@ from sage.rings.real_mpfr import is_RealField from sage.rings.integer_ring import is_IntegerRing, ZZ from sage.rings.integer cimport Integer from sage.rings.integer import GCD_list -from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing from sage.rings.number_field.number_field_base cimport NumberField from sage.structure.element import coerce_binop @@ -1407,7 +1407,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): elif is_IntegerRing(base_ring): self.__singular = singular.ring("(integer)", _vars, order=order) - elif is_IntegerModRing(base_ring): + elif isinstance(base_ring, sage.rings.abc.IntegerModRing): ch = base_ring.characteristic() if ch.is_power_of(2): exp = ch.nbits() -1 diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index f7807221d55..1e948372613 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -101,7 +101,6 @@ from sage.structure.element cimport (parent, have_same_parent, from sage.rings.rational_field import QQ, is_RationalField from sage.rings.integer_ring import ZZ, is_IntegerRing -from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing from sage.rings.integer cimport Integer, smallInteger from sage.libs.gmp.mpz cimport * from sage.rings.fraction_field import is_FractionField @@ -4446,7 +4445,7 @@ cdef class Polynomial(CommutativeAlgebraElement): n = None - if is_IntegerModRing(R) or is_IntegerRing(R): + if isinstance(R, sage.rings.abc.IntegerModRing) or is_IntegerRing(R): try: G = list(self._pari_with_name().factor()) except PariError: @@ -8124,7 +8123,7 @@ cdef class Polynomial(CommutativeAlgebraElement): if K.is_finite(): if multiplicities: raise NotImplementedError("root finding with multiplicities for this polynomial not implemented (try the multiplicities=False option)") - elif is_IntegerModRing(K): + elif isinstance(K, sage.rings.abc.IntegerModRing): # handling via the chinese remainders theorem N = K.cardinality() primes = N.prime_divisors() diff --git a/src/sage/rings/polynomial/polynomial_ring_constructor.py b/src/sage/rings/polynomial/polynomial_ring_constructor.py index c88f6705ccd..603bdaff2ec 100644 --- a/src/sage/rings/polynomial/polynomial_ring_constructor.py +++ b/src/sage/rings/polynomial/polynomial_ring_constructor.py @@ -27,9 +27,9 @@ import sage.rings.ring as ring import sage.rings.padics.padic_base_leaves as padic_base_leaves +import sage.rings.abc from sage.rings.integer import Integer from sage.rings.finite_rings.finite_field_base import is_FiniteField -from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing from sage.misc.cachefunc import weak_cached_function @@ -694,7 +694,7 @@ def _single_variate(base_ring, name, sparse=None, implementation=None, order=Non # Specialized implementations specialized = None - if is_IntegerModRing(base_ring): + if isinstance(base_ring, sage.rings.abc.IntegerModRing): n = base_ring.order() if n.is_prime(): specialized = polynomial_ring.PolynomialRing_dense_mod_p diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index 61777d5556a..d8b537789be 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -38,13 +38,13 @@ ###################################################################### import sage.rings.fraction_field +import sage.rings.abc import sage.rings.number_field as number_field from sage.interfaces.all import singular from sage.rings.complex_mpfr import is_ComplexField from sage.rings.real_mpfr import is_RealField from sage.rings.complex_double import is_ComplexDoubleField -from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing from sage.rings.real_double import is_RealDoubleField from sage.rings.rational_field import is_RationalField from sage.rings.function_field.function_field import RationalFunctionField @@ -336,7 +336,7 @@ def _singular_init_(self, singular=singular): gen = str(base_ring.gen()) self.__singular = singular.ring( "(%s,%s)"%(base_ring.characteristic(),gen), _vars, order=order, check=False) - elif is_IntegerModRing(base_ring): + elif isinstance(base_ring, sage.rings.abc.IntegerModRing): ch = base_ring.characteristic() if ch.is_power_of(2): exp = ch.nbits() -1 @@ -388,7 +388,7 @@ def can_convert_to_singular(R): if (base_ring is ZZ or sage.rings.finite_rings.finite_field_constructor.is_FiniteField(base_ring) or is_RationalField(base_ring) - or is_IntegerModRing(base_ring) + or isinstance(base_ring, sage.rings.abc.IntegerModRing) or is_RealField(base_ring) or is_ComplexField(base_ring) or is_RealDoubleField(base_ring) diff --git a/src/sage/schemes/elliptic_curves/constructor.py b/src/sage/schemes/elliptic_curves/constructor.py index e9320cc174b..90bc4519082 100644 --- a/src/sage/schemes/elliptic_curves/constructor.py +++ b/src/sage/schemes/elliptic_curves/constructor.py @@ -25,7 +25,7 @@ import sage.rings.all as rings -from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing +import sage.rings.abc from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.rings.number_field.number_field import is_NumberField @@ -464,7 +464,7 @@ def create_object(self, version, key, **kwds): elif rings.is_pAdicField(R): from .ell_padic_field import EllipticCurve_padic_field return EllipticCurve_padic_field(R, x) - elif is_FiniteField(R) or (is_IntegerModRing(R) and R.characteristic().is_prime()): + elif is_FiniteField(R) or (isinstance(R, sage.rings.abc.IntegerModRing) and R.characteristic().is_prime()): from .ell_finite_field import EllipticCurve_finite_field return EllipticCurve_finite_field(R, x) elif R in _Fields: diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index 912496bca28..b5207f513f0 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -46,6 +46,7 @@ import math +import sage.rings.abc from sage.rings.all import PolynomialRing from sage.rings.polynomial.polynomial_ring import polygen, polygens import sage.groups.additive_abelian.additive_abelian_group as groups @@ -156,8 +157,7 @@ def __init__(self, K, ainvs): # EllipticCurvePoint_finite_field for finite rings, so that we # can do some arithmetic on points over Z/NZ, for teaching # purposes. - from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing - if is_IntegerModRing(K): + if isinstance(K, sage.rings.abc.IntegerModRing): self._point = ell_point.EllipticCurvePoint_finite_field _point = ell_point.EllipticCurvePoint diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index ffe8d7443f2..9bc5c1db7a1 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -47,6 +47,7 @@ from sage.structure.element cimport Element from sage.categories.morphism cimport Morphism from sage.structure.coerce cimport is_numpy_type +import sage.rings.abc from sage.rings.integer_ring import ZZ # is_SymbolicVariable used to be defined here; re-export it @@ -205,7 +206,6 @@ cdef class SymbolicRing(CommutativeRing): from sage.rings.real_mpfr import mpfr_prec_min from sage.rings.fraction_field import is_FractionField - from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing from sage.rings.real_mpfi import is_RealIntervalField from sage.rings.complex_interval_field import is_ComplexIntervalField from sage.rings.real_arb import RealBallField @@ -234,7 +234,7 @@ cdef class SymbolicRing(CommutativeRing): or is_RealIntervalField(R) or is_ComplexIntervalField(R) or isinstance(R, RealBallField) or isinstance(R, ComplexBallField) - or is_IntegerModRing(R) or is_FiniteField(R)): + or isinstance(R, sage.rings.abc.IntegerModRing) or is_FiniteField(R)): return True elif isinstance(R, GenericSymbolicSubring): return True From f596395836a4c6e3f7a42b56acc4a805c8633abf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 21:14:44 -0700 Subject: [PATCH 196/511] sage.rings.finite_rings.integer_mod_ring: Fixup --- src/sage/rings/finite_rings/integer_mod_ring.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index c225d412a11..27ea7f424fc 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -64,6 +64,7 @@ from sage.arith.all import factor, primitive_root, CRT_basis import sage.rings.ring as ring +import sage.rings.abc from . import integer_mod import sage.rings.integer as integer import sage.rings.integer_ring as integer_ring @@ -297,7 +298,7 @@ def _unit_gens_primepowercase(p, r): @richcmp_method -class IntegerModRing_generic(quotient_ring.QuotientRing_generic, IntegerModRing): +class IntegerModRing_generic(quotient_ring.QuotientRing_generic, sage.rings.abc.IntegerModRing): """ The ring of integers modulo `N`. From 00de6e6d69b40c7e0c9ad207628854292b237bdb Mon Sep 17 00:00:00 2001 From: dcoudert Date: Fri, 1 Oct 2021 17:25:34 +0200 Subject: [PATCH 197/511] trac #14657: better documentation for set_embedding --- src/sage/graphs/generic_graph.py | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 6a966a01e3f..12f265e0316 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -2470,14 +2470,23 @@ def set_embedding(self, embedding): """ Set a combinatorial embedding dictionary to ``_embedding`` attribute. - Dictionary is organized with vertex labels as keys and a list of each - vertex's neighbors in clockwise order. + The dictionary ``embedding`` represents a combinatorial embedding of + ``self`` and is organized as a mapping from vertex labels to list of + vertex neighbors in clockwise order. - Dictionary is error-checked for validity. + Parameter ``embedding`` is error-checked for validity. + + .. WARNING:: + + Combinatorial embeddings are defined for simple graphs only (i.e., + without loops or multiple edges). Therefore, an error is raised when + this method is used for a graph with loops or multiple edges. INPUT: - - ``embedding`` -- a dictionary + - ``embedding`` -- dictionary representing a combinatorial embedding of + ``self``. Format: "{v1: [v2,v3], v2: [v1], v3: [v1]}" (clockwise + ordering of neighbors at each vertex). EXAMPLES:: @@ -2487,7 +2496,21 @@ def set_embedding(self, embedding): Traceback (most recent call last): ... ValueError: vertices in ['s'] from the embedding do not belong to the graph + + TESTS:: + + sage: G = Graph([(0, 0)], loops=True) + sage: G.set_embedding({0: [0]}) + Traceback (most recent call last): + ... + ValueError: This method is not known to work on graphs with loops. Perhaps this method can be updated to handle them, but in the meantime if you want to use it please disallow loops using allow_loops(). + sage: G = Graph([(0, 1), (0, 1)], multiedges=True) + sage: G.set_embedding({0: [1], 1: [0]}) + Traceback (most recent call last): + ... + ValueError: This method is not known to work on graphs with multiedges. Perhaps this method can be updated to handle them, but in the meantime if you want to use it please disallow multiedges using allow_multiple_edges(). """ + self._scream_if_not_simple() self._check_embedding_validity(embedding, boolean=False) self._embedding = embedding From af06e5b43bd15181de7b1f6123dda5839f248699 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 1 Oct 2021 09:02:22 -0700 Subject: [PATCH 198/511] is_IntegerModRing: Deprecate --- src/sage/rings/finite_rings/integer_mod_ring.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index 27ea7f424fc..28fb2736491 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -244,11 +244,18 @@ def is_IntegerModRing(x): """ Return ``True`` if ``x`` is an integer modulo ring. + This function is deprecated. Use :func:`isinstance` with + :class:`sage.rings.abc.IntegerModRing` instead. + EXAMPLES:: sage: from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing sage: R = IntegerModRing(17) sage: is_IntegerModRing(R) + doctest:warning... + DeprecationWarning: the function is_IntegerModRing is deprecated. + Use isinstance(..., sage.rings.abc.IntegerModRing) instead. + See https://trac.sagemath.org/32606 for details. True sage: is_IntegerModRing(GF(13)) True @@ -259,6 +266,9 @@ def is_IntegerModRing(x): sage: is_IntegerModRing(ZZ) False """ + from sage.misc.superseded import deprecation + deprecation(32606, "the function is_IntegerModRing is deprecated. " + "Use isinstance(..., sage.rings.abc.IntegerModRing) instead.") return isinstance(x, IntegerModRing_generic) From 1a845fa1d975fa76396b3c48c2441b41b043c829 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 1 Oct 2021 09:04:59 -0700 Subject: [PATCH 199/511] src/sage/geometry/polyhedron/parent.py: Add missing import --- src/sage/geometry/polyhedron/parent.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 002c93e9dfb..0091b5e12fb 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -14,6 +14,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.modules.free_module import FreeModule, is_FreeModule from sage.misc.cachefunc import cached_method, cached_function +from sage.misc.lazy_import import lazy_import from sage.rings.all import ZZ, QQ, RDF, CommutativeRing from sage.categories.fields import Fields from sage.categories.rings import Rings From 015b89911e606112327f57949e3bce7af1a0595b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 1 Oct 2021 10:23:51 -0700 Subject: [PATCH 200/511] build/bin/sage-print-system-package-command: Handle cpan --- build/bin/sage-print-system-package-command | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/bin/sage-print-system-package-command b/build/bin/sage-print-system-package-command index 618c88174e0..6be76bdaf5f 100755 --- a/build/bin/sage-print-system-package-command +++ b/build/bin/sage-print-system-package-command @@ -149,6 +149,9 @@ case $system:$command in pip:install) [ -n "$system_packages" ] && print_shell_command "sage -pip install $system_packages" ;; + cpan:install) + [ -n "$system_packages" ] && print_shell_command "cpan -i $system_packages" + ;; repology:install) if [ -n "$system_packages" ]; then links="" From fc0e37c7e30db6bc11f6c88f2941ac1529549908 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Fri, 1 Oct 2021 10:31:59 -0700 Subject: [PATCH 201/511] fix symengine_py tests --- build/pkgs/symengine_py/spkg-check.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build/pkgs/symengine_py/spkg-check.in b/build/pkgs/symengine_py/spkg-check.in index ac32958383b..5ead50de889 100644 --- a/build/pkgs/symengine_py/spkg-check.in +++ b/build/pkgs/symengine_py/spkg-check.in @@ -1,3 +1,7 @@ cd src -python3 -m pytest -s -v symengine/tests/test_*.py +# since the module is not built in place, go to a new directory +mkdir empty +cd empty + +python3 ../bin/test_python.py From 27a265c12b0df142f0b08a5875ea81482d80a361 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 1 Oct 2021 12:07:52 -0700 Subject: [PATCH 202/511] src/sage/geometry/polyhedron/parent.py: Fixup --- src/sage/geometry/polyhedron/parent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 0091b5e12fb..7228c64b3ea 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -1129,7 +1129,7 @@ def _make_Line(self, polyhedron, data): from sage.geometry.polyhedron.backend_cdd import Polyhedron_QQ_cdd -lazy_import('sage.geometry.polyhedron.backend_cdd_rdf', Polyhedron_RDF_cdd) +lazy_import('sage.geometry.polyhedron.backend_cdd_rdf', 'Polyhedron_RDF_cdd') from sage.geometry.polyhedron.backend_ppl import Polyhedron_ZZ_ppl, Polyhedron_QQ_ppl from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz, Polyhedron_ZZ_normaliz, Polyhedron_QQ_normaliz from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake From 73aabd22000d7703710df29ad89434d790d4e6b6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 1 Oct 2021 17:52:30 -0700 Subject: [PATCH 203/511] src/sage/sets/condition_set.py: Fix up import --- src/sage/sets/condition_set.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/sets/condition_set.py b/src/sage/sets/condition_set.py index b9373e65fad..c779ed9b356 100644 --- a/src/sage/sets/condition_set.py +++ b/src/sage/sets/condition_set.py @@ -295,6 +295,7 @@ def arguments(self): sage: args[0].parent() Symbolic Ring """ + from sage.symbolic.ring import SR return SR.var(self.variable_names()) def _element_constructor_(self, *args, **kwds): From 6633bc4ddd66e982fc3484f399cf62e50e36fd61 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Thu, 30 Sep 2021 23:32:44 +0800 Subject: [PATCH 204/511] use GSL macros for compatibility with gsl 2.7 --- src/sage/libs/gsl/complex.pxd | 6 +- src/sage/libs/gsl/types.pxd | 4 +- src/sage/plot/complex_plot.pyx | 7 +- src/sage/rings/complex_double.pyx | 71 ++++++++++--------- src/sage/rings/complex_mpfr.pyx | 6 +- src/sage/rings/convert/mpfi.pyx | 7 +- src/sage/symbolic/pynac_impl.pxi | 4 +- .../autogen/interpreters/specs/cdf.py | 6 +- 8 files changed, 58 insertions(+), 53 deletions(-) diff --git a/src/sage/libs/gsl/complex.pxd b/src/sage/libs/gsl/complex.pxd index d0e6f9f33a2..b6e0a16fbb1 100644 --- a/src/sage/libs/gsl/complex.pxd +++ b/src/sage/libs/gsl/complex.pxd @@ -10,11 +10,11 @@ cdef extern from "gsl/gsl_complex.h": int GSL_COMPLEX_EQ(gsl_complex z1,gsl_complex z2) - double GSL_SET_COMPLEX(gsl_complex * zp, double x, double y) + void GSL_SET_COMPLEX(gsl_complex * zp, double x, double y) - double GSL_SET_REAL(gsl_complex * zp, double x) + void GSL_SET_REAL(gsl_complex * zp, double x) - double GSL_SET_IMAG(gsl_complex * zp, double y) + void GSL_SET_IMAG(gsl_complex * zp, double y) cdef extern from "gsl/gsl_complex_math.h": diff --git a/src/sage/libs/gsl/types.pxd b/src/sage/libs/gsl/types.pxd index 04b9e17a501..217738be893 100644 --- a/src/sage/libs/gsl/types.pxd +++ b/src/sage/libs/gsl/types.pxd @@ -43,9 +43,7 @@ cdef extern from "gsl/gsl_complex.h": ctypedef double * gsl_complex_packed_ptr ctypedef struct gsl_complex: - double dat[2] - double real "dat[0]" - double imag "dat[1]" + pass cdef extern from "gsl/gsl_block_double.h": diff --git a/src/sage/plot/complex_plot.pyx b/src/sage/plot/complex_plot.pyx index d688b6e4996..acebaa95d62 100644 --- a/src/sage/plot/complex_plot.pyx +++ b/src/sage/plot/complex_plot.pyx @@ -29,11 +29,11 @@ from sage.arith.srange import srange from libc.math cimport hypot, atan2, atan, log, sqrt from sage.arith.constants cimport M_PI as PI +from sage.libs.gsl.complex cimport * cdef inline ComplexDoubleElement new_CDF_element(double x, double y): z = ComplexDoubleElement.__new__(ComplexDoubleElement) - z._complex.real = x - z._complex.imag = y + GSL_SET_COMPLEX(&z._complex, x, y) return z @@ -113,7 +113,8 @@ def complex_to_rgb(z_values): z = zz else: z = CDF(zz) - x, y = z._complex.dat + x = GSL_REAL(z._complex) + y = GSL_IMAG(z._complex) mag = hypot(x, y) arg = atan2(y, x) # math module arctan has range from -pi to pi, so cut along negative x-axis diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 3c47faf4344..432afdd5b1c 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -796,7 +796,7 @@ cdef class ComplexDoubleElement(FieldElement): True """ return (ComplexDoubleElement, - (self._complex.real, self._complex.imag)) + (GSL_REAL(self._complex), GSL_IMAG(self._complex))) cdef ComplexDoubleElement _new_c(self, gsl_complex x): """ @@ -861,13 +861,13 @@ cdef class ComplexDoubleElement(FieldElement): sage: 4.3 > CDF(5,1) False """ - if left._complex.real < (right)._complex.real: + if GSL_REAL(left._complex) < GSL_REAL((right)._complex): return rich_to_bool(op, -1) - if left._complex.real > (right)._complex.real: + if GSL_REAL(left._complex) > GSL_REAL((right)._complex): return rich_to_bool(op, 1) - if left._complex.imag < (right)._complex.imag: + if GSL_IMAG(left._complex) < GSL_IMAG((right)._complex): return rich_to_bool(op, -1) - if left._complex.imag > (right)._complex.imag: + if GSL_IMAG(left._complex) > GSL_IMAG((right)._complex): return rich_to_bool(op, 1) return rich_to_bool(op, 0) @@ -893,8 +893,10 @@ cdef class ComplexDoubleElement(FieldElement): ... IndexError: index n must be 0 or 1 """ - if n >= 0 and n <= 1: - return self._complex.dat[n] + if n == 0: + return GSL_REAL(self._complex) + if n == 1: + return GSL_IMAG(self._complex) raise IndexError("index n must be 0 or 1") def _magma_init_(self, magma): @@ -968,9 +970,9 @@ cdef class ComplexDoubleElement(FieldElement): sage: float(abs(CDF(1,1))) 1.4142135623730951 """ - if self._complex.imag: + if GSL_IMAG(self._complex): raise TypeError(f"unable to convert {self} to float; use abs() or real_part() as desired") - return self._complex.real + return GSL_REAL(self._complex) def __complex__(self): """ @@ -984,7 +986,7 @@ cdef class ComplexDoubleElement(FieldElement): sage: complex(CDF(a)) (2303-3939j) """ - return complex(self._complex.real, self._complex.imag) + return complex(GSL_REAL(self._complex), GSL_IMAG(self._complex)) def _interface_init_(self, I=None): """ @@ -1042,7 +1044,8 @@ cdef class ComplexDoubleElement(FieldElement): sage: type(_) """ - x, y = self._complex.dat + x = GSL_REAL(self._complex) + y = GSL_IMAG(self._complex) import sympy return sympy.Float(x) + sympy.Float(y) * sympy.I @@ -1075,7 +1078,8 @@ cdef class ComplexDoubleElement(FieldElement): sage: CDF(0) 0.0 """ - x, y = self._complex.dat + x = GSL_REAL(self._complex) + y = GSL_IMAG(self._complex) if x == 0: if y == 0: # Not sure what to do with the signs of the real and @@ -1126,8 +1130,8 @@ cdef class ComplexDoubleElement(FieldElement): sage: format(CDF(0, 0), '+#.4') '+0.000' """ - return complex_mpfr._format_complex_number(self._complex.real, - self._complex.imag, + return complex_mpfr._format_complex_number(GSL_REAL(self._complex), + GSL_IMAG(self._complex), format_spec) def _latex_(self): @@ -1161,10 +1165,10 @@ cdef class ComplexDoubleElement(FieldElement): sage: pari(CDF(I)) 1.00000000000000*I """ - if not self._complex.imag: - return new_gen_from_double(self._complex.real) + if not GSL_IMAG(self._complex): + return new_gen_from_double(GSL_REAL(self._complex)) else: - return new_t_COMPLEX_from_double(self._complex.real, self._complex.imag) + return new_t_COMPLEX_from_double(GSL_REAL(self._complex), GSL_IMAG(self._complex)) def __mpc__(self): """ @@ -1179,7 +1183,7 @@ cdef class ComplexDoubleElement(FieldElement): sage: mpc(c) mpc('2.0+1.0j') """ - return gmpy2.mpc(self._complex.dat[0], self._complex.dat[1]) + return gmpy2.mpc(GSL_REAL(self._complex), GSL_IMAG(self._complex)) ####################################################################### # Arithmetic @@ -1461,7 +1465,7 @@ cdef class ComplexDoubleElement(FieldElement): sage: a.real_part() 3.0 """ - return RealDoubleElement(self._complex.real) + return RealDoubleElement(GSL_REAL(self._complex)) real_part = real @@ -1477,7 +1481,7 @@ cdef class ComplexDoubleElement(FieldElement): sage: a.imag_part() -2.0 """ - return RealDoubleElement(self._complex.imag) + return RealDoubleElement(GSL_IMAG(self._complex)) imag_part = imag @@ -1718,9 +1722,9 @@ cdef class ComplexDoubleElement(FieldElement): res = gsl_complex_rect(1, 0) elif other == -1: res = gsl_complex_inverse(self._complex) - elif not self._complex.imag: + elif not GSL_IMAG(self._complex): # If self is real, the result should be real too - real = self._complex.real ** other + real = GSL_REAL(self._complex) ** other res = gsl_complex_rect(real, 0) else: # General case @@ -1728,9 +1732,9 @@ cdef class ComplexDoubleElement(FieldElement): return self._new_c(res) cpdef _pow_int(self, other): - if not self._complex.imag: + if not GSL_IMAG(self._complex): # If self is real, the result should be real too - real = self._complex.real ** other + real = GSL_REAL(self._complex) ** other res = gsl_complex_rect(real, 0) else: # General case @@ -2257,10 +2261,10 @@ cdef class ComplexDoubleElement(FieldElement): """ cdef GEN a, b, c, y, t - if self._complex.imag <= 0: + if GSL_IMAG(self._complex) <= 0: raise ValueError("value must be in the upper half plane") - if self._complex.imag > 100000 and not omit_frac: + if GSL_IMAG(self._complex) > 100000 and not omit_frac: # To the precision of doubles for such large imaginary # part, the answer is automatically 0. If we don't do # this, PARI can easily underflow. @@ -2400,13 +2404,13 @@ cdef class ComplexDoubleElement(FieldElement): sage: CDF(-1,0).gamma() Infinity """ - if not self._complex.imag: - if self._complex.real == 0: + if not GSL_IMAG(self._complex): + if GSL_REAL(self._complex) == 0: from .infinity import unsigned_infinity return unsigned_infinity try: from sage.rings.all import Integer, CC - if Integer(self._complex.real) < 0: + if Integer(GSL_REAL(self._complex)) < 0: return CC(self).gamma() except TypeError: pass @@ -2441,7 +2445,7 @@ cdef class ComplexDoubleElement(FieldElement): sage: zeta(CDF(1)) Infinity """ - if self._complex.real == 1 and self._complex.imag == 0: + if GSL_REAL(self._complex) == 1 and GSL_IMAG(self._complex) == 0: from .infinity import unsigned_infinity return unsigned_infinity return pari_to_cdf(self.__pari__().zeta()) @@ -2633,8 +2637,8 @@ cdef inline double complex extract_double_complex(ComplexDoubleElement x): Return the value of ``x`` as a c99 complex double. """ cdef double complex z - z.real = x._complex.real - z.imag = x._complex.imag + z.real = GSL_REAL(x._complex) + z.imag = GSL_IMAG(x._complex) return z @@ -2644,6 +2648,5 @@ cdef inline ComplexDoubleElement ComplexDoubleElement_from_doubles(double re, do imaginary parts. """ z = ComplexDoubleElement.__new__(ComplexDoubleElement) - z._complex.real = re - z._complex.imag = im + GSL_SET_COMPLEX(&z._complex, re, im) return z diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index d121e29d537..00f1e5effd3 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -52,6 +52,7 @@ from .integer cimport Integer from .complex_double cimport ComplexDoubleElement from .real_mpfr cimport RealNumber +from sage.libs.gsl.complex cimport * from sage.libs.mpmath.utils cimport mpfr_to_mpfval from sage.rings.integer_ring import ZZ @@ -3439,8 +3440,9 @@ cdef class CCtoCDF(Map): 0.7071067811865476 + 0.7071067811865475*I """ z = ComplexDoubleElement.__new__(ComplexDoubleElement) - z._complex.real = mpfr_get_d((x).__re, MPFR_RNDN) - z._complex.imag = mpfr_get_d((x).__im, MPFR_RNDN) + GSL_SET_COMPLEX(&z._complex, + mpfr_get_d((x).__re, MPFR_RNDN), + mpfr_get_d((x).__im, MPFR_RNDN)) return z diff --git a/src/sage/rings/convert/mpfi.pyx b/src/sage/rings/convert/mpfi.pyx index a7d1561ec09..0e5e68c8825 100644 --- a/src/sage/rings/convert/mpfi.pyx +++ b/src/sage/rings/convert/mpfi.pyx @@ -16,6 +16,7 @@ from cpython.complex cimport PyComplex_RealAsDouble, PyComplex_ImagAsDouble from sage.libs.mpfr cimport * from sage.libs.mpfi cimport * +from sage.libs.gsl.complex cimport * from sage.arith.long cimport integer_check_long from sage.cpython.string cimport bytes_to_str @@ -135,11 +136,11 @@ cdef int mpfi_set_sage(mpfi_ptr re, mpfi_ptr im, x, field, int base) except -1: if isinstance(x, ComplexDoubleElement): zd = x if im is NULL: - if zd._complex.imag: + if GSL_IMAG(zd._complex): raise TypeError(f"unable to convert complex number {x!r} to real interval") else: - mpfi_set_d(im, zd._complex.imag) - mpfi_set_d(re, zd._complex.real) + mpfi_set_d(im, GSL_IMAG(zd._complex)) + mpfi_set_d(re, GSL_REAL(zd._complex)) return 0 else: # not a Sage Element # Real diff --git a/src/sage/symbolic/pynac_impl.pxi b/src/sage/symbolic/pynac_impl.pxi index 01a51af2997..f4ddecb577c 100644 --- a/src/sage/symbolic/pynac_impl.pxi +++ b/src/sage/symbolic/pynac_impl.pxi @@ -1734,7 +1734,7 @@ cdef py_log(x): return math.log(real) elif real < 0: res = gsl_complex_log(gsl_complex_rect(real, 0)) - return PyComplex_FromDoubles(res.real, res.imag) + return PyComplex_FromDoubles(GSL_REAL(res), GSL_IMAG(res)) else: return float('-inf') elif type(x) is complex: @@ -1743,7 +1743,7 @@ cdef py_log(x): if real == 0 and imag == 0: return float('-inf') res = gsl_complex_log(gsl_complex_rect(real, imag)) - return PyComplex_FromDoubles(res.real, res.imag) + return PyComplex_FromDoubles(GSL_REAL(res), GSL_IMAG(res)) elif isinstance(x, Integer): return x.log().n() elif hasattr(x, 'log'): diff --git a/src/sage_setup/autogen/interpreters/specs/cdf.py b/src/sage_setup/autogen/interpreters/specs/cdf.py index 1921c807c80..7f09c3b6a5c 100644 --- a/src/sage_setup/autogen/interpreters/specs/cdf.py +++ b/src/sage_setup/autogen/interpreters/specs/cdf.py @@ -157,6 +157,7 @@ def __init__(self): """) self.pyx_header = ri(0, """ + from sage.libs.gsl.complex cimport * from sage.rings.complex_double cimport ComplexDoubleElement import sage.rings.complex_double cdef object CDF = sage.rings.complex_double.CDF @@ -168,12 +169,11 @@ def __init__(self): cdef inline double_complex CDE_to_dz(zz): cdef ComplexDoubleElement z = (zz if isinstance(zz, ComplexDoubleElement) else CDF(zz)) - return z._complex.real + _Complex_I * z._complex.imag + return GSL_REAL(z._complex) + _Complex_I * GSL_IMAG(z._complex) cdef inline ComplexDoubleElement dz_to_CDE(double_complex dz): cdef ComplexDoubleElement z = ComplexDoubleElement.__new__(ComplexDoubleElement) - z._complex.real = creal(dz) - z._complex.imag = cimag(dz) + GSL_SET_COMPLEX(&z._complex, creal(dz), cimag(dz)) return z cdef public bint cdf_py_call_helper(object fn, From 1b2bdbb5c295085f08fe4350ea417f20c8d23d4f Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Fri, 1 Oct 2021 19:30:26 -0700 Subject: [PATCH 205/511] Fix getting string representation of sage objects --- ...tring-representation-of-sage-objects.patch | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 build/pkgs/symengine_py/patches/0001-Fix-getting-string-representation-of-sage-objects.patch diff --git a/build/pkgs/symengine_py/patches/0001-Fix-getting-string-representation-of-sage-objects.patch b/build/pkgs/symengine_py/patches/0001-Fix-getting-string-representation-of-sage-objects.patch new file mode 100644 index 00000000000..78c71610b53 --- /dev/null +++ b/build/pkgs/symengine_py/patches/0001-Fix-getting-string-representation-of-sage-objects.patch @@ -0,0 +1,118 @@ +From 68c90c14ae3e779b88a513195cc89db599d10efb Mon Sep 17 00:00:00 2001 +From: Isuru Fernando +Date: Fri, 1 Oct 2021 19:25:07 -0700 +Subject: [PATCH] Fix getting string representation of sage objects + +--- + symengine/lib/pywrapper.cpp | 17 ++++++----------- + symengine/lib/symengine_wrapper.pyx | 9 ++++++--- + symengine/tests/test_sage.py | 10 +++------- + symengine/tests/test_sympy_conv.py | 1 + + 4 files changed, 16 insertions(+), 21 deletions(-) + +diff --git a/symengine/lib/pywrapper.cpp b/symengine/lib/pywrapper.cpp +index ca7b7c1..c321ea3 100644 +--- a/symengine/lib/pywrapper.cpp ++++ b/symengine/lib/pywrapper.cpp +@@ -175,17 +175,12 @@ RCP PyNumber::eval(long bits) const { + } + + std::string PyNumber::__str__() const { +- PyObject* temp; +- std::string str; +-#if PY_MAJOR_VERSION > 2 +- temp = PyUnicode_AsUTF8String(pyobject_); +- str = std::string(PyBytes_AsString(temp)); +-#else +- temp = PyObject_Str(pyobject_); +- str = std::string(PyString_AsString(temp)); +-#endif +- Py_XDECREF(temp); +- return str; ++ Py_ssize_t size; ++ PyObject *pystr = PyObject_Str(pyobject_); ++ const char* data = PyUnicode_AsUTF8AndSize(pystr, &size); ++ std::string result = std::string(data, size); ++ Py_XDECREF(pystr); ++ return result; + } + + // PyFunctionClass +diff --git a/symengine/lib/symengine_wrapper.pyx b/symengine/lib/symengine_wrapper.pyx +index d178afe..d18c058 100644 +--- a/symengine/lib/symengine_wrapper.pyx ++++ b/symengine/lib/symengine_wrapper.pyx +@@ -2690,7 +2690,7 @@ class FunctionSymbol(Function): + def _sage_(self): + import sage.all as sage + name = self.get_name() +- return sage.function(name, *self.args_as_sage()) ++ return sage.function(name)(*self.args_as_sage()) + + def func(self, *values): + name = self.get_name() +@@ -2711,7 +2711,7 @@ cdef rcp_const_basic pynumber_to_symengine(PyObject* o1): + + cdef PyObject* symengine_to_sage(rcp_const_basic o1): + import sage.all as sage +- t = sage.SR(c2py(o1)._sage_()) ++ t = c2py(o1)._sage_() + Py_XINCREF(t) + return (t) + +@@ -2765,7 +2765,10 @@ cdef class PyNumber(Number): + + def _sage_(self): + import sage.all as sage +- return sage.SR(self.pyobject()) ++ res = self.pyobject() ++ if hasattr(res, '_sage_'): ++ return res._sage_() ++ return res + + def pyobject(self): + return deref(symengine.rcp_static_cast_PyNumber(self.thisptr)).get_py_object() +diff --git a/symengine/tests/test_sage.py b/symengine/tests/test_sage.py +index 3b994ab..e364bd6 100644 +--- a/symengine/tests/test_sage.py ++++ b/symengine/tests/test_sage.py +@@ -66,9 +66,9 @@ def test_sage_conversions(): + assert cos(x1)._sage_() == sage.cos(x) + assert cos(x1) == sympify(sage.cos(x)) + +- assert function_symbol('f', x1, y1)._sage_() == sage.function('f', x, y) ++ assert function_symbol('f', x1, y1)._sage_() == sage.function('f')(x, y) + assert (function_symbol('f', 2 * x1, x1 + y1).diff(x1)._sage_() == +- sage.function('f', 2 * x, x + y).diff(x)) ++ sage.function('f')(2 * x, x + y).diff(x)) + + assert LambertW(x1) == LambertW(x) + assert LambertW(x1)._sage_() == sage.lambert_w(x) +@@ -142,11 +142,7 @@ def test_sage_conversions(): + b = b + 8 + assert isinstance(b, PyNumber) + assert b._sage_() == a +- +- a = a + x +- b = b + x +- assert isinstance(b, Add) +- assert b._sage_() == a ++ assert str(a) == str(b) + + # Sage Function + e = x1 + wrap_sage_function(sage.log_gamma(x)) +diff --git a/symengine/tests/test_sympy_conv.py b/symengine/tests/test_sympy_conv.py +index 3f8b152..ee070a8 100644 +--- a/symengine/tests/test_sympy_conv.py ++++ b/symengine/tests/test_sympy_conv.py +@@ -760,6 +760,7 @@ def test_pynumber(): + assert isinstance(b, PyNumber) + assert b == a # Check equality via SymEngine + assert a == b # Check equality via SymPy ++ assert str(a) == str(b) + + a = 1 - a + b = 1 - b +-- +2.7.4 + From 6dd3e5bc36d46fb8482163dde0f7dec1c9fefa6c Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Sat, 2 Oct 2021 06:52:11 -0700 Subject: [PATCH 206/511] update version for a rebuild --- build/pkgs/symengine_py/package-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/symengine_py/package-version.txt b/build/pkgs/symengine_py/package-version.txt index 6f4eebdf6f6..25329dc9cba 100644 --- a/build/pkgs/symengine_py/package-version.txt +++ b/build/pkgs/symengine_py/package-version.txt @@ -1 +1 @@ -0.8.1 +0.8.1.p0 From a16530020d7b48e53616880f4987139d1fac749c Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sat, 2 Oct 2021 23:33:26 +0900 Subject: [PATCH 207/511] Speed up ideal multiplication --- src/sage/rings/function_field/ideal.py | 122 ++++++++++++++++++++----- 1 file changed, 99 insertions(+), 23 deletions(-) diff --git a/src/sage/rings/function_field/ideal.py b/src/sage/rings/function_field/ideal.py index 4230b3780a0..3dbadab335c 100644 --- a/src/sage/rings/function_field/ideal.py +++ b/src/sage/rings/function_field/ideal.py @@ -99,6 +99,8 @@ from sage.structure.factorization import Factorization from sage.structure.unique_representation import UniqueRepresentation +from sage.arith.power import generic_power + from sage.modules.free_module_element import vector from sage.categories.monoids import Monoids @@ -1228,6 +1230,12 @@ def __init__(self, ring, hnf, denominator=1): # for fast multiplication with other ideal. self._kummer_form = None + # tuple of at most two gens: + # the first gen is an element of the base ring of the maximal order + # the second gen is the vector form of an element of the maximal order + # if the second gen is zero, the tuple has only the first gen. + self._gens_two_vecs = None + def __bool__(self): """ Test if this ideal is zero. @@ -1514,6 +1522,20 @@ def _mul_(self, other): elif other._kummer_form is not None: p, q = other._kummer_form vecs = list(p * self._hnf) + [mul(q, v) for v in self._hnf] + elif self._gens_two_vecs is not None: + if len(self._gens_two_vecs) == 1: + g1, = self._gens_two_vecs + vecs = list(g1 * other._hnf) + else: + g1, g2 = self._gens_two_vecs + vecs = list(g1 * other._hnf) + [mul(g2, v) for v in other._hnf] + elif other._gens_two_vecs is not None: + if len(other._gens_two_vecs) == 1: + g1, = other._gens_two_vecs + vecs = list(g1 * self._hnf) + else: + g1, g2 = other._gens_two_vecs + vecs = list(g1 * self._hnf) + [mul(g2, v) for v in self._hnf] else: vecs = [mul(r1,r2) for r1 in self._hnf for r2 in other._hnf] @@ -2138,6 +2160,53 @@ def __init__(self, ring, hnf, denominator=1): """ FunctionFieldIdeal_polymod.__init__(self, ring, hnf, denominator) + def __pow__(self, mod): + """ + Return ``self`` to the power of ``mod``. + + If a two-generators representation of ``self`` is known, it is used + to speed up powering. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^7 - x^3*Y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: J = O.ideal(x + y) + sage: S = I / J + sage: S^100 == I^100 / J^100 + True + sage: _ = S.gens_two() + sage: S^100 == I^100 / J^100 # faster + True + """ + if mod > 2 and self._gens_two_vecs is not None: + O = self._ring + mul = O._mul_vecs + R = self._hnf.base_ring() + n = self._hnf.ncols() + + I = matrix.identity(R, n) + + if len(self._gens_two_vecs) == 1: + p, = self._gens_two_vecs + ppow = p**mod + J = [ppow * v for v in I] + else: + p, q = self._gens_two_vecs + if len(self._gens_two.cache) == 2: + _, q = self._gens_two.cache + else: + q = sum(e1 * e2 for e1,e2 in zip(O.basis(), q)) + ppow = p**mod + qpow = O._coordinate_vector(q**mod) + J = [ppow * v for v in I] + [mul(qpow,v) for v in I] + + return O._ideal_from_vectors_and_denominator(J, self._denominator**mod) + + return generic_power(self, mod) + def gens(self): """ Return a set of generators of this ideal. @@ -2171,26 +2240,6 @@ def gens_two(self): If the ideal is principal, one generator *may* be returned. - ALGORITHM: - - At most two generators are required to generate ideals in - Dedekind domains. - - Lemma 4.7.9, algorithm 4.7.10, and exercise 4.29 of [Coh1993]_ - tell us that for an integral ideal `I` in a number field, if - we pick `a` such that `\gcd(N(I), N(a)/N(I)) = 1`, then `a` - and `N(I)` generate the ideal. `N()` is the norm, and this - result (presumably) generalizes to function fields. - - After computing `N(I)`, we search exhaustively to find `a`. - - .. TODO:: - - Always return a single generator for a principal ideal. - - Testing for principality is not trivial. Algorithm 6.5.10 - of [Coh1993]_ could probably be adapted for function fields. - EXAMPLES:: sage: K. = FunctionField(GF(2)); _. = K[] @@ -2224,6 +2273,26 @@ def _gens_two(self): Return a set of two generators of the integral ideal, that is the denominator times this fractional ideal. + ALGORITHM: + + At most two generators are required to generate ideals in + Dedekind domains. + + Lemma 4.7.9, algorithm 4.7.10, and exercise 4.29 of [Coh1993]_ + tell us that for an integral ideal `I` in a number field, if + we pick `a` such that `\gcd(N(I), N(a)/N(I)) = 1`, then `a` + and `N(I)` generate the ideal. `N()` is the norm, and this + result (presumably) generalizes to function fields. + + After computing `N(I)`, we search exhaustively to find `a`. + + .. TODO:: + + Always return a single generator for a principal ideal. + + Testing for principality is not trivial. Algorithm 6.5.10 + of [Coh1993]_ could probably be adapted for function fields. + EXAMPLES:: sage: K. = FunctionField(GF(4)); _. = K[] @@ -2247,8 +2316,10 @@ def _gens_two(self): g1 = F(_g1) g2 = sum([c1*c2 for c1,c2 in zip(_g2, O.basis())]) if g2: + self._gens_two_vecs = (_g1, _g2) return (g1,g2) else: + self._gens_two_vecs = (_g1,) return (g1,) ### start to search for two generators @@ -2260,14 +2331,16 @@ def _gens_two(self): norm *= e if norm.is_constant(): # unit ideal + self._gens_two_vecs = (1,) return (F(1),) # one generator; see .ideal_below() - l = hnf[0][0] - p = l.degree() - l = F(l) + _l = hnf[0][0] + p = _l.degree() + l = F(_l) if self._hnf == O.ideal(l)._hnf: # principal ideal + self._gens_two_vecs = (_l,) return (l,) R = hnf.base_ring() @@ -2286,6 +2359,7 @@ def check(alpha): # Trial 1: search for alpha among generators for alpha in basis: if check(alpha): + self._gens_two_vecs = (_l, O._coordinate_vector(alpha)) return (l, alpha) # Trial 2: exhaustive search for alpha using only polynomials @@ -2295,6 +2369,7 @@ def check(alpha): for g in G: alpha = sum([R(c1)*c2 for c1,c2 in zip(g, basis)]) if check(alpha): + self._gens_two_vecs = (_l, O._coordinate_vector(alpha)) return (l, alpha) # Trial 3: exhaustive search for alpha using all polynomials @@ -2312,6 +2387,7 @@ def check(alpha): alpha = sum([c1*c2 for c1,c2 in zip(g, basis)]) if check(alpha): + self._gens_two_vecs = (_l, O._coordinate_vector(alpha)) return (l, alpha) # should not reach here From 608148900e8764bb654ddcdcdb15a1e890acba94 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 10:17:24 -0700 Subject: [PATCH 208/511] git grep -l -E 'is_(Real|Complex)(Double)?Field' | xargs sed -E -i.bak 's/^from sage[.]rings.*import is_((Real|Complex)(Double)?Field) *$/import sage.rings.abc/;s/is_((Real|Complex)(Double)?Field)[(]([^)]*)[)]/isinstance(\4, sage.rings.abc.\1)/g;' --- .../arithmetic_dynamics/projective_ds.py | 2 +- src/sage/functions/orthogonal_polys.py | 12 +++--- src/sage/functions/special.py | 2 +- src/sage/matrix/misc.pyx | 2 +- src/sage/modular/dirichlet.py | 12 +++--- src/sage/modules/free_module.py | 4 +- src/sage/probability/random_variable.py | 2 +- src/sage/quadratic_forms/special_values.py | 4 +- src/sage/rings/complex_double.pyx | 6 +-- src/sage/rings/complex_mpfr.pyx | 4 +- src/sage/rings/number_field/number_field.py | 6 +-- .../number_field/number_field_element.pyx | 2 +- .../multi_polynomial_libsingular.pyx | 8 ++-- .../rings/polynomial/polynomial_element.pyx | 40 +++++++++---------- src/sage/rings/polynomial/polynomial_ring.py | 4 +- .../polynomial_singular_interface.py | 24 +++++------ src/sage/rings/real_double.pyx | 6 +-- src/sage/rings/real_mpfr.pyx | 6 +-- src/sage/schemes/elliptic_curves/ell_field.py | 8 ++-- .../elliptic_curves/ell_number_field.py | 2 +- src/sage/schemes/elliptic_curves/ell_point.py | 8 ++-- .../schemes/elliptic_curves/period_lattice.py | 14 +++---- src/sage/schemes/plane_conics/con_field.py | 8 ++-- .../plane_conics/con_rational_field.py | 6 +-- src/sage/symbolic/expression.pyx | 6 +-- 25 files changed, 99 insertions(+), 99 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 164c4c35f47..e5f2b9225cf 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2065,7 +2065,7 @@ def canonical_height(self, P, **kwds): # it uses Real or Complex Double Field in place of RealField(prec) or ComplexField(prec) # the function is_RealField does not identify RDF as real, so we test for that ourselves. for v in emb: - if is_RealField(v.codomain()) or v.codomain() is RDF: + if isinstance(v.codomain(, sage.rings.abc.RealField)) or v.codomain() is RDF: dv = R.one() else: dv = R(2) diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 9b5636f3fdc..c879cd6c8fe 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -304,8 +304,8 @@ from sage.misc.latex import latex from sage.rings.all import ZZ, QQ, RR, CC from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.real_mpfr import is_RealField -from sage.rings.complex_mpfr import is_ComplexField +import sage.rings.abc +import sage.rings.abc from sage.symbolic.function import BuiltinFunction, GinacFunction from sage.symbolic.expression import Expression @@ -672,7 +672,7 @@ def _evalf_(self, n, x, **kwds): except KeyError: real_parent = parent(x) - if not is_RealField(real_parent) and not is_ComplexField(real_parent): + if not isinstance(real_parent, sage.rings.abc.RealField) and not isinstance(real_parent, sage.rings.abc.ComplexField): # parent is not a real or complex field: figure out a good parent if x in RR: x = RR(x) @@ -681,7 +681,7 @@ def _evalf_(self, n, x, **kwds): x = CC(x) real_parent = CC - if not is_RealField(real_parent) and not is_ComplexField(real_parent): + if not isinstance(real_parent, sage.rings.abc.RealField) and not isinstance(real_parent, sage.rings.abc.ComplexField): raise TypeError("cannot evaluate chebyshev_T with parent {}".format(real_parent)) from sage.libs.mpmath.all import call as mpcall @@ -1031,7 +1031,7 @@ def _evalf_(self, n, x, **kwds): except KeyError: real_parent = parent(x) - if not is_RealField(real_parent) and not is_ComplexField(real_parent): + if not isinstance(real_parent, sage.rings.abc.RealField) and not isinstance(real_parent, sage.rings.abc.ComplexField): # parent is not a real or complex field: figure out a good parent if x in RR: x = RR(x) @@ -1040,7 +1040,7 @@ def _evalf_(self, n, x, **kwds): x = CC(x) real_parent = CC - if not is_RealField(real_parent) and not is_ComplexField(real_parent): + if not isinstance(real_parent, sage.rings.abc.RealField) and not isinstance(real_parent, sage.rings.abc.ComplexField): raise TypeError("cannot evaluate chebyshev_U with parent {}".format(real_parent)) from sage.libs.mpmath.all import call as mpcall diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index d48208a21d0..c409631f392 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -365,7 +365,7 @@ def elliptic_j(z, prec=53): CC = z.parent() from sage.rings.complex_mpfr import is_ComplexField - if not is_ComplexField(CC): + if not isinstance(CC, sage.rings.abc.ComplexField): CC = ComplexField(prec) try: z = CC(z) diff --git a/src/sage/matrix/misc.pyx b/src/sage/matrix/misc.pyx index 9008edf5920..a70a9a0f711 100644 --- a/src/sage/matrix/misc.pyx +++ b/src/sage/matrix/misc.pyx @@ -510,7 +510,7 @@ def hadamard_row_bound_mpfr(Matrix A): ... OverflowError: cannot convert float infinity to integer """ - if not is_RealField(A.base_ring()): + if not isinstance(A.base_ring(, sage.rings.abc.RealField)): raise TypeError("A must have base field an mpfr real field.") cdef RealNumber a, b diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 53492ad517f..f71ef1e6f17 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -68,7 +68,7 @@ from sage.categories.map import Map from sage.rings.rational_field import is_RationalField -from sage.rings.complex_mpfr import is_ComplexField +import sage.rings.abc from sage.rings.qqbar import is_AlgebraicField from sage.rings.ring import is_Ring @@ -1153,7 +1153,7 @@ def _pari_init_(self): # now compute the input for pari (list of exponents) P = self.parent() - if is_ComplexField(P.base_ring()): + if isinstance(P.base_ring(, sage.rings.abc.ComplexField)): zeta = P.zeta() zeta_argument = zeta.argument() v = [int(x.argument() / zeta_argument) for x in values_on_gens] @@ -1345,7 +1345,7 @@ def gauss_sum(self, a=1): K = G.base_ring() chi = self m = G.modulus() - if is_ComplexField(K): + if isinstance(K, sage.rings.abc.ComplexField): return self.gauss_sum_numerical(a=a) elif is_AlgebraicField(K): L = K @@ -1422,7 +1422,7 @@ def gauss_sum_numerical(self, prec=53, a=1): """ G = self.parent() K = G.base_ring() - if is_ComplexField(K): + if isinstance(K, sage.rings.abc.ComplexField): def phi(t): return t @@ -2138,7 +2138,7 @@ def element(self): """ P = self.parent() M = P._module - if is_ComplexField(P.base_ring()): + if isinstance(P.base_ring(, sage.rings.abc.ComplexField)): zeta = P.zeta() zeta_argument = zeta.argument() v = M([int(round(x.argument() / zeta_argument)) @@ -2607,7 +2607,7 @@ def _zeta_powers(self): w = [a] zeta = self.zeta() zeta_order = self.zeta_order() - if is_ComplexField(R): + if isinstance(R, sage.rings.abc.ComplexField): for i in range(1, zeta_order): a = a * zeta a._set_multiplicative_order(zeta_order / gcd(zeta_order, i)) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 57c10114174..6288e77cf76 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -7443,9 +7443,9 @@ def element_class(R, is_sparse): return Vector_modn_dense else: return free_module_element.FreeModuleElement_generic_dense - elif sage.rings.real_double.is_RealDoubleField(R) and not is_sparse: + elif sage.rings.real_double.isinstance(R, sage.rings.abc.RealDoubleField) and not is_sparse: return sage.modules.vector_real_double_dense.Vector_real_double_dense - elif sage.rings.complex_double.is_ComplexDoubleField(R) and not is_sparse: + elif sage.rings.complex_double.isinstance(R, sage.rings.abc.ComplexDoubleField) and not is_sparse: return sage.modules.vector_complex_double_dense.Vector_complex_double_dense elif sage.symbolic.ring.is_SymbolicExpressionRing(R) and not is_sparse: import sage.modules.vector_symbolic_dense diff --git a/src/sage/probability/random_variable.py b/src/sage/probability/random_variable.py index 5355636aa56..ea2c4c86b2f 100644 --- a/src/sage/probability/random_variable.py +++ b/src/sage/probability/random_variable.py @@ -338,7 +338,7 @@ def __init__(self, X, P, codomain=None, check=False): """ if codomain is None: codomain = RealField() - if not is_RealField(codomain) and not is_RationalField(codomain): + if not isinstance(codomain, sage.rings.abc.RealField) and not is_RationalField(codomain): raise TypeError("Argument codomain (= %s) must be the reals or rationals" % codomain) if check: one = sum(P.values()) diff --git a/src/sage/quadratic_forms/special_values.py b/src/sage/quadratic_forms/special_values.py index 47f8ec3008f..5c7e3a1ccfe 100644 --- a/src/sage/quadratic_forms/special_values.py +++ b/src/sage/quadratic_forms/special_values.py @@ -15,7 +15,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ -from sage.rings.real_mpfr import is_RealField +import sage.rings.abc from sage.symbolic.constants import pi, I # ---------------- The Gamma Function ------------------ @@ -278,7 +278,7 @@ def quadratic_L_function__numerical(n, d, num_terms=1000): ....: print("Oops! We have a problem at d = {}: exact = {}, numerical = {}".format(d, RR(quadratic_L_function__exact(1, d)), RR(quadratic_L_function__numerical(1, d)))) """ # Set the correct precision if it is given (for n). - if is_RealField(n.parent()): + if isinstance(n.parent(, sage.rings.abc.RealField)): R = n.parent() else: R = RealField() diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 3c47faf4344..7621cc043c2 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -111,16 +111,16 @@ from sage.structure.richcmp cimport rich_to_bool cimport gmpy2 gmpy2.import_gmpy2() -def is_ComplexDoubleField(x): +def isinstance(x, sage.rings.abc.ComplexDoubleField): """ Return ``True`` if ``x`` is the complex double field. EXAMPLES:: sage: from sage.rings.complex_double import is_ComplexDoubleField - sage: is_ComplexDoubleField(CDF) + sage: isinstance(CDF, sage.rings.abc.ComplexDoubleField) True - sage: is_ComplexDoubleField(ComplexField(53)) + sage: isinstance(ComplexField(53, sage.rings.abc.ComplexDoubleField)) False """ return isinstance(x, ComplexDoubleField_class) diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index d121e29d537..d3d32b69de5 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -157,7 +157,7 @@ def is_ComplexNumber(x): """ return isinstance(x, ComplexNumber) -def is_ComplexField(x): +def isinstance(x, sage.rings.abc.ComplexField): """ Check if ``x`` is a :class:`complex field `. @@ -543,7 +543,7 @@ class ComplexField_class(ring.Field): RR = self._real_field() if RR.has_coerce_map_from(S): return RRtoCC(RR, self) * RR._internal_coerce_map_from(S) - if is_ComplexField(S): + if isinstance(S, sage.rings.abc.ComplexField): if self._prec <= S._prec: return self._generic_coerce_map(S) else: diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 3ad7ffa26ef..bc626635105 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -9949,12 +9949,12 @@ def hilbert_symbol(self, a, b, P = None): from sage.rings.complex_interval_field import is_ComplexIntervalField from sage.rings.real_mpfr import is_RealField from sage.rings.all import (AA, CDF, QQbar, RDF) - if is_ComplexField(codom) or is_ComplexIntervalField(codom) or \ + if isinstance(codom, sage.rings.abc.ComplexField) or is_ComplexIntervalField(codom) or \ codom is CDF or codom is QQbar: if P(self.gen()).imag() == 0: raise ValueError("Possibly real place (=%s) given as complex embedding in hilbert_symbol. Is it real or complex?" % P) return 1 - if is_RealField(codom) or codom is RDF or codom is AA: + if isinstance(codom, sage.rings.abc.RealField) or codom is RDF or codom is AA: if P(a) > 0 or P(b) > 0: return 1 return -1 @@ -12317,7 +12317,7 @@ def refine_embedding(e, prec=None): return e # We first compute all the embeddings at the new precision: - if sage.rings.real_mpfr.is_RealField(RC) or RC in (RDF, RLF): + if sage.rings.real_mpfr.isinstance(RC, sage.rings.abc.RealField) or RC in (RDF, RLF): if prec == Infinity: elist = K.embeddings(sage.rings.qqbar.AA) else: diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 37af865e4f5..4ee3d048f07 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -3946,7 +3946,7 @@ cdef class NumberFieldElement(FieldElement): return Kv.zero() ht = a.log() from sage.rings.real_mpfr import is_RealField - if weighted and not is_RealField(Kv): + if weighted and not isinstance(Kv, sage.rings.abc.RealField): ht*=2 return ht diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index ec706f3129d..f32e42d83f3 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -224,8 +224,8 @@ from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn from sage.rings.rational cimport Rational from sage.rings.rational_field import QQ -from sage.rings.complex_mpfr import is_ComplexField -from sage.rings.real_mpfr import is_RealField +import sage.rings.abc +import sage.rings.abc from sage.rings.integer_ring import is_IntegerRing, ZZ from sage.rings.integer cimport Integer from sage.rings.integer import GCD_list @@ -1366,14 +1366,14 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): base_ring = self.base_ring() - if is_RealField(base_ring): + if isinstance(base_ring, sage.rings.abc.RealField): # singular converts to bits from base_10 in mpr_complex.cc by: # size_t bits = 1 + (size_t) ((float)digits * 3.5); precision = base_ring.precision() digits = ceil((2*precision - 2)/7.0) self.__singular = singular.ring("(real,%d,0)"%digits, _vars, order=order) - elif is_ComplexField(base_ring): + elif isinstance(base_ring, sage.rings.abc.ComplexField): # singular converts to bits from base_10 in mpr_complex.cc by: # size_t bits = 1 + (size_t) ((float)digits * 3.5); precision = base_ring.precision() diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index dabc030c828..70f026179a4 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -7912,25 +7912,25 @@ cdef class Polynomial(CommutativeAlgebraElement): late_import() - input_fp = (is_RealField(K) - or is_ComplexField(K) - or is_RealDoubleField(K) - or is_ComplexDoubleField(K)) - output_fp = (is_RealField(L) - or is_ComplexField(L) - or is_RealDoubleField(L) - or is_ComplexDoubleField(L)) - input_complex = (is_ComplexField(K) - or is_ComplexDoubleField(K)) - output_complex = (is_ComplexField(L) - or is_ComplexDoubleField(L)) + input_fp = (isinstance(K, sage.rings.abc.RealField) + or isinstance(K, sage.rings.abc.ComplexField) + or isinstance(K, sage.rings.abc.RealDoubleField) + or isinstance(K, sage.rings.abc.ComplexDoubleField)) + output_fp = (isinstance(L, sage.rings.abc.RealField) + or isinstance(L, sage.rings.abc.ComplexField) + or isinstance(L, sage.rings.abc.RealDoubleField) + or isinstance(L, sage.rings.abc.ComplexDoubleField)) + input_complex = (isinstance(K, sage.rings.abc.ComplexField) + or isinstance(K, sage.rings.abc.ComplexDoubleField)) + output_complex = (isinstance(L, sage.rings.abc.ComplexField) + or isinstance(L, sage.rings.abc.ComplexDoubleField)) input_gaussian = (isinstance(K, NumberField_quadratic) and list(K.polynomial()) == [1, 0, 1]) if input_fp and output_fp: # allow for possibly using a fast but less reliable # floating point algorithm from numpy - low_prec = is_RealDoubleField(K) or is_ComplexDoubleField(K) + low_prec = isinstance(K, sage.rings.abc.RealDoubleField) or isinstance(K, sage.rings.abc.ComplexDoubleField) if algorithm is None: if low_prec: algorithm = 'either' @@ -7943,8 +7943,8 @@ cdef class Polynomial(CommutativeAlgebraElement): # We should support GSL, too. We could also support PARI's # old Newton-iteration algorithm. - input_arbprec = (is_RealField(K) or - is_ComplexField(K)) + input_arbprec = (isinstance(K, sage.rings.abc.RealField) or + isinstance(K, sage.rings.abc.ComplexField)) if algorithm == 'numpy' or algorithm == 'either': if K.prec() > 53 and L.prec() > 53: @@ -8082,7 +8082,7 @@ cdef class Polynomial(CommutativeAlgebraElement): # If we want the complex roots, and the input is not # floating point, we convert to a real polynomial # (except when the input coefficients are Gaussian rationals). - if is_ComplexDoubleField(L): + if isinstance(L, sage.rings.abc.ComplexDoubleField): real_field = RDF else: real_field = RealField(L.prec()) @@ -8250,7 +8250,7 @@ cdef class Polynomial(CommutativeAlgebraElement): True """ K = self.base_ring() - if is_RealField(K) or is_RealDoubleField(K): + if isinstance(K, sage.rings.abc.RealField) or isinstance(K, sage.rings.abc.RealDoubleField): return self.roots(multiplicities=False) return self.roots(ring=RR, multiplicities=False) @@ -8292,11 +8292,11 @@ cdef class Polynomial(CommutativeAlgebraElement): True """ K = self.base_ring() - if is_RealField(K): + if isinstance(K, sage.rings.abc.RealField): return self.roots(ring=ComplexField(K.prec()), multiplicities=False) - if is_RealDoubleField(K): + if isinstance(K, sage.rings.abc.RealDoubleField): return self.roots(ring=CDF, multiplicities=False) - if is_ComplexField(K) or is_ComplexDoubleField(K): + if isinstance(K, sage.rings.abc.ComplexField) or isinstance(K, sage.rings.abc.ComplexDoubleField): return self.roots(multiplicities=False) return self.roots(ring=CC, multiplicities=False) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 7cef097c1a8..b480bd09ff0 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -165,7 +165,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute -from sage.rings.real_mpfr import is_RealField +import sage.rings.abc from sage.rings.fraction_field_element import FractionFieldElement from sage.rings.finite_rings.element_base import FiniteRingElement @@ -1995,7 +1995,7 @@ def __init__(self, base_ring, name="x", sparse=False, element_class=None, catego else: from sage.rings.polynomial.polynomial_number_field import Polynomial_relative_number_field_dense element_class = Polynomial_relative_number_field_dense - elif is_RealField(base_ring): + elif isinstance(base_ring, sage.rings.abc.RealField): element_class = PolynomialRealDense elif isinstance(base_ring, sage.rings.complex_arb.ComplexBallField): from sage.rings.polynomial.polynomial_complex_arb import Polynomial_complex_arb diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index 61777d5556a..256bb0997cc 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -41,11 +41,11 @@ import sage.rings.number_field as number_field from sage.interfaces.all import singular -from sage.rings.complex_mpfr import is_ComplexField -from sage.rings.real_mpfr import is_RealField -from sage.rings.complex_double import is_ComplexDoubleField +import sage.rings.abc +import sage.rings.abc +import sage.rings.abc from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing -from sage.rings.real_double import is_RealDoubleField +import sage.rings.abc from sage.rings.rational_field import is_RationalField from sage.rings.function_field.function_field import RationalFunctionField from sage.rings.finite_rings.finite_field_base import is_FiniteField @@ -257,26 +257,26 @@ def _singular_init_(self, singular=singular): base_ring = self.base_ring() - if is_RealField(base_ring): + if isinstance(base_ring, sage.rings.abc.RealField): # singular converts to bits from base_10 in mpr_complex.cc by: # size_t bits = 1 + (size_t) ((float)digits * 3.5); precision = base_ring.precision() digits = sage.arith.all.integer_ceil((2*precision - 2)/7.0) self.__singular = singular.ring("(real,%d,0)"%digits, _vars, order=order, check=False) - elif is_ComplexField(base_ring): + elif isinstance(base_ring, sage.rings.abc.ComplexField): # singular converts to bits from base_10 in mpr_complex.cc by: # size_t bits = 1 + (size_t) ((float)digits * 3.5); precision = base_ring.precision() digits = sage.arith.all.integer_ceil((2*precision - 2)/7.0) self.__singular = singular.ring("(complex,%d,0,I)"%digits, _vars, order=order, check=False) - elif is_RealDoubleField(base_ring): + elif isinstance(base_ring, sage.rings.abc.RealDoubleField): # singular converts to bits from base_10 in mpr_complex.cc by: # size_t bits = 1 + (size_t) ((float)digits * 3.5); self.__singular = singular.ring("(real,15,0)", _vars, order=order, check=False) - elif is_ComplexDoubleField(base_ring): + elif isinstance(base_ring, sage.rings.abc.ComplexDoubleField): # singular converts to bits from base_10 in mpr_complex.cc by: # size_t bits = 1 + (size_t) ((float)digits * 3.5); self.__singular = singular.ring("(complex,15,0,I)", _vars, order=order, check=False) @@ -389,10 +389,10 @@ def can_convert_to_singular(R): or sage.rings.finite_rings.finite_field_constructor.is_FiniteField(base_ring) or is_RationalField(base_ring) or is_IntegerModRing(base_ring) - or is_RealField(base_ring) - or is_ComplexField(base_ring) - or is_RealDoubleField(base_ring) - or is_ComplexDoubleField(base_ring)): + or isinstance(base_ring, sage.rings.abc.RealField) + or isinstance(base_ring, sage.rings.abc.ComplexField) + or isinstance(base_ring, sage.rings.abc.RealDoubleField) + or isinstance(base_ring, sage.rings.abc.ComplexDoubleField)): return True elif base_ring.is_prime_field(): return base_ring.characteristic() <= 2147483647 diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index a967e8f9e7e..750adf89b72 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -73,16 +73,16 @@ from sage.arith.constants cimport * cimport gmpy2 -def is_RealDoubleField(x): +def isinstance(x, sage.rings.abc.RealDoubleField): """ Returns ``True`` if ``x`` is the field of real double precision numbers. EXAMPLES:: sage: from sage.rings.real_double import is_RealDoubleField - sage: is_RealDoubleField(RDF) + sage: isinstance(RDF, sage.rings.abc.RealDoubleField) True - sage: is_RealDoubleField(RealField(53)) + sage: isinstance(RealField(53, sage.rings.abc.RealDoubleField)) False """ return isinstance(x, RealDoubleField_class) diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index 69568a5fb9d..cb9851fc8f9 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -5896,15 +5896,15 @@ def create_RealNumber(s, int base=10, int pad=0, rnd="RNDN", int min_prec=53): return RealLiteral(R, s, base) -def is_RealField(x): +def isinstance(x, sage.rings.abc.RealField): """ Returns ``True`` if ``x`` is technically of a Python real field type. EXAMPLES:: - sage: sage.rings.real_mpfr.is_RealField(RR) + sage: sage.rings.real_mpfr.isinstance(RR, sage.rings.abc.RealField) True - sage: sage.rings.real_mpfr.is_RealField(CC) + sage: sage.rings.real_mpfr.isinstance(CC, sage.rings.abc.RealField) False """ return isinstance(x, RealField_class) diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index bd7a8027b0c..55bd2790b08 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -13,8 +13,8 @@ #***************************************************************************** import sage.rings.all as rings -from sage.rings.complex_mpfr import is_ComplexField -from sage.rings.real_mpfr import is_RealField +import sage.rings.abc +import sage.rings.abc from sage.schemes.elliptic_curves.ell_point import EllipticCurvePoint_field from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_field @@ -1069,9 +1069,9 @@ def isogenies_prime_degree(self, l=None, max_l=31): ValueError: 4 is not prime. """ F = self.base_ring() - if is_RealField(F): + if isinstance(F, sage.rings.abc.RealField): raise NotImplementedError("This code could be implemented for general real fields, but has not been yet.") - if is_ComplexField(F): + if isinstance(F, sage.rings.abc.ComplexField): raise NotImplementedError("This code could be implemented for general complex fields, but has not been yet.") if F is rings.QQbar: raise NotImplementedError("This code could be implemented for QQbar, but has not been yet.") diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 821d2e96639..322b24f9540 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -2616,7 +2616,7 @@ def real_components(self, embedding): try: if not embedding.domain() is self.base_field(): raise ValueError("invalid embedding specified: should have domain {}".format(self.base_field())) - if not is_RealField(embedding.codomain()): + if not isinstance(embedding.codomain(, sage.rings.abc.RealField)): raise ValueError("invalid embedding specified: should be real") except AttributeError: raise ValueError("invalid embedding") diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 7edafee118a..068ea589b3d 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -125,7 +125,7 @@ from sage.rings.padics.precision_error import PrecisionError import sage.rings.all as rings -from sage.rings.real_mpfr import is_RealField +import sage.rings.abc from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ import sage.groups.generic as generic @@ -2219,7 +2219,7 @@ def is_on_identity_component(self, embedding=None): e = embedding # It is also trivially true if we have a complex embedding if e is not None: - if not is_RealField(e.codomain()): + if not isinstance(e.codomain(, sage.rings.abc.RealField)): return True # find a suitable embedding if none was supplied: @@ -2232,7 +2232,7 @@ def is_on_identity_component(self, embedding=None): e = K.embeddings(rings.ComplexField())[0] # If there is only one component, the result is True: - if not is_RealField(e.codomain()): # complex embedding + if not isinstance(e.codomain(, sage.rings.abc.RealField)): # complex embedding return True if e(E.discriminant()) < 0: # only one component return True @@ -3237,7 +3237,7 @@ def elliptic_logarithm(self, embedding=None, precision=100, L = E.period_lattice(emb) - if algorithm == 'sage' or not is_RealField(emb.codomain): + if algorithm == 'sage' or not isinstance(emb.codomain, sage.rings.abc.RealField): return L.elliptic_logarithm(self, precision) if algorithm != 'pari': diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index fe1899f647c..974f560c4db 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -100,7 +100,7 @@ from sage.modules.free_module import FreeModule_generic_pid from sage.rings.all import ZZ, QQ, RealField, ComplexField, QQbar, AA -from sage.rings.real_mpfr import is_RealField +import sage.rings.abc from sage.rings.complex_mpfr import ComplexNumber, is_ComplexField from sage.rings.real_mpfr import RealNumber as RealNumber from sage.rings.number_field.number_field import refine_embedding @@ -1169,11 +1169,11 @@ def coordinates(self, z, rounding=None): (12, 23) """ C = z.parent() - if is_RealField(C): + if isinstance(C, sage.rings.abc.RealField): C = ComplexField(C.precision()) z = C(z) else: - if is_ComplexField(C): + if isinstance(C, sage.rings.abc.ComplexField): pass else: try: @@ -1233,10 +1233,10 @@ def reduce(self, z): 0.958696500380444 """ C = z.parent() - if is_RealField(C): + if isinstance(C, sage.rings.abc.RealField): C = ComplexField(C.precision()) z = C(z) - elif is_ComplexField(C): + elif isinstance(C, sage.rings.abc.ComplexField): pass else: try: @@ -1789,12 +1789,12 @@ def elliptic_exponential(self, z, to_curve=True): """ C = z.parent() z_is_real = False - if is_RealField(C): + if isinstance(C, sage.rings.abc.RealField): z_is_real = True C = ComplexField(C.precision()) z = C(z) else: - if is_ComplexField(C): + if isinstance(C, sage.rings.abc.ComplexField): z_is_real = z.is_real() else: try: diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index 04ee419f880..ad2273cc99d 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -26,8 +26,8 @@ from sage.rings.all import PolynomialRing -from sage.rings.complex_mpfr import is_ComplexField -from sage.rings.real_mpfr import is_RealField +import sage.rings.abc +import sage.rings.abc from sage.modules.free_module_element import vector from sage.structure.sequence import Sequence @@ -517,7 +517,7 @@ def has_rational_point(self, point = False, if algorithm != 'default': raise ValueError("Unknown algorithm: %s" % algorithm) - if is_ComplexField(B): + if isinstance(B, sage.rings.abc.ComplexField): if point: [_,_,_,d,e,f] = self._coefficients if d == 0: @@ -525,7 +525,7 @@ def has_rational_point(self, point = False, return True, self.point([0, ((e**2-4*d*f).sqrt()-e)/(2*d), 1], check = False) return True - if is_RealField(B): + if isinstance(B, sage.rings.abc.RealField): D, T = self.diagonal_matrix() [a, b, c] = [D[0,0], D[1,1], D[2,2]] if a == 0: diff --git a/src/sage/schemes/plane_conics/con_rational_field.py b/src/sage/schemes/plane_conics/con_rational_field.py index e8b1d824cbd..4ff7cc39a61 100644 --- a/src/sage/schemes/plane_conics/con_rational_field.py +++ b/src/sage/schemes/plane_conics/con_rational_field.py @@ -26,7 +26,7 @@ from sage.rings.all import (PolynomialRing, ZZ, QQ) -from sage.rings.real_mpfr import is_RealField +import sage.rings.abc from sage.structure.sequence import Sequence from sage.schemes.projective.projective_space import ProjectiveSpace @@ -230,11 +230,11 @@ def is_locally_solvable(self, p) -> bool: return True a = -abc[0] / abc[2] b = -abc[1] / abc[2] - if is_RealField(p) or isinstance(p, InfinityElement): + if isinstance(p, sage.rings.abc.RealField) or isinstance(p, InfinityElement): p = -1 elif isinstance(p, Map) and p.category_for().is_subcategory(Rings()): # p is a morphism of Rings - if p.domain() is QQ and is_RealField(p.codomain()): + if p.domain() is QQ and isinstance(p.codomain(, sage.rings.abc.RealField)): p = -1 else: raise TypeError("p (=%s) needs to be a prime of base field " diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index de4720f90a7..beab2ce78ca 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -395,7 +395,7 @@ from sage.misc.latex import latex_variable_name from sage.rings.infinity import AnInfinity, infinity, minus_infinity, unsigned_infinity from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR -from sage.rings.complex_mpfr import is_ComplexField +import sage.rings.abc from sage.misc.decorators import rename_keyword from sage.structure.dynamic_class import dynamic_class from sage.structure.element cimport CommutativeRingElement @@ -13830,7 +13830,7 @@ cdef unsigned sage_domain_to_ginac_domain(object domain) except? 3474701533: return domain_real elif domain == 'positive': return domain_positive - elif is_ComplexField(domain) or domain == 'complex': + elif isinstance(domain, sage.rings.abc.ComplexField) or domain == 'complex': return domain_complex elif domain is ZZ or domain == 'integer': return domain_integer @@ -13844,7 +13844,7 @@ cdef void send_sage_domain_to_maxima(Expression v, object domain) except +: assume(v, 'real') elif domain == 'positive': assume(v>0) - elif is_ComplexField(domain) or domain == 'complex': + elif isinstance(domain, sage.rings.abc.ComplexField) or domain == 'complex': assume(v, 'complex') elif domain is ZZ or domain == 'integer': assume(v, 'integer') From 28e328a995088c574c1e1ab3fc31f613d273b725 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 11:05:20 -0700 Subject: [PATCH 209/511] Remove repeated imports of sage.rings.abc --- src/sage/functions/orthogonal_polys.py | 1 - src/sage/modules/free_module.py | 4 ++-- src/sage/rings/polynomial/multi_polynomial_libsingular.pyx | 1 - src/sage/rings/polynomial/polynomial_singular_interface.py | 3 --- src/sage/schemes/elliptic_curves/ell_field.py | 1 - src/sage/schemes/plane_conics/con_field.py | 1 - 6 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index c879cd6c8fe..67c0381b541 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -305,7 +305,6 @@ from sage.rings.all import ZZ, QQ, RR, CC from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing import sage.rings.abc -import sage.rings.abc from sage.symbolic.function import BuiltinFunction, GinacFunction from sage.symbolic.expression import Expression diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 6288e77cf76..57c10114174 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -7443,9 +7443,9 @@ def element_class(R, is_sparse): return Vector_modn_dense else: return free_module_element.FreeModuleElement_generic_dense - elif sage.rings.real_double.isinstance(R, sage.rings.abc.RealDoubleField) and not is_sparse: + elif sage.rings.real_double.is_RealDoubleField(R) and not is_sparse: return sage.modules.vector_real_double_dense.Vector_real_double_dense - elif sage.rings.complex_double.isinstance(R, sage.rings.abc.ComplexDoubleField) and not is_sparse: + elif sage.rings.complex_double.is_ComplexDoubleField(R) and not is_sparse: return sage.modules.vector_complex_double_dense.Vector_complex_double_dense elif sage.symbolic.ring.is_SymbolicExpressionRing(R) and not is_sparse: import sage.modules.vector_symbolic_dense diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index f32e42d83f3..03f8015f7ea 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -225,7 +225,6 @@ from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_mo from sage.rings.rational cimport Rational from sage.rings.rational_field import QQ import sage.rings.abc -import sage.rings.abc from sage.rings.integer_ring import is_IntegerRing, ZZ from sage.rings.integer cimport Integer from sage.rings.integer import GCD_list diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index 256bb0997cc..0a472405790 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -42,10 +42,7 @@ from sage.interfaces.all import singular import sage.rings.abc -import sage.rings.abc -import sage.rings.abc from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing -import sage.rings.abc from sage.rings.rational_field import is_RationalField from sage.rings.function_field.function_field import RationalFunctionField from sage.rings.finite_rings.finite_field_base import is_FiniteField diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 55bd2790b08..d972c4e1fc9 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -14,7 +14,6 @@ import sage.rings.all as rings import sage.rings.abc -import sage.rings.abc from sage.schemes.elliptic_curves.ell_point import EllipticCurvePoint_field from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_field diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index ad2273cc99d..0d5eb412034 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -26,7 +26,6 @@ from sage.rings.all import PolynomialRing -import sage.rings.abc import sage.rings.abc from sage.modules.free_module_element import vector From 45cc21ad1afb7c06cc2a61a65adeeb9b2e8664f9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 11:07:17 -0700 Subject: [PATCH 210/511] is_Real[Double]Field, is_Complex[Double]Field: Undo automatic edits, deprecate --- src/sage/rings/complex_double.pyx | 12 +++++++++--- src/sage/rings/complex_mpfr.pyx | 11 +++++++++-- src/sage/rings/real_double.pyx | 12 +++++++++--- src/sage/rings/real_mpfr.pyx | 12 +++++++++--- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 7621cc043c2..a1a2ae29a29 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -111,18 +111,24 @@ from sage.structure.richcmp cimport rich_to_bool cimport gmpy2 gmpy2.import_gmpy2() -def isinstance(x, sage.rings.abc.ComplexDoubleField): + +def is_ComplexDoubleField(x): """ Return ``True`` if ``x`` is the complex double field. + This function is deprecated. Use :func:`isinstance` with + :class:`~sage.rings.abc.ComplexDoubleField` instead. + EXAMPLES:: sage: from sage.rings.complex_double import is_ComplexDoubleField - sage: isinstance(CDF, sage.rings.abc.ComplexDoubleField) + sage: is_ComplexDoubleField(CDF) True - sage: isinstance(ComplexField(53, sage.rings.abc.ComplexDoubleField)) + sage: is_ComplexDoubleField(ComplexField(53)) False """ + from sage.misc.superseded import deprecation + deprecation(32610, 'is_ComplexDoubleField is deprecated; use isinstance(..., sage.rings.abc.ComplexDoubleField) instead') return isinstance(x, ComplexDoubleField_class) diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index d3d32b69de5..e3d73b4a268 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -157,10 +157,14 @@ def is_ComplexNumber(x): """ return isinstance(x, ComplexNumber) -def isinstance(x, sage.rings.abc.ComplexField): + +def is_ComplexField(x): """ Check if ``x`` is a :class:`complex field `. + This function is deprecated. Use :func:`isinstance` with + :class:`~sage.rings.abc.ComplexField` instead. + EXAMPLES:: sage: from sage.rings.complex_mpfr import is_ComplexField as is_CF @@ -171,8 +175,11 @@ def isinstance(x, sage.rings.abc.ComplexField): sage: is_CF(CC) True """ + from sage.misc.superseded import deprecation + deprecation(32610, 'is_ComplexField is deprecated; use isinstance(..., sage.rings.abc.ComplexField) instead') return isinstance(x, ComplexField_class) + cache = {} def ComplexField(prec=53, names=None): """ @@ -543,7 +550,7 @@ class ComplexField_class(ring.Field): RR = self._real_field() if RR.has_coerce_map_from(S): return RRtoCC(RR, self) * RR._internal_coerce_map_from(S) - if isinstance(S, sage.rings.abc.ComplexField): + if isinstance(S, ComplexField_class): if self._prec <= S._prec: return self._generic_coerce_map(S) else: diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index 750adf89b72..5be63115735 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -73,20 +73,26 @@ from sage.arith.constants cimport * cimport gmpy2 -def isinstance(x, sage.rings.abc.RealDoubleField): +def is_RealDoubleField(x): """ Returns ``True`` if ``x`` is the field of real double precision numbers. + This function is deprecated. Use :func:`isinstance` with + :class:`~sage.rings.abc.RealDoubleField` instead. + EXAMPLES:: sage: from sage.rings.real_double import is_RealDoubleField - sage: isinstance(RDF, sage.rings.abc.RealDoubleField) + sage: is_RealDoubleField(RDF) True - sage: isinstance(RealField(53, sage.rings.abc.RealDoubleField)) + sage: is_RealDoubleField(RealField(53)) False """ + from sage.misc.superseded import deprecation + deprecation(32610, 'is_RealDoubleField is deprecated; use isinstance(..., sage.rings.abc.RealDoubleField) instead') return isinstance(x, RealDoubleField_class) + cdef class RealDoubleField_class(Field): """ An approximation to the field of real numbers using double diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index cb9851fc8f9..f0d2eb5919b 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -5896,19 +5896,25 @@ def create_RealNumber(s, int base=10, int pad=0, rnd="RNDN", int min_prec=53): return RealLiteral(R, s, base) -def isinstance(x, sage.rings.abc.RealField): +def is_RealField(x): """ Returns ``True`` if ``x`` is technically of a Python real field type. + This function is deprecated. Use :func:`isinstance` with + :class:`~sage.rings.abc.RealField` instead. + EXAMPLES:: - sage: sage.rings.real_mpfr.isinstance(RR, sage.rings.abc.RealField) + sage: sage.rings.real_mpfr.is_RealField(RR) True - sage: sage.rings.real_mpfr.isinstance(CC, sage.rings.abc.RealField) + sage: sage.rings.real_mpfr.is_RealField(CC) False """ + from sage.misc.superseded import deprecation + deprecation(32610, 'is_RealField is deprecated; use isinstance(..., sage.rings.abc.RealField) instead') return isinstance(x, RealField_class) + def is_RealNumber(x): """ Return ``True`` if ``x`` is of type :class:`RealNumber`, meaning that it From e003603ebb665c064a459f55b9ad4731d9900424 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 11:08:33 -0700 Subject: [PATCH 211/511] sage.dynamics: Fix up replacement of is_{Real,Complex}[Double]Field --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index e5f2b9225cf..3c56fd3885b 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -88,8 +88,8 @@ class initialization directly. from sage.rings.qqbar import QQbar, number_field_elements_from_algebraics from sage.rings.quotient_ring import QuotientRing_generic from sage.rings.rational_field import QQ -from sage.rings.real_double import RDF -from sage.rings.real_mpfr import (RealField, is_RealField) +import sage.rings.abc +from sage.rings.real_mpfr import RealField from sage.schemes.generic.morphism import SchemeMorphism_polynomial from sage.schemes.projective.projective_subscheme import AlgebraicScheme_subscheme_projective from sage.schemes.projective.projective_morphism import ( @@ -2062,10 +2062,10 @@ def canonical_height(self, P, **kwds): # Archimedean local heights # :: WARNING: If places is fed the default Sage precision of 53 bits, - # it uses Real or Complex Double Field in place of RealField(prec) or ComplexField(prec) - # the function is_RealField does not identify RDF as real, so we test for that ourselves. + # it uses Real or Complex Double Field in place of RealField(prec) or ComplexField(prec). + # RDF is an instance of a separate class. for v in emb: - if isinstance(v.codomain(, sage.rings.abc.RealField)) or v.codomain() is RDF: + if isinstance(v.codomain(), (sage.rings.abc.RealField, sage.rings.abc.RealDoubleField)): dv = R.one() else: dv = R(2) From 4adc553551b756d2cb177055359a55c6bd4691e6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 11:08:50 -0700 Subject: [PATCH 212/511] sage.functions: Fix up replacement of is_{Real,Complex}[Double]Field --- src/sage/functions/orthogonal_polys.py | 8 ++++---- src/sage/functions/special.py | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 67c0381b541..0e965c57da6 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -671,7 +671,7 @@ def _evalf_(self, n, x, **kwds): except KeyError: real_parent = parent(x) - if not isinstance(real_parent, sage.rings.abc.RealField) and not isinstance(real_parent, sage.rings.abc.ComplexField): + if not isinstance(real_parent, (sage.rings.abc.RealField, sage.rings.abc.ComplexField)): # parent is not a real or complex field: figure out a good parent if x in RR: x = RR(x) @@ -680,7 +680,7 @@ def _evalf_(self, n, x, **kwds): x = CC(x) real_parent = CC - if not isinstance(real_parent, sage.rings.abc.RealField) and not isinstance(real_parent, sage.rings.abc.ComplexField): + if not isinstance(real_parent, (sage.rings.abc.RealField, sage.rings.abc.ComplexField)): raise TypeError("cannot evaluate chebyshev_T with parent {}".format(real_parent)) from sage.libs.mpmath.all import call as mpcall @@ -1030,7 +1030,7 @@ def _evalf_(self, n, x, **kwds): except KeyError: real_parent = parent(x) - if not isinstance(real_parent, sage.rings.abc.RealField) and not isinstance(real_parent, sage.rings.abc.ComplexField): + if not isinstance(real_parent, (sage.rings.abc.RealField, sage.rings.abc.ComplexField)): # parent is not a real or complex field: figure out a good parent if x in RR: x = RR(x) @@ -1039,7 +1039,7 @@ def _evalf_(self, n, x, **kwds): x = CC(x) real_parent = CC - if not isinstance(real_parent, sage.rings.abc.RealField) and not isinstance(real_parent, sage.rings.abc.ComplexField): + if not isinstance(real_parent, (sage.rings.abc.RealField, sage.rings.abc.ComplexField)): raise TypeError("cannot evaluate chebyshev_U with parent {}".format(real_parent)) from sage.libs.mpmath.all import call as mpcall diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index c409631f392..bc43c362141 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -159,7 +159,6 @@ # **************************************************************************** from sage.rings.integer import Integer -from sage.rings.complex_mpfr import ComplexField from sage.misc.latex import latex from sage.rings.all import ZZ from sage.symbolic.constants import pi @@ -362,10 +361,9 @@ def elliptic_j(z, prec=53): sage: (-elliptic_j(tau, 100).real().round())^(1/3) 640320 """ - CC = z.parent() - from sage.rings.complex_mpfr import is_ComplexField if not isinstance(CC, sage.rings.abc.ComplexField): + from sage.rings.complex_mpfr import ComplexField CC = ComplexField(prec) try: z = CC(z) From 5b988c69369a02eea230d61303742195f3ba4a36 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 11:09:11 -0700 Subject: [PATCH 213/511] sage.schemes: Fix up replacement of is_{Real,Complex}[Double]Field --- src/sage/schemes/elliptic_curves/ell_number_field.py | 3 +-- src/sage/schemes/elliptic_curves/ell_point.py | 4 ++-- src/sage/schemes/elliptic_curves/period_lattice.py | 2 +- src/sage/schemes/plane_conics/con_rational_field.py | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 322b24f9540..f0bcda573df 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -2612,11 +2612,10 @@ def real_components(self, embedding): ... ValueError: invalid embedding specified: should have domain ... """ - from sage.rings.real_mpfr import is_RealField try: if not embedding.domain() is self.base_field(): raise ValueError("invalid embedding specified: should have domain {}".format(self.base_field())) - if not isinstance(embedding.codomain(, sage.rings.abc.RealField)): + if not isinstance(embedding.codomain(), sage.rings.abc.RealField): raise ValueError("invalid embedding specified: should be real") except AttributeError: raise ValueError("invalid embedding") diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 068ea589b3d..63b027eae62 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -2219,7 +2219,7 @@ def is_on_identity_component(self, embedding=None): e = embedding # It is also trivially true if we have a complex embedding if e is not None: - if not isinstance(e.codomain(, sage.rings.abc.RealField)): + if not isinstance(e.codomain(), sage.rings.abc.RealField): return True # find a suitable embedding if none was supplied: @@ -2232,7 +2232,7 @@ def is_on_identity_component(self, embedding=None): e = K.embeddings(rings.ComplexField())[0] # If there is only one component, the result is True: - if not isinstance(e.codomain(, sage.rings.abc.RealField)): # complex embedding + if not isinstance(e.codomain(), sage.rings.abc.RealField): # complex embedding return True if e(E.discriminant()) < 0: # only one component return True diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 974f560c4db..01a96c37627 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -101,7 +101,7 @@ from sage.modules.free_module import FreeModule_generic_pid from sage.rings.all import ZZ, QQ, RealField, ComplexField, QQbar, AA import sage.rings.abc -from sage.rings.complex_mpfr import ComplexNumber, is_ComplexField +from sage.rings.complex_mpfr import ComplexNumber from sage.rings.real_mpfr import RealNumber as RealNumber from sage.rings.number_field.number_field import refine_embedding from sage.rings.infinity import Infinity diff --git a/src/sage/schemes/plane_conics/con_rational_field.py b/src/sage/schemes/plane_conics/con_rational_field.py index 4ff7cc39a61..d24bd59898c 100644 --- a/src/sage/schemes/plane_conics/con_rational_field.py +++ b/src/sage/schemes/plane_conics/con_rational_field.py @@ -234,7 +234,7 @@ def is_locally_solvable(self, p) -> bool: p = -1 elif isinstance(p, Map) and p.category_for().is_subcategory(Rings()): # p is a morphism of Rings - if p.domain() is QQ and isinstance(p.codomain(, sage.rings.abc.RealField)): + if p.domain() is QQ and isinstance(p.codomain(), sage.rings.abc.RealField): p = -1 else: raise TypeError("p (=%s) needs to be a prime of base field " From 402dbec95818340a31e0b1d1790fc5ba31690480 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 11:10:11 -0700 Subject: [PATCH 214/511] sage.rings.number_field: Fix up replacement of is_{Real,Complex}[Double]Field --- src/sage/rings/number_field/number_field.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index bc626635105..863fbd8aad8 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -9945,16 +9945,14 @@ def hilbert_symbol(self, a, b, P = None): if P.domain() is not self: raise ValueError("Domain of P (=%s) should be self (=%s) in self.hilbert_symbol" % (P, self)) codom = P.codomain() - from sage.rings.complex_mpfr import is_ComplexField from sage.rings.complex_interval_field import is_ComplexIntervalField - from sage.rings.real_mpfr import is_RealField - from sage.rings.all import (AA, CDF, QQbar, RDF) - if isinstance(codom, sage.rings.abc.ComplexField) or is_ComplexIntervalField(codom) or \ - codom is CDF or codom is QQbar: + from sage.rings.all import (AA, QQbar) + if isinstance(codom, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField) or is_ComplexIntervalField(codom) or \ + codom is QQbar: if P(self.gen()).imag() == 0: raise ValueError("Possibly real place (=%s) given as complex embedding in hilbert_symbol. Is it real or complex?" % P) return 1 - if isinstance(codom, sage.rings.abc.RealField) or codom is RDF or codom is AA: + if isinstance(codom, (sage.rings.abc.RealField, sage.rings.abc.RealDoubleField) or codom is AA: if P(a) > 0 or P(b) > 0: return 1 return -1 @@ -12317,7 +12315,7 @@ def refine_embedding(e, prec=None): return e # We first compute all the embeddings at the new precision: - if sage.rings.real_mpfr.isinstance(RC, sage.rings.abc.RealField) or RC in (RDF, RLF): + if isinstance(RC, (sage.rings.abc.RealField, sage.rings.abc.RealDoubleField)) or RC == RLF: if prec == Infinity: elist = K.embeddings(sage.rings.qqbar.AA) else: From e82709c128895eb1d9c0d127ee878c2830ffaef3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 11:10:24 -0700 Subject: [PATCH 215/511] sage.rings.polynomial: Fix up replacement of is_{Real,Complex}[Double]Field --- .../rings/polynomial/polynomial_element.pyx | 36 ++++++++----------- .../polynomial_singular_interface.py | 6 ++-- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 70f026179a4..add33c68590 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -51,7 +51,7 @@ TESTS:: # https://www.gnu.org/licenses/ # **************************************************************************** -cdef is_FractionField, is_RealField, is_ComplexField +cdef is_FractionField cdef ZZ, QQ, RR, CC, RDF, CDF cimport cython @@ -64,6 +64,7 @@ import re from sage.cpython.wrapperdescr cimport wrapperdescr_fastcall import sage.rings.rational import sage.rings.integer +import sage.rings.abc from . import polynomial_ring import sage.rings.integer_ring import sage.rings.rational_field @@ -84,13 +85,13 @@ from sage.structure.richcmp cimport (richcmp, richcmp_item, from sage.interfaces.singular import singular as singular_default, is_SingularElement from sage.libs.all import pari, pari_gen, PariError -from sage.rings.real_mpfr import RealField, is_RealField, RR +from sage.rings.real_mpfr import RealField, RR -from sage.rings.complex_mpfr import is_ComplexField, ComplexField +from sage.rings.complex_mpfr import ComplexField CC = ComplexField() -from sage.rings.real_double import is_RealDoubleField, RDF -from sage.rings.complex_double import is_ComplexDoubleField, CDF +from sage.rings.real_double import RDF +from sage.rings.complex_double import CDF from sage.rings.real_mpfi import is_RealIntervalField from sage.structure.coerce cimport coercion_model @@ -7912,18 +7913,12 @@ cdef class Polynomial(CommutativeAlgebraElement): late_import() - input_fp = (isinstance(K, sage.rings.abc.RealField) - or isinstance(K, sage.rings.abc.ComplexField) - or isinstance(K, sage.rings.abc.RealDoubleField) - or isinstance(K, sage.rings.abc.ComplexDoubleField)) - output_fp = (isinstance(L, sage.rings.abc.RealField) - or isinstance(L, sage.rings.abc.ComplexField) - or isinstance(L, sage.rings.abc.RealDoubleField) - or isinstance(L, sage.rings.abc.ComplexDoubleField)) - input_complex = (isinstance(K, sage.rings.abc.ComplexField) - or isinstance(K, sage.rings.abc.ComplexDoubleField)) - output_complex = (isinstance(L, sage.rings.abc.ComplexField) - or isinstance(L, sage.rings.abc.ComplexDoubleField)) + input_fp = isinstance(K, (sage.rings.abc.RealField, sage.rings.abc.ComplexField, + sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)) + output_fp = isinstance(L, (sage.rings.abc.RealField, sage.rings.abc.ComplexField, + sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)) + input_complex = isinstance(K, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) + output_complex = isinstance(L, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) input_gaussian = (isinstance(K, NumberField_quadratic) and list(K.polynomial()) == [1, 0, 1]) @@ -7943,8 +7938,7 @@ cdef class Polynomial(CommutativeAlgebraElement): # We should support GSL, too. We could also support PARI's # old Newton-iteration algorithm. - input_arbprec = (isinstance(K, sage.rings.abc.RealField) or - isinstance(K, sage.rings.abc.ComplexField)) + input_arbprec = isinstance(K, (sage.rings.abc.RealField, sage.rings.abc.ComplexField)) if algorithm == 'numpy' or algorithm == 'either': if K.prec() > 53 and L.prec() > 53: @@ -8250,7 +8244,7 @@ cdef class Polynomial(CommutativeAlgebraElement): True """ K = self.base_ring() - if isinstance(K, sage.rings.abc.RealField) or isinstance(K, sage.rings.abc.RealDoubleField): + if isinstance(K, (sage.rings.abc.RealField, sage.rings.abc.RealDoubleField)): return self.roots(multiplicities=False) return self.roots(ring=RR, multiplicities=False) @@ -8296,7 +8290,7 @@ cdef class Polynomial(CommutativeAlgebraElement): return self.roots(ring=ComplexField(K.prec()), multiplicities=False) if isinstance(K, sage.rings.abc.RealDoubleField): return self.roots(ring=CDF, multiplicities=False) - if isinstance(K, sage.rings.abc.ComplexField) or isinstance(K, sage.rings.abc.ComplexDoubleField): + if isinstance(K, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)): return self.roots(multiplicities=False) return self.roots(ring=CC, multiplicities=False) diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index 0a472405790..419eab22f40 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -386,10 +386,8 @@ def can_convert_to_singular(R): or sage.rings.finite_rings.finite_field_constructor.is_FiniteField(base_ring) or is_RationalField(base_ring) or is_IntegerModRing(base_ring) - or isinstance(base_ring, sage.rings.abc.RealField) - or isinstance(base_ring, sage.rings.abc.ComplexField) - or isinstance(base_ring, sage.rings.abc.RealDoubleField) - or isinstance(base_ring, sage.rings.abc.ComplexDoubleField)): + or isinstance(base_ring, (sage.rings.abc.RealField, sage.rings.abc.ComplexField, + sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)): return True elif base_ring.is_prime_field(): return base_ring.characteristic() <= 2147483647 From 1d2956914662cf5b6390e381aa16a574cb804d58 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 11:10:56 -0700 Subject: [PATCH 216/511] sage.{modular,quadratic_forms}: Fix up replacement of is_{Real,Complex}[Double]Field --- src/sage/modular/dirichlet.py | 4 ++-- src/sage/quadratic_forms/special_values.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index f71ef1e6f17..22c632c9789 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -1153,7 +1153,7 @@ def _pari_init_(self): # now compute the input for pari (list of exponents) P = self.parent() - if isinstance(P.base_ring(, sage.rings.abc.ComplexField)): + if isinstance(P.base_ring(), sage.rings.abc.ComplexField): zeta = P.zeta() zeta_argument = zeta.argument() v = [int(x.argument() / zeta_argument) for x in values_on_gens] @@ -2138,7 +2138,7 @@ def element(self): """ P = self.parent() M = P._module - if isinstance(P.base_ring(, sage.rings.abc.ComplexField)): + if isinstance(P.base_ring(), sage.rings.abc.ComplexField): zeta = P.zeta() zeta_argument = zeta.argument() v = M([int(round(x.argument() / zeta_argument)) diff --git a/src/sage/quadratic_forms/special_values.py b/src/sage/quadratic_forms/special_values.py index 5c7e3a1ccfe..e7b4c425866 100644 --- a/src/sage/quadratic_forms/special_values.py +++ b/src/sage/quadratic_forms/special_values.py @@ -9,7 +9,6 @@ from sage.combinat.combinat import bernoulli_polynomial from sage.misc.functional import denominator -from sage.rings.all import RealField from sage.arith.all import kronecker_symbol, bernoulli, factorial, fundamental_discriminant from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ @@ -278,9 +277,10 @@ def quadratic_L_function__numerical(n, d, num_terms=1000): ....: print("Oops! We have a problem at d = {}: exact = {}, numerical = {}".format(d, RR(quadratic_L_function__exact(1, d)), RR(quadratic_L_function__numerical(1, d)))) """ # Set the correct precision if it is given (for n). - if isinstance(n.parent(, sage.rings.abc.RealField)): + if isinstance(n.parent(), sage.rings.abc.RealField): R = n.parent() else: + from sage.rings.real_mpfr import RealField R = RealField() if n < 0: From a4ad3d4a21062fe99408d71d49bd8e21e10c63c4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 11:11:08 -0700 Subject: [PATCH 217/511] sage.matrix: Fix up replacement of is_{Real,Complex}[Double]Field --- src/sage/matrix/misc.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/misc.pyx b/src/sage/matrix/misc.pyx index a70a9a0f711..c7fc1c70161 100644 --- a/src/sage/matrix/misc.pyx +++ b/src/sage/matrix/misc.pyx @@ -40,7 +40,7 @@ from sage.rings.rational_field import QQ from sage.rings.integer cimport Integer from sage.arith.all import previous_prime, CRT_basis -from sage.rings.real_mpfr import is_RealField +from sage.rings.real_mpfr cimport RealField_class from sage.rings.real_mpfr cimport RealNumber @@ -510,7 +510,7 @@ def hadamard_row_bound_mpfr(Matrix A): ... OverflowError: cannot convert float infinity to integer """ - if not isinstance(A.base_ring(, sage.rings.abc.RealField)): + if not isinstance(A.base_ring(), RealField_class): raise TypeError("A must have base field an mpfr real field.") cdef RealNumber a, b From f8d734d38c8f956581c08fedddc04ef156d8c562 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 11:58:47 -0700 Subject: [PATCH 218/511] tox.ini, build/bin/write-dockerfile.sh: Re-enable networkx, symengine_py SAGE_CHECK --- build/bin/write-dockerfile.sh | 8 ++++---- tox.ini | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/bin/write-dockerfile.sh b/build/bin/write-dockerfile.sh index aa7050b203b..bd709957ef1 100755 --- a/build/bin/write-dockerfile.sh +++ b/build/bin/write-dockerfile.sh @@ -219,7 +219,7 @@ ARG NUMPROC=8 ENV MAKE="make -j\${NUMPROC}" ARG USE_MAKEFLAGS="-k V=0" ENV SAGE_CHECK=warn -ENV SAGE_CHECK_PACKAGES="!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" +ENV SAGE_CHECK_PACKAGES="!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!rpy2,!sage_sws2rst" #:toolchain: $RUN make \${USE_MAKEFLAGS} base-toolchain $ENDRUN @@ -228,7 +228,7 @@ ARG NUMPROC=8 ENV MAKE="make -j\${NUMPROC}" ARG USE_MAKEFLAGS="-k V=0" ENV SAGE_CHECK=warn -ENV SAGE_CHECK_PACKAGES="!gfan,!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" +ENV SAGE_CHECK_PACKAGES="!gfan,!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!rpy2,!sage_sws2rst" #:make: ARG TARGETS_PRE="all-sage-local" $RUN make SAGE_SPKG="sage-spkg -y -o" \${USE_MAKEFLAGS} \${TARGETS_PRE} $ENDRUN @@ -238,7 +238,7 @@ ARG NUMPROC=8 ENV MAKE="make -j\${NUMPROC}" ARG USE_MAKEFLAGS="-k V=0" ENV SAGE_CHECK=warn -ENV SAGE_CHECK_PACKAGES="!gfan,!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" +ENV SAGE_CHECK_PACKAGES="!gfan,!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!rpy2,!sage_sws2rst" ADD src src ARG TARGETS="build" $RUN make SAGE_SPKG="sage-spkg -y -o" \${USE_MAKEFLAGS} \${TARGETS} $ENDRUN @@ -248,7 +248,7 @@ ARG NUMPROC=8 ENV MAKE="make -j\${NUMPROC}" ARG USE_MAKEFLAGS="-k V=0" ENV SAGE_CHECK=warn -ENV SAGE_CHECK_PACKAGES="!gfan,!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" +ENV SAGE_CHECK_PACKAGES="!gfan,!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!rpy2,!sage_sws2rst" ARG TARGETS_OPTIONAL="ptest" $RUN make SAGE_SPKG="sage-spkg -y -o" \${USE_MAKEFLAGS} \${TARGETS_OPTIONAL} || echo "(error ignored)" $ENDRUN diff --git a/tox.ini b/tox.ini index d565133513b..d119fdfbd82 100644 --- a/tox.ini +++ b/tox.ini @@ -577,8 +577,8 @@ commands = local: config*) ;; \ local: *) make -k V=0 base-toolchain ;; \ local: esac && \ - local: make -k V=0 SAGE_CHECK=warn SAGE_CHECK_PACKAGES="!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" {env:TARGETS_PRE:} {posargs:build} && \ - local: ( [ -z "{env:TARGETS_OPTIONAL:}" ] || make -k V=0 SAGE_CHECK=warn SAGE_CHECK_PACKAGES="!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!networkx,!rpy2,!symengine_py,!sage_sws2rst" {env:TARGETS_OPTIONAL:} || echo "(error ignored)" ) ' + local: make -k V=0 SAGE_CHECK=warn SAGE_CHECK_PACKAGES="!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!rpy2,!sage_sws2rst" {env:TARGETS_PRE:} {posargs:build} && \ + local: ( [ -z "{env:TARGETS_OPTIONAL:}" ] || make -k V=0 SAGE_CHECK=warn SAGE_CHECK_PACKAGES="!cython,!r,!python3,!gap,!cysignals,!linbox,!git,!ppl,!cmake,!rpy2,!sage_sws2rst" {env:TARGETS_OPTIONAL:} || echo "(error ignored)" ) ' [testenv:check_configure] ## Test that configure behaves properly From c7aa947e4bd2437c872477176eab735d2d835f9e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 12:40:48 -0700 Subject: [PATCH 219/511] sage.probability: Fix up replacement of is_{Real,Complex}[Double]Field --- src/sage/probability/random_variable.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/probability/random_variable.py b/src/sage/probability/random_variable.py index ea2c4c86b2f..bdb666dfeab 100644 --- a/src/sage/probability/random_variable.py +++ b/src/sage/probability/random_variable.py @@ -18,7 +18,6 @@ from sage.structure.parent import Parent from sage.functions.log import log from sage.functions.all import sqrt -from sage.rings.real_mpfr import (RealField, is_RealField) from sage.rings.rational_field import is_RationalField from sage.sets.set import Set from pprint import pformat @@ -83,6 +82,7 @@ def __init__(self, X, f, codomain=None, check=False): if check: raise NotImplementedError("Not implemented") if codomain is None: + from sage.rings.real_mpfr import RealField RR = RealField() else: RR = codomain @@ -337,6 +337,7 @@ def __init__(self, X, P, codomain=None, check=False): 1.50000000000000 """ if codomain is None: + from sage.rings.real_mpfr import RealField codomain = RealField() if not isinstance(codomain, sage.rings.abc.RealField) and not is_RationalField(codomain): raise TypeError("Argument codomain (= %s) must be the reals or rationals" % codomain) From b8691cc3154217d0ec0fa555403d6e88d31fd275 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 12:41:03 -0700 Subject: [PATCH 220/511] src/sage/rings/number_field/number_field_element.pyx: Remove unused import --- src/sage/rings/number_field/number_field_element.pyx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 4ee3d048f07..67d8274d4c6 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -3945,7 +3945,6 @@ cdef class NumberFieldElement(FieldElement): if a <= Kv.one(): return Kv.zero() ht = a.log() - from sage.rings.real_mpfr import is_RealField if weighted and not isinstance(Kv, sage.rings.abc.RealField): ht*=2 return ht From abbe26dcc98ef905e3b70d1ef6cfd874181345df Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 12:46:28 -0700 Subject: [PATCH 221/511] src/sage/modules/free_module.py: Remove another use of is_... functions --- src/sage/modules/free_module.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 57c10114174..c28a31707a7 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -170,6 +170,7 @@ from sage.modules.module import Module import sage.rings.finite_rings.finite_field_constructor as finite_field import sage.rings.ring as ring +import sage.rings.abc import sage.rings.integer_ring import sage.rings.rational_field import sage.rings.finite_rings.integer_mod_ring @@ -7443,9 +7444,9 @@ def element_class(R, is_sparse): return Vector_modn_dense else: return free_module_element.FreeModuleElement_generic_dense - elif sage.rings.real_double.is_RealDoubleField(R) and not is_sparse: + elif isinstance(R, sage.rings.abc.RealDoubleField) and not is_sparse: return sage.modules.vector_real_double_dense.Vector_real_double_dense - elif sage.rings.complex_double.is_ComplexDoubleField(R) and not is_sparse: + elif isinstance(R, sage.rings.abc.ComplexDoubleField) and not is_sparse: return sage.modules.vector_complex_double_dense.Vector_complex_double_dense elif sage.symbolic.ring.is_SymbolicExpressionRing(R) and not is_sparse: import sage.modules.vector_symbolic_dense From 65e9b9833bc8e4e837f775c8b867755271dedbe4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 14:07:52 -0700 Subject: [PATCH 222/511] src/sage/rings/polynomial/polynomial_singular_interface.py: Fixup --- src/sage/rings/polynomial/polynomial_singular_interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index 419eab22f40..2fd1ac24b2b 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -387,7 +387,7 @@ def can_convert_to_singular(R): or is_RationalField(base_ring) or is_IntegerModRing(base_ring) or isinstance(base_ring, (sage.rings.abc.RealField, sage.rings.abc.ComplexField, - sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)): + sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField))): return True elif base_ring.is_prime_field(): return base_ring.characteristic() <= 2147483647 From 9096edb73bfa435e242635b5d5eb01b62aadd21a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 16:20:51 -0700 Subject: [PATCH 223/511] sage.features.sagemath: New --- src/sage/features/sagemath.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/sage/features/sagemath.py diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py new file mode 100644 index 00000000000..32c6246b7fd --- /dev/null +++ b/src/sage/features/sagemath.py @@ -0,0 +1,28 @@ +r""" +Check for SageMath Python modules +""" +from . import PythonModule + + +class sage__combinat(PythonModule): + + def __init__(self): + PythonModule.__init__('sage.combinat.combinations') + + +class sage__graphs(PythonModule): + + def __init__(self): + PythonModule.__init__('sage.graphs.graph') + + +class sage__rings__real_double(PythonModule): + + def __init__(self): + PythonModule.__init__('sage.rings.real_double') + + +class sage__symbolic(PythonModule): + + def __init__(self): + PythonModule.__init__('sage.symbolic.expression', spkg="sagemath_symbolics") From a00d97a6da3193a8d12f7fb01488eb81ce13aa40 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 16:24:14 -0700 Subject: [PATCH 224/511] src/sage/rings/number_field/number_field.py: Fixup --- src/sage/rings/number_field/number_field.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 863fbd8aad8..f8cadacb0d0 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -9947,12 +9947,12 @@ def hilbert_symbol(self, a, b, P = None): codom = P.codomain() from sage.rings.complex_interval_field import is_ComplexIntervalField from sage.rings.all import (AA, QQbar) - if isinstance(codom, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField) or is_ComplexIntervalField(codom) or \ + if isinstance(codom, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) or is_ComplexIntervalField(codom) or \ codom is QQbar: if P(self.gen()).imag() == 0: raise ValueError("Possibly real place (=%s) given as complex embedding in hilbert_symbol. Is it real or complex?" % P) return 1 - if isinstance(codom, (sage.rings.abc.RealField, sage.rings.abc.RealDoubleField) or codom is AA: + if isinstance(codom, (sage.rings.abc.RealField, sage.rings.abc.RealDoubleField)) or codom is AA: if P(a) > 0 or P(b) > 0: return 1 return -1 From 2938e1387d002460ff7fdcc60e250799e47b6b4f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 17:05:06 -0700 Subject: [PATCH 225/511] src/sage/doctest/parsing.py: Allow . in optional tags --- src/sage/doctest/parsing.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 0be358f35be..7bceddde322 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -34,7 +34,7 @@ from .external import available_software float_regex = re.compile(r'\s*([+-]?\s*((\d*\.?\d+)|(\d+\.?))([eE][+-]?\d+)?)') -optional_regex = re.compile(r'(arb216|arb218|py2|py3|long time|not implemented|not tested|known bug)|([^ a-z]\s*optional\s*[:-]*((\s|\w)*))') +optional_regex = re.compile(r'(arb216|arb218|py2|py3|long time|not implemented|not tested|known bug)|([^ a-z]\s*optional\s*[:-]*((\s|\w|[.])*))') # Version 4.65 of glpk prints the warning "Long-step dual simplex will # be used" frequently. When Sage uses a system installation of glpk # which has not been patched, we need to ignore that message. @@ -316,6 +316,8 @@ def parse_optional_tags(string): {''} sage: sorted(list(parse_optional_tags("sage: #optional -- foo bar, baz"))) ['bar', 'foo'] + sage: parse_optional_tags("sage: #optional -- foo.bar, baz") + {'foo.bar'} sage: sorted(list(parse_optional_tags(" sage: factor(10^(10^10) + 1) # LoNg TiME, NoT TeSTED; OptioNAL -- P4cka9e"))) ['long time', 'not tested', 'p4cka9e'] sage: parse_optional_tags(" sage: raise RuntimeError # known bug") From 747b458420bffc389fdc1e3a1acec4148e818ba4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 17:05:46 -0700 Subject: [PATCH 226/511] sage.doctest.control, sage.features.sagemath: Provide/use optional tags --- src/sage/doctest/control.py | 3 +++ src/sage/features/sagemath.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index afb0d6cbcf1..c7d68478ff7 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -53,6 +53,9 @@ except ImportError: pass +from sage.features.sagemath import sage_optional_tags +auto_optional_tags |= sage_optional_tags() + class DocTestDefaults(SageObject): """ This class is used for doctesting the Sage doctest module. diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index 32c6246b7fd..c6d253a9c51 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -7,6 +7,9 @@ class sage__combinat(PythonModule): def __init__(self): + # sage.combinat will be a namespace package. + # Testing whether sage.combinat itself can be imported is meaningless. + # Hence, we test a Python module within the package. PythonModule.__init__('sage.combinat.combinations') @@ -26,3 +29,28 @@ class sage__symbolic(PythonModule): def __init__(self): PythonModule.__init__('sage.symbolic.expression', spkg="sagemath_symbolics") + + +def sage_optional_tags(): + """ + Return tags for conditionalizing doctests. + + These tags are named after Python packages/modules (e.g., :mod:`~sage.symbolic`), + not distribution packages (``sagemath-symbolics``). + + This is motivated by a separation of concerns: The author of a module that depends + on some functionality provided by a Python module usually already knows the + name of the Python module, so we do not want to force the author to also + know about the distribution package that provides the Python module. + + Instead, we associate distribution packages to Python modules in + :mod:`sage.features.sagemath` via the ``spkg`` parameter of :class:`PythonModule``. + """ + if sage__combinat().is_functional(): + yield 'sage.combinat' + if sage__graphs().is_functional(): + yield 'sage.graphs' + if sage__rings__real_double().is_functional(): + yield 'sage.rings.real_double' + if sage__symbolic().is_functional(): + yield 'sage.symbolic' From e3a541e039081242121e247b51c3fc42c963cd43 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 17:13:22 -0700 Subject: [PATCH 227/511] Fixup --- src/sage/doctest/control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index c7d68478ff7..42ed54ddb49 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -54,7 +54,7 @@ pass from sage.features.sagemath import sage_optional_tags -auto_optional_tags |= sage_optional_tags() +auto_optional_tags.update(sage_optional_tags()) class DocTestDefaults(SageObject): """ From 5e04a85c4dbe3663bab664b7356d255b5ddc1cf6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 17:16:55 -0700 Subject: [PATCH 228/511] src/sage/features/sagemath.py: Fixup --- src/sage/features/sagemath.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index c6d253a9c51..57bb082c8c5 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -10,25 +10,25 @@ def __init__(self): # sage.combinat will be a namespace package. # Testing whether sage.combinat itself can be imported is meaningless. # Hence, we test a Python module within the package. - PythonModule.__init__('sage.combinat.combinations') + PythonModule.__init__(self, 'sage.combinat.combinations') class sage__graphs(PythonModule): def __init__(self): - PythonModule.__init__('sage.graphs.graph') + PythonModule.__init__(self, 'sage.graphs.graph') class sage__rings__real_double(PythonModule): def __init__(self): - PythonModule.__init__('sage.rings.real_double') + PythonModule.__init__(self, 'sage.rings.real_double') class sage__symbolic(PythonModule): def __init__(self): - PythonModule.__init__('sage.symbolic.expression', spkg="sagemath_symbolics") + PythonModule.__init__(self, 'sage.symbolic.expression', spkg="sagemath_symbolics") def sage_optional_tags(): @@ -46,11 +46,11 @@ def sage_optional_tags(): Instead, we associate distribution packages to Python modules in :mod:`sage.features.sagemath` via the ``spkg`` parameter of :class:`PythonModule``. """ - if sage__combinat().is_functional(): + if sage__combinat().is_present(): yield 'sage.combinat' - if sage__graphs().is_functional(): + if sage__graphs().is_present(): yield 'sage.graphs' - if sage__rings__real_double().is_functional(): + if sage__rings__real_double().is_present(): yield 'sage.rings.real_double' - if sage__symbolic().is_functional(): + if sage__symbolic().is_present(): yield 'sage.symbolic' From 66cf3e12e49e6d5b86bd6023edc2d9d92ee2b00e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 17:58:35 -0700 Subject: [PATCH 229/511] src/sage/doctest/control.py: Fixup handling of sage_optional_tags --- src/sage/doctest/control.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 42ed54ddb49..05767a50876 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -40,7 +40,7 @@ from .external import external_software, available_software nodoctest_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*nodoctest') -optionaltag_regex = re.compile(r'^\w+$') +optionaltag_regex = re.compile(r'^(\w|[.])+$') # Optional tags which are always automatically added @@ -53,9 +53,6 @@ except ImportError: pass -from sage.features.sagemath import sage_optional_tags -auto_optional_tags.update(sage_optional_tags()) - class DocTestDefaults(SageObject): """ This class is used for doctesting the Sage doctest module. @@ -374,6 +371,9 @@ def __init__(self, options, args): from sage.features import package_systems options.optional.update(system.name for system in package_systems()) + from sage.features.sagemath import sage_optional_tags + options.optional.update(sage_optional_tags()) + # Check that all tags are valid for o in options.optional: if not optionaltag_regex.search(o): From 13eed83e9ab842e4299d5cc81a0e97679856e5f5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 17:59:21 -0700 Subject: [PATCH 230/511] src/sage/doctest/parsing.py: Do not fail if RealIntervalField cannot be imported, just warn --- src/sage/doctest/parsing.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 0be358f35be..1591dd609cd 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -83,9 +83,19 @@ def RIFtol(*args): """ global _RIFtol if _RIFtol is None: - # We need to import from sage.all to avoid circular imports. - from sage.all import RealIntervalField - _RIFtol = RealIntervalField(1044) + try: + # We need to import from sage.all to avoid circular imports. + from sage.all import RealIntervalField + except ImportError: + from warnings import warn + warn("RealIntervalField not available, ignoring all tolerance specifications in doctests") + def fake_RIFtol(*args): + if len(args) == 2: + return (args[0] + args[1]) / 2 + return args[0] + _RIFtol = fake_RIFtol + else: + _RIFtol = RealIntervalField(1044) return _RIFtol(*args) # This is the correct pattern to match ISO/IEC 6429 ANSI escape sequences: From 1ec0c485ccaed52ce83ba66c479fadfa3ef9b167 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 18:37:51 -0700 Subject: [PATCH 231/511] src/sage/features/sagemath.py: Add sage.rings.number_field --- src/sage/features/sagemath.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index 57bb082c8c5..1172b6a3ff6 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -19,6 +19,12 @@ def __init__(self): PythonModule.__init__(self, 'sage.graphs.graph') +class sage__rings__number_field(PythonModule): + + def __init__(self): + PythonModule.__init__(self, 'sage.rings.number_field_element') + + class sage__rings__real_double(PythonModule): def __init__(self): @@ -50,6 +56,8 @@ def sage_optional_tags(): yield 'sage.combinat' if sage__graphs().is_present(): yield 'sage.graphs' + if sage__rings__number_field().is_present(): + yield 'sage.rings.number_field' if sage__rings__real_double().is_present(): yield 'sage.rings.real_double' if sage__symbolic().is_present(): From 875afbf83aaf1182902023e3d323feb4a855fd01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 5 Dec 2014 20:12:13 +0100 Subject: [PATCH 232/511] trac #17442 italian translation of tutorial, start --- src/doc/it/tutorial/index.rst | 35 +++ src/doc/it/tutorial/introduction.rst | 146 ++++++++++ src/doc/it/tutorial/tour_algebra.rst | 398 +++++++++++++++++++++++++++ 3 files changed, 579 insertions(+) create mode 100644 src/doc/it/tutorial/index.rst create mode 100644 src/doc/it/tutorial/introduction.rst create mode 100644 src/doc/it/tutorial/tour_algebra.rst diff --git a/src/doc/it/tutorial/index.rst b/src/doc/it/tutorial/index.rst new file mode 100644 index 00000000000..e192767dd6f --- /dev/null +++ b/src/doc/it/tutorial/index.rst @@ -0,0 +1,35 @@ +.. Sage documentation master file, created by sphinx-quickstart on Thu Aug 21 20:15:55 2008. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Benvenuti al tutorial di Sage! +================================ + +Sage è un software di calcolo numerico e simbolico libero e open-source di supporto +nell'insegnamento e della ricerca in algebra, geometria, teoria dei numeri, crittografia, +calcolo numerico e aree correlate. Sia il modello di sviluppo di Sage, sia la tecnologia +utilizzata in Sage stesso, si distinguono per un'enfasi particolarmente forte +su apertura, community, cooperazione e collaborazione: vogliamo creare +l'automobile, non reinventare la ruota. L'obiettivo complessivo di Sage è creare +un'alternativa adeguata, libera e open-source a Maple, Mathematica, Magma e +MATLAB. + +Questo tutorial è la via migliore per familiarizzare con Sage in poche ore e può +essere letto in HTML o PDF, oppure direttamente dal Notebook di Sage (fare click +su "Help" e poi su "Tutorial" per seguire il tutorial in modo interattivo +dall'interno di Sage). + + +.. toctree:: + :maxdepth: 2 + + introduction + tour_algebra + +Indici e tabelle +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`cerca` + diff --git a/src/doc/it/tutorial/introduction.rst b/src/doc/it/tutorial/introduction.rst new file mode 100644 index 00000000000..e72e4ef25e1 --- /dev/null +++ b/src/doc/it/tutorial/introduction.rst @@ -0,0 +1,146 @@ +************ +Introduzione +************ +Questo tutorial dovrebbe richiedere circa 3/4 ore per +una lettura completa. Lo si può leggere in versione HTML o PDF, o dal notebook Sage; +fare clic su "Help", poi fare clic su "Tutorial" per leggere interattivamente +il tutorial dall'interno di Sage. + +Nonostante molto in Sage sia implementato usando Python, la conoscenza di Python +non è un prerequisito per la lettura di questo tutorial. Per chi volesse imparare +il Python (un linguaggio molto divertente!) allo stesso tempo, ci sono molte risorse +eccellenti e libere per farlo tra le quali [PyT]_ e [Dive]_. +Se si vuole solo provare velocemente Sage, questo tutorial è il punto di partenza adatto. +Per esempio: + +:: + + sage: 2 + 2 + 4 + sage: factor(-2007) + -1 * 3^2 * 223 + + sage: A = matrix(4,4, range(16)); A + [ 0 1 2 3] + [ 4 5 6 7] + [ 8 9 10 11] + [12 13 14 15] + + sage: factor(A.charpoly()) + x^2 * (x^2 - 30*x - 80) + + sage: m = matrix(ZZ,2, range(4)) + sage: m[0,0] = m[0,0] - 3 + sage: m + [-3 1] + [ 2 3] + + sage: E = EllipticCurve([1,2,3,4,5]); + sage: E + Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 + over Rational Field + sage: E.anlist(10) + [0, 1, 1, 0, -1, -3, 0, -1, -3, -3, -3] + sage: E.rank() + 1 + + sage: k = 1/(sqrt(3)*I + 3/4 + sqrt(73)*5/9); k + 36/(20*sqrt(73) + 36*I*sqrt(3) + 27) + + sage: N(k) + 0.165495678130644 - 0.0521492082074256*I + sage: N(k,30) # 30 "bits" + 0.16549568 - 0.052149208*I + sage: latex(k) + \frac{36}{20 \, \sqrt{73} + 36 i \, \sqrt{3} + 27} + +Installazione +============= + +Se non si ha Sage installato su un computer e si vogliono solamente +provare alcuni comandi, si può usare online all'indirizzo http://www.sagenb.org. + +Si veda la Sage Installation Guide nella sezione documentazione della homepage +di Sage [Sage]_ per istruzioni sull'installazione di Sage sul proprio computer. +Qui vengono fatti solamente due commenti. + + +#. Il file di download di Sage arrive con le "batterie incluse". + In altre parole, nonostante Sage usi Python, IPython, PARI, GAP, + Singular, Maxima, NTL, GMP e così via, non è necessario installarli + separatemente siccome sono incluse con la distribuzione di Sage. + Comunque, per usare certe feature di \sage, ad es. Macaulay o KASH, + bisogna installare il pacchetto opzionale Sage che interessa o almeno + avere i programmi in questioni gia installati sul proprio computer. + Macaulay e KASH sono pacchetti di Sage (per una lista dei pacchetti + opzionali disponibili, digitare "sage -optional", o sfogliare la pagina + "Download" sul sito web di Sage. + +#. Le versioni binarie precompilate di Sage (che si trovano sul sito web di + Sage) possono essere più facili e più veloci da installare invece che la + versione da codice sorgente. Basta solo spachettare il file e eseguire "sage". + +Modi di usare Sage +================== + +Sage si può usare in molti modi. + + +- **Interfaccia grafica del notebook:** vedere la sezioni sul + Notebook nel manuale di riferimento e la :ref:"sezione-notebook" sotto, + +- **Linea di comando interattiva:** vedere :ref:'capitolo-shell_interattiva', + +- **Programmi:** scrivendo programmi interpretati e compilati in Sage (vedere + :ref:'sezione-loadattach' e :ref:'sezione-compilazione'), e + +- **Scripts:** scrivendo degli script autosufficienti che usino la libreria + Sage (vedere :ref:'sezione-autosufficienti'). + + +Obiettivi di lungo periodo per Sage +=================================== + +- **Utile**: il pubblico per Sage il quale sage è stato pensato sono gli + studentu di matematica (dalla scuola superiore all'università), gli insegnanti + e i ricercatori in matematica. Lo scopo è di fornire software che possa essere + usato per esplorare e sperimentare le costruzioni matematiche in algebra, + geometria, teoria dei numeri, calcolo, calcolo numerico, ecc. Sage aiuta a + rendere più facile la sperimentazione interattiva con gli oggetti matematici. + +- **Efficiente:** essere veloce. Sage usa del software maturo e altamente + ottimizzato come GMP, PARI, GAP e NTL e così è molto veloce con certe + operazioni. + +- **Libero e open source:** il codice sorgente deve essere liberamente disponibile + e leggibile, così che gli utenti posssano capire cosa stia facendo veramente il + sistema e possano estenderlo più facilmente. Così come i matematici acquisiscono + una comprensione più profonda di un teorema leggendo attentamete o almeno scorrendo + velocemente la dimostrazione, le persone che fanno calcoli dovrebbero essere capaci + di capire come funzionano i calcoli leggengo il codice sorgente documentato. Se + si usa Sage per fare calcoli in un articolo che si pubblica, si può essere rassicurati + dal fatto che i lettori avranno sempre libero accesso a Sage e a tutto il suo codice + sorgente ed è persino concesso di archiviare la versione di Sage che si è utilizzata. + +- **Facile da compilare:** Sage dovrebbe essere facile da compilare dal sorgente per + gli utenti Linux, OS X e Windows. Questo garantisce maggiore flessibilità agli utenti + di modificare il sistema. + +- **Cooperazione:** Fornire un interfaccia robusta alla maggior parte degli altri sistemi + di algebra computazionale, compresi: PARI, GAP, Singular, Maxima, KASH, Magma, Maple e + Mathematica. Sage è pensato per unificare e estendere il software matematico esistente. + +- **Ben documentato:** tutorial, guida alla programmazione, manuale di riferimento e + how to con numerosi esempi e discussioni della matematica sottostante. + +- **Amichevole verso l'utente:** dovrebbe essere facile capire quale funzionalità è + fornita per un dato oggetto e guardare la documentazione e il codice sorgente. + Bisogna anche raggiungere un alto livello di supporto agli utenti. + + +.. [Dive] (en) Tuffati in Python, Liberamente disponibile in linea + all'indirizzo: http://www.diveintopython.net + +.. [PyT] (en) Il tutorial Python, http://www.python.org/ + +.. [Sage] (en) Sage, http://www.sagemath.org diff --git a/src/doc/it/tutorial/tour_algebra.rst b/src/doc/it/tutorial/tour_algebra.rst new file mode 100644 index 00000000000..7ef0b3d799d --- /dev/null +++ b/src/doc/it/tutorial/tour_algebra.rst @@ -0,0 +1,398 @@ +Algebra di base e Analisi + +========================= + +Sage sa svolgere diversi calcoli legati all'algebra di base +ed all'analisi: per esempio, risoluzione di equazioni, +calcolo differenziale ed integrale e trasformate di Laplace. +Si veda la documentazione per le "Costruzioni di Sage" per +ulteriori esempi. + +Risoluzione di equazioni +------------------------ + +La funzione ``solve`` risolve le equazioni. Per usarla, +bisogna anzitutto specificare alcune variabili; pertanto +gli argomenti di ``solve`` sono un'equazione (od un sistema +di equazioni), insieme con le variabili rispetto alle quali +risolvere: + +:: + + sage: x = var('x') + sage: solve(x^2 + 3*x + 2, x) + [x == -2, x == -1] + +Si possono risolvere le equazioni rispetto ad una variabile in funzione +delle altre: + +:: + + sage: x, b, c = var('x b c') + sage: solve([x^2 + b*x + c == 0],x) + [x == -1/2*b - 1/2*sqrt(b^2 - 4*c), x == -1/2*b + 1/2*sqrt(b^2 - 4*c)] + +Si può anche risolvere rispetto a diverse variabili: + +:: + + sage: x, y = var('x, y') + sage: solve([x+y==6, x-y==4], x, y) + [[x == 5, y == 1]] + +Il seguente esempio dell'uso di Sage per risolvere un sistema di +equazioni non lineari è stato fornito da Jason Grout: per prima cosa, +si risolve il sistema simbolicamente: + +:: + + sage: var('x y p q') + (x, y, p, q) + sage: eq1 = p+q==9 + sage: eq2 = q*y+p*x==-6 + sage: eq3 = q*y^2+p*x^2==24 + sage: solve([eq1,eq2,eq3,p==1],p,q,x,y) + [[p == 1, q == 8, x == -4/3*sqrt(10) - 2/3, y == 1/6*sqrt(10) - 2/3], + [p == 1, q == 8, x == 4/3*sqrt(10) - 2/3, y == -1/6*sqrt(10) - 2/3]] + +Per una soluzione numerica, si può invece usare: + +.. link + +:: + + sage: solns = solve([eq1,eq2,eq3,p==1],p,q,x,y, solution_dict=True) + sage: [[s[p].n(30), s[q].n(30), s[x].n(30), s[y].n(30)] for s in solns] + [[1.0000000, 8.0000000, -4.8830369, -0.13962039], + [1.0000000, 8.0000000, 3.5497035, -1.1937129]] + +(La funzione ``n`` scrive un'approssimazione numerica, e +l'argomento è il numero di bit di precisione.) + +Differenziazione, Integrazione, etc. +------------------------------------ + +Sage è in grado di differenziae ed integrare molte funzioni. Per +esempio, per differenziare :math:`\sin(u)` rispetto a :math:`u`, +si procede come nelle righe seguenti: + +:: + + sage: u = var('u') + sage: diff(sin(u), u) + cos(u) + +Per calcolare la derivata quarta di :math:`\sin(x^2)`: + +:: + + sage: diff(sin(x^2), x, 4) + 16*x^4*sin(x^2) - 48*x^2*cos(x^2) - 12*sin(x^2) + +Per calcolare le derivate parziali di :math:`x^2+17y^2` +rispetto a *x* e *y*, rispettivamente: + +:: + + sage: x, y = var('x,y') + sage: f = x^2 + 17*y^2 + sage: f.diff(x) + 2*x + sage: f.diff(y) + 34*y + +Passiamo agli integrali, sia indefiniti che definiti. Per calcolare +:math:`\int x\sin(x^2)\, dx` e +:math:`\int_0^1 \frac{x}{x^2+1}\, dx` + +:: + + sage: integral(x*sin(x^2), x) + -1/2*cos(x^2) + sage: integral(x/(x^2+1), x, 0, 1) + 1/2*log(2) + +Per calcolare la decomposizione in frazioni parziali di +:math:`\frac{1}{x^2-1}`: + +:: + + sage: f = 1/((1+x)*(x-1)) + sage: f.partial_fraction(x) + -1/2/(x + 1) + 1/2/(x - 1) + +.. _section-systems: + +Risoluzione di Equazioni Differenziali +-------------------------------------- + +Si può usare Sage per studiare le equazioni differenziali ordinarie. +Per risolvere l'equazione :math:`x'+x-1=0`: + +:: + + sage: t = var('t') # definisce una variabile t + sage: x = function('x')(t) # definisce x come funzione di quella variabile + sage: DE = diff(x,t) + x - 1 + sage: desolve(DE, [x,t]) + (_C + e^t)*e^(-t) + +Questo metodo utilizza l'interfaccia di Sage per Maxima [Max]_, e così il suo +output può essere leggermente diverso dagli altri output di Sage. In questo caso, +risulta che la soluzione generale dell'equazione differenziale è +:math:`x(t) = e^{-t}(e^{t}+c)`. + +Si può anche calcolare la trasformata di Laplace; la trasformata di Laplace di +:math:`t^2e^t -\sin(t)` è calcolata come segue: + +:: + + sage: s = var("s") + sage: t = var("t") + sage: f = t^2*exp(t) - sin(t) + sage: f.laplace(t,s) + -1/(s^2 + 1) + 2/(s - 1)^3 + +Il successivo è un esempio più articolato. Lo scostamento dall'equilibrio +(rispettivamente) per due molle accoppiate fissate ad un muro a sinistra + +:: + + |------\/\/\/\/\---|massa1|----\/\/\/\/\/----|massa2| + molla1 molla2 + +è modellizzato dal sistema di equazioni differenziali del secondo ordine + +.. math:: + m_1 x_1'' + (k_1+k_2) x_1 - k_2 x_2 = 0 + m_2 x_2''+ k_2 (x_2-x_1) = 0, + + + +dove :math:`m_{i}` è la massa dell'oggetto *i*, :math:`x_{i}` è +lo scostamento dall'equilibrio della massa *i*, e :math:`k_{i}` +è la costante elastica della molla *i*. + +**Esempio:** Usare Sage per risolvere il problema precedente con +:math:`m_{1}=2`, :math:`m_{2}=1`, :math:`k_{1}=4`, +:math:`k_{2}=2`, :math:`x_{1}(0)=3`, :math:`x_{1}'(0)=0`, +:math:`x_{2}(0)=3`, :math:`x_{2}'(0)=0`. + +Soluzione: Calcolare la trasformata di Laplace della prima equazione (con +la notazione :math:`x=x_{1}`, :math:`y=x_{2}`: + +:: + + sage: de1 = maxima("2*diff(x(t),t, 2) + 6*x(t) - 2*y(t)") + sage: lde1 = de1.laplace("t","s"); lde1 + 2*((-%at('diff(x(t),t,1),t=0))+s^2*'laplace(x(t),t,s)-x(0)*s)-2*'laplace(y(t),t,s)+6*'laplace(x(t),t,s) + +Questo è di difficile lettura, ma dice che + +.. math:: -2x'(0) + 2s^2*X(s) - 2sx(0) - 2Y(s) + 6X(s) = 0 + + +(dove la trasformata di Laplace di una funzione in minuscolo come +:math:`x(t)` è la funzione in maiuscolo :math:`X(s)`). Calcolare la +trasformata di Laplace della seconda equazione: + +:: + + sage: de2 = maxima("diff(y(t),t, 2) + 2*y(t) - 2*x(t)") + sage: lde2 = de2.laplace("t","s"); lde2 + (-%at('diff(y(t),t,1),t=0))+s^2*'laplace(y(t),t,s)+2*'laplace(y(t),t,s)-2*'laplace(x(t),t,s)-y(0)*s + +che significa + +.. math:: -Y'(0) + s^2Y(s) + 2Y(s) - 2X(s) - sy(0) = 0. + + +Imporre le condizioni iniziali per :math:`x(0)`, :math:`x'(0)`, +:math:`y(0)`, e :math:`y'(0)`, e risolvere le due equazioni +risultanti: + +:: + + sage: var('s X Y') + (s, X, Y) + sage: eqns = [(2*s^2+6)*X-2*Y == 6*s, -2*X +(s^2+2)*Y == 3*s] + sage: solve(eqns, X,Y) + [[X == 3*(s^3 + 3*s)/(s^4 + 5*s^2 + 4), + Y == 3*(s^3 + 5*s)/(s^4 + 5*s^2 + 4)]] + +Ora si calcola la trasformata inversa di Laplace per ottenere la risposta: + +:: + + sage: var('s t') + (s, t) + sage: inverse_laplace((3*s^3 + 9*s)/(s^4 + 5*s^2 + 4),s,t) + cos(2*t) + 2*cos(t) + sage: inverse_laplace((3*s^3 + 15*s)/(s^4 + 5*s^2 + 4),s,t) + -cos(2*t) + 4*cos(t) + +Pertanto, la soluzione è + +.. math:: x_1(t) = \cos(2t) + 2\cos(t), \quad x_2(t) = 4\cos(t) - \cos(2t). + + +Essa può essere disegnata in forma parametrica usando + +:: + + sage: t = var('t') + sage: P = parametric_plot((cos(2*t) + 2*cos(t), 4*cos(t) - cos(2*t) ), + ....: (0, 2*pi), rgbcolor=hue(0.9)) + sage: show(P) + +Le singole componenti possono essere tracciate usando: + +:: + + sage: t = var('t') + sage: p1 = plot(cos(2*t) + 2*cos(t), 0, 2*pi, rgbcolor=hue(0.3)) + sage: p2 = plot(4*cos(t) - cos(2*t), 0, 2*pi, rgbcolor=hue(0.6)) + sage: show(p1 + p2) + +(Per ulteriori informazioni sul disegno di funzioni, si veda :ref:`section-plot`.) + +BIBLIOGRAFIA: Nagle, Saff, Snider, Fundamentals of Differential +Equations, 6th ed, Addison-Wesley, 2004. (si veda § 5.5). + +Metodo di Eulero per i sistemi di equazioni differenziali +--------------------------------------------------------- + +Nel prossimo esempio, si illustrerà il metodo di Eulero per le ODE +di primo e secondo ordine. Per prima cosa ricordiamo l'idea di base per +le equazioni di primo ordine. Dato un problema di Cauchy della forma + +.. math:: + y'=f(x,y) + y(a)=c + + +si vuole trovare il valore approssimato della soluzione a +:math:`x=b` con :math:`b>a`. + +Ricordando dalla definizione di derivata che + +.. math:: y'(x) \approx \frac{y(x+h)-y(x)}{h}, + + +dove :math:`h>0` è dato e piccolo. Questo e la DE insieme danno +give :math:`f(x,y(x))\approx +\frac{y(x+h)-y(x)}{h}`. Ora si risolve +per :math:`y(x+h)`: + +.. math:: y(x+h) \approx y(x) + h*f(x,y(x)). + + +Se chiamiamo :math:`h f(x,y(x))` il "termine di correzione" (per mancanza +di un termine migliore), :math:`y(x)` il "vecchio valore di *y*", e + :math:`y(x+h)` il "nuovo valore di *y*", allora questa +approssimazione può essere espressa come + +.. math:: y_{new} \approx y_{old} + h*f(x,y_{old}). + + +Se si spezza l'intervallo da *a* a *b* in *n* intervalli, dimodoché +:math:`h=\frac{b-a}{n}`, allora si possono registrare le informazioni per +questo metodo in una tabella. + +============== ================== ================ +:math:`x` :math:`y` :math:`hf(x,y)` +============== ================== ================ +:math:`a` :math:`c` :math:`hf(a,c)` +:math:`a+h` :math:`c+hf(a,c)` ... +:math:`a+2h` ... +... +:math:`b=a+nh` ??? ... +============== ================== ================ + + +L'obiettivo è riempire tutti gli spazi vuoti della tavella, una riga alla +volta, finché si arriva al valore ???, che è il +metodo di approssimazione di Eulero per :math:`y(b)`. + +L'idea per sistemi di ODE è simile. + +**Esempio:** Si approssimi numericamente :math:`z(t)` a :math:`t=1` usando 4 +passi del metodo di Eulero, dove :math:`z''+tz'+z=0`, +:math:`z(0)=1`, :math:`z'(0)=0`. + +Si deve ridurre l'ODE di secondo ordine ad un sistema di due equazioni del primo +ordine (usando :math:`x=z`, :math:`y=z'`) ed applicare il metodo di +Eulero: + +:: + + sage: t,x,y = PolynomialRing(RealField(10),3,"txy").gens() + sage: f = y; g = -x - y * t + sage: eulers_method_2x2(f,g, 0, 1, 0, 1/4, 1) + t x h*f(t,x,y) y h*g(t,x,y) + 0 1 0.00 0 -0.25 + 1/4 1.0 -0.062 -0.25 -0.23 + 1/2 0.94 -0.12 -0.48 -0.17 + 3/4 0.82 -0.16 -0.66 -0.081 + 1 0.65 -0.18 -0.74 0.022 + +Pertanto, :math:`z(1)\approx 0.75`. + +Si possono anche tracciare i punti :math:`(x,y)` per ottenere un grafico +approssimato della curva. La funzione ``eulers_method_2x2_plot`` svolge +questa funzione; per usarla, bisogna definire le funzioni *f* e +*g* che prendono on argomento con tre coordinate: (*t*, *x*, +*y*). + +:: + + sage: f = lambda z: z[2] # f(t,x,y) = y + sage: g = lambda z: -sin(z[1]) # g(t,x,y) = -sin(x) + sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0) + +A questo punto, ``P`` ha in memoria due grafici: ``P[0]``, il grafico di *x* +vs. *t*, e ``P[1]``, il grafico di *y* vs. *t*. Si possono tracciare entrambi +come mostrato qui in seguito: + +.. link + +:: + + sage: show(P[0] + P[1]) + +(Per ulteriori informazioni sul disegno di grafici, si veda :ref:`section-plot`.) + +Funzioni speciali +----------------- + +Sono implementati diversi polinomi ortogonali e funzioni +speciali, usando sia PARI [GAP]_ che Maxima [Max]_. Essi +sono documentati nelle sezioni apposite ("Polinomi ortogonali" +e "Funzioni speciali", rispettivamente) del manuale di Sage. + +:: + + sage: x = polygen(QQ, 'x') + sage: chebyshev_U(2,x) + 4*x^2 - 1 + sage: bessel_I(1,1).n(250) + 0.56515910399248502720769602760986330732889962162109200948029448947925564096 + sage: bessel_I(1,1).n() + 0.565159103992485 + sage: bessel_I(2,1.1).n() + 0.167089499251049 + +A questo punto, Sage ha soltanto incorporato queste funzioni per l'uso numerico. +Per l'uso simbolico, si usi direttamente l'intefaccia di Maxima, come +nell'esempio seguente: + +:: + + sage: maxima.eval("f:bessel_y(v, w)") + 'bessel_y(v,w)' + sage: maxima.eval("diff(f,w)") + '(bessel_y(v-1,w)-bessel_y(v+1,w))/2' + +.. [GAP] (en) The GAP Group, ``GAP - Groups, Algorithms, and Programming``, http://www.gap-system.org + +.. [Max] (en) Maxima, http://maxima.sf.net/ From 6da082a7c611da789273d17686dd70d013fdd57a Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 3 Oct 2021 10:52:29 +0200 Subject: [PATCH 233/511] trac #17537: typo --- src/sage/graphs/convexity_properties.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/convexity_properties.pyx b/src/sage/graphs/convexity_properties.pyx index 19c1224cab3..c260daff32e 100644 --- a/src/sage/graphs/convexity_properties.pyx +++ b/src/sage/graphs/convexity_properties.pyx @@ -599,7 +599,7 @@ def geodetic_closure(G, S): cdef dict vertex_to_int = {u: i for i, u in enumerate(int_to_vertex)} cdef list S_int = [vertex_to_int[u] for u in S] - # Copy the graph has a short digraph + # Copy the graph as a short digraph cdef short_digraph sd init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) From a5c3ea8e7bbbefdd9b7ac65e70af4d6fc88c11e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 3 Oct 2021 10:54:45 +0200 Subject: [PATCH 234/511] fixing some details, refresh --- src/doc/it/tutorial/index.rst | 5 +---- src/doc/it/tutorial/introduction.rst | 19 +++++++++---------- src/doc/it/tutorial/tour_algebra.rst | 5 +++-- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/doc/it/tutorial/index.rst b/src/doc/it/tutorial/index.rst index e192767dd6f..c4c4ade017a 100644 --- a/src/doc/it/tutorial/index.rst +++ b/src/doc/it/tutorial/index.rst @@ -15,9 +15,7 @@ un'alternativa adeguata, libera e open-source a Maple, Mathematica, Magma e MATLAB. Questo tutorial è la via migliore per familiarizzare con Sage in poche ore e può -essere letto in HTML o PDF, oppure direttamente dal Notebook di Sage (fare click -su "Help" e poi su "Tutorial" per seguire il tutorial in modo interattivo -dall'interno di Sage). +essere letto in HTML o PDF. .. toctree:: @@ -32,4 +30,3 @@ Indici e tabelle * :ref:`genindex` * :ref:`modindex` * :ref:`cerca` - diff --git a/src/doc/it/tutorial/introduction.rst b/src/doc/it/tutorial/introduction.rst index e72e4ef25e1..7e388e04dfc 100644 --- a/src/doc/it/tutorial/introduction.rst +++ b/src/doc/it/tutorial/introduction.rst @@ -2,14 +2,12 @@ Introduzione ************ Questo tutorial dovrebbe richiedere circa 3/4 ore per -una lettura completa. Lo si può leggere in versione HTML o PDF, o dal notebook Sage; -fare clic su "Help", poi fare clic su "Tutorial" per leggere interattivamente -il tutorial dall'interno di Sage. +una lettura completa. Lo si può leggere in versione HTML o PDF. Nonostante molto in Sage sia implementato usando Python, la conoscenza di Python non è un prerequisito per la lettura di questo tutorial. Per chi volesse imparare il Python (un linguaggio molto divertente!) allo stesso tempo, ci sono molte risorse -eccellenti e libere per farlo tra le quali [PyT]_ e [Dive]_. +eccellenti e libere per farlo tra le quali [PyT]_ e [PyB]_. Se si vuole solo provare velocemente Sage, questo tutorial è il punto di partenza adatto. Per esempio: @@ -58,7 +56,7 @@ Installazione ============= Se non si ha Sage installato su un computer e si vogliono solamente -provare alcuni comandi, si può usare online all'indirizzo http://www.sagenb.org. +provare alcuni comandi, si può usare online all'indirizzo https://sagecell.sagemath.org/. Si veda la Sage Installation Guide nella sezione documentazione della homepage di Sage [Sage]_ per istruzioni sull'installazione di Sage sul proprio computer. @@ -123,7 +121,7 @@ Obiettivi di lungo periodo per Sage sorgente ed è persino concesso di archiviare la versione di Sage che si è utilizzata. - **Facile da compilare:** Sage dovrebbe essere facile da compilare dal sorgente per - gli utenti Linux, OS X e Windows. Questo garantisce maggiore flessibilità agli utenti + gli utenti Linux, macOS e Windows. Questo garantisce maggiore flessibilità agli utenti di modificare il sistema. - **Cooperazione:** Fornire un interfaccia robusta alla maggior parte degli altri sistemi @@ -138,9 +136,10 @@ Obiettivi di lungo periodo per Sage Bisogna anche raggiungere un alto livello di supporto agli utenti. -.. [Dive] (en) Tuffati in Python, Liberamente disponibile in linea - all'indirizzo: http://www.diveintopython.net +.. [PyB] (en) The Python Beginner's Guide, + https://wiki.python.org/moin/BeginnersGuide -.. [PyT] (en) Il tutorial Python, http://www.python.org/ +.. [PyT] (en) The Python Tutorial, + https://docs.python.org/3/tutorial/ -.. [Sage] (en) Sage, http://www.sagemath.org +.. [Sage] (en) Sage, https://www.sagemath.org diff --git a/src/doc/it/tutorial/tour_algebra.rst b/src/doc/it/tutorial/tour_algebra.rst index 7ef0b3d799d..c745905ab05 100644 --- a/src/doc/it/tutorial/tour_algebra.rst +++ b/src/doc/it/tutorial/tour_algebra.rst @@ -393,6 +393,7 @@ nell'esempio seguente: sage: maxima.eval("diff(f,w)") '(bessel_y(v-1,w)-bessel_y(v+1,w))/2' -.. [GAP] (en) The GAP Group, ``GAP - Groups, Algorithms, and Programming``, http://www.gap-system.org +.. [GAP] (en) The GAP Group, GAP - Groups, Algorithms, and + Programming, Version 4.11; 2021, https://www.gap-system.org -.. [Max] (en) Maxima, http://maxima.sf.net/ +.. [Max] (en) Maxima, Version 5.45; 2021, http://maxima.sf.net/ From 5d190dd754444367f9728bc24d0f1616502aa3a2 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 3 Oct 2021 18:05:26 +0900 Subject: [PATCH 235/511] Use raw docstring to prevent invalid escape warning --- src/sage/rings/function_field/ideal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/function_field/ideal.py b/src/sage/rings/function_field/ideal.py index 3dbadab335c..e1a96b3d171 100644 --- a/src/sage/rings/function_field/ideal.py +++ b/src/sage/rings/function_field/ideal.py @@ -2269,7 +2269,7 @@ def gens_two(self): @cached_method def _gens_two(self): - """ + r""" Return a set of two generators of the integral ideal, that is the denominator times this fractional ideal. From 0a77fa52ca71ec76aca7ad9a7867b66828e6c761 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 3 Oct 2021 18:34:31 +0900 Subject: [PATCH 236/511] Drop use of _gens_two.cache --- src/sage/rings/function_field/ideal.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/function_field/ideal.py b/src/sage/rings/function_field/ideal.py index e1a96b3d171..8c40ae37398 100644 --- a/src/sage/rings/function_field/ideal.py +++ b/src/sage/rings/function_field/ideal.py @@ -2175,10 +2175,12 @@ def __pow__(self, mod): sage: I = O.ideal(y) sage: J = O.ideal(x + y) sage: S = I / J - sage: S^100 == I^100 / J^100 - True + sage: a = S^100 sage: _ = S.gens_two() - sage: S^100 == I^100 / J^100 # faster + sage: b = S^100 # faster + sage: b == I^100 / J^100 + True + sage: b == a True """ if mod > 2 and self._gens_two_vecs is not None: @@ -2195,10 +2197,7 @@ def __pow__(self, mod): J = [ppow * v for v in I] else: p, q = self._gens_two_vecs - if len(self._gens_two.cache) == 2: - _, q = self._gens_two.cache - else: - q = sum(e1 * e2 for e1,e2 in zip(O.basis(), q)) + q = sum(e1 * e2 for e1,e2 in zip(O.basis(), q)) ppow = p**mod qpow = O._coordinate_vector(q**mod) J = [ppow * v for v in I] + [mul(qpow,v) for v in I] From fa79b1020329a8a616be4a315451db2cc85c88f0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 09:45:38 -0700 Subject: [PATCH 237/511] Add missing imports of sage.rings.abc --- src/sage/functions/special.py | 1 + src/sage/probability/random_variable.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index bc43c362141..63083a617a0 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -158,6 +158,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +import sage.rings.abc from sage.rings.integer import Integer from sage.misc.latex import latex from sage.rings.all import ZZ diff --git a/src/sage/probability/random_variable.py b/src/sage/probability/random_variable.py index bdb666dfeab..47d108996f0 100644 --- a/src/sage/probability/random_variable.py +++ b/src/sage/probability/random_variable.py @@ -15,6 +15,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +import sage.rings.abc from sage.structure.parent import Parent from sage.functions.log import log from sage.functions.all import sqrt From 94fd9c52828b628f2417aa85ce2fe694545424a6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 09:48:50 -0700 Subject: [PATCH 238/511] is_{Real,Complex}[Double]Field: In doctests, add deprecation warning to expected output --- src/sage/rings/complex_double.pyx | 4 ++++ src/sage/rings/complex_mpfr.pyx | 4 ++++ src/sage/rings/real_double.pyx | 4 ++++ src/sage/rings/real_mpfr.pyx | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 6977939b789..7a2d45d1028 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -123,6 +123,10 @@ def is_ComplexDoubleField(x): sage: from sage.rings.complex_double import is_ComplexDoubleField sage: is_ComplexDoubleField(CDF) + doctest:warning... + DeprecationWarning: is_ComplexDoubleField is deprecated; + use isinstance(..., sage.rings.abc.ComplexDoubleField) instead + See https://trac.sagemath.org/32610 for details. True sage: is_ComplexDoubleField(ComplexField(53)) False diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index d51bbdbc469..3021ab5d177 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -169,6 +169,10 @@ def is_ComplexField(x): sage: from sage.rings.complex_mpfr import is_ComplexField as is_CF sage: is_CF(ComplexField()) + doctest:warning... + DeprecationWarning: is_ComplexField is deprecated; + use isinstance(..., sage.rings.abc.ComplexField) instead + See https://trac.sagemath.org/32610 for details. True sage: is_CF(ComplexField(12)) True diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index bccbc382bff..d3ad8ecfb0e 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -84,6 +84,10 @@ def is_RealDoubleField(x): sage: from sage.rings.real_double import is_RealDoubleField sage: is_RealDoubleField(RDF) + doctest:warning... + DeprecationWarning: is_RealDoubleField is deprecated; + use isinstance(..., sage.rings.abc.RealDoubleField) instead + See https://trac.sagemath.org/32610 for details. True sage: is_RealDoubleField(RealField(53)) False diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index cefe99b6c1c..bd9b7931463 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -5906,6 +5906,10 @@ def is_RealField(x): EXAMPLES:: sage: sage.rings.real_mpfr.is_RealField(RR) + doctest:warning... + DeprecationWarning: is_RealField is deprecated; + use isinstance(..., sage.rings.abc.RealField) instead + See https://trac.sagemath.org/32610 for details. True sage: sage.rings.real_mpfr.is_RealField(CC) False From dd7e96c442e45b509ee607a6cbd96f2ff7bbefdc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 14:45:50 -0700 Subject: [PATCH 239/511] src/sage/schemes/elliptic_curves/ell_number_field.py: Add missing import --- src/sage/schemes/elliptic_curves/ell_number_field.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index f0bcda573df..097ca89624d 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -85,6 +85,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +import sage.rings.abc from .ell_field import EllipticCurve_field from .ell_generic import is_EllipticCurve from .ell_point import EllipticCurvePoint_number_field From 006374980e227e2e15b9324d3a3b47b2290d7570 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 14:55:25 -0700 Subject: [PATCH 240/511] src/sage/features/sagemath.py: Add features for modules that were optional extensions --- src/sage/features/sagemath.py | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index 1172b6a3ff6..f18e5e79e88 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -19,6 +19,38 @@ def __init__(self): PythonModule.__init__(self, 'sage.graphs.graph') +class sage__graphs__bliss(PythonModule): + + def __init__(self): + # Currently part of sagemath_standard, conditionally built. + # Will be changed to spkg='sagemath_bliss' later + PythonModule.__init__(self, 'sage.graphs.bliss', spkg='bliss') + + +class sage__graphs__graph_decompositions__tdlib(PythonModule): + + def __init__(self): + # Currently part of sagemath_standard, conditionally built. + # Will be changed to spkg='sagemath_tdlib' later + PythonModule.__init__(self, 'sage.graphs.graph_decompositions.tdlib', spkg='tdlib') + + +class sage__graphs__mcqd(PythonModule): + + def __init__(self): + # Currently part of sagemath_standard, conditionally built. + # Will be changed to spkg='sagemath_mcqd' later + PythonModule.__init__(self, 'sage.graphs.mcqd', spkg='mcqd') + + +class sage__matrix__matrix_gfpn_dense(PythonModule): + + def __init__(self): + # Currently part of sagemath_standard, conditionally built. + # Will be changed to spkg='sagemath_meataxe' later + PythonModule.__init__(self, 'sage.matrix.matrix_gfpn_dense', spkg='meataxe') + + class sage__rings__number_field(PythonModule): def __init__(self): @@ -56,6 +88,14 @@ def sage_optional_tags(): yield 'sage.combinat' if sage__graphs().is_present(): yield 'sage.graphs' + if sage__graphs__bliss().is_present(): + yield 'sage.graphs.bliss' + if sage__graphs__graph_decompositions__tdlib().is_present(): + yield 'sage.graphs.graph_decompositions.tdlib' + if sage__graphs__mcqd().is_present(): + yield 'sage.graphs.mcqd' + if sage__matrix__matrix_gfpn_dense().is_present(): + yield 'sage.matrix.matrix_gfpn_dense' if sage__rings__number_field().is_present(): yield 'sage.rings.number_field' if sage__rings__real_double().is_present(): From d6c6e90f5d4e8653fcd776bc534aa06aa2effdd9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 17:26:27 -0700 Subject: [PATCH 241/511] sage.rings.abc: Add {Real,Complex}{Ball,Interval}Field --- src/sage/rings/abc.pyx | 32 ++++++++++++++++++++++++ src/sage/rings/complex_arb.pyx | 4 ++- src/sage/rings/complex_interval_field.py | 3 ++- src/sage/rings/real_arb.pyx | 3 ++- src/sage/rings/real_mpfi.pxd | 4 +-- src/sage/rings/real_mpfi.pyx | 2 +- 6 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index c65e03d9ed0..66ad7030fc7 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -10,6 +10,22 @@ cdef class RealField(Field): pass +class RealBallField(Field): + r""" + Abstract base class for :class:`~sage.rings.real_arb.RealBallField`. + """ + + pass + + +cdef class RealIntervalField(Field): + r""" + Abstract base class for :class:`~sage.rings.real_mpfi.RealIntervalField_class`. + """ + + pass + + cdef class RealDoubleField(Field): r""" Abstract base class for :class:`~sage.rings.real_double.RealDoubleField_class`. @@ -26,6 +42,22 @@ cdef class ComplexField(Field): pass +class ComplexBallField(Field): + r""" + Abstract base class for :class:`~sage.rings.complex_arb.ComplexBallField`. + """ + + pass + + +class ComplexIntervalField(Field): + r""" + Abstract base class for :class:`~sage.rings.complex_interval_field.ComplexIntervalField_class`. + """ + + pass + + cdef class ComplexDoubleField(Field): r""" Abstract base class for :class:`~sage.rings.complex_double.ComplexDoubleField_class`. diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index 2fc0a3bb420..2e2643946da 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -147,6 +147,7 @@ from cysignals.signals cimport sig_on, sig_str, sig_off, sig_error import sage.categories.fields +cimport sage.rings.abc cimport sage.rings.rational from cpython.float cimport PyFloat_AS_DOUBLE @@ -301,7 +302,8 @@ cdef int acb_calc_func_callback(acb_ptr out, const acb_t inp, void * param, finally: sig_on() -class ComplexBallField(UniqueRepresentation, Field): + +class ComplexBallField(UniqueRepresentation, sage.rings.abc.ComplexBallField): r""" An approximation of the field of complex numbers using pairs of mid-rad intervals. diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index cee580b22a3..e046891c437 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -40,6 +40,7 @@ from .integer_ring import ZZ from .rational_field import QQ from .ring import Field +import sage.rings.abc from . import integer from . import complex_interval import weakref @@ -93,7 +94,7 @@ def ComplexIntervalField(prec=53, names=None): return C -class ComplexIntervalField_class(Field): +class ComplexIntervalField_class(sage.rings.abc.ComplexIntervalField): """ The field of complex (interval) numbers. diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 66a9d7bda06..43b6b6da5fd 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -219,6 +219,7 @@ from sage.libs.mpfr cimport MPFR_RNDN, MPFR_RNDU, MPFR_RNDD, MPFR_RNDZ from sage.structure.element cimport Element, ModuleElement, RingElement from sage.rings.ring cimport Field +import sage.rings.abc from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational from sage.rings.real_double cimport RealDoubleElement @@ -320,7 +321,7 @@ cdef int arb_to_mpfi(mpfi_t target, arb_t source, const long precision) except - mpfr_clear(right) -class RealBallField(UniqueRepresentation, Field): +class RealBallField(UniqueRepresentation, sage.rings.abc.RealBallField): r""" An approximation of the field of real numbers using mid-rad intervals, also known as balls. diff --git a/src/sage/rings/real_mpfi.pxd b/src/sage/rings/real_mpfi.pxd index c32dcc959d0..5466a5f575f 100644 --- a/src/sage/rings/real_mpfi.pxd +++ b/src/sage/rings/real_mpfi.pxd @@ -2,7 +2,7 @@ from sage.libs.mpfr.types cimport mpfr_prec_t from sage.libs.mpfi.types cimport mpfi_t from sage.rings.ring cimport Field - +cimport sage.rings.abc from sage.structure.element cimport RingElement from .rational cimport Rational @@ -10,7 +10,7 @@ from .real_mpfr cimport RealField_class cdef class RealIntervalFieldElement(RingElement) # forward decl -cdef class RealIntervalField_class(Field): +cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): cdef mpfr_prec_t __prec cdef bint sci_not # Cache RealField instances for the lower, upper, and middle bounds. diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 2bfdc5f2512..ce83e1ddf4e 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -345,7 +345,7 @@ cpdef RealIntervalField_class RealIntervalField(prec=53, sci_not=False): return R -cdef class RealIntervalField_class(Field): +cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): """ Class of the real interval field. From 8964311a5e358b93a72381faa550e31e5d9ed90d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 4 Oct 2021 09:26:51 +0900 Subject: [PATCH 242/511] Some cleanup and micro-optimizations to (skew) tableau. --- src/sage/combinat/lr_tableau.py | 5 +- src/sage/combinat/skew_tableau.py | 87 +++++++++++++++++------------- src/sage/combinat/tableau.py | 32 +++++------ src/sage/combinat/tableau_tuple.py | 2 +- 4 files changed, 71 insertions(+), 55 deletions(-) diff --git a/src/sage/combinat/lr_tableau.py b/src/sage/combinat/lr_tableau.py index 6d14d998066..a300846d8de 100644 --- a/src/sage/combinat/lr_tableau.py +++ b/src/sage/combinat/lr_tableau.py @@ -116,12 +116,12 @@ def check(self): Traceback (most recent call last): ... ValueError: [[1, 1, 2], [3, 3], [4]] is not an element of - Littlewood-Richardson Tableaux of shape [3, 2, 1] and weight ([2, 1], [2, 1]). + Littlewood-Richardson Tableaux of shape [3, 2, 1] and weight ([2, 1], [2, 1]) sage: LR([[1, 1, 2, 3], [3], [4]]) Traceback (most recent call last): ... ValueError: [[1, 1, 2, 3], [3], [4]] is not an element of - Littlewood-Richardson Tableaux of shape [3, 2, 1] and weight ([2, 1], [2, 1]). + Littlewood-Richardson Tableaux of shape [3, 2, 1] and weight ([2, 1], [2, 1]) sage: LR([[1, 1, 3], [3, 3], [4]]) Traceback (most recent call last): ... @@ -304,3 +304,4 @@ def _tableau_join(t1, t2, shift=0): """ return [[e1 for e1 in row1] + [e2+shift for e2 in row2 if e2 is not None] for (row1, row2) in zip_longest(t1, t2, fillvalue=[])] + diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index c04128ce691..99ef0d512e3 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -437,7 +437,8 @@ def size(self): sage: SkewTableau([[None, 2], [1, 3]]).size() 3 """ - return sum(len([x for x in row if x is not None]) for row in self) + one = ZZ.one() + return sum(one for row in self for x in row if x is not None) def conjugate(self): """ @@ -539,10 +540,8 @@ def to_permutation(self): [] """ from sage.combinat.permutation import Permutation - word = [] - for row in reversed(self): - word += [i for i in row if i is not None] - return Permutation(word) + perm = [i for row in reversed(self) for i in row if i is not None] + return Permutation(perm) def weight(self): r""" @@ -591,7 +590,7 @@ def weight(self): sage: all(by_word(t) == SkewTableau(t).weight() for t in SST) True """ - if len(self) == 0 or all(c is None for row in self for c in row): + if (not self) or all(c is None for row in self for c in row): return [] m = max(c for row in self for c in row if c is not None) if m is None: @@ -623,10 +622,7 @@ def is_standard(self): """ # Check to make sure that it is filled with 1...size w = [i for row in self for i in row if i is not None] - if sorted(w) != list(range(1, len(w) + 1)): - return False - else: - return self.is_semistandard() + return sorted(w) == list(range(1, len(w) + 1)) and self.is_semistandard() def is_semistandard(self): """ @@ -683,9 +679,8 @@ def to_tableau(self): if self.inner_size() != 0: raise ValueError("the inner size of the skew tableau must be 0") - else: - from sage.combinat.tableau import Tableau - return Tableau(self[:]) + from sage.combinat.tableau import Tableau + return Tableau(self[:]) def restrict(self, n): """ @@ -708,9 +703,8 @@ def restrict(self, n): sage: SkewTableau([[None,1],[1],[2]]).restrict(1) [[None, 1], [1]] """ - t = self[:] return SkewTableau([z for z in [[y for y in x if y is None or y <= n] - for x in t] if z]) + for x in self] if z]) def restriction_outer_shape(self, n): """ @@ -743,9 +737,10 @@ def restriction_outer_shape(self, n): sage: T.restriction_outer_shape(19) [4, 3, 1] """ - from sage.combinat.partition import Partition - res = [len([y for y in row if y is None or y <= n]) for row in self] - return Partition(res) + from sage.combinat.partition import _Partitions + one = ZZ.one() + res = [sum(one for y in row if y is None or y <= n) for row in self] + return _Partitions(res) def restriction_shape(self, n): """ @@ -821,7 +816,7 @@ def to_chain(self, max_entry=None): [[1]] """ if max_entry is None: - if len(self) == 0 or all(c is None for row in self for c in row): + if (not self) or all(c is None for row in self for c in row): max_entry = 0 else: max_entry = max(c for row in self for c in row if c is not None) @@ -1214,38 +1209,49 @@ def bender_knuth_involution(self, k, rows=None, check=True): EXAMPLES:: - sage: t = SkewTableau([[None,None,None,4,4,5,6,7],[None,2,4,6,7,7,7],[None,4,5,8,8,9],[None,6,7,10],[None,8,8,11],[None],[4]]) + sage: t = SkewTableau([[None,None,None,4,4,5,6,7],[None,2,4,6,7,7,7], + ....: [None,4,5,8,8,9],[None,6,7,10],[None,8,8,11],[None],[4]]) sage: t - [[None, None, None, 4, 4, 5, 6, 7], [None, 2, 4, 6, 7, 7, 7], [None, 4, 5, 8, 8, 9], [None, 6, 7, 10], [None, 8, 8, 11], [None], [4]] + [[None, None, None, 4, 4, 5, 6, 7], [None, 2, 4, 6, 7, 7, 7], + [None, 4, 5, 8, 8, 9], [None, 6, 7, 10], [None, 8, 8, 11], [None], [4]] sage: t.bender_knuth_involution(1) - [[None, None, None, 4, 4, 5, 6, 7], [None, 1, 4, 6, 7, 7, 7], [None, 4, 5, 8, 8, 9], [None, 6, 7, 10], [None, 8, 8, 11], [None], [4]] + [[None, None, None, 4, 4, 5, 6, 7], [None, 1, 4, 6, 7, 7, 7], + [None, 4, 5, 8, 8, 9], [None, 6, 7, 10], [None, 8, 8, 11], [None], [4]] sage: t.bender_knuth_involution(4) - [[None, None, None, 4, 5, 5, 6, 7], [None, 2, 4, 6, 7, 7, 7], [None, 5, 5, 8, 8, 9], [None, 6, 7, 10], [None, 8, 8, 11], [None], [5]] + [[None, None, None, 4, 5, 5, 6, 7], [None, 2, 4, 6, 7, 7, 7], + [None, 5, 5, 8, 8, 9], [None, 6, 7, 10], [None, 8, 8, 11], [None], [5]] sage: t.bender_knuth_involution(5) - [[None, None, None, 4, 4, 5, 6, 7], [None, 2, 4, 5, 7, 7, 7], [None, 4, 6, 8, 8, 9], [None, 5, 7, 10], [None, 8, 8, 11], [None], [4]] + [[None, None, None, 4, 4, 5, 6, 7], [None, 2, 4, 5, 7, 7, 7], + [None, 4, 6, 8, 8, 9], [None, 5, 7, 10], [None, 8, 8, 11], [None], [4]] sage: t.bender_knuth_involution(6) - [[None, None, None, 4, 4, 5, 6, 6], [None, 2, 4, 6, 6, 7, 7], [None, 4, 5, 8, 8, 9], [None, 6, 7, 10], [None, 8, 8, 11], [None], [4]] + [[None, None, None, 4, 4, 5, 6, 6], [None, 2, 4, 6, 6, 7, 7], + [None, 4, 5, 8, 8, 9], [None, 6, 7, 10], [None, 8, 8, 11], [None], [4]] sage: t.bender_knuth_involution(666) == t True sage: t.bender_knuth_involution(4, 2) == t True sage: t.bender_knuth_involution(4, 3) - [[None, None, None, 4, 4, 5, 6, 7], [None, 2, 4, 6, 7, 7, 7], [None, 5, 5, 8, 8, 9], [None, 6, 7, 10], [None, 8, 8, 11], [None], [4]] + [[None, None, None, 4, 4, 5, 6, 7], [None, 2, 4, 6, 7, 7, 7], + [None, 5, 5, 8, 8, 9], [None, 6, 7, 10], [None, 8, 8, 11], [None], [4]] The Bender--Knuth involution is an involution:: sage: t = SkewTableau([[None,3,4,4],[None,6,10],[7,7,11],[18]]) - sage: all(t.bender_knuth_involution(k).bender_knuth_involution(k) == t for k in range(1,4)) + sage: all(t.bender_knuth_involution(k).bender_knuth_involution(k) + ....: == t for k in range(1,4)) True The same for the single switches:: - sage: all(t.bender_knuth_involution(k, j).bender_knuth_involution(k, j) == t for k in range(1,5) for j in range(1, 5)) + sage: all(t.bender_knuth_involution(k, j).bender_knuth_involution(k, j) + ....: == t for k in range(1,5) for j in range(1, 5)) True Locality of the Bender--Knuth involutions:: - sage: all(t.bender_knuth_involution(k).bender_knuth_involution(l) == t.bender_knuth_involution(l).bender_knuth_involution(k) for k in range(1,5) for l in range(1,5) if abs(k - l) > 1) + sage: all(t.bender_knuth_involution(k).bender_knuth_involution(l) + ....: == t.bender_knuth_involution(l).bender_knuth_involution(k) + ....: for k in range(1,5) for l in range(1,5) if abs(k - l) > 1) True TESTS:: @@ -1494,7 +1500,7 @@ def cells_by_content(self, c): sage: s.cells_by_content(-2) [(2, 0)] """ - if len(self) == 0: + if not self: return [] if c >= 0: @@ -1704,8 +1710,10 @@ def __contains__(self, x): def from_expr(self, expr): """ - Return a :class:`SkewTableau` from a MuPAD-Combinat expr for a skew - tableau. The first list in ``expr`` is the inner shape of the skew + Return a :class:`SkewTableau` from a MuPAD-Combinat expr for + a skew tableau. + + The first list in ``expr`` is the inner shape of the skew tableau. The second list are the entries in the rows of the skew tableau from bottom to top. @@ -1735,7 +1743,7 @@ def from_chain(self, chain): [[None, 1, 2], [None, 3, 4], [5]] """ shape = chain[-1] - T = [[None for _ in range(r)] for r in shape] + T = [[None]*r for r in shape] for i in range(1, len(chain)): la = chain[i] mu = chain[i - 1] @@ -1760,11 +1768,16 @@ def from_shape_and_word(self, shape, word): sage: SkewTableaux().from_shape_and_word(shape, word) [[None, 1, 3], [None, 2], [4]] """ - st = [[None] * row_length for row_length in shape[0]] + outer, inner = shape + st = [[None] * row_length for row_length in outer] w_count = 0 - for i in reversed(range(len(shape[0]))): - for j in range(shape[0][i]): - if i >= len(shape[1]) or j >= shape[1][i]: + for i in reversed(range(len(inner), len(outer))): + for j in range(outer[i]): + st[i][j] = word[w_count] + w_count += 1 + for i in reversed(range(len(inner))): + for j in range(outer[i]): + if j >= inner[i]: st[i][j] = word[w_count] w_count += 1 return self.element_class(self, st) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index ab24316debc..294110aeb70 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -175,11 +175,11 @@ class Tableau(ClonableList, metaclass=InheritComparisonClasscallMetaclass): sage: Tableau([[1],[2,3]]) Traceback (most recent call last): ... - ValueError: A tableau must be a list of iterables of weakly decreasing length. + ValueError: a tableau must be a list of iterables of weakly decreasing length sage: Tableau([1,2,3]) Traceback (most recent call last): ... - ValueError: A tableau must be a list of iterables. + ValueError: a tableau must be a list of iterables """ @staticmethod @@ -208,7 +208,7 @@ def __classcall_private__(cls, t): try: t = [tuple(_) for _ in t] except TypeError: - raise ValueError("A tableau must be a list of iterables.") + raise ValueError("a tableau must be a list of iterables") return Tableaux_all().element_class(Tableaux_all(), t) @@ -330,16 +330,16 @@ def check(self): sage: t = Tableau([[None, None, 1], [2, 4], [3, 4, 5]]) # indirect doctest Traceback (most recent call last): ... - ValueError: A tableau must be a list of iterables of weakly decreasing length. + ValueError: a tableau must be a list of iterables of weakly decreasing length """ # Check that it has partition shape. That's all we require from a # general tableau. - lens = [len(_) for _ in self] + lens = [len(row) for row in self] for (a, b) in zip(lens, lens[1:]): if a < b: - raise ValueError("A tableau must be a list of iterables of weakly decreasing length.") + raise ValueError("a tableau must be a list of iterables of weakly decreasing length") if lens and lens[-1] == 0: - raise ValueError("A tableau must not have empty rows.") + raise ValueError("a tableau must not have empty rows") def _repr_(self): """ @@ -4884,7 +4884,8 @@ def from_chain(chain): for j in range(len(chain[i - 1])): for k in range(chain[i - 1][j]): res[j][k] = i -1 - return Tableau(res) + T = Tableaux_all() + return T.element_class(T, res) def from_shape_and_word(shape, w, convention="French"): @@ -4919,7 +4920,7 @@ def from_shape_and_word(shape, w, convention="French"): sage: from_shape_and_word(shape, word) [[1, 3], [2], [4]] sage: word = Word(flatten(t)) - sage: from_shape_and_word(shape, word, convention = "English") + sage: from_shape_and_word(shape, word, convention="English") [[1, 3], [2], [4]] """ res = [] @@ -4927,11 +4928,12 @@ def from_shape_and_word(shape, w, convention="French"): if convention == "French": shape = reversed(shape) for l in shape: - res.append( list(w[j:j+l]) ) + res.append( tuple(w[j:j+l]) ) j += l if convention == "French": res.reverse() - return Tableau(res) + T = Tableaux_all() + return T.element_class(T, res) class IncreasingTableau(Tableau): @@ -5324,7 +5326,7 @@ class Tableaux(UniqueRepresentation, Parent): sage: Tableaux(3)([[1, 1]]) Traceback (most recent call last): ... - ValueError: [[1, 1]] is not an element of Tableaux of size 3. + ValueError: [[1, 1]] is not an element of Tableaux of size 3 sage: t0 = Tableau([[1]]) sage: t1 = Tableaux()([[1]]) @@ -5498,10 +5500,10 @@ def _element_constructor_(self, t): sage: T([[1,2]]) Traceback (most recent call last): ... - ValueError: [[1, 2]] is not an element of Tableaux of size 3. + ValueError: [[1, 2]] is not an element of Tableaux of size 3 """ if t not in self: - raise ValueError("%s is not an element of %s." % (t, self)) + raise ValueError("%s is not an element of %s" % (t, self)) return self.element_class(self, t) @@ -5541,7 +5543,7 @@ def __contains__(self, x): except TypeError: return False # any list of lists of partition shape is a tableau - return [len(_) for _ in x] in _Partitions + return [len(row) for row in x] in _Partitions else: return False diff --git a/src/sage/combinat/tableau_tuple.py b/src/sage/combinat/tableau_tuple.py index 9e8e689ac0f..ac3f23b1375 100644 --- a/src/sage/combinat/tableau_tuple.py +++ b/src/sage/combinat/tableau_tuple.py @@ -346,7 +346,7 @@ class TableauTuple(CombinatorialElement): sage: TableauTuple([[1],[2,3]]) Traceback (most recent call last): ... - ValueError: A tableau must be a list of iterables. + ValueError: a tableau must be a list of iterables sage: TestSuite( TableauTuple([ [[1,2],[3,4]], [[1,2],[3,4]] ]) ).run() sage: TestSuite( TableauTuple([ [[1,2],[3,4]], [], [[1,2],[3,4]] ]) ).run() From 7ce73e69d0042961c557756bbbbf25f4427445e9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 17:40:39 -0700 Subject: [PATCH 243/511] git grep -l -E 'is_(Real|Complex)(Interval|Ball)Field' | xargs sed -E -i.bak 's/^from sage[.]rings.*import is_((Real|Complex)(Interval|Ball)Field) *$/import sage.rings.abc/;s/is_((Real|Complex)(Interval|Ball)Field)[(]([^)]*)[)]/isinstance(\4, sage.rings.abc.\1)/g;' --- src/sage/rings/complex_interval_field.py | 2 +- src/sage/rings/number_field/number_field.py | 2 +- src/sage/rings/polynomial/polynomial_element.pyx | 8 ++++---- src/sage/rings/qqbar.py | 4 ++-- src/sage/rings/real_interval_absolute.pyx | 2 +- src/sage/rings/real_interval_field.py | 2 +- src/sage/rings/real_mpfi.pyx | 6 +++--- src/sage/symbolic/expression.pyx | 6 +++--- src/sage/symbolic/ring.pyx | 2 +- src/sage/symbolic/subring.py | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index e046891c437..ff7830505d0 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -49,7 +49,7 @@ from sage.misc.cachefunc import cached_method -def is_ComplexIntervalField(x): +def isinstance(x, sage.rings.abc.ComplexIntervalField): """ Check if ``x`` is a :class:`ComplexIntervalField`. diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 3ad7ffa26ef..1752d3fb214 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -9949,7 +9949,7 @@ def hilbert_symbol(self, a, b, P = None): from sage.rings.complex_interval_field import is_ComplexIntervalField from sage.rings.real_mpfr import is_RealField from sage.rings.all import (AA, CDF, QQbar, RDF) - if is_ComplexField(codom) or is_ComplexIntervalField(codom) or \ + if is_ComplexField(codom) or isinstance(codom, sage.rings.abc.ComplexIntervalField) or \ codom is CDF or codom is QQbar: if P(self.gen()).imag() == 0: raise ValueError("Possibly real place (=%s) given as complex embedding in hilbert_symbol. Is it real or complex?" % P) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index f7807221d55..0d2cfda744d 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -92,7 +92,7 @@ CC = ComplexField() from sage.rings.real_double import RDF from sage.rings.complex_double import CDF -from sage.rings.real_mpfi import is_RealIntervalField +import sage.rings.abc from sage.structure.coerce cimport coercion_model from sage.structure.element import coerce_binop @@ -8030,7 +8030,7 @@ cdef class Polynomial(CommutativeAlgebraElement): # and complex root isolation and for p-adic factorization if (is_IntegerRing(K) or is_RationalField(K) or is_AlgebraicRealField(K)) and \ - (is_AlgebraicRealField(L) or is_RealIntervalField(L)): + (is_AlgebraicRealField(L) or isinstance(L, sage.rings.abc.RealIntervalField)): from sage.rings.polynomial.real_roots import real_roots @@ -8060,11 +8060,11 @@ cdef class Polynomial(CommutativeAlgebraElement): if (is_IntegerRing(K) or is_RationalField(K) or is_AlgebraicField_common(K) or input_gaussian) and \ - (is_ComplexIntervalField(L) or is_AlgebraicField_common(L)): + (isinstance(L, sage.rings.abc.ComplexIntervalField) or is_AlgebraicField_common(L)): from sage.rings.polynomial.complex_roots import complex_roots - if is_ComplexIntervalField(L): + if isinstance(L, sage.rings.abc.ComplexIntervalField): rts = complex_roots(self, min_prec=L.prec()) elif is_AlgebraicField(L): rts = complex_roots(self, retval='algebraic') diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index a63315f93b1..a36b5de3c72 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -5013,7 +5013,7 @@ def interval_exact(self, field): sage: (a - b).interval_exact(CIF) 0 """ - if not is_ComplexIntervalField(field): + if not isinstance(field, sage.rings.abc.ComplexIntervalField): raise ValueError("AlgebraicNumber interval_exact requires a ComplexIntervalField") rfld = field._real_field() re = self.real().interval_exact(rfld) @@ -5910,7 +5910,7 @@ def _complex_mpfr_field_(self, field): sage: AA(golden_ratio)._complex_mpfr_field_(ComplexField(100)) 1.6180339887498948482045868344 """ - if is_ComplexIntervalField(field): + if isinstance(field, sage.rings.abc.ComplexIntervalField): return field(self.interval(field._real_field())) else: return field(self.real_number(field._real_field())) diff --git a/src/sage/rings/real_interval_absolute.pyx b/src/sage/rings/real_interval_absolute.pyx index 2b193145eb3..16a275aab2b 100644 --- a/src/sage/rings/real_interval_absolute.pyx +++ b/src/sage/rings/real_interval_absolute.pyx @@ -185,7 +185,7 @@ cdef class RealIntervalAbsoluteField_class(Field): """ if isinstance(R, RealIntervalAbsoluteField_class): return self._absprec < (R)._absprec - elif is_RealIntervalField(R): + elif isinstance(R, sage.rings.abc.RealIntervalField): return True else: return RR_min_prec.has_coerce_map_from(R) diff --git a/src/sage/rings/real_interval_field.py b/src/sage/rings/real_interval_field.py index 97a32ae67cc..8a00d507bc4 100644 --- a/src/sage/rings/real_interval_field.py +++ b/src/sage/rings/real_interval_field.py @@ -7,7 +7,7 @@ from sage.rings.real_mpfi import RealIntervalField_class, RealIntervalFieldElement -def is_RealIntervalField(x): +def isinstance(x, sage.rings.abc.RealIntervalField): """ Check if ``x`` is a :class:`RealIntervalField_class`. diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index ce83e1ddf4e..4bc459f2695 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -5317,15 +5317,15 @@ def RealInterval(s, upper=None, int base=10, int pad=0, min_prec=53): # The default real interval field, with precision 53 bits RIF = RealIntervalField() -def is_RealIntervalField(x): +def isinstance(x, sage.rings.abc.RealIntervalField): """ Check if ``x`` is a :class:`RealIntervalField_class`. EXAMPLES:: - sage: sage.rings.real_mpfi.is_RealIntervalField(RIF) + sage: sage.rings.real_mpfi.isinstance(RIF, sage.rings.abc.RealIntervalField) True - sage: sage.rings.real_mpfi.is_RealIntervalField(RealIntervalField(200)) + sage: sage.rings.real_mpfi.isinstance(RealIntervalField(200, sage.rings.abc.RealIntervalField)) True """ return isinstance(x, RealIntervalField_class) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index de4720f90a7..52fa2d2e5a3 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -3565,8 +3565,8 @@ cdef class Expression(CommutativeRingElement): else: domain = RIF else: - is_interval = (is_RealIntervalField(domain) - or is_ComplexIntervalField(domain) + is_interval = (isinstance(domain, sage.rings.abc.RealIntervalField) + or isinstance(domain, sage.rings.abc.ComplexIntervalField) or is_AlgebraicField(domain) or is_AlgebraicRealField(domain)) zero = domain(0) @@ -3620,7 +3620,7 @@ cdef class Expression(CommutativeRingElement): eq_count += val.contains_zero() except (TypeError, ValueError, ArithmeticError, AttributeError) as ex: errors += 1 - if k == errors > 3 and is_ComplexIntervalField(domain): + if k == errors > 3 and isinstance(domain, sage.rings.abc.ComplexIntervalField): domain = RIF.to_prec(domain.prec()) # we are plugging in random values above, don't be surprised # if something goes wrong... diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index ffe8d7443f2..18174ae3212 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -231,7 +231,7 @@ cdef class SymbolicRing(CommutativeRing): base = R.base_ring() return base is not self and self.has_coerce_map_from(base) elif (R is InfinityRing or R is UnsignedInfinityRing - or is_RealIntervalField(R) or is_ComplexIntervalField(R) + or isinstance(R, sage.rings.abc.RealIntervalField) or isinstance(R, sage.rings.abc.ComplexIntervalField) or isinstance(R, RealBallField) or isinstance(R, ComplexBallField) or is_IntegerModRing(R) or is_FiniteField(R)): diff --git a/src/sage/symbolic/subring.py b/src/sage/symbolic/subring.py index 060ad32a5ed..832d75236bc 100644 --- a/src/sage/symbolic/subring.py +++ b/src/sage/symbolic/subring.py @@ -425,7 +425,7 @@ def _coerce_map_from_(self, P): return True elif (P is InfinityRing or - is_RealIntervalField(P) or is_ComplexIntervalField(P)): + isinstance(P, sage.rings.abc.RealIntervalField) or isinstance(P, sage.rings.abc.ComplexIntervalField)): return True elif P._is_numerical(): From a8432f910c2b61ef4f4e4d681e531e11551d64ea Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 17:50:01 -0700 Subject: [PATCH 244/511] is_{Real,Complex}{Ball,Interval}Field: Undo automatic edits --- src/sage/rings/complex_interval_field.py | 5 ++++- src/sage/rings/real_interval_field.py | 2 +- src/sage/rings/real_mpfi.pyx | 6 +++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index ff7830505d0..3c37e000154 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -49,7 +49,7 @@ from sage.misc.cachefunc import cached_method -def isinstance(x, sage.rings.abc.ComplexIntervalField): +def is_ComplexIntervalField(x): """ Check if ``x`` is a :class:`ComplexIntervalField`. @@ -61,8 +61,11 @@ def isinstance(x, sage.rings.abc.ComplexIntervalField): sage: is_CIF(CC) False """ + from sage.misc.superseded import deprecation + deprecation(32612, 'is_ComplexIntervalField is deprecated; use isinstance(..., sage.rings.abc.ComplexIntervalField) instead') return isinstance(x, ComplexIntervalField_class) + cache = {} def ComplexIntervalField(prec=53, names=None): """ diff --git a/src/sage/rings/real_interval_field.py b/src/sage/rings/real_interval_field.py index 8a00d507bc4..97a32ae67cc 100644 --- a/src/sage/rings/real_interval_field.py +++ b/src/sage/rings/real_interval_field.py @@ -7,7 +7,7 @@ from sage.rings.real_mpfi import RealIntervalField_class, RealIntervalFieldElement -def isinstance(x, sage.rings.abc.RealIntervalField): +def is_RealIntervalField(x): """ Check if ``x`` is a :class:`RealIntervalField_class`. diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 4bc459f2695..ce83e1ddf4e 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -5317,15 +5317,15 @@ def RealInterval(s, upper=None, int base=10, int pad=0, min_prec=53): # The default real interval field, with precision 53 bits RIF = RealIntervalField() -def isinstance(x, sage.rings.abc.RealIntervalField): +def is_RealIntervalField(x): """ Check if ``x`` is a :class:`RealIntervalField_class`. EXAMPLES:: - sage: sage.rings.real_mpfi.isinstance(RIF, sage.rings.abc.RealIntervalField) + sage: sage.rings.real_mpfi.is_RealIntervalField(RIF) True - sage: sage.rings.real_mpfi.isinstance(RealIntervalField(200, sage.rings.abc.RealIntervalField)) + sage: sage.rings.real_mpfi.is_RealIntervalField(RealIntervalField(200)) True """ return isinstance(x, RealIntervalField_class) From 6209c1fdab2879e042970014628459ccbdda7e7f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 18:03:22 -0700 Subject: [PATCH 245/511] src/sage/rings/complex_interval_field.py: Add deprecation warning to doctest output --- src/sage/rings/complex_interval_field.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index 3c37e000154..05758d9956b 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -56,6 +56,10 @@ def is_ComplexIntervalField(x): EXAMPLES:: sage: from sage.rings.complex_interval_field import is_ComplexIntervalField as is_CIF + doctest:warning... + DeprecationWarning: is_ComplexIntervalField is deprecated; + use isinstance(..., sage.rings.abc.ComplexIntervalField) instead + See https://trac.sagemath.org/32612 for details. sage: is_CIF(CIF) True sage: is_CIF(CC) From 5cb3d59d6724546ff37e3329cd28fe239e95fb5a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 18:04:23 -0700 Subject: [PATCH 246/511] Fix imports, consolidate isinstance calls --- src/sage/rings/number_field/number_field.py | 1 - src/sage/symbolic/expression.pyx | 4 ++-- src/sage/symbolic/ring.pyx | 7 ++++--- src/sage/symbolic/subring.py | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 1752d3fb214..d6694f1bb9a 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -9946,7 +9946,6 @@ def hilbert_symbol(self, a, b, P = None): raise ValueError("Domain of P (=%s) should be self (=%s) in self.hilbert_symbol" % (P, self)) codom = P.codomain() from sage.rings.complex_mpfr import is_ComplexField - from sage.rings.complex_interval_field import is_ComplexIntervalField from sage.rings.real_mpfr import is_RealField from sage.rings.all import (AA, CDF, QQbar, RDF) if is_ComplexField(codom) or isinstance(codom, sage.rings.abc.ComplexIntervalField) or \ diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 52fa2d2e5a3..0d2d194560c 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -3565,8 +3565,8 @@ cdef class Expression(CommutativeRingElement): else: domain = RIF else: - is_interval = (isinstance(domain, sage.rings.abc.RealIntervalField) - or isinstance(domain, sage.rings.abc.ComplexIntervalField) + is_interval = (isinstance(domain, (sage.rings.abc.RealIntervalField, + sage.rings.abc.ComplexIntervalField)) or is_AlgebraicField(domain) or is_AlgebraicRealField(domain)) zero = domain(0) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 18174ae3212..d0022b060d9 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -231,9 +231,10 @@ cdef class SymbolicRing(CommutativeRing): base = R.base_ring() return base is not self and self.has_coerce_map_from(base) elif (R is InfinityRing or R is UnsignedInfinityRing - or isinstance(R, sage.rings.abc.RealIntervalField) or isinstance(R, sage.rings.abc.ComplexIntervalField) - or isinstance(R, RealBallField) - or isinstance(R, ComplexBallField) + or isinstance(R, (sage.rings.abc.RealIntervalField, + sage.rings.abc.ComplexIntervalField, + sage.rings.abc.RealBallField, + sage.rings.abc.ComplexBallField)) or is_IntegerModRing(R) or is_FiniteField(R)): return True elif isinstance(R, GenericSymbolicSubring): diff --git a/src/sage/symbolic/subring.py b/src/sage/symbolic/subring.py index 832d75236bc..c1eb48e16ae 100644 --- a/src/sage/symbolic/subring.py +++ b/src/sage/symbolic/subring.py @@ -97,6 +97,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +import sage.rings.abc from .ring import SymbolicRing, SR from sage.categories.pushout import ConstructionFunctor from sage.structure.factory import UniqueFactory @@ -412,8 +413,6 @@ def _coerce_map_from_(self, P): return False from sage.rings.all import RLF, CLF, AA, QQbar, InfinityRing - from sage.rings.real_mpfi import is_RealIntervalField - from sage.rings.complex_interval_field import is_ComplexIntervalField if isinstance(P, type): return SR._coerce_map_from_(P) @@ -425,7 +424,8 @@ def _coerce_map_from_(self, P): return True elif (P is InfinityRing or - isinstance(P, sage.rings.abc.RealIntervalField) or isinstance(P, sage.rings.abc.ComplexIntervalField)): + isinstance(P, (sage.rings.abc.RealIntervalField, + sage.rings.abc.ComplexIntervalField))): return True elif P._is_numerical(): From be1db022c9bb35ca0875a5c7bdd8a99ede246d97 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 19:32:26 -0700 Subject: [PATCH 247/511] src/sage/rings/abc.pxd: Add cdef class RealIntervalField --- src/sage/rings/abc.pxd | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/rings/abc.pxd b/src/sage/rings/abc.pxd index ea998549070..5b2aec37eff 100644 --- a/src/sage/rings/abc.pxd +++ b/src/sage/rings/abc.pxd @@ -5,6 +5,11 @@ cdef class RealField(Field): pass +cdef class RealIntervalField(Field): + + pass + + cdef class RealDoubleField(Field): pass From 7e7f5fe8ddc7c10308584579701b556f8a13ddac Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 19:36:58 -0700 Subject: [PATCH 248/511] sage.doctest.forker: Use sage.misc.lazy_import.ensure_startup_finished --- src/sage/doctest/forker.py | 5 +++++ src/sage/misc/lazy_import.pyx | 28 ++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index 960429a8ed0..f7fe607eadf 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -2496,6 +2496,11 @@ def _run(self, runner, options, results): from importlib import import_module sage_all = import_module(options.environment) dict_all = sage_all.__dict__ + # When using global environments other than sage.all, + # make sure startup is finished so we don't get "Resolving lazy import" + # warnings. + from sage.misc.lazy_import import ensure_startup_finished + ensure_startup_finished() # Remove '__package__' item from the globals since it is not # always in the globals in an actual Sage session. dict_all.pop('__package__', None) diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 7e8b731965a..50a3bb325d4 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -79,11 +79,15 @@ cdef inline obj(x): # boolean to determine whether Sage is still starting up cdef bint startup_guard = True +cdef bint finish_startup_called = False + cpdef finish_startup(): """ + Finish the startup phase. + This function must be called exactly once at the end of the Sage - import process + import process (:mod:`~sage.all`). TESTS:: @@ -96,6 +100,24 @@ cpdef finish_startup(): global startup_guard assert startup_guard, 'finish_startup() must be called exactly once' startup_guard = False + finish_startup_called = True + + +cpdef ensure_startup_finished(): + """ + Make sure that the startup phase is finished. + + In contrast to :func:`finish_startup`, this function can + be called repeatedly. + + TESTS:: + + sage: from sage.misc.lazy_import import ensure_startup_finished + sage: ensure_startup_finished() + """ + global startup_guard + startup_guard = False + cpdef bint is_during_startup(): """ @@ -114,6 +136,7 @@ cpdef bint is_during_startup(): global startup_guard return startup_guard + cpdef test_fake_startup(): """ For testing purposes only. @@ -218,7 +241,8 @@ cdef class LazyImport(object): if startup_guard and not self._at_startup: print(f"Resolving lazy import {self._name} during startup") elif self._at_startup and not startup_guard: - print(f"Option ``at_startup=True`` for lazy import {self._name} not needed anymore") + if finish_startup_called: + print(f"Option ``at_startup=True`` for lazy import {self._name} not needed anymore") try: self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name) From 181e4a00604d7ec5d4653acc9783738779dc8105 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 19:39:25 -0700 Subject: [PATCH 249/511] src/sage/misc/lazy_import.pyx: Use warnings.warn instead of print --- src/sage/misc/lazy_import.pyx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 50a3bb325d4..880cf80352c 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -63,6 +63,7 @@ cdef extern from *: import os import pickle +from warnings import warn import inspect from . import sageinspect @@ -239,10 +240,10 @@ cdef class LazyImport(object): return self._object if startup_guard and not self._at_startup: - print(f"Resolving lazy import {self._name} during startup") + warn(f"Resolving lazy import {self._name} during startup") elif self._at_startup and not startup_guard: if finish_startup_called: - print(f"Option ``at_startup=True`` for lazy import {self._name} not needed anymore") + warn(f"Option ``at_startup=True`` for lazy import {self._name} not needed anymore") try: self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name) From 13607cb249da2bdedaee511a7741b744bd439ca6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 19:43:01 -0700 Subject: [PATCH 250/511] src/sage/dynamics/arithmetic_dynamics/projective_ds.py: Remove unused import --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 3c56fd3885b..96df43c2d8d 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -80,7 +80,6 @@ class initialization directly. from sage.rings.polynomial.flatten import FlatteningMorphism, UnflatteningMorphism from sage.rings.morphism import RingHomomorphism_im_gens from sage.rings.number_field.number_field_ideal import NumberFieldFractionalIdeal -from sage.rings.number_field.number_field import is_NumberField from sage.rings.padics.all import Qp from sage.rings.polynomial.multi_polynomial_ring_base import is_MPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing From 271e04420c0868f1d9630e7c3feb68b2c83003c7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 20:55:33 -0700 Subject: [PATCH 251/511] src/sage/rings/real_interval_absolute.pyx: Fix imports --- src/sage/rings/real_interval_absolute.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/real_interval_absolute.pyx b/src/sage/rings/real_interval_absolute.pyx index 16a275aab2b..7b39d84b5fa 100644 --- a/src/sage/rings/real_interval_absolute.pyx +++ b/src/sage/rings/real_interval_absolute.pyx @@ -10,12 +10,13 @@ from sage.structure.factory import UniqueFactory from sage.structure.element cimport RingElement, ModuleElement, Element, FieldElement from sage.rings.ring cimport Field from sage.rings.integer cimport Integer +import sage.rings.abc from sage.structure.parent cimport Parent from sage.structure.element cimport parent from sage.rings.real_mpfr import RR_min_prec -from sage.rings.real_mpfi import RealIntervalField, RealIntervalFieldElement, is_RealIntervalField +from sage.rings.real_mpfi import RealIntervalField, RealIntervalFieldElement from sage.rings.rational_field import QQ cdef Integer zero = Integer(0) From fc039f12c354c9f0c3cb55373bcabaa897500e91 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 20:57:07 -0700 Subject: [PATCH 252/511] src/sage/symbolic/ring.pyx: Fix imports --- src/sage/symbolic/ring.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index d0022b060d9..7e899398a9b 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -32,6 +32,7 @@ The symbolic ring # **************************************************************************** from sage.rings.integer cimport Integer +import sage.rings.abc from sage.symbolic.expression cimport ( is_Expression, @@ -207,7 +208,6 @@ cdef class SymbolicRing(CommutativeRing): from sage.rings.fraction_field import is_FractionField from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing from sage.rings.real_mpfi import is_RealIntervalField - from sage.rings.complex_interval_field import is_ComplexIntervalField from sage.rings.real_arb import RealBallField from sage.rings.complex_arb import ComplexBallField from sage.rings.polynomial.polynomial_ring import is_PolynomialRing From f7e07bf5cdebaef88504d15169c45d7b8a43c285 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 21:43:06 -0700 Subject: [PATCH 253/511] git grep -l 'all import ZZ' src/sage | xargs sed -E -i.bak $'s/^( *)from sage.*all import (ZZ, QQ|QQ, ZZ) *$/\1from sage.rings.integer_ring import ZZ\\n\1from sage.rings.rational_field import QQ/' --- src/sage/algebras/lie_algebras/verma_module.py | 3 ++- src/sage/algebras/schur_algebra.py | 3 ++- src/sage/combinat/derangements.py | 3 ++- src/sage/combinat/descent_algebra.py | 3 ++- src/sage/combinat/diagram_algebras.py | 3 ++- src/sage/combinat/dyck_word.py | 3 ++- src/sage/combinat/ncsf_qsym/qsym.py | 3 ++- src/sage/combinat/partition_algebra.py | 3 ++- src/sage/combinat/root_system/ambient_space.py | 3 ++- src/sage/combinat/root_system/plot.py | 3 ++- .../combinat/root_system/reflection_group_complex.py | 3 ++- .../root_system/reflection_group_element.pyx | 3 ++- .../root_system/root_lattice_realizations.py | 3 ++- src/sage/combinat/root_system/root_system.py | 3 ++- src/sage/combinat/root_system/weyl_group.py | 3 ++- src/sage/combinat/skew_partition.py | 3 ++- src/sage/groups/additive_abelian/qmodnz.py | 3 ++- src/sage/libs/linkages/padics/Polynomial_shared.pxi | 3 ++- src/sage/matroids/constructor.py | 3 ++- src/sage/modular/abvar/morphism.py | 3 ++- src/sage/modular/hecke/algebra.py | 3 ++- src/sage/modular/pollack_stevens/padic_lseries.py | 3 ++- src/sage/rings/number_field/totallyreal.pyx | 3 ++- src/sage/rings/number_field/totallyreal_rel.py | 3 ++- src/sage/rings/padics/padic_valuation.py | 12 ++++++++---- src/sage/schemes/affine/affine_rational_point.py | 3 ++- src/sage/schemes/elliptic_curves/isogeny_class.py | 3 ++- .../schemes/elliptic_curves/isogeny_small_degree.py | 3 ++- src/sage/schemes/toric/ideal.py | 3 ++- src/sage/schemes/toric/library.py | 3 ++- 30 files changed, 66 insertions(+), 33 deletions(-) diff --git a/src/sage/algebras/lie_algebras/verma_module.py b/src/sage/algebras/lie_algebras/verma_module.py index 9c9fdca0147..730714b0bb3 100644 --- a/src/sage/algebras/lie_algebras/verma_module.py +++ b/src/sage/algebras/lie_algebras/verma_module.py @@ -31,7 +31,8 @@ from sage.modules.free_module_element import vector from sage.sets.family import Family from sage.structure.richcmp import richcmp -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ class VermaModule(CombinatorialFreeModule): diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 2d7af71b6f6..08b921ea160 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -45,7 +45,8 @@ from sage.matrix.constructor import Matrix from sage.misc.cachefunc import cached_method from sage.misc.flatten import flatten -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ def _schur_I_nr_representatives(n, r): diff --git a/src/sage/combinat/derangements.py b/src/sage/combinat/derangements.py index 4ad088c9575..4640798c7dc 100644 --- a/src/sage/combinat/derangements.py +++ b/src/sage/combinat/derangements.py @@ -29,7 +29,8 @@ from sage.misc.all import prod from sage.misc.prandom import random, randrange from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.rings.integer import Integer from sage.combinat.combinat import CombinatorialElement from sage.combinat.permutation import Permutation, Permutations diff --git a/src/sage/combinat/descent_algebra.py b/src/sage/combinat/descent_algebra.py index bff1e214ee5..8d2678bc518 100644 --- a/src/sage/combinat/descent_algebra.py +++ b/src/sage/combinat/descent_algebra.py @@ -20,7 +20,8 @@ from sage.categories.algebras import Algebras from sage.categories.realizations import Realizations, Category_realization_of_parent from sage.categories.all import FiniteDimensionalAlgebrasWithBasis -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.arith.misc import factorial from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.permutation import Permutations diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 1f7dfef039d..17a9f85bc5f 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -41,7 +41,8 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.flatten import flatten from sage.misc.misc_c import prod -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.functions.other import floor, ceil import itertools diff --git a/src/sage/combinat/dyck_word.py b/src/sage/combinat/dyck_word.py index 10f8a588a8b..4eb3cebf1b4 100644 --- a/src/sage/combinat/dyck_word.py +++ b/src/sage/combinat/dyck_word.py @@ -91,7 +91,8 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.all import Posets -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.combinat.permutation import Permutation, Permutations from sage.combinat.words.word import Word from sage.combinat.alternating_sign_matrix import AlternatingSignMatrices diff --git a/src/sage/combinat/ncsf_qsym/qsym.py b/src/sage/combinat/ncsf_qsym/qsym.py index f76f1891ad3..a13e4acf51e 100644 --- a/src/sage/combinat/ncsf_qsym/qsym.py +++ b/src/sage/combinat/ncsf_qsym/qsym.py @@ -1908,7 +1908,8 @@ def lambda_of_monomial(self, I, n): # The following algorithm is a rewriting of the formula in the docstring. # We are working over QQ because there are denominators which don't # immediately cancel. - from sage.rings.all import ZZ, QQ + from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ QQM = QuasiSymmetricFunctions(QQ).M() QQ_result = QQM.zero() for lam in Partitions(n): diff --git a/src/sage/combinat/partition_algebra.py b/src/sage/combinat/partition_algebra.py index 9a6869b0de2..a820494f388 100644 --- a/src/sage/combinat/partition_algebra.py +++ b/src/sage/combinat/partition_algebra.py @@ -23,7 +23,8 @@ from sage.graphs.graph import Graph from sage.arith.all import factorial, binomial from .permutation import Permutations -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from .subset import Subsets from sage.functions.all import ceil diff --git a/src/sage/combinat/root_system/ambient_space.py b/src/sage/combinat/root_system/ambient_space.py index e1d4adea0ea..c55646e94ce 100644 --- a/src/sage/combinat/root_system/ambient_space.py +++ b/src/sage/combinat/root_system/ambient_space.py @@ -11,7 +11,8 @@ from sage.misc.cachefunc import cached_method from sage.combinat.free_module import CombinatorialFreeModule from .weight_lattice_realizations import WeightLatticeRealizations -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.categories.homset import End diff --git a/src/sage/combinat/root_system/plot.py b/src/sage/combinat/root_system/plot.py index 5e8ee505465..36da0e98384 100644 --- a/src/sage/combinat/root_system/plot.py +++ b/src/sage/combinat/root_system/plot.py @@ -809,7 +809,8 @@ from sage.misc.lazy_import import lazy_import from sage.structure.element import parent from sage.modules.free_module_element import vector -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.combinat.root_system.cartan_type import CartanType lazy_import("sage.combinat.root_system.root_lattice_realizations", "RootLatticeRealizations") diff --git a/src/sage/combinat/root_system/reflection_group_complex.py b/src/sage/combinat/root_system/reflection_group_complex.py index 5f769683634..f66ff07ab5c 100644 --- a/src/sage/combinat/root_system/reflection_group_complex.py +++ b/src/sage/combinat/root_system/reflection_group_complex.py @@ -205,7 +205,8 @@ from sage.sets.family import Family from sage.structure.unique_representation import UniqueRepresentation from sage.groups.perm_gps.permgroup import PermutationGroup_generic -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.matrix.all import Matrix, identity_matrix from sage.structure.element import is_Matrix from sage.interfaces.gap3 import gap3 diff --git a/src/sage/combinat/root_system/reflection_group_element.pyx b/src/sage/combinat/root_system/reflection_group_element.pyx index 157c74e18dd..bd96e4297c3 100644 --- a/src/sage/combinat/root_system/reflection_group_element.pyx +++ b/src/sage/combinat/root_system/reflection_group_element.pyx @@ -27,7 +27,8 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod from sage.arith.functions import lcm from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.interfaces.gap3 import gap3 from sage.combinat.root_system.cartan_matrix import CartanMatrix from sage.misc.sage_eval import sage_eval diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index 1eaf908e63c..95301036614 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -22,7 +22,8 @@ from sage.categories.modules_with_basis import ModulesWithBasis from sage.structure.element import Element from sage.sets.family import Family -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet diff --git a/src/sage/combinat/root_system/root_system.py b/src/sage/combinat/root_system/root_system.py index 628afb34833..9285d9b958b 100644 --- a/src/sage/combinat/root_system/root_system.py +++ b/src/sage/combinat/root_system/root_system.py @@ -18,7 +18,8 @@ from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation from .cartan_type import CartanType -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.misc.all import cached_method from .root_space import RootSpace from .weight_space import WeightSpace diff --git a/src/sage/combinat/root_system/weyl_group.py b/src/sage/combinat/root_system/weyl_group.py index e546d399274..f5b693f1313 100644 --- a/src/sage/combinat/root_system/weyl_group.py +++ b/src/sage/combinat/root_system/weyl_group.py @@ -40,7 +40,8 @@ from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap from sage.groups.matrix_gps.group_element import MatrixGroupElement_gap from sage.groups.perm_gps.permgroup import PermutationGroup_generic -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.interfaces.gap import gap from sage.misc.cachefunc import cached_method from sage.combinat.root_system.cartan_type import CartanType diff --git a/src/sage/combinat/skew_partition.py b/src/sage/combinat/skew_partition.py index 9be0a9b6237..585e1802c74 100644 --- a/src/sage/combinat/skew_partition.py +++ b/src/sage/combinat/skew_partition.py @@ -148,7 +148,8 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.sets.set import Set from sage.graphs.digraph import DiGraph from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/groups/additive_abelian/qmodnz.py b/src/sage/groups/additive_abelian/qmodnz.py index 344344234a6..6fdb3838fd2 100644 --- a/src/sage/groups/additive_abelian/qmodnz.py +++ b/src/sage/groups/additive_abelian/qmodnz.py @@ -31,7 +31,8 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups from .qmodnz_element import QmodnZ_Element diff --git a/src/sage/libs/linkages/padics/Polynomial_shared.pxi b/src/sage/libs/linkages/padics/Polynomial_shared.pxi index 7c66463ac12..738ab9bf457 100644 --- a/src/sage/libs/linkages/padics/Polynomial_shared.pxi +++ b/src/sage/libs/linkages/padics/Polynomial_shared.pxi @@ -29,7 +29,8 @@ AUTHORS: from cpython.list cimport * from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.ext.stdsage cimport PY_NEW from copy import copy from sage.rings.padics.common_conversion cimport cconv_mpz_t_out_shared, cconv_mpz_t_shared, cconv_mpq_t_out_shared, cconv_mpq_t_shared, cconv_shared diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index 8fc0a44957a..1e2a85ff6bc 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -105,7 +105,8 @@ from sage.matrix.constructor import Matrix from sage.graphs.all import Graph from sage.structure.element import is_Matrix -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.categories.all import Fields, Rings from sage.rings.finite_rings.finite_field_base import FiniteField import sage.matroids.matroid diff --git a/src/sage/modular/abvar/morphism.py b/src/sage/modular/abvar/morphism.py index 99bbd68af9d..386561a1b02 100644 --- a/src/sage/modular/abvar/morphism.py +++ b/src/sage/modular/abvar/morphism.py @@ -40,7 +40,8 @@ ########################################################################### from sage.categories.morphism import Morphism as base_Morphism -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ import sage.modules.matrix_morphism import sage.matrix.matrix_space as matrix_space diff --git a/src/sage/modular/hecke/algebra.py b/src/sage/modular/hecke/algebra.py index 2e8506d4599..ffd6364c8bc 100644 --- a/src/sage/modular/hecke/algebra.py +++ b/src/sage/modular/hecke/algebra.py @@ -32,7 +32,8 @@ from sage.arith.all import lcm, gcd from sage.misc.latex import latex from sage.matrix.matrix_space import MatrixSpace -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.structure.element import Element from sage.structure.unique_representation import CachedRepresentation from sage.misc.cachefunc import cached_method diff --git a/src/sage/modular/pollack_stevens/padic_lseries.py b/src/sage/modular/pollack_stevens/padic_lseries.py index 5dd019eee93..4a3beb12fdf 100644 --- a/src/sage/modular/pollack_stevens/padic_lseries.py +++ b/src/sage/modular/pollack_stevens/padic_lseries.py @@ -21,7 +21,8 @@ # **************************************************************************** from sage.rings.padics.all import pAdicField -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.rings.power_series_ring import PowerSeriesRing from sage.arith.all import binomial, kronecker from sage.rings.padics.precision_error import PrecisionError diff --git a/src/sage/rings/number_field/totallyreal.pyx b/src/sage/rings/number_field/totallyreal.pyx index 0512f0559fc..3841146b7a7 100644 --- a/src/sage/rings/number_field/totallyreal.pyx +++ b/src/sage/rings/number_field/totallyreal.pyx @@ -105,7 +105,8 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer import Integer from sage.rings.integer cimport Integer from sage.rings.integer_ring import IntegerRing -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.misc.misc import cputime from sage.rings.number_field.totallyreal_data import tr_data, int_has_small_square_divisor diff --git a/src/sage/rings/number_field/totallyreal_rel.py b/src/sage/rings/number_field/totallyreal_rel.py index e531dcaa126..f5061ff7b36 100644 --- a/src/sage/rings/number_field/totallyreal_rel.py +++ b/src/sage/rings/number_field/totallyreal_rel.py @@ -98,7 +98,8 @@ 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.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ import math import sys diff --git a/src/sage/rings/padics/padic_valuation.py b/src/sage/rings/padics/padic_valuation.py index f47f1d8de5b..3aaa77b1d6f 100644 --- a/src/sage/rings/padics/padic_valuation.py +++ b/src/sage/rings/padics/padic_valuation.py @@ -119,7 +119,8 @@ def create_key_and_extra_args(self, R, prime=None, approximants=None): 2-adic valuation """ - from sage.rings.all import ZZ, QQ + from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ from sage.rings.padics.padic_generic import pAdicGeneric from sage.rings.number_field.number_field import is_NumberField from sage.rings.polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing @@ -389,7 +390,8 @@ def create_object(self, version, key, **extra_args): 5-adic valuation """ - from sage.rings.all import ZZ, QQ + from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ from sage.rings.padics.padic_generic import pAdicGeneric from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace from sage.rings.polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing @@ -956,7 +958,8 @@ def element_with_valuation(self, v): y^3 + O(y^43) """ - from sage.rings.all import QQ, ZZ + from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ v = QQ(v) if v not in self.value_semigroup(): raise ValueError("%r is not in the value semigroup of %r"%(v, self)) @@ -1327,7 +1330,8 @@ def inverse(self, x, precision): if self(x) > 0 or precision is infinity: raise ValueError("element has no approximate inverse in this ring") - from sage.rings.all import ZZ, QQ + from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ return self.domain()(ZZ(x).inverse_mod(self.p() ** QQ(precision).ceil())) diff --git a/src/sage/schemes/affine/affine_rational_point.py b/src/sage/schemes/affine/affine_rational_point.py index 122103dacc4..513b5d67aa0 100644 --- a/src/sage/schemes/affine/affine_rational_point.py +++ b/src/sage/schemes/affine/affine_rational_point.py @@ -51,7 +51,8 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.misc.all import cartesian_product_iterator from sage.schemes.generic.scheme import is_Scheme diff --git a/src/sage/schemes/elliptic_curves/isogeny_class.py b/src/sage/schemes/elliptic_curves/isogeny_class.py index 94d99a82ec5..174359868b3 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_class.py +++ b/src/sage/schemes/elliptic_curves/isogeny_class.py @@ -28,7 +28,8 @@ from sage.structure.sage_object import SageObject from sage.structure.richcmp import richcmp_method, richcmp import sage.databases.cremona -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.misc.all import flatten, cached_method from sage.schemes.elliptic_curves.ell_field import EllipticCurve_field from sage.schemes.elliptic_curves.ell_number_field import EllipticCurve_number_field diff --git a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py index d5e08668737..58bfc0fb5b8 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py +++ b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py @@ -32,7 +32,8 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import polygen -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.schemes.elliptic_curves.all import EllipticCurve from sage.misc.cachefunc import cached_function diff --git a/src/sage/schemes/toric/ideal.py b/src/sage/schemes/toric/ideal.py index fc0c5ecde5c..20681b39896 100644 --- a/src/sage/schemes/toric/ideal.py +++ b/src/sage/schemes/toric/ideal.py @@ -135,7 +135,8 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.misc.misc_c import prod from sage.matrix.constructor import matrix -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal diff --git a/src/sage/schemes/toric/library.py b/src/sage/schemes/toric/library.py index 7de2cd950bc..7b3509c2132 100644 --- a/src/sage/schemes/toric/library.py +++ b/src/sage/schemes/toric/library.py @@ -42,7 +42,8 @@ from sage.matrix.all import matrix, identity_matrix from sage.geometry.all import Fan, LatticePolytope, ToricLattice -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.arith.all import gcd from sage.schemes.toric.variety import (DEFAULT_PREFIX, ToricVariety, From acf7ae99825035ec3b5f0262c8d1c5c5124fdde0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 21:44:13 -0700 Subject: [PATCH 254/511] git grep -l 'all import ZZ' src/sage | xargs sed -E -i.bak $'s/^( *)from sage.*all import ZZ *$/\1from sage.rings.integer_ring import ZZ/' --- src/sage/interfaces/qepcad.py | 2 +- src/sage/interfaces/singular.py | 2 +- src/sage/quivers/path_semigroup.py | 2 +- src/sage/rings/pari_ring.py | 2 +- src/sage/rings/polynomial/term_order.py | 2 +- src/sage/rings/tests.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index 29baa767b4e..3007961aad6 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -2253,7 +2253,7 @@ def exactly_k(self, k, v, formula, allow_multi=False): sage: qf.exactly_k(0, b, a*b == 1) (A b)[~a b = 1] """ - from sage.all import ZZ + from sage.rings.integer_ring import ZZ k = ZZ(k) if k < 0: raise ValueError("negative k in exactly_k quantifier") diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index d9c0a90fb08..35dfd02c88b 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -1608,7 +1608,7 @@ def sage_global_ring(self): # extract the ring of coefficients singular = self.parent() charstr = singular.eval('charstr(basering)').split(',',1) - from sage.all import ZZ + from sage.rings.integer_ring import ZZ is_extension = len(charstr)==2 if charstr[0] in ['integer', 'ZZ']: br = ZZ diff --git a/src/sage/quivers/path_semigroup.py b/src/sage/quivers/path_semigroup.py index 7426132d4ec..d4e05928d85 100644 --- a/src/sage/quivers/path_semigroup.py +++ b/src/sage/quivers/path_semigroup.py @@ -543,7 +543,7 @@ def cardinality(self): ... ValueError: the underlying quiver has cycles, thus, there may be an infinity of directed paths """ - from sage.all import ZZ + from sage.rings.integer_ring import ZZ if self._quiver.is_directed_acyclic() and not self._quiver.has_loops(): return ZZ(len(self)) from sage.rings.infinity import Infinity diff --git a/src/sage/rings/pari_ring.py b/src/sage/rings/pari_ring.py index 17e5f161473..c46fceed07b 100644 --- a/src/sage/rings/pari_ring.py +++ b/src/sage/rings/pari_ring.py @@ -215,7 +215,7 @@ def random_element(self, x=None, y=None, distribution=None): True """ - from sage.all import ZZ + from sage.rings.integer_ring import ZZ return self(ZZ.random_element(x, y, distribution)) def zeta(self): diff --git a/src/sage/rings/polynomial/term_order.py b/src/sage/rings/polynomial/term_order.py index 6c411c2011e..51c4e6ef4c6 100644 --- a/src/sage/rings/polynomial/term_order.py +++ b/src/sage/rings/polynomial/term_order.py @@ -2216,7 +2216,7 @@ def termorder_from_singular(S): sage: PolynomialRing(QQ, 'x,y', order='degneglex')('x^2')._singular_().sage() x^2 """ - from sage.all import ZZ + from sage.rings.integer_ring import ZZ singular = S T = singular('ringlist(basering)[3]') order = [] diff --git a/src/sage/rings/tests.py b/src/sage/rings/tests.py index 4fd37826771..58e88decae2 100644 --- a/src/sage/rings/tests.py +++ b/src/sage/rings/tests.py @@ -182,7 +182,7 @@ def relative_number_field(n=2, maxdeg=2): sage: from sage.rings.tests import relative_number_field sage: _ = relative_number_field(3) """ - from sage.all import ZZ + from sage.rings.integer_ring import ZZ K = absolute_number_field(maxdeg) n -= 1 var = 'aa' From 31e17a41bf21118dfba1ea3a67667ada48bd078d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 21:46:17 -0700 Subject: [PATCH 255/511] git grep -l 'all import .*ZZ' src/sage | xargs sed -E -i.bak $'s/^( *)from sage.*all import (ZZ, GF) *$/\1from sage.rings.integer_ring import ZZ\\n\1from sage.rings.finite_rings.finite_field_constructor import GF/' --- src/sage/algebras/steenrod/steenrod_algebra.py | 6 ++++-- src/sage/interfaces/macaulay2.py | 6 ++++-- src/sage/matroids/catalog.py | 3 ++- src/sage/rings/tests.py | 9 ++++++--- src/sage/schemes/elliptic_curves/ell_torsion.py | 3 ++- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index f289d4fd86d..3eb15efd811 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -2037,7 +2037,8 @@ def _coerce_map_from_(self, S): sage: B3._coerce_map_from_(A31) False """ - from sage.rings.all import ZZ, GF + from sage.rings.integer_ring import ZZ + from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.infinity import Infinity p = self.prime() if S == ZZ or S == GF(p): @@ -2099,7 +2100,8 @@ def _element_constructor_(self, x): sage: A1({(2,): 1, (1,): 13}) Sq(1) + Sq(2) """ - from sage.rings.all import ZZ, GF + from sage.rings.integer_ring import ZZ + from sage.rings.finite_rings.finite_field_constructor import GF if x in GF(self.prime()) or x in ZZ: return self.from_base_ring_from_one_basis(x) diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 64dd877ab05..5fb903b7f6a 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -1562,7 +1562,8 @@ def _sage_(self): #Handle the ZZ/n case ambient = self.ambient() if ambient.external_string() == 'ZZ': - from sage.rings.all import ZZ, GF + from sage.rings.integer_ring import ZZ + from sage.rings.finite_rings.finite_field_constructor import GF external_string = self.external_string() zz, n = external_string.split("/") @@ -1600,7 +1601,8 @@ def _sage_(self): return PolynomialRing(base_ring, order=order, names=gens) elif cls_str == "GaloisField": - from sage.rings.all import ZZ, GF + from sage.rings.integer_ring import ZZ + from sage.rings.finite_rings.finite_field_constructor import GF gf, n = repr_str.split(" ") n = ZZ(n) if n.is_prime(): diff --git a/src/sage/matroids/catalog.py b/src/sage/matroids/catalog.py index d6a35bd6091..f80d1741248 100644 --- a/src/sage/matroids/catalog.py +++ b/src/sage/matroids/catalog.py @@ -38,7 +38,8 @@ from sage.matrix.constructor import Matrix from sage.graphs.all import graphs -from sage.rings.all import ZZ, GF +from sage.rings.integer_ring import ZZ +from sage.rings.finite_rings.finite_field_constructor import GF from sage.schemes.all import ProjectiveSpace import sage.matroids.matroid diff --git a/src/sage/rings/tests.py b/src/sage/rings/tests.py index 58e88decae2..9575ef5c6a8 100644 --- a/src/sage/rings/tests.py +++ b/src/sage/rings/tests.py @@ -29,7 +29,8 @@ def prime_finite_field(): sage: K.cardinality().is_prime() True """ - from sage.all import ZZ, GF + from sage.rings.integer_ring import ZZ + from sage.rings.finite_rings.finite_field_constructor import GF return GF(ZZ.random_element(x=2, y=10**20 - 12).next_prime()) @@ -49,7 +50,8 @@ def finite_field(): sage: while K.cardinality().is_prime(): ....: K = sage.rings.tests.finite_field() """ - from sage.all import ZZ, GF + from sage.rings.integer_ring import ZZ + from sage.rings.finite_rings.finite_field_constructor import GF p = ZZ.random_element(x=2, y=10**6 - 18).next_prime() d = ZZ.random_element(x=1, y=20) return GF(p**d, 'a') @@ -72,7 +74,8 @@ def small_finite_field(): sage: q <= 2^16 True """ - from sage.all import ZZ, GF + from sage.rings.integer_ring import ZZ + from sage.rings.finite_rings.finite_field_constructor import GF while True: q = ZZ.random_element(x=2, y=2**16) if q.is_prime_power(): diff --git a/src/sage/schemes/elliptic_curves/ell_torsion.py b/src/sage/schemes/elliptic_curves/ell_torsion.py index 33265f11d7d..5e1795f088f 100644 --- a/src/sage/schemes/elliptic_curves/ell_torsion.py +++ b/src/sage/schemes/elliptic_curves/ell_torsion.py @@ -320,7 +320,8 @@ def torsion_bound(E, number_of_places=20): sage: E.torsion_subgroup().invariants() (4, 4) """ - from sage.rings.all import ZZ, GF + from sage.rings.integer_ring import ZZ + from sage.rings.finite_rings.finite_field_constructor import GF from sage.schemes.elliptic_curves.constructor import EllipticCurve K = E.base_field() From d9dd2d008821e19886c20cd3e2270c5bff3c5473 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 21:53:36 -0700 Subject: [PATCH 256/511] git grep -l 'all import.*ZZ' src/sage | xargs sed -E -i.bak $'s/^( *)from sage.*all import (ZZ, QQ|QQ, ZZ) *$/\1from sage.rings.integer_ring import ZZ\\n\1from sage.rings.rational_field import QQ/' --- src/sage/combinat/path_tableaux/frieze.py | 3 ++- src/sage/combinat/ribbon_tableau.py | 3 ++- src/sage/combinat/root_system/associahedron.py | 3 ++- src/sage/interfaces/chomp.py | 3 ++- src/sage/modular/abvar/abvar_newform.py | 3 ++- src/sage/rings/valuation/valuation_space.py | 3 ++- src/sage/schemes/elliptic_curves/gp_simon.py | 3 ++- src/sage/schemes/toric/divisor.py | 3 ++- 8 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index e68a0747b9d..da1d4205b00 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -25,7 +25,8 @@ from sage.categories.sets_cat import Sets from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux, CylindricalDiagram from sage.categories.fields import Fields -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ class FriezePattern(PathTableau, metaclass=InheritComparisonClasscallMetaclass): diff --git a/src/sage/combinat/ribbon_tableau.py b/src/sage/combinat/ribbon_tableau.py index f164a886729..b6cf87a57b5 100644 --- a/src/sage/combinat/ribbon_tableau.py +++ b/src/sage/combinat/ribbon_tableau.py @@ -21,7 +21,8 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.sets_cat import Sets -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.rings.integer import Integer from sage.combinat.combinat import CombinatorialElement from sage.combinat.skew_partition import SkewPartition, SkewPartitions diff --git a/src/sage/combinat/root_system/associahedron.py b/src/sage/combinat/root_system/associahedron.py index 498e37aa782..30092073473 100644 --- a/src/sage/combinat/root_system/associahedron.py +++ b/src/sage/combinat/root_system/associahedron.py @@ -27,7 +27,8 @@ from sage.geometry.polyhedron.parent import Polyhedra, Polyhedra_base, Polyhedra_QQ_ppl, Polyhedra_QQ_normaliz, Polyhedra_QQ_cdd, Polyhedra_polymake, Polyhedra_field from sage.combinat.root_system.cartan_type import CartanType from sage.modules.free_module_element import vector -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ ancestors_of_associahedron = set([Polyhedron_QQ_ppl, Polyhedron_QQ_normaliz, Polyhedron_QQ_cdd, Polyhedron_field, Polyhedron_polymake]) diff --git a/src/sage/interfaces/chomp.py b/src/sage/interfaces/chomp.py index 00f4b3f93b3..c86ae49b2cc 100644 --- a/src/sage/interfaces/chomp.py +++ b/src/sage/interfaces/chomp.py @@ -138,7 +138,8 @@ def __call__(self, program, complex, subcomplex=None, **kwds): from sage.topology.simplicial_complex import SimplicialComplex, Simplex from sage.homology.chain_complex import HomologyGroup from subprocess import Popen, PIPE - from sage.rings.all import QQ, ZZ + from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ from sage.modules.all import VectorSpace, vector from sage.combinat.free_module import CombinatorialFreeModule diff --git a/src/sage/modular/abvar/abvar_newform.py b/src/sage/modular/abvar/abvar_newform.py index 21a1758283a..67c478511f3 100644 --- a/src/sage/modular/abvar/abvar_newform.py +++ b/src/sage/modular/abvar/abvar_newform.py @@ -14,7 +14,8 @@ ########################################################################### from sage.misc.lazy_import import lazy_import -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.modular.modform.element import Newform from sage.modular.arithgroup.all import is_Gamma0, is_Gamma1, is_GammaH diff --git a/src/sage/rings/valuation/valuation_space.py b/src/sage/rings/valuation/valuation_space.py index f64072338b5..da900837371 100644 --- a/src/sage/rings/valuation/valuation_space.py +++ b/src/sage/rings/valuation/valuation_space.py @@ -475,7 +475,8 @@ def element_with_valuation(self, s): 1024 """ - from sage.rings.all import QQ, ZZ + from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ s = QQ.coerce(s) if s not in self.value_semigroup(): raise ValueError("s must be in the value semigroup of this valuation but %r is not in %r"%(s, self.value_semigroup())) diff --git a/src/sage/schemes/elliptic_curves/gp_simon.py b/src/sage/schemes/elliptic_curves/gp_simon.py index d1d45aa7c3d..fd68549b118 100644 --- a/src/sage/schemes/elliptic_curves/gp_simon.py +++ b/src/sage/schemes/elliptic_curves/gp_simon.py @@ -21,7 +21,8 @@ from sage.interfaces.gp import Gp from sage.misc.sage_eval import sage_eval from sage.misc.randstate import current_randstate -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ gp = None diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index 576845ac1e8..fb6b60f71ff 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -176,7 +176,8 @@ from sage.modules.all import vector from sage.modules.free_module import (FreeModule_ambient_field, FreeModule_ambient_pid) -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.schemes.generic.divisor import Divisor_generic from sage.schemes.generic.divisor_group import DivisorGroup_generic from sage.schemes.toric.divisor_class import ToricRationalDivisorClass From 0b06521bbe9ff8075d7158f7266657785a02da93 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 23:20:49 -0700 Subject: [PATCH 257/511] src/sage/sets/disjoint_union_enumerated_sets.py: Remove import from sage.misc.all --- src/sage/sets/disjoint_union_enumerated_sets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/sets/disjoint_union_enumerated_sets.py b/src/sage/sets/disjoint_union_enumerated_sets.py index 7a6f604dc16..79e5954c561 100644 --- a/src/sage/sets/disjoint_union_enumerated_sets.py +++ b/src/sage/sets/disjoint_union_enumerated_sets.py @@ -21,7 +21,8 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.rings.infinity import Infinity -from sage.misc.all import cached_method, lazy_attribute +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute from sage.structure.unique_representation import UniqueRepresentation class DisjointUnionEnumeratedSets(UniqueRepresentation, Parent): From 43ed0cadadf02c48c31990b62817ef53d4eef15d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 23:25:04 -0700 Subject: [PATCH 258/511] git grep -l 'all import cputime' src/sage | xargs sed -E -i.bak $'s/^( *)from sage.*all import (cputime) *$/\1from sage.misc.misc import \2/' --- src/sage/modular/modform/eis_series.py | 2 +- src/sage/modular/quatalg/brandt.py | 2 +- src/sage/rings/number_field/splitting_field.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/modular/modform/eis_series.py b/src/sage/modular/modform/eis_series.py index adf7ec610c7..4f2e0ed878a 100644 --- a/src/sage/modular/modform/eis_series.py +++ b/src/sage/modular/modform/eis_series.py @@ -12,7 +12,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.misc.all import cputime +from sage.misc.misc import cputime import sage.modular.dirichlet as dirichlet from sage.modular.arithgroup.congroup_gammaH import GammaH_class from sage.rings.all import Integer, CyclotomicField, ZZ, QQ diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index 5fbde461d12..366830a6325 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -1685,7 +1685,7 @@ def benchmark_sage(levels, silent=False): ('sage', 43, 2, ...) ('sage', 97, 2, ...) """ - from sage.misc.all import cputime + from sage.misc.misc import cputime ans = [] for p, M in levels: t = cputime() diff --git a/src/sage/rings/number_field/splitting_field.py b/src/sage/rings/number_field/splitting_field.py index 06edcad31d5..8818e5d1bad 100644 --- a/src/sage/rings/number_field/splitting_field.py +++ b/src/sage/rings/number_field/splitting_field.py @@ -339,7 +339,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No To: Number Field in x with defining polynomial x Defn: 1 |--> 1) """ - from sage.misc.all import cputime + from sage.misc.misc import cputime from sage.misc.verbose import verbose degree_multiple = Integer(degree_multiple or 0) From bc4e07dc4e0bc7999fcc31ba5db3d065a7ddfb84 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 4 Oct 2021 15:45:55 +0900 Subject: [PATCH 259/511] Using another iterator in restrict(). --- src/sage/combinat/skew_tableau.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 99ef0d512e3..676aff61440 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -703,8 +703,8 @@ def restrict(self, n): sage: SkewTableau([[None,1],[1],[2]]).restrict(1) [[None, 1], [1]] """ - return SkewTableau([z for z in [[y for y in x if y is None or y <= n] - for x in self] if z]) + data = ([y for y in x if y is None or y <= n] for x in self) + return SkewTableau([z for z in data if z]) def restriction_outer_shape(self, n): """ From 3a20afe93036dcd0c0e3869e0a4001c6711dc788 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Oct 2021 23:48:30 -0700 Subject: [PATCH 260/511] src/sage/categories/pushout.py: Remove .all imports --- src/sage/categories/pushout.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 7a15885b609..10e17140849 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -2584,7 +2584,7 @@ def merge(self, other): True """ if self == other: # both are Completion functors with the same p - from sage.all import Infinity + from sage.rings.infinity import Infinity if self.p == Infinity: new_prec = min(self.prec, other.prec) new_type = self._real_types[min(self._real_types.index(self.type), @@ -2773,7 +2773,7 @@ def _apply_functor(self, R): if not I.is_zero(): from sage.categories.fields import Fields if R in Fields(): - from sage.all import Integers + from sage.rings.finite_rings.integer_mod_ring import Integers return Integers(1) if I.ring() != R: if I.ring().has_coerce_map_from(R): @@ -3153,8 +3153,10 @@ def _apply_functor(self, R): 3-adic Eisenstein Extension Field in a defined by a^2 - 3 """ - from sage.all import QQ, ZZ, CyclotomicField + from sage.rings.rational_field import QQ + from sage.rings.integer_ring import ZZ if self.cyclotomic: + from sage.rings.number_field.number_field import CyclotomicField if R == QQ: return CyclotomicField(self.cyclotomic) if R == ZZ: @@ -3325,7 +3327,7 @@ def merge(self, other): # return other # ... or we may use the given embeddings: if self.embeddings != [None] and other.embeddings != [None]: - from sage.all import QQ + from sage.rings.rational_field import QQ KS = self(QQ) KO = other(QQ) if KS.has_coerce_map_from(KO): @@ -3566,7 +3568,7 @@ def merge(self, other): """ if self.__class__ != other.__class__: return None - from sage.sets.all import FiniteEnumeratedSet + from sage.sets.finite_enumerated_set import FiniteEnumeratedSet new_domain = set(self._domain).union(set(other._domain)) try: From 19ac6fd5e7826aa726a555bf73dfcde0f753e579 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 00:00:40 -0700 Subject: [PATCH 261/511] src/sage/rings/complex_interval_field.py: Fixup deprecation warning in doctest output --- src/sage/rings/complex_interval_field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index 05758d9956b..013977aa338 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -56,11 +56,11 @@ def is_ComplexIntervalField(x): EXAMPLES:: sage: from sage.rings.complex_interval_field import is_ComplexIntervalField as is_CIF + sage: is_CIF(CIF) doctest:warning... DeprecationWarning: is_ComplexIntervalField is deprecated; use isinstance(..., sage.rings.abc.ComplexIntervalField) instead See https://trac.sagemath.org/32612 for details. - sage: is_CIF(CIF) True sage: is_CIF(CC) False From e18d1fb9864580a70255291b84396ec67d94660f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 00:07:43 -0700 Subject: [PATCH 262/511] src/sage/categories/enumerated_sets.py: Remove .all import --- src/sage/categories/enumerated_sets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 4ca5747f04e..68bebd0f84f 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -146,7 +146,7 @@ def _call_(self, X): """ import sage.sets.set if isinstance(X, (tuple, list, set, range, sage.sets.set.Set_object_enumerated)): - return sage.sets.all.FiniteEnumeratedSet(X) + return sage.sets.finite_enumerated_set.FiniteEnumeratedSet(X) raise NotImplementedError class ParentMethods: From f31deb3c73264040962e0d7b9f43bc0d38d07d8c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 08:49:16 -0700 Subject: [PATCH 263/511] src/sage/rings/qqbar.py: Remove unused import --- src/sage/rings/qqbar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index a36b5de3c72..63b566f47f2 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -566,7 +566,7 @@ from sage.rings.real_mpfr import RR from sage.rings.real_mpfi import RealIntervalField, RIF, is_RealIntervalFieldElement, RealIntervalField_class from sage.rings.complex_mpfr import ComplexField -from sage.rings.complex_interval_field import ComplexIntervalField, is_ComplexIntervalField +from sage.rings.complex_interval_field import ComplexIntervalField from sage.rings.complex_interval import is_ComplexIntervalFieldElement from sage.rings.polynomial.all import PolynomialRing from sage.rings.polynomial.polynomial_element import is_Polynomial From 14fd1e54a13b1df7f81858019b31fb92cdf36007 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 15:37:57 -0700 Subject: [PATCH 264/511] src/doc/en/developer/coding_basics.rst: Update discussion of feature tags --- src/doc/en/developer/coding_basics.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index f6413de91e8..31d87ef7d84 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -1101,9 +1101,10 @@ framework. Here is a comprehensive list: .. NOTE:: - Any words after ``# optional`` are interpreted as a list of - package names, separated by spaces. + package (spkg) names or other feature tags, separated by spaces. - - Any punctuation (periods, commas, hyphens, semicolons, ...) after the + - Any punctuation other than underscores (``_``) and periods (``.``), + that is, commas, hyphens, semicolons, ..., after the first word ends the list of packages. Hyphens or colons between the word ``optional`` and the first package name are allowed. Therefore, you should not write ``optional: needs package CHomP`` but simply From 29f5a7ee02dc0064af63c2f58a262bb431b077d3 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 5 Oct 2021 12:28:49 +0900 Subject: [PATCH 265/511] Replacing all sage.combinat.family import with sage.sets.family. --- src/sage/algebras/iwahori_hecke_algebra.py | 2 +- src/sage/categories/modules_with_basis.py | 4 ++-- src/sage/combinat/chas/fsym.py | 2 +- src/sage/combinat/fqsym.py | 2 +- src/sage/combinat/root_system/type_E.py | 2 +- src/sage/combinat/root_system/type_F.py | 2 +- src/sage/combinat/root_system/weight_lattice_realizations.py | 2 +- src/sage/libs/coxeter3/coxeter_group.py | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 660699d2a93..a35fd831f9d 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -30,7 +30,7 @@ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.arith.all import is_square from sage.combinat.root_system.coxeter_group import CoxeterGroup -from sage.combinat.family import Family +from sage.sets.family import Family from sage.combinat.free_module import CombinatorialFreeModule diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index bb1dd2d4bbf..6cd291e4c91 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -219,7 +219,7 @@ def basis(self): sage: list(QS3.basis()) [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] """ - from sage.combinat.family import Family + from sage.sets.family import Family return Family(self._indices, self.monomial) def module_morphism(self, on_basis=None, matrix=None, function=None, @@ -1155,7 +1155,7 @@ def _apply_module_morphism(self, x, on_basis, codomain=False): """ if x == self.zero(): if not codomain: - from sage.combinat.family import Family + from sage.sets.family import Family B = Family(self.basis()) try: z = B.first() diff --git a/src/sage/combinat/chas/fsym.py b/src/sage/combinat/chas/fsym.py index 5a3fe04b921..d618f44d3fd 100644 --- a/src/sage/combinat/chas/fsym.py +++ b/src/sage/combinat/chas/fsym.py @@ -284,7 +284,7 @@ def basis(self, degree=None): sage: TG.basis(degree=3).list() [G[123], G[13|2], G[12|3], G[1|2|3]] """ - from sage.combinat.family import Family + from sage.sets.family import Family if degree is None: return Family(self._indices, self.monomial) else: diff --git a/src/sage/combinat/fqsym.py b/src/sage/combinat/fqsym.py index fc29f0f0a06..ba89286a1a3 100644 --- a/src/sage/combinat/fqsym.py +++ b/src/sage/combinat/fqsym.py @@ -1337,7 +1337,7 @@ def basis(self, degree=None): sage: G.basis(degree=3).list() [G[1, 2, 3], G[1, 3, 2], G[2, 1, 3], G[2, 3, 1], G[3, 1, 2], G[3, 2, 1]] """ - from sage.combinat.family import Family + from sage.sets.family import Family if degree is None: return Family(self._indices, self.monomial) else: diff --git a/src/sage/combinat/root_system/type_E.py b/src/sage/combinat/root_system/type_E.py index 7c910ecab6d..aeb03ecccd9 100644 --- a/src/sage/combinat/root_system/type_E.py +++ b/src/sage/combinat/root_system/type_E.py @@ -13,7 +13,7 @@ from . import ambient_space from sage.rings.all import ZZ -from sage.combinat.family import Family +from sage.sets.family import Family class AmbientSpace(ambient_space.AmbientSpace): """ diff --git a/src/sage/combinat/root_system/type_F.py b/src/sage/combinat/root_system/type_F.py index f7b9dbcf667..3ce580d78e0 100644 --- a/src/sage/combinat/root_system/type_F.py +++ b/src/sage/combinat/root_system/type_F.py @@ -13,7 +13,7 @@ from . import ambient_space from sage.rings.all import ZZ -from sage.combinat.family import Family +from sage.sets.family import Family # TODO: double check that this can't be defined over ZZ diff --git a/src/sage/combinat/root_system/weight_lattice_realizations.py b/src/sage/combinat/root_system/weight_lattice_realizations.py index 033152d42ec..0503d6ddc74 100644 --- a/src/sage/combinat/root_system/weight_lattice_realizations.py +++ b/src/sage/combinat/root_system/weight_lattice_realizations.py @@ -23,7 +23,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.all import prod from sage.categories.category_types import Category_over_base_ring -from sage.combinat.family import Family +from sage.sets.family import Family from .root_lattice_realizations import RootLatticeRealizations diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index b4118ca9592..fe4457b5eaf 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -160,7 +160,7 @@ def simple_reflections(self): sage: s[2]*s[1]*s[2] # optional - coxeter3 [2, 1, 2] """ - from sage.combinat.family import Family + from sage.sets.family import Family return Family(self.index_set(), lambda i: self.element_class(self, [i])) gens = simple_reflections From 6228141f7317aeb05034e68099b54306aefdbc0a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 5 Oct 2021 15:22:26 +0900 Subject: [PATCH 266/511] Allowing more than 9 variables for quantum matrix coordinate ring. --- .../quantum_matrix_coordinate_algebra.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/quantum_matrix_coordinate_algebra.py b/src/sage/algebras/quantum_matrix_coordinate_algebra.py index 498aa34811d..a38a00aa2b7 100644 --- a/src/sage/algebras/quantum_matrix_coordinate_algebra.py +++ b/src/sage/algebras/quantum_matrix_coordinate_algebra.py @@ -515,6 +515,16 @@ def __init__(self, m, n, q, bar, R): sage: O = algebras.QuantumMatrixCoordinate(4) sage: TestSuite(O).run() + + sage: O = algebras.QuantumMatrixCoordinate(10) + sage: O.variable_names() + ('x0101', ..., 'x1010') + sage: O = algebras.QuantumMatrixCoordinate(11,3) + sage: O.variable_names() + ('x011', ..., 'x113') + sage: O = algebras.QuantumMatrixCoordinate(3,11) + sage: O.variable_names() + ('x101', ..., 'x311') """ gp_indices = [(i, j) for i in range(1, m + 1) for j in range(1, n + 1)] @@ -526,7 +536,10 @@ def __init__(self, m, n, q, bar, R): self._m = m QuantumMatrixCoordinateAlgebra_abstract.__init__(self, gp_indices, n, q, bar, R, cat) # Set the names - names = ['x{}{}'.format(*k) for k in gp_indices] + mb = len(str(m)) + nb = len(str(n)) + base = 'x{{:0>{}}}{{:0>{}}}'.format(mb,nb) + names = [base.format(*k) for k in gp_indices] self._assign_names(names) def _repr_(self): @@ -992,3 +1005,4 @@ def _generator_key(t): if isinstance(t, tuple): return t return () + From 9ea834aba64a3e54ee9e96a668e875e3964be442 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 5 Oct 2021 15:28:00 +0900 Subject: [PATCH 267/511] Speedup for quantum det. --- src/sage/algebras/quantum_matrix_coordinate_algebra.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/quantum_matrix_coordinate_algebra.py b/src/sage/algebras/quantum_matrix_coordinate_algebra.py index a38a00aa2b7..26b783d7101 100644 --- a/src/sage/algebras/quantum_matrix_coordinate_algebra.py +++ b/src/sage/algebras/quantum_matrix_coordinate_algebra.py @@ -238,9 +238,8 @@ def quantum_determinant(self): raise ValueError("undefined for non-square quantum matrices") from sage.combinat.permutation import Permutations q = self._q - return self.sum(self.term(self._indices({(i, p(i)): 1 for i in range(1, self._n + 1)}), - (-q) ** p.length()) - for p in Permutations(self._n)) + return self._from_dict({self._indices({(i, p(i)): 1 for i in range(1, self._n + 1)}): + (-q) ** p.length() for p in Permutations(self._n)}) def product_on_basis(self, a, b): """ From 28dc817c7b8a97807e5514d28a66a178652d3ed4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 22:28:02 -0700 Subject: [PATCH 268/511] Polyhedron._test...: Avoid testing using unavailable functionality --- src/sage/geometry/polyhedron/base.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 47063568802..32e2193fd1c 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -6369,12 +6369,17 @@ def _test_lawrence(self, tester=None, **options): with warnings.catch_warnings(): warnings.simplefilter("error") try: + from sage.rings.real_double_field import RDF + two = RDF(2.0) # Implicitly checks :trac:`30328`. - R = self.lawrence_extension(2.0*v - self.center()) + R = self.lawrence_extension(two * v - self.center()) tester.assertEqual(self.dim() + 1, R.dim()) tester.assertEqual(self.n_vertices() + 2, R.n_vertices()) tester.assertTrue(Q.is_combinatorially_isomorphic(R)) + except ImportError: + # RDF not available + pass except UserWarning: # Data is numerically complicated. pass @@ -7373,8 +7378,13 @@ def _test_combinatorial_face_as_combinatorial_polyhedron(self, tester=None, **op D2 = f2.as_combinatorial_polyhedron(quotient=True).dual() D1._test_bitsets(tester, **options) D2._test_bitsets(tester, **options) - tester.assertTrue(P.combinatorial_polyhedron().vertex_facet_graph().is_isomorphic(D1.vertex_facet_graph())) - tester.assertTrue(P.combinatorial_polyhedron().vertex_facet_graph().is_isomorphic(D2.vertex_facet_graph())) + try: + import sage.graphs.graph + except ImportError: + pass + else: + tester.assertTrue(P.combinatorial_polyhedron().vertex_facet_graph().is_isomorphic(D1.vertex_facet_graph())) + tester.assertTrue(P.combinatorial_polyhedron().vertex_facet_graph().is_isomorphic(D2.vertex_facet_graph())) @cached_method(do_pickle=True) def f_vector(self, num_threads=None, parallelization_depth=None): @@ -7954,7 +7964,12 @@ def check_pyramid_certificate(P, cert): tester.assertTrue(b) check_pyramid_certificate(polar_pyr, cert) - tester.assertTrue(pyr_polar.is_combinatorially_isomorphic(pyr_polar)) + try: + import sage.graphs.graph + except ImportError: + pass + else: + tester.assertTrue(pyr_polar.is_combinatorially_isomorphic(pyr_polar)) # Basic properties of the pyramid. @@ -10736,6 +10751,11 @@ def _test_is_combinatorially_isomorphic(self, tester=None, **options): # Avoid very long doctests. return + try: + import sage.graphs.graph + except ImportError: + return + tester.assertTrue(self.is_combinatorially_isomorphic(ZZ(4)*self)) if self.n_vertices(): tester.assertTrue(self.is_combinatorially_isomorphic(self + self.center())) From 52ac1dac69cfc8b869459e08408ff94ff2f81611 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 23:26:44 -0700 Subject: [PATCH 269/511] Polyhedron_base._test_gale_transform: Do not test is_combinatorially_isomorphic if sage.graphs.graphs not available --- src/sage/geometry/polyhedron/base.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 32e2193fd1c..d6662d8a156 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -4220,7 +4220,12 @@ def _test_gale_transform(self, tester=None, **options): g = self.gale_transform() P = gale_transform_to_polytope(g, base_ring=self.base_ring(), backend=self.backend()) - tester.assertTrue(self.is_combinatorially_isomorphic(P)) + try: + import sage.graphs.graph + except ImportError: + pass + else: + tester.assertTrue(self.is_combinatorially_isomorphic(P)) @cached_method def normal_fan(self, direction='inner'): From 9793567a731d895b9239bee77d76e66276531172 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Tue, 5 Oct 2021 09:53:05 +0200 Subject: [PATCH 270/511] adding quantum_determinant to matrix --- src/sage/matrix/matrix2.pyx | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index d4a8ec9d3a1..bb6f9855c0f 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -62,6 +62,7 @@ AUTHORS: - Michael Jung (2020-10-02): added Bär-Faddeev-LeVerrier algorithm for the Pfaffian +- Moritz Firsching(2020-10-05): added ``quantum_determinant`` """ # **************************************************************************** @@ -2113,6 +2114,43 @@ cdef class Matrix(Matrix1): self.swap_rows(level, i) return d + def quantum_determinant(self, q=None): + r""" + Return the quantum deteminant of a matrix. + + INPUT: + - ``q`` -- a symbolic variable or a generator for a + (Laurent) polynomial ring. Creates a generator for a + polynomial ring over the base ring of the by default. + + EXAMPLES:: + + sage: A = Matrix([[SR(f'a{i}{j}') for i in range(2)] + ....: for j in range(2)]); A + [a00 a10] + [a01 a11] + sage: A.quantum_determinant() + -a01*a10*q + a00*a11 + sage: R. = LaurentPolynomialRing(ZZ) + sage: A = MatrixSpace(Integers(8),3)([1,7,3, 1,1,1, 3,4,5]) + sage: A.quantum_determinant(q) + 5 + q + q^2 + 7*q^3 + """ + n = self._ncols + + if self._nrows != n: + raise ValueError("self must be a square matrix") + + if q is None: + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + q = PolynomialRing(self.base_ring(), 'q').gen() + + from sage.misc.misc_c import prod + from sage.combinat.permutation import Permutations + return sum((-q)**(s.number_of_inversions()) * + prod(self[s(i + 1) - 1, i] for i in range(n)) + for s in Permutations(n)) + def pfaffian(self, algorithm=None, check=True): r""" Return the Pfaffian of ``self``, assuming that ``self`` is an From b8969296368a4a1ad944792780d3cba17f72817a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 5 Oct 2021 19:08:12 +0900 Subject: [PATCH 271/511] Reviewer changes to quantum_determinant. --- src/sage/matrix/matrix2.pyx | 48 ++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index bb6f9855c0f..cbe509e2180 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -2116,27 +2116,52 @@ cdef class Matrix(Matrix1): def quantum_determinant(self, q=None): r""" - Return the quantum deteminant of a matrix. + Return the quantum deteminant of ``self``. INPUT: - - ``q`` -- a symbolic variable or a generator for a - (Laurent) polynomial ring. Creates a generator for a - polynomial ring over the base ring of the by default. + + - ``q`` -- the parameter `q`; the default is `q \in F[q]`, + where `F` is the base ring of ``self`` EXAMPLES:: - sage: A = Matrix([[SR(f'a{i}{j}') for i in range(2)] + sage: A = matrix([[SR(f'a{i}{j}') for i in range(2)] ....: for j in range(2)]); A [a00 a10] [a01 a11] sage: A.quantum_determinant() -a01*a10*q + a00*a11 + + sage: A = matrix([[SR(f'a{i}{j}') for i in range(3)] + ....: for j in range(3)]) + sage: A.quantum_determinant() + -a02*a11*a20*q^3 + (a01*a12*a20 + a02*a10*a21)*q^2 + + (-a00*a12*a21 - a01*a10*a22)*q + a00*a11*a22 + sage: R. = LaurentPolynomialRing(ZZ) - sage: A = MatrixSpace(Integers(8),3)([1,7,3, 1,1,1, 3,4,5]) - sage: A.quantum_determinant(q) - 5 + q + q^2 + 7*q^3 + sage: MS = MatrixSpace(Integers(8), 3) + sage: A = MS([1,7,3, 1,1,1, 3,4,5]) + sage: A.det() + 6 + sage: A.quantum_determinant(q^-2) + 7*q^-6 + q^-4 + q^-2 + 5 + + sage: S. = PolynomialRing(GF(7)) + sage: R. = LaurentPolynomialRing(S) + sage: MS = MatrixSpace(S, 3, sparse=True) + sage: A = MS([[x, y, 3], [4, 2+y, x^2], [0, 1-x, x+y]]) + sage: A.det() + x^4 - x^3 + x^2*y + x*y^2 + 2*x^2 - 2*x*y + 3*y^2 + 2*x - 2 + sage: A.quantum_determinant() + (2*x - 2)*q^2 + (x^4 - x^3 + 3*x*y + 3*y^2)*q + x^2*y + x*y^2 + 2*x^2 + 2*x*y + sage: A.quantum_determinant(int(2)) + 2*x^4 - 2*x^3 + x^2*y + x*y^2 + 2*x^2 + x*y - y^2 + x - 1 + sage: A.quantum_determinant(q*x + q^-1*y) + (2*x*y^2 - 2*y^2)*q^-2 + (x^4*y - x^3*y + 3*x*y^2 + 3*y^3)*q^-1 + + (-2*x^2*y + x*y^2 + 2*x^2 - 2*x*y) + + (x^5 - x^4 + 3*x^2*y + 3*x*y^2)*q + (2*x^3 - 2*x^2)*q^2 """ - n = self._ncols + cdef Py_ssize_t n = self._ncols if self._nrows != n: raise ValueError("self must be a square matrix") @@ -2147,8 +2172,9 @@ cdef class Matrix(Matrix1): from sage.misc.misc_c import prod from sage.combinat.permutation import Permutations - return sum((-q)**(s.number_of_inversions()) * - prod(self[s(i + 1) - 1, i] for i in range(n)) + cdef Py_ssize_t i + return sum((-q)**s.number_of_inversions() + * prod(self.get_unsafe(s[i] - 1, i) for i in range(n)) for s in Permutations(n)) def pfaffian(self, algorithm=None, check=True): From c2e0df82741088621dea14172f47a816a51aceff Mon Sep 17 00:00:00 2001 From: Julian Ritter Date: Tue, 5 Oct 2021 13:14:28 +0200 Subject: [PATCH 272/511] replaced "as far as" by "if" --- src/sage/geometry/polyhedron/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 47063568802..c8bff702b56 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -3312,7 +3312,7 @@ def representative_point(self): OUTPUT: A point as a coordinate vector. The point is chosen to be - interior as far as possible. If the polyhedron is not + interior if possible. If the polyhedron is not full-dimensional, the point is in the relative interior. If the polyhedron is zero-dimensional, its single point is returned. From 924dc714eddde5bb8168126e0baccbe6ae3cb604 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 5 Oct 2021 21:12:14 +0900 Subject: [PATCH 273/511] Adding a description of the quantum det. --- src/sage/matrix/matrix2.pyx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index cbe509e2180..8373ca6d7ea 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -2118,6 +2118,19 @@ cdef class Matrix(Matrix1): r""" Return the quantum deteminant of ``self``. + The quantum determinant of a matrix `M = (m_{ij})_{i,j=1}^n` + is defined by + + .. MATH:: + + \det_q(M) = + \sum_{\sigma \in S_n} (-q)^{\ell(\sigma)} M_{\sigma(i),j}, + + where `S_n` is symmetric group on `\{1, \ldots, n\}` and + `\ell(\sigma)` denotes the length of `\sigma` witten as simple + transpositions (equivalently the number of inversions when + written in one-line notation). + INPUT: - ``q`` -- the parameter `q`; the default is `q \in F[q]`, @@ -2177,6 +2190,8 @@ cdef class Matrix(Matrix1): * prod(self.get_unsafe(s[i] - 1, i) for i in range(n)) for s in Permutations(n)) + qdet = quantum_determinant + def pfaffian(self, algorithm=None, check=True): r""" Return the Pfaffian of ``self``, assuming that ``self`` is an From d457a590d19791fa16eda91b99b7203f781a4715 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 5 Oct 2021 21:34:21 +0900 Subject: [PATCH 274/511] Fixing typos in qdet description. --- src/sage/matrix/matrix2.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 8373ca6d7ea..0c741a395d3 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -2126,8 +2126,8 @@ cdef class Matrix(Matrix1): \det_q(M) = \sum_{\sigma \in S_n} (-q)^{\ell(\sigma)} M_{\sigma(i),j}, - where `S_n` is symmetric group on `\{1, \ldots, n\}` and - `\ell(\sigma)` denotes the length of `\sigma` witten as simple + where `S_n` is the symmetric group on `\{1, \ldots, n\}` and + `\ell(\sigma)` denotes the length of `\sigma` written as simple transpositions (equivalently the number of inversions when written in one-line notation). From 6dfcfd9517f7a3d7ee5aa58ac80b29464f3c1248 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Tue, 5 Oct 2021 22:32:00 +0800 Subject: [PATCH 275/511] fix formula for Weierstrass isomorphisms when char=2, j!=0 --- .../elliptic_curves/weierstrass_morphism.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py index f55123c70ea..39ea09acb3d 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py @@ -282,6 +282,19 @@ def isomorphisms(E, F, JustOne=False): sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a1')) [] sage: isomorphisms(EllipticCurve_from_j(0),EllipticCurve('27a1'),JustOne=True) + + TESTS: + + Check that :trac:`32632` is fixed:: + + sage: z8 = GF(2^8).gen() + sage: E1 = EllipticCurve([z8, z8, z8, z8, z8]) + sage: isomorphisms(E1, E1) + [(1, 0, 0, 0), (1, 0, z8, z8)] + sage: E2 = EllipticCurve([z8^2, 0, 0, 0, z8^7 + z8^4]) + sage: isomorphisms(E1, E2) + [(z8^7 + z8^3 + z8^2 + z8, 1, 1, z8^7 + z8^3 + z8^2 + z8 + 1), + (z8^7 + z8^3 + z8^2 + z8, 1, z8 + 1, z8^7 + z8^3 + z8^2 + z8 + 1)] """ from .ell_generic import is_EllipticCurve if not is_EllipticCurve(E) or not is_EllipticCurve(F): @@ -325,7 +338,7 @@ def isomorphisms(E, F, JustOne=False): r = (a3E+a3F*u**3)/a1E slist = [s[0] for s in (x**2+a1E*x+(r+a2E+a2F*u**2)).roots()] for s in slist: - t = (a4E+a4F*u**4 + s*a3E + r*s*a1E + r**2) + t = (a4E+a4F*u**4 + s*a3E + r*s*a1E + r**2) / a1E if JustOne: return (u, r, s, t) ans.append((u, r, s, t)) From 71cb38201a3aca2411ffb774f671d5bacb7ee201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 5 Oct 2021 16:37:30 +0200 Subject: [PATCH 276/511] pep cleanup for toric Chow group file --- src/sage/schemes/toric/chow_group.py | 122 +++++++++++---------------- 1 file changed, 47 insertions(+), 75 deletions(-) diff --git a/src/sage/schemes/toric/chow_group.py b/src/sage/schemes/toric/chow_group.py index 84d32fe373e..34deb208d74 100644 --- a/src/sage/schemes/toric/chow_group.py +++ b/src/sage/schemes/toric/chow_group.py @@ -110,7 +110,6 @@ sage: sum( mixed.project_to_degree(i) for i in range(X.dimension()+1) ) == mixed True """ - # **************************************************************************** # Copyright (C) 2010 Volker Braun # @@ -118,6 +117,7 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +from __future__ import annotations from sage.misc.all import flatten from sage.misc.fast_methods import WithEqualityById @@ -133,9 +133,6 @@ from sage.schemes.toric.divisor import is_ToricDivisor - - -#******************************************************************* class ChowCycle(FGP_Element): """ The elements of the Chow group. @@ -158,7 +155,6 @@ class ChowCycle(FGP_Element): sage: A( Cone([(1,0)]) ) ( 0 | 1 | 0 ) """ - def __init__(self, parent, v, check=True): r""" Construct a :class:`ChowCycle`. @@ -184,7 +180,7 @@ def __init__(self, parent, v, check=True): """ FGP_Element.__init__(self, parent, v, check) - def _repr_(self): + def _repr_(self) -> str: r""" Return a string representation of the Chow cycle. @@ -230,7 +226,7 @@ def _repr_(self): s += ')' return s - def degree(self): + def degree(self) -> int: r""" The degree of the Chow cycle. @@ -253,14 +249,13 @@ def degree(self): ambient_dim = self.parent()._variety.dimension() cone_dim = None for i, cone in enumerate(self.parent()._cones): - if self.lift()[i]!=0: - if cone_dim not in [None,cone.dim()]: + if self.lift()[i] != 0: + if cone_dim not in [None, cone.dim()]: raise ValueError('Chow cycle is not of definite degree.') cone_dim = cone.dim() self._dim = ambient_dim - cone_dim return self._dim - def project_to_degree(self, degree): r""" Project a (mixed-degree) Chow cycle to the given ``degree``. @@ -287,13 +282,12 @@ def project_to_degree(self, degree): v = list(self.lift()) for i in range(len(v)): cone = self.parent()._cones[i] - if cone.dim() != ambient_dim-degree: + if cone.dim() != ambient_dim - degree: v[i] = 0 v = self.parent().cover()(v) P = self.parent() return P.element_class(P, v, check=False) - def count_points(self): r""" Return the number of points in the Chow cycle. @@ -340,9 +334,7 @@ def count_points(self): sage: P1xP1_Z2.integrate( Dt.cohomology_class() * Dy.cohomology_class() ) 1/2 """ - c0 = self.project_to_degree(0).lift() - return sum(c0) - + return sum(self.project_to_degree(0).lift()) def intersection_with_divisor(self, divisor): """ @@ -413,7 +405,7 @@ def intersection_with_divisor(self, divisor): (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)] """ - assert is_ToricDivisor(divisor), str(divisor)+' is not a toric divisor.' + assert is_ToricDivisor(divisor), f'{divisor} is not a toric divisor' A = self.parent() # the Chow group X = A._variety # the toric variety @@ -421,11 +413,11 @@ def intersection_with_divisor(self, divisor): coefficients = self.lift() for sigma_idx, sigma in enumerate(A._cones): - if sigma.dim()==X.dimension(): + if sigma.dim() == X.dimension(): # full-dimensional cone = degree-0 Chow cycle continue coefficient = coefficients[sigma_idx] - if coefficient==0: + if coefficient == 0: continue D = divisor.move_away_from(sigma) for gamma in sigma.facet_of(): @@ -436,13 +428,11 @@ def intersection_with_divisor(self, divisor): i = I_gamma.pop() # index of a ray in gamma but not sigma v_i = X.fan().ray(i) a_i = D.coefficient(i) - s_i = (v_i*perp)/(n*perp) - b_gamma = a_i/s_i - # print sigma._points_idx, "\t", i, D, a_i, s_i, b_gamma, gamma.A() - intersection += self.base_ring()(coefficient*b_gamma) * A(gamma) + s_i = (v_i * perp) / (n * perp) + b_gamma = a_i / s_i + intersection += self.base_ring()(coefficient * b_gamma) * A(gamma) return intersection - def cohomology_class(self): r""" Return the (Poincaré-dual) cohomology class. @@ -523,13 +513,13 @@ def cohomology_class(self): """ toric_variety = self.parent().scheme() if not toric_variety.is_orbifold(): - raise ValueError + raise ValueError('not an orbifold') HH = toric_variety.cohomology_ring() coeff = self.lift() - return sum([ HH(cone) * coeff[i] for i,cone in enumerate(self.parent()._cones) ]) + return sum([HH(cone) * coeff[i] + for i, cone in enumerate(self.parent()._cones)]) -#******************************************************************* class ChowGroupFactory(UniqueFactory): """ Factory for :class:`ChowGroup_class`. @@ -558,14 +548,13 @@ def create_key_and_extra_args(self, toric_variety, base_ring=ZZ, check=True): if not is_ToricVariety(toric_variety): raise ValueError('First argument must be a toric variety.') - if not base_ring in [ZZ,QQ]: + if base_ring not in [ZZ, QQ]: raise ValueError('Base ring must be either ZZ or QQ.') key = tuple([toric_variety, base_ring]) - extra = {'check':check} + extra = {'check': check} return key, extra - def create_object(self, version, key, **extra_args): """ Create a :class:`ChowGroup_class`. @@ -593,21 +582,19 @@ def create_object(self, version, key, **extra_args): ChowGroup = ChowGroupFactory('ChowGroup') -#******************************************************************* class ChowGroup_class(FGP_Module_class, WithEqualityById): r""" The Chow group of a toric variety. EXAMPLES:: - sage: P2=toric_varieties.P2() + sage: P2 = toric_varieties.P2() sage: from sage.schemes.toric.chow_group import ChowGroup_class sage: A = ChowGroup_class(P2,ZZ,True); A Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches sage: A.an_element() ( 0 | 0 | 1 ) """ - Element = ChowCycle def __init__(self, toric_variety, base_ring, check): @@ -615,7 +602,7 @@ def __init__(self, toric_variety, base_ring, check): EXAMPLES:: sage: from sage.schemes.toric.chow_group import * - sage: P2=toric_varieties.P2() + sage: P2 = toric_varieties.P2() sage: A = ChowGroup_class(P2,ZZ,True); A Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches sage: is_ChowGroup(A) @@ -639,7 +626,7 @@ def __init__(self, toric_variety, base_ring, check): sage: print(coercion_model.get_action(A_ZZ, QQ)) None - You can't multiply integer classes with fractional + You cannot multiply integer classes with fractional numbers. For that you need to go to the rational Chow group:: sage: A_QQ = P2.Chow_group(QQ) @@ -657,13 +644,12 @@ def __init__(self, toric_variety, base_ring, check): self._variety = toric_variety # cones are automatically sorted by dimension - self._cones = flatten( toric_variety.fan().cones() ) + self._cones = flatten(toric_variety.fan().cones()) V = FreeModule(base_ring, len(self._cones)) W = self._rational_equivalence_relations(V) - super(ChowGroup_class,self).__init__(V, W, check) - + super(ChowGroup_class, self).__init__(V, W, check) def scheme(self): r""" @@ -685,7 +671,6 @@ def scheme(self): """ return self._variety - def _element_constructor_(self, x, check=True): r""" Construct a :class:`ChowCycle`. @@ -716,15 +701,14 @@ def _element_constructor_(self, x, check=True): cone = fan.embed(x) return self.element_class(self, self._cone_to_V(cone), False) if is_ToricDivisor(x): - v = sum(x.coefficient(i)*self._cone_to_V(onecone) - for i,onecone in enumerate(fan(1))) + v = sum(x.coefficient(i) * self._cone_to_V(onecone) + for i, onecone in enumerate(fan(1))) return self.element_class(self, v, False) - return super(ChowGroup_class,self)._element_constructor_(x, check) - + return super(ChowGroup_class, self)._element_constructor_(x, check) def _coerce_map_from_(self, S): """ - Return true if S canonically coerces to self. + Return ``True`` if ``S`` canonically coerces to ``self``. EXAMPLES:: @@ -735,9 +719,8 @@ def _coerce_map_from_(self, S): False """ # We might want to coerce Cone_of_fans into ChowCycles - # but cones don't have parents at the moment. - return super(ChowGroup_class,self)._coerce_map_from_(S) - + # but cones do not have parents at the moment. + return super(ChowGroup_class, self)._coerce_map_from_(S) def _rational_equivalence_relations(self, V): r""" @@ -770,8 +753,8 @@ def _rational_equivalence_relations(self, V): for sigma in rho.facet_of(): sigma_idx = self._cones.index(sigma) Q = sigma.relative_quotient(rho) - for v in [n.lift() for n in Q.gens()]: - rel += (u * v) * V.gen(sigma_idx) + for n in Q.gens(): + rel += (u * n.lift()) * V.gen(sigma_idx) relations.append(rel) return V.span(relations) @@ -790,18 +773,17 @@ def __truediv__(self, other): sage: A/Asub Traceback (most recent call last): ... - NotImplementedError: Quotients of the Chow group are not implemented. + NotImplementedError: quotients of the Chow group are not implemented """ - raise NotImplementedError('Quotients of the Chow group are not implemented.') + raise NotImplementedError('quotients of the Chow group are not implemented') - - def _repr_(self): + def _repr_(self) -> str: """ Return a string representation. EXAMPLES:: - sage: P2=toric_varieties.P2() + sage: P2 = toric_varieties.P2() sage: from sage.schemes.toric.chow_group import ChowGroup sage: ChowGroup(P2,ZZ)._repr_() 'Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches' @@ -840,7 +822,6 @@ def _cone_to_V(self, cone): x[self._cones.index(cone)] = 1 return self._V(x) - def degree(self, k=None): r""" Return the degree-`k` Chow group. @@ -939,11 +920,10 @@ def degree(self, k=None): except AttributeError: pass - self._degree = tuple(ChowGroup_degree_class(self,d) + self._degree = tuple(ChowGroup_degree_class(self, d) for d in range(self._variety.dimension() + 1)) return self._degree - def coordinate_vector(self, chow_cycle, degree=None, reduce=True): r""" Return the coordinate vector of the ``chow_cycle``. @@ -981,7 +961,6 @@ def coordinate_vector(self, chow_cycle, degree=None, reduce=True): a = chow_cycle.project_to_degree(degree) return self.degree(degree).module().coordinate_vector(a, reduce=reduce) - def gens(self, degree=None): r""" Return the generators of the Chow group. @@ -1012,7 +991,6 @@ def gens(self, degree=None): else: return self.degree(degree).gens() - def relation_gens(self): r""" Return the Chow cycles equivalent to zero. @@ -1044,7 +1022,6 @@ def relation_gens(self): A tuple of Chow cycles, each rationally equivalent to zero, that generates the rational equivalence. - EXAMPLES:: sage: P2 = toric_varieties.P2() @@ -1057,11 +1034,9 @@ def relation_gens(self): sage: first.lift() (0, 1, 0, -1, 0, 0, 0) """ - gens = self.W().gens() - return tuple( self(gen) for gen in gens ) + return tuple(self(gen) for gen in self.W().gens()) -#******************************************************************* class ChowGroup_degree_class(SageObject): r""" A fixed-degree subgroup of the Chow group of a toric variety. @@ -1119,11 +1094,10 @@ def __init__(self, A, d): # The minimal set of generators self._module = A.submodule(gens) - self._gens = tuple([ A.element_class(A, a.lift(), False) - for a in self._module.gens() ]) - + self._gens = tuple([A.element_class(A, a.lift(), False) + for a in self._module.gens()]) - def _repr_(self): + def _repr_(self) -> str: """ Return a string representation. @@ -1153,7 +1127,7 @@ def _repr_(self): elif self._Chow_group.base_ring() is QQ: ring = 'Q' else: - raise NotImplementedError('Base ring must be ZZ or QQ.') + raise NotImplementedError('base ring must be ZZ or QQ') s = ['C' + str(x) for x in tors] if len(free) == 1: @@ -1179,7 +1153,7 @@ def module(self): """ return self._module - def ngens(self): + def ngens(self) -> int: """ Return the number of generators. @@ -1238,8 +1212,7 @@ def gens(self): return self._gens -#******************************************************************* -def is_ChowGroup(x): +def is_ChowGroup(x) -> bool: r""" Return whether ``x`` is a :class:`ChowGroup_class` @@ -1261,11 +1234,10 @@ def is_ChowGroup(x): sage: is_ChowGroup('Victoria') False """ - return isinstance(x,ChowGroup_class) + return isinstance(x, ChowGroup_class) -#******************************************************************* -def is_ChowCycle(x): +def is_ChowCycle(x) -> bool: r""" Return whether ``x`` is a :class:`ChowGroup_class` @@ -1279,7 +1251,7 @@ def is_ChowCycle(x): EXAMPLES:: - sage: P2=toric_varieties.P2() + sage: P2 = toric_varieties.P2() sage: A = P2.Chow_group() sage: from sage.schemes.toric.chow_group import * sage: is_ChowCycle(A) @@ -1289,4 +1261,4 @@ def is_ChowCycle(x): sage: is_ChowCycle('Victoria') False """ - return isinstance(x,ChowCycle) + return isinstance(x, ChowCycle) From 15f2086c821a2ac2ef062023a70e41ea835734bb Mon Sep 17 00:00:00 2001 From: Julian Ritter Date: Tue, 5 Oct 2021 17:06:54 +0200 Subject: [PATCH 277/511] Removed import of deprecated_function_alias (imported but unused according to pyflakes) --- src/sage/geometry/polyhedron/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index c8bff702b56..f3b23fa3bb8 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -39,7 +39,6 @@ from sage.misc.cachefunc import cached_method from sage.misc.all import prod from sage.misc.randstate import current_randstate -from sage.misc.superseded import deprecated_function_alias from sage.rings.all import QQ, ZZ, AA from sage.rings.real_double import RDF From 22f125bcd0544c53c32cead5ccc2bb260f450716 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 15:57:09 -0700 Subject: [PATCH 278/511] src/sage/misc/latex.py: Move import from sage.misc.sage_eval into method --- src/sage/misc/latex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 3aa015bb062..5c9d8680efd 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -31,7 +31,6 @@ import shutil from subprocess import call, PIPE -from sage.misc import sage_eval from sage.misc.cachefunc import cached_function, cached_method from sage.misc.sage_ostools import have_program from sage.misc.temporary_file import tmp_dir @@ -1015,6 +1014,7 @@ def _latex_preparse(self, s, locals): sage: sage.misc.latex.Latex()._latex_preparse(r'\sage{s}', locals()) '2' """ + from sage.misc.sage_eval import sage_eval i0 = -1 while True: i = s.find('\\sage{') @@ -1028,7 +1028,7 @@ def _latex_preparse(self, s, locals): var = t[:j] try: - k = str(latex(sage_eval.sage_eval(var, locals))) + k = str(latex(sage_eval(var, locals))) except Exception as msg: print(msg) k = '\\mbox{\\rm [%s undefined]}' % var From 0809840464cd51dc09624d5953894dec04bf9c3b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 16:22:10 -0700 Subject: [PATCH 279/511] src/sage/misc/latex.py: Move import of have_program into methods --- src/sage/misc/latex.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 5c9d8680efd..56a47ea4513 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -32,7 +32,6 @@ from subprocess import call, PIPE from sage.misc.cachefunc import cached_function, cached_method -from sage.misc.sage_ostools import have_program from sage.misc.temporary_file import tmp_dir from sage.structure.sage_object import SageObject @@ -81,6 +80,7 @@ def have_latex() -> bool: sage: have_latex() # random True """ + from sage.misc.sage_ostools import have_program return have_program('latex') @@ -98,6 +98,7 @@ def have_pdflatex() -> bool: sage: have_pdflatex() # random True """ + from sage.misc.sage_ostools import have_program return have_program('pdflatex') @@ -115,6 +116,7 @@ def have_xelatex() -> bool: sage: have_xelatex() # random True """ + from sage.misc.sage_ostools import have_program return have_program('xelatex') @@ -132,6 +134,7 @@ def have_dvipng() -> bool: sage: have_dvipng() # random True """ + from sage.misc.sage_ostools import have_program return have_program('dvipng') @@ -150,6 +153,7 @@ def have_convert() -> bool: sage: have_convert() # random True """ + from sage.misc.sage_ostools import have_program return have_program('convert') From bdd032501fd8ad7b5363c4269cdc598c9fd29826 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 16:21:36 -0700 Subject: [PATCH 280/511] sage.repl.display.fancy_repr: For isinstance testing, import abc Matrix from sage.structure.element --- src/sage/repl/display/fancy_repr.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/repl/display/fancy_repr.py b/src/sage/repl/display/fancy_repr.py index de3a5569ba5..6a231d526d8 100644 --- a/src/sage/repl/display/fancy_repr.py +++ b/src/sage/repl/display/fancy_repr.py @@ -200,10 +200,7 @@ def __call__(self, obj, p, cycle): if not p.toplevel(): # Do not print the help for matrices inside containers return False - try: - from sage.matrix.matrix1 import Matrix - except ModuleNotFoundError: - return False + from sage.structure.element import Matrix if not isinstance(obj, Matrix): return False from sage.matrix.constructor import options From e94e96f00087822e829ae46fc70c0ab01a88ec58 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Sep 2021 15:11:05 -0700 Subject: [PATCH 281/511] src/sage/matrix/{matrix_space.py,action.pyx}: Do not fail if sage.schemes is not present --- src/sage/matrix/action.pyx | 7 ++++++- src/sage/matrix/matrix_space.py | 7 +++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/action.pyx b/src/sage/matrix/action.pyx index 14d2d5cc414..6d4d7853b5f 100644 --- a/src/sage/matrix/action.pyx +++ b/src/sage/matrix/action.pyx @@ -66,7 +66,12 @@ from .matrix_space import MatrixSpace, is_MatrixSpace from sage.modules.free_module import FreeModule, is_FreeModule from sage.structure.coerce cimport coercion_model from sage.categories.homset import Hom, End -from sage.schemes.generic.homset import SchemeHomset_generic, SchemeHomset_points + + +try: + from sage.schemes.generic.homset import SchemeHomset_generic, SchemeHomset_points +except ImportError: + SchemeHomset_generic = SchemeHomset_points = () cdef class MatrixMulAction(Action): diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 47766db0c46..15423ad1b8f 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -968,8 +968,11 @@ def _get_action_(self, S, op, self_on_left): Left scalar multiplication by Integer Ring on Full MatrixSpace of 2 by 3 dense matrices over Rational Field """ try: - from sage.schemes.generic.homset import SchemeHomset_generic - from sage.schemes.generic.homset import SchemeHomset_points + try: + from sage.schemes.generic.homset import SchemeHomset_generic + from sage.schemes.generic.homset import SchemeHomset_points + except ImportError: + SchemeHomset_generic = SchemeHomset_points = None if op is operator.mul: from . import action as matrix_action if self_on_left: From bc2b707315325ec40dc4e257ce8fa538cbd75b6c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 10:27:55 -0700 Subject: [PATCH 282/511] sage.misc.lazy_import.finish_startup: Fixup --- src/sage/misc/lazy_import.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 880cf80352c..771c2f600f3 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -98,7 +98,7 @@ cpdef finish_startup(): ... AssertionError: finish_startup() must be called exactly once """ - global startup_guard + global startup_guard, finish_startup_called assert startup_guard, 'finish_startup() must be called exactly once' startup_guard = False finish_startup_called = True From 37ee682cde696bd9a49b61b2f5081f042d4b3f68 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 16:34:57 -0700 Subject: [PATCH 283/511] sage.structure.element.Expression: New abc for sage.symbolic.expression.Expression --- src/sage/structure/element.pxd | 4 +++- src/sage/structure/element.pyx | 11 +++++++++++ src/sage/symbolic/expression.pyx | 3 ++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/sage/structure/element.pxd b/src/sage/structure/element.pxd index 3cc480aa18c..5c6e295a4b8 100644 --- a/src/sage/structure/element.pxd +++ b/src/sage/structure/element.pxd @@ -236,9 +236,11 @@ cdef class AlgebraElement(RingElement): cdef class CommutativeAlgebraElement(CommutativeRingElement): pass -cdef class InfinityElement(RingElement): +cdef class Expression(CommutativeRingElement): pass +cdef class InfinityElement(RingElement): + pass cdef class Vector(ModuleElementWithMutability): cdef Py_ssize_t _degree diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index d610bbb71cc..2e12a318981 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -47,6 +47,7 @@ abstract base classes. EuclideanDomainElement FieldElement CommutativeAlgebraElement + Expression AlgebraElement Matrix InfinityElement @@ -3254,6 +3255,16 @@ cdef class CommutativeRingElement(RingElement): ############################################## +cdef class Expression(CommutativeRingElement): + + r""" + Abstract base class for :class:`~sage.symbolic.expression.Expression`. + """ + + pass + + ############################################## + cdef class Vector(ModuleElementWithMutability): cdef bint is_sparse_c(self): raise NotImplementedError diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index de4720f90a7..5f49c78a260 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -385,6 +385,7 @@ from cpython.object cimport Py_EQ, Py_NE, Py_LE, Py_GE, Py_LT, Py_GT from sage.cpython.string cimport str_to_bytes, char_to_str from sage.structure.element cimport RingElement, Element, Matrix +from sage.structure.element cimport Expression as Expression_abc from sage.symbolic.complexity_measures import string_length from sage.symbolic.function cimport SymbolicFunction from sage.rings.rational import Rational @@ -694,7 +695,7 @@ def _subs_fun_make_dict(s): raise TypeError(msg.format(s)) -cdef class Expression(CommutativeRingElement): +cdef class Expression(Expression_abc): cdef GEx _gobj From 9830e4eb3a0d8dd387b89891c9d8af73cc668dd8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 16:39:40 -0700 Subject: [PATCH 284/511] src/sage/misc/lazy_import.pyx: Adjust doctest output to use of warnings.warn --- src/sage/misc/lazy_import.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 771c2f600f3..a454bd5d0e4 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -31,7 +31,7 @@ it is actually resolved after the startup, so that the developer knows that (s)he can remove the flag:: sage: ZZ - Option ``at_startup=True`` for lazy import ZZ not needed anymore + UserWarning: Option ``at_startup=True`` for lazy import ZZ not needed anymore Integer Ring .. SEEALSO:: :func:`lazy_import`, :class:`LazyImport` @@ -149,7 +149,7 @@ cpdef test_fake_startup(): sage: sage.misc.lazy_import.test_fake_startup() sage: lazy_import('sage.rings.all', 'ZZ', 'my_ZZ') sage: my_ZZ(123) - Resolving lazy import ZZ during startup + UserWarning: Resolving lazy import ZZ during startup 123 sage: sage.misc.lazy_import.finish_startup() """ @@ -233,7 +233,7 @@ cdef class LazyImport(object): False sage: my_integer_ring = LazyImport('sage.rings.all', 'ZZ', at_startup=True) sage: my_integer_ring - Option ``at_startup=True`` for lazy import ZZ not needed anymore + UserWarning: Option ``at_startup=True`` for lazy import ZZ not needed anymore Integer Ring """ if self._object is not None: From 56d1c36fbe3862ed104560137442774594ad8dab Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 16:49:41 -0700 Subject: [PATCH 285/511] git grep -l -E 'is_Expression' | xargs sed -E -i.bak 's/sage[.]symbolic.*import is_Expression *$/sage.structure.element import Expression/;s/is_Expression[(]([^)]*)[)]/isinstance(\1, Expression)/g;' --- src/sage/calculus/all.py | 4 ++-- src/sage/calculus/integration.pyx | 4 ++-- src/sage/ext/fast_callable.pyx | 8 +++---- src/sage/plot/contour_plot.py | 14 ++++++------ src/sage/plot/plot3d/plot3d.py | 4 ++-- src/sage/rings/padics/factory.py | 12 +++++----- .../schemes/berkovich/berkovich_cp_element.py | 22 +++++++++---------- src/sage/sets/condition_set.py | 4 ++-- src/sage/structure/parent.pyx | 4 ++-- src/sage/symbolic/callable.py | 4 ++-- src/sage/symbolic/comparison_impl.pxi | 14 ++++++------ src/sage/symbolic/expression.pxd | 2 +- src/sage/symbolic/expression.pyx | 14 ++++++------ src/sage/symbolic/function.pyx | 4 ++-- src/sage/symbolic/relation.py | 12 +++++----- src/sage/symbolic/ring.pyx | 2 +- 16 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/sage/calculus/all.py b/src/sage/calculus/all.py index 1f89c3f7ffe..4cd480570fd 100644 --- a/src/sage/calculus/all.py +++ b/src/sage/calculus/all.py @@ -58,8 +58,8 @@ def symbolic_expression(x): 2*x^2 + 3 sage: type(a) - sage: from sage.symbolic.expression import is_Expression - sage: is_Expression(a) + sage: from sage.structure.element import Expression + sage: isinstance(a, Expression) True sage: a in SR True diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index 56456173632..508ad2d6537 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -612,8 +612,8 @@ def monte_carlo_integral(func, xl, xu, size_t calls, algorithm='plain', "more items in upper and lower limits" ).format(len(vars), tuple(vars), target_dim)) - from sage.symbolic.expression import is_Expression - if is_Expression(func): + from sage.structure.element import Expression + if isinstance(func, Expression): if params: to_sub = dict(zip(vars[-len(params):], params)) func = func.subs(to_sub) diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index 11d4b652ceb..fb26e1f2d50 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -428,7 +428,7 @@ def fast_callable(x, domain=None, vars=None, vars = et._etb._vars else: from sage.symbolic.callable import is_CallableSymbolicExpression - from sage.symbolic.expression import is_Expression + from sage.structure.element import Expression if not vars: # fast_float passes empty list/tuple @@ -439,7 +439,7 @@ def fast_callable(x, domain=None, vars=None, vars = x.arguments() if expect_one_var and len(vars) != 1: raise ValueError(f"passed expect_one_var=True, but the callable expression takes {len(vars)} arguments") - elif is_Expression(x): + elif isinstance(x, Expression): from sage.symbolic.ring import is_SymbolicVariable if vars is None: vars = x.variables() @@ -999,8 +999,8 @@ cdef class Expression: return ExpressionIPow(es._etb, s, o) else: # I really don't like this, but I can't think of a better way - from sage.symbolic.expression import is_Expression - if is_Expression(o) and o in ZZ: + from sage.structure.element import Expression + if isinstance(o, Expression) and o in ZZ: es = s return ExpressionIPow(es._etb, s, ZZ(o)) else: diff --git a/src/sage/plot/contour_plot.py b/src/sage/plot/contour_plot.py index b1d9533c90f..27577d396d6 100644 --- a/src/sage/plot/contour_plot.py +++ b/src/sage/plot/contour_plot.py @@ -1217,8 +1217,8 @@ def f(x,y): options.pop('contours', None) incol = options.pop('fillcolor', 'blue') bordercol = options.pop('cmap', [None])[0] - from sage.symbolic.expression import is_Expression - if not is_Expression(f): + from sage.structure.element import Expression + if not isinstance(f, Expression): return region_plot(lambda x, y: f(x, y) < 0, xrange, yrange, borderwidth=linewidths, borderstyle=linestyles, incol=incol, bordercol=bordercol, @@ -1499,7 +1499,7 @@ def region_plot(f, xrange, yrange, plot_points, incol, outcol, bordercol, """ from sage.plot.all import Graphics from sage.plot.misc import setup_for_eval_on_grid - from sage.symbolic.expression import is_Expression + from sage.structure.element import Expression from warnings import warn import numpy @@ -1507,10 +1507,10 @@ def region_plot(f, xrange, yrange, plot_points, incol, outcol, bordercol, f = [f] feqs = [equify(g) for g in f - if is_Expression(g) and g.operator() is operator.eq + if isinstance(g, Expression) and g.operator() is operator.eq and not equify(g).is_zero()] f = [equify(g) for g in f - if not (is_Expression(g) and g.operator() is operator.eq)] + if not (isinstance(g, Expression) and g.operator() is operator.eq)] neqs = len(feqs) if neqs > 1: warn("There are at least 2 equations; " @@ -1620,8 +1620,8 @@ def equify(f): -1 """ from sage.calculus.all import symbolic_expression - from sage.symbolic.expression import is_Expression - if not is_Expression(f): + from sage.structure.element import Expression + if not isinstance(f, Expression): return lambda x, y: -1 if f(x, y) else 1 op = f.operator() diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index d5951640950..d95d332bf18 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -306,10 +306,10 @@ def to_cartesian(self, func, params=None): Graphics3d Object """ - from sage.symbolic.expression import is_Expression + from sage.structure.element import Expression from sage.rings.real_mpfr import is_RealNumber from sage.rings.integer import is_Integer - if params is not None and (is_Expression(func) or is_RealNumber(func) or is_Integer(func)): + if params is not None and (isinstance(func, Expression) or is_RealNumber(func) or is_Integer(func)): return self.transform(**{ self.dep_var: func, self.indep_vars[0]: params[0], diff --git a/src/sage/rings/padics/factory.py b/src/sage/rings/padics/factory.py index 90c54a2524a..abfce6c44c9 100644 --- a/src/sage/rings/padics/factory.py +++ b/src/sage/rings/padics/factory.py @@ -2534,8 +2534,8 @@ def Zq(q, prec = None, type = 'capped-rel', modulus = None, names=None, prec = Integer(prec) if isinstance(names, (list, tuple)): names = names[0] - from sage.symbolic.expression import is_Expression - if not (modulus is None or is_Polynomial(modulus) or is_Expression(modulus)): + from sage.structure.element import Expression + if not (modulus is None or is_Polynomial(modulus) or isinstance(modulus, Expression)): raise TypeError("modulus must be a polynomial") if names is not None and not isinstance(names, str): names = str(names) @@ -3271,9 +3271,9 @@ def create_key_and_extra_args(self, base, modulus, prec = None, print_mode = Non if print_max_terse_terms is None: print_max_terse_terms = base._printer._max_terse_terms() show_prec = _canonicalize_show_prec(base._prec_type(), print_mode, show_prec) - from sage.symbolic.expression import is_Expression + from sage.structure.element import Expression if check: - if is_Expression(modulus): + if isinstance(modulus, Expression): if len(modulus.variables()) != 1: raise ValueError("symbolic expression must be in only one variable") exact_modulus = modulus.polynomial(base.exact_field()) @@ -3378,8 +3378,8 @@ def create_object(self, version, key, approx_modulus=None, shift_seed=None): if version[0] < 8: (polytype, base, premodulus, approx_modulus, names, prec, halt, print_mode, print_pos, print_sep, print_alphabet, print_max_ram_terms, print_max_unram_terms, print_max_terse_terms, implementation) = key - from sage.symbolic.expression import is_Expression - if is_Expression(premodulus): + from sage.structure.element import Expression + if isinstance(premodulus, Expression): exact_modulus = premodulus.polynomial(base.exact_field()) elif is_Polynomial(premodulus): exact_modulus = premodulus.change_ring(base.exact_field()) diff --git a/src/sage/schemes/berkovich/berkovich_cp_element.py b/src/sage/schemes/berkovich/berkovich_cp_element.py index 9c730a31626..ef419c0b50a 100644 --- a/src/sage/schemes/berkovich/berkovich_cp_element.py +++ b/src/sage/schemes/berkovich/berkovich_cp_element.py @@ -34,7 +34,7 @@ # ***************************************************************************** from sage.structure.element import Element -from sage.symbolic.expression import is_Expression +from sage.structure.element import Expression from sage.rings.real_mpfr import RR, is_RealNumber from sage.rings.padics.padic_generic_element import pAdicGenericElement from sage.rings.padics.padic_base_generic import pAdicBaseGeneric @@ -118,16 +118,16 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= # check if the radius and the center are functions center_func_check = is_FunctionFieldElement(center) or is_Polynomial(center) or\ - isinstance(center, FractionFieldElement_1poly_field) or is_Expression(center) + isinstance(center, FractionFieldElement_1poly_field) or isinstance(center, Expression) radius_func_check = is_FunctionFieldElement(radius) or is_Polynomial(radius) or\ - isinstance(radius, FractionFieldElement_1poly_field) or is_Expression(radius) + isinstance(radius, FractionFieldElement_1poly_field) or isinstance(radius, Expression) if center_func_check: # check that both center and radii are supported univariate function center_expr_check = False radius_expr_check = False if error_check: - if is_Expression(center): + if isinstance(center, Expression): if len(center.variables()) != 1: raise ValueError("an expression with %s " % (len(center.variables())) + "variables cannot define the centers approximating a type IV point") @@ -136,16 +136,16 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= center_expr_check = True if not radius_func_check: raise TypeError("center was passed a function but radius was not a function") - if is_Expression(radius): + if isinstance(radius, Expression): if len(radius.variables()) != 1: raise ValueError("an expression with %s " % (len(radius.variables())) + "variables cannot define the radii approximating a type IV point") else: radius_expr_check = True else: - if is_Expression(center): + if isinstance(center, Expression): center_expr_check = True - if is_Expression(radius): + if isinstance(radius, Expression): radius_expr_check = True self._type = 4 self._prec = prec @@ -216,7 +216,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= center.normalize_coordinates() # make sure the radius coerces into the reals if not is_RealNumber(radius): - if is_Expression(radius): + if isinstance(radius, Expression): radius = RR(radius) elif RR.has_coerce_map_from(radius.parent()): radius = RR(radius) @@ -259,7 +259,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= raise ValueError('could not convert %s to %s' % (center, self._base_space)) # make sure the radius coerces into the reals if not is_RealNumber(radius): - if is_Expression(radius): + if isinstance(radius, Expression): radius = RR(radius) elif RR.has_coerce_map_from(radius.parent()): radius = RR(radius) @@ -375,7 +375,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= self._type = 2 return if radius is not None: - if is_Expression(radius): + if isinstance(radius, Expression): try: power = QQ(radius.log(self._p).expand_log()) except TypeError: @@ -659,7 +659,7 @@ def diameter(self, basepoint=Infinity): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R = PolynomialRing(QQ, names="x") x = R.gens()[0] - if is_Expression(self._radius_func): + if isinstance(self._radius_func, Expression): radius_func_variable = self._radius_func.variables()[0] radius_expr = self._radius_func.subs({radius_func_variable: x}) else: diff --git a/src/sage/sets/condition_set.py b/src/sage/sets/condition_set.py index 757014ace6c..2660a52077b 100644 --- a/src/sage/sets/condition_set.py +++ b/src/sage/sets/condition_set.py @@ -19,7 +19,7 @@ from sage.categories.enumerated_sets import EnumeratedSets from sage.misc.cachefunc import cached_method from sage.misc.misc import _stable_uniq -from sage.symbolic.expression import is_Expression +from sage.structure.element import Expression from sage.symbolic.callable import is_CallableSymbolicExpression from sage.symbolic.ring import SR @@ -165,7 +165,7 @@ def __classcall_private__(cls, universe, *predicates, vars=None, names=None, cat if vars is None: vars = predicate.args() callable_symbolic_predicates.append(predicate) - elif is_Expression(predicate): + elif isinstance(predicate, Expression): if names is None: raise TypeError('use callable symbolic expressions or provide variable names') if vars is None: diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 4559972c94f..53df4273f29 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1169,8 +1169,8 @@ cdef class Parent(sage.structure.category_object.CategoryObject): elif EQ: return True else: - from sage.symbolic.expression import is_Expression - return is_Expression(EQ) + from sage.structure.element import Expression + return isinstance(EQ, Expression) # if comparing gives an Expression, then it must be an equation. # We return *true* here, even though the equation # EQ must have evaluated to False for us to get to diff --git a/src/sage/symbolic/callable.py b/src/sage/symbolic/callable.py index 758fa7ff790..f1a45811db8 100644 --- a/src/sage/symbolic/callable.py +++ b/src/sage/symbolic/callable.py @@ -109,8 +109,8 @@ def is_CallableSymbolicExpression(x): sage: is_CallableSymbolicExpression(foo) False """ - from sage.symbolic.expression import is_Expression - return is_Expression(x) and isinstance(x.parent(), CallableSymbolicExpressionRing_class) + from sage.structure.element import Expression + return isinstance(x, Expression) and isinstance(x.parent(), CallableSymbolicExpressionRing_class) class CallableSymbolicExpressionFunctor(ConstructionFunctor): def __init__(self, arguments): diff --git a/src/sage/symbolic/comparison_impl.pxi b/src/sage/symbolic/comparison_impl.pxi index 9d73c7359fe..2b112b271cd 100644 --- a/src/sage/symbolic/comparison_impl.pxi +++ b/src/sage/symbolic/comparison_impl.pxi @@ -79,9 +79,9 @@ cpdef int print_order(lhs, rhs) except -2: sage: print_order(SR(oo), sqrt(2)) 1 """ - if not is_Expression(lhs): + if not isinstance(lhs, Expression): lhs = SR(lhs) - if not is_Expression(rhs): + if not isinstance(rhs, Expression): rhs = SR(rhs) return print_order_c(lhs, rhs) @@ -103,7 +103,7 @@ class _print_key(object): sage: _print_key(1) """ - self.ex = ex if is_Expression(ex) else SR(ex) + self.ex = ex if isinstance(ex, Expression) else SR(ex) def __lt__(self, other): """ @@ -171,7 +171,7 @@ class _math_key(object): sage: _math_key(1) """ - self.ex = ex if is_Expression(ex) else SR(ex) + self.ex = ex if isinstance(ex, Expression) else SR(ex) def __lt__(self, other): """ @@ -283,9 +283,9 @@ cpdef int mixed_order(lhs, rhs) except -2: """ if lhs is rhs: return 0 - if not is_Expression(lhs): + if not isinstance(lhs, Expression): lhs = SR(lhs) - if not is_Expression(rhs): + if not isinstance(rhs, Expression): rhs = SR(rhs) less_than = _mixed_key(lhs) < _mixed_key(rhs) if less_than: @@ -318,7 +318,7 @@ class _mixed_key(object): sage: _mixed_key(1) """ - self.ex = ex if is_Expression(ex) else SR(ex) + self.ex = ex if isinstance(ex, Expression) else SR(ex) def __lt__(self, other): """ diff --git a/src/sage/symbolic/expression.pxd b/src/sage/symbolic/expression.pxd index 1fa578d43c3..be27fb8b224 100644 --- a/src/sage/symbolic/expression.pxd +++ b/src/sage/symbolic/expression.pxd @@ -1,4 +1,4 @@ -cpdef bint is_Expression(x) +cpdef bint isinstance(x, Expression) cpdef _repr_Expression(x) cpdef _latex_Expression(x) cpdef new_Expression(parent, x) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 5f49c78a260..ed615c42429 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -406,18 +406,18 @@ include "pynac.pxi" include "pynac_impl.pxi" -cpdef bint is_Expression(x): +cpdef bint isinstance(x, Expression): """ Return True if *x* is a symbolic Expression. EXAMPLES:: - sage: from sage.symbolic.expression import is_Expression - sage: is_Expression(x) + sage: from sage.structure.element import Expression + sage: isinstance(x, Expression) True - sage: is_Expression(2) + sage: isinstance(2, Expression) False - sage: is_Expression(SR(2)) + sage: isinstance(SR(2, Expression)) True """ return isinstance(x, Expression) @@ -473,7 +473,7 @@ cpdef bint _is_SymbolicVariable(x): sage: ZZ['x'] Univariate Polynomial Ring in x over Integer Ring """ - return is_Expression(x) and is_a_symbol((x)._gobj) + return isinstance(x, Expression) and is_a_symbol((x)._gobj) def _dict_update_check_duplicate(dict d1, dict d2): @@ -13579,7 +13579,7 @@ cpdef new_Expression(parent, x): x + 1 """ cdef GEx exp - if is_Expression(x): + if isinstance(x, Expression): return new_Expression_from_GEx(parent, (x)._gobj) if hasattr(x, '_symbolic_'): return x._symbolic_(parent) diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 7feef512673..15fe84b3195 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -334,7 +334,7 @@ cdef class Function(SageObject): try: evalf = self._evalf_ # catch AttributeError early if any(self._is_numerical(x) for x in args): - if not any(is_Expression(x) for x in args): + if not any(isinstance(x, Expression) for x in args): p = coercion_model.common_parent(*args) return evalf(*args, parent=p) except Exception: @@ -553,7 +553,7 @@ cdef class Function(SageObject): else: # coerce == False for a in args: - if not is_Expression(a): + if not isinstance(a, Expression): raise TypeError("arguments must be symbolic expressions") return call_registered_function(self._serial, self._nargs, args, hold, diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index 28b1bce0301..698eed45d0e 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -1058,14 +1058,14 @@ def solve(f, *args, **kwds): if isinstance(f, (list, tuple)) and len(f) == 1: # f is a list with a single element - if is_Expression(f[0]): + if isinstance(f[0], Expression): f = f[0] else: raise TypeError("The first argument to solve() should be a " "symbolic expression or a list of symbolic " "expressions.") - if is_Expression(f): # f is a single expression + if isinstance(f, Expression): # f is a single expression return _solve_expression(f, x, explicit_solutions, multiplicities, to_poly_solve, solution_dict, algorithm, domain) if not isinstance(f, (list, tuple)): @@ -1095,7 +1095,7 @@ def solve(f, *args, **kwds): if algorithm == 'sympy': from sympy import solve as ssolve from sage.interfaces.sympy import sympy_set_to_list - if is_Expression(f): # f is a single expression + if isinstance(f, Expression): # f is a single expression sympy_f = f._sympy_() else: sympy_f = [s._sympy_() for s in f] @@ -1103,7 +1103,7 @@ def solve(f, *args, **kwds): sympy_vars = (x._sympy_(),) else: sympy_vars = tuple([v._sympy_() for v in x]) - if len(sympy_vars) > 1 or not is_Expression(f): + if len(sympy_vars) > 1 or not isinstance(f, Expression): ret = ssolve(sympy_f, sympy_vars, dict=True) if isinstance(ret, dict): if solution_dict: @@ -1569,14 +1569,14 @@ def solve_mod(eqns, modulus, solution_dict=False): """ from sage.rings.all import Integer, Integers, crt_basis - from sage.symbolic.expression import is_Expression + from sage.structure.element import Expression from sage.misc.all import cartesian_product_iterator from sage.modules.all import vector from sage.matrix.all import matrix if not isinstance(eqns, (list, tuple)): eqns = [eqns] - eqns = [eq if is_Expression(eq) else (eq.lhs() - eq.rhs()) for eq in eqns] + eqns = [eq if isinstance(eq, Expression) else (eq.lhs() - eq.rhs()) for eq in eqns] modulus = Integer(modulus) if modulus < 1: raise ValueError("the modulus must be a positive integer") diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index ffe8d7443f2..cca5dec8fee 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -870,7 +870,7 @@ cdef class SymbolicRing(CommutativeRing): ... ValueError: cannot specify n for multiple symbol names """ - if is_Expression(name): + if isinstance(name, Expression): return name if not isinstance(name, (basestring, list, tuple)): name = repr(name) From 08bf900dd929f3859110130c98155e4fbe1d95e4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 16:54:12 -0700 Subject: [PATCH 286/511] is_Expression: Undo automatic edit of the definition; deprecate --- src/sage/symbolic/expression.pyx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index ed615c42429..3f6cb7b0f3d 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -406,20 +406,24 @@ include "pynac.pxi" include "pynac_impl.pxi" -cpdef bint isinstance(x, Expression): +cpdef bint is_Expression(x): """ Return True if *x* is a symbolic Expression. EXAMPLES:: - sage: from sage.structure.element import Expression - sage: isinstance(x, Expression) + sage: from sage.symbolic.expression import is_Expression + sage: is_Expression(x) + DeprecationWarning: is_Expression is deprecated; + use isinstance(..., sage.structure.element.Expression) instead True - sage: isinstance(2, Expression) + sage: is_Expression(2) False - sage: isinstance(SR(2, Expression)) + sage: is_Expression(SR(2)) True """ + from sage.misc.superseded import deprecation + deprecation(32638, 'is_Expression is deprecated; use isinstance(..., sage.structure.element.Expression) instead') return isinstance(x, Expression) From 4e5fe35817b7bc335af222e540e367b7704e2661 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 18:56:37 -0700 Subject: [PATCH 287/511] src/sage/symbolic/expression.pxd: Undo automatic edit --- src/sage/symbolic/expression.pxd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/symbolic/expression.pxd b/src/sage/symbolic/expression.pxd index be27fb8b224..1fa578d43c3 100644 --- a/src/sage/symbolic/expression.pxd +++ b/src/sage/symbolic/expression.pxd @@ -1,4 +1,4 @@ -cpdef bint isinstance(x, Expression) +cpdef bint is_Expression(x) cpdef _repr_Expression(x) cpdef _latex_Expression(x) cpdef new_Expression(parent, x) From dadfa07f6bf9356db6c971b51ee320fbb04481f2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 19:02:18 -0700 Subject: [PATCH 288/511] src/sage/misc/lazy_import.pyx: Fix markup of doctest output --- src/sage/misc/lazy_import.pyx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index a454bd5d0e4..71839dc2ef8 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -31,6 +31,7 @@ it is actually resolved after the startup, so that the developer knows that (s)he can remove the flag:: sage: ZZ + doctest:warning... UserWarning: Option ``at_startup=True`` for lazy import ZZ not needed anymore Integer Ring @@ -149,6 +150,7 @@ cpdef test_fake_startup(): sage: sage.misc.lazy_import.test_fake_startup() sage: lazy_import('sage.rings.all', 'ZZ', 'my_ZZ') sage: my_ZZ(123) + doctest:warning... UserWarning: Resolving lazy import ZZ during startup 123 sage: sage.misc.lazy_import.finish_startup() @@ -233,6 +235,7 @@ cdef class LazyImport(object): False sage: my_integer_ring = LazyImport('sage.rings.all', 'ZZ', at_startup=True) sage: my_integer_ring + doctest:warning... UserWarning: Option ``at_startup=True`` for lazy import ZZ not needed anymore Integer Ring """ From e14259b90bb05950c575731090220f08f41f563f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 19:14:48 -0700 Subject: [PATCH 289/511] src/sage/ext/fast_callable.pyx: Fix up clash of sage.ext.fast_callable.Expression and sage.structure.element.Expression --- src/sage/ext/fast_callable.pyx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index fb26e1f2d50..50fb5e21f7a 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -308,6 +308,7 @@ from sage.rings.all import RDF, CDF from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.structure.element cimport parent +from sage.structure.element cimport Expression as Expression_abc def fast_callable(x, domain=None, vars=None, @@ -428,7 +429,6 @@ def fast_callable(x, domain=None, vars=None, vars = et._etb._vars else: from sage.symbolic.callable import is_CallableSymbolicExpression - from sage.structure.element import Expression if not vars: # fast_float passes empty list/tuple @@ -439,7 +439,7 @@ def fast_callable(x, domain=None, vars=None, vars = x.arguments() if expect_one_var and len(vars) != 1: raise ValueError(f"passed expect_one_var=True, but the callable expression takes {len(vars)} arguments") - elif isinstance(x, Expression): + elif isinstance(x, Expression_abc): from sage.symbolic.ring import is_SymbolicVariable if vars is None: vars = x.variables() @@ -999,8 +999,7 @@ cdef class Expression: return ExpressionIPow(es._etb, s, o) else: # I really don't like this, but I can't think of a better way - from sage.structure.element import Expression - if isinstance(o, Expression) and o in ZZ: + if isinstance(o, Expression_abc) and o in ZZ: es = s return ExpressionIPow(es._etb, s, ZZ(o)) else: From daed11ede2e3dd63897eb16cda2a23d56b0dc220 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 21:20:17 -0700 Subject: [PATCH 290/511] src/sage/symbolic/function.pyx: Update imports --- src/sage/symbolic/function.pyx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 15fe84b3195..7d7773163b8 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -139,12 +139,11 @@ is attempted, and after that ``sin()`` which succeeds:: #***************************************************************************** from sage.structure.sage_object cimport SageObject -from sage.structure.element cimport Element, parent +from sage.structure.element cimport Element, parent, Expression from sage.misc.lazy_attribute import lazy_attribute from .expression import ( call_registered_function, find_registered_function, register_or_update_function, - get_sfunction_from_hash, - is_Expression + get_sfunction_from_hash ) from .expression import get_sfunction_from_serial as get_sfunction_from_serial From c52251b59f888d3d9a2821ee5189daff95d056a9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 21:21:18 -0700 Subject: [PATCH 291/511] src/sage/symbolic/ring.pyx: Update imports --- src/sage/symbolic/ring.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index cca5dec8fee..512c996a8d3 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -34,7 +34,6 @@ The symbolic ring from sage.rings.integer cimport Integer from sage.symbolic.expression cimport ( - is_Expression, _latex_Expression, _repr_Expression, new_Expression, @@ -43,7 +42,7 @@ from sage.symbolic.expression cimport ( new_Expression_symbol, ) -from sage.structure.element cimport Element +from sage.structure.element cimport Element, Expression from sage.categories.morphism cimport Morphism from sage.structure.coerce cimport is_numpy_type From 98d2e9b0ebb6d56b18518ec2624592532fac034a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 22:43:27 -0700 Subject: [PATCH 292/511] src/sage/misc/lazy_import.pyx: In test_fake_startup, also reset finish_startup_called --- src/sage/misc/lazy_import.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 71839dc2ef8..fb06fa01f56 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -155,8 +155,9 @@ cpdef test_fake_startup(): 123 sage: sage.misc.lazy_import.finish_startup() """ - global startup_guard + global startup_guard, finish_startup_called startup_guard = True + finish_startup_called = False @cython.final From 5a9ca1efca281c47c4345b2007147cb6cd6f93fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 6 Oct 2021 09:50:20 +0200 Subject: [PATCH 293/511] enumeration of linear intervals in posets --- src/sage/combinat/posets/hasse_diagram.py | 31 ++++++++++++++ src/sage/combinat/posets/posets.py | 52 ++++++++++++++++++++++- 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index 17c632e9b02..e8c0d6b92b2 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -2353,6 +2353,37 @@ def chains(self, element_class=list, exclude=None, conversion=None): """ return IncreasingChains(self._leq_storage, element_class, exclude, conversion) + def is_linear_interval(self, t_min, t_max) -> bool: + """ + Return whether the interval ``[t_min, t_max]`` is linear. + + This means that this interval is a total order. + + .. WARNING:: + + For speed, this assumes that the input is an interval! + + EXAMPLES:: + + sage: P = posets.PentagonPoset() + sage: H = P._hasse_diagram + sage: H.is_linear_interval(0,4) + False + sage: H.is_linear_interval(0,3) + True + """ + t = t_max + while t != t_min: + found = False + for u in self.neighbor_in_iterator(t): + if self.is_lequal(t_min, u): + if not found: + found = True + t = u + else: + return False + return True + def diamonds(self): r""" Return the list of diamonds of ``self``. diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 3c5b56dedf2..f987759cae4 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -66,6 +66,7 @@ :meth:`~FinitePoset.height` | Return the number of elements in a longest chain of the poset. :meth:`~FinitePoset.width` | Return the number of elements in a longest antichain of the poset. :meth:`~FinitePoset.relations_number` | Return the number of relations in the poset. + :meth:`~FinitePoset.linear_intervals_count` | Return the enumeration of linear intervals in the poset. :meth:`~FinitePoset.dimension` | Return the dimension of the poset. :meth:`~FinitePoset.jump_number` | Return the jump number of the poset. :meth:`~FinitePoset.magnitude` | Return the magnitude of the poset. @@ -281,8 +282,9 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** - +from __future__ import annotations from copy import copy, deepcopy + from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod @@ -2649,6 +2651,54 @@ def relations_number(self): # Maybe this should also be deprecated. intervals_number = relations_number + def linear_intervals_count(self) -> list[int]: + """ + Return the enumeration of linear intervals w.r.t. their cardinality. + + An interval is linear if it is a total order. + + OUTPUT: list of integers + + EXAMPLES:: + + sage: P = posets.PentagonPoset() + sage: P.linear_intervals_count() + [5, 5, 2] + sage: P = posets.TamariLattice(4) + sage: P.linear_intervals_count() + [14, 21, 12, 2] + + TESTS:: + + sage: P = Poset() + sage: P.linear_intervals_count() + [] + """ + if not self.cardinality(): + return [] + H = self._hasse_diagram + stock = [(x, x, x) for x in H] + poly = [len(stock)] + exposant = 0 + while True: + exposant += 1 + next_stock = [] + short_stock = [(ch[0], ch[2]) for ch in stock] + for xmin, cov_xmin, xmax in stock: + for y in H.neighbor_out_iterator(xmax): + if exposant == 1: + next_stock.append((xmin, y, y)) + else: + if (cov_xmin, y) in short_stock: + if H.is_linear_interval(xmin, y): + next_stock.append((xmin, cov_xmin, y)) + if next_stock: + poly.append(len(next_stock)) + stock = next_stock + else: + break + return poly + def is_incomparable_chain_free(self, m, n=None) -> bool: r""" Return ``True`` if the poset is `(m+n)`-free, and ``False`` otherwise. From c5d3cccacfdd8b3ccf7337453abdb38853fe827b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 5 Oct 2021 20:29:09 +0200 Subject: [PATCH 294/511] partial pep cleanup of one cluster file --- .../quiver_mutation_type.py | 791 +++++++++--------- 1 file changed, 398 insertions(+), 393 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py index b819aed8966..4a8d8816fa1 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py @@ -15,7 +15,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # *************************************************************************** - +from __future__ import annotations import os import pickle @@ -62,12 +62,12 @@ def __call__(self, *args): _mutation_type_error(data) # check for reducible types - if all( type( data_component ) in [list,tuple,QuiverMutationType_Irreducible] for data_component in data ): + if all(type(data_component) in [list, tuple, QuiverMutationType_Irreducible] for data_component in data): if len(data) == 1: return QuiverMutationType(data[0]) else: - data = tuple( QuiverMutationType(comp) for comp in data ) - return QuiverMutationType_Reducible( *data ) + data = tuple(QuiverMutationType(comp) for comp in data) + return QuiverMutationType_Reducible(*data) # check for irreducible types if len(data) == 2: @@ -83,114 +83,114 @@ def __call__(self, *args): data = (data[0], tuple(data[1]), data[2]) # mutation type casting - if data == ('D',2,None): - return QuiverMutationType( ('A',1,None), ('A',1,None) ) - elif data == ('D',3,None): - data = ('A',3,None) - elif data == ('C',2,None): - data = ('B',2,None) - elif data == ('E',9,None): - data = ('E',8,1) + if data == ('D', 2, None): + return QuiverMutationType(('A', 1, None), ('A', 1, None)) + elif data == ('D', 3, None): + data = ('A', 3, None) + elif data == ('C', 2, None): + data = ('B', 2, None) + elif data == ('E', 9, None): + data = ('E', 8, 1) elif data[0] == 'A' and data[2] == 1 and isinstance(data[1], tuple) and len(data[1]) == 2 and min(data[1]) == 0: if max(data[1]) == 0: pass elif max(data[1]) == 1: - data = ('A', 1,None) + data = ('A', 1, None) elif max(data[1]) == 2: - return QuiverMutationType( ('A',1,None), ('A',1,None) ) + return QuiverMutationType(('A', 1, None), ('A', 1, None)) elif max(data[1]) == 3: - data = ('A',3,None) + data = ('A', 3, None) else: - data = ('D',max(data[1]),None) + data = ('D', max(data[1]), None) elif data[0] == 'GR' and data[2] is None and isinstance(data[1], tuple) and len(data[1]) == 2 and data[1][1] > data[1][0]: - if min(data[1]) > max(data[1])/2 and max(data[1]) != min(data[1])+1: - data = (data[0],(max(data[1])-min(data[1]),max(data[1])),data[2]) + if min(data[1]) > max(data[1]) / 2 and max(data[1]) != min(data[1]) + 1: + data = (data[0], (max(data[1]) - min(data[1]), max(data[1])), data[2]) if min(data[1]) == 2 and max(data[1]) > 3: - data = ('A',max(data[1])-3,None) - elif data[1] == (3,6): - data = ('D',4,None) - elif data[1] == (3,7): - data = ('E',6,None) - elif data[1] == (3,8): - data = ('E',8,None) - elif data[1] == (3,9): - data = ('E',8,[1,1]) - elif data[1] == (4,8): - data = ('E',7,[1,1]) - elif data == ('TR',1,None): - data = ('A',1,None) - elif data == ('TR',2,None): - data = ('A',3,None) - elif data == ('TR',3,None): - data = ('D',6,None) - elif data == ('TR',4,None): - data = ('E',8,(1,1)) + data = ('A', max(data[1]) - 3, None) + elif data[1] == (3, 6): + data = ('D', 4, None) + elif data[1] == (3, 7): + data = ('E', 6, None) + elif data[1] == (3, 8): + data = ('E', 8, None) + elif data[1] == (3, 9): + data = ('E', 8, [1, 1]) + elif data[1] == (4, 8): + data = ('E', 7, [1, 1]) + elif data == ('TR', 1, None): + data = ('A', 1, None) + elif data == ('TR', 2, None): + data = ('A', 3, None) + elif data == ('TR', 3, None): + data = ('D', 6, None) + elif data == ('TR', 4, None): + data = ('E', 8, (1, 1)) # mutation type casting from Kac conventions - elif data == ('A',1,1): - data = ('A',(1,1),1) + elif data == ('A', 1, 1): + data = ('A', (1, 1), 1) elif data[0] == 'B' and data[2] == 1: if data[1] == 2: - data = ('CC',2,1) + data = ('CC', 2, 1) elif data[1] > 2: - data = ('BD',data[1],1) + data = ('BD', data[1], 1) elif data[0] == 'B' and data[2] == -1: if data[1] == 2: - data = ('BB',2,1) + data = ('BB', 2, 1) elif data[1] > 2: data = ('CD', data[1], 1) elif data[0] == 'C' and data[1] > 1 and data[2] == 1: - data = ('CC', data[1],1) + data = ('CC', data[1], 1) elif data[0] == 'C' and data[1] > 1 and data[2] == -1: data = ('BB', data[1], 1) - elif data == ('A',2,2): + elif data == ('A', 2, 2): data = ('BC', 1, 1) elif data[0] == 'A' and data[1] in ZZ and data[1] > 1 and data[1] % 2 == 0 and data[2] == 2: data = ('BC', data[1] // 2, 1) elif data[0] == 'A' and data[1] in ZZ and data[1] > 3 and data[1] % 2 and data[2] == 2: data = ('CD', (data[1] + 1) // 2, 1) - # We think of ('A',3,2) as ('D',3,2) - elif data == ('A',3,2): - data = ('BB',2,1) + # We think of ('A',3, 2) as ('D',3, 2) + elif data == ('A', 3, 2): + data = ('BB', 2, 1) elif data[0] == 'D' and data[1] in ZZ and data[1] > 2 and data[2] == 2: - data = ('BB',data[1]-1,1) - elif data == ('E',6,2): - data = ('F',4,-1) - elif data == ('D',4,3): - data = ('G',2,-1) - elif data == ('F',4,(2,1)): - data = ('F',4,(1,2)) - elif data == ('G',2,(3,1)): - data = ('G',2,(1,3)) + data = ('BB', data[1] - 1, 1) + elif data == ('E', 6, 2): + data = ('F', 4, -1) + elif data == ('D', 4, 3): + data = ('G', 2, -1) + elif data == ('F', 4, (2, 1)): + data = ('F', 4, (1, 2)) + elif data == ('G', 2, (3, 1)): + data = ('G', 2, (1, 3)) elif data[0] == 'T' and data[2] is None: - data = (data[0],tuple(sorted(data[1])),data[2]) - r,p,q = data[1] + data = (data[0], tuple(sorted(data[1])), data[2]) + r, p, q = data[1] if r == 1: - data = ('A',p+q-1,None) + data = ('A', p + q - 1, None) elif r == p == 2: - data = ('D',q+2,None) + data = ('D', q + 2, None) elif r == 2 and p == 3: - if q in (3,4,5): - data = ('E',q+3,None) + if q in (3, 4, 5): + data = ('E', q + 3, None) elif q == 6: - data = ('E',8,1) + data = ('E', 8, 1) else: - data = ('E',q+3,None) + data = ('E', q + 3, None) elif r == 2 and p == q == 4: - data = ('E',7,1) + data = ('E', 7, 1) elif r == p == q == 3: - data = ('E',6,1) - elif data[0] == 'R2' and data[2] is None and all(data[1][i] in ZZ and data[1][i] > 0 for i in [0,1]): + data = ('E', 6, 1) + elif data[0] == 'R2' and data[2] is None and all(data[1][i] in ZZ and data[1][i] > 0 for i in [0, 1]): data = (data[0], tuple(sorted(data[1])), data[2]) - if data[1] == (1,1): - data = ('A',2,None) - elif data[1] == (1,2): - data = ('B',2,None) - elif data[1] == (1,3): - data = ('G',2,None) - elif data[1] == (1,4): - data = ('BC',1,1) - elif data[1] == (2,2): - data = ('A',(1,1),1) + if data[1] == (1, 1): + data = ('A', 2, None) + elif data[1] == (1, 2): + data = ('B', 2, None) + elif data[1] == (1, 3): + data = ('G', 2, None) + elif data[1] == (1, 4): + data = ('BC', 1, 1) + elif data[1] == (2, 2): + data = ('A', (1, 1), 1) # setting the parameters and returning the mutation type letter, rank, twist = data @@ -200,9 +200,9 @@ def __call__(self, *args): rank = tuple(rank) if isinstance(twist, list): twist = tuple(twist) - return QuiverMutationType_Irreducible(letter,rank,twist) + return QuiverMutationType_Irreducible(letter, rank, twist) - def _repr_(self): + def _repr_(self) -> str: """ Return the string representation of ``self``. @@ -284,13 +284,13 @@ def _samples(self): ["E", 6], ["E", 7], ["E", 8], ["F", 4], ["G", 2]]] affine_types = \ - [QuiverMutationType(t) for t in [['A', [1,1], 1], ['A', [4,5], 1], ['D', 4, 1], ['BB', 5, 1]]] + [QuiverMutationType(t) for t in [['A', [1, 1], 1], ['A', [4, 5], 1], ['D', 4, 1], ['BB', 5, 1]]] elliptic_types = \ - [QuiverMutationType(t) for t in [['E', 6, [1,1]], ['E', 7, [1,1]]]] + [QuiverMutationType(t) for t in [['E', 6, [1, 1]], ['E', 7, [1, 1]]]] mutation_finite_types = \ - [QuiverMutationType(t) for t in [['R2',(1,5)], ['R2',(3,5)]]] + [QuiverMutationType(t) for t in [['R2', (1, 5)], ['R2', (3, 5)]]] mutation_infinite_types = \ - [QuiverMutationType(t) for t in [['E',10], ['BE',5], ['GR',(3,10)], ['T',(3,3,4)]]] + [QuiverMutationType(t) for t in [['E', 10], ['BE', 5], ['GR', (3, 10)], ['T', (3, 3, 4)]]] return finite_types + affine_types + elliptic_types + mutation_finite_types + mutation_infinite_types @@ -299,7 +299,7 @@ def _samples(self): QuiverMutationType.__doc__ = \ -r""" + r""" *Quiver mutation types* can be seen as a slight generalization of *generalized Cartan types*. @@ -358,7 +358,7 @@ def _samples(self): ``BC`` and ``rank=1``. * Macdonald notation: for the dual of an untwisted affine type - (such as ['C', 6,1]), we accept a twist of -1 (i.e., + (such as ['C', 6, 1]), we accept a twist of -1 (i.e., ['C',6,-1]). - Elliptic type -- ``letter`` is a Dynkin type, ``rank`` is the rank @@ -417,22 +417,22 @@ def _samples(self): Finite types:: - sage: QuiverMutationType('A',1) + sage: QuiverMutationType('A', 1) ['A', 1] sage: QuiverMutationType('A',5) ['A', 5] - sage: QuiverMutationType('B',2) + sage: QuiverMutationType('B', 2) ['B', 2] sage: QuiverMutationType('B',5) ['B', 5] - sage: QuiverMutationType('C',2) + sage: QuiverMutationType('C', 2) ['B', 2] sage: QuiverMutationType('C',5) ['C', 5] - sage: QuiverMutationType('D',2) + sage: QuiverMutationType('D', 2) [ ['A', 1], ['A', 1] ] sage: QuiverMutationType('D',3) ['A', 3] @@ -442,111 +442,111 @@ def _samples(self): sage: QuiverMutationType('E',6) ['E', 6] - sage: QuiverMutationType('G',2) + sage: QuiverMutationType('G', 2) ['G', 2] - sage: QuiverMutationType('A',(1,0),1) + sage: QuiverMutationType('A',(1,0), 1) ['A', 1] - sage: QuiverMutationType('A',(2,0),1) + sage: QuiverMutationType('A',(2,0), 1) [ ['A', 1], ['A', 1] ] - sage: QuiverMutationType('A',(7,0),1) + sage: QuiverMutationType('A',(7,0), 1) ['D', 7] Affine types:: - sage: QuiverMutationType('A',(1,1),1) + sage: QuiverMutationType('A',(1, 1), 1) ['A', [1, 1], 1] - sage: QuiverMutationType('A',(2,4),1) + sage: QuiverMutationType('A',(2,4), 1) ['A', [2, 4], 1] - sage: QuiverMutationType('BB',2,1) + sage: QuiverMutationType('BB', 2, 1) ['BB', 2, 1] - sage: QuiverMutationType('BB',4,1) + sage: QuiverMutationType('BB',4, 1) ['BB', 4, 1] - sage: QuiverMutationType('CC',2,1) + sage: QuiverMutationType('CC', 2, 1) ['CC', 2, 1] - sage: QuiverMutationType('CC',4,1) + sage: QuiverMutationType('CC',4, 1) ['CC', 4, 1] - sage: QuiverMutationType('BC',1,1) + sage: QuiverMutationType('BC', 1, 1) ['BC', 1, 1] - sage: QuiverMutationType('BC',5,1) + sage: QuiverMutationType('BC',5, 1) ['BC', 5, 1] - sage: QuiverMutationType('BD',3,1) + sage: QuiverMutationType('BD',3, 1) ['BD', 3, 1] - sage: QuiverMutationType('BD',5,1) + sage: QuiverMutationType('BD',5, 1) ['BD', 5, 1] - sage: QuiverMutationType('CD',3,1) + sage: QuiverMutationType('CD',3, 1) ['CD', 3, 1] - sage: QuiverMutationType('CD',5,1) + sage: QuiverMutationType('CD',5, 1) ['CD', 5, 1] - sage: QuiverMutationType('D',4,1) + sage: QuiverMutationType('D',4, 1) ['D', 4, 1] - sage: QuiverMutationType('D',6,1) + sage: QuiverMutationType('D',6, 1) ['D', 6, 1] - sage: QuiverMutationType('E',6,1) + sage: QuiverMutationType('E',6, 1) ['E', 6, 1] - sage: QuiverMutationType('E',7,1) + sage: QuiverMutationType('E',7, 1) ['E', 7, 1] - sage: QuiverMutationType('E',8,1) + sage: QuiverMutationType('E',8, 1) ['E', 8, 1] - sage: QuiverMutationType('F',4,1) + sage: QuiverMutationType('F',4, 1) ['F', 4, 1] sage: QuiverMutationType('F',4,-1) ['F', 4, -1] - sage: QuiverMutationType('G',2,1) + sage: QuiverMutationType('G', 2, 1) ['G', 2, 1] - sage: QuiverMutationType('G',2,-1) + sage: QuiverMutationType('G', 2,-1) ['G', 2, -1] - sage: QuiverMutationType('A',3,2) == QuiverMutationType('D',3,2) + sage: QuiverMutationType('A',3, 2) == QuiverMutationType('D',3, 2) True Affine types using Kac's Notation:: - sage: QuiverMutationType('A',1,1) + sage: QuiverMutationType('A', 1, 1) ['A', [1, 1], 1] - sage: QuiverMutationType('B',5,1) + sage: QuiverMutationType('B',5, 1) ['BD', 5, 1] - sage: QuiverMutationType('C',5,1) + sage: QuiverMutationType('C',5, 1) ['CC', 5, 1] - sage: QuiverMutationType('A',2,2) + sage: QuiverMutationType('A', 2, 2) ['BC', 1, 1] - sage: QuiverMutationType('A',7,2) + sage: QuiverMutationType('A',7, 2) ['CD', 4, 1] - sage: QuiverMutationType('A',8,2) + sage: QuiverMutationType('A',8, 2) ['BC', 4, 1] - sage: QuiverMutationType('D',6,2) + sage: QuiverMutationType('D',6, 2) ['BB', 5, 1] - sage: QuiverMutationType('E',6,2) + sage: QuiverMutationType('E',6, 2) ['F', 4, -1] sage: QuiverMutationType('D',4,3) ['G', 2, -1] Elliptic types:: - sage: QuiverMutationType('E',6,[1,1]) + sage: QuiverMutationType('E',6,[1, 1]) ['E', 6, [1, 1]] - sage: QuiverMutationType('F',4,[2,1]) + sage: QuiverMutationType('F',4,[2, 1]) ['F', 4, [1, 2]] - sage: QuiverMutationType('G',2,[3,3]) + sage: QuiverMutationType('G', 2,[3,3]) ['G', 2, [3, 3]] Mutation finite types: Rank 2 cases:: - sage: QuiverMutationType('R2',(1,1)) + sage: QuiverMutationType('R2',(1, 1)) ['A', 2] - sage: QuiverMutationType('R2',(1,2)) + sage: QuiverMutationType('R2',(1, 2)) ['B', 2] sage: QuiverMutationType('R2',(1,3)) ['G', 2] @@ -554,7 +554,7 @@ def _samples(self): ['BC', 1, 1] sage: QuiverMutationType('R2',(1,5)) ['R2', [1, 5]] - sage: QuiverMutationType('R2',(2,2)) + sage: QuiverMutationType('R2',(2, 2)) ['A', [1, 1], 1] sage: QuiverMutationType('R2',(3,5)) ['R2', [3, 5]] @@ -571,9 +571,9 @@ def _samples(self): sage: QuiverMutationType('E',9) ['E', 8, 1] - sage: QuiverMutationType('E',10) + sage: QuiverMutationType('E', 10) ['E', 10] - sage: QuiverMutationType('E',12) + sage: QuiverMutationType('E', 12) ['E', 12] sage: QuiverMutationType('AE',(2,3)) @@ -597,12 +597,12 @@ def _samples(self): ['E', 6] sage: QuiverMutationType('GR',(3,8)) ['E', 8] - sage: QuiverMutationType('GR',(3,10)) + sage: QuiverMutationType('GR',(3, 10)) ['GR', [3, 10]] Triangular types:: - sage: QuiverMutationType('TR',2) + sage: QuiverMutationType('TR', 2) ['A', 3] sage: QuiverMutationType('TR',3) ['D', 6] @@ -613,15 +613,15 @@ def _samples(self): T types:: - sage: QuiverMutationType('T',(1,1,1)) + sage: QuiverMutationType('T',(1, 1, 1)) ['A', 1] - sage: QuiverMutationType('T',(1,1,4)) + sage: QuiverMutationType('T',(1, 1,4)) ['A', 4] sage: QuiverMutationType('T',(1,4,4)) ['A', 7] - sage: QuiverMutationType('T',(2,2,2)) + sage: QuiverMutationType('T',(2, 2, 2)) ['D', 4] - sage: QuiverMutationType('T',(2,2,4)) + sage: QuiverMutationType('T',(2, 2,4)) ['D', 6] sage: QuiverMutationType('T',(2,3,3)) ['E', 6] @@ -664,7 +664,7 @@ def _repr_(self): EXAMPLES:: - sage: QuiverMutationType(['A',2]) # indirect doctest + sage: QuiverMutationType(['A', 2]) # indirect doctest ['A', 2] """ return self._description @@ -706,7 +706,7 @@ def show(self, circular=False, directed=True): sage: QMT = QuiverMutationType(['A',5]) sage: QMT.show() # long time """ - self.plot( circular=circular, directed=directed ).show() + self.plot(circular=circular, directed=directed).show() def letter(self): """ @@ -719,7 +719,7 @@ def letter(self): sage: mut_type.letter() 'A' - sage: mut_type = QuiverMutationType( ['BC',5,1] ); mut_type + sage: mut_type = QuiverMutationType( ['BC',5, 1] ); mut_type ['BC', 5, 1] sage: mut_type.letter() 'BC' @@ -749,12 +749,12 @@ def rank(self): sage: mut_type.rank() 5 - sage: mut_type = QuiverMutationType( ['A',[4,5],1] ); mut_type + sage: mut_type = QuiverMutationType( ['A',[4,5], 1] ); mut_type ['A', [4, 5], 1] sage: mut_type.rank() 9 - sage: mut_type = QuiverMutationType( ['BC',5,1] ); mut_type + sage: mut_type = QuiverMutationType( ['BC',5, 1] ); mut_type ['BC', 5, 1] sage: mut_type.rank() 6 @@ -814,7 +814,7 @@ def standard_quiver(self): sage: mut_type.standard_quiver() Quiver on 5 vertices of type ['A', 5] - sage: mut_type = QuiverMutationType( ['A',[5,3],1] ); mut_type + sage: mut_type = QuiverMutationType( ['A',[5,3], 1] ); mut_type ['A', [3, 5], 1] sage: mut_type.standard_quiver() Quiver on 8 vertices of type ['A', [3, 5], 1] @@ -884,7 +884,7 @@ def is_irreducible(self): EXAMPLES:: - sage: mt = QuiverMutationType(['A',2]) + sage: mt = QuiverMutationType(['A', 2]) sage: mt.is_irreducible() True """ @@ -899,7 +899,7 @@ def is_mutation_finite(self): EXAMPLES:: - sage: mt = QuiverMutationType(['D',5,1]) + sage: mt = QuiverMutationType(['D',5, 1]) sage: mt.is_mutation_finite() True """ @@ -914,15 +914,15 @@ def is_simply_laced(self): EXAMPLES:: - sage: mt = QuiverMutationType(['A',2]) + sage: mt = QuiverMutationType(['A', 2]) sage: mt.is_simply_laced() True - sage: mt = QuiverMutationType(['B',2]) + sage: mt = QuiverMutationType(['B', 2]) sage: mt.is_simply_laced() False - sage: mt = QuiverMutationType(['A',(1,1),1]) + sage: mt = QuiverMutationType(['A',(1, 1), 1]) sage: mt.is_simply_laced() False """ @@ -934,15 +934,15 @@ def is_skew_symmetric(self): EXAMPLES:: - sage: mt = QuiverMutationType(['A',2]) + sage: mt = QuiverMutationType(['A', 2]) sage: mt.is_skew_symmetric() True - sage: mt = QuiverMutationType(['B',2]) + sage: mt = QuiverMutationType(['B', 2]) sage: mt.is_skew_symmetric() False - sage: mt = QuiverMutationType(['A',(1,1),1]) + sage: mt = QuiverMutationType(['A',(1, 1), 1]) sage: mt.is_skew_symmetric() True """ @@ -957,11 +957,11 @@ def is_finite(self): EXAMPLES:: - sage: mt = QuiverMutationType(['A',2]) + sage: mt = QuiverMutationType(['A', 2]) sage: mt.is_finite() True - sage: mt = QuiverMutationType(['A',[4,2],1]) + sage: mt = QuiverMutationType(['A',[4, 2], 1]) sage: mt.is_finite() False """ @@ -973,11 +973,11 @@ def is_affine(self): EXAMPLES:: - sage: mt = QuiverMutationType(['A',2]) + sage: mt = QuiverMutationType(['A', 2]) sage: mt.is_affine() False - sage: mt = QuiverMutationType(['A',[4,2],1]) + sage: mt = QuiverMutationType(['A',[4, 2], 1]) sage: mt.is_affine() True """ @@ -992,11 +992,11 @@ def is_elliptic(self): EXAMPLES:: - sage: mt = QuiverMutationType(['A',2]) + sage: mt = QuiverMutationType(['A', 2]) sage: mt.is_elliptic() False - sage: mt = QuiverMutationType(['E',6,[1,1]]) + sage: mt = QuiverMutationType(['E',6,[1, 1]]) sage: mt.is_elliptic() True """ @@ -1039,7 +1039,7 @@ def properties(self): - affine: False - elliptic: False - sage: mut_type = QuiverMutationType(['B',3,1]); mut_type + sage: mut_type = QuiverMutationType(['B',3, 1]); mut_type ['BD', 3, 1] sage: mut_type.properties() ['BD', 3, 1] has rank 4 and the following properties: @@ -1051,7 +1051,7 @@ def properties(self): - affine: True - elliptic: False - sage: mut_type = QuiverMutationType(['E',6,[1,1]]); mut_type + sage: mut_type = QuiverMutationType(['E',6,[1, 1]]); mut_type ['E', 6, [1, 1]] sage: mut_type.properties() ['E', 6, [1, 1]] has rank 8 and the following properties: @@ -1103,6 +1103,7 @@ class QuiverMutationType_Irreducible(QuiverMutationType_abstract): The mutation type for a cluster algebra or a quiver. Should not be called directly, but through QuiverMutationType. """ + def __init__(self, letter, rank, twist=None): """ Should not be called directly but through QuiverMutationType. @@ -1118,10 +1119,10 @@ def __init__(self, letter, rank, twist=None): sage: QuiverMutationType('A',5) ['A', 5] - sage: QuiverMutationType('A',[4,5],1) + sage: QuiverMutationType('A',[4,5], 1) ['A', [4, 5], 1] - sage: QuiverMutationType('BB',5,1) + sage: QuiverMutationType('BB',5, 1) ['BB', 5, 1] sage: QuiverMutationType('X',6) @@ -1155,7 +1156,7 @@ def __init__(self, letter, rank, twist=None): self._letter = letter self._twist = twist - data = [letter,rank,twist] + data = [letter, rank, twist] # type A (finite and affine) if letter == 'A': @@ -1167,11 +1168,11 @@ def __init__(self, letter, rank, twist=None): self._info['finite'] = True elif twist == 1 and isinstance(rank, list) and len(rank) == 2 and all(ri in ZZ and ri >= 0 for ri in rank) and rank != [0, 0]: if isinstance(rank, tuple): - rank = list( rank ) + rank = list(rank) data[1] = rank rank = sorted(rank) self._bi_rank = rank - self._rank = sum( self._bi_rank ) + self._rank = sum(self._bi_rank) self._info['mutation_finite'] = True if self._rank > 2: self._info['simply_laced'] = True @@ -1182,24 +1183,24 @@ def __init__(self, letter, rank, twist=None): self._info['finite'] = True else: _mutation_type_error(data) - # types ['A',1] and ['A',[0,1],1] need to be treated on + # types ['A', 1] and ['A',[0, 1], 1] need to be treated on # itself (as there is no edge) if twist is None and self._rank == 1 or twist == 1 and self._rank == 1: - self._graph.add_vertex( 0 ) - # type ['A',[1,1],1] needs to be treated on itself as well + self._graph.add_vertex(0) + # type ['A',[1, 1], 1] needs to be treated on itself as well # (as there is a double edge) elif twist == 1 and self._bi_rank[0] == 1 and self._bi_rank[1] == 1: - self._graph.add_edge( 0,1,2 ) + self._graph.add_edge(0, 1, 2) else: - for i in range( self._rank - 1 ): - self._graph.add_edge( i, i+1, 1 ) + for i in range(self._rank - 1): + self._graph.add_edge(i, i + 1, 1) if twist == 1: - self._digraph.add_edge( self._rank - 1, 0, 1 ) - for i in range( self._rank - 1 ): + self._digraph.add_edge(self._rank - 1, 0, 1) + for i in range(self._rank - 1): if i < (2 * self._bi_rank[0]) and i % 2 == 0: - self._digraph.add_edge( i+1, i, 1 ) + self._digraph.add_edge(i + 1, i, 1) else: - self._digraph.add_edge( i, i+1, 1 ) + self._digraph.add_edge(i, i + 1, 1) # type B (finite) elif letter == 'B': @@ -1209,12 +1210,12 @@ def __init__(self, letter, rank, twist=None): self._info['finite'] = True else: _mutation_type_error(data) - for i in range( rank - 2 ): - self._graph.add_edge( i, i+1, 1 ) + for i in range(rank - 2): + self._graph.add_edge(i, i+1, 1) if (rank % 2 == 0): - self._graph.add_edge( rank-2, rank-1, (1,-2) ) + self._graph.add_edge(rank-2, rank-1, (1, -2)) else: - self._graph.add_edge( rank-2, rank-1, (2,-1) ) + self._graph.add_edge(rank-2, rank-1, (2, -1)) # type C (finite) elif letter == 'C': @@ -1224,12 +1225,12 @@ def __init__(self, letter, rank, twist=None): self._info['finite'] = True else: _mutation_type_error(data) - for i in range( rank - 2 ): - self._graph.add_edge( i, i+1, 1 ) + for i in range(rank - 2): + self._graph.add_edge(i, i+1, 1) if (rank % 2 == 0): - self._graph.add_edge( rank-2, rank-1, (2,-1) ) + self._graph.add_edge(rank-2, rank-1, (2, -1)) else: - self._graph.add_edge( rank-2, rank-1, (1,-2) ) + self._graph.add_edge(rank-2, rank-1, (1, -2)) # type BB (affine) elif letter == 'BB': @@ -1239,12 +1240,12 @@ def __init__(self, letter, rank, twist=None): self._info['affine'] = True else: _mutation_type_error(data) - for i in range( rank - 2 ): - self._graph.add_edge( i, i+1, 1 ) + for i in range(rank - 2): + self._graph.add_edge(i, i+1, 1) if rank % 2 == 0: - self._graph.add_edge( rank-2, rank-1, (1, -2) ) + self._graph.add_edge(rank-2, rank-1, (1, -2)) else: - self._graph.add_edge( rank-2, rank-1, (2, -1) ) + self._graph.add_edge(rank-2, rank-1, (2, -1)) self._graph.add_edge(rank, 0, (1, -2)) # type CC (affine) @@ -1255,12 +1256,12 @@ def __init__(self, letter, rank, twist=None): self._info['affine'] = True else: _mutation_type_error(data) - for i in range( rank - 2 ): - self._graph.add_edge( i, i+1, 1 ) + for i in range(rank - 2): + self._graph.add_edge(i, i+1, 1) if rank % 2 == 0: - self._graph.add_edge( rank-2, rank-1, (2,-1) ) + self._graph.add_edge(rank-2, rank-1, (2, -1)) else: - self._graph.add_edge( rank-2, rank-1, (1,-2) ) + self._graph.add_edge(rank-2, rank-1, (1, -2)) self._graph.add_edge(rank, 0, (2, -1)) # type BC (affine) @@ -1272,14 +1273,14 @@ def __init__(self, letter, rank, twist=None): else: _mutation_type_error(data) if rank == 1: - self._graph.add_edge( 0,1,(1,-4) ) + self._graph.add_edge(0, 1, (1, -4)) else: - for i in range( rank - 2 ): - self._graph.add_edge( i, i+1, 1 ) + for i in range(rank - 2): + self._graph.add_edge(i, i+1, 1) if (rank % 2 == 0): - self._graph.add_edge( rank-2, rank-1, (2,-1) ) + self._graph.add_edge(rank-2, rank-1, (2, -1)) else: - self._graph.add_edge( rank-2, rank-1, (1,-2) ) + self._graph.add_edge(rank-2, rank-1, (1, -2)) if twist == 1: self._graph.add_edge(rank, 0, (1, -2)) @@ -1291,12 +1292,12 @@ def __init__(self, letter, rank, twist=None): self._info['affine'] = True else: _mutation_type_error(data) - for i in range( rank - 2 ): - self._graph.add_edge( i, i+1, 1 ) + for i in range(rank - 2): + self._graph.add_edge(i, i+1, 1) if (rank % 2 == 0): - self._graph.add_edge( rank-2, rank-1, (1,-2) ) + self._graph.add_edge(rank-2, rank-1, (1, -2)) else: - self._graph.add_edge( rank-2, rank-1, (2,-1) ) + self._graph.add_edge(rank-2, rank-1, (2, -1)) if twist == 1: self._graph.add_edge(rank, 1, 1) @@ -1308,12 +1309,12 @@ def __init__(self, letter, rank, twist=None): self._info['affine'] = True else: _mutation_type_error(data) - for i in range( rank - 2 ): - self._graph.add_edge( i, i+1, 1 ) + for i in range(rank - 2): + self._graph.add_edge(i, i+1, 1) if (rank % 2 == 0): - self._graph.add_edge( rank-2, rank-1, (2,-1) ) + self._graph.add_edge(rank-2, rank-1, (2, -1)) else: - self._graph.add_edge( rank-2, rank-1, (1,-2) ) + self._graph.add_edge(rank-2, rank-1, (1, -2)) if twist == 1: self._graph.add_edge(rank, 1, 1) @@ -1333,10 +1334,10 @@ def __init__(self, letter, rank, twist=None): self._info['affine'] = True else: _mutation_type_error(data) - for i in range( rank - 2 ): - self._graph.add_edge( i, i+1, 1 ) + for i in range(rank - 2): + self._graph.add_edge(i, i+1, 1) - self._graph.add_edge( rank-3, rank-1, 1 ) + self._graph.add_edge(rank-3, rank-1, 1) if twist is not None: self._graph.add_edge(rank, 1, 1) @@ -1349,63 +1350,65 @@ def __init__(self, letter, rank, twist=None): self._info['skew_symmetric'] = True self._info['finite'] = True if rank == 6: - self._graph.add_edges( [ (0,1),(1,2),(2,3),(3,4),(2,5) ] ) + self._graph.add_edges([(0, 1), (1, 2), (2, 3), (3, 4), (2, 5)]) elif rank == 7: self._graph.add_edges([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (2, 6)]) elif rank == 8: self._graph.add_edges([(0, 1), (1, 2), (2, 3), - (3, 4), (4, 5), (5, 6),(2, 7)]) - elif rank in [6,7,8] and twist == 1: + (3, 4), (4, 5), (5, 6), (2, 7)]) + elif rank in [6, 7, 8] and twist == 1: self._rank = rank + 1 self._info['mutation_finite'] = True self._info['simply_laced'] = True self._info['skew_symmetric'] = True self._info['affine'] = True if rank == 6: - self._graph.add_edges( [ (0,1),(1,2),(2,3),(3,4),(2,5),(5,6) ] ) + self._graph.add_edges([(0, 1), (1, 2), (2, 3), (3, 4), (2, 5), (5, 6)]) elif rank == 7: - self._graph.add_edges( [ (0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(3,7) ] ) + self._graph.add_edges([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (3, 7)]) elif rank == 8: - self._graph.add_edges( [ (0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(2,8) ] ) - elif rank in [6,7,8] and twist == [1,1]: + self._graph.add_edges([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (2, 8)]) + elif rank in [6, 7, 8] and twist == [1, 1]: self._rank = rank + 2 self._info['mutation_finite'] = True self._info['skew_symmetric'] = True self._info['elliptic'] = True if rank == 6: - self._digraph.add_edges( [ (0,1,1),(1,2,1),(3,2,1),(3,4,1),(5,6,1),(6,7,1),(5,1,1),(2,5,2),(5,3,1),(6,2,1) ] ) + self._digraph.add_edges([(0, 1, 1), (1, 2, 1), (3, 2, 1), (3, 4, 1), (5, 6, 1), (6, 7, 1), (5, 1, 1), (2, 5, 2), (5, 3, 1), (6, 2, 1)]) elif rank == 7: - self._digraph.add_edges( [ (1,0,1),(1,2,1),(2,3,1),(4,3,1),(4,5,1),(6,5,1),(7,8,1),(3,7,2),(7,2,1),(7,4,1),(8,3,1) ] ) + self._digraph.add_edges([(1, 0, 1), (1, 2, 1), (2, 3, 1), (4, 3, 1), (4, 5, 1), + (6, 5, 1), (7, 8, 1), (3, 7, 2), (7, 2, 1), (7, 4, 1), (8, 3, 1)]) elif rank == 8: - self._digraph.add_edges( [ (0,1,1),(1,9,1),(3,9,1),(3,4,1),(2,8,1),(2,1,1),(9,2,2),(2,3,1),(8,9,1),(5,4,1),(5,6,1),(7,6,1) ] ) + self._digraph.add_edges([(0, 1, 1), (1, 9, 1), (3, 9, 1), (3, 4, 1), (2, 8, 1), (2, 1, 1), + (9, 2, 2), (2, 3, 1), (8, 9, 1), (5, 4, 1), (5, 6, 1), (7, 6, 1)]) # type E (mutation infinite) elif rank > 9 and twist is None: self._info['simply_laced'] = True self._info['skew_symmetric'] = True self._rank = rank for i in range(rank-2): - self._graph.add_edge( i, i+1, 1 ) - self._graph.add_edge( 2, rank-1 ) + self._graph.add_edge(i, i+1, 1) + self._graph.add_edge(2, rank-1) else: _mutation_type_error(data) # type AE (mutation infinite) elif letter == 'AE': - if isinstance(rank, list) and len(rank) == 2 and all( rank[i] in ZZ and rank[i] > 0 for i in [0,1] ) and twist is None: + if isinstance(rank, list) and len(rank) == 2 and all(rank[i] in ZZ and rank[i] > 0 for i in [0, 1]) and twist is None: if isinstance(rank, tuple): - rank = list( rank ) + rank = list(rank) data[1] = rank rank = sorted(rank) self._bi_rank = rank - self._rank = sum( self._bi_rank ) + 1 + self._rank = sum(self._bi_rank) + 1 if self._rank > 3: self._info['simply_laced'] = True self._info['skew_symmetric'] = True - if self._bi_rank == [1,1]: - self._graph.add_edges( [(0,1,2),(1,2,None)] ) + if self._bi_rank == [1, 1]: + self._graph.add_edges([(0, 1, 2), (1, 2, None)]) else: - self._digraph.add_edge( self._rank - 2, 0 ) + self._digraph.add_edge(self._rank - 2, 0) for i in range(self._rank-2): if i < (2 * self._bi_rank[0]) and i % 2 == 0: self._digraph.add_edge(i + 1, i) @@ -1420,12 +1423,12 @@ def __init__(self, letter, rank, twist=None): if rank > 4 and twist is None: self._rank = rank for i in range(rank-3): - self._graph.add_edge( i, i+1 ) - self._graph.add_edge( 2, rank-1 ) + self._graph.add_edge(i, i+1) + self._graph.add_edge(2, rank-1) if rank % 2 == 0: - self._graph.add_edge( rank-3,rank-2,(2,-1) ) + self._graph.add_edge(rank-3, rank-2, (2, -1)) else: - self._graph.add_edge( rank-3,rank-2,(1,-2) ) + self._graph.add_edge(rank-3, rank-2, (1, -2)) else: _mutation_type_error(data) @@ -1434,12 +1437,12 @@ def __init__(self, letter, rank, twist=None): if rank > 4 and twist is None: self._rank = rank for i in range(rank-3): - self._graph.add_edge( i, i+1 ) - self._graph.add_edge( 2, rank-1 ) + self._graph.add_edge(i, i+1) + self._graph.add_edge(2, rank-1) if rank % 2 == 0: - self._graph.add_edge( rank-3,rank-2,(1,-2) ) + self._graph.add_edge(rank-3, rank-2, (1, -2)) else: - self._graph.add_edge( rank-3,rank-2,(2,-1) ) + self._graph.add_edge(rank-3, rank-2, (2, -1)) else: _mutation_type_error(data) @@ -1450,9 +1453,9 @@ def __init__(self, letter, rank, twist=None): self._info['simply_laced'] = True self._info['skew_symmetric'] = True for i in range(rank-3): - self._graph.add_edge( i, i+1 ) - self._graph.add_edge( 2, rank-2 ) - self._graph.add_edge( rank-4, rank-1 ) + self._graph.add_edge(i, i+1) + self._graph.add_edge(2, rank-2) + self._graph.add_edge(rank-4, rank-1) else: _mutation_type_error(data) @@ -1462,48 +1465,48 @@ def __init__(self, letter, rank, twist=None): self._rank = rank self._info['mutation_finite'] = True self._info['finite'] = True - self._graph.add_edges( [ (0,1,None),(1,2,(2,-1)),(2,3,None) ] ) + self._graph.add_edges([(0, 1, None), (1, 2, (2, -1)), (2, 3, None)]) elif rank == 4 and twist == 1: self._rank = rank + 1 self._info['mutation_finite'] = True self._info['affine'] = True - self._graph.add_edges( [ (0,1,None), (1,2,None), - (2,3,(1,-2)),(3,4,None) ] ) + self._graph.add_edges([(0, 1, None), (1, 2, None), + (2, 3, (1, -2)), (3, 4, None)]) elif rank == 4 and twist == -1: self._rank = rank + 1 self._info['mutation_finite'] = True self._info['affine'] = True - self._graph.add_edges( [ (0,1,None), (1,2,None), - (2,3,(2,-1)),(3,4,None) ] ) - elif rank == 4 and (twist == [1,2]): + self._graph.add_edges([(0, 1, None), (1, 2, None), + (2, 3, (2, -1)), (3, 4, None)]) + elif rank == 4 and (twist == [1, 2]): self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges( [ (0,1,None), (1,2,None), - (2,3,(2,-1)), (4,2,(1,-2)), - (3,4,2), (4,5,None), (5,3,None) ]) - elif rank == 4 and (twist == [2,1]): + self._digraph.add_edges([(0, 1, None), (1, 2, None), + (2, 3, (2, -1)), (4, 2, (1, -2)), + (3, 4, 2), (4, 5, None), (5, 3, None)]) + elif rank == 4 and (twist == [2, 1]): self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges( [ (0,1,None), (1,2,None), - (2,3,(1,-2)), (4,2,(2,-1)), - (3,4,2), (4,5,None), (5,3,None) ]) - elif rank == 4 and twist == [2,2]: + self._digraph.add_edges([(0, 1, None), (1, 2, None), + (2, 3, (1, -2)), (4, 2, (2, -1)), + (3, 4, 2), (4, 5, None), (5, 3, None)]) + elif rank == 4 and twist == [2, 2]: self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges( [ (0,1,None), (1,2,None), - (3,1,None), (2,3,2), - (4,2,(2,-1)), (3,4,(1,-2)), - (5,4,None) ] ) - elif rank == 4 and twist == [1,1]: + self._digraph.add_edges([(0, 1, None), (1, 2, None), + (3, 1, None), (2, 3, 2), + (4, 2, (2, -1)), (3, 4, (1, -2)), + (5, 4, None)]) + elif rank == 4 and twist == [1, 1]: self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges( [ (0,1,None), (1,2,None), - (3,1,None), (2,3,2), (4,2,(1,-2)), - (3,4,(2,-1)), (5,4,None) ] ) + self._digraph.add_edges([(0, 1, None), (1, 2, None), + (3, 1, None), (2, 3, 2), (4, 2, (1, -2)), + (3, 4, (2, -1)), (5, 4, None)]) else: _mutation_type_error(data) @@ -1513,109 +1516,109 @@ def __init__(self, letter, rank, twist=None): self._rank = rank self._info['mutation_finite'] = True self._info['finite'] = True - self._graph.add_edges( [ (0,1,(1,-3)) ] ) + self._graph.add_edges([(0, 1, (1, -3))]) elif rank == 2 and twist == -1: self._rank = rank + 1 self._info['mutation_finite'] = True self._info['affine'] = True - self._graph.add_edges( [ (0,1,None),(1,2,(1,-3)) ] ) + self._graph.add_edges([(0, 1, None), (1, 2, (1, -3))]) elif rank == 2 and twist == 1: self._rank = rank + 1 self._info['mutation_finite'] = True self._info['affine'] = True - self._graph.add_edges( [ (0,1,None),(1,2,(3,-1)) ] ) - elif rank == 2 and (twist == [1,3]): + self._graph.add_edges([(0, 1, None), (1, 2, (3, -1))]) + elif rank == 2 and (twist == [1, 3]): self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges( [ (0,1,None), (1,2,(3,-1)), - (3,1,(1,-3)), (2,3,2)] ) - elif rank == 2 and (twist == [3,1]): + self._digraph.add_edges([(0, 1, None), (1, 2, (3, -1)), + (3, 1, (1, -3)), (2, 3, 2)]) + elif rank == 2 and (twist == [3, 1]): self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges( [ (0,1,None), (1,2,(1,-3)), - (3,1,(3,-1)), (2,3,2)] ) - elif rank == 2 and twist == [3,3]: + self._digraph.add_edges([(0, 1, None), (1, 2, (1, -3)), + (3, 1, (3, -1)), (2, 3, 2)]) + elif rank == 2 and twist == [3, 3]: self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges( [ (1,0,None), (0,2,2), (3,0,(3,-1)), - (2,1,None), (2,3, (1,-3))]) - elif rank == 2 and twist == [1,1]: + self._digraph.add_edges([(1, 0, None), (0, 2, 2), (3, 0, (3, -1)), + (2, 1, None), (2, 3, (1, -3))]) + elif rank == 2 and twist == [1, 1]: self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges( [ (1,0,None), (0,2,2), (3,0,(1,-3)), - (2,1,None), (2,3,(3,-1)) ] ) + self._digraph.add_edges([(1, 0, None), (0, 2, 2), (3, 0, (1, -3)), + (2, 1, None), (2, 3, (3, -1))]) else: _mutation_type_error(data) # type GR (mutation infinite) elif letter == 'GR': - if twist is None and isinstance(rank, list) and len(rank) == 2 and all( rank[i] in ZZ and rank[i] > 0 for i in [0,1] ) and rank[1] - 1 > rank[0] > 1: - gr_rank = (rank[0]-1,rank[1]-rank[0]-1) + if twist is None and isinstance(rank, list) and len(rank) == 2 and all(rank[i] in ZZ and rank[i] > 0 for i in [0, 1]) and rank[1] - 1 > rank[0] > 1: + gr_rank = (rank[0]-1, rank[1]-rank[0]-1) self._rank = prod(gr_rank) self._info['simply_laced'] = True self._info['skew_symmetric'] = True - a,b = gr_rank + a, b = gr_rank for i in range(a): for j in range(b): if i < a-1: if (i+j) % 2 == 0: - self._digraph.add_edge(i*b+j,(i+1)*b+j) + self._digraph.add_edge(i*b+j, (i+1)*b+j) else: - self._digraph.add_edge((i+1)*b+j,i*b+j) + self._digraph.add_edge((i+1)*b+j, i*b+j) if j < b-1: if (i+j) % 2 == 0: - self._digraph.add_edge(i*b+j+1,i*b+j) + self._digraph.add_edge(i*b+j+1, i*b+j) else: - self._digraph.add_edge(i*b+j,i*b+j+1) + self._digraph.add_edge(i*b+j, i*b+j+1) else: _mutation_type_error(data) # type R2 (rank 2 finite mutation types) elif letter == 'R2': - if twist is None and isinstance(rank, list) and len(rank) == 2 and all( rank[i] in ZZ and rank[i] > 0 for i in [0,1] ): + if twist is None and isinstance(rank, list) and len(rank) == 2 and all(rank[i] in ZZ and rank[i] > 0 for i in [0, 1]): rank = sorted(rank) - b,c = rank + b, c = rank self._rank = 2 if b == c: self._info['skew_symmetric'] = True - self._graph.add_edge(0,1,(b,-c)) + self._graph.add_edge(0, 1, (b, -c)) else: _mutation_type_error(data) # type T elif letter == 'T': - if twist is None and isinstance(rank, list) and len(rank) == 3 and all( rank[i] in ZZ and rank[i] > 0 for i in [0,1,2] ): + if twist is None and isinstance(rank, list) and len(rank) == 3 and all(rank[i] in ZZ and rank[i] > 0 for i in [0, 1, 2]): if isinstance(rank, tuple): - rank = list( rank ) + rank = list(rank) data[1] = rank - rank = sorted( rank ) - self._rank = sum( rank ) - 2 + rank = sorted(rank) + self._rank = sum(rank) - 2 self._info['simply_laced'] = True self._info['skew_symmetric'] = True - r,p,q = rank + r, p, q = rank for i in range(q-1): if i == 0: - self._graph.add_edge(0,1) - self._graph.add_edge(0,r) - self._graph.add_edge(0,r+p-1) + self._graph.add_edge(0, 1) + self._graph.add_edge(0, r) + self._graph.add_edge(0, r+p-1) else: if i < r-1: - self._graph.add_edge(i,i+1) + self._graph.add_edge(i, i+1) if i < p-1: - self._graph.add_edge(i+r-1,i+r) - self._graph.add_edge(i+r+p-2,i+r+p-1) + self._graph.add_edge(i+r-1, i+r) + self._graph.add_edge(i+r+p-2, i+r+p-1) else: _mutation_type_error(data) # type TR (mutation infinite if rank > 2) elif letter == 'TR': - # type ['TR',1] needs to be treated on itself (as there is no edge) + # type ['TR', 1] needs to be treated on itself (as there is no edge) if twist is None and rank == 1: - self._graph.add_vertex( 0 ) + self._graph.add_vertex(0) elif twist is None and rank > 1: self._rank = rank*(rank+1)//2 self._info['simply_laced'] = True @@ -1623,25 +1626,25 @@ def __init__(self, letter, rank, twist=None): level = 0 while level < rank: nr = rank*level-sum(range(level)) - for i in range(nr,nr+rank-level-1): - self._digraph.add_edge(i,i+1) - self._digraph.add_edge(i+rank-level,i) - self._digraph.add_edge(i+1,i+rank-level) + for i in range(nr, nr+rank-level-1): + self._digraph.add_edge(i, i+1) + self._digraph.add_edge(i+rank-level, i) + self._digraph.add_edge(i+1, i+rank-level) level += 1 else: _mutation_type_error(data) # type X elif letter == 'X': - if rank in [6,7] and twist is None: + if rank in [6, 7] and twist is None: self._rank = rank self._info['mutation_finite'] = True self._info['skew_symmetric'] = True - self._digraph.add_edges( [ (0,1,2),(1,2,None),(2,0,None), - (2,3,None),(3,4,2),(4,2,None), - (2,5,None) ] ) + self._digraph.add_edges([(0, 1, 2), (1, 2, None), (2, 0, None), + (2, 3, None), (3, 4, 2), (4, 2, None), + (2, 5, None)]) if rank == 7: - self._digraph.add_edges( [ (5,6,2),(6,2,None) ] ) + self._digraph.add_edges([(5, 6, 2), (6, 2, None)]) else: _mutation_type_error(data) @@ -1652,7 +1655,7 @@ def __init__(self, letter, rank, twist=None): # in the bipartite case, the digraph is constructed from the graph if not self._digraph: if self._graph.is_bipartite(): - self._digraph = _bipartite_graph_to_digraph( self._graph ) + self._digraph = _bipartite_graph_to_digraph(self._graph) else: raise ValueError('The QuiverMutationType does not have ' 'a Coxeter diagram.') @@ -1667,7 +1670,7 @@ def __init__(self, letter, rank, twist=None): else: self._description = str([letter, rank]) - def irreducible_components( self ): + def irreducible_components(self): """ Return a list of all irreducible components of ``self``. @@ -1708,7 +1711,7 @@ def class_size(self): sage: mut_type.class_size() 19 - sage: mut_type = QuiverMutationType( ['A',[10,3],1] ); mut_type + sage: mut_type = QuiverMutationType( ['A',[10,3], 1] ); mut_type ['A', [3, 10], 1] sage: mut_type.class_size() 142120 @@ -1718,7 +1721,7 @@ def class_size(self): sage: mut_type.class_size() 132 - sage: mut_type = QuiverMutationType( ['BD',6,1] ); mut_type + sage: mut_type = QuiverMutationType( ['BD',6, 1] ); mut_type ['BD', 6, 1] sage: mut_type.class_size() Warning: This method uses a formula which has not been proved correct. @@ -1726,7 +1729,7 @@ def class_size(self): Check that :trac:`14048` is fixed:: - sage: mut_type = QuiverMutationType( ['F',4,(2,1)] ) + sage: mut_type = QuiverMutationType( ['F',4,(2, 1)] ) sage: mut_type.class_size() 90 """ @@ -1739,29 +1742,29 @@ def class_size(self): # cluster-tilted algebras of type A if self.is_finite(): n = self._rank - a = binomial( 2*(n+1), n+1 ) // (n+2) + a = binomial(2*(n+1), n+1) // (n+2) if n % 2 == 1: - a += binomial( n+1, (n+1)//2 ) + a += binomial(n+1, (n+1)//2) if n % 3 == 0: - a += 2 * binomial( 2*n//3, n//3 ) + a += 2 * binomial(2*n//3, n//3) return a // (n+3) # the formula is taken from Bastian, Prellberg, Rubey, Stump elif self.is_affine(): - i,j = self._bi_rank + i, j = self._bi_rank i = ZZ(i) j = ZZ(j) n = i+j f = euler_phi if i == j: - return ( binomial( 2*i,i ) + - sum( f(k) * binomial(2*i//k,i//k)**2 - for k in [k for k in i.divisors() - if k in j.divisors()] ) // n ) // 4 + return (binomial(2 * i, i) + + sum(f(k) * binomial(2 * i // k, i // k)**2 + for k in i.divisors() + if k in j.divisors()) // n) // 4 else: - return sum( f(k) * binomial(2*i//k,i//k) * - binomial(2*j//k,j//k) - for k in [k for k in i.divisors() - if k in j.divisors()] ) // ( 2 * n ) + return sum(f(k) * binomial(2 * i // k, i // k) * + binomial(2 * j // k, j // k) + for k in i.divisors() + if k in j.divisors()) // (2 * n) # types B and C (finite and affine) elif self._letter in ['B', 'C']: @@ -1771,7 +1774,7 @@ def class_size(self): n = self._rank return binomial(2 * n, n) // (n + 1) - elif self._letter in ['BB','CC']: + elif self._letter in ['BB', 'CC']: # these two formulas are not yet proven print("Warning: This method uses a formula " "which has not been proved correct.") @@ -1795,7 +1798,7 @@ def class_size(self): return binomial(2 * n, n) # types BD and CD (affine) - elif self._letter in ['BD','CD']: + elif self._letter in ['BD', 'CD']: # this formula is not yet proven print("Warning: This method uses a formula " "which has not been proved correct.") @@ -1860,9 +1863,9 @@ def class_size(self): elif self.is_affine(): return 60 elif self.is_elliptic(): - if self._twist == [1,2]: + if self._twist == [1, 2]: return 90 - if self._twist == [1,1] or self._twist == [2,2]: + if self._twist == [1, 1] or self._twist == [2, 2]: return 35 # type G @@ -1872,9 +1875,9 @@ def class_size(self): elif self.is_affine(): return 6 elif self.is_elliptic(): - if self._twist == [1,3]: + if self._twist == [1, 3]: return 7 - if self._twist == [1,1] or self._twist == [3,3]: + if self._twist == [1, 1] or self._twist == [3, 3]: return 2 # type X @@ -1911,7 +1914,7 @@ def dual(self): """ letter = self.letter() # the self-dual cases - if letter != 'BC' and letter[0] in ['B','C']: + if letter != 'BC' and letter[0] in ['B', 'C']: if letter == 'BB': letter = 'CC' elif letter == 'CC': @@ -1924,9 +1927,9 @@ def dual(self): if self.is_affine(): rank -= 1 twist = self._twist - return QuiverMutationType(letter,rank,twist) + return QuiverMutationType(letter, rank, twist) # the cases F and G have non-trivial duality in some cases - elif letter in ['F','G']: + elif letter in ['F', 'G']: if self.is_finite(): return self elif self.is_affine(): @@ -1936,15 +1939,15 @@ def dual(self): twist = self._twist rank = self._rank - 2 if letter == 'F': - if self._twist == [2,2]: - twist == [1,1] - if self._twist == [1,1]: - twist == [2,2] + if self._twist == [2, 2]: + twist == [1, 1] + if self._twist == [1, 1]: + twist == [2, 2] if letter == 'G': - if self._twist == [3,3]: - twist = [1,1] - elif self._twist == [1,1]: - twist = [3,3] + if self._twist == [3, 3]: + twist = [1, 1] + elif self._twist == [1, 1]: + twist = [3, 3] else: rank = self._rank return QuiverMutationType(letter, rank, twist) @@ -1958,6 +1961,7 @@ class QuiverMutationType_Reducible(QuiverMutationType_abstract): called directly, but through QuiverMutationType. Inherits from QuiverMutationType_abstract. """ + def __init__(self, *args): """ Should not be called directly, but through QuiverMutationType. @@ -1973,7 +1977,7 @@ def __init__(self, *args): [ ['A', 4], ['B', 6] ] """ data = args - if len(data) < 2 or not all( isinstance(comp, QuiverMutationType_Irreducible) for comp in data ): + if len(data) < 2 or not all(isinstance(comp, QuiverMutationType_Irreducible) for comp in data): return _mutation_type_error(data) # _info is initialized @@ -2017,7 +2021,7 @@ def __init__(self, *args): self._description += comps[i]._description self._description += " ]" - def irreducible_components( self ): + def irreducible_components(self): """ Return a list of all irreducible components of ``self``. @@ -2085,7 +2089,7 @@ def class_size(self): multiplicities[i]) for i in range(len(sizes))) - def dual(self): + def dual(self) -> QuiverMutationType: """ Return the QuiverMutationType which is dual to ``self``. @@ -2097,10 +2101,10 @@ def dual(self): [ ['A', 5], ['C', 6], ['B', 5], ['D', 4] ] """ comps = self.irreducible_components() - return QuiverMutationType( [comp.dual() for comp in comps ] ) + return QuiverMutationType([comp.dual() for comp in comps]) -def _construct_classical_mutation_classes(n): +def _construct_classical_mutation_classes(n) -> dict: r""" Return a dict with keys being tuples representing regular QuiverMutationTypes of the given rank, and with values being lists @@ -2122,42 +2126,42 @@ def _construct_classical_mutation_classes(n): data = {} # finite A - data[ ('A',n) ] = ClusterQuiver(['A',n]).mutation_class(data_type='dig6') + data[('A', n)] = ClusterQuiver(['A', n]).mutation_class(data_type='dig6') # affine A for j in range(1, n//2+1): - data[ ('A',(n-j,j),1) ] = ClusterQuiver(['A',[n-j,j],1]).mutation_class(data_type='dig6') + data[('A', (n-j, j), 1)] = ClusterQuiver(['A', [n-j, j], 1]).mutation_class(data_type='dig6') # finite B if n > 1: - data[ ('B',n) ] = ClusterQuiver(['B',n]).mutation_class(data_type='dig6') + data[('B', n)] = ClusterQuiver(['B', n]).mutation_class(data_type='dig6') # affine B if n > 2: - data[ ('BB',n-1,1) ] = ClusterQuiver(['BB',n-1,1]).mutation_class(data_type='dig6') + data[('BB', n-1, 1)] = ClusterQuiver(['BB', n-1, 1]).mutation_class(data_type='dig6') # finite C if n > 2: - data[ ('C',n) ] = ClusterQuiver(['C',n]).mutation_class(data_type='dig6') + data[('C', n)] = ClusterQuiver(['C', n]).mutation_class(data_type='dig6') # affine C if n > 1: - data[ ('BC',n-1,1) ] = ClusterQuiver(['BC',n-1,1]).mutation_class(data_type='dig6') + data[('BC', n-1, 1)] = ClusterQuiver(['BC', n-1, 1]).mutation_class(data_type='dig6') # affine CC if n > 2: - data[ ('CC',n-1,1) ] = ClusterQuiver(['CC',n-1,1]).mutation_class(data_type='dig6') + data[('CC', n-1, 1)] = ClusterQuiver(['CC', n-1, 1]).mutation_class(data_type='dig6') # affine BD if n > 3: - data[ ('BD',n-1,1) ] = ClusterQuiver(['BD',n-1,1]).mutation_class(data_type='dig6') + data[('BD', n-1, 1)] = ClusterQuiver(['BD', n-1, 1]).mutation_class(data_type='dig6') # affine CD if n > 3: - data[ ('CD',n-1,1) ] = ClusterQuiver(['CD',n-1,1]).mutation_class(data_type='dig6') + data[('CD', n-1, 1)] = ClusterQuiver(['CD', n-1, 1]).mutation_class(data_type='dig6') # finite D if n > 3: - data[ ('D',n) ] = ClusterQuiver(['D',n]).mutation_class(data_type='dig6') + data[('D', n)] = ClusterQuiver(['D', n]).mutation_class(data_type='dig6') # affine D if n > 4: - data[ ('D',n-1,1) ] = ClusterQuiver(['D',n-1,1]).mutation_class(data_type='dig6') + data[('D', n-1, 1)] = ClusterQuiver(['D', n-1, 1]).mutation_class(data_type='dig6') return data -def _construct_exceptional_mutation_classes(n): +def _construct_exceptional_mutation_classes(n) -> dict: r""" Return a dict with keys being tuples representing exceptional QuiverMutationTypes of the given rank, and with values being lists @@ -2183,41 +2187,41 @@ def _construct_exceptional_mutation_classes(n): from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver data = {} # finite E - if n in [6,7,8]: - data[ ('E',n) ] = ClusterQuiver(['E',n]).mutation_class(data_type='dig6') + if n in [6, 7, 8]: + data[('E', n)] = ClusterQuiver(['E', n]).mutation_class(data_type='dig6') # affine E - if n in [7,8,9]: - data[ ('E',n-1,1) ] = ClusterQuiver(['E',n-1,1]).mutation_class(data_type='dig6') + if n in [7, 8, 9]: + data[('E', n - 1, 1)] = ClusterQuiver(['E', n - 1, 1]).mutation_class(data_type='dig6') # elliptic E - if n in [8,9,10]: - data[ ('E',n-2,(1,1)) ] = ClusterQuiver(['E',n-2,[1,1]]).mutation_class(data_type='dig6') + if n in [8, 9, 10]: + data[('E', n - 2, (1, 1))] = ClusterQuiver(['E', n - 2, [1, 1]]).mutation_class(data_type='dig6') # finite F if n == 4: - data[ ('F',4) ] = ClusterQuiver(['F',4]).mutation_class(data_type='dig6') + data[('F', 4)] = ClusterQuiver(['F', 4]).mutation_class(data_type='dig6') # affine F if n == 5: - data[ ('F',4,1) ] = ClusterQuiver(['F',4,1]).mutation_class(data_type='dig6') - data[ ('F',4,-1) ] = ClusterQuiver(['F',4,-1]).mutation_class(data_type='dig6') + data[('F', 4, 1)] = ClusterQuiver(['F', 4, 1]).mutation_class(data_type='dig6') + data[('F', 4, -1)] = ClusterQuiver(['F', 4, -1]).mutation_class(data_type='dig6') # finite G if n == 2: - data[ ('G',2) ] = ClusterQuiver(['G',2]).mutation_class(data_type='dig6') + data[('G', 2)] = ClusterQuiver(['G', 2]).mutation_class(data_type='dig6') # affine G if n == 3: - data[ ('G',2,1) ] = ClusterQuiver(['G',2,1]).mutation_class(data_type='dig6') - data[ ('G',2,-1) ] = ClusterQuiver(['G',2,-1]).mutation_class(data_type='dig6') + data[('G', 2, 1)] = ClusterQuiver(['G', 2, 1]).mutation_class(data_type='dig6') + data[('G', 2, -1)] = ClusterQuiver(['G', 2, -1]).mutation_class(data_type='dig6') # elliptic G if n == 4: - data[ ('G',2,(1,3)) ] = ClusterQuiver(['G',2,(1,3)]).mutation_class(data_type='dig6') - data[ ('G',2,(1,1)) ] = ClusterQuiver(['G',2,(1,1)]).mutation_class(data_type='dig6') - data[ ('G',2,(3,3)) ] = ClusterQuiver(['G',2,(3,3)]).mutation_class(data_type='dig6') + data[('G', 2, (1, 3))] = ClusterQuiver(['G', 2, (1, 3)]).mutation_class(data_type='dig6') + data[('G', 2, (1, 1))] = ClusterQuiver(['G', 2, (1, 1)]).mutation_class(data_type='dig6') + data[('G', 2, (3, 3))] = ClusterQuiver(['G', 2, (3, 3)]).mutation_class(data_type='dig6') # X - if n in [6,7]: - data[ ('X',n) ] = ClusterQuiver(['X',n]).mutation_class(data_type='dig6') + if n in [6, 7]: + data[('X', n)] = ClusterQuiver(['X', n]).mutation_class(data_type='dig6') # elliptic F if n == 6: - data[ ('F',4,(1,2)) ] = ClusterQuiver(['F',4,(1,2)]).mutation_class(data_type='dig6') - data[ ('F',4,(1,1)) ] = ClusterQuiver(['F',4,(1,1)]).mutation_class(data_type='dig6') - data[ ('F',4,(2,2)) ] = ClusterQuiver(['F',4,(2,2)]).mutation_class(data_type='dig6') + data[('F', 4, (1, 2))] = ClusterQuiver(['F', 4, (1, 2)]).mutation_class(data_type='dig6') + data[('F', 4, (1, 1))] = ClusterQuiver(['F', 4, (1, 1)]).mutation_class(data_type='dig6') + data[('F', 4, (2, 2))] = ClusterQuiver(['F', 4, (2, 2)]).mutation_class(data_type='dig6') return data @@ -2268,14 +2272,14 @@ def _save_data_dig6(n, types='ClassicalExceptional', verbose=False): from sage.env import DOT_SAGE from sage.misc.misc import sage_makedirs types_path = os.path.join(DOT_SAGE, 'cluster_algebra_quiver') - types_file = os.path.join(types_path,'mutation_classes_%s.dig6' % n) + types_file = os.path.join(types_path, 'mutation_classes_%s.dig6' % n) sage_makedirs(types_path) from sage.misc.temporary_file import atomic_write with atomic_write(types_file, binary=True) as f: pickle.dump(data, f) if verbose: - keys = sorted(data.keys(),key=str) - print("\nThe following types are saved to file", types_file,"and will now be used to determine quiver mutation types:") + keys = sorted(data, key=str) + print("\nThe following types are saved to file", types_file, "and will now be used to determine quiver mutation types:") print(keys) @@ -2331,16 +2335,16 @@ def save_quiver_data(n, up_to=True, types='ClassicalExceptional', verbose=True): """ from sage.combinat.cluster_algebra_quiver.mutation_type import load_data if up_to is True: - ranks = range(1,n+1) + ranks = range(1, n + 1) elif up_to is False: ranks = [n] for i in ranks: - _save_data_dig6(i,types=types,verbose=verbose) + _save_data_dig6(i, types=types, verbose=verbose) # we finally clear the load_data load_data.clear_cache() -def _bipartite_graph_to_digraph(g): +def _bipartite_graph_to_digraph(g) -> DiGraph: """ Return a digraph obtained from a bipartite graph ``g`` by choosing one set of the bipartition to be the set of sinks and the other to be the @@ -2349,7 +2353,7 @@ def _bipartite_graph_to_digraph(g): EXAMPLES:: sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _bipartite_graph_to_digraph - sage: G = Graph([(1,2)]) + sage: G = Graph([(1, 2)]) sage: _bipartite_graph_to_digraph(G) Digraph on 2 vertices """ @@ -2364,7 +2368,7 @@ def _bipartite_graph_to_digraph(g): return dg -def _is_mutation_type(data): +def _is_mutation_type(data) -> bool: """ Return ``True`` if ``data`` is a QuiverMutationType. @@ -2412,7 +2416,7 @@ def _mutation_type_error(data): raise ValueError(return_str) -def _edge_list_to_matrix(edges, nlist, mlist): +def _edge_list_to_matrix(edges, nlist, mlist) -> matrix: r""" Return the matrix obtained from the edge list of a quiver. @@ -2429,8 +2433,8 @@ def _edge_list_to_matrix(edges, nlist, mlist): EXAMPLES:: sage: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _edge_list_to_matrix - sage: G = QuiverMutationType(['A',2])._digraph - sage: _edge_list_to_matrix(G.edges(), [0,1], []) + sage: G = QuiverMutationType(['A', 2])._digraph + sage: _edge_list_to_matrix(G.edges(), [0, 1], []) [ 0 1] [-1 0] @@ -2446,15 +2450,16 @@ def _edge_list_to_matrix(edges, nlist, mlist): [ 0 -1] """ n = len(nlist) - m = len(mlist) nmlist = nlist + mlist - M = matrix(ZZ, n + m, n, sparse=True) - for edge in edges: - if edge[2] is None: - edge = (edge[0], edge[1], (1, -1)) - elif edge[2] in ZZ: - edge = (edge[0], edge[1], (edge[2], -edge[2])) - v1, v2, (a, b) = edge + nm = len(nmlist) + M = matrix(ZZ, nm, n, sparse=True) + for v1, v2, label in edges: + if label is None: + a, b = 1, -1 + elif label in ZZ: + a, b = label, -label + else: + a, b = label if v1 in nlist: M[nmlist.index(v2), nmlist.index(v1)] = b if v2 in nlist: From c616d52bfeda725ca1d6ae4231489e8d4ce0cd60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 6 Oct 2021 14:52:16 +0200 Subject: [PATCH 295/511] fix a problem in is_connected --- src/sage/graphs/base/c_graph.pyx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index a3b122c9d81..515ca3076ff 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -4400,11 +4400,18 @@ cdef class CGraphBackend(GenericGraphBackend): sage: Graph(graphs.CubeGraph(3)).is_connected() True + + TESTS:: + + sage: P = posets.PentagonPoset() + sage: H = P._hasse_diagram + sage: H._backend.is_connected() + True """ cdef int v_int cdef CGraph cg = self.cg() - if cg.num_edges() < cg.num_verts - 1: + if cg.num_arcs < cg.num_verts - 1: return False v_int = bitset_first(cg.active_vertices) From 0f305308bcb2c5860f88ab6e687b3d5b614c6d85 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 09:15:18 -0700 Subject: [PATCH 296/511] src/sage/misc/sageinspect.py: Fix up a doctest on the source code of src/sage/symbolic/expression.pyx --- src/sage/misc/sageinspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 72c9cdf1d22..be7d50783bc 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -2308,7 +2308,7 @@ def sage_getsourcelines(obj): ...) sage: x = var('x') sage: lines, lineno = sage_getsourcelines(x); lines[0:5] - ['cdef class Expression(CommutativeRingElement):\n', + ['cdef class Expression(...):\n', '\n', ' cdef GEx _gobj\n', '\n', From 2a81e0f5a362bafa6612bab4fb4f31ddccc731cd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 09:15:31 -0700 Subject: [PATCH 297/511] src/sage/symbolic/expression.pyx: Fix markup of doctest output --- src/sage/symbolic/expression.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 3f6cb7b0f3d..518ea825d1e 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -414,6 +414,7 @@ cpdef bint is_Expression(x): sage: from sage.symbolic.expression import is_Expression sage: is_Expression(x) + doctest:warning... DeprecationWarning: is_Expression is deprecated; use isinstance(..., sage.structure.element.Expression) instead True From 27c53ac6450f789246b1df895bc26950a0cceb65 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 12:55:43 -0700 Subject: [PATCH 298/511] src/sage/features/sagemath.py: Add 'sage.plot' --- src/sage/features/sagemath.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index f18e5e79e88..95676aa2cc1 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -51,6 +51,12 @@ def __init__(self): PythonModule.__init__(self, 'sage.matrix.matrix_gfpn_dense', spkg='meataxe') +class sage__plot(PythonModule): + + def __init__(self): + PythonModule.__init__(self, 'sage.plot.plot') + + class sage__rings__number_field(PythonModule): def __init__(self): @@ -96,6 +102,8 @@ def sage_optional_tags(): yield 'sage.graphs.mcqd' if sage__matrix__matrix_gfpn_dense().is_present(): yield 'sage.matrix.matrix_gfpn_dense' + if sage__plot().is_present(): + yield 'sage.plot' if sage__rings__number_field().is_present(): yield 'sage.rings.number_field' if sage__rings__real_double().is_present(): From db154ec51e3a22e44cbbd9317e05c8cc9c6b7dec Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 14:50:00 -0700 Subject: [PATCH 299/511] sage.doctest.parsing.RIFtol: Fixup when RealIntervalField not available --- src/sage/doctest/parsing.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 1591dd609cd..7af1b1c8f8c 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -90,9 +90,7 @@ def RIFtol(*args): from warnings import warn warn("RealIntervalField not available, ignoring all tolerance specifications in doctests") def fake_RIFtol(*args): - if len(args) == 2: - return (args[0] + args[1]) / 2 - return args[0] + return 0 _RIFtol = fake_RIFtol else: _RIFtol = RealIntervalField(1044) From 88886ee09c6e402de41ddd415cae0e48d807ce13 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 15:17:03 -0700 Subject: [PATCH 300/511] src/sage/symbolic/expression.pyx: Fix doctest output --- src/sage/symbolic/expression.pyx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 518ea825d1e..8a75c1c435c 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -408,7 +408,10 @@ include "pynac_impl.pxi" cpdef bint is_Expression(x): """ - Return True if *x* is a symbolic Expression. + Return True if ``x`` is a symbolic expression. + + This method is deprecated. Use :func:`isinstance` with + :class:`sage.structure.element.Expression` instead. EXAMPLES:: @@ -417,6 +420,7 @@ cpdef bint is_Expression(x): doctest:warning... DeprecationWarning: is_Expression is deprecated; use isinstance(..., sage.structure.element.Expression) instead + See https://trac.sagemath.org/32638 for details. True sage: is_Expression(2) False From f48534bd4dbf4c9612ce0cefd8ef3aedaed10490 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 19:23:30 -0700 Subject: [PATCH 301/511] build/pkgs/sqlite: Update to 3.36.0 --- build/pkgs/sqlite/checksums.ini | 9 +++++---- build/pkgs/sqlite/package-version.txt | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build/pkgs/sqlite/checksums.ini b/build/pkgs/sqlite/checksums.ini index 72262b7523c..5cb33394ab3 100644 --- a/build/pkgs/sqlite/checksums.ini +++ b/build/pkgs/sqlite/checksums.ini @@ -1,4 +1,5 @@ -tarball=sqlite-autoconf-VERSION.tar.gz -sha1=053d8237eb9741b0e297073810668c2611a8e38e -md5=8f3dfe83387e62ecb91c7c5c09c688dc -cksum=1918823569 +tarball=sqlite-autoconf-3360000.tar.gz +sha1=a4bcf9e951bfb9745214241ba08476299fc2dc1e +md5=f5752052fc5b8e1b539af86a3671eac7 +cksum=763219165 +upstream_url=https://www.sqlite.org/2021/sqlite-autoconf-3360000.tar.gz diff --git a/build/pkgs/sqlite/package-version.txt b/build/pkgs/sqlite/package-version.txt index b4456b4138a..0b477b458f2 100644 --- a/build/pkgs/sqlite/package-version.txt +++ b/build/pkgs/sqlite/package-version.txt @@ -1 +1 @@ -3290000 +3.36.0 From adcd8206905a8ec0bfb6217d9cd8d8d3ecc2765e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 19:24:22 -0700 Subject: [PATCH 302/511] build/pkgs/sqlite/spkg-install.in: Do not copy in config.* files --- build/pkgs/sqlite/spkg-install.in | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build/pkgs/sqlite/spkg-install.in b/build/pkgs/sqlite/spkg-install.in index f20e4ecdb23..f8151f3ac84 100644 --- a/build/pkgs/sqlite/spkg-install.in +++ b/build/pkgs/sqlite/spkg-install.in @@ -2,10 +2,6 @@ rm -f "$SAGE_LOCAL/bin/sqlite3" cd src -# Use newer version of config.guess and config.sub (see Trac #19711) -cp "$SAGE_ROOT"/config/config.* . - - export CPPFLAGS="$CPPFLAGS -I$SAGE_LOCAL/include" # Old OS X systems need -DSQLITE_WITHOUT_ZONEMALLOC From fb4414d04d250caf3e16ac419b7961635bd56db8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 19:25:13 -0700 Subject: [PATCH 303/511] build/pkgs/sqlite/spkg-install.in: Remove workaround for ancient OS X --- build/pkgs/sqlite/spkg-install.in | 6 ------ 1 file changed, 6 deletions(-) diff --git a/build/pkgs/sqlite/spkg-install.in b/build/pkgs/sqlite/spkg-install.in index f8151f3ac84..af18b54dd3c 100644 --- a/build/pkgs/sqlite/spkg-install.in +++ b/build/pkgs/sqlite/spkg-install.in @@ -4,12 +4,6 @@ cd src export CPPFLAGS="$CPPFLAGS -I$SAGE_LOCAL/include" -# Old OS X systems need -DSQLITE_WITHOUT_ZONEMALLOC -if uname -sr |grep 'Darwin [0-8][.]' >/dev/null; then - export CPPFLAGS="$CPPFLAGS -DSQLITE_WITHOUT_ZONEMALLOC" -fi - - sdh_configure sdh_make sdh_make_install From 95a51e87c8687ce6458476db47ab32ffae5f81be Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 19:29:09 -0700 Subject: [PATCH 304/511] build/pkgs/sqlite/spkg-install.in: Make sure autotools are not invoked --- build/pkgs/sqlite/spkg-install.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/pkgs/sqlite/spkg-install.in b/build/pkgs/sqlite/spkg-install.in index af18b54dd3c..d071ddebe17 100644 --- a/build/pkgs/sqlite/spkg-install.in +++ b/build/pkgs/sqlite/spkg-install.in @@ -4,6 +4,9 @@ cd src export CPPFLAGS="$CPPFLAGS -I$SAGE_LOCAL/include" +# Trac #32646: configure script does not have --disable-maintainer-mode +rm -f configure.ac */configure.ac Makefile.am + sdh_configure sdh_make sdh_make_install From cf9b75a008388ceaa019e28a3eda883350ba7ee1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 21:25:22 -0700 Subject: [PATCH 305/511] src/sage/symbolic/relation.py: Remove unused import; use sage.structure.element.Expression for isinstance --- src/sage/symbolic/relation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index 698eed45d0e..62eabb3b356 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -1029,7 +1029,7 @@ def solve(f, *args, **kwds): or a list of symbolic expressions. """ from sage.symbolic.ring import is_SymbolicVariable - from sage.symbolic.expression import Expression, is_Expression + from sage.structure.element import Expression explicit_solutions = kwds.get('explicit_solutions', None) multiplicities = kwds.get('multiplicities', None) to_poly_solve = kwds.get('to_poly_solve', None) From 10e8d6395e1c829b6a28750d3035de95862230b8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 21:36:56 -0700 Subject: [PATCH 306/511] sage.features.sagemath: Use JoinFeature when tag is different from the actually tested module --- src/sage/features/sagemath.py | 75 ++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index 95676aa2cc1..f0ecfdddca7 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -2,21 +2,24 @@ Check for SageMath Python modules """ from . import PythonModule +from .join_feature import JoinFeature -class sage__combinat(PythonModule): +class sage__combinat(JoinFeature): def __init__(self): # sage.combinat will be a namespace package. # Testing whether sage.combinat itself can be imported is meaningless. # Hence, we test a Python module within the package. - PythonModule.__init__(self, 'sage.combinat.combinations') + JoinFeature.__init__(self, 'sage.combinat', + [PythonModule('sage.combinat.combinations')]) -class sage__graphs(PythonModule): +class sage__graphs(JoinFeature): def __init__(self): - PythonModule.__init__(self, 'sage.graphs.graph') + JoinFeature.__init__(self, 'sage.graphs', + [PythonModule('sage.graphs.graph')]) class sage__graphs__bliss(PythonModule): @@ -51,16 +54,18 @@ def __init__(self): PythonModule.__init__(self, 'sage.matrix.matrix_gfpn_dense', spkg='meataxe') -class sage__plot(PythonModule): +class sage__plot(JoinFeature): def __init__(self): - PythonModule.__init__(self, 'sage.plot.plot') + JoinFeature.__init__(self, 'sage.plot', + [PythonModule('sage.plot.plot')]) -class sage__rings__number_field(PythonModule): +class sage__rings__number_field(JoinFeature): def __init__(self): - PythonModule.__init__(self, 'sage.rings.number_field_element') + JoinFeature.__init__(self, 'sage.rings.number_field', + [PythonModule('sage.rings.number_field.number_field_element')]) class sage__rings__real_double(PythonModule): @@ -69,10 +74,12 @@ def __init__(self): PythonModule.__init__(self, 'sage.rings.real_double') -class sage__symbolic(PythonModule): +class sage__symbolic(JoinFeature): def __init__(self): - PythonModule.__init__(self, 'sage.symbolic.expression', spkg="sagemath_symbolics") + JoinFeature.__init__(self, 'sage.symbolic', + [PythonModule('sage.symbolic.expression')], + spkg="sagemath_symbolics") def sage_optional_tags(): @@ -82,31 +89,35 @@ def sage_optional_tags(): These tags are named after Python packages/modules (e.g., :mod:`~sage.symbolic`), not distribution packages (``sagemath-symbolics``). - This is motivated by a separation of concerns: The author of a module that depends + This design is motivated by a separation of concerns: The author of a module that depends on some functionality provided by a Python module usually already knows the name of the Python module, so we do not want to force the author to also know about the distribution package that provides the Python module. Instead, we associate distribution packages to Python modules in - :mod:`sage.features.sagemath` via the ``spkg`` parameter of :class:`PythonModule``. + :mod:`sage.features.sagemath` via the ``spkg`` parameter of :class:`Feature`. + + EXAMPLES:: + + sage: from sage.features.sagemath import sage_optional_tags + sage: list(sage_optional_tags()) # random + ['sage.graphs', + 'sage.graphs.bliss', + 'sage.matrix.matrix_gfpn_dense', + 'sage.plot', + 'sage.rings.number_field', + 'sage.rings.real_double', + 'sage.symbolic'] """ - if sage__combinat().is_present(): - yield 'sage.combinat' - if sage__graphs().is_present(): - yield 'sage.graphs' - if sage__graphs__bliss().is_present(): - yield 'sage.graphs.bliss' - if sage__graphs__graph_decompositions__tdlib().is_present(): - yield 'sage.graphs.graph_decompositions.tdlib' - if sage__graphs__mcqd().is_present(): - yield 'sage.graphs.mcqd' - if sage__matrix__matrix_gfpn_dense().is_present(): - yield 'sage.matrix.matrix_gfpn_dense' - if sage__plot().is_present(): - yield 'sage.plot' - if sage__rings__number_field().is_present(): - yield 'sage.rings.number_field' - if sage__rings__real_double().is_present(): - yield 'sage.rings.real_double' - if sage__symbolic().is_present(): - yield 'sage.symbolic' + for feature in [sage__combinat(), + sage__graphs(), + sage__graphs__bliss(), + sage__graphs__graph_decompositions__tdlib(), + sage__graphs__mcqd(), + sage__matrix__matrix_gfpn_dense(), + sage__plot(), + sage__rings__number_field(), + sage__rings__real_double(), + sage__symbolic()]: + if feature.is_present(): + yield feature.name From 654d09ca4c22f4888d8e511789e57a7627043492 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 22:31:57 -0700 Subject: [PATCH 307/511] sage.features.sagemath: Change sage_optional_tags to sage_features --- src/sage/doctest/control.py | 4 ++-- src/sage/features/sagemath.py | 19 ++++++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 05767a50876..3f11a5bf982 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -371,8 +371,8 @@ def __init__(self, options, args): from sage.features import package_systems options.optional.update(system.name for system in package_systems()) - from sage.features.sagemath import sage_optional_tags - options.optional.update(sage_optional_tags()) + from sage.features.sagemath import sage_features + options.optional.update(feature.name for feature in sage_features()) # Check that all tags are valid for o in options.optional: diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index f0ecfdddca7..91fec0ac498 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -82,7 +82,7 @@ def __init__(self): spkg="sagemath_symbolics") -def sage_optional_tags(): +def sage_features(): """ Return tags for conditionalizing doctests. @@ -99,15 +99,12 @@ def sage_optional_tags(): EXAMPLES:: - sage: from sage.features.sagemath import sage_optional_tags - sage: list(sage_optional_tags()) # random - ['sage.graphs', - 'sage.graphs.bliss', - 'sage.matrix.matrix_gfpn_dense', - 'sage.plot', - 'sage.rings.number_field', - 'sage.rings.real_double', - 'sage.symbolic'] + sage: from sage.features.sagemath import sage_features + sage: list(sage_features()) # random + [Feature('sage.graphs'), + Feature('sage.graphs.bliss'), + Feature('sage.plot'), + Feature('sage.rings.real_double')] """ for feature in [sage__combinat(), sage__graphs(), @@ -120,4 +117,4 @@ def sage_optional_tags(): sage__rings__real_double(), sage__symbolic()]: if feature.is_present(): - yield feature.name + yield feature From f63a7d0171ba5f753d1755e0aff3fd00e373590c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 00:19:30 -0700 Subject: [PATCH 308/511] src/sage/features/: Move features depending on optional packages to separate files --- src/sage/features/bliss.py | 14 +++++++----- src/sage/features/mcqd.py | 11 ++++++++++ src/sage/features/meataxe.py | 11 ++++++++++ src/sage/features/sagemath.py | 40 ++--------------------------------- src/sage/features/tdlib.py | 11 ++++++++++ 5 files changed, 44 insertions(+), 43 deletions(-) create mode 100644 src/sage/features/mcqd.py create mode 100644 src/sage/features/meataxe.py create mode 100644 src/sage/features/tdlib.py diff --git a/src/sage/features/bliss.py b/src/sage/features/bliss.py index bda43f4a5f8..d870ade5973 100644 --- a/src/sage/features/bliss.py +++ b/src/sage/features/bliss.py @@ -3,6 +3,7 @@ Checks for bliss """ from . import CythonFeature, PythonModule +from .join_feature import JoinFeature TEST_CODE = """ @@ -45,10 +46,10 @@ def __init__(self): url="http://www.tcs.hut.fi/Software/bliss/") -class Bliss(PythonModule): +class Bliss(JoinFeature): r""" A :class:`Feature` which describes whether the :mod:`sage.graphs.bliss` - module has been enabled for this build of Sage and is functional. + module is available in this installation of Sage. EXAMPLES:: @@ -61,7 +62,10 @@ def __init__(self): sage: from sage.features.bliss import Bliss sage: Bliss() - Feature('sage.graphs.bliss') + Feature('bliss') """ - PythonModule.__init__(self, "sage.graphs.bliss", spkg="bliss", - url="http://www.tcs.hut.fi/Software/bliss/") + # Currently part of sagemath_standard, conditionally built. + # Will be changed to spkg='sagemath_bliss' later + JoinFeature.__init__(self, "bliss", + [PythonModule("sage.graphs.bliss", spkg="bliss", + url="http://www.tcs.hut.fi/Software/bliss/")]) diff --git a/src/sage/features/mcqd.py b/src/sage/features/mcqd.py new file mode 100644 index 00000000000..6539af1d6d5 --- /dev/null +++ b/src/sage/features/mcqd.py @@ -0,0 +1,11 @@ +from . import PythonModule +from .join_feature import JoinFeature + + +class Mcqd(JoinFeature): + + def __init__(self): + # Currently part of sagemath_standard, conditionally built. + # Will be changed to spkg='sagemath_mcqd' later + JoinFeature.__init__(self, 'mcqd', + [PythonModule('sage.graphs.mcqd', spkg='mcqd')]) diff --git a/src/sage/features/meataxe.py b/src/sage/features/meataxe.py new file mode 100644 index 00000000000..a8b65d166dc --- /dev/null +++ b/src/sage/features/meataxe.py @@ -0,0 +1,11 @@ +from . import PythonModule +from .join_feature import JoinFeature + + +class Meataxe(JoinFeature): + + def __init__(self): + # Currently part of sagemath_standard, conditionally built. + # Will be changed to spkg='sagemath_meataxe' later + JoinFeature.__init__(self, 'meataxe', + [PythonModule('sage.matrix.matrix_gfpn_dense', spkg='meataxe')]) diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index 91fec0ac498..2af7def3668 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -22,38 +22,6 @@ def __init__(self): [PythonModule('sage.graphs.graph')]) -class sage__graphs__bliss(PythonModule): - - def __init__(self): - # Currently part of sagemath_standard, conditionally built. - # Will be changed to spkg='sagemath_bliss' later - PythonModule.__init__(self, 'sage.graphs.bliss', spkg='bliss') - - -class sage__graphs__graph_decompositions__tdlib(PythonModule): - - def __init__(self): - # Currently part of sagemath_standard, conditionally built. - # Will be changed to spkg='sagemath_tdlib' later - PythonModule.__init__(self, 'sage.graphs.graph_decompositions.tdlib', spkg='tdlib') - - -class sage__graphs__mcqd(PythonModule): - - def __init__(self): - # Currently part of sagemath_standard, conditionally built. - # Will be changed to spkg='sagemath_mcqd' later - PythonModule.__init__(self, 'sage.graphs.mcqd', spkg='mcqd') - - -class sage__matrix__matrix_gfpn_dense(PythonModule): - - def __init__(self): - # Currently part of sagemath_standard, conditionally built. - # Will be changed to spkg='sagemath_meataxe' later - PythonModule.__init__(self, 'sage.matrix.matrix_gfpn_dense', spkg='meataxe') - - class sage__plot(JoinFeature): def __init__(self): @@ -84,7 +52,7 @@ def __init__(self): def sage_features(): """ - Return tags for conditionalizing doctests. + Return features corresponding to parts of the Sage library. These tags are named after Python packages/modules (e.g., :mod:`~sage.symbolic`), not distribution packages (``sagemath-symbolics``). @@ -102,16 +70,12 @@ def sage_features(): sage: from sage.features.sagemath import sage_features sage: list(sage_features()) # random [Feature('sage.graphs'), - Feature('sage.graphs.bliss'), Feature('sage.plot'), + Feature('sage.rings.number_field'), Feature('sage.rings.real_double')] """ for feature in [sage__combinat(), sage__graphs(), - sage__graphs__bliss(), - sage__graphs__graph_decompositions__tdlib(), - sage__graphs__mcqd(), - sage__matrix__matrix_gfpn_dense(), sage__plot(), sage__rings__number_field(), sage__rings__real_double(), diff --git a/src/sage/features/tdlib.py b/src/sage/features/tdlib.py new file mode 100644 index 00000000000..e01e1bdfdf6 --- /dev/null +++ b/src/sage/features/tdlib.py @@ -0,0 +1,11 @@ +from . import PythonModule +from .join_feature import JoinFeature + + +class Tdlib(JoinFeature): + + def __init__(self): + # Currently part of sagemath_standard, conditionally built. + # Will be changed to spkg='sagemath_tdlib' later + JoinFeature.__init__(self, 'tdlib', + [PythonModule('sage.graphs.graph_decompositions.tdlib', spkg='tdlib')]) From f4e0d26d4eb193da548044d51badaf349d1860dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 7 Oct 2021 09:45:03 +0200 Subject: [PATCH 309/511] is_linear_interval, in frontend, and another algo in backend --- src/sage/combinat/posets/hasse_diagram.py | 65 ++++++++++++++++------- src/sage/combinat/posets/posets.py | 27 +++++++++- 2 files changed, 71 insertions(+), 21 deletions(-) diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index e8c0d6b92b2..9d0a62a1f5a 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -2359,30 +2359,57 @@ def is_linear_interval(self, t_min, t_max) -> bool: This means that this interval is a total order. - .. WARNING:: - - For speed, this assumes that the input is an interval! - EXAMPLES:: sage: P = posets.PentagonPoset() sage: H = P._hasse_diagram - sage: H.is_linear_interval(0,4) + sage: H.is_linear_interval(0, 4) False - sage: H.is_linear_interval(0,3) + sage: H.is_linear_interval(0, 3) True - """ - t = t_max - while t != t_min: - found = False - for u in self.neighbor_in_iterator(t): - if self.is_lequal(t_min, u): - if not found: - found = True - t = u - else: - return False - return True + sage: H.is_linear_interval(1, 3) + False + sage: H.is_linear_interval(1, 1) + True + + TESTS:: + + sage: P = posets.TamariLattice(3) + sage: H = P._hasse_diagram + sage: D = H._leq_storage + sage: a, b = H.bottom(), H.top() + sage: H.is_linear_interval(a, b) + False + sage: H.is_linear_interval(a, a) + True + """ + if '_leq_storage' in self.__dict__: + if not self.is_lequal(t_min, t_max): # very quick check + return False + t = t_max + while t != t_min: + found = False + for u in self.neighbor_in_iterator(t): + if self.is_lequal(t_min, u): + if not found: + found = True + t = u + else: + return False + return True + + # fall back to default implementation + it = self.all_paths_iterator([t_min], [t_max], + simple=True, trivial=True) + try: + next(it) + except StopIteration: # not comparable + return False + try: + next(it) + except StopIteration: # one path + return True + return False def diamonds(self): r""" @@ -3312,7 +3339,7 @@ def principal_congruences_poset(self): D[ab] = cong P[ab] = cong_ - # Todo: Make a function that creates the poset from a set + # TODO: Make a function that creates the poset from a set # by comparison function with minimal number of comparisons. T = SetPartitions(n) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index f987759cae4..9ca16928e51 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -66,7 +66,6 @@ :meth:`~FinitePoset.height` | Return the number of elements in a longest chain of the poset. :meth:`~FinitePoset.width` | Return the number of elements in a longest antichain of the poset. :meth:`~FinitePoset.relations_number` | Return the number of relations in the poset. - :meth:`~FinitePoset.linear_intervals_count` | Return the enumeration of linear intervals in the poset. :meth:`~FinitePoset.dimension` | Return the dimension of the poset. :meth:`~FinitePoset.jump_number` | Return the jump number of the poset. :meth:`~FinitePoset.magnitude` | Return the magnitude of the poset. @@ -128,7 +127,7 @@ :meth:`~FinitePoset.canonical_label` | Return copy of the poset canonically (re)labelled to integers. :meth:`~FinitePoset.slant_sum` | Return the slant sum poset of two posets. -**Chains & antichains** +**Chains, antichains & linear intervals** .. csv-table:: :class: contentstable @@ -137,6 +136,7 @@ :meth:`~FinitePoset.is_chain_of_poset` | Return ``True`` if elements in the given list are comparable. :meth:`~FinitePoset.is_antichain_of_poset` | Return ``True`` if elements in the given list are incomparable. + :meth:`~FinitePoset.is_linear_interval` | Return whether the given interval is a total order. :meth:`~FinitePoset.chains` | Return the chains of the poset. :meth:`~FinitePoset.antichains` | Return the antichains of the poset. :meth:`~FinitePoset.maximal_chains` | Return the maximal chains of the poset. @@ -146,6 +146,7 @@ :meth:`~FinitePoset.antichains_iterator` | Return an iterator over the antichains of the poset. :meth:`~FinitePoset.random_maximal_chain` | Return a random maximal chain. :meth:`~FinitePoset.random_maximal_antichain` | Return a random maximal antichain. + :meth:`~FinitePoset.linear_intervals_count` | Return the enumeration of linear intervals in the poset. **Drawing** @@ -2659,6 +2660,8 @@ def linear_intervals_count(self) -> list[int]: OUTPUT: list of integers + .. SEEALSO:: :meth:`is_linear_interval` + EXAMPLES:: sage: P = posets.PentagonPoset() @@ -2699,6 +2702,26 @@ def linear_intervals_count(self) -> list[int]: break return poly + def is_linear_interval(self, x, y) -> bool: + """ + Return whether the interval ``[x, y]`` is linear. + + This means that this interval is a total order. + + EXAMPLES:: + + sage: P = posets.PentagonPoset() + sage: P.is_linear_interval(0, 4) + False + sage: P.is_linear_interval(0, 3) + True + sage: P.is_linear_interval(1, 3) + False + """ + a = self._element_to_vertex(x) + b = self._element_to_vertex(y) + return self._hasse_diagram.is_linear_interval(a, b) + def is_incomparable_chain_free(self, m, n=None) -> bool: r""" Return ``True`` if the poset is `(m+n)`-free, and ``False`` otherwise. From bb7b73307961922191a95eb1dda0bb5f8978d355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 7 Oct 2021 12:00:49 +0200 Subject: [PATCH 310/511] remove things form namespace (steenrod base and modular forms dimensions) --- src/sage/algebras/steenrod/all.py | 7 ++-- src/sage/modular/all.py | 11 +++--- src/sage/modular/dims.py | 59 +++++++------------------------ 3 files changed, 23 insertions(+), 54 deletions(-) diff --git a/src/sage/algebras/steenrod/all.py b/src/sage/algebras/steenrod/all.py index 77a93db16ed..134b2b032cf 100644 --- a/src/sage/algebras/steenrod/all.py +++ b/src/sage/algebras/steenrod/all.py @@ -1,7 +1,8 @@ """ The Steenrod algebra """ - from .steenrod_algebra import SteenrodAlgebra, Sq -from .steenrod_algebra_bases import steenrod_algebra_basis - +from sage.misc.lazy_import import lazy_import +lazy_import('sage.algebras.steenrod.steenrod_algebra_bases', + 'steenrod_algebra_basis', + deprecation=(32647, 'removed from namespace')) diff --git a/src/sage/modular/all.py b/src/sage/modular/all.py index 2532c33e107..cfccb18e65f 100644 --- a/src/sage/modular/all.py +++ b/src/sage/modular/all.py @@ -20,11 +20,12 @@ from .cusps import Cusp, Cusps -from .dims import (dimension_cusp_forms, - dimension_new_cusp_forms, - dimension_eis, - dimension_modular_forms, - sturm_bound) +lazy_import('sage.modular.dims', ('dimension_cusp_forms', + 'dimension_new_cusp_forms', + 'dimension_eis', + 'dimension_modular_forms', + 'sturm_bound'), + deprecation=(32647, 'removed from main namespace')) from .etaproducts import (EtaGroup, EtaProduct, EtaGroupElement, AllCusps, CuspFamily) diff --git a/src/sage/modular/dims.py b/src/sage/modular/dims.py index 1bf9aba3773..1050a557330 100644 --- a/src/sage/modular/dims.py +++ b/src/sage/modular/dims.py @@ -265,32 +265,25 @@ def dimension_new_cusp_forms(X, k=2, p=0): EXAMPLES:: + sage: from sage.modular.dims import dimension_new_cusp_forms sage: dimension_new_cusp_forms(100,2) 1 - :: - sage: dimension_new_cusp_forms(Gamma0(100),2) 1 sage: dimension_new_cusp_forms(Gamma0(100),4) 5 - :: - sage: dimension_new_cusp_forms(Gamma1(100),2) 141 sage: dimension_new_cusp_forms(Gamma1(100),4) 463 - :: - sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,2) 2 sage: dimension_new_cusp_forms(DirichletGroup(100).1^2,4) 8 - :: - sage: sum(dimension_new_cusp_forms(e,3) for e in DirichletGroup(30)) 12 sage: dimension_new_cusp_forms(Gamma1(30),3) @@ -315,8 +308,7 @@ def dimension_new_cusp_forms(X, k=2, p=0): return Gamma1(N).dimension_new_cusp_forms(k, eps=X, p=p) elif isinstance(X, (int, Integer)): return Gamma0(X).dimension_new_cusp_forms(k, p=p) - else: - raise TypeError("X (=%s) must be an integer, a Dirichlet character or a congruence subgroup of type Gamma0, Gamma1 or GammaH" % X) + raise TypeError(f"X (={X}) must be an integer, a Dirichlet character or a congruence subgroup of type Gamma0, Gamma1 or GammaH") def dimension_cusp_forms(X, k=2): @@ -333,25 +325,20 @@ def dimension_cusp_forms(X, k=2): EXAMPLES:: + sage: from sage.modular.dims import dimension_cusp_forms sage: dimension_cusp_forms(5,4) 1 - :: - sage: dimension_cusp_forms(Gamma0(11),2) 1 sage: dimension_cusp_forms(Gamma1(13),2) 2 - :: - sage: dimension_cusp_forms(DirichletGroup(13).0^2,2) 1 sage: dimension_cusp_forms(DirichletGroup(13).0,3) 1 - :: - sage: dimension_cusp_forms(Gamma0(11),2) 1 sage: dimension_cusp_forms(Gamma0(11),0) @@ -363,8 +350,6 @@ def dimension_cusp_forms(X, k=2): sage: dimension_cusp_forms(Gamma0(1),4) 0 - :: - sage: dimension_cusp_forms(Gamma0(389),2) 32 sage: dimension_cusp_forms(Gamma0(389),4) @@ -374,8 +359,6 @@ def dimension_cusp_forms(X, k=2): sage: dimension_cusp_forms(Gamma0(11),1) 0 - :: - sage: dimension_cusp_forms(Gamma1(11),2) 1 sage: dimension_cusp_forms(Gamma1(1),12) @@ -385,8 +368,6 @@ def dimension_cusp_forms(X, k=2): sage: dimension_cusp_forms(Gamma1(1),4) 0 - :: - sage: dimension_cusp_forms(Gamma1(389),2) 6112 sage: dimension_cusp_forms(Gamma1(389),4) @@ -394,13 +375,9 @@ def dimension_cusp_forms(X, k=2): sage: dimension_cusp_forms(Gamma1(2005),2) 159201 - :: - sage: dimension_cusp_forms(Gamma1(11),1) 0 - :: - sage: e = DirichletGroup(13).0 sage: e.order() 12 @@ -426,9 +403,8 @@ def dimension_cusp_forms(X, k=2): return X.dimension_cusp_forms(k) elif isinstance(X, (int, Integer)): return Gamma0(X).dimension_cusp_forms(k) - else: - raise TypeError("argument 1 must be a Dirichlet character, an integer " - "or a finite index subgroup of SL2Z") + raise TypeError("argument 1 must be a Dirichlet character, an integer " + "or a finite index subgroup of SL2Z") def dimension_eis(X, k=2): @@ -445,11 +421,10 @@ def dimension_eis(X, k=2): EXAMPLES:: + sage: from sage.modular.dims import dimension_eis sage: dimension_eis(5,4) 2 - :: - sage: dimension_eis(Gamma0(11),2) 1 sage: dimension_eis(Gamma1(13),2) @@ -457,8 +432,6 @@ def dimension_eis(X, k=2): sage: dimension_eis(Gamma1(2006),2) 3711 - :: - sage: e = DirichletGroup(13).0 sage: e.order() 12 @@ -467,8 +440,6 @@ def dimension_eis(X, k=2): sage: dimension_eis(e^2,2) 2 - :: - sage: e = DirichletGroup(13).0 sage: e.order() 12 @@ -479,8 +450,6 @@ def dimension_eis(X, k=2): sage: dimension_eis(e,13) 2 - :: - sage: G = DirichletGroup(20) sage: dimension_eis(G.0,3) 4 @@ -489,8 +458,6 @@ def dimension_eis(X, k=2): sage: dimension_eis(G.1^2,2) 6 - :: - sage: G = DirichletGroup(200) sage: e = prod(G.gens(), G(1)) sage: e.conductor() @@ -498,8 +465,7 @@ def dimension_eis(X, k=2): sage: dimension_eis(e,2) 4 - :: - + sage: from sage.modular.dims import dimension_modular_forms sage: dimension_modular_forms(Gamma1(4), 11) 6 """ @@ -509,8 +475,7 @@ def dimension_eis(X, k=2): return Gamma1(X.modulus()).dimension_eis(k, X) elif isinstance(X, (int, Integer)): return Gamma0(X).dimension_eis(k) - else: - raise TypeError("argument in dimension_eis must be an integer, a Dirichlet character, or a finite index subgroup of SL2Z (got %s)" % X) + raise TypeError(f"argument in dimension_eis must be an integer, a Dirichlet character, or a finite index subgroup of SL2Z (got {X})") def dimension_modular_forms(X, k=2): @@ -527,6 +492,7 @@ def dimension_modular_forms(X, k=2): EXAMPLES:: + sage: from sage.modular.dims import dimension_modular_forms sage: dimension_modular_forms(Gamma0(11),2) 2 sage: dimension_modular_forms(Gamma0(11),0) @@ -542,8 +508,10 @@ def dimension_modular_forms(X, k=2): sage: e = DirichletGroup(20).1 sage: dimension_modular_forms(e,3) 9 + sage: from sage.modular.dims import dimension_cusp_forms sage: dimension_cusp_forms(e,3) 3 + sage: from sage.modular.dims import dimension_eis sage: dimension_eis(e,3) 6 sage: dimension_modular_forms(11,2) @@ -576,6 +544,7 @@ def sturm_bound(level, weight=2): EXAMPLES:: + sage: from sage.modular.dims import sturm_bound sage: sturm_bound(11,2) 2 sage: sturm_bound(389,2) @@ -592,8 +561,6 @@ def sturm_bound(level, weight=2): if is_ArithmeticSubgroup(level): if level.is_congruence(): return level.sturm_bound(weight) - else: - raise ValueError("no Sturm bound defined for noncongruence " - "subgroups") + raise ValueError("no Sturm bound defined for noncongruence subgroups") if isinstance(level, (int, Integer)): return Gamma0(level).sturm_bound(weight) From 8c91c6be45c0375d5a7d7a9a6aacd427909b3bc6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 11:13:34 -0700 Subject: [PATCH 311/511] build/pkgs/sqlite/spkg-install.in: Just make sure that autotools-generated files are newer than sources --- build/pkgs/sqlite/spkg-install.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/sqlite/spkg-install.in b/build/pkgs/sqlite/spkg-install.in index d071ddebe17..d13df2ba1b8 100644 --- a/build/pkgs/sqlite/spkg-install.in +++ b/build/pkgs/sqlite/spkg-install.in @@ -5,7 +5,7 @@ cd src export CPPFLAGS="$CPPFLAGS -I$SAGE_LOCAL/include" # Trac #32646: configure script does not have --disable-maintainer-mode -rm -f configure.ac */configure.ac Makefile.am +touch configure */configure Makefile.in sdh_configure sdh_make From 1c6335a1f994cd18055f27bfc8bf70b771231202 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 12:02:02 -0700 Subject: [PATCH 312/511] sage.doctest.external.has_internet: Refactor through new Feature --- src/sage/doctest/external.py | 12 +++------ src/sage/features/internet.py | 47 +++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 src/sage/features/internet.py diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index 77f9c333977..6c8763cb917 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -53,15 +53,11 @@ def has_internet(): EXAMPLES:: sage: from sage.doctest.external import has_internet - sage: has_internet() # random, optional -- internet - True + sage: has_internet() # random, optional -- internet + FeatureTestResult('internet', True) """ - req = Request("https://www.sagemath.org",headers={"User-Agent":"sage-doctest"}) - try: - urlopen(req, timeout=1, context=SSLContext()) - return True - except urllib.error.URLError: - return False + from sage.features.internet import Internet + return Internet().is_present() def has_latex(): """ diff --git a/src/sage/features/internet.py b/src/sage/features/internet.py new file mode 100644 index 00000000000..19cd6689253 --- /dev/null +++ b/src/sage/features/internet.py @@ -0,0 +1,47 @@ +from . import Feature, FeatureTestResult + + +class Internet(Feature): + r""" + A feature describing if Internet is available. + + Failure of connecting to the site "https://www.sagemath.org" within a second + is regarded as internet being not available. + + EXAMPLES:: + + sage: from sage.features.internet import Internet + sage: Internet() + Feature('internet') + """ + + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.internet import Internet + sage: Internet() is Internet() + True + """ + Feature.__init__(self, 'internet') + + def _is_present(self): + r""" + Test whether Internet is available. + + EXAMPLES:: + + sage: from sage.features.internet import Internet + sage: Internet().is_present() # random, optional -- internet + FeatureTestResult('internet', True) + """ + import urllib.error + from urllib.request import Request, urlopen + from ssl import SSLContext + + req = Request("https://www.sagemath.org", headers={"User-Agent": "sage-doctest"}) + try: + urlopen(req, timeout=1, context=SSLContext()) + return FeatureTestResult(self, True) + except urllib.error.URLError: + return FeatureTestResult(self, False) From b7f79036bafd3b2321064342c05ffc711946f640 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 12:41:37 -0700 Subject: [PATCH 313/511] sage.features.graphviz: Make .name lowercase to match optional tag; refactor through JoinFeature --- src/sage/doctest/external.py | 2 +- src/sage/features/graphviz.py | 28 +++++++--------------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index a0a8565b24b..4b82fa0e6e1 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -255,7 +255,7 @@ def has_graphviz(): sage: from sage.doctest.external import has_graphviz sage: has_graphviz() # optional -- graphviz - FeatureTestResult('Graphviz', True) + FeatureTestResult('graphviz', True) """ from sage.features.graphviz import Graphviz return Graphviz().is_present() diff --git a/src/sage/features/graphviz.py b/src/sage/features/graphviz.py index d3c24d7e804..ac6445c44e4 100644 --- a/src/sage/features/graphviz.py +++ b/src/sage/features/graphviz.py @@ -12,6 +12,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from . import Feature, Executable, FeatureTestResult +from .join_feature import JoinFeature class dot(Executable): @@ -86,7 +87,7 @@ def __init__(self): url="https://www.graphviz.org/") -class Graphviz(Feature): +class Graphviz(JoinFeature): r""" A :class:`sage.features.Feature` describing the presence of ``dot``, ``neato`` and ``twopi``. @@ -95,7 +96,7 @@ class Graphviz(Feature): sage: from sage.features.graphviz import Graphviz sage: Graphviz().is_present() # optional: graphviz - FeatureTestResult('Graphviz', True) + FeatureTestResult('graphviz', True) """ def __init__(self): r""" @@ -105,22 +106,7 @@ def __init__(self): sage: isinstance(Graphviz(), Graphviz) True """ - Feature.__init__(self, "Graphviz", - spkg="graphviz", - url="https://www.graphviz.org/") - - def _is_present(self): - r""" - EXAMPLES:: - - sage: from sage.features.graphviz import Graphviz - sage: Graphviz()._is_present() # optional: graphviz - FeatureTestResult('Graphviz', True) - """ - test = (dot()._is_present() and - neato()._is_present() and - twopi()._is_present()) - if not test: - return test - else: - return FeatureTestResult(self, True) + JoinFeature.__init__(self, "graphviz", + [dot(), neato(), twopi()], + spkg="graphviz", + url="https://www.graphviz.org/") From 2c95e702974afd2538e77ab870f77be8139e4279 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 12:42:28 -0700 Subject: [PATCH 314/511] sage.features.pandoc: Make .name lowercase to match optional tag --- src/sage/doctest/external.py | 2 +- src/sage/features/pandoc.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index 4b82fa0e6e1..c23ace9690c 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -191,7 +191,7 @@ def has_pandoc(): sage: from sage.doctest.external import has_pandoc sage: has_pandoc() # optional -- pandoc - FeatureTestResult('Pandoc', True) + FeatureTestResult('pandoc', True) """ from sage.features.pandoc import Pandoc return Pandoc().is_present() diff --git a/src/sage/features/pandoc.py b/src/sage/features/pandoc.py index e9a22e65aa7..566032a643b 100644 --- a/src/sage/features/pandoc.py +++ b/src/sage/features/pandoc.py @@ -23,7 +23,7 @@ class Pandoc(Executable): sage: from sage.features.pandoc import Pandoc sage: Pandoc().is_present() # optional: pandoc - FeatureTestResult('Pandoc', True) + FeatureTestResult('pandoc', True) """ def __init__(self): r""" @@ -33,5 +33,5 @@ def __init__(self): sage: isinstance(Pandoc(), Pandoc) True """ - Executable.__init__(self, "Pandoc", executable="pandoc", + Executable.__init__(self, "pandoc", executable="pandoc", url="https://pandoc.org/") From 214fa899b8ced64604dc8eeca1e99ccfbe0404f5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 12:43:40 -0700 Subject: [PATCH 315/511] sage.features.ffmpeg: Make .name lowercase to match optional tag --- src/sage/doctest/external.py | 2 +- src/sage/features/ffmpeg.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index c23ace9690c..57778375a34 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -268,7 +268,7 @@ def has_ffmpeg(): sage: from sage.doctest.external import has_ffmpeg sage: has_ffmpeg() # optional -- ffmpeg - FeatureTestResult('FFmpeg', True) + FeatureTestResult('ffmpeg', True) """ from sage.features.ffmpeg import FFmpeg return FFmpeg().is_present() diff --git a/src/sage/features/ffmpeg.py b/src/sage/features/ffmpeg.py index 1f508577e1d..68245d24c27 100644 --- a/src/sage/features/ffmpeg.py +++ b/src/sage/features/ffmpeg.py @@ -23,7 +23,7 @@ class FFmpeg(Executable): sage: from sage.features.ffmpeg import FFmpeg sage: FFmpeg().is_present() # optional: ffmpeg - FeatureTestResult('FFmpeg', True) + FeatureTestResult('ffmpeg', True) """ def __init__(self): r""" @@ -33,5 +33,5 @@ def __init__(self): sage: isinstance(FFmpeg(), FFmpeg) True """ - Executable.__init__(self, "FFmpeg", executable="ffmpeg", + Executable.__init__(self, "ffmpeg", executable="ffmpeg", url="https://www.ffmpeg.org/") From eb8f63724d78bd03a79fb471db6835a1c8570a09 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 12:44:31 -0700 Subject: [PATCH 316/511] sage.features.imagemagick: Make .name 'imagemagick' to match optional tag via JoinFeature --- src/sage/doctest/external.py | 2 +- src/sage/features/imagemagick.py | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index 57778375a34..bfc393b5451 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -281,7 +281,7 @@ def has_imagemagick(): sage: from sage.doctest.external import has_imagemagick sage: has_imagemagick() # optional -- imagemagick - FeatureTestResult('convert', True) + FeatureTestResult('imagemagick', True) """ from sage.features.imagemagick import ImageMagick return ImageMagick().is_present() diff --git a/src/sage/features/imagemagick.py b/src/sage/features/imagemagick.py index 42213f95197..7ea27ea40de 100644 --- a/src/sage/features/imagemagick.py +++ b/src/sage/features/imagemagick.py @@ -18,9 +18,10 @@ # **************************************************************************** from . import Executable +from .join_feature import JoinFeature -class ImageMagick(Executable): +class ImageMagick(JoinFeature): r""" A :class:`sage.features.Feature` describing the presence of ``ImageMagick`` @@ -31,7 +32,7 @@ class ImageMagick(Executable): sage: from sage.features.imagemagick import ImageMagick sage: ImageMagick().is_present() # optional: imagemagick - FeatureTestResult('convert', True) + FeatureTestResult('imagemagick', True) """ def __init__(self): r""" @@ -41,5 +42,7 @@ def __init__(self): sage: isinstance(ImageMagick(), ImageMagick) True """ - Executable.__init__(self, "convert", executable="convert", - url="https://www.imagemagick.org/") + JoinFeature.__init__(self, "imagemagick", + [Executable("convert", executable="convert")], + spkg="_recommended", + url="https://www.imagemagick.org/") From 0c012f75acc3d3ff3536afb6ba8f2f4b552254d0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 12:47:05 -0700 Subject: [PATCH 317/511] sage.features.rubiks: Make .name lowercase to match optional tag; refactor through JoinFeature --- src/sage/doctest/external.py | 2 +- src/sage/features/rubiks.py | 30 +++++++----------------------- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index bfc393b5451..8684fc046a2 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -295,7 +295,7 @@ def has_rubiks(): sage: from sage.doctest.external import has_rubiks sage: has_rubiks() # optional -- rubiks - FeatureTestResult('Rubiks', True) + FeatureTestResult('rubiks', True) """ from sage.features.rubiks import Rubiks return Rubiks().is_present() diff --git a/src/sage/features/rubiks.py b/src/sage/features/rubiks.py index 5364719f159..84cca71ee61 100644 --- a/src/sage/features/rubiks.py +++ b/src/sage/features/rubiks.py @@ -10,6 +10,8 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from . import Feature, Executable, FeatureTestResult +from .join_feature import JoinFeature + class cu2(Executable): r""" @@ -149,7 +151,7 @@ def __init__(self): spkg="rubiks") -class Rubiks(Feature): +class Rubiks(JoinFeature): r""" A :class:`sage.features.Feature` describing the presence of ``cu2``, ``cubex``, ``dikcube``, ``mcube``, ``optimal``, and @@ -159,7 +161,7 @@ class Rubiks(Feature): sage: from sage.features.rubiks import Rubiks sage: Rubiks().is_present() # optional: rubiks - FeatureTestResult('Rubiks', True) + FeatureTestResult('rubiks', True) """ def __init__(self): r""" @@ -169,24 +171,6 @@ def __init__(self): sage: isinstance(Rubiks(), Rubiks) True """ - Feature.__init__(self, "Rubiks", - spkg="rubiks") - - def _is_present(self): - r""" - EXAMPLES:: - - sage: from sage.features.rubiks import Rubiks - sage: Rubiks()._is_present() # optional: rubiks - FeatureTestResult('Rubiks', True) - """ - test = (cu2()._is_present() and - size222()._is_present() and - optimal()._is_present() and - mcube()._is_present() and - dikcube()._is_present() and - cubex()._is_present()) - if not test: - return test - else: - return FeatureTestResult(self, True) + JoinFeature.__init__(self, "rubiks", + [cu2(), size222(), optimal(), mcube(), dikcube(), cubex()] + spkg="rubiks") From 0321b5e888b7d09bb0ef79ff108c9eca54cdd85b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 12:55:28 -0700 Subject: [PATCH 318/511] src/sage/features/rubiks.py: Fixup --- src/sage/features/rubiks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/features/rubiks.py b/src/sage/features/rubiks.py index 84cca71ee61..19c478888f5 100644 --- a/src/sage/features/rubiks.py +++ b/src/sage/features/rubiks.py @@ -172,5 +172,5 @@ def __init__(self): True """ JoinFeature.__init__(self, "rubiks", - [cu2(), size222(), optimal(), mcube(), dikcube(), cubex()] + [cu2(), size222(), optimal(), mcube(), dikcube(), cubex()], spkg="rubiks") From 1bba4867e81a7dbb5a0b6f43abf55cfdf37f6e3c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 15:11:33 -0700 Subject: [PATCH 319/511] src/sage/features: Change remaining features to make .name equal to the optional tag --- src/sage/features/__init__.py | 4 ++-- src/sage/features/csdp.py | 6 +++--- src/sage/features/databases.py | 12 ++++++------ src/sage/features/fes.py | 10 +++++++--- src/sage/features/graph_generators.py | 12 ++++++------ src/sage/features/kenzo.py | 6 +++--- src/sage/features/latte.py | 4 ++-- 7 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 42058cf07dc..623226fc97d 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -799,8 +799,8 @@ def __init__(self, name, **kwds): TESTS:: sage: from sage.features import PythonModule - sage: from sage.features.fes import LibFES - sage: isinstance(LibFES(), PythonModule) # indirect doctest + sage: from sage.features.databases import DatabaseKnotInfo + sage: isinstance(DatabaseKnotInfo(), PythonModule) # indirect doctest True """ Feature.__init__(self, name, **kwds) diff --git a/src/sage/features/csdp.py b/src/sage/features/csdp.py index e1d668451ea..1d739f684eb 100644 --- a/src/sage/features/csdp.py +++ b/src/sage/features/csdp.py @@ -20,7 +20,7 @@ class CSDP(Executable): sage: from sage.features.csdp import CSDP sage: CSDP().is_present() # optional: csdp - FeatureTestResult('CSDP', True) + FeatureTestResult('csdp', True) """ def __init__(self): r""" @@ -30,7 +30,7 @@ def __init__(self): sage: isinstance(CSDP(), CSDP) True """ - Executable.__init__(self, name="CSDP", spkg="csdp", executable="theta", + Executable.__init__(self, name="csdp", spkg="csdp", executable="theta", url="https://github.com/dimpase/csdp") def is_functional(self): @@ -41,7 +41,7 @@ def is_functional(self): sage: from sage.features.csdp import CSDP sage: CSDP().is_functional() # optional: csdp - FeatureTestResult('CSDP', True) + FeatureTestResult('csdp', True) """ from sage.misc.temporary_file import tmp_filename tf_name = tmp_filename() diff --git a/src/sage/features/databases.py b/src/sage/features/databases.py index 778a70fe796..8e9b4b1a5c0 100644 --- a/src/sage/features/databases.py +++ b/src/sage/features/databases.py @@ -19,7 +19,7 @@ class DatabaseConwayPolynomials(StaticFile): sage: from sage.features.databases import DatabaseConwayPolynomials sage: DatabaseConwayPolynomials().is_present() - FeatureTestResult("Frank Luebeck's database of Conway polynomials", True) + FeatureTestResult('conway_polynomials', True) """ def __init__(self): @@ -34,7 +34,7 @@ def __init__(self): search_path = [CONWAY_POLYNOMIALS_DATA_DIR] else: search_path = [] - StaticFile.__init__(self, "Frank Luebeck's database of Conway polynomials", + StaticFile.__init__(self, "conway_polynomials", filename='conway_polynomials.p', search_path=search_path, spkg='conway_polynomials') @@ -57,9 +57,9 @@ class DatabaseCremona(StaticFile): sage: from sage.features.databases import DatabaseCremona sage: DatabaseCremona('cremona_mini').is_present() - FeatureTestResult("Cremona's database of elliptic curves", True) + FeatureTestResult('database_cremona_mini_ellcurve', True) sage: DatabaseCremona().is_present() # optional: database_cremona_ellcurve - FeatureTestResult("Cremona's database of elliptic curves", True) + FeatureTestResult("database_cremona_ellcurve", True) """ def __init__(self, name="cremona", spkg="database_cremona_ellcurve"): r""" @@ -69,7 +69,7 @@ def __init__(self, name="cremona", spkg="database_cremona_ellcurve"): sage: isinstance(DatabaseCremona(), DatabaseCremona) True """ - StaticFile.__init__(self, "Cremona's database of elliptic curves", + StaticFile.__init__(self, f"database_{name}_ellcurve", filename='{}.db'.format(name.replace(' ', '_')), search_path=CREMONA_DATA_DIRS, spkg=spkg, @@ -94,7 +94,7 @@ def __init__(self): sage: isinstance(DatabaseJones(), DatabaseJones) True """ - StaticFile.__init__(self, "John Jones's tables of number fields", + StaticFile.__init__(self, "database_jones_numfield", filename='jones/jones.sobj', spkg="database_jones_numfield") diff --git a/src/sage/features/fes.py b/src/sage/features/fes.py index 9575df8cfaf..69fee67be9b 100644 --- a/src/sage/features/fes.py +++ b/src/sage/features/fes.py @@ -4,6 +4,8 @@ """ from . import CythonFeature, PythonModule +from .join_feature import JoinFeature + TEST_CODE = """ # distutils: libraries=fes @@ -70,7 +72,7 @@ def __init__(self): url="http://www.lifl.fr/~bouillag/fes/") -class LibFES(PythonModule): +class LibFES(JoinFeature): r""" A :class:`Feature` which describes whether the :mod:`sage.libs.fes` module has been enabled for this build of Sage and is functional. @@ -88,5 +90,7 @@ def __init__(self): sage: isinstance(LibFES(), LibFES) True """ - PythonModule.__init__(self, "sage.libs.fes", spkg="fes", - url="http://www.lifl.fr/~bouillag/fes/") + JoinFeature.__init__(self, 'fes', + [PythonModule("sage.libs.fes")], + spkg="fes", + url="http://www.lifl.fr/~bouillag/fes/") diff --git a/src/sage/features/graph_generators.py b/src/sage/features/graph_generators.py index 7fd6cacb85b..a47dca0e5d5 100644 --- a/src/sage/features/graph_generators.py +++ b/src/sage/features/graph_generators.py @@ -66,7 +66,7 @@ class Buckygen(Executable): sage: from sage.features.graph_generators import Buckygen sage: Buckygen().is_present() # optional: buckygen - FeatureTestResult('Buckygen', True) + FeatureTestResult('buckygen', True) """ def __init__(self): r""" @@ -76,7 +76,7 @@ def __init__(self): sage: isinstance(Buckygen(), Buckygen) True """ - Executable.__init__(self, name="Buckygen", spkg="buckygen", + Executable.__init__(self, name="buckygen", spkg="buckygen", executable="buckygen", url="http://caagt.ugent.be/buckygen/") @@ -88,7 +88,7 @@ def is_functional(self): sage: from sage.features.graph_generators import Buckygen sage: Buckygen().is_functional() # optional: buckygen - FeatureTestResult('Buckygen', True) + FeatureTestResult('buckygen', True) """ command = ["buckygen", "-d", "22d"] try: @@ -114,7 +114,7 @@ class Benzene(Executable): sage: from sage.features.graph_generators import Benzene sage: Benzene().is_present() # optional: benzene - FeatureTestResult('Benzene', True) + FeatureTestResult('benzene', True) """ def __init__(self): r""" @@ -124,7 +124,7 @@ def __init__(self): sage: isinstance(Benzene(), Benzene) True """ - Executable.__init__(self, name="Benzene", spkg="benzene", + Executable.__init__(self, name="benzene", spkg="benzene", executable="benzene", url="http://www.grinvin.org/") @@ -136,7 +136,7 @@ def is_functional(self): sage: from sage.features.graph_generators import Benzene sage: Benzene().is_functional() # optional: benzene - FeatureTestResult('Benzene', True) + FeatureTestResult('benzene', True) """ devnull = open(os.devnull, 'wb') command = ["benzene", "2", "p"] diff --git a/src/sage/features/kenzo.py b/src/sage/features/kenzo.py index b6c068eac83..7012dc230ec 100644 --- a/src/sage/features/kenzo.py +++ b/src/sage/features/kenzo.py @@ -14,7 +14,7 @@ class Kenzo(Feature): sage: from sage.features.kenzo import Kenzo sage: Kenzo().is_present() # optional - kenzo - FeatureTestResult('Kenzo', True) + FeatureTestResult('kenzo', True) """ def __init__(self): r""" @@ -24,7 +24,7 @@ def __init__(self): sage: isinstance(Kenzo(), Kenzo) True """ - Feature.__init__(self, name="Kenzo", spkg="kenzo", + Feature.__init__(self, name="kenzo", spkg="kenzo", url="https://github.com/miguelmarco/kenzo/") def _is_present(self): @@ -35,7 +35,7 @@ def _is_present(self): sage: from sage.features.kenzo import Kenzo sage: Kenzo()._is_present() # optional - kenzo - FeatureTestResult('Kenzo', True) + FeatureTestResult('kenzo', True) """ # Redirection of ECL and Maxima stdout to /dev/null # This is also done in the Maxima library, but we diff --git a/src/sage/features/latte.py b/src/sage/features/latte.py index 6abc450281c..1beb43f179a 100644 --- a/src/sage/features/latte.py +++ b/src/sage/features/latte.py @@ -38,7 +38,7 @@ class Latte(JoinFeature): sage: from sage.features.latte import Latte sage: Latte().is_present() # optional - latte_int - FeatureTestResult('LattE', True) + FeatureTestResult('latte_int', True) """ def __init__(self): r""" @@ -48,5 +48,5 @@ def __init__(self): sage: isinstance(Latte(), Latte) True """ - JoinFeature.__init__(self, "LattE", + JoinFeature.__init__(self, "latte_int", (Latte_count(), Latte_integrate())) From d7bd9c40ac4b0729a2c11f83de6ec25a10cfb537 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 15:21:04 -0700 Subject: [PATCH 320/511] src/sage/features/gap.py: Set .name of a GapPackage feature as gap_package_PACKAGE --- src/sage/features/__init__.py | 20 ++++++++++---------- src/sage/features/gap.py | 7 +++---- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 623226fc97d..b6742ecef67 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -28,7 +28,7 @@ sage: from sage.features.gap import GapPackage sage: GapPackage("grape", spkg="gap_packages").is_present() # optional: gap_packages - FeatureTestResult('GAP package grape', True) + FeatureTestResult('gap_package_grape', True) Note that a :class:`FeatureTestResult` acts like a bool in most contexts:: @@ -99,7 +99,7 @@ class Feature(TrivialUniqueRepresentation): sage: from sage.features.gap import GapPackage sage: GapPackage("grape", spkg="gap_packages") # indirect doctest - Feature('GAP package grape') + Feature('gap_package_grape') For efficiency, features are unique:: @@ -134,9 +134,9 @@ def is_present(self): sage: from sage.features.gap import GapPackage sage: GapPackage("grape", spkg="gap_packages").is_present() # optional: gap_packages - FeatureTestResult('GAP package grape', True) + FeatureTestResult('gap_package_grape', True) sage: GapPackage("NOT_A_PACKAGE", spkg="gap_packages").is_present() - FeatureTestResult('GAP package NOT_A_PACKAGE', False) + FeatureTestResult('gap_package_NOT_A_PACKAGE', False) The result is cached:: @@ -184,7 +184,7 @@ def require(self): sage: GapPackage("ve1EeThu").require() Traceback (most recent call last): ... - FeatureNotPresentError: GAP package ve1EeThu is not available. + FeatureNotPresentError: gap_package_ve1EeThu is not available. `TestPackageAvailability("ve1EeThu")` evaluated to `fail` in GAP. """ presence = self.is_present() @@ -199,7 +199,7 @@ def __repr__(self): sage: from sage.features.gap import GapPackage sage: GapPackage("grape") # indirect doctest - Feature('GAP package grape') + Feature('gap_package_grape') """ return 'Feature({name!r})'.format(name=self.name) @@ -264,7 +264,7 @@ def __str__(self): sage: GapPackage("gapZuHoh8Uu").require() # indirect doctest Traceback (most recent call last): ... - FeatureNotPresentError: GAP package gapZuHoh8Uu is not available. + FeatureNotPresentError: gap_package_gapZuHoh8Uu is not available. `TestPackageAvailability("gapZuHoh8Uu")` evaluated to `fail` in GAP. """ lines = ["{feature} is not available.".format(feature=self.feature.name)] @@ -286,7 +286,7 @@ class FeatureTestResult(object): sage: from sage.features.gap import GapPackage sage: presence = GapPackage("NOT_A_PACKAGE").is_present(); presence # indirect doctest - FeatureTestResult('GAP package NOT_A_PACKAGE', False) + FeatureTestResult('gap_package_NOT_A_PACKAGE', False) sage: bool(presence) False @@ -305,9 +305,9 @@ class FeatureTestResult(object): sage: from sage.features import FeatureTestResult sage: package = GapPackage("NOT_A_PACKAGE", spkg="no_package") sage: str(FeatureTestResult(package, True).resolution) # optional - sage_spkg - '...To install GAP package NOT_A_PACKAGE...you can try to run...sage -i no_package...' + '...To install gap_package_NOT_A_PACKAGE...you can try to run...sage -i no_package...' sage: str(FeatureTestResult(package, False).resolution) # optional - sage_spkg - '...To install GAP package NOT_A_PACKAGE...you can try to run...sage -i no_package...' + '...To install gap_package_NOT_A_PACKAGE...you can try to run...sage -i no_package...' sage: FeatureTestResult(package, False, resolution="rtm").resolution 'rtm' """ diff --git a/src/sage/features/gap.py b/src/sage/features/gap.py index 25f6e52a1fd..24b62689459 100644 --- a/src/sage/features/gap.py +++ b/src/sage/features/gap.py @@ -14,7 +14,7 @@ class GapPackage(Feature): sage: from sage.features.gap import GapPackage sage: GapPackage("grape", spkg="gap_packages") - Feature('GAP package grape') + Feature('gap_package_grape') """ def __init__(self, package, **kwds): r""" @@ -24,8 +24,7 @@ def __init__(self, package, **kwds): sage: isinstance(GapPackage("grape", spkg="gap_packages"), GapPackage) True """ - Feature.__init__(self, "GAP package {package}".format(package=package), - **kwds) + Feature.__init__(self, f"gap_package_{package}", **kwds) self.package = package def _is_present(self): @@ -38,7 +37,7 @@ def _is_present(self): sage: from sage.features.gap import GapPackage sage: GapPackage("grape", spkg="gap_packages").is_present() # optional: gap_packages - FeatureTestResult('GAP package grape', True) + FeatureTestResult('gap_package_grape', True) """ from sage.libs.gap.libgap import libgap command = 'TestPackageAvailability("{package}")'.format(package=self.package) From 9ee32434dd5715650445123125065e9cc820c1e1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 15:26:27 -0700 Subject: [PATCH 321/511] Feature: Add documentation --- src/sage/features/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index b6742ecef67..feb9c9ea1ee 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -93,6 +93,16 @@ class Feature(TrivialUniqueRepresentation): r""" A feature of the runtime environment + INPUT: + + - ``name`` -- (string) name of the feature; this should be suitable as an optional tag + for the Sage doctester, i.e., lowercase alphanumeric with underscores (``_``) allowed; + features that correspond to Python modules/packages may use periods (``.``) + + - ``spkg`` -- (string) name of the SPKG providing the feature + + - ``url`` -- a URL for the upstream package providing the feature + Overwrite :meth:`_is_present` to add feature checks. EXAMPLES:: From 50248edb702144f171b5df3a2217bb7eb7083e88 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 16:13:20 -0700 Subject: [PATCH 322/511] sage.doctest.external.has_{cplex,gurobi}: Refactor through new Features --- src/sage/databases/cremona.py | 4 ++-- src/sage/doctest/external.py | 20 +++++----------- src/sage/features/mip_backends.py | 38 +++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 16 deletions(-) create mode 100644 src/sage/features/mip_backends.py diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index e388d0558b0..345867606a3 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -1699,13 +1699,13 @@ def CremonaDatabase(name=None,mini=None,set_global=None): sage: c = CremonaDatabase('should not exist',mini=True) Traceback (most recent call last): ... - FeatureNotPresentError: Cremona's database of elliptic curves is not available. + FeatureNotPresentError: database_should_not_exist_ellcurve is not available. '...db' not found in any of [...] ...Further installation instructions might be available at https://github.com/JohnCremona/ecdata. sage: c = CremonaDatabase('should not exist',mini=False) Traceback (most recent call last): ... - FeatureNotPresentError: Cremona's database of elliptic curves is not available. + FeatureNotPresentError: database_should_not_exist_ellcurve is not available. '...db' not found in any of [...] ...Further installation instructions might be available at https://github.com/JohnCremona/ecdata. """ diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index 8684fc046a2..e4ef6fb55b5 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -221,14 +221,10 @@ def has_cplex(): sage: from sage.doctest.external import has_cplex sage: has_cplex() # random, optional - CPLEX - True + FeatureTestResult('cplex', True) """ - from sage.numerical.mip import MixedIntegerLinearProgram - try: - MixedIntegerLinearProgram(solver='cplex') - return True - except Exception: - return False + from sage.features.mip_backends import CPLEX + return CPLEX().is_present() def has_gurobi(): """ @@ -238,14 +234,10 @@ def has_gurobi(): sage: from sage.doctest.external import has_gurobi sage: has_gurobi() # random, optional - Gurobi - True + FeatureTestResult('gurobi', True) """ - from sage.numerical.mip import MixedIntegerLinearProgram - try: - MixedIntegerLinearProgram(solver='gurobi') - return True - except Exception: - return False + from sage.features.mip_backends import Gurobi + return Gurobi().is_present() def has_graphviz(): """ diff --git a/src/sage/features/mip_backends.py b/src/sage/features/mip_backends.py new file mode 100644 index 00000000000..e6e89e0acfb --- /dev/null +++ b/src/sage/features/mip_backends.py @@ -0,0 +1,38 @@ +from . import Feature +from join_feature import JoinFeature + + +class MIPBackend(Feature): + r""" + A feature describing whether a :class:`MixedIntegerLinearProgram` backend is available. + """ + + def _is_present(self): + try: + from sage.numerical.mip import MixedIntegerLinearProgram + MixedIntegerLinearProgram(solver=self.name) + return FeatureTestResult(self, True) + except Exception: + return FeatureTestResult(self, False) + + +class CPLEX(MIPBackend): + + def __init__(self): + MIPBackend.__init__('cplex', + spkg='sage_numerical_backends_cplex') + + +class Gurobi(MIPBackend): + + def __init__(self): + MIPBackend.__init__('gurobi', + spkg='sage_numerical_backends_gurobi') + + +class COIN(JoinFeature): + + def __init__(self): + JoinFeature.__init__('sage_numerical_backends_coin', + [MIPBackend('coin')], + spkg='sage_numerical_backends_coin') From 6457ee93e17d32327bb03394e4da3993165f3043 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Oct 2021 18:55:16 -0700 Subject: [PATCH 323/511] src/sage/features/mip_backends.py: Fixup --- src/sage/features/mip_backends.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/features/mip_backends.py b/src/sage/features/mip_backends.py index e6e89e0acfb..a72c054a857 100644 --- a/src/sage/features/mip_backends.py +++ b/src/sage/features/mip_backends.py @@ -1,5 +1,5 @@ -from . import Feature -from join_feature import JoinFeature +from . import Feature, FeatureTestResult +from .join_feature import JoinFeature class MIPBackend(Feature): @@ -19,20 +19,20 @@ def _is_present(self): class CPLEX(MIPBackend): def __init__(self): - MIPBackend.__init__('cplex', + MIPBackend.__init__(self, 'cplex', spkg='sage_numerical_backends_cplex') class Gurobi(MIPBackend): def __init__(self): - MIPBackend.__init__('gurobi', + MIPBackend.__init__(self, 'gurobi', spkg='sage_numerical_backends_gurobi') class COIN(JoinFeature): def __init__(self): - JoinFeature.__init__('sage_numerical_backends_coin', + JoinFeature.__init__(self, 'sage_numerical_backends_coin', [MIPBackend('coin')], spkg='sage_numerical_backends_coin') From c0e73d8531b99e65379a6b9e79e096b380204bbf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Oct 2021 18:38:09 -0700 Subject: [PATCH 324/511] src/sage/geometry/polyhedron/double_description.py: Add # optional - sage.rings.number_field --- .../geometry/polyhedron/double_description.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/sage/geometry/polyhedron/double_description.py b/src/sage/geometry/polyhedron/double_description.py index d8d85adde6e..06d729e12aa 100644 --- a/src/sage/geometry/polyhedron/double_description.py +++ b/src/sage/geometry/polyhedron/double_description.py @@ -28,10 +28,10 @@ `\RR`, for example:: sage: from sage.geometry.polyhedron.double_description import StandardAlgorithm - sage: A = matrix(AA, [(1,0,1), (0,1,1), (-AA(2).sqrt(),-AA(3).sqrt(),1), + sage: A = matrix(AA, [(1,0,1), (0,1,1), (-AA(2).sqrt(),-AA(3).sqrt(),1), # optional - sage.rings.number_field ....: (-AA(3).sqrt(),-AA(2).sqrt(),1)]) - sage: alg = StandardAlgorithm(A) - sage: alg.run().R + sage: alg = StandardAlgorithm(A) # optional - sage.rings.number_field + sage: alg.run().R # optional - sage.rings.number_field [(-0.4177376677004119?, 0.5822623322995881?, 0.4177376677004119?), (-0.2411809548974793?, -0.2411809548974793?, 0.2411809548974793?), (0.07665629029830300?, 0.07665629029830300?, 0.2411809548974793?), @@ -411,11 +411,12 @@ def matrix_space(self, nrows, ncols): sage: DD.matrix_space(3,2) Full MatrixSpace of 3 by 2 dense matrices over Rational Field - sage: K. = QuadraticField(2) - sage: A = matrix([[1,sqrt2],[2,0]]) - sage: DD, _ = Problem(A).initial_pair() - sage: DD.matrix_space(1,2) - Full MatrixSpace of 1 by 2 dense matrices over Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? + sage: K. = QuadraticField(2) # optional - sage.rings.number_field + sage: A = matrix([[1,sqrt2],[2,0]]) # optional - sage.rings.number_field + sage: DD, _ = Problem(A).initial_pair() # optional - sage.rings.number_field + sage: DD.matrix_space(1,2) # optional - sage.rings.number_field + Full MatrixSpace of 1 by 2 dense matrices + over Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? """ return MatrixSpace(self.problem.base_ring(), nrows, ncols) @@ -596,9 +597,9 @@ def base_ring(self): EXAMPLES:: - sage: A = matrix(AA, [(1, 1), (-1, 1)]) + sage: A = matrix(AA, [(1, 1), (-1, 1)]) # optional - sage.rings.number_field sage: from sage.geometry.polyhedron.double_description import Problem - sage: Problem(A).base_ring() + sage: Problem(A).base_ring() # optional - sage.rings.number_field Algebraic Real Field """ return self._field From 49658e0b1931df29b01ca914705bd0bd96c242b7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 19:49:27 -0700 Subject: [PATCH 325/511] src/sage/geometry/polyhedron/backend_normaliz.py: Mark non-rational examples # optional - sage.rings.number_field --- .../geometry/polyhedron/backend_normaliz.py | 114 +++++++++--------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index af8f3287d9a..cfd9b38baab 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -47,12 +47,12 @@ def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds EXAMPLES:: - sage: rt2 = AA(sqrt(2)); rt2 + sage: rt2 = AA(sqrt(2)); rt2 # optional - sage.rings.number_field 1.414213562373095? - sage: rt3 = AA(sqrt(3)); rt3 + sage: rt3 = AA(sqrt(3)); rt3 # optional - sage.rings.number_field 1.732050807568878? sage: from sage.geometry.polyhedron.backend_normaliz import _number_field_elements_from_algebraics_list_of_lists_of_lists - sage: K, results, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists([[[rt2], [1]], [[rt3]], [[1], []]]); results + sage: K, results, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists([[[rt2], [1]], [[rt3]], [[1], []]]); results # optional - sage.rings.number_field [[[-a^3 + 3*a], [1]], [[-a^2 + 2]], [[1], []]] """ from sage.rings.qqbar import number_field_elements_from_algebraics @@ -171,7 +171,7 @@ class Polyhedron_normaliz(Polyhedron_base): Algebraic polyhedra:: - sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], backend='normaliz', verbose=True) # optional - pynormaliz + sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], backend='normaliz', verbose=True) # optional - pynormaliz # optional - sage.rings.number_field # ----8<---- Equivalent Normaliz input file ----8<---- amb_space 1 number_field min_poly (a^2 - 2) embedding [1.414213562373095 +/- 2.99e-16] @@ -182,16 +182,16 @@ class Polyhedron_normaliz(Polyhedron_base): (a) 1 # ----8<-------------------8<-------------------8<---- # Calling PyNormaliz.NmzCone(cone=[], number_field=['a^2 - 2', 'a', '[1.414213562373095 +/- 2.99e-16]'], subspace=[], vertices=[[1, 1], [[[0, 1], [1, 1]], 1]]) - sage: P # optional - pynormaliz + sage: P # optional - pynormaliz # optional - sage.rings.number_field A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - pynormaliz + sage: P.vertices() # optional - pynormaliz # optional - sage.rings.number_field (A vertex at (1), A vertex at (sqrt(2))) - sage: P = polytopes.icosahedron(exact=True, backend='normaliz') # optional - pynormaliz - sage: P # optional - pynormaliz + sage: P = polytopes.icosahedron(exact=True, backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field + sage: P # optional - pynormaliz # optional - sage.rings.number_field A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 defined as the convex hull of 12 vertices - sage: x = polygen(ZZ); P = Polyhedron(vertices=[[sqrt(2)], [AA.polynomial_root(x^3-2, RIF(0,3))]], backend='normaliz', verbose=True) # optional - pynormaliz + sage: x = polygen(ZZ); P = Polyhedron(vertices=[[sqrt(2)], [AA.polynomial_root(x^3-2, RIF(0,3))]], backend='normaliz', verbose=True) # optional - pynormaliz # optional - sage.rings.number_field # ----8<---- Equivalent Normaliz input file ----8<---- amb_space 1 number_field min_poly (a^6 - 2) embedding [1.122462048309373 +/- 5.38e-16] @@ -202,9 +202,9 @@ class Polyhedron_normaliz(Polyhedron_base): (a^2) 1 # ----8<-------------------8<-------------------8<---- # Calling PyNormaliz.NmzCone(cone=[], number_field=['a^6 - 2', 'a', '[1.122462048309373 +/- 5.38e-16]'], subspace=[], vertices=[[[[0, 1], [0, 1], [0, 1], [1, 1], [0, 1], [0, 1]], 1], [[[0, 1], [0, 1], [1, 1], [0, 1], [0, 1], [0, 1]], 1]]) - sage: P # optional - pynormaliz + sage: P # optional - pynormaliz # optional - sage.rings.number_field A 1-dimensional polyhedron in (Symbolic Ring)^1 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - pynormaliz + sage: P.vertices() # optional - pynormaliz # optional - sage.rings.number_field (A vertex at (2^(1/3)), A vertex at (sqrt(2))) """ @@ -255,20 +255,20 @@ def _nmz_result(self, normaliz_cone, property): NormalizError: Some error in the normaliz input data detected: Unknown ConeProperty... sage: x = polygen(QQ, 'x') - sage: K. = NumberField(x^3 - 3, embedding=AA(3)**(1/3)) - sage: p = Polyhedron(vertices=[(0,0),(1,1),(a,3),(-1,a**2)], rays=[(-1,-a)], backend='normaliz') # optional - pynormaliz - sage: sorted(p._nmz_result(p._normaliz_cone, 'VerticesOfPolyhedron')) # optional - pynormaliz + sage: K. = NumberField(x^3 - 3, embedding=AA(3)**(1/3)) # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=[(0,0),(1,1),(a,3),(-1,a**2)], rays=[(-1,-a)], backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field + sage: sorted(p._nmz_result(p._normaliz_cone, 'VerticesOfPolyhedron')) # optional - pynormaliz # optional - sage.rings.number_field [[-1, a^2, 1], [1, 1, 1], [a, 3, 1]] - sage: triangulation_generators = p._nmz_result(p._normaliz_cone, 'Triangulation')[1] # optional - pynormaliz - sage: sorted(triangulation_generators) # optional - pynormaliz + sage: triangulation_generators = p._nmz_result(p._normaliz_cone, 'Triangulation')[1] # optional - pynormaliz # optional - sage.rings.number_field + sage: sorted(triangulation_generators) # optional - pynormaliz # optional - sage.rings.number_field [[-a^2, -3, 0], [-1, a^2, 1], [0, 0, 1], [1, 1, 1], [a, 3, 1]] - sage: p._nmz_result(p._normaliz_cone, 'AffineDim') == 2 # optional - pynormaliz + sage: p._nmz_result(p._normaliz_cone, 'AffineDim') == 2 # optional - pynormaliz # optional - sage.rings.number_field True - sage: p._nmz_result(p._normaliz_cone, 'EmbeddingDim') == 3 # optional - pynormaliz + sage: p._nmz_result(p._normaliz_cone, 'EmbeddingDim') == 3 # optional - pynormaliz # optional - sage.rings.number_field True - sage: p._nmz_result(p._normaliz_cone, 'ExtremeRays') # optional - pynormaliz + sage: p._nmz_result(p._normaliz_cone, 'ExtremeRays') # optional - pynormaliz # optional - sage.rings.number_field [[-1/3*a^2, -1, 0]] - sage: p._nmz_result(p._normaliz_cone, 'MaximalSubspace') # optional - pynormaliz + sage: p._nmz_result(p._normaliz_cone, 'MaximalSubspace') # optional - pynormaliz # optional - sage.rings.number_field [] """ def rational_handler(list): @@ -313,7 +313,7 @@ def _convert_to_pynormaliz(x): TESTS:: - sage: K. = QuadraticField(2) + sage: K. = QuadraticField(2) # optional - sage.rings.number_field sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz as Pn sage: Pn._convert_to_pynormaliz(17) 17 @@ -325,9 +325,9 @@ def _convert_to_pynormaliz(x): [[28, 5]] sage: Pn._convert_to_pynormaliz(28901824309821093821093812093810928309183091832091/5234573685674784567853456543456456786543456765) [[28901824309821093821093812093810928309183091832091, 5234573685674784567853456543456456786543456765]] - sage: Pn._convert_to_pynormaliz(7 + sqrt2) + sage: Pn._convert_to_pynormaliz(7 + sqrt2) # optional - sage.rings.number_field [[7, 1], [1, 1]] - sage: Pn._convert_to_pynormaliz(7/2 + sqrt2) + sage: Pn._convert_to_pynormaliz(7/2 + sqrt2) # optional - sage.rings.number_field [[7, 2], [1, 1]] sage: Pn._convert_to_pynormaliz([[1, 2], (3, 4)]) [[1, 2], [3, 4]] @@ -335,8 +335,8 @@ def _convert_to_pynormaliz(x): Check that :trac:`29836` is fixed:: sage: P = polytopes.simplex(backend='normaliz') # optional - pynormaliz - sage: K. = QuadraticField(2) # optional - pynormaliz - sage: P.dilation(sqrt2) # optional - pynormaliz + sage: K. = QuadraticField(2) # optional - pynormaliz # optional - sage.rings.number_field + sage: P.dilation(sqrt2) # optional - pynormaliz # optional - sage.rings.number_field A 3-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.41...)^4 defined as the convex hull of 4 vertices """ def _QQ_pair(x): @@ -369,16 +369,16 @@ def _init_from_normaliz_data(self, data, normaliz_field=None, verbose=False): [[0, -1, 2], [0, 2, -1]] sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz # optional - pynormaliz - sage: from sage.rings.qqbar import AA # optional - pynormaliz - sage: from sage.rings.number_field.number_field import QuadraticField # optional - pynormaliz + sage: from sage.rings.qqbar import AA # optional - pynormaliz # optional - sage.rings.number_field + sage: from sage.rings.number_field.number_field import QuadraticField # optional - pynormaliz # optional - sage.rings.number_field sage: data = {'number_field': ['a^2 - 2', 'a', '[1.4 +/- 0.1]'], # optional - pynormaliz ....: 'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} sage: from sage.geometry.polyhedron.parent import Polyhedra_normaliz # optional - pynormaliz - sage: parent = Polyhedra_normaliz(AA, 2, 'normaliz') # optional - pynormaliz - sage: Polyhedron_normaliz(parent, None, None, normaliz_data=data, # indirect doctest, optional - pynormaliz + sage: parent = Polyhedra_normaliz(AA, 2, 'normaliz') # optional - pynormaliz # optional - sage.rings.number_field + sage: Polyhedron_normaliz(parent, None, None, normaliz_data=data, # indirect doctest, optional - pynormaliz # optional - sage.rings.number_field ....: normaliz_field=QuadraticField(2)) A 2-dimensional polyhedron in AA^2 defined as the convex hull of 1 vertex and 2 rays - sage: _.inequalities_list() # optional - pynormaliz + sage: _.inequalities_list() # optional - pynormaliz # optional - sage.rings.number_field [[0, -1/2, 1], [0, 2, -1]] """ if normaliz_field is None: @@ -433,10 +433,10 @@ def _is_zero(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) - sage: p._is_zero(0) + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field + sage: p._is_zero(0) # optional - sage.rings.number_field True - sage: p._is_zero(1/100000) + sage: p._is_zero(1/100000) # optional - sage.rings.number_field False """ return x == 0 @@ -455,10 +455,10 @@ def _is_nonneg(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) - sage: p._is_nonneg(1) + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field + sage: p._is_nonneg(1) # optional - sage.rings.number_field True - sage: p._is_nonneg(-1/100000) + sage: p._is_nonneg(-1/100000) # optional - sage.rings.number_field False """ return x >= 0 @@ -477,10 +477,10 @@ def _is_positive(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) - sage: p._is_positive(1) + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field + sage: p._is_positive(1) # optional - sage.rings.number_field True - sage: p._is_positive(0) + sage: p._is_positive(0) # optional - sage.rings.number_field False """ return x > 0 @@ -595,14 +595,14 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): Check that :trac:`30248` is fixed, that maps as input works:: - sage: q = Polyhedron(backend='normaliz', base_ring=AA, # optional - pynormaliz + sage: q = Polyhedron(backend='normaliz', base_ring=AA, # optional - pynormaliz # optional - sage.rings.number_field ....: rays=[(0, 0, 1), (0, 1, -1), (1, 0, -1)]) sage: make_new_Hrep = lambda h: tuple(x if i == 0 else -1*x for i, x in enumerate(h._vector)) - sage: new_inequalities = map(make_new_Hrep, q.inequality_generator()) # optional - pynormaliz - sage: new_equations = map(make_new_Hrep, q.equation_generator()) # optional - pynormaliz - sage: parent = q.parent() # optional - pynormaliz - sage: new_q = parent.element_class(parent,None,[new_inequalities,new_equations]) # optional - pynormaliz - sage: new_q # optional - pynormaliz + sage: new_inequalities = map(make_new_Hrep, q.inequality_generator()) # optional - pynormaliz # optional - sage.rings.number_field + sage: new_equations = map(make_new_Hrep, q.equation_generator()) # optional - pynormaliz # optional - sage.rings.number_field + sage: parent = q.parent() # optional - pynormaliz # optional - sage.rings.number_field + sage: new_q = parent.element_class(parent,None,[new_inequalities,new_equations]) # optional - pynormaliz # optional - sage.rings.number_field + sage: new_q # optional - pynormaliz # optional - sage.rings.number_field A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays """ @@ -928,15 +928,15 @@ def _compute_nmz_data_lists_and_field(self, data_lists, convert_QQ, convert_NF): sage: p._compute_nmz_data_lists_and_field([[[AA(1)]], [[1/2]]], # optional - pynormaliz ....: convert_QQ, convert_NF) (([[1000]], [[500]]), Rational Field) - sage: p._compute_nmz_data_lists_and_field([[[AA(sqrt(2))]], [[1/2]]], # optional - pynormaliz + sage: p._compute_nmz_data_lists_and_field([[[AA(sqrt(2))]], [[1/2]]], # optional - pynormaliz # optional - sage.rings.number_field ....: convert_QQ, convert_NF) ([[[a]], [[1/2]]], Number Field in a with defining polynomial y^2 - 2 with a = 1.414213562373095?) TESTS:: - sage: K. = QuadraticField(-5) - sage: p = Polyhedron(vertices=[(a,1/2),(2,0),(4,5/6)], # indirect doctest # optional - pynormaliz + sage: K. = QuadraticField(-5) # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=[(a,1/2),(2,0),(4,5/6)], # indirect doctest # optional - pynormaliz # optional - sage.rings.number_field ....: base_ring=K, backend='normaliz') Traceback (most recent call last): ... @@ -944,10 +944,10 @@ def _compute_nmz_data_lists_and_field(self, data_lists, convert_QQ, convert_NF): Checks that :trac:`30248` is fixed:: - sage: q = Polyhedron(backend='normaliz', base_ring=AA, # indirect doctest # optional - pynormaliz + sage: q = Polyhedron(backend='normaliz', base_ring=AA, # indirect doctest # optional - pynormaliz # optional - sage.rings.number_field ....: rays=[(0, 0, 1), (0, 1, -1), (1, 0, -1)]); q A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays - sage: -q # optional - pynormaliz + sage: -q # optional - pynormaliz # optional - sage.rings.number_field A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays """ from sage.categories.number_fields import NumberFields @@ -1078,7 +1078,7 @@ def _number_field_triple(normaliz_field): sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz as Pn sage: Pn._number_field_triple(QQ) is None True - sage: Pn._number_field_triple(QuadraticField(5)) + sage: Pn._number_field_triple(QuadraticField(5)) # optional - sage.rings.number_field ['a^2 - 5', 'a', '[2.236067977499789 +/- 8.06e-16]'] """ from sage.rings.real_arb import RealBallField @@ -1327,10 +1327,10 @@ def __setstate__(self, state): sage: P2 == P # optional - pynormaliz True - sage: P = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz - sage: P1 = loads(dumps(P)) # optional - pynormaliz - sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone, normaliz_field=P1._normaliz_field) # optional - pynormaliz - sage: P == P2 # optional - pynormaliz + sage: P = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field + sage: P1 = loads(dumps(P)) # optional - pynormaliz # optional - sage.rings.number_field + sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone, normaliz_field=P1._normaliz_field) # optional - pynormaliz # optional - sage.rings.number_field + sage: P == P2 # optional - pynormaliz # optional - sage.rings.number_field True Test that :trac:`31820` is fixed:: @@ -1496,8 +1496,8 @@ def _volume_normaliz(self, measure='euclidean'): Check that :trac:`28872` is fixed:: - sage: P = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz - sage: P.volume(measure='induced_lattice') # optional - pynormaliz + sage: P = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field + sage: P.volume(measure='induced_lattice') # optional - pynormaliz # optional - sage.rings.number_field -1056*sqrt5 + 2400 Some sanity checks that the ambient volume works correctly:: From a47c25bcc0e630feebb5680d694cfd21dc8a68ac Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 21:54:10 -0700 Subject: [PATCH 326/511] src/sage/geometry/polyhedron/constructor.py: Mark doctests # optional - sage.rings.number_field --- src/sage/geometry/polyhedron/constructor.py | 39 +++++++++++---------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/sage/geometry/polyhedron/constructor.py b/src/sage/geometry/polyhedron/constructor.py index 7f68ca41ce0..e97a72a4aa3 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -177,8 +177,8 @@ exact way to work with roots in Sage is the :mod:`Algebraic Real Field ` :: - sage: triangle = Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)], base_ring=AA) - sage: triangle.Hrepresentation() + sage: triangle = Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)], base_ring=AA) # optional - sage.rings.number_field + sage: triangle.Hrepresentation() # optional - sage.rings.number_field (An inequality (-1, -0.5773502691896258?) x + 1 >= 0, An inequality (1, -0.5773502691896258?) x + 0 >= 0, An inequality (0, 1.154700538379252?) x + 0 >= 0) @@ -187,20 +187,20 @@ symbolic ring element and, therefore, the polyhedron defined over the symbolic ring. This is currently not supported as SR is not exact:: - sage: Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)]) + sage: Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)]) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: no default backend for computations with Symbolic Ring - sage: SR.is_exact() + sage: SR.is_exact() # optional - sage.symbolic False Even faster than all algebraic real numbers (the field ``AA``) is to take the smallest extension field. For the equilateral triangle, that would be:: - sage: K. = NumberField(x^2 - 3, embedding=AA(3)**(1/2)) - sage: Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)]) + sage: K. = NumberField(x^2 - 3, embedding=AA(3)**(1/2)) # optional - sage.rings.number_field + sage: Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)]) # optional - sage.rings.number_field A 2-dimensional polyhedron in (Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?)^2 defined as the convex hull of 3 vertices .. WARNING:: @@ -441,24 +441,25 @@ def Polyhedron(vertices=None, rays=None, lines=None, by the cyclic shifts of `(0, \pm 1, \pm (1+\sqrt(5))/2)`, cf. :wikipedia:`Regular_icosahedron`. It needs a number field:: - sage: R0. = QQ[] - sage: R1. = NumberField(r0^2-5, embedding=AA(5)**(1/2)) - sage: gold = (1+r1)/2 - sage: v = [[0, 1, gold], [0, 1, -gold], [0, -1, gold], [0, -1, -gold]] - sage: pp = Permutation((1, 2, 3)) - sage: icosah = Polyhedron([(pp^2).action(w) for w in v] - ....: + [pp.action(w) for w in v] + v, base_ring=R1) - sage: len(icosah.faces(2)) + sage: R0. = QQ[] # optional - sage.rings.number_field + sage: R1. = NumberField(r0^2-5, embedding=AA(5)**(1/2)) # optional - sage.rings.number_field + sage: gold = (1+r1)/2 # optional - sage.rings.number_field + sage: v = [[0, 1, gold], [0, 1, -gold], [0, -1, gold], [0, -1, -gold]] # optional - sage.rings.number_field + sage: pp = Permutation((1, 2, 3)) # optional - sage.combinat # optional - sage.rings.number_field + sage: icosah = Polyhedron( # optional - sage.combinat # optional - sage.rings.number_field + ....: [(pp^2).action(w) for w in v] + [pp.action(w) for w in v] + v, + ....: base_ring=R1) + sage: len(icosah.faces(2)) # optional - sage.combinat # optional - sage.rings.number_field 20 When the input contains elements of a Number Field, they require an embedding:: - sage: K = NumberField(x^2-2,'s') - sage: s = K.0 - sage: L = NumberField(x^3-2,'t') - sage: t = L.0 - sage: P = Polyhedron(vertices = [[0,s],[t,0]]) + sage: K = NumberField(x^2-2,'s') # optional - sage.rings.number_field + sage: s = K.0 # optional - sage.rings.number_field + sage: L = NumberField(x^3-2,'t') # optional - sage.rings.number_field + sage: t = L.0 # optional - sage.rings.number_field + sage: P = Polyhedron(vertices = [[0,s],[t,0]]) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: invalid base ring From 9ab8040da8700b460adc2fe2f59b344ba23c114a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 5 Oct 2021 22:52:10 -0700 Subject: [PATCH 327/511] src/sage/geometry/polyhedron/backend_field.py: Mark doctests # optional - sage.rings.number_field --- src/sage/geometry/polyhedron/backend_field.py | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_field.py b/src/sage/geometry/polyhedron/backend_field.py index d0f50782016..17cba0ed2ef 100644 --- a/src/sage/geometry/polyhedron/backend_field.py +++ b/src/sage/geometry/polyhedron/backend_field.py @@ -9,13 +9,13 @@ sage: p0 = (0, 0) sage: p1 = (1, 0) - sage: p2 = (1/2, AA(3).sqrt()/2) - sage: equilateral_triangle = Polyhedron([p0, p1, p2]) - sage: equilateral_triangle.vertices() + sage: p2 = (1/2, AA(3).sqrt()/2) # optional - sage.rings.number_field + sage: equilateral_triangle = Polyhedron([p0, p1, p2]) # optional - sage.rings.number_field + sage: equilateral_triangle.vertices() # optional - sage.rings.number_field (A vertex at (0, 0), A vertex at (1, 0), A vertex at (0.500000000000000?, 0.866025403784439?)) - sage: equilateral_triangle.inequalities() + sage: equilateral_triangle.inequalities() # optional - sage.rings.number_field (An inequality (-1, -0.5773502691896258?) x + 1 >= 0, An inequality (1, -0.5773502691896258?) x + 0 >= 0, An inequality (0, 1.154700538379252?) x + 0 >= 0) @@ -46,22 +46,22 @@ class Polyhedron_field(Polyhedron_base): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], + sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # optional - sage.rings.number_field ....: rays=[(1,1)], lines=[], backend='field', base_ring=AA) - sage: TestSuite(p).run() + sage: TestSuite(p).run() # optional - sage.rings.number_field TESTS:: - sage: K. = QuadraticField(3) - sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)]) - sage: TestSuite(p).run() + sage: K. = QuadraticField(3) # optional - sage.rings.number_field + sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)]) # optional - sage.rings.number_field + sage: TestSuite(p).run() # optional - sage.rings.number_field Check that :trac:`19013` is fixed:: - sage: K. = NumberField(x^2-x-1, embedding=1.618) - sage: P1 = Polyhedron([[0,1],[1,1],[1,-phi+1]]) - sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]]) - sage: P1.intersection(P2) + sage: K. = NumberField(x^2-x-1, embedding=1.618) # optional - sage.rings.number_field + sage: P1 = Polyhedron([[0,1],[1,1],[1,-phi+1]]) # optional - sage.rings.number_field + sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]]) # optional - sage.rings.number_field + sage: P1.intersection(P2) # optional - sage.rings.number_field The empty polyhedron in (Number Field in phi with defining polynomial x^2 - x - 1 with phi = 1.618033988749895?)^2 Check that :trac:`28654` is fixed:: @@ -83,10 +83,10 @@ def _is_zero(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) - sage: p._is_zero(0) + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field + sage: p._is_zero(0) # optional - sage.rings.number_field True - sage: p._is_zero(1/100000) + sage: p._is_zero(1/100000) # optional - sage.rings.number_field False """ return x == 0 @@ -105,10 +105,10 @@ def _is_nonneg(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) - sage: p._is_nonneg(1) + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field + sage: p._is_nonneg(1) # optional - sage.rings.number_field True - sage: p._is_nonneg(-1/100000) + sage: p._is_nonneg(-1/100000) # optional - sage.rings.number_field False """ return x >= 0 @@ -127,10 +127,10 @@ def _is_positive(self, x): EXAMPLES:: - sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) - sage: p._is_positive(1) + sage: p = Polyhedron([(sqrt(3),sqrt(2))], base_ring=AA) # optional - sage.rings.number_field + sage: p._is_positive(1) # optional - sage.rings.number_field True - sage: p._is_positive(0) + sage: p._is_positive(0) # optional - sage.rings.number_field False """ return x > 0 @@ -150,12 +150,12 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep): sage: from sage.geometry.polyhedron.parent import Polyhedra_field sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field - sage: parent = Polyhedra_field(AA, 1, 'field') + sage: parent = Polyhedra_field(AA, 1, 'field') # optional - sage.rings.number_field sage: Vrep = [[[0], [1]], [], []] sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_field(parent, Vrep, Hrep, - ....: Vrep_minimal=True, Hrep_minimal=True) # indirect doctest - sage: p + sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # optional - sage.rings.number_field + ....: Vrep_minimal=True, Hrep_minimal=True) + sage: p # optional - sage.rings.number_field A 1-dimensional polyhedron in AA^1 defined as the convex hull of 2 vertices """ self._init_Vrepresentation(*Vrep) @@ -234,12 +234,12 @@ def _init_Vrepresentation(self, vertices, rays, lines): sage: from sage.geometry.polyhedron.parent import Polyhedra_field sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field - sage: parent = Polyhedra_field(AA, 1, 'field') + sage: parent = Polyhedra_field(AA, 1, 'field') # optional - sage.rings.number_field sage: Vrep = [[[0], [1]], [], []] sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest + sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # optional - sage.rings.number_field ....: Vrep_minimal=True, Hrep_minimal=True) - sage: p.vertices_list() + sage: p.vertices_list() # optional - sage.rings.number_field [[0], [1]] """ self._Vrepresentation = [] @@ -258,13 +258,13 @@ def _init_Vrepresentation_backend(self, Vrep): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,1/sqrt(2)),(sqrt(2),0),(4,sqrt(5)/6)], + sage: p = Polyhedron(vertices=[(0,1/sqrt(2)),(sqrt(2),0),(4,sqrt(5)/6)], # optional - sage.rings.number_field ....: base_ring=AA, backend='field') # indirect doctest - sage: p.Hrepresentation() + sage: p.Hrepresentation() # optional - sage.rings.number_field (An inequality (-0.1582178750233332?, 1.097777812326429?) x + 0.2237538646678492? >= 0, An inequality (-0.1419794359520263?, -1.698172434277148?) x + 1.200789243901438? >= 0, An inequality (0.3001973109753594?, 0.600394621950719?) x - 0.4245431085692869? >= 0) - sage: p.Vrepresentation() + sage: p.Vrepresentation() # optional - sage.rings.number_field (A vertex at (0.?e-15, 0.707106781186548?), A vertex at (1.414213562373095?, 0), A vertex at (4.000000000000000?, 0.372677996249965?)) @@ -279,10 +279,10 @@ def _init_Hrepresentation(self, inequalities, equations): sage: from sage.geometry.polyhedron.parent import Polyhedra_field sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field - sage: parent = Polyhedra_field(AA, 1, 'field') + sage: parent = Polyhedra_field(AA, 1, 'field') # optional - sage.rings.number_field sage: Vrep = [[[0], [1]], [], []] sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest + sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # optional - sage.rings.number_field ....: Vrep_minimal=True, Hrep_minimal=True) sage: p.inequalities_list() [[0, 1], [1, -1]] @@ -301,13 +301,13 @@ def _init_Hrepresentation_backend(self, Hrep): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,1/sqrt(2)),(sqrt(2),0),(4,sqrt(5)/6)], + sage: p = Polyhedron(vertices=[(0,1/sqrt(2)),(sqrt(2),0),(4,sqrt(5)/6)], # optional - sage.rings.number_field ....: base_ring=AA, backend='field') # indirect doctest - sage: p.Hrepresentation() + sage: p.Hrepresentation() # optional - sage.rings.number_field (An inequality (-0.1582178750233332?, 1.097777812326429?) x + 0.2237538646678492? >= 0, An inequality (-0.1419794359520263?, -1.698172434277148?) x + 1.200789243901438? >= 0, An inequality (0.3001973109753594?, 0.600394621950719?) x - 0.4245431085692869? >= 0) - sage: p.Vrepresentation() + sage: p.Vrepresentation() # optional - sage.rings.number_field (A vertex at (0.?e-15, 0.707106781186548?), A vertex at (1.414213562373095?, 0), A vertex at (4.000000000000000?, 0.372677996249965?)) @@ -320,13 +320,13 @@ def _init_empty_polyhedron(self): TESTS:: - sage: empty = Polyhedron(backend='field', base_ring=AA); empty + sage: empty = Polyhedron(backend='field', base_ring=AA); empty # optional - sage.rings.number_field The empty polyhedron in AA^0 - sage: empty.Vrepresentation() + sage: empty.Vrepresentation() # optional - sage.rings.number_field () - sage: empty.Hrepresentation() + sage: empty.Hrepresentation() # optional - sage.rings.number_field (An equation -1 == 0,) - sage: Polyhedron(vertices = [], backend='field') + sage: Polyhedron(vertices=[], backend='field') The empty polyhedron in QQ^0 sage: Polyhedron(backend='field')._init_empty_polyhedron() """ From ce90678dd360868bc85908681b230f6795b567ce Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 12:58:06 -0700 Subject: [PATCH 328/511] src/sage/geometry/polyhedron/base_ZZ.py: Mark a doctest # optional - sage.rings.number_field --- src/sage/geometry/polyhedron/base_ZZ.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index aabb5806504..d8c1367f7c5 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -79,7 +79,7 @@ def is_lattice_polytope(self): sage: polytopes.cross_polytope(3).is_lattice_polytope() True - sage: polytopes.regular_polygon(5).is_lattice_polytope() + sage: polytopes.regular_polygon(5).is_lattice_polytope() # optional - sage.rings.number_field False TESTS: From 607598a3b82ad3e337b43a93d67cc425f07c8650 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 14:06:26 -0700 Subject: [PATCH 329/511] src/sage/geometry/polyhedron/base.py: Mark more doctests # optional - sage.rings.number_field --- src/sage/geometry/polyhedron/base.py | 144 +++++++++++++-------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 47063568802..4272c3b0d29 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -641,13 +641,13 @@ def change_ring(self, base_ring, backend=None): ... TypeError: cannot change the base ring to the Integer Ring - sage: P = polytopes.regular_polygon(3); P + sage: P = polytopes.regular_polygon(3); P # optional - sage.rings.number_field A 2-dimensional polyhedron in AA^2 defined as the convex hull of 3 vertices - sage: P.vertices() + sage: P.vertices() # optional - sage.rings.number_field (A vertex at (0.?e-16, 1.000000000000000?), A vertex at (0.866025403784439?, -0.500000000000000?), A vertex at (-0.866025403784439?, -0.500000000000000?)) - sage: P.change_ring(QQ) + sage: P.change_ring(QQ) # optional - sage.rings.number_field Traceback (most recent call last): ... TypeError: cannot change the base ring to the Rational Field @@ -660,11 +660,11 @@ def change_ring(self, base_ring, backend=None): base ring from an exact ring into ``RDF`` may cause a loss of data:: - sage: P = Polyhedron([[2/3,0],[6666666666666667/10^16,0]], base_ring=AA); P + sage: P = Polyhedron([[2/3,0],[6666666666666667/10^16,0]], base_ring=AA); P # optional - sage.rings.number_field A 1-dimensional polyhedron in AA^2 defined as the convex hull of 2 vertices - sage: Q = P.change_ring(RDF); Q + sage: Q = P.change_ring(RDF); Q # optional - sage.rings.number_field A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex - sage: P.n_vertices() == Q.n_vertices() + sage: P.n_vertices() == Q.n_vertices() # optional - sage.rings.number_field False """ @@ -3831,8 +3831,8 @@ def is_pyramid(self, certificate=False): True sage: P.is_pyramid(certificate=True) (True, A vertex at (1, 0, 0, 0)) - sage: egyptian_pyramid = polytopes.regular_polygon(4).pyramid() - sage: egyptian_pyramid.is_pyramid() + sage: egyptian_pyramid = polytopes.regular_polygon(4).pyramid() # optional - sage.rings.number_field + sage: egyptian_pyramid.is_pyramid() # optional - sage.rings.number_field True sage: Q = polytopes.octahedron() sage: Q.is_pyramid() @@ -5331,28 +5331,28 @@ def linear_transformation(self, linear_transf, new_base_ring=None): sage: b3_proj = proj_mat * b3; b3_proj A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices - sage: square = polytopes.regular_polygon(4) - sage: square.vertices_list() + sage: square = polytopes.regular_polygon(4) # optional - sage.rings.number_field + sage: square.vertices_list() # optional - sage.rings.number_field [[0, -1], [1, 0], [-1, 0], [0, 1]] - sage: transf = matrix([[1,1],[0,1]]) - sage: sheared = transf * square - sage: sheared.vertices_list() + sage: transf = matrix([[1,1],[0,1]]) # optional - sage.rings.number_field + sage: sheared = transf * square # optional - sage.rings.number_field + sage: sheared.vertices_list() # optional - sage.rings.number_field [[-1, -1], [1, 0], [-1, 0], [1, 1]] - sage: sheared == square.linear_transformation(transf) + sage: sheared == square.linear_transformation(transf) # optional - sage.rings.number_field True Specifying the new base ring may avoid coercion failure:: - sage: K. = QuadraticField(2) - sage: L. = QuadraticField(3) - sage: P = polytopes.cube()*sqrt2 - sage: M = matrix([[sqrt3, 0, 0], [0, sqrt3, 0], [0, 0, 1]]) - sage: P.linear_transformation(M, new_base_ring=K.composite_fields(L)[0]) + sage: K. = QuadraticField(2) # optional - sage.rings.number_field + sage: L. = QuadraticField(3) # optional - sage.rings.number_field + sage: P = polytopes.cube()*sqrt2 # optional - sage.rings.number_field + sage: M = matrix([[sqrt3, 0, 0], [0, sqrt3, 0], [0, 0, 1]]) # optional - sage.rings.number_field + sage: P.linear_transformation(M, new_base_ring=K.composite_fields(L)[0]) # optional - sage.rings.number_field A 3-dimensional polyhedron in (Number Field in sqrt2sqrt3 with defining polynomial x^4 - 10*x^2 + 1 with sqrt2sqrt3 = 0.3178372451957823?)^3 defined as the convex hull of 8 vertices Linear transformation without specified new base ring fails in this case:: - sage: M*P + sage: M*P # optional - sage.rings.number_field Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 3 by 3 dense matrices over Number Field in sqrt3 with defining polynomial x^2 - 3 with sqrt3 = 1.732050807568878?' and 'Full MatrixSpace of 3 by 8 dense matrices over Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?' @@ -5372,7 +5372,7 @@ def linear_transformation(self, linear_transf, new_base_ring=None): A 3-dimensional polyhedron in RDF^4 defined as the convex hull of 5 vertices sage: (1/1 * proj_mat) * b3 A 3-dimensional polyhedron in QQ^4 defined as the convex hull of 5 vertices - sage: (AA(2).sqrt() * proj_mat) * b3 + sage: (AA(2).sqrt() * proj_mat) * b3 # optional - sage.rings.number_field A 3-dimensional polyhedron in AA^4 defined as the convex hull of 5 vertices Check that zero-matrices act correctly:: @@ -5963,15 +5963,15 @@ def stack(self, face, position=None): (1, 9, 16, 9, 1) sage: stacked_square_large = cube.stack(square_face,position=10) - sage: hexaprism = polytopes.regular_polygon(6).prism() - sage: hexaprism.f_vector() + sage: hexaprism = polytopes.regular_polygon(6).prism() # optional - sage.rings.number_field + sage: hexaprism.f_vector() # optional - sage.rings.number_field (1, 12, 18, 8, 1) - sage: square_face = hexaprism.faces(2)[2] - sage: stacked_hexaprism = hexaprism.stack(square_face) - sage: stacked_hexaprism.f_vector() + sage: square_face = hexaprism.faces(2)[2] # optional - sage.rings.number_field + sage: stacked_hexaprism = hexaprism.stack(square_face) # optional - sage.rings.number_field + sage: stacked_hexaprism.f_vector() # optional - sage.rings.number_field (1, 13, 22, 11, 1) - sage: hexaprism.stack(square_face,position=4) + sage: hexaprism.stack(square_face,position=4) # optional - sage.rings.number_field Traceback (most recent call last): ... ValueError: the chosen position is too large @@ -6318,7 +6318,7 @@ def _test_lawrence(self, tester=None, **options): Check that :trac:`28725` is fixed:: - sage: polytopes.regular_polygon(3)._test_lawrence() + sage: polytopes.regular_polygon(3)._test_lawrence() # optional - sage.rings.number_field Check that :trac:`30293` is fixed:: @@ -6445,8 +6445,8 @@ def barycentric_subdivision(self, subdivision_frac=None): sage: P.barycentric_subdivision() A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 6 vertices - sage: P = polytopes.regular_polygon(4, base_ring=QQ) - sage: P.barycentric_subdivision() + sage: P = polytopes.regular_polygon(4, base_ring=QQ) # optional - sage.rings.number_field + sage: P.barycentric_subdivision() # optional - sage.rings.number_field A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 8 vertices @@ -6662,31 +6662,31 @@ def hasse_diagram(self): EXAMPLES:: - sage: P = polytopes.regular_polygon(4).pyramid() - sage: D = P.hasse_diagram(); D + sage: P = polytopes.regular_polygon(4).pyramid() # optional - sage.rings.number_field + sage: D = P.hasse_diagram(); D # optional - sage.rings.number_field Digraph on 20 vertices - sage: D.degree_polynomial() + sage: D.degree_polynomial() # optional - sage.rings.number_field x^5 + x^4*y + x*y^4 + y^5 + 4*x^3*y + 8*x^2*y^2 + 4*x*y^3 Faces of an mutable polyhedron are not hashable. Hence those are not suitable as vertices of the hasse diagram. Use the combinatorial polyhedron instead:: - sage: P = polytopes.regular_polygon(4).pyramid() - sage: parent = P.parent() - sage: parent = parent.change_ring(QQ, backend='ppl') - sage: Q = parent._element_constructor_(P, mutable=True) - sage: Q.hasse_diagram() + sage: P = polytopes.regular_polygon(4).pyramid() # optional - sage.rings.number_field + sage: parent = P.parent() # optional - sage.rings.number_field + sage: parent = parent.change_ring(QQ, backend='ppl') # optional - sage.rings.number_field + sage: Q = parent._element_constructor_(P, mutable=True) # optional - sage.rings.number_field + sage: Q.hasse_diagram() # optional - sage.rings.number_field Traceback (most recent call last): ... TypeError: mutable polyhedra are unhashable - sage: C = Q.combinatorial_polyhedron() - sage: D = C.hasse_diagram() - sage: set(D.vertices()) == set(range(20)) + sage: C = Q.combinatorial_polyhedron() # optional - sage.rings.number_field + sage: D = C.hasse_diagram() # optional - sage.rings.number_field + sage: set(D.vertices()) == set(range(20)) # optional - sage.rings.number_field True sage: def index_to_combinatorial_face(n): ....: return C.face_by_face_lattice_index(n) - sage: D.relabel(index_to_combinatorial_face, inplace=True) - sage: D.vertices() + sage: D.relabel(index_to_combinatorial_face, inplace=True) # optional - sage.rings.number_field + sage: D.vertices() # optional - sage.rings.number_field [A -1-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 0-dimensional face of a 3-dimensional combinatorial polyhedron, @@ -6707,7 +6707,7 @@ def hasse_diagram(self): A 2-dimensional face of a 3-dimensional combinatorial polyhedron, A 2-dimensional face of a 3-dimensional combinatorial polyhedron, A 3-dimensional face of a 3-dimensional combinatorial polyhedron] - sage: D.degree_polynomial() + sage: D.degree_polynomial() # optional - sage.rings.number_field x^5 + x^4*y + x*y^4 + y^5 + 4*x^3*y + 8*x^2*y^2 + 4*x*y^3 """ @@ -7914,7 +7914,7 @@ def _test_pyramid(self, tester=None, **options): TESTS: - sage: polytopes.regular_polygon(4)._test_pyramid() + sage: polytopes.regular_polygon(4)._test_pyramid() # optional - sage.rings.number_field """ if tester is None: tester = self._tester(**options) @@ -8178,10 +8178,10 @@ def one_point_suspension(self, vertex): sage: ops_cube.f_vector() (1, 9, 24, 24, 9, 1) - sage: pentagon = polytopes.regular_polygon(5) - sage: v = pentagon.vertices()[0] - sage: ops_pentagon = pentagon.one_point_suspension(v) - sage: ops_pentagon.f_vector() + sage: pentagon = polytopes.regular_polygon(5) # optional - sage.rings.number_field + sage: v = pentagon.vertices()[0] # optional - sage.rings.number_field + sage: ops_pentagon = pentagon.one_point_suspension(v) # optional - sage.rings.number_field + sage: ops_pentagon.f_vector() # optional - sage.rings.number_field (1, 6, 12, 8, 1) It works with a polyhedral face as well:: @@ -8228,10 +8228,10 @@ def face_split(self, face): EXAMPLES:: - sage: pentagon = polytopes.regular_polygon(5) - sage: f = pentagon.faces(1)[0] - sage: fsplit_pentagon = pentagon.face_split(f) - sage: fsplit_pentagon.f_vector() + sage: pentagon = polytopes.regular_polygon(5) # optional - sage.rings.number_field + sage: f = pentagon.faces(1)[0] # optional - sage.rings.number_field + sage: fsplit_pentagon = pentagon.face_split(f) # optional - sage.rings.number_field + sage: fsplit_pentagon.f_vector() # optional - sage.rings.number_field (1, 7, 14, 9, 1) TESTS: @@ -8610,13 +8610,13 @@ def volume(self, measure='ambient', engine='auto', **kwds): If the base ring is exact, the answer is exact:: - sage: P5 = polytopes.regular_polygon(5) - sage: P5.volume() + sage: P5 = polytopes.regular_polygon(5) # optional - sage.rings.number_field + sage: P5.volume() # optional - sage.rings.number_field 2.377641290737884? - sage: polytopes.icosahedron().volume() + sage: polytopes.icosahedron().volume() # optional - sage.rings.number_field 5/12*sqrt5 + 5/4 - sage: numerical_approx(_) # abs tol 1e9 + sage: numerical_approx(_) # abs tol 1e9 # optional - sage.rings.number_field 2.18169499062491 When considering lower-dimensional polytopes, we can ask for the @@ -8634,20 +8634,20 @@ def volume(self, measure='ambient', engine='auto', **kwds): sage: P.volume(measure='induced_rational') # optional -- latte_int 1 - sage: S = polytopes.regular_polygon(6); S + sage: S = polytopes.regular_polygon(6); S # optional - sage.rings.number_field A 2-dimensional polyhedron in AA^2 defined as the convex hull of 6 vertices - sage: edge = S.faces(1)[4].as_polyhedron() - sage: edge.vertices() + sage: edge = S.faces(1)[4].as_polyhedron() # optional - sage.rings.number_field + sage: edge.vertices() # optional - sage.rings.number_field (A vertex at (0.866025403784439?, 1/2), A vertex at (0, 1)) - sage: edge.volume() + sage: edge.volume() # optional - sage.rings.number_field 0 - sage: edge.volume(measure='induced') + sage: edge.volume(measure='induced') # optional - sage.rings.number_field 1 sage: P = Polyhedron(backend='normaliz',vertices=[[1,0,0],[0,0,1],[-1,1,1],[-1,2,0]]) # optional - pynormaliz sage: P.volume() # optional - pynormaliz 0 - sage: P.volume(measure='induced') # optional - pynormaliz + sage: P.volume(measure='induced') # optional - pynormaliz # optional - sage.rings.number_field 2.598076211353316? sage: P.volume(measure='induced',engine='normaliz') # optional - pynormaliz 2.598076211353316 @@ -8664,12 +8664,12 @@ def volume(self, measure='ambient', engine='auto', **kwds): sage: P.volume(measure='induced_lattice',engine='latte') # optional - latte_int 3 - sage: Dexact = polytopes.dodecahedron() - sage: v = Dexact.faces(2)[0].as_polyhedron().volume(measure='induced', engine='internal'); v + sage: Dexact = polytopes.dodecahedron() # optional - sage.rings.number_field + sage: v = Dexact.faces(2)[0].as_polyhedron().volume(measure='induced', engine='internal'); v # optional - sage.rings.number_field 1.53406271079097? - sage: v = Dexact.faces(2)[4].as_polyhedron().volume(measure='induced', engine='internal'); v + sage: v = Dexact.faces(2)[4].as_polyhedron().volume(measure='induced', engine='internal'); v # optional - sage.rings.number_field 1.53406271079097? - sage: RDF(v) # abs tol 1e-9 + sage: RDF(v) # abs tol 1e-9 # optional - sage.rings.number_field 1.53406271079044 sage: Dinexact = polytopes.dodecahedron(exact=False) @@ -8680,13 +8680,13 @@ def volume(self, measure='ambient', engine='auto', **kwds): True sage: I = Polyhedron([[-3, 0], [0, 9]]) - sage: I.volume(measure='induced') + sage: I.volume(measure='induced') # optional - sage.rings.number_field 9.48683298050514? sage: I.volume(measure='induced_rational') # optional -- latte_int 3 sage: T = Polyhedron([[3, 0, 0], [0, 4, 0], [0, 0, 5]]) - sage: T.volume(measure='induced') + sage: T.volume(measure='induced') # optional - sage.rings.number_field 13.86542462386205? sage: T.volume(measure='induced_rational') # optional -- latte_int 1/2 @@ -9505,7 +9505,7 @@ def is_lattice_polytope(self): sage: polytopes.cross_polytope(3).is_lattice_polytope() True - sage: polytopes.regular_polygon(5).is_lattice_polytope() + sage: polytopes.regular_polygon(5).is_lattice_polytope() # optional - sage.rings.number_field False """ if not self.is_compact(): @@ -10623,7 +10623,7 @@ def is_combinatorially_isomorphic(self, other, algorithm='bipartite_graph'): All the faces of the 3-dimensional permutahedron are either combinatorially isomorphic to a square or a hexagon:: - sage: H = polytopes.regular_polygon(6) + sage: H = polytopes.regular_polygon(6) # optional - sage.rings.number_field sage: S = polytopes.hypercube(2) sage: P = polytopes.permutahedron(4) sage: all(F.as_polyhedron().is_combinatorially_isomorphic(S) or F.as_polyhedron().is_combinatorially_isomorphic(H) for F in P.faces(2)) @@ -10643,7 +10643,7 @@ def is_combinatorially_isomorphic(self, other, algorithm='bipartite_graph'): ....: return C.intersection(H) sage: [simplex_intersection(k).is_combinatorially_isomorphic(cube_intersection(k)) for k in range(2,5)] [True, True, True] - sage: simplex_intersection(2).is_combinatorially_isomorphic(polytopes.regular_polygon(6)) + sage: simplex_intersection(2).is_combinatorially_isomorphic(polytopes.regular_polygon(6)) # optional - sage.rings.number_field True sage: simplex_intersection(3).is_combinatorially_isomorphic(polytopes.octahedron()) True From b84efa55878dfc84a75887a7c4669a489491d838 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 6 Oct 2021 23:15:39 -0700 Subject: [PATCH 330/511] src/sage/geometry/polyhedron/base.py: Mark more doctests # optional - sage.rings.number_field --- src/sage/geometry/polyhedron/base.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 4272c3b0d29..49b3b645c3d 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -3635,8 +3635,8 @@ def is_compact(self): EXAMPLES:: - sage: p = polytopes.icosahedron() - sage: p.is_compact() + sage: p = polytopes.icosahedron() # optional - sage.rings.number_field + sage: p.is_compact() # optional - sage.rings.number_field True sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0],[0,0,0,1],[1,-1,0,0]]) sage: p.is_compact() @@ -8928,8 +8928,8 @@ def integrate(self, function, measure='ambient', **kwds): Testing a polytope with non-rational vertices:: - sage: P = polytopes.icosahedron() - sage: P.integrate(x^2*y^2*z^2) # optional - latte_int + sage: P = polytopes.icosahedron() # optional - sage.rings.number_field + sage: P.integrate(x^2*y^2*z^2) # optional - latte_int # optional - sage.rings.number_field Traceback (most recent call last): ... TypeError: the base ring must be ZZ, QQ, or RDF From add89fa38eb90d798ea24b797641d4242e57699d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 15:56:21 -0700 Subject: [PATCH 331/511] src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx: Mark doctests using combinatorial polytopes # optional - sage.combinat or # optional - sage.rings.number_field --- .../combinatorial_polyhedron/base.pyx | 132 +++++++++--------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index dd1a2ba54d7..612a4da19b9 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -600,12 +600,13 @@ cdef class CombinatorialPolyhedron(SageObject): TESTS:: - sage: P = polytopes.permutahedron(4) - sage: C = CombinatorialPolyhedron(P) - sage: C1 = loads(C.dumps()) - sage: it = C.face_iter() - sage: it1 = C1.face_iter() - sage: tup = tuple((face.ambient_Vrepresentation(), face.ambient_Hrepresentation()) for face in it) + sage: P = polytopes.permutahedron(4) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: C1 = loads(C.dumps()) # optional - sage.combinat + sage: it = C.face_iter() # optional - sage.combinat + sage: it1 = C1.face_iter() # optional - sage.combinat + sage: tup = tuple((face.ambient_Vrepresentation(), # optional - sage.combinat + ....: face.ambient_Hrepresentation()) for face in it) sage: tup1 = tuple((face.ambient_Vrepresentation(), face.ambient_Hrepresentation()) for face in it1) sage: tup == tup1 True @@ -705,9 +706,9 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(3) - sage: C = CombinatorialPolyhedron(P) - sage: C.Hrepresentation() + sage: P = polytopes.permutahedron(3) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: C.Hrepresentation() # optional - sage.combinat (An inequality (1, 1, 0) x - 3 >= 0, An inequality (-1, -1, 0) x + 5 >= 0, An inequality (0, 1, 0) x - 1 >= 0, @@ -1060,10 +1061,10 @@ cdef class CombinatorialPolyhedron(SageObject): :: - sage: P = polytopes.permutahedron(5, backend='field') - sage: C = P.combinatorial_polyhedron() - sage: C.incidence_matrix.clear_cache() - sage: C.incidence_matrix() == P.incidence_matrix() + sage: P = polytopes.permutahedron(5, backend='field') # optional - sage.combinat + sage: C = P.combinatorial_polyhedron() # optional - sage.combinat + sage: C.incidence_matrix.clear_cache() # optional - sage.combinat + sage: C.incidence_matrix() == P.incidence_matrix() # optional - sage.combinat True The incidence matrix is consistent with @@ -1294,11 +1295,11 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(2) - sage: C = CombinatorialPolyhedron(P) - sage: C.ridges() + sage: P = polytopes.permutahedron(2) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: C.ridges() # optional - sage.combinat ((An inequality (1, 0) x - 1 >= 0, An inequality (-1, 0) x + 2 >= 0),) - sage: C.ridges(add_equations=True) + sage: C.ridges(add_equations=True) # optional - sage.combinat (((An inequality (1, 0) x - 1 >= 0, An equation (1, 1) x - 3 == 0), (An inequality (-1, 0) x + 2 >= 0, An equation (1, 1) x - 3 == 0)),) @@ -1608,9 +1609,9 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) - sage: C = CombinatorialPolyhedron(P) - sage: C.f_vector() + sage: P = polytopes.permutahedron(5) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: C.f_vector() # optional - sage.combinat (1, 120, 240, 150, 30, 1) sage: P = polytopes.cyclic_polytope(6,10) @@ -1620,9 +1621,9 @@ cdef class CombinatorialPolyhedron(SageObject): Using two threads:: - sage: P = polytopes.permutahedron(5) - sage: C = CombinatorialPolyhedron(P) - sage: C.f_vector(num_threads=2) + sage: P = polytopes.permutahedron(5) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: C.f_vector(num_threads=2) # optional - sage.combinat (1, 120, 240, 150, 30, 1) TESTS:: @@ -2320,15 +2321,15 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(4) - sage: C = CombinatorialPolyhedron(P) - sage: C.join_of_Vrep(0,1) + sage: P = polytopes.permutahedron(4) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: C.join_of_Vrep(0,1) # optional - sage.combinat A 1-dimensional face of a 3-dimensional combinatorial polyhedron - sage: C.join_of_Vrep(0,11).ambient_V_indices() + sage: C.join_of_Vrep(0,11).ambient_V_indices() # optional - sage.combinat (0, 1, 10, 11, 12, 13) - sage: C.join_of_Vrep(8).ambient_V_indices() + sage: C.join_of_Vrep(8).ambient_V_indices() # optional - sage.combinat (8,) - sage: C.join_of_Vrep().ambient_V_indices() + sage: C.join_of_Vrep().ambient_V_indices() # optional - sage.combinat () """ return self.face_iter().join_of_Vrep(*indices) @@ -2343,19 +2344,19 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.dodecahedron() - sage: C = CombinatorialPolyhedron(P) - sage: C.meet_of_Hrep(0) + sage: P = polytopes.dodecahedron() # optional - sage.rings.number_field + sage: C = CombinatorialPolyhedron(P) # optional - sage.rings.number_field + sage: C.meet_of_Hrep(0) # optional - sage.rings.number_field A 2-dimensional face of a 3-dimensional combinatorial polyhedron - sage: C.meet_of_Hrep(0).ambient_H_indices() + sage: C.meet_of_Hrep(0).ambient_H_indices() # optional - sage.rings.number_field (0,) - sage: C.meet_of_Hrep(0,1).ambient_H_indices() + sage: C.meet_of_Hrep(0,1).ambient_H_indices() # optional - sage.rings.number_field (0, 1) - sage: C.meet_of_Hrep(0,2).ambient_H_indices() + sage: C.meet_of_Hrep(0,2).ambient_H_indices() # optional - sage.rings.number_field (0, 2) - sage: C.meet_of_Hrep(0,2,3).ambient_H_indices() + sage: C.meet_of_Hrep(0,2,3).ambient_H_indices() # optional - sage.rings.number_field (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) - sage: C.meet_of_Hrep().ambient_H_indices() + sage: C.meet_of_Hrep().ambient_H_indices() # optional - sage.rings.number_field () """ return self.face_iter().meet_of_Hrep(*indices) @@ -2382,38 +2383,38 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) - sage: C = CombinatorialPolyhedron(P) - sage: it = C.face_iter(dimension=2) - sage: face = next(it); face + sage: P = polytopes.permutahedron(5) # optional - sage.rings.number_field + sage: C = CombinatorialPolyhedron(P) # optional - sage.rings.number_field + sage: it = C.face_iter(dimension=2) # optional - sage.rings.number_field + sage: face = next(it); face # optional - sage.rings.number_field A 2-dimensional face of a 4-dimensional combinatorial polyhedron - sage: face.ambient_Vrepresentation() + sage: face.ambient_Vrepresentation() # optional - sage.rings.number_field (A vertex at (1, 3, 2, 5, 4), A vertex at (2, 3, 1, 5, 4), A vertex at (3, 1, 2, 5, 4), A vertex at (3, 2, 1, 5, 4), A vertex at (2, 1, 3, 5, 4), A vertex at (1, 2, 3, 5, 4)) - sage: face = next(it); face + sage: face = next(it); face # optional - sage.rings.number_field A 2-dimensional face of a 4-dimensional combinatorial polyhedron - sage: face.ambient_Vrepresentation() + sage: face.ambient_Vrepresentation() # optional - sage.rings.number_field (A vertex at (2, 1, 4, 5, 3), A vertex at (3, 2, 4, 5, 1), A vertex at (3, 1, 4, 5, 2), A vertex at (1, 3, 4, 5, 2), A vertex at (1, 2, 4, 5, 3), A vertex at (2, 3, 4, 5, 1)) - sage: face.ambient_Hrepresentation() + sage: face.ambient_Hrepresentation() # optional - sage.rings.number_field (An inequality (0, 0, -1, -1, 0) x + 9 >= 0, An inequality (0, 0, 0, -1, 0) x + 5 >= 0, An equation (1, 1, 1, 1, 1) x - 15 == 0) - sage: face.ambient_H_indices() + sage: face.ambient_H_indices() # optional - sage.rings.number_field (25, 29, 30) - sage: face = next(it); face + sage: face = next(it); face # optional - sage.rings.number_field A 2-dimensional face of a 4-dimensional combinatorial polyhedron - sage: face.ambient_H_indices() + sage: face.ambient_H_indices() # optional - sage.rings.number_field (24, 29, 30) - sage: face.ambient_V_indices() + sage: face.ambient_V_indices() # optional - sage.rings.number_field (32, 89, 90, 94) sage: C = CombinatorialPolyhedron([[0,1,2],[0,1,3],[0,2,3],[1,2,3]]) @@ -2508,9 +2509,9 @@ cdef class CombinatorialPolyhedron(SageObject): sage: C.face_lattice().is_isomorphic(C1.face_lattice()) True - sage: P = polytopes.permutahedron(5) - sage: C = CombinatorialPolyhedron(P) - sage: C.face_lattice() + sage: P = polytopes.permutahedron(5) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: C.face_lattice() # optional - sage.combinat Finite lattice containing 542 elements TESTS:: @@ -2520,9 +2521,9 @@ cdef class CombinatorialPolyhedron(SageObject): sage: C.face_lattice().is_isomorphic(P.face_lattice()) True - sage: P = polytopes.permutahedron(4) - sage: C = CombinatorialPolyhedron(P) - sage: C.face_lattice().is_isomorphic(P.face_lattice()) + sage: P = polytopes.permutahedron(4) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: C.face_lattice().is_isomorphic(P.face_lattice()) # optional - sage.combinat True """ from sage.combinat.posets.lattices import FiniteLatticePoset @@ -2731,9 +2732,9 @@ cdef class CombinatorialPolyhedron(SageObject): sage: [face.ambient_V_indices() for face in chain] [(15,), (6, 15), (5, 6, 14, 15), (0, 5, 6, 7, 8, 9, 14, 15)] - sage: P = polytopes.permutahedron(4) - sage: C = P.combinatorial_polyhedron() - sage: chain = C.a_maximal_chain(); chain + sage: P = polytopes.permutahedron(4) # optional - sage.combinat + sage: C = P.combinatorial_polyhedron() # optional - sage.combinat + sage: chain = C.a_maximal_chain(); chain # optional - sage.combinat [A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 1-dimensional face of a 3-dimensional combinatorial polyhedron, A 2-dimensional face of a 3-dimensional combinatorial polyhedron] @@ -3493,14 +3494,15 @@ cdef class CombinatorialPolyhedron(SageObject): TESTS:: - sage: P = polytopes.permutahedron(4) - sage: C = CombinatorialPolyhedron(P) - sage: it = C.face_iter() - sage: tup = tuple((face.ambient_Vrepresentation(),face.ambient_Hrepresentation()) for face in it) - sage: rg = range(1,sum(C.f_vector()) - 1) - sage: tup2 = tuple((C.face_by_face_lattice_index(i).ambient_Vrepresentation(), + sage: P = polytopes.permutahedron(4) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: it = C.face_iter() # optional - sage.combinat + sage: tup = tuple((face.ambient_Vrepresentation(), # optional - sage.combinat + ....: face.ambient_Hrepresentation()) for face in it) + sage: rg = range(1,sum(C.f_vector()) - 1) # optional - sage.combinat + sage: tup2 = tuple((C.face_by_face_lattice_index(i).ambient_Vrepresentation(), # optional - sage.combinat ....: C.face_by_face_lattice_index(i).ambient_Hrepresentation()) for i in rg) - sage: sorted(tup) == sorted(tup2) + sage: sorted(tup) == sorted(tup2) # optional - sage.combinat True sage: P = polytopes.cyclic_polytope(4,10) From a307e92f14c5b6067e36b1e0ee85dacb579fd853 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 15:56:45 -0700 Subject: [PATCH 332/511] src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx: Mark doctests # optional - sage.combinat --- .../polyhedron/combinatorial_polyhedron/conversions.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx index eb1666b99f6..35f8902ad0a 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx @@ -33,9 +33,9 @@ Obtain the Vrepresentation of a polyhedron as facet-incidences stored in sage: from sage.geometry.polyhedron.combinatorial_polyhedron.conversions \ ....: import incidence_matrix_to_bit_rep_of_Vrep - sage: P = polytopes.associahedron(['A',4]) - sage: face_list = incidence_matrix_to_bit_rep_of_Vrep(P.incidence_matrix()) - sage: face_list.compute_dimension() + sage: P = polytopes.associahedron(['A',4]) # optional - sage.combinat + sage: face_list = incidence_matrix_to_bit_rep_of_Vrep(P.incidence_matrix()) # optional - sage.combinat + sage: face_list.compute_dimension() # optional - sage.combinat 4 Obtain the facets of a polyhedron as :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces.ListOfFaces` from a facet list:: From b9ce371da02b21845c29eb8d3633c41406f5fe1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 8 Oct 2021 13:47:09 +0200 Subject: [PATCH 333/511] remove some deprecations in rings/polynomial/ --- .../multi_polynomial_ring_generic.py | 17 ------ .../rings/polynomial/ore_polynomial_ring.py | 52 +++++-------------- 2 files changed, 12 insertions(+), 57 deletions(-) delete mode 100644 src/sage/rings/polynomial/multi_polynomial_ring_generic.py diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_generic.py b/src/sage/rings/polynomial/multi_polynomial_ring_generic.py deleted file mode 100644 index 06198d9d289..00000000000 --- a/src/sage/rings/polynomial/multi_polynomial_ring_generic.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -TESTS:: - - sage: R. = QQbar[] - sage: from sage.rings.polynomial.multi_polynomial_ring_generic import MPolynomialRing_generic - doctest:...: DeprecationWarning: the module sage.rings.polynomial.multi_polynomial_ring_generic is deprecated, use sage.rings.polynomial.multi_polynomial_ring_base instead. - See https://trac.sagemath.org/25563 for details. - sage: isinstance(R, MPolynomialRing_generic) - True -""" - -from sage.misc.superseded import deprecation -deprecation(25563, "the module sage.rings.polynomial.multi_polynomial_ring_generic is deprecated, " - "use sage.rings.polynomial.multi_polynomial_ring_base instead.") - -from .multi_polynomial_ring_base import MPolynomialRing_base -MPolynomialRing_generic = MPolynomialRing_base diff --git a/src/sage/rings/polynomial/ore_polynomial_ring.py b/src/sage/rings/polynomial/ore_polynomial_ring.py index 69d218b9cc9..05ebcf6d1c7 100644 --- a/src/sage/rings/polynomial/ore_polynomial_ring.py +++ b/src/sage/rings/polynomial/ore_polynomial_ring.py @@ -21,7 +21,6 @@ # https://www.gnu.org/licenses/ # *************************************************************************** - from sage.misc.prandom import randint from sage.misc.cachefunc import cached_method from sage.rings.infinity import Infinity @@ -338,7 +337,7 @@ def __classcall_private__(cls, base_ring, twist=None, names=None, sparse=False): raise NotImplementedError("sparse Ore polynomial rings are not implemented") from sage.rings.polynomial import skew_polynomial_ring - constructors = [ ] + constructors = [] if derivation is None: if base_ring in _Fields: try: @@ -467,6 +466,7 @@ def _element_constructor_(self, a=None, check=True, construct=False, **kwds): return C(self, a, check=check, construct=construct) if isinstance(a, Element): P = a.parent() + def build(check): if a.is_zero(): return P.zero() @@ -574,7 +574,7 @@ def _coerce_map_from_(self, P): if P.variable_name() == self.variable_name(): return base_ring.has_coerce_map_from(P.base_ring()) - def _repr_(self): + def _repr_(self) -> str: r""" Return a string representation of ``self``. @@ -602,7 +602,7 @@ def _repr_(self): s = "Sparse " + s return s - def _latex_(self): + def _latex_(self) -> str: r""" Return a latex representation of ``self``. @@ -754,34 +754,6 @@ def twisting_morphism(self, n=1): else: raise ValueError("Unexpected error in iterating the twisting morphism: %s", e) - def twist_map(self, n=1): - r""" - Return the twisting endomorphism defining this Ore polynomial ring - iterated ``n`` times or ``None`` if this Ore polynomial ring is not - twisted by an endomorphism. - - This method is deprecated. Use :meth:`twisting_morphism` instead. - - INPUT: - - - ``n`` - an integer (default: 1) - - EXAMPLES:: - - sage: R. = QQ[] - sage: sigma = R.hom([t+1]) - sage: S. = R['x', sigma] - sage: S.twist_map() - ... - DeprecationWarning: The method twist_map is deprecated; use twisting_morphism (same semantic) instead - See https://trac.sagemath.org/29629 for details. - Ring endomorphism of Univariate Polynomial Ring in t over Rational Field - Defn: t |--> t + 1 - """ - from sage.misc.superseded import deprecation - deprecation(29629, "The method twist_map is deprecated; use twisting_morphism (same semantic) instead") - return self.twisting_morphism(n) - def twisting_derivation(self): r""" Return the twisting derivation defining this Ore polynomial ring @@ -846,7 +818,7 @@ def gen(self, n=0): """ if n != 0: raise IndexError("generator %s not defined" % n) - return self.Element(self, [0,1]) + return self.Element(self, [0, 1]) parameter = gen @@ -943,7 +915,7 @@ def ngens(self): """ return 1 - def random_element(self, degree=(-1,2), monic=False, *args, **kwds): + def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): r""" Return a random Ore polynomial in this ring. @@ -1022,11 +994,11 @@ def random_element(self, degree=(-1,2), monic=False, *args, **kwds): degree = randint(*degree) if degree < 0: return self.zero() - coeffs = [ R.random_element(*args, **kwds) for _ in range(degree) ] + coeffs = [R.random_element(*args, **kwds) for _ in range(degree)] if monic: - return self(coeffs + [ R.one() ]) + return self(coeffs + [R.one()]) else: - return self(coeffs + [ R._random_nonzero_element() ]) + return self(coeffs + [R._random_nonzero_element()]) def random_irreducible(self, degree=2, monic=True, *args, **kwds): r""" @@ -1068,11 +1040,11 @@ def random_irreducible(self, degree=2, monic=True, *args, **kwds): raise ValueError("minimum degree must be less or equal than maximum degree") degree = randint(*degree) while True: - irred = self.random_element((degree,degree), monic=monic) + irred = self.random_element((degree, degree), monic=monic) if irred.is_irreducible(): return irred - def is_commutative(self): + def is_commutative(self) -> bool: r""" Return ``True`` if this Ore polynomial ring is commutative, i.e. if the twisting morphism is the identity and the twisting derivation vanishes. @@ -1101,7 +1073,7 @@ def is_commutative(self): """ return self._morphism is None and self._derivation is None - def is_field(self, proof=False): + def is_field(self, proof=False) -> bool: r""" Return always ``False`` since Ore polynomial rings are never fields. From ee21b90476390af07b88ac03116f00d0c1471678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 8 Oct 2021 14:01:00 +0200 Subject: [PATCH 334/511] fix some doctests --- src/doc/en/constructions/modular_forms.rst | 3 ++- .../explicit_methods_in_number_theory/level_one_forms.rst | 3 ++- .../modular_forms_and_hecke_operators.rst | 6 +++--- src/sage/modular/arithgroup/arithgroup_generic.py | 6 ++---- src/sage/modular/modform/ambient_R.py | 1 + src/sage/modular/modform/ring.py | 1 + src/sage/modular/overconvergent/hecke_series.py | 7 ++++--- src/sage/tests/book_stein_modform.py | 1 + 8 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/doc/en/constructions/modular_forms.rst b/src/doc/en/constructions/modular_forms.rst index 34ab41622db..d3c76fd2d33 100644 --- a/src/doc/en/constructions/modular_forms.rst +++ b/src/doc/en/constructions/modular_forms.rst @@ -4,7 +4,7 @@ Modular forms ************* -One of 's computational specialities is (the very technical field +One of SageMath's computational specialities is (the very technical field of) modular forms and can do a lot more than is even suggested in this very brief introduction. @@ -19,6 +19,7 @@ section "Modular forms" in the Tutorial: :: + sage: from sage.modular.dims import dimension_cusp_forms sage: dimension_cusp_forms(Gamma0(11),2) 1 sage: dimension_cusp_forms(Gamma0(1),12) diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/level_one_forms.rst b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/level_one_forms.rst index 42841173aa0..e2777d45512 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/level_one_forms.rst +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/level_one_forms.rst @@ -52,6 +52,7 @@ rather nice diagonal shape. q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6) ] + sage: from sage.modular.dims import dimension_modular_forms sage: dimension_modular_forms(1,200) 17 sage: B = victor_miller_basis(200, 18) #5 seconds @@ -64,7 +65,7 @@ rather nice diagonal shape. ] Note: Craig Citro has made the above computation an order of -magnitude faster in code he hasn't quite got into Sage yet. +magnitude faster in code he has not quite got into Sage yet. "I'll clean those up and submit them soon, since I need them for something I'm working on ... I'm currently in the process of making diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/modular_forms_and_hecke_operators.rst b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/modular_forms_and_hecke_operators.rst index e9cf689d171..4d223f282d3 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/modular_forms_and_hecke_operators.rst +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/modular_forms_and_hecke_operators.rst @@ -164,14 +164,14 @@ dimension formulas. sage: ModularForms(Gamma1(949284), 456).dimension() 11156973844800 + sage: from sage.modular.dims import dimension_cusp_forms sage: a = [dimension_cusp_forms(Gamma0(N),2) for N in [1..25]]; a [0, 0, ..., 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 2, 2, 1, 0] sage: oeis(a) # optional - internet 0: A001617: Genus of modular group Gamma_0(n). Or, genus of modular curve X_0(n). -Sage doesn't have simple formulas for dimensions of spaces of -modular forms of weight :math:`1`, since such formulas perhaps do -not exist. +Sage does not have simple formulas for dimensions of spaces of modular +forms of weight :math:`1`, since such formulas perhaps do not exist. Diamond Bracket Operators ~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/sage/modular/arithgroup/arithgroup_generic.py b/src/sage/modular/arithgroup/arithgroup_generic.py index a2a97d403d9..58b74d9851b 100644 --- a/src/sage/modular/arithgroup/arithgroup_generic.py +++ b/src/sage/modular/arithgroup/arithgroup_generic.py @@ -952,7 +952,7 @@ def is_congruence(self): def genus(self): r""" - Return the genus of the modular curve of self. + Return the genus of the modular curve of ``self``. EXAMPLES:: @@ -960,6 +960,7 @@ def genus(self): 0 sage: Gamma1(31).genus() 26 + sage: from sage.modular.dims import dimension_cusp_forms sage: Gamma1(157).genus() == dimension_cusp_forms(Gamma1(157), 2) True sage: GammaH(7, [2]).genus() @@ -968,10 +969,7 @@ def genus(self): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 2, 2] sage: [n for n in [1..200] if Gamma0(n).genus() == 1] [11, 14, 15, 17, 19, 20, 21, 24, 27, 32, 36, 49] - - """ - return ZZ(1 + (self.projective_index()) / ZZ(12) - (self.nu2())/ZZ(4) - (self.nu3())/ZZ(3) - self.ncusps()/ZZ(2)) def farey_symbol(self): diff --git a/src/sage/modular/modform/ambient_R.py b/src/sage/modular/modform/ambient_R.py index 97ac8ef61eb..b64334dd231 100644 --- a/src/sage/modular/modform/ambient_R.py +++ b/src/sage/modular/modform/ambient_R.py @@ -95,6 +95,7 @@ def _compute_q_expansion_basis(self, prec=None): sage: S = M.cuspidal_subspace() sage: 0 in [f.valuation() for f in S.basis()] False + sage: from sage.modular.dims import dimension_cusp_forms sage: len(S.basis()) == dimension_cusp_forms(Gamma1(29), 2) True """ diff --git a/src/sage/modular/modform/ring.py b/src/sage/modular/modform/ring.py index 45c9c16126f..8d77f47d7f0 100644 --- a/src/sage/modular/modform/ring.py +++ b/src/sage/modular/modform/ring.py @@ -698,6 +698,7 @@ def generators(self, maxweight=8, prec=10, start_gens=[], start_weight=2): 3 sage: [k for k, _ in v] [2, 2, 4] + sage: from sage.modular.dims import dimension_modular_forms sage: dimension_modular_forms(11,2) 2 sage: dimension_modular_forms(11,4) diff --git a/src/sage/modular/overconvergent/hecke_series.py b/src/sage/modular/overconvergent/hecke_series.py index 220d34696e6..eb5cf8b362c 100644 --- a/src/sage/modular/overconvergent/hecke_series.py +++ b/src/sage/modular/overconvergent/hecke_series.py @@ -66,8 +66,8 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.functions.all import floor, ceil from sage.arith.all import valuation @@ -75,7 +75,7 @@ from sage.rings.finite_rings.finite_field_constructor import GF from sage.modular.modform.all import ModularForms, ModularFormsRing, delta_qexp, eisenstein_series_qexp from sage.modular.dims import dimension_modular_forms -from sage.misc.functional import dimension,transpose,charpoly +from sage.misc.functional import dimension, transpose, charpoly from sage.matrix.constructor import matrix, random_matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.misc import cputime @@ -858,6 +858,7 @@ def compute_Wi(k,p,h,hj,E4,E6): sage: E4 = eisenstein_series_qexp(4, prec, K=S, normalization="constant") sage: E6 = eisenstein_series_qexp(6, prec, K=S, normalization="constant") sage: h = delta_qexp(prec, K=S) / E6^2 + sage: from sage.modular.dims import dimension_modular_forms sage: j = dimension_modular_forms(1, k - (p-1)) sage: hj = h**j sage: c = compute_Wi(k,p,h,hj,E4,E6); c diff --git a/src/sage/tests/book_stein_modform.py b/src/sage/tests/book_stein_modform.py index 14bcacf8888..b0e909c0017 100644 --- a/src/sage/tests/book_stein_modform.py +++ b/src/sage/tests/book_stein_modform.py @@ -444,6 +444,7 @@ (Dirichlet character modulo 13 of conductor 13 mapping 2 |--> -zeta6, Dirichlet character modulo 13 of conductor 1 mapping 2 |--> 1, 1) (Dirichlet character modulo 13 of conductor 1 mapping 2 |--> 1, Dirichlet character modulo 13 of conductor 13 mapping 2 |--> -zeta6 + 1, 1) (Dirichlet character modulo 13 of conductor 13 mapping 2 |--> -zeta6 + 1, Dirichlet character modulo 13 of conductor 1 mapping 2 |--> 1, 1) +sage: from sage.modular.dims import * sage: dimension_cusp_forms(Gamma0(2007),2) 221 sage: dimension_eis(Gamma0(2007),2) From 070eaafcbec4304630b6a1f5864f293c14fd0b8c Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 6 Oct 2021 20:31:13 -0400 Subject: [PATCH 335/511] Trac #32656: don't list psutil as a dependency of pyrsistent. Perusing the pyrsistent source code, we see that the psutil package is needed only to run the pyrsistent test suite -- not in the course of normal usage. Here we remove "psutil" from its list of dependencies, pending the removal of psutil itself, so that `git grep psutil` does not return false positives. --- build/pkgs/pyrsistent/SPKG.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/build/pkgs/pyrsistent/SPKG.rst b/build/pkgs/pyrsistent/SPKG.rst index a0209e2dfdd..d943e31aaf8 100644 --- a/build/pkgs/pyrsistent/SPKG.rst +++ b/build/pkgs/pyrsistent/SPKG.rst @@ -25,7 +25,6 @@ Dependencies - Setuptools - hypothesis - memory-profiler -- psutil - pyperform - pytest - Sphinx From f3a720181e95019ffafc8d0f84f7f1be88a2ae92 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 6 Oct 2021 20:41:06 -0400 Subject: [PATCH 336/511] Trac #32656: remove commented GAP code in quadratic_form__neighbors.py. The sage/quadratic_forms/quadratic_form__neighbors.py file contains some commented code for messing with the GAP memory pool size. The code is of course never run, but since we intend to remove the GAP memory management code altogether in a future commit, now is as good a time as any to prune these dead comments. --- src/sage/quadratic_forms/quadratic_form__neighbors.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/quadratic_forms/quadratic_form__neighbors.py b/src/sage/quadratic_forms/quadratic_form__neighbors.py index 15c31fb8d91..1a6cf3be1c4 100644 --- a/src/sage/quadratic_forms/quadratic_form__neighbors.py +++ b/src/sage/quadratic_forms/quadratic_form__neighbors.py @@ -394,12 +394,7 @@ def orbits_lines_mod_p(self, p): reps:= List(orb, g->g[1]); return reps; end;""") - # run this at startup if you need more memory... - #from sage.interfaces.gap import get_gap_memory_pool_size, set_gap_memory_pool_size - #memory_gap = get_gap_memory_pool_size() - #set_gap_memory_pool_size(1028*memory_gap) orbs_reps = orbs(gens, p) - #set_gap_memory_pool_size(memory_gap) M = GF(p)**self.dim() return [M(m.sage()) for m in orbs_reps if not m.IsZero()] From 44f7442085fd21b4a63ff4979bb5d23f87459158 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 6 Oct 2021 20:51:35 -0400 Subject: [PATCH 337/511] Trac #32656: remove unused import in sage.matrix.matrix_integer_dense. This module imports get_memory_usage() from sage.misc.getusage, but then never calls it. We plan to remove these memory-management functions soon, so we prune the unused import now. --- src/sage/matrix/matrix_integer_dense.pyx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index 5422d985eee..1c0a7e08997 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -4873,7 +4873,6 @@ cdef class Matrix_integer_dense(Matrix_dense): [ 0 0 545], [0, 1, 2] ) """ - from sage.misc.getusage import get_memory_usage cdef Py_ssize_t i, j, piv, n = self._nrows, m = self._ncols from .constructor import matrix From 1bcc8c92aba162b703c0fa5bb2fd7eb3137a6e0d Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 6 Oct 2021 20:53:29 -0400 Subject: [PATCH 338/511] Trac #32656: remove unused sage/modular/modform/test.py. This file contains a bunch of vestigial modular forms tests that were added to the tree in 2008, and which would (if ever run) make use of sage.misc.getusage. Since this file essentially does nothing, we remove it now so that e.g. `git grep getusage` does not show false positives prior to the removal of that module. --- src/sage/modular/modform/test.py | 125 ------------------------------- 1 file changed, 125 deletions(-) delete mode 100644 src/sage/modular/modform/test.py diff --git a/src/sage/modular/modform/test.py b/src/sage/modular/modform/test.py deleted file mode 100644 index c097c36e9ac..00000000000 --- a/src/sage/modular/modform/test.py +++ /dev/null @@ -1,125 +0,0 @@ -r""" -Run difficult calculations that test the modular forms -functionality. - -There is currently no good system for timing these doctests across -all platforms, so I am turning these all into comments (so that they -are not counted against are doctest coverage), noting that we should -use these when (if?) we one day have a good regression testing -system in place. - -Craig Citro - - -from sage.all import * - -m=0; t=0; tw=0 - -def pre(): - global m, t, tw - m = get_memory_usage() - t = cputime() - tw = walltime() - - -def post(): - global m,t - print("total time: %s (wall: %.2f); memory usage diff: %sMB"%(cputime(t), - walltime(tw), get_memory_usage() - m)) - -def test1(): - pre() - for N in range(1,75): - M = ModularForms(N,2) - print(M) - print(M.basis()) - post() - -def test2(): - pre() - for N in range(1,30): - M = ModularForms(Gamma1(N),2) - print(M) - print(M.basis()) - post() - -def test3(): - pre() - for k in range(2,100): - M = ModularForms(1,k) - print(M) - print(M.basis()) - post() - -def test4(): - pre() - for N in range(1,30): - M = ModularForms(N,4, prec=20) - print(M) - print(M.basis()) - post() - -def test5(): - pre() - for N in range(1,50): - M = ModularForms(N,2, prec=30) - print(M) - print(M.basis()) - post() - -def test6(): - pre() - for N in range(225,230): - M = ModularForms(N,2,prec=40) - print(M) - print(M.basis()) - post() - -def test7(): - pre() - for k in range(2,30): - M = ModularForms(2,k) - print(M) - print(M.basis()) - post() - -def test8(): - pre() - for k in range(2,20): - M = ModularForms(Gamma1(3),k) - print(M) - print(M.basis()) - post() - -def test9(): - pre() - for k in range(2,11): - M = ModularForms(Gamma1(8),k) - M.set_precision(M.dimension()+2) - print(M) - print(M.basis()) - post() - -def test10(): - pre() - for k in range(2,11): - M = ModularForms(k,k) - M.set_precision(M.dimension()+2) - print(M) - print(M.basis()) - post() - -def test11(): - pre() - for i in range(100): - M = ModularForms(randint(1,100),randint(2,6)) - print(M) - print(M.basis()) - post() - -def test12(): - S = CuspForms(23,2) - print(S) - print(S.hecke_operator(2)) - print(S.hecke_operator(2).matrix()) -""" From 3ba8c868ea0068b85a126e5addc0560664274637 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 8 Oct 2021 08:40:29 -0400 Subject: [PATCH 339/511] Trac #32656: drop memory usage information from some ring tests. Some of the tests in sage/rings/tests.py report their memory usage alongside the number of tests that have passed. In preparation for the removal of get_memory_usage(), we drop the extra information from the expected (and actual) output. --- src/sage/rings/tests.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/tests.py b/src/sage/rings/tests.py index 4fd37826771..a3ff284f677 100644 --- a/src/sage/rings/tests.py +++ b/src/sage/rings/tests.py @@ -11,7 +11,6 @@ import sage.misc.prandom as random -from sage.misc.all import get_memory_usage from sage.misc.random_testing import random_testing @@ -324,11 +323,11 @@ def test_random_elements(level=MAX_LEVEL, trials=1): sage: import sage.rings.tests sage: sage.rings.tests.test_random_elements(trials=2, seed=0) - survived 0 tests (memory usage = ...) + survived 0 tests Rational Field -1/2 ---- - survived 1 tests (memory usage = ...) + survived 1 tests Number Field in a with defining polynomial x^2 - 61891 with a = 248.7790184079036? -12 ---- @@ -341,8 +340,7 @@ def test_random_elements(level=MAX_LEVEL, trials=1): r = random_rings(level) i = 0 for R in r: - print("survived %s tests (memory usage = %s)" % - (i, get_memory_usage())) + print("survived %s tests" % i) i += 1 print(R) print(R.random_element()) @@ -373,11 +371,11 @@ def test_random_arith(level=MAX_LEVEL, trials=1): sage: import sage.rings.tests sage: sage.rings.tests.test_random_arith(trials=2, seed=0) - survived 0 tests (memory usage = ...) + survived 0 tests Rational Field -1/2 -1/95 49/95 - survived 1 tests (memory usage = ...) + survived 1 tests Number Field in a with defining polynomial x^2 - 15083 with a = 122.81286577553673? a -2*a - 1 2*a - 30164 @@ -389,8 +387,7 @@ def test_random_arith(level=MAX_LEVEL, trials=1): """ i = 0 for x in random_rings(level): - print("survived %s tests (memory usage = %s)" % - (i, get_memory_usage())) + print("survived %s tests" % i) i += 1 print(x) a = x.random_element() From 5aeba4461bbff370eefe9811673850f458e6d932 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 8 Oct 2021 11:10:58 -0400 Subject: [PATCH 340/511] Trac #32656: avoid using psutil in one FriCAS doctest. We will soon drop psutil as a dependency, so we modify the one FriCAS doctest that uses it to avoid doing so. The goal of the previous test was to ensure that a new FriCAS process (with no children) had been started; we now accomplish that by comparing PIDs. --- src/sage/interfaces/fricas.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index 9d1b817d2ba..f04d60dd7e6 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -369,13 +369,15 @@ def _quit_string(self): sage: a.is_running() # optional - fricas False - TESTS:: + TESTS: + + Ensure that a new process is started after ``quit()``:: + + sage: p = fricas.pid() # optional - fricas + sage: fricas.quit() # optional - fricas + sage: fricas.pid() == p # optional - fricas + False - sage: import psutil # optional - fricas - sage: p = fricas.pid(); pr = psutil.Process(p); pr # optional - fricas - - sage: pr.children() # optional - fricas - [] """ return ')quit' From 24319d275b1a54a0cb82fde2b9add66dfac0c173 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 8 Oct 2021 08:42:21 -0400 Subject: [PATCH 341/511] Trac #32656: don't import sage.misc.getusage into sage.misc.all. The sage.misc.getusage module will be removed soon, so we drop this import now. --- src/sage/misc/all.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/misc/all.py b/src/sage/misc/all.py index 375b8e852f1..c43f18eefed 100644 --- a/src/sage/misc/all.py +++ b/src/sage/misc/all.py @@ -71,8 +71,6 @@ from .reset import reset, restore -from .getusage import get_memory_usage - from .mathml import mathml from .defaults import (set_default_variable_name, From cbeaedf2639bb1af3f0e7823b6a027bcc56ea8d3 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 6 Oct 2021 20:50:20 -0400 Subject: [PATCH 342/511] Trac #32656: remove two doctests for memory leaks. Two modules, sage.geometry.polyhedron.base and sage.graphs.bipartite_graph, contain doctests that call get_memory_usage() before and after some operation to detect memory leaks within the operation. Regardless of their merit, we intend to eliminate the psutil package and the get_memory_usage() function with it. In preparation for that, we must remove these two doctests. --- src/sage/geometry/polyhedron/base.py | 12 ------------ src/sage/graphs/bipartite_graph.py | 20 -------------------- 2 files changed, 32 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 47063568802..828b0289262 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -6635,18 +6635,6 @@ def face_lattice(self): sage: [[ls.ambient_V_indices() for ls in lss] for lss in Polyhedron(lines=[(1,0)], vertices=[(0,0)]).face_lattice().level_sets()] [[()], [(0, 1)]] - Test that computing the face lattice does not lead to a memory leak:: - - sage: import gc - sage: _ = gc.collect() - sage: P = polytopes.cube() - sage: a = P.face_lattice() - sage: n = get_memory_usage() - sage: P = polytopes.cube() - sage: a = P.face_lattice() - sage: _ = gc.collect() - sage: n == get_memory_usage() - True """ from sage.combinat.posets.lattices import FiniteLatticePoset return FiniteLatticePoset(self.hasse_diagram()) diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 415f1fa34d9..07ce4ef8b04 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -310,26 +310,6 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): sage: partition = [list(range(5)), list(range(5, 10))] sage: B = BipartiteGraph(P, partition, check=False) - TESTS: - - Test that the memory leak in :trac:`31313` is fixed:: - - sage: A = Matrix(ZZ, 100, 125) - sage: for i in range(A.nrows()): - ....: for j in Subsets(A.ncols()).random_element(): - ....: A[i, j - 1] = 1 - sage: def make_bip_graph(A): - ....: G = BipartiteGraph(A) - sage: for _ in range(10): - ....: make_bip_graph(A) - sage: import gc - sage: _ = gc.collect() - sage: start_mem = get_memory_usage() - sage: for _ in range(10): - ....: make_bip_graph(A) - sage: _ = gc.collect() - sage: print(round(get_memory_usage() - start_mem)) - 0.0 """ if kwds is None: kwds = {'loops': False} From 1ea7b697e812302dfca03a1c7fe41c9a8dc3c98e Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 6 Oct 2021 20:48:22 -0400 Subject: [PATCH 343/511] Trac #32656: eliminate manual GAP memory management. Our GAP interface provides a few functions to get/set the GAP memory pool size. That size used when initializing the GAP interface, being passed as the argument to GAP's "-o" and "-s" command-line flags: https://www.gap-system.org/Manuals/doc/ref/chap3.html In preparation for the removal of psutil and sage.misc.getusage, we remove all of this custom memory management code. The "-o" flag specifies an upper bound, and can simply be omitted. We also omit the "-s" flag in this commit, but that flag is a bit more delicate, since it may affect users with custom GAP modules. However, if the omission of "-s" causes a problem down the line, and if the GAP documentation's assumptions about mmap et al. are correct, then we can simply add back the "-s" flag with a large, static value. --- src/sage/all.py | 8 --- src/sage/interfaces/all.py | 2 +- src/sage/interfaces/gap.py | 93 ------------------------------ src/sage/libs/gap/util.pyx | 30 ++++------ src/sage_docbuild/build_options.py | 4 -- 5 files changed, 12 insertions(+), 125 deletions(-) diff --git a/src/sage/all.py b/src/sage/all.py index 4fa89329e81..6a4035af16a 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -75,14 +75,6 @@ if deprecationWarning in warnings.filters: warnings.filters.remove(deprecationWarning) -# The psutil swap_memory() function tries to collect some statistics -# that may not be available and that we don't need. Hide the warnings -# that are emitted if the stats aren't available (Trac #28329). That -# function is called in two places, so let's install this filter -# before the first one is imported from sage.misc.all below. -warnings.filterwarnings('ignore', category=RuntimeWarning, - message=r"'sin' and 'sout' swap memory stats couldn't be determined") - # Ignore all deprecations from IPython etc. warnings.filterwarnings('ignore', category=DeprecationWarning, module='(IPython|ipykernel|jupyter_client|jupyter_core|nbformat|notebook|ipywidgets|storemagic|jedi)') diff --git a/src/sage/interfaces/all.py b/src/sage/interfaces/all.py index 5bb00ff70b4..0a71ed81ae7 100644 --- a/src/sage/interfaces/all.py +++ b/src/sage/interfaces/all.py @@ -7,7 +7,7 @@ from .axiom import Axiom, axiom from .fricas import FriCAS, fricas -from .gap import gap, gap_reset_workspace, set_gap_memory_pool_size, Gap +from .gap import gap, gap_reset_workspace, Gap from .gap3 import gap3, gap3_version, Gap3 lazy_import('sage.interfaces.genus2reduction', ['genus2reduction', 'Genus2reduction']) from .gfan import gfan, Gfan diff --git a/src/sage/interfaces/gap.py b/src/sage/interfaces/gap.py index 3185fcccc22..5ee4c9edaaf 100644 --- a/src/sage/interfaces/gap.py +++ b/src/sage/interfaces/gap.py @@ -214,95 +214,6 @@ def gap_command(use_workspace_cache=True, local=True): else: return gap_cmd, True -############ Set the GAP memory pool size - -# you should always use get_gap_memory_pool_size() to access this value -gap_memory_pool_size = None - -def set_gap_memory_pool_size(size_in_bytes): - """ - Set the desired gap memory pool size. - - Subsequently started GAP instances will use this as default. - Already running instances are unchanged. - - GAP will only reserve ``size_in_bytes`` address space. Unless you - actually start a big GAP computation, the memory will not be - used. However, corresponding swap space will be reserved so that - GAP will always be able to use the reserved address space if - needed. While nothing is actually written to disc as long as you - don't run a big GAP computation, the reserved swap space will not - be available for other processes. - - INPUT: - - - ``size_in_bytes`` -- integer. The desired memory pool size. - - EXAMPLES:: - - sage: from sage.interfaces.gap import \ - ....: get_gap_memory_pool_size, set_gap_memory_pool_size - sage: n = get_gap_memory_pool_size() - sage: set_gap_memory_pool_size(n) - sage: n == get_gap_memory_pool_size() - True - sage: n # random output - 1534059315 - """ - global gap_memory_pool_size - gap_memory_pool_size = size_in_bytes - -def get_gap_memory_pool_size(): - """ - Get the gap memory pool size for new GAP processes. - - EXAMPLES:: - - sage: from sage.interfaces.gap import get_gap_memory_pool_size - sage: get_gap_memory_pool_size() # random output - 1534059315 - """ - global gap_memory_pool_size - if gap_memory_pool_size is not None: - return gap_memory_pool_size - - import psutil - from sage.misc.getusage import virtual_memory_limit - mem = psutil.virtual_memory() - swap = psutil.swap_memory() - vmax = virtual_memory_limit() - - suggested_size = max(swap.free // 10, mem.available // 50) - # Don't eat all address space if the user set ulimit -v - suggested_size = min(suggested_size, vmax // 10) - # ~220MB is the minimum for long doctests - suggested_size = max(suggested_size, 400 * 1024**2) - return suggested_size - - -def _get_gap_memory_pool_size_MB(): - """ - Return the gap memory pool size suitable for usage on the GAP - command line. - - The GAP 4.5.6 command line parser had issues with large numbers, so - we return it in megabytes. - - OUTPUT: - - String. - - EXAMPLES:: - - sage: from sage.interfaces.gap import \ - ....: _get_gap_memory_pool_size_MB - sage: _get_gap_memory_pool_size_MB() # random output - '1467m' - """ - pool = get_gap_memory_pool_size() - pool = (pool // (1024**2)) + 1 - return str(pool)+'m' - ############ Classes with methods for both the GAP3 and GAP4 interface @@ -1145,10 +1056,6 @@ def __init__(self, max_workspace_size=None, # -T: disable interactive break loop when encountering errors # -E: disable readline support cmd += " -b -p -T -E" - if max_workspace_size is None: - max_workspace_size = _get_gap_memory_pool_size_MB() - cmd += ' -o ' + str(max_workspace_size) - cmd += ' -s ' + str(max_workspace_size) cmd += ' -m 64m ' # attempt at a workaround for http://tracker.gap-system.org/issues/224 cmd += ' ' + os.path.join(SAGE_EXTCODE, 'gap', 'sage.g') Expect.__init__(self, diff --git a/src/sage/libs/gap/util.pyx b/src/sage/libs/gap/util.pyx index f98a71328b3..c501a26140e 100644 --- a/src/sage/libs/gap/util.pyx +++ b/src/sage/libs/gap/util.pyx @@ -238,31 +238,23 @@ cdef initialize(): dlclose(handle) # Define argv variable, which we will pass in to - # initialize GAP. Note that we must pass define the memory pool - # size! + # initialize GAP. cdef char* argv[18] argv[0] = "sage" argv[1] = "-l" s = str_to_bytes(gap_root(), FS_ENCODING, "surrogateescape") argv[2] = s - from sage.interfaces.gap import _get_gap_memory_pool_size_MB - memory_pool = str_to_bytes(_get_gap_memory_pool_size_MB()) - argv[3] = "-o" - argv[4] = memory_pool - argv[5] = "-s" - argv[6] = memory_pool - - argv[7] = "-m" - argv[8] = "64m" - - argv[9] = "-q" # no prompt! - argv[10] = "-E" # don't use readline as this will interfere with Python - argv[11] = "--nointeract" # Implies -T - argv[12] = "-x" # set the "screen" width so that GAP is less likely to - argv[13] = "4096" # insert newlines when printing objects - # 4096 unfortunately is the hard-coded max, but should - # be long enough for most cases + argv[3] = "-m" + argv[4] = "64m" + + argv[5] = "-q" # no prompt! + argv[6] = "-E" # don't use readline as this will interfere with Python + argv[7] = "--nointeract" # Implies -T + argv[8] = "-x" # set the "screen" width so that GAP is less likely to + argv[9] = "4096" # insert newlines when printing objects + # 4096 unfortunately is the hard-coded max, but should + # be long enough for most cases cdef int argc = 14 # argv[argc] must be NULL diff --git a/src/sage_docbuild/build_options.py b/src/sage_docbuild/build_options.py index ddc88a39f0e..44bb883c021 100644 --- a/src/sage_docbuild/build_options.py +++ b/src/sage_docbuild/build_options.py @@ -23,10 +23,6 @@ # Number of threads to use for parallel-building the documentation. NUM_THREADS = int(os.environ.get('SAGE_NUM_THREADS', 1)) -# Minimize GAP RAM usage in the builder, docbuild already uses too much -from sage.interfaces.gap import set_gap_memory_pool_size -set_gap_memory_pool_size(80 * 1024 * 1024) - INCREMENTAL_BUILD = os.path.isdir(SAGE_DOC) # Error out on errors From 082ed59394834a1052d56a5189dfdee2062c652c Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 6 Oct 2021 21:06:06 -0400 Subject: [PATCH 344/511] Trac #32656: use static stack size bound for PARI. Cypari requires that we pass both an initial stack size and a maximum stack size to its Pari() constructor. Previously, the initial stack size was chosen to be 1MB, and the maximum was set at 25% of whatever the virtual_memory_limit() function returns. In preparation for the removal of virtual_memory_limit(), we change that upper limit to a static value of 1GiB. Since this is only a bound, we should be able to increase it in the future if 1GiB proves too low; I quote the docstring for Pari.__init__ from cypari2, When the PARI system is already initialized, the PARI stack is only grown if ``size`` is greater than the current stack... --- src/sage/libs/pari/__init__.py | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/src/sage/libs/pari/__init__.py b/src/sage/libs/pari/__init__.py index 507b98c5098..bc20d9bdf3d 100644 --- a/src/sage/libs/pari/__init__.py +++ b/src/sage/libs/pari/__init__.py @@ -173,30 +173,10 @@ """ def _get_pari_instance(): - # There are two constraints for the virtual stack size: - # 1) on 32-bit systems, even virtual memory can be a scarce - # resource since it is limited by 4GB (of which the kernel - # needs a significant part) - # 2) the system should actually be able to handle a stack size - # as large as the complete virtual stack. - # As a simple heuristic, we set the virtual stack to 1/4 of the - # virtual memory. - from sage.misc.getusage import virtual_memory_limit - - sizemax = virtual_memory_limit() // 4 - - from sage.env import CYGWIN_VERSION - if CYGWIN_VERSION and CYGWIN_VERSION < (2, 5, 2): - # Cygwin's mmap is broken for large NORESERVE mmaps (>~ 4GB) See - # http://trac.sagemath.org/ticket/20463 So we set the max stack - # size to a little below 4GB (putting it right on the margin proves - # too fragile) - # - # The underlying issue is fixed in Cygwin v2.5.2 - sizemax = min(sizemax, 0xf0000000) - from cypari2 import Pari - P = Pari(1000000, sizemax) + 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 b2667b513fe8ad2671e2b9ffabbfd6d176a3d1a4 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 6 Oct 2021 21:06:31 -0400 Subject: [PATCH 345/511] Trac #32656: remove the sage.misc.getusage module. There are no more consumers of this module, and we plan to eliminate the psutil package that it is based upon soon, so here we remove the module itself and drop it from the reference manual. --- src/doc/en/reference/misc/index.rst | 1 - src/sage/misc/getusage.py | 79 ----------------------------- 2 files changed, 80 deletions(-) delete mode 100644 src/sage/misc/getusage.py diff --git a/src/doc/en/reference/misc/index.rst b/src/doc/en/reference/misc/index.rst index dbaa7602438..489fc699447 100644 --- a/src/doc/en/reference/misc/index.rst +++ b/src/doc/en/reference/misc/index.rst @@ -281,7 +281,6 @@ Miscellaneous Inspection and Development Tools sage/docs/instancedoc sage/misc/sageinspect sage/misc/edit_module - sage/misc/getusage sage/misc/classgraph sage/misc/dev_tools sage/misc/function_mangling diff --git a/src/sage/misc/getusage.py b/src/sage/misc/getusage.py deleted file mode 100644 index cf9632dcd54..00000000000 --- a/src/sage/misc/getusage.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -Get resource usage of process - -AUTHORS: - -- William Stein (2006-03-04): initial version - -- Jeroen Demeyer (2016-11-14): implement as thin wrapper over - ``psutil`` package -""" - -# **************************************************************************** -# Copyright (C) 2006 William Stein -# -# Distributed under the terms of the GNU General Public License (GPL) -# as published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. -# https://www.gnu.org/licenses/ -# **************************************************************************** - - -import sys - - -def get_memory_usage(t=None): - """ - Return the memory usage of the current process in megabytes. - - INPUT: - - - ``t`` -- a float (default: None); output of an earlier call. - If this is given, return the current usage minus `t`. - - OUTPUT: a float representing the number of megabytes used. - - EXAMPLES:: - - sage: t = get_memory_usage(); t # random - 873.98046875 - sage: type(t) - <... 'float'> - """ - import psutil - m = psutil.Process().memory_info().vms / 1048576 - if t is None: - return m - else: - return m - t - - -def virtual_memory_limit(): - """ - Return the upper limit for virtual memory usage. - - This is the value set by ``ulimit -v`` at the command line or a - practical limit if no limit is set. In any case, the value is - bounded by ``sys.maxsize``. - - OUTPUT: - - Integer. The virtual memory limit in bytes. - - EXAMPLES:: - - sage: from sage.misc.getusage import virtual_memory_limit - sage: virtual_memory_limit() > 0 - True - sage: virtual_memory_limit() <= sys.maxsize - True - """ - import resource - try: - vmax = resource.getrlimit(resource.RLIMIT_AS)[0] - except resource.error: - vmax = resource.RLIM_INFINITY - if vmax == resource.RLIM_INFINITY: - import psutil - vmax = psutil.virtual_memory().total + psutil.swap_memory().total - return min(vmax, sys.maxsize) From 7c8de66769d155b0e4c58253a94a22a053c359db Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 6 Oct 2021 20:30:45 -0400 Subject: [PATCH 346/511] Trac #32656: remove the psutil package. With all consumers of the psutil package gone, we delete the SPKG itself, and remove all traces of it from the build system. --- Pipfile.m4 | 1 - build/make/Makefile.in | 3 +- build/pkgs/psutil/SPKG.rst | 20 - build/pkgs/psutil/checksums.ini | 4 - build/pkgs/psutil/dependencies | 1 - build/pkgs/psutil/distros/conda.txt | 1 - build/pkgs/psutil/distros/macports.txt | 1 - build/pkgs/psutil/distros/opensuse.txt | 1 - build/pkgs/psutil/distros/repology.txt | 2 - build/pkgs/psutil/install-requires.txt | 1 - build/pkgs/psutil/package-version.txt | 1 - .../pkgs/psutil/patches/cygwin-support.patch | 4644 ----------------- build/pkgs/psutil/spkg-install.in | 7 - build/pkgs/psutil/type | 1 - src/requirements.txt.m4 | 1 - src/setup.cfg.m4 | 1 - 16 files changed, 1 insertion(+), 4689 deletions(-) delete mode 100644 build/pkgs/psutil/SPKG.rst delete mode 100644 build/pkgs/psutil/checksums.ini delete mode 100644 build/pkgs/psutil/dependencies delete mode 100644 build/pkgs/psutil/distros/conda.txt delete mode 100644 build/pkgs/psutil/distros/macports.txt delete mode 100644 build/pkgs/psutil/distros/opensuse.txt delete mode 100644 build/pkgs/psutil/distros/repology.txt delete mode 100644 build/pkgs/psutil/install-requires.txt delete mode 100644 build/pkgs/psutil/package-version.txt delete mode 100644 build/pkgs/psutil/patches/cygwin-support.patch delete mode 100644 build/pkgs/psutil/spkg-install.in delete mode 100644 build/pkgs/psutil/type diff --git a/Pipfile.m4 b/Pipfile.m4 index 76df035b999..e7dd86744a0 100644 --- a/Pipfile.m4 +++ b/Pipfile.m4 @@ -24,7 +24,6 @@ numpy = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../numpy/package-version.txt)')" cysignals = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../cysignals/package-version.txt)')" cypari2 = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../cypari/package-version.txt)')" gmpy2 = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../gmpy2/package-version.txt)')" -psutil = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../psutil/package-version.txt)')" pexpect = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../pexpect/package-version.txt)')" ipython = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../ipython/package-version.txt)')" sympy = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../sympy/package-version.txt)')" diff --git a/build/make/Makefile.in b/build/make/Makefile.in index bd8ca2a99da..acdfd997537 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -288,8 +288,7 @@ python3-SAGE_VENV-no-deps: setuptools-clean # Everything needed to start up Sage using "./sage". Of course, not # every part of Sage will work. It does not include Maxima for example. -SAGERUNTIME = sagelib $(inst_ipython) $(inst_pexpect) \ - $(inst_psutil) +SAGERUNTIME = sagelib $(inst_ipython) $(inst_pexpect) all-sageruntime: toolchain-deps +$(MAKE_REC) $(SAGERUNTIME) diff --git a/build/pkgs/psutil/SPKG.rst b/build/pkgs/psutil/SPKG.rst deleted file mode 100644 index e6ddbcc038b..00000000000 --- a/build/pkgs/psutil/SPKG.rst +++ /dev/null @@ -1,20 +0,0 @@ -psutil: Python library to retrieve information on processes and system utilization -================================================================================== - -Description ------------ - -psutil is a cross-platform library for retrieving information on running -processes and system utilization (CPU, memory, disks, network) in -Python. - -License -------- - -3-clause BSD license - - -Upstream Contact ----------------- - -https://github.com/giampaolo/psutil/ diff --git a/build/pkgs/psutil/checksums.ini b/build/pkgs/psutil/checksums.ini deleted file mode 100644 index 8154abe0921..00000000000 --- a/build/pkgs/psutil/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=psutil-VERSION.tar.gz -sha1=94bfd957caf439c504858dfbfea4c43581698d9c -md5=c9aa2599dcd9e5b59d71b6660d396062 -cksum=1440797320 diff --git a/build/pkgs/psutil/dependencies b/build/pkgs/psutil/dependencies deleted file mode 100644 index da2b0925acd..00000000000 --- a/build/pkgs/psutil/dependencies +++ /dev/null @@ -1 +0,0 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) diff --git a/build/pkgs/psutil/distros/conda.txt b/build/pkgs/psutil/distros/conda.txt deleted file mode 100644 index a4d92cc08db..00000000000 --- a/build/pkgs/psutil/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -psutil diff --git a/build/pkgs/psutil/distros/macports.txt b/build/pkgs/psutil/distros/macports.txt deleted file mode 100644 index 5b16d848a6d..00000000000 --- a/build/pkgs/psutil/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -py-psutil diff --git a/build/pkgs/psutil/distros/opensuse.txt b/build/pkgs/psutil/distros/opensuse.txt deleted file mode 100644 index ac842e4b343..00000000000 --- a/build/pkgs/psutil/distros/opensuse.txt +++ /dev/null @@ -1 +0,0 @@ -python3-psutil diff --git a/build/pkgs/psutil/distros/repology.txt b/build/pkgs/psutil/distros/repology.txt deleted file mode 100644 index 651f0493a90..00000000000 --- a/build/pkgs/psutil/distros/repology.txt +++ /dev/null @@ -1,2 +0,0 @@ -psutil -python:psutil diff --git a/build/pkgs/psutil/install-requires.txt b/build/pkgs/psutil/install-requires.txt deleted file mode 100644 index cafe08598f8..00000000000 --- a/build/pkgs/psutil/install-requires.txt +++ /dev/null @@ -1 +0,0 @@ -psutil >=5.2.0 diff --git a/build/pkgs/psutil/package-version.txt b/build/pkgs/psutil/package-version.txt deleted file mode 100644 index 3d61945d1ef..00000000000 --- a/build/pkgs/psutil/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -5.2.0.p2 diff --git a/build/pkgs/psutil/patches/cygwin-support.patch b/build/pkgs/psutil/patches/cygwin-support.patch deleted file mode 100644 index 96538e65d99..00000000000 --- a/build/pkgs/psutil/patches/cygwin-support.patch +++ /dev/null @@ -1,4644 +0,0 @@ -diff --git a/psutil/__init__.py b/psutil/__init__.py -index 6b88776..cb0f840 100644 ---- a/psutil/__init__.py -+++ b/psutil/__init__.py -@@ -71,6 +71,7 @@ from ._common import OSX - from ._common import POSIX # NOQA - from ._common import SUNOS - from ._common import WINDOWS -+from ._common import CYGWIN - - if LINUX: - # This is public API and it will be retrieved from _pslinux.py -@@ -147,6 +148,10 @@ elif SUNOS: - # _pssunos.py via sys.modules. - PROCFS_PATH = "/proc" - -+elif CYGWIN: -+ PROCFS_PATH = "/proc" -+ from . import _pscygwin as _psplatform -+ - else: # pragma: no cover - raise NotImplementedError('platform %s is not supported' % sys.platform) - -@@ -174,7 +179,7 @@ __all__ = [ - "POWER_TIME_UNKNOWN", "POWER_TIME_UNLIMITED", - - "BSD", "FREEBSD", "LINUX", "NETBSD", "OPENBSD", "OSX", "POSIX", "SUNOS", -- "WINDOWS", -+ "WINDOWS", "CYGWIN", - - # classes - "Process", "Popen", -@@ -326,6 +331,13 @@ _psplatform.ZombieProcess = ZombieProcess - _psplatform.AccessDenied = AccessDenied - _psplatform.TimeoutExpired = TimeoutExpired - -+# TODO: probably having these both is superfulous, and platform -+# specific modules can import these exceptions from _common -+_common.NoSuchProcess = NoSuchProcess -+_common.ZombieProcess = ZombieProcess -+_common.AccessDenied = AccessDenied -+_common.TimeoutExpired = TimeoutExpired -+ - - # ===================================================================== - # --- Process class -@@ -942,7 +954,7 @@ class Process(object): - # (self) it means child's PID has been reused - if self.create_time() <= p.create_time(): - ret.append(p) -- except (NoSuchProcess, ZombieProcess): -+ except (AccessDenied, NoSuchProcess, ZombieProcess): - pass - else: # pragma: no cover - # Windows only (faster) -@@ -964,7 +976,7 @@ class Process(object): - for p in process_iter(): - try: - table[p.ppid()].append(p) -- except (NoSuchProcess, ZombieProcess): -+ except (AccessDenied, NoSuchProcess, ZombieProcess): - pass - else: # pragma: no cover - for pid, ppid in ppid_map.items(): -diff --git a/psutil/_common.py b/psutil/_common.py -index 2497226..7b48ddf 100644 ---- a/psutil/_common.py -+++ b/psutil/_common.py -@@ -32,10 +32,14 @@ if sys.version_info >= (3, 4): - else: - enum = None - -+ -+PY3 = sys.version_info[0] == 3 -+ -+ - __all__ = [ - # OS constants - 'FREEBSD', 'BSD', 'LINUX', 'NETBSD', 'OPENBSD', 'OSX', 'POSIX', 'SUNOS', -- 'WINDOWS', -+ 'WINDOWS', 'CYGWIN', - # connection constants - 'CONN_CLOSE', 'CONN_CLOSE_WAIT', 'CONN_CLOSING', 'CONN_ESTABLISHED', - 'CONN_FIN_WAIT1', 'CONN_FIN_WAIT2', 'CONN_LAST_ACK', 'CONN_LISTEN', -@@ -72,6 +76,7 @@ OPENBSD = sys.platform.startswith("openbsd") - NETBSD = sys.platform.startswith("netbsd") - BSD = FREEBSD or OPENBSD or NETBSD - SUNOS = sys.platform.startswith("sunos") or sys.platform.startswith("solaris") -+CYGWIN = sys.platform.startswith("cygwin") - - - # =================================================================== -@@ -232,6 +237,18 @@ if AF_UNIX is not None: - del AF_INET, AF_INET6, AF_UNIX, SOCK_STREAM, SOCK_DGRAM - - -+# ===================================================================== -+# -- exceptions -+# ===================================================================== -+ -+ -+# these get overwritten on "import psutil" from the __init__.py file -+NoSuchProcess = None -+ZombieProcess = None -+AccessDenied = None -+TimeoutExpired = None -+ -+ - # =================================================================== - # --- utils - # =================================================================== -@@ -334,6 +351,10 @@ def memoize_when_activated(fun): - return wrapper - - -+def get_procfs_path(): -+ return sys.modules['psutil'].PROCFS_PATH -+ -+ - def isfile_strict(path): - """Same as os.path.isfile() but does not swallow EACCES / EPERM - exceptions, see: -@@ -349,6 +370,55 @@ def isfile_strict(path): - return stat.S_ISREG(st.st_mode) - - -+def open_binary(fname, **kwargs): -+ return open(fname, "rb", **kwargs) -+ -+ -+_FS_ENCODING = sys.getfilesystemencoding() -+_ENCODING_ERRORS_HANDLER = 'surrogateescape' -+ -+ -+# TODO: Move some of these functions to ._compat since they're more for py2/3 -+# compatibility than anything else -+ -+def open_text(fname, **kwargs): -+ """On Python 3 opens a file in text mode by using fs encoding and -+ a proper en/decoding errors handler. -+ On Python 2 this is just an alias for open(name, 'rt'). -+ """ -+ if PY3: -+ # See: -+ # https://github.com/giampaolo/psutil/issues/675 -+ # https://github.com/giampaolo/psutil/pull/733 -+ kwargs.setdefault('encoding', _FS_ENCODING) -+ kwargs.setdefault('errors', _ENCODING_ERRORS_HANDLER) -+ return open(fname, "rt", **kwargs) -+ -+ -+if PY3: -+ def decode(s): -+ return s.decode(encoding=_FS_ENCODING, errors=_ENCODING_ERRORS_HANDLER) -+else: -+ def decode(s): -+ return s -+ -+ -+if PY3: -+ def encode(s, encoding=_FS_ENCODING): -+ return s -+else: -+ def encode(s, encoding=_FS_ENCODING): -+ if isinstance(s, str): -+ return s -+ -+ try: -+ return s.encode(encoding) -+ except UnicodeEncodeError: -+ # Filesystem codec failed, return the plain unicode -+ # string (this should never happen). -+ return s -+ -+ - def path_exists_strict(path): - """Same as os.path.exists() but does not swallow EACCES / EPERM - exceptions, see: -@@ -447,3 +517,23 @@ def deprecated_method(replacement): - return getattr(self, replacement)(*args, **kwargs) - return inner - return outer -+ -+ -+def wrap_exceptions(fun): -+ """Decorator which translates bare OSError and IOError exceptions -+ into NoSuchProcess and AccessDenied. -+ """ -+ @functools.wraps(fun) -+ def wrapper(self, *args, **kwargs): -+ try: -+ return fun(self, *args, **kwargs) -+ except EnvironmentError as err: -+ # ENOENT (no such file or directory) gets raised on open(). -+ # ESRCH (no such process) can get raised on read() if -+ # process is gone in meantime. -+ if err.errno in (errno.ENOENT, errno.ESRCH): -+ raise NoSuchProcess(self.pid, self._name) -+ if err.errno in (errno.EPERM, errno.EACCES): -+ raise AccessDenied(self.pid, self._name) -+ raise -+ return wrapper -diff --git a/psutil/_pscygwin.py b/psutil/_pscygwin.py -new file mode 100644 -index 0000000..ffba639 ---- /dev/null -+++ b/psutil/_pscygwin.py -@@ -0,0 +1,891 @@ -+"""Cygwin platform implementation.""" -+ -+# TODO: Large chunks of this module are copy/pasted from the Linux module; -+# seek out further opportunities for refactoring -+ -+from __future__ import division -+ -+import errno -+import os -+import re -+import sys -+from collections import namedtuple -+ -+from . import _common -+from . import _psposix -+from . import _psutil_cygwin as cext -+from . import _psutil_posix as cext_posix -+from ._common import conn_tmap -+from ._common import decode -+from ._common import encode -+from ._common import get_procfs_path -+from ._common import isfile_strict -+from ._common import memoize_when_activated -+from ._common import open_binary -+from ._common import open_text -+from ._common import popenfile -+from ._common import sockfam_to_enum -+from ._common import socktype_to_enum -+from ._common import usage_percent -+from ._common import wrap_exceptions -+from ._compat import PY3 -+from ._compat import b -+from ._compat import lru_cache -+from ._compat import xrange -+ -+if sys.version_info >= (3, 4): -+ import enum -+else: -+ enum = None -+ -+__extra__all__ = ["PROCFS_PATH"] -+ -+ -+# ===================================================================== -+# --- constants -+# ===================================================================== -+ -+ -+if enum is None: -+ AF_LINK = -1 -+else: -+ AddressFamily = enum.IntEnum('AddressFamily', {'AF_LINK': -1}) -+ AF_LINK = AddressFamily.AF_LINK -+ -+ -+# Number of clock ticks per second -+CLOCK_TICKS = os.sysconf("SC_CLK_TCK") -+ -+ -+# TODO: Update me to properly reflect Cygwin-recognized process statuses -+# taken from /fs/proc/array.c -+PROC_STATUSES = { -+ "R": _common.STATUS_RUNNING, -+ "S": _common.STATUS_SLEEPING, -+ "D": _common.STATUS_DISK_SLEEP, -+ "T": _common.STATUS_STOPPED, -+ "t": _common.STATUS_TRACING_STOP, -+ "Z": _common.STATUS_ZOMBIE, -+ "X": _common.STATUS_DEAD, -+ "x": _common.STATUS_DEAD, -+ "K": _common.STATUS_WAKE_KILL, -+ "W": _common.STATUS_WAKING -+} -+ -+CONN_DELETE_TCB = "DELETE_TCB" -+ -+TCP_STATUSES = { -+ cext.MIB_TCP_STATE_ESTAB: _common.CONN_ESTABLISHED, -+ cext.MIB_TCP_STATE_SYN_SENT: _common.CONN_SYN_SENT, -+ cext.MIB_TCP_STATE_SYN_RCVD: _common.CONN_SYN_RECV, -+ cext.MIB_TCP_STATE_FIN_WAIT1: _common.CONN_FIN_WAIT1, -+ cext.MIB_TCP_STATE_FIN_WAIT2: _common.CONN_FIN_WAIT2, -+ cext.MIB_TCP_STATE_TIME_WAIT: _common.CONN_TIME_WAIT, -+ cext.MIB_TCP_STATE_CLOSED: _common.CONN_CLOSE, -+ cext.MIB_TCP_STATE_CLOSE_WAIT: _common.CONN_CLOSE_WAIT, -+ cext.MIB_TCP_STATE_LAST_ACK: _common.CONN_LAST_ACK, -+ cext.MIB_TCP_STATE_LISTEN: _common.CONN_LISTEN, -+ cext.MIB_TCP_STATE_CLOSING: _common.CONN_CLOSING, -+ cext.MIB_TCP_STATE_DELETE_TCB: CONN_DELETE_TCB, -+ cext.PSUTIL_CONN_NONE: _common.CONN_NONE, -+} -+ -+ -+ACCESS_DENIED_SET = frozenset([errno.EPERM, errno.EACCES, -+ cext.ERROR_ACCESS_DENIED]) -+ -+# ===================================================================== -+# -- exceptions -+# ===================================================================== -+ -+ -+# these get overwritten on "import psutil" from the __init__.py file -+NoSuchProcess = None -+ZombieProcess = None -+AccessDenied = None -+TimeoutExpired = None -+ -+ -+# ===================================================================== -+# --- utils -+# ===================================================================== -+ -+ -+# TODO: Alternatively use Cygwin's API to get this, maybe? -+def cygpid_to_winpid(pid): -+ """ -+ Converts Cygwin's internal PID (the one exposed by all POSIX interfaces) -+ to the associated Windows PID. -+ """ -+ -+ procfs_path = get_procfs_path() -+ path = '%s/%s/winpid' % (procfs_path, pid) -+ if not os.path.exists(path): -+ raise NoSuchProcess(pid) -+ -+ with open_binary('%s/%s/winpid' % (procfs_path, pid)) as f: -+ return int(f.readline().strip()) -+ -+ -+def winpid_to_cygpid(pid): -+ """ -+ Converts a Windows PID to its associated Cygwin PID. -+ """ -+ -+ # TODO: This is quite ineffecient--Cygwin provides an API for this that we -+ # can use later -+ procfs_path = get_procfs_path() -+ for path in os.listdir(procfs_path): -+ if not path.isdigit(): -+ continue -+ -+ winpid_path = '%s/%s/winpid' % (procfs_path, path) -+ -+ if not os.path.exists(winpid_path): -+ continue -+ -+ with open_binary(winpid_path) as f: -+ winpid = int(f.readline().strip()) -+ if winpid == pid: -+ return int(path) -+ -+ raise NoSuchProcess(pid) -+ -+ -+@lru_cache(maxsize=512) -+def _win32_QueryDosDevice(s): -+ return cext.win32_QueryDosDevice(s) -+ -+ -+# TODO: Copied almost verbatim from the windows module, except don't -+# us os.path.join since that uses posix sep -+def convert_dos_path(s): -+ # convert paths using native DOS format like: -+ # "\Device\HarddiskVolume1\Windows\systemew\file.txt" -+ # into: "C:\Windows\systemew\file.txt" -+ if PY3 and not isinstance(s, str): -+ s = s.decode('utf8') -+ rawdrive = '\\'.join(s.split('\\')[:3]) -+ driveletter = _win32_QueryDosDevice(rawdrive) -+ return '%s\\%s' % (driveletter, s[len(rawdrive):]) -+ -+ -+# ===================================================================== -+# --- named tuples -+# ===================================================================== -+ -+ -+scputimes = namedtuple('scputimes', ['user', 'system', 'idle']) -+pmem = namedtuple('pmem', ['rss', 'vms', 'shared', 'text', 'lib', 'data', -+ 'dirty']) -+pmem = namedtuple( -+ 'pmem', ['rss', 'vms', -+ 'num_page_faults', 'peak_wset', 'wset', 'peak_paged_pool', -+ 'paged_pool', 'peak_nonpaged_pool', 'nonpaged_pool', -+ 'pagefile', 'peak_pagefile', 'private']) -+pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', )) -+svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free']) -+pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss']) -+pmmap_ext = namedtuple( -+ 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) -+ntpinfo = namedtuple( -+ 'ntpinfo', ['num_handles', 'ctx_switches', 'user_time', 'kernel_time', -+ 'create_time', 'num_threads', 'io_rcount', 'io_wcount', -+ 'io_rbytes', 'io_wbytes']) -+ -+ -+# ===================================================================== -+# --- system memory -+# ===================================================================== -+ -+ -+def _get_meminfo(): -+ mems = {} -+ with open_binary('%s/meminfo' % get_procfs_path()) as f: -+ for line in f: -+ fields = line.split() -+ mems[fields[0].rstrip(b':')] = int(fields[1]) * 1024 -+ -+ return mems -+ -+ -+def virtual_memory(): -+ """Report virtual memory stats. -+ This implementation matches "free" and "vmstat -s" cmdline -+ utility values and procps-ng-3.3.12 source was used as a reference -+ (2016-09-18): -+ https://gitlab.com/procps-ng/procps/blob/ -+ 24fd2605c51fccc375ab0287cec33aa767f06718/proc/sysinfo.c -+ For reference, procps-ng-3.3.10 is the version available on Ubuntu -+ 16.04. -+ -+ Note about "available" memory: up until psutil 4.3 it was -+ calculated as "avail = (free + buffers + cached)". Now -+ "MemAvailable:" column (kernel 3.14) from /proc/meminfo is used as -+ it's more accurate. -+ That matches "available" column in newer versions of "free". -+ """ -+ mems = _get_meminfo() -+ -+ # /proc doc states that the available fields in /proc/meminfo vary -+ # by architecture and compile options, but these 3 values are also -+ # returned by sysinfo(2); as such we assume they are always there. -+ total = mems[b'MemTotal'] -+ free = mems[b'MemFree'] -+ -+ used = total - free -+ -+ # On Windows we are treating avail and free as the same -+ # TODO: Are they really though? -+ avail = free -+ -+ percent = usage_percent((total - avail), total, _round=1) -+ -+ return svmem(total, avail, percent, used, free) -+ -+ -+def swap_memory(): -+ mems = _get_meminfo() -+ total = mems[b'SwapTotal'] -+ free = mems[b'SwapFree'] -+ used = total - free -+ percent = usage_percent(used, total, _round=1) -+ return _common.sswap(total, used, free, percent, 0, 0) -+ -+ -+# ===================================================================== -+# --- CPUs -+# ===================================================================== -+ -+ -+def cpu_times(): -+ """Return a named tuple representing the following system-wide -+ CPU times: -+ (user, nice, system, idle, iowait, irq, softirq [steal, [guest, -+ [guest_nice]]]) -+ Last 3 fields may not be available on all Linux kernel versions. -+ """ -+ procfs_path = get_procfs_path() -+ with open_binary('%s/stat' % procfs_path) as f: -+ values = f.readline().split() -+ fields = values[1:2] + values[3:len(scputimes._fields) + 2] -+ fields = [float(x) / CLOCK_TICKS for x in fields] -+ return scputimes(*fields) -+ -+ -+def per_cpu_times(): -+ """Return a list of namedtuple representing the CPU times -+ for every CPU available on the system. -+ """ -+ procfs_path = get_procfs_path() -+ cpus = [] -+ with open_binary('%s/stat' % procfs_path) as f: -+ # get rid of the first line which refers to system wide CPU stats -+ f.readline() -+ for line in f: -+ if line.startswith(b'cpu'): -+ values = line.split() -+ fields = values[1:2] + values[3:len(scputimes._fields) + 2] -+ fields = [float(x) / CLOCK_TICKS for x in fields] -+ entry = scputimes(*fields) -+ cpus.append(entry) -+ return cpus -+ -+ -+def cpu_count_logical(): -+ """Return the number of logical CPUs in the system.""" -+ try: -+ return os.sysconf("SC_NPROCESSORS_ONLN") -+ except ValueError: -+ # as a second fallback we try to parse /proc/cpuinfo -+ num = 0 -+ with open_binary('%s/cpuinfo' % get_procfs_path()) as f: -+ for line in f: -+ if line.lower().startswith(b'processor'): -+ num += 1 -+ -+ # unknown format (e.g. amrel/sparc architectures), see: -+ # https://github.com/giampaolo/psutil/issues/200 -+ # try to parse /proc/stat as a last resort -+ if num == 0: -+ search = re.compile('cpu\d') -+ with open_text('%s/stat' % get_procfs_path()) as f: -+ for line in f: -+ line = line.split(' ')[0] -+ if search.match(line): -+ num += 1 -+ -+ if num == 0: -+ # mimic os.cpu_count() -+ return None -+ return num -+ -+ -+def cpu_count_physical(): -+ """Return the number of physical cores in the system.""" -+ mapping = {} -+ current_info = {} -+ with open_binary('%s/cpuinfo' % get_procfs_path()) as f: -+ for line in f: -+ line = line.strip().lower() -+ if not line: -+ # new section -+ if (b'physical id' in current_info and -+ b'cpu cores' in current_info): -+ mapping[current_info[b'physical id']] = \ -+ current_info[b'cpu cores'] -+ current_info = {} -+ else: -+ # ongoing section -+ if (line.startswith(b'physical id') or -+ line.startswith(b'cpu cores')): -+ key, value = line.split(b'\t:', 1) -+ current_info[key] = int(value) -+ -+ # mimic os.cpu_count() -+ return sum(mapping.values()) or None -+ -+ -+# TODO: Works mostly the same as on Linux, but softirq is not available; -+# meanwhile the Windows module supports number of system calls, but this -+# implementation does not. There's also a question of whether we want it -+# to count Cygwin "system" calls, actual Windows system calls, or what... -+# It's a somewhat ill-defined field on Cygwin; may have to come back to it -+# TODO: Depending on what we decide to do about syscalls, this implementation -+# could be shared with the Linux implementation with some minor tweaks to the -+# latter -+def cpu_stats(): -+ with open_binary('%s/stat' % get_procfs_path()) as f: -+ ctx_switches = None -+ interrupts = None -+ for line in f: -+ if line.startswith(b'ctxt'): -+ ctx_switches = int(line.split()[1]) -+ elif line.startswith(b'intr'): -+ interrupts = int(line.split()[1]) -+ if ctx_switches is not None and interrupts is not None: -+ break -+ syscalls = 0 -+ soft_interrupts = 0 -+ return _common.scpustats( -+ ctx_switches, interrupts, soft_interrupts, syscalls) -+ -+ -+# ===================================================================== -+# --- network -+# ===================================================================== -+ -+ -+# TODO: This might merit a little further work to get the "friendly" -+# interface names instead of interface UUIDs -+net_if_addrs = cext_posix.net_if_addrs -+ -+ -+def net_connections(kind, _pid=-1): -+ """Return socket connections. If pid == -1 return system-wide -+ connections (as opposed to connections opened by one process only). -+ """ -+ if kind not in conn_tmap: -+ raise ValueError("invalid %r kind argument; choose between %s" -+ % (kind, ', '.join([repr(x) for x in conn_tmap]))) -+ elif kind == 'unix': -+ raise ValueError("invalid %r kind argument; although UNIX sockets " -+ "are supported on Cygwin it is not possible to " -+ "enumerate the UNIX sockets opened by a process" -+ % kind) -+ -+ families, types = conn_tmap[kind] -+ if _pid > 0: -+ _pid = cygpid_to_winpid(_pid) -+ -+ # Note: This lists *all* net connections on the system, not just ones by -+ # Cygwin processes; below we whittle it down just to Cygwin processes, but -+ # we might consider an extra option for showing non-Cygwin processes as -+ # well -+ rawlist = cext.net_connections(_pid, families, types) -+ ret = set() -+ for item in rawlist: -+ fd, fam, type, laddr, raddr, status, pid = item -+ status = TCP_STATUSES[status] -+ fam = sockfam_to_enum(fam) -+ type = socktype_to_enum(type) -+ if _pid == -1: -+ try: -+ pid = winpid_to_cygpid(pid) -+ except NoSuchProcess: -+ continue -+ nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid) -+ else: -+ nt = _common.pconn(fd, fam, type, laddr, raddr, status) -+ ret.add(nt) -+ return list(ret) -+ -+ -+def net_if_stats(): -+ ret = {} -+ if_stats = cext.net_if_stats() -+ # NOTE: Cygwin does some tricky things in how getifaddrs is handled -+ # which our net_if_stats does not do, such that net_if_stats does not -+ # return all the same interfaces as net_if_stats, so here we artifically -+ # limit the net_if_stats() results to just those interfaces returned by -+ # net_if_addrs -+ if_names = set(addr[0] for addr in net_if_addrs()) -+ for name, items in if_stats.items(): -+ if name not in if_names: -+ continue -+ name = encode(name) -+ isup, duplex, speed, mtu = items -+ if hasattr(_common, 'NicDuplex'): -+ duplex = _common.NicDuplex(duplex) -+ ret[name] = _common.snicstats(isup, duplex, speed, mtu) -+ return ret -+ -+ -+def net_io_counters(): -+ ret = cext.net_io_counters() -+ return dict([(encode(k), v) for k, v in ret.items()]) -+ -+ -+# ===================================================================== -+# --- sensors -+# ===================================================================== -+ -+ -+# TODO: Copied verbatim from the Windows module -+def sensors_battery(): -+ """Return battery information.""" -+ # For constants meaning see: -+ # https://msdn.microsoft.com/en-us/library/windows/desktop/ -+ # aa373232(v=vs.85).aspx -+ acline_status, flags, percent, secsleft = cext.sensors_battery() -+ power_plugged = acline_status == 1 -+ no_battery = bool(flags & 128) -+ charging = bool(flags & 8) -+ -+ if no_battery: -+ return None -+ if power_plugged or charging: -+ secsleft = _common.POWER_TIME_UNLIMITED -+ elif secsleft == -1: -+ secsleft = _common.POWER_TIME_UNKNOWN -+ -+ return _common.sbattery(percent, secsleft, power_plugged) -+ -+ -+# ===================================================================== -+# --- disks -+# ===================================================================== -+ -+ -+disk_io_counters = cext.disk_io_counters -+ -+ -+disk_usage = _psposix.disk_usage -+ -+ -+# TODO: Copied verbatim from the Linux module; refactor -+def disk_partitions(all=False): -+ """Return mounted disk partitions as a list of namedtuples""" -+ fstypes = set() -+ with open_text("%s/filesystems" % get_procfs_path()) as f: -+ for line in f: -+ line = line.strip() -+ if not line.startswith("nodev"): -+ fstypes.add(line.strip()) -+ else: -+ # ignore all lines starting with "nodev" except "nodev zfs" -+ fstype = line.split("\t")[1] -+ if fstype == "zfs": -+ fstypes.add("zfs") -+ -+ retlist = [] -+ partitions = cext.disk_partitions() -+ for partition in partitions: -+ device, mountpoint, fstype, opts = partition -+ if device == 'none': -+ device = '' -+ if not all: -+ if device == '' or fstype not in fstypes: -+ continue -+ ntuple = _common.sdiskpart(device, mountpoint, fstype, opts) -+ retlist.append(ntuple) -+ return retlist -+ -+ -+# ===================================================================== -+# --- other system functions -+# ===================================================================== -+ -+ -+def boot_time(): -+ """The system boot time expressed in seconds since the epoch.""" -+ return cext.boot_time() -+ -+ -+# TODO: Copied verbatim from the Linux module -+def users(): -+ """Return currently connected users as a list of namedtuples.""" -+ retlist = [] -+ rawlist = cext.users() -+ for item in rawlist: -+ user, tty, hostname, tstamp, user_process = item -+ # note: the underlying C function includes entries about -+ # system boot, run level and others. We might want -+ # to use them in the future. -+ if not user_process: -+ continue -+ if hostname == ':0.0' or hostname == ':0': -+ hostname = 'localhost' -+ nt = _common.suser(user, tty or None, hostname, tstamp) -+ retlist.append(nt) -+ return retlist -+ -+ -+# ===================================================================== -+# --- processes -+# ===================================================================== -+ -+ -+def pids(): -+ """Returns a list of PIDs currently running on the system.""" -+ return [int(x) for x in os.listdir(b(get_procfs_path())) if x.isdigit()] -+ -+ -+def pid_exists(pid): -+ """Check For the existence of a unix pid.""" -+ return _psposix.pid_exists(pid) -+ -+ -+class Process(object): -+ """Cygwin process implementation.""" -+ -+ __slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_winpid"] -+ -+ def __init__(self, pid): -+ self.pid = pid -+ self._name = None -+ self._ppid = None -+ self._procfs_path = get_procfs_path() -+ self._winpid = cygpid_to_winpid(pid) -+ -+ @memoize_when_activated -+ def _parse_stat_file(self): -+ """Parse /proc/{pid}/stat file. Return a list of fields where -+ process name is in position 0. -+ Using "man proc" as a reference: where "man proc" refers to -+ position N, always subscract 2 (e.g starttime pos 22 in -+ 'man proc' == pos 20 in the list returned here). -+ """ -+ -+ stat_filename = "%s/%s/stat" % (self._procfs_path, self.pid) -+ -+ # NOTE: On Cygwin, if the stat file exists but reading it raises an -+ # EINVAL, this indicates that we are probably looking at a zombie -+ # process (this doesn't happen in all cases--seems to be a bug in -+ # Cygwin) -+ try: -+ with open_binary(stat_filename) as f: -+ data = f.read() -+ except IOError as err: -+ if (err.errno == errno.EINVAL and -+ os.path.exists(err.filename)): -+ raise ZombieProcess(self.pid, self._name, self._ppid) -+ -+ raise -+ # Process name is between parentheses. It can contain spaces and -+ # other parentheses. This is taken into account by looking for -+ # the first occurrence of "(" and the last occurence of ")". -+ rpar = data.rfind(b')') -+ name = data[data.find(b'(') + 1:rpar] -+ fields_after_name = data[rpar + 2:].split() -+ return [name] + fields_after_name -+ -+ @memoize_when_activated -+ def _read_status_file(self): -+ with open_binary("%s/%s/status" % (self._procfs_path, self.pid)) as f: -+ return f.read() -+ -+ @memoize_when_activated -+ def oneshot_info(self): -+ """Return multiple information about this process as a -+ raw tuple. -+ """ -+ return cext.proc_info(self._winpid) -+ -+ def oneshot_enter(self): -+ self._parse_stat_file.cache_activate() -+ self._read_status_file.cache_activate() -+ self.oneshot_info.cache_activate() -+ -+ def oneshot_exit(self): -+ self._parse_stat_file.cache_deactivate() -+ self._read_status_file.cache_deactivate() -+ self.oneshot_info.cache_deactivate() -+ -+ @wrap_exceptions -+ def name(self): -+ name = self._parse_stat_file()[0] -+ if PY3: -+ name = decode(name) -+ # XXX - gets changed later and probably needs refactoring -+ return name -+ -+ def exe(self): -+ try: -+ return os.readlink("%s/%s/exe" % (self._procfs_path, self.pid)) -+ except OSError as err: -+ if err.errno in (errno.ENOENT, errno.ESRCH): -+ # no such file error; might be raised also if the -+ # path actually exists for system processes with -+ # low pids (about 0-20) -+ if os.path.lexists("%s/%s" % (self._procfs_path, self.pid)): -+ return "" -+ else: -+ if not _psposix.pid_exists(self.pid): -+ raise NoSuchProcess(self.pid, self._name) -+ else: -+ raise ZombieProcess(self.pid, self._name, self._ppid) -+ if err.errno in (errno.EPERM, errno.EACCES): -+ raise AccessDenied(self.pid, self._name) -+ raise -+ -+ @wrap_exceptions -+ def cmdline(self): -+ with open_text("%s/%s/cmdline" % (self._procfs_path, self.pid)) as f: -+ data = f.read() -+ if not data: -+ # may happen in case of zombie process -+ return [] -+ if data.endswith('\x00'): -+ data = data[:-1] -+ return [x for x in data.split('\x00')] -+ -+ # TODO: /proc//environ will be available in newer versions of -+ # Cygwin--do a version check and provide it if available. -+ -+ @wrap_exceptions -+ def terminal(self): -+ tty_nr = int(self._parse_stat_file()[5]) -+ tmap = _psposix.get_terminal_map() -+ try: -+ return tmap[tty_nr] -+ except KeyError: -+ return None -+ -+ @wrap_exceptions -+ def io_counters(self): -+ try: -+ ret = cext.proc_io_counters(self._winpid) -+ except OSError as err: -+ if err.errno in ACCESS_DENIED_SET: -+ nt = ntpinfo(*self.oneshot_info()) -+ ret = (nt.io_rcount, nt.io_wcount, nt.io_rbytes, nt.io_wbytes) -+ else: -+ raise -+ return _common.pio(*ret) -+ -+ @wrap_exceptions -+ def cpu_times(self): -+ values = self._parse_stat_file() -+ utime = float(values[12]) / CLOCK_TICKS -+ stime = float(values[13]) / CLOCK_TICKS -+ children_utime = float(values[14]) / CLOCK_TICKS -+ children_stime = float(values[15]) / CLOCK_TICKS -+ return _common.pcputimes(utime, stime, children_utime, children_stime) -+ -+ @wrap_exceptions -+ def wait(self, timeout=None): -+ try: -+ return _psposix.wait_pid(self.pid, timeout) -+ except _psposix.TimeoutExpired: -+ raise TimeoutExpired(timeout, self.pid, self._name) -+ -+ @wrap_exceptions -+ def create_time(self): -+ try: -+ return cext.proc_create_time(self._winpid) -+ except OSError as err: -+ if err.errno in ACCESS_DENIED_SET: -+ return ntpinfo(*self.oneshot_info()).create_time -+ raise -+ -+ def _get_raw_meminfo(self): -+ try: -+ return cext.proc_memory_info(self._winpid) -+ except OSError as err: -+ if err.errno in ACCESS_DENIED_SET: -+ # TODO: the C ext can probably be refactored in order -+ # to get this from cext.proc_info() -+ return cext.proc_memory_info_2(self._winpid) -+ raise -+ -+ @wrap_exceptions -+ def memory_info(self): -+ # on Windows RSS == WorkingSetSize and VMS == PagefileUsage. -+ # Underlying C function returns fields of PROCESS_MEMORY_COUNTERS -+ # struct. -+ t = self._get_raw_meminfo() -+ rss = t[2] # wset -+ vms = t[7] # pagefile -+ return pmem(*(rss, vms, ) + t) -+ -+ @wrap_exceptions -+ def memory_full_info(self): -+ basic_mem = self.memory_info() -+ uss = cext.proc_memory_uss(self._winpid) -+ return pfullmem(*basic_mem + (uss, )) -+ -+ def memory_maps(self): -+ try: -+ raw = cext.proc_memory_maps(self._winpid) -+ except OSError as err: -+ # XXX - can't use wrap_exceptions decorator as we're -+ # returning a generator; probably needs refactoring. -+ if err.errno in ACCESS_DENIED_SET: -+ raise AccessDenied(self.pid, self._name) -+ if err.errno == errno.ESRCH: -+ raise NoSuchProcess(self.pid, self._name) -+ raise -+ else: -+ for addr, perm, path, rss in raw: -+ path = cext.winpath_to_cygpath(convert_dos_path(path)) -+ addr = hex(addr) -+ yield (addr, perm, path, rss) -+ -+ @wrap_exceptions -+ def cwd(self): -+ return os.readlink("%s/%s/cwd" % (self._procfs_path, self.pid)) -+ -+ @wrap_exceptions -+ def num_ctx_switches(self): -+ ctx_switches = ntpinfo(*self.oneshot_info()).ctx_switches -+ # only voluntary ctx switches are supported -+ return _common.pctxsw(ctx_switches, 0) -+ -+ @wrap_exceptions -+ def num_threads(self): -+ return ntpinfo(*self.oneshot_info()).num_threads -+ -+ @wrap_exceptions -+ def threads(self): -+ rawlist = cext.proc_threads(self._winpid) -+ retlist = [] -+ for thread_id, utime, stime in rawlist: -+ ntuple = _common.pthread(thread_id, utime, stime) -+ retlist.append(ntuple) -+ return retlist -+ -+ @wrap_exceptions -+ def nice_get(self): -+ # Use C implementation -+ return cext_posix.getpriority(self.pid) -+ -+ @wrap_exceptions -+ def nice_set(self, value): -+ return cext_posix.setpriority(self.pid, value) -+ -+ @wrap_exceptions -+ def cpu_affinity_get(self): -+ def from_bitmask(x): -+ return [i for i in xrange(64) if (1 << i) & x] -+ bitmask = cext.proc_cpu_affinity_get(self._winpid) -+ return from_bitmask(bitmask) -+ -+ @wrap_exceptions -+ def cpu_affinity_set(self, value): -+ def to_bitmask(l): -+ if not l: -+ raise ValueError("invalid argument %r" % l) -+ out = 0 -+ for bit in l: -+ out |= 2 ** bit -+ return out -+ -+ # SetProcessAffinityMask() states that ERROR_INVALID_PARAMETER -+ # is returned for an invalid CPU but this seems not to be true, -+ # therefore we check CPUs validy beforehand. -+ allcpus = list(range(len(per_cpu_times()))) -+ for cpu in value: -+ if cpu not in allcpus: -+ if not isinstance(cpu, (int, long)): -+ raise TypeError( -+ "invalid CPU %r; an integer is required" % cpu) -+ else: -+ raise ValueError("invalid CPU %r" % cpu) -+ -+ bitmask = to_bitmask(value) -+ try: -+ cext.proc_cpu_affinity_set(self._winpid, bitmask) -+ except OSError as exc: -+ if exc.errno == errno.EIO: -+ raise AccessDenied(self.pid, self._name) -+ -+ @wrap_exceptions -+ def status(self): -+ letter = self._parse_stat_file()[1] -+ if PY3: -+ letter = letter.decode() -+ # XXX is '?' legit? (we're not supposed to return it anyway) -+ return PROC_STATUSES.get(letter, '?') -+ -+ @wrap_exceptions -+ def open_files(self): -+ retlist = [] -+ files = os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)) -+ hit_enoent = False -+ for fd in files: -+ file = "%s/%s/fd/%s" % (self._procfs_path, self.pid, fd) -+ try: -+ path = os.readlink(file) -+ except OSError as err: -+ # ENOENT == file which is gone in the meantime -+ if err.errno in (errno.ENOENT, errno.ESRCH): -+ hit_enoent = True -+ continue -+ elif err.errno == errno.EINVAL: -+ # not a link -+ continue -+ else: -+ raise -+ else: -+ # If path is not an absolute there's no way to tell -+ # whether it's a regular file or not, so we skip it. -+ # A regular file is always supposed to be have an -+ # absolute path though. -+ if path.startswith('/') and isfile_strict(path): -+ ntuple = popenfile(path, int(fd)) -+ retlist.append(ntuple) -+ if hit_enoent: -+ # raise NSP if the process disappeared on us -+ os.stat('%s/%s' % (self._procfs_path, self.pid)) -+ return retlist -+ -+ @wrap_exceptions -+ def connections(self, kind='inet'): -+ return net_connections(kind, _pid=self.pid) -+ -+ @wrap_exceptions -+ def num_fds(self): -+ return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid))) -+ -+ @wrap_exceptions -+ def ppid(self): -+ return int(self._parse_stat_file()[2]) -+ -+ @wrap_exceptions -+ def uids(self, _uids_re=re.compile(b'Uid:\t(\d+)')): -+ # More or less the same as on Linux, but the fields are separated by -+ # spaces instead of tabs; and anyways there is no difference on Cygwin -+ # between real, effective, and saved uids. -+ # TODO: We could use the same regexp on both Linux and Cygwin by just -+ # changing the Linux regexp to treat whitespace more flexibly -+ data = self._read_status_file() -+ real = _uids_re.findall(data)[0] -+ return _common.puids(int(real), int(real), int(real)) -+ -+ @wrap_exceptions -+ def gids(self, _gids_re=re.compile(b'Gid:\t(\d+)')): -+ # See note in uids -+ data = self._read_status_file() -+ real = _gids_re.findall(data)[0] -+ return _common.pgids(int(real), int(real), int(real)) -diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py -index 533b548..51852b1 100644 ---- a/psutil/_pslinux.py -+++ b/psutil/_pslinux.py -@@ -9,7 +9,6 @@ from __future__ import division - import base64 - import collections - import errno --import functools - import glob - import os - import re -@@ -25,9 +24,13 @@ from . import _common - from . import _psposix - from . import _psutil_linux as cext - from . import _psutil_posix as cext_posix -+from ._common import decode -+from ._common import get_procfs_path - from ._common import isfile_strict - from ._common import memoize - from ._common import memoize_when_activated -+from ._common import open_binary -+from ._common import open_text - from ._common import parse_environ_block - from ._common import NIC_DUPLEX_FULL - from ._common import NIC_DUPLEX_HALF -@@ -35,6 +38,7 @@ from ._common import NIC_DUPLEX_UNKNOWN - from ._common import path_exists_strict - from ._common import supports_ipv6 - from ._common import usage_percent -+from ._common import wrap_exceptions - from ._compat import b - from ._compat import basestring - from ._compat import long -@@ -83,9 +87,7 @@ BOOT_TIME = None # set later - # speedup, see: https://github.com/giampaolo/psutil/issues/708 - BIGGER_FILE_BUFFERING = -1 if PY3 else 8192 - LITTLE_ENDIAN = sys.byteorder == 'little' --if PY3: -- FS_ENCODING = sys.getfilesystemencoding() -- ENCODING_ERRORS_HANDLER = 'surrogateescape' -+ - if enum is None: - AF_LINK = socket.AF_PACKET - else: -@@ -186,37 +188,6 @@ pio = namedtuple('pio', ['read_count', 'write_count', - # ===================================================================== - - --def open_binary(fname, **kwargs): -- return open(fname, "rb", **kwargs) -- -- --def open_text(fname, **kwargs): -- """On Python 3 opens a file in text mode by using fs encoding and -- a proper en/decoding errors handler. -- On Python 2 this is just an alias for open(name, 'rt'). -- """ -- if PY3: -- # See: -- # https://github.com/giampaolo/psutil/issues/675 -- # https://github.com/giampaolo/psutil/pull/733 -- kwargs.setdefault('encoding', FS_ENCODING) -- kwargs.setdefault('errors', ENCODING_ERRORS_HANDLER) -- return open(fname, "rt", **kwargs) -- -- --if PY3: -- def decode(s): -- return s.decode(encoding=FS_ENCODING, errors=ENCODING_ERRORS_HANDLER) --else: -- def decode(s): -- return s -- -- --def get_procfs_path(): -- """Return updated psutil.PROCFS_PATH constant.""" -- return sys.modules['psutil'].PROCFS_PATH -- -- - def readlink(path): - """Wrapper around os.readlink().""" - assert isinstance(path, basestring), path -@@ -1304,26 +1275,6 @@ def pid_exists(pid): - return pid in pids() - - --def wrap_exceptions(fun): -- """Decorator which translates bare OSError and IOError exceptions -- into NoSuchProcess and AccessDenied. -- """ -- @functools.wraps(fun) -- def wrapper(self, *args, **kwargs): -- try: -- return fun(self, *args, **kwargs) -- except EnvironmentError as err: -- # ENOENT (no such file or directory) gets raised on open(). -- # ESRCH (no such process) can get raised on read() if -- # process is gone in meantime. -- if err.errno in (errno.ENOENT, errno.ESRCH): -- raise NoSuchProcess(self.pid, self._name) -- if err.errno in (errno.EPERM, errno.EACCES): -- raise AccessDenied(self.pid, self._name) -- raise -- return wrapper -- -- - class Process(object): - """Linux process implementation.""" - -diff --git a/psutil/_psposix.py b/psutil/_psposix.py -index 6ed7694..5b79a42 100644 ---- a/psutil/_psposix.py -+++ b/psutil/_psposix.py -@@ -173,12 +173,16 @@ def get_terminal_map(): - Used by Process.terminal() - """ - ret = {} -- ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*') -+ # NOTE: On Cygwin pseudo-ttys are mapped to /dev/ptyN or /dev/consN -+ ls = (glob.glob('/dev/tty*') + glob.glob('/dev/pts/*') + -+ glob.glob('/dev/pty*') + glob.glob('/dev/cons*')) - for name in ls: - assert name not in ret, name - try: - ret[os.stat(name).st_rdev] = name - except OSError as err: -- if err.errno != errno.ENOENT: -+ if err.errno not in (errno.ENOENT, errno.ENXIO): -+ # Note: ENXIO can happen in some cases on Cygwin due to a -+ # bug; see: https://cygwin.com/ml/cygwin/2017-08/msg00198.html - raise - return ret -diff --git a/psutil/_pssunos.py b/psutil/_pssunos.py -index ad72de2..9269ca9 100644 ---- a/psutil/_pssunos.py -+++ b/psutil/_pssunos.py -@@ -15,6 +15,7 @@ from . import _common - from . import _psposix - from . import _psutil_posix as cext_posix - from . import _psutil_sunos as cext -+from ._common import get_procfs_path - from ._common import isfile_strict - from ._common import memoize_when_activated - from ._common import sockfam_to_enum -@@ -97,13 +98,15 @@ pmmap_ext = namedtuple( - - - # ===================================================================== --# --- utils -+# --- exceptions - # ===================================================================== - - --def get_procfs_path(): -- """Return updated psutil.PROCFS_PATH constant.""" -- return sys.modules['psutil'].PROCFS_PATH -+# these get overwritten on "import psutil" from the __init__.py file -+NoSuchProcess = None -+ZombieProcess = None -+AccessDenied = None -+TimeoutExpired = None - - - # ===================================================================== -diff --git a/psutil/_psutil_cygwin.c b/psutil/_psutil_cygwin.c -new file mode 100644 -index 0000000..e2f9e94 ---- /dev/null -+++ b/psutil/_psutil_cygwin.c -@@ -0,0 +1,2035 @@ -+#define WIN32_LEAN_AND_MEAN -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* On Cygwin, mprapi.h is missing a necessary include of wincrypt.h -+ * which is needed to define some types, so we include it here since -+ * iphlpapi.h includes iprtrmib.h which in turn includes mprapi.h -+ */ -+#include -+ -+/* TODO: There are some structs defined in netioapi.h that are only defined in -+ * ws2ipdef.h has been included; however, for reasons unknown to me currently, -+ * the headers included with Cygwin deliberately do not include ws2ipdef.h -+ * when compiling for Cygwin. For now I include it manually which seems to work -+ * but it would be good to track down why this was in the first place. -+ */ -+#include -+#include -+ -+#include -+ -+#include -+ -+#include -+#include -+ -+#include "arch/windows/process_info.h" -+#include "_psutil_common.h" -+ -+ -+/* -+ * ============================================================================ -+ * Utilities -+ * ============================================================================ -+ */ -+ -+ // a flag for connections without an actual status -+static int PSUTIL_CONN_NONE = 128; -+#define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff) -+#define _psutil_conn_decref_objs() \ -+ Py_DECREF(_AF_INET); \ -+ Py_DECREF(_AF_INET6);\ -+ Py_DECREF(_SOCK_STREAM);\ -+ Py_DECREF(_SOCK_DGRAM); -+ -+ -+// fix for mingw32, see -+// https://github.com/giampaolo/psutil/issues/351#c2 -+typedef struct _DISK_PERFORMANCE_WIN_2008 { -+ LARGE_INTEGER BytesRead; -+ LARGE_INTEGER BytesWritten; -+ LARGE_INTEGER ReadTime; -+ LARGE_INTEGER WriteTime; -+ LARGE_INTEGER IdleTime; -+ DWORD ReadCount; -+ DWORD WriteCount; -+ DWORD QueueDepth; -+ DWORD SplitCount; -+ LARGE_INTEGER QueryTime; -+ DWORD StorageDeviceNumber; -+ WCHAR StorageManagerName[8]; -+} DISK_PERFORMANCE_WIN_2008; -+ -+/* Python wrappers for Cygwin's cygwin_conv_path API--accepts and returns -+ * Python unicode strings. Always returns absolute paths. -+ */ -+static PyObject * -+psutil_cygwin_conv_path(PyObject *self, PyObject *args, -+ cygwin_conv_path_t what) { -+ char *from; -+ char *to; -+ ssize_t size; -+ -+ if (!PyArg_ParseTuple(args, "s", &from)) { -+ return NULL; -+ } -+ -+ size = cygwin_conv_path(what, from, NULL, 0); -+ -+ if (size < 0) { -+ /* TODO: Better error handling */ -+ return size; -+ } -+ -+ to = malloc(size); -+ if (to == NULL) { -+ return NULL; -+ } -+ -+ if (cygwin_conv_path(what, from, to, size)) { -+ return NULL; -+ } -+ -+ /* size includes the terminal null byte */ -+#if PY_MAJOR_VERSION >= 3 -+ return PyUnicode_FromStringAndSize(to, size - 1); -+#else -+ return PyString_FromStringAndSize(to, size - 1); -+#endif -+} -+ -+ -+static PyObject * -+psutil_cygpath_to_winpath(PyObject *self, PyObject *args) { -+ return psutil_cygwin_conv_path(self, args, CCP_POSIX_TO_WIN_A); -+} -+ -+ -+static PyObject * -+psutil_winpath_to_cygpath(PyObject *self, PyObject *args) { -+ return psutil_cygwin_conv_path(self, args, CCP_WIN_A_TO_POSIX); -+} -+ -+ -+/* TODO: Copied almost verbatim (_tcscmp -> wcscmp, _stprintf_s -> snprintf, -+ * _countof -> sizeof) so consider moving this into arch/windows or something -+ */ -+/* -+ Accept a filename's drive in native format like "\Device\HarddiskVolume1\" -+ and return the corresponding drive letter (e.g. "C:\\"). -+ If no match is found return an empty string. -+*/ -+static PyObject * -+psutil_win32_QueryDosDevice(PyObject *self, PyObject *args) { -+ LPCTSTR lpDevicePath; -+ TCHAR d = TEXT('A'); -+ TCHAR szBuff[5]; -+ -+ if (!PyArg_ParseTuple(args, "s", &lpDevicePath)) -+ return NULL; -+ -+ while (d <= TEXT('Z')) { -+ TCHAR szDeviceName[3] = {d, TEXT(':'), TEXT('\0')}; -+ TCHAR szTarget[512] = {0}; -+ if (QueryDosDevice(szDeviceName, szTarget, 511) != 0) { -+ if (wcscmp(lpDevicePath, szTarget) == 0) { -+ snprintf(szBuff, sizeof(szBuff), TEXT("%c:"), d); -+ return Py_BuildValue("s", szBuff); -+ } -+ } -+ d++; -+ } -+ return Py_BuildValue("s", ""); -+} -+ -+ -+static ULONGLONG (*psutil_GetTickCount64)(void) = NULL; -+ -+/* -+ * Return a Python float representing the system uptime expressed in seconds -+ * since the epoch. -+ */ -+static PyObject * -+psutil_boot_time(PyObject *self, PyObject *args) { -+ double uptime; -+ double pt; -+ FILETIME fileTime; -+ long long ll; -+ HINSTANCE hKernel32; -+ psutil_GetTickCount64 = NULL; -+ -+ GetSystemTimeAsFileTime(&fileTime); -+ -+ /* -+ HUGE thanks to: -+ http://johnstewien.spaces.live.com/blog/cns!E6885DB5CEBABBC8!831.entry -+ -+ This function converts the FILETIME structure to a 32-bit Unix time. -+ The Unix time is a 32-bit value for the number of seconds since -+ January 1, 1970. A FILETIME is a 64-bit for the number of -+ 100-nanosecond periods since January 1, 1601. Convert by -+ subtracting the number of 100-nanosecond period betwee 01-01-1970 -+ and 01-01-1601, from time_t the divide by 1e+7 to get to the same -+ base granularity. -+ */ -+ ll = (((LONGLONG)(fileTime.dwHighDateTime)) << 32) \ -+ + fileTime.dwLowDateTime; -+ pt = (double)(ll - 116444736000000000ull) / 1e7; -+ -+ // GetTickCount64() is Windows Vista+ only. Dinamically load -+ // GetTickCount64() at runtime. We may have used -+ // "#if (_WIN32_WINNT >= 0x0600)" pre-processor but that way -+ // the produced exe/wheels cannot be used on Windows XP, see: -+ // https://github.com/giampaolo/psutil/issues/811#issuecomment-230639178 -+ hKernel32 = GetModuleHandleW(L"KERNEL32"); -+ psutil_GetTickCount64 = (void*)GetProcAddress(hKernel32, "GetTickCount64"); -+ if (psutil_GetTickCount64 != NULL) { -+ // Windows >= Vista -+ uptime = (double)psutil_GetTickCount64() / 1000.00; -+ } -+ else { -+ // Windows XP. -+ // GetTickCount() time will wrap around to zero if the -+ // system is run continuously for 49.7 days. -+ uptime = (double)GetTickCount() / 1000.00; -+ } -+ -+ return Py_BuildValue("d", floor(pt - uptime)); -+} -+ -+ -+/* TODO: Copied verbatim from the Linux module; refactor */ -+/* -+ * Return disk mounted partitions as a list of tuples including device, -+ * mount point and filesystem type -+ */ -+static PyObject * -+psutil_disk_partitions(PyObject *self, PyObject *args) { -+ FILE *file = NULL; -+ struct mntent *entry; -+ PyObject *py_retlist = PyList_New(0); -+ PyObject *py_tuple = NULL; -+ -+ if (py_retlist == NULL) -+ return NULL; -+ -+ // MOUNTED constant comes from mntent.h and it's == '/etc/mtab' -+ Py_BEGIN_ALLOW_THREADS -+ file = setmntent(MOUNTED, "r"); -+ Py_END_ALLOW_THREADS -+ if ((file == 0) || (file == NULL)) { -+ PyErr_SetFromErrnoWithFilename(PyExc_OSError, MOUNTED); -+ goto error; -+ } -+ -+ while ((entry = getmntent(file))) { -+ if (entry == NULL) { -+ PyErr_Format(PyExc_RuntimeError, "getmntent() failed"); -+ goto error; -+ } -+ py_tuple = Py_BuildValue("(ssss)", -+ entry->mnt_fsname, // device -+ entry->mnt_dir, // mount point -+ entry->mnt_type, // fs type -+ entry->mnt_opts); // options -+ if (! py_tuple) -+ goto error; -+ if (PyList_Append(py_retlist, py_tuple)) -+ goto error; -+ Py_DECREF(py_tuple); -+ } -+ endmntent(file); -+ return py_retlist; -+ -+error: -+ if (file != NULL) -+ endmntent(file); -+ Py_XDECREF(py_tuple); -+ Py_DECREF(py_retlist); -+ return NULL; -+} -+ -+ -+/* Copied verbatim from the Windows module -+ TODO: Refactor this later -+ */ -+/* -+ * Return process CPU affinity as a bitmask -+ */ -+static PyObject * -+psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { -+ DWORD pid; -+ HANDLE hProcess; -+ DWORD_PTR proc_mask; -+ DWORD_PTR system_mask; -+ -+ if (! PyArg_ParseTuple(args, "l", &pid)) -+ return NULL; -+ hProcess = psutil_handle_from_pid(pid); -+ if (hProcess == NULL) -+ return NULL; -+ -+ if (GetProcessAffinityMask(hProcess, &proc_mask, &system_mask) == 0) { -+ CloseHandle(hProcess); -+ return PyErr_SetFromWindowsErr(0); -+ } -+ -+ CloseHandle(hProcess); -+#ifdef _WIN64 -+ return Py_BuildValue("K", (unsigned long long)proc_mask); -+#else -+ return Py_BuildValue("k", (unsigned long)proc_mask); -+#endif -+} -+ -+ -+/* -+ * Return process memory information as a Python tuple. -+ */ -+static PyObject * -+psutil_proc_memory_info(PyObject *self, PyObject *args) { -+ HANDLE hProcess; -+ DWORD pid; -+#if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 -+ PROCESS_MEMORY_COUNTERS_EX cnt; -+#else -+ PROCESS_MEMORY_COUNTERS cnt; -+#endif -+ SIZE_T private = 0; -+ -+ if (! PyArg_ParseTuple(args, "l", &pid)) -+ return NULL; -+ -+ hProcess = psutil_handle_from_pid(pid); -+ if (NULL == hProcess) -+ return NULL; -+ -+ if (! GetProcessMemoryInfo(hProcess, (PPROCESS_MEMORY_COUNTERS)&cnt, -+ sizeof(cnt))) { -+ CloseHandle(hProcess); -+ return PyErr_SetFromWindowsErr(0); -+ } -+ -+#if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 -+ private = cnt.PrivateUsage; -+#endif -+ -+ CloseHandle(hProcess); -+ -+ // PROCESS_MEMORY_COUNTERS values are defined as SIZE_T which on 64bits -+ // is an (unsigned long long) and on 32bits is an (unsigned int). -+ // "_WIN64" is defined if we're running a 64bit Python interpreter not -+ // exclusively if the *system* is 64bit. -+#if defined(_WIN64) -+ return Py_BuildValue( -+ "(kKKKKKKKKK)", -+ cnt.PageFaultCount, // unsigned long -+ (unsigned long long)cnt.PeakWorkingSetSize, -+ (unsigned long long)cnt.WorkingSetSize, -+ (unsigned long long)cnt.QuotaPeakPagedPoolUsage, -+ (unsigned long long)cnt.QuotaPagedPoolUsage, -+ (unsigned long long)cnt.QuotaPeakNonPagedPoolUsage, -+ (unsigned long long)cnt.QuotaNonPagedPoolUsage, -+ (unsigned long long)cnt.PagefileUsage, -+ (unsigned long long)cnt.PeakPagefileUsage, -+ (unsigned long long)private); -+#else -+ return Py_BuildValue( -+ "(kIIIIIIIII)", -+ cnt.PageFaultCount, // unsigned long -+ (unsigned int)cnt.PeakWorkingSetSize, -+ (unsigned int)cnt.WorkingSetSize, -+ (unsigned int)cnt.QuotaPeakPagedPoolUsage, -+ (unsigned int)cnt.QuotaPagedPoolUsage, -+ (unsigned int)cnt.QuotaPeakNonPagedPoolUsage, -+ (unsigned int)cnt.QuotaNonPagedPoolUsage, -+ (unsigned int)cnt.PagefileUsage, -+ (unsigned int)cnt.PeakPagefileUsage, -+ (unsigned int)private); -+#endif -+} -+ -+ -+/* -+ * Alternative implementation of the one above but bypasses ACCESS DENIED. -+ */ -+static PyObject * -+psutil_proc_memory_info_2(PyObject *self, PyObject *args) { -+ DWORD pid; -+ PSYSTEM_PROCESS_INFORMATION process; -+ PVOID buffer; -+ SIZE_T private; -+ unsigned long pfault_count; -+ -+#if defined(_WIN64) -+ unsigned long long m1, m2, m3, m4, m5, m6, m7, m8; -+#else -+ unsigned int m1, m2, m3, m4, m5, m6, m7, m8; -+#endif -+ -+ if (! PyArg_ParseTuple(args, "l", &pid)) -+ return NULL; -+ if (! psutil_get_proc_info(pid, &process, &buffer)) -+ return NULL; -+ -+#if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 -+ private = process->PrivatePageCount; -+#else -+ private = 0; -+#endif -+ pfault_count = process->PageFaultCount; -+ -+ m1 = process->PeakWorkingSetSize; -+ m2 = process->WorkingSetSize; -+ m3 = process->QuotaPeakPagedPoolUsage; -+ m4 = process->QuotaPagedPoolUsage; -+ m5 = process->QuotaPeakNonPagedPoolUsage; -+ m6 = process->QuotaNonPagedPoolUsage; -+ m7 = process->PagefileUsage; -+ m8 = process->PeakPagefileUsage; -+ -+ free(buffer); -+ -+ // SYSTEM_PROCESS_INFORMATION values are defined as SIZE_T which on 64 -+ // bits is an (unsigned long long) and on 32bits is an (unsigned int). -+ // "_WIN64" is defined if we're running a 64bit Python interpreter not -+ // exclusively if the *system* is 64bit. -+#if defined(_WIN64) -+ return Py_BuildValue("(kKKKKKKKKK)", -+#else -+ return Py_BuildValue("(kIIIIIIIII)", -+#endif -+ pfault_count, m1, m2, m3, m4, m5, m6, m7, m8, private); -+} -+ -+ -+/** -+ * Returns the USS of the process. -+ * Reference: -+ * https://dxr.mozilla.org/mozilla-central/source/xpcom/base/ -+ * nsMemoryReporterManager.cpp -+ */ -+static PyObject * -+psutil_proc_memory_uss(PyObject *self, PyObject *args) -+{ -+ DWORD pid; -+ HANDLE proc; -+ PSAPI_WORKING_SET_INFORMATION tmp; -+ DWORD tmp_size = sizeof(tmp); -+ size_t entries; -+ size_t private_pages; -+ size_t i; -+ DWORD info_array_size; -+ PSAPI_WORKING_SET_INFORMATION* info_array; -+ SYSTEM_INFO system_info; -+ PyObject* py_result = NULL; -+ unsigned long long total = 0; -+ -+ if (! PyArg_ParseTuple(args, "l", &pid)) -+ return NULL; -+ -+ proc = psutil_handle_from_pid(pid); -+ if (proc == NULL) -+ return NULL; -+ -+ // Determine how many entries we need. -+ memset(&tmp, 0, tmp_size); -+ if (!QueryWorkingSet(proc, &tmp, tmp_size)) { -+ // NB: QueryWorkingSet is expected to fail here due to the -+ // buffer being too small. -+ if (tmp.NumberOfEntries == 0) { -+ PyErr_SetFromWindowsErr(0); -+ goto done; -+ } -+ } -+ -+ // Fudge the size in case new entries are added between calls. -+ entries = tmp.NumberOfEntries * 2; -+ -+ if (!entries) { -+ goto done; -+ } -+ -+ info_array_size = tmp_size + (entries * sizeof(PSAPI_WORKING_SET_BLOCK)); -+ info_array = (PSAPI_WORKING_SET_INFORMATION*)malloc(info_array_size); -+ if (!info_array) { -+ PyErr_NoMemory(); -+ goto done; -+ } -+ -+ if (!QueryWorkingSet(proc, info_array, info_array_size)) { -+ PyErr_SetFromWindowsErr(0); -+ goto done; -+ } -+ -+ entries = (size_t)info_array->NumberOfEntries; -+ private_pages = 0; -+ for (i = 0; i < entries; i++) { -+ // Count shared pages that only one process is using as private. -+ if (!info_array->WorkingSetInfo[i].Shared || -+ info_array->WorkingSetInfo[i].ShareCount <= 1) { -+ private_pages++; -+ } -+ } -+ -+ // GetSystemInfo has no return value. -+ GetSystemInfo(&system_info); -+ total = private_pages * system_info.dwPageSize; -+ py_result = Py_BuildValue("K", total); -+ -+done: -+ if (proc) { -+ CloseHandle(proc); -+ } -+ -+ if (info_array) { -+ free(info_array); -+ } -+ -+ return py_result; -+} -+ -+ -+/* -+ * Set process CPU affinity -+ */ -+static PyObject * -+psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) { -+ DWORD pid; -+ HANDLE hProcess; -+ DWORD dwDesiredAccess = \ -+ PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION; -+ DWORD_PTR mask; -+ -+#ifdef _WIN64 -+ if (! PyArg_ParseTuple(args, "lK", &pid, &mask)) -+#else -+ if (! PyArg_ParseTuple(args, "lk", &pid, &mask)) -+#endif -+ { -+ return NULL; -+ } -+ hProcess = psutil_handle_from_pid_waccess(pid, dwDesiredAccess); -+ if (hProcess == NULL) -+ return NULL; -+ -+ if (SetProcessAffinityMask(hProcess, mask) == 0) { -+ CloseHandle(hProcess); -+ PyErr_SetFromWindowsErr(0); -+ return NULL; -+ } -+ -+ CloseHandle(hProcess); -+ Py_RETURN_NONE; -+} -+ -+ -+/* -+ * Return a Python float indicating the process create time expressed in -+ * seconds since the epoch. -+ */ -+static PyObject * -+psutil_proc_create_time(PyObject *self, PyObject *args) { -+ long pid; -+ long long unix_time; -+ DWORD exitCode; -+ HANDLE hProcess; -+ BOOL ret; -+ FILETIME ftCreate, ftExit, ftKernel, ftUser; -+ -+ if (! PyArg_ParseTuple(args, "l", &pid)) -+ return NULL; -+ -+ // special case for PIDs 0 and 4, return system boot time -+ if (0 == pid || 4 == pid) -+ return psutil_boot_time(NULL, NULL); -+ -+ hProcess = psutil_handle_from_pid(pid); -+ if (hProcess == NULL) -+ return NULL; -+ -+ if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { -+ CloseHandle(hProcess); -+ printf("GetLastError() = %d\n", GetLastError()); -+ if (GetLastError() == ERROR_ACCESS_DENIED) { -+ // usually means the process has died so we throw a -+ // NoSuchProcess here -+ return NoSuchProcess(); -+ } -+ else { -+ PyErr_SetFromWindowsErr(0); -+ return NULL; -+ } -+ } -+ -+ // Make sure the process is not gone as OpenProcess alone seems to be -+ // unreliable in doing so (it seems a previous call to p.wait() makes -+ // it unreliable). -+ // This check is important as creation time is used to make sure the -+ // process is still running. -+ ret = GetExitCodeProcess(hProcess, &exitCode); -+ CloseHandle(hProcess); -+ if (ret != 0) { -+ if (exitCode != STILL_ACTIVE) -+ return NoSuchProcess(); -+ } -+ else { -+ // Ignore access denied as it means the process is still alive. -+ // For all other errors, we want an exception. -+ if (GetLastError() != ERROR_ACCESS_DENIED) { -+ PyErr_SetFromWindowsErr(0); -+ return NULL; -+ } -+ } -+ -+ /* -+ Convert the FILETIME structure to a Unix time. -+ It's the best I could find by googling and borrowing code here and there. -+ The time returned has a precision of 1 second. -+ */ -+ unix_time = ((LONGLONG)ftCreate.dwHighDateTime) << 32; -+ unix_time += ftCreate.dwLowDateTime - 116444736000000000LL; -+ unix_time /= 10000000; -+ return Py_BuildValue("d", (double)unix_time); -+} -+ -+ -+// TODO: Copied verbatim from the windows module -+/* -+ * Get various process information by using NtQuerySystemInformation. -+ * We use this as a fallback when faster functions fail with access -+ * denied. This is slower because it iterates over all processes. -+ * Returned tuple includes the following process info: -+ * -+ * - num_threads -+ * - ctx_switches -+ * - num_handles (fallback) -+ * - user/kernel times (fallback) -+ * - create time (fallback) -+ * - io counters (fallback) -+ */ -+static PyObject * -+psutil_proc_info(PyObject *self, PyObject *args) { -+ DWORD pid; -+ PSYSTEM_PROCESS_INFORMATION process; -+ PVOID buffer; -+ ULONG num_handles; -+ ULONG i; -+ ULONG ctx_switches = 0; -+ double user_time; -+ double kernel_time; -+ long long create_time; -+ int num_threads; -+ LONGLONG io_rcount, io_wcount, io_rbytes, io_wbytes; -+ -+ -+ if (! PyArg_ParseTuple(args, "l", &pid)) -+ return NULL; -+ if (! psutil_get_proc_info(pid, &process, &buffer)) -+ return NULL; -+ -+ num_handles = process->HandleCount; -+ for (i = 0; i < process->NumberOfThreads; i++) { -+ // The updated headers in mingw-w64 appear to be using an older version -+ // of this API in which the ContextSwitches member is still called -+ // Reserved3 -+#if __MINGW64_VERSION_MAJOR < 7 -+ // Using the copy of this struct definition included in psutil -+ ctx_switches += process->Threads[i].ContextSwitches; -+#else -+ // Using the definition from mingw-w64-w32api-headers -+ ctx_switches += process->Threads[i].Reserved3; -+#endif -+ } -+ user_time = (double)process->UserTime.HighPart * 429.4967296 + \ -+ (double)process->UserTime.LowPart * 1e-7; -+ kernel_time = (double)process->KernelTime.HighPart * 429.4967296 + \ -+ (double)process->KernelTime.LowPart * 1e-7; -+ // Convert the LARGE_INTEGER union to a Unix time. -+ // It's the best I could find by googling and borrowing code here -+ // and there. The time returned has a precision of 1 second. -+ if (0 == pid || 4 == pid) { -+ // the python module will translate this into BOOT_TIME later -+ create_time = 0; -+ } -+ else { -+ create_time = ((LONGLONG)process->CreateTime.HighPart) << 32; -+ create_time += process->CreateTime.LowPart - 116444736000000000LL; -+ create_time /= 10000000; -+ } -+ num_threads = (int)process->NumberOfThreads; -+ io_rcount = process->ReadOperationCount.QuadPart; -+ io_wcount = process->WriteOperationCount.QuadPart; -+ io_rbytes = process->ReadTransferCount.QuadPart; -+ io_wbytes = process->WriteTransferCount.QuadPart; -+ free(buffer); -+ -+ return Py_BuildValue( -+ "kkdddiKKKK", -+ num_handles, -+ ctx_switches, -+ user_time, -+ kernel_time, -+ (double)create_time, -+ num_threads, -+ io_rcount, -+ io_wcount, -+ io_rbytes, -+ io_wbytes -+ ); -+} -+ -+ -+// TODO: Copied verbatim from windows module -+/* -+ * Return a Python tuple referencing process I/O counters. -+ */ -+static PyObject * -+psutil_proc_io_counters(PyObject *self, PyObject *args) { -+ DWORD pid; -+ HANDLE hProcess; -+ IO_COUNTERS IoCounters; -+ -+ if (! PyArg_ParseTuple(args, "l", &pid)) -+ return NULL; -+ hProcess = psutil_handle_from_pid(pid); -+ if (NULL == hProcess) -+ return NULL; -+ if (! GetProcessIoCounters(hProcess, &IoCounters)) { -+ CloseHandle(hProcess); -+ return PyErr_SetFromWindowsErr(0); -+ } -+ CloseHandle(hProcess); -+ return Py_BuildValue("(KKKK)", -+ IoCounters.ReadOperationCount, -+ IoCounters.WriteOperationCount, -+ IoCounters.ReadTransferCount, -+ IoCounters.WriteTransferCount); -+} -+ -+ -+static PyObject * -+psutil_proc_threads(PyObject *self, PyObject *args) { -+ HANDLE hThread; -+ THREADENTRY32 te32 = {0}; -+ long pid; -+ int pid_return; -+ int rc; -+ FILETIME ftDummy, ftKernel, ftUser; -+ HANDLE hThreadSnap = NULL; -+ PyObject *py_tuple = NULL; -+ PyObject *py_retlist = PyList_New(0); -+ -+ if (py_retlist == NULL) -+ return NULL; -+ if (! PyArg_ParseTuple(args, "l", &pid)) -+ goto error; -+ if (pid == 0) { -+ // raise AD instead of returning 0 as procexp is able to -+ // retrieve useful information somehow -+ AccessDenied(); -+ goto error; -+ } -+ -+ pid_return = psutil_pid_is_running(pid); -+ if (pid_return == 0) { -+ NoSuchProcess(); -+ goto error; -+ } -+ if (pid_return == -1) -+ goto error; -+ -+ hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); -+ if (hThreadSnap == INVALID_HANDLE_VALUE) { -+ PyErr_SetFromWindowsErr(0); -+ goto error; -+ } -+ -+ // Fill in the size of the structure before using it -+ te32.dwSize = sizeof(THREADENTRY32); -+ -+ if (! Thread32First(hThreadSnap, &te32)) { -+ PyErr_SetFromWindowsErr(0); -+ goto error; -+ } -+ -+ // Walk the thread snapshot to find all threads of the process. -+ // If the thread belongs to the process, increase the counter. -+ do { -+ if (te32.th32OwnerProcessID == pid) { -+ py_tuple = NULL; -+ hThread = NULL; -+ hThread = OpenThread(THREAD_QUERY_INFORMATION, -+ FALSE, te32.th32ThreadID); -+ if (hThread == NULL) { -+ // thread has disappeared on us -+ continue; -+ } -+ -+ rc = GetThreadTimes(hThread, &ftDummy, &ftDummy, &ftKernel, -+ &ftUser); -+ if (rc == 0) { -+ PyErr_SetFromWindowsErr(0); -+ goto error; -+ } -+ -+ /* -+ * User and kernel times are represented as a FILETIME structure -+ * wich contains a 64-bit value representing the number of -+ * 100-nanosecond intervals since January 1, 1601 (UTC): -+ * http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx -+ * To convert it into a float representing the seconds that the -+ * process has executed in user/kernel mode I borrowed the code -+ * below from Python's Modules/posixmodule.c -+ */ -+ py_tuple = Py_BuildValue( -+ "kdd", -+ te32.th32ThreadID, -+ (double)(ftUser.dwHighDateTime * 429.4967296 + \ -+ ftUser.dwLowDateTime * 1e-7), -+ (double)(ftKernel.dwHighDateTime * 429.4967296 + \ -+ ftKernel.dwLowDateTime * 1e-7)); -+ if (!py_tuple) -+ goto error; -+ if (PyList_Append(py_retlist, py_tuple)) -+ goto error; -+ Py_DECREF(py_tuple); -+ -+ CloseHandle(hThread); -+ } -+ } while (Thread32Next(hThreadSnap, &te32)); -+ -+ CloseHandle(hThreadSnap); -+ return py_retlist; -+ -+error: -+ Py_XDECREF(py_tuple); -+ Py_DECREF(py_retlist); -+ if (hThread != NULL) -+ CloseHandle(hThread); -+ if (hThreadSnap != NULL) -+ CloseHandle(hThreadSnap); -+ return NULL; -+} -+ -+ -+// TODO: This is copied almost verbatim from the Linux module, but on Cygwin -+// it's necessary to use the utmpx APIs in order to access some of the extended -+// utmp fields, such as ut_tv. -+/* -+ * Return currently connected users as a list of tuples. -+ */ -+static PyObject * -+psutil_users(PyObject *self, PyObject *args) { -+ struct utmpx *ut; -+ PyObject *py_retlist = PyList_New(0); -+ PyObject *py_tuple = NULL; -+ PyObject *py_user_proc = NULL; -+ -+ if (py_retlist == NULL) -+ return NULL; -+ setutxent(); -+ while (NULL != (ut = getutxent())) { -+ py_tuple = NULL; -+ py_user_proc = NULL; -+ if (ut->ut_type == USER_PROCESS) -+ py_user_proc = Py_True; -+ else -+ py_user_proc = Py_False; -+ py_tuple = Py_BuildValue( -+ "(sssfO)", -+ ut->ut_user, // username -+ ut->ut_line, // tty -+ ut->ut_host, // hostname -+ (float)ut->ut_tv.tv_sec, // tstamp -+ py_user_proc // (bool) user process -+ ); -+ if (! py_tuple) -+ goto error; -+ if (PyList_Append(py_retlist, py_tuple)) -+ goto error; -+ Py_DECREF(py_tuple); -+ } -+ endutent(); -+ return py_retlist; -+ -+error: -+ Py_XDECREF(py_tuple); -+ Py_XDECREF(py_user_proc); -+ Py_DECREF(py_retlist); -+ endutent(); -+ return NULL; -+} -+ -+ -+PIP_ADAPTER_ADDRESSES -+psutil_get_nic_addresses(int all) { -+ // allocate a 15 KB buffer to start with -+ int outBufLen = 15000; -+ DWORD dwRetVal = 0; -+ ULONG attempts = 0; -+ PIP_ADAPTER_ADDRESSES pAddresses = NULL; -+ -+ do { -+ pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen); -+ if (pAddresses == NULL) { -+ PyErr_NoMemory(); -+ return NULL; -+ } -+ -+ dwRetVal = GetAdaptersAddresses( -+ AF_UNSPEC, -+ all ? GAA_FLAG_INCLUDE_ALL_INTERFACES : 0, -+ NULL, pAddresses, -+ &outBufLen); -+ if (dwRetVal == ERROR_BUFFER_OVERFLOW) { -+ free(pAddresses); -+ pAddresses = NULL; -+ } -+ else { -+ break; -+ } -+ -+ attempts++; -+ } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3)); -+ -+ if (dwRetVal != NO_ERROR) { -+ PyErr_SetString(PyExc_RuntimeError, "GetAdaptersAddresses() failed."); -+ return NULL; -+ } -+ -+ return pAddresses; -+} -+ -+ -+/* -+ * Provides stats about NIC interfaces installed on the system. -+ * TODO: get 'duplex' (currently it's hard coded to '2', aka -+ 'full duplex') -+ */ -+ -+/* TODO: This and the helper get_nic_addresses are copied *almost* verbatim -+ from the windows module. One difference is the use of snprintf with -+ the %ls format, as opposed to using sprintf_s from MSCRT -+ The other difference is that get_nic_addresses() returns all interfaces, -+ */ -+static PyObject * -+psutil_net_if_stats(PyObject *self, PyObject *args) { -+ int i; -+ DWORD dwSize = 0; -+ DWORD dwRetVal = 0; -+ MIB_IFTABLE *pIfTable; -+ MIB_IFROW *pIfRow; -+ PIP_ADAPTER_ADDRESSES pAddresses = NULL; -+ PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; -+ char descr[MAX_PATH]; -+ int ifname_found; -+ -+ PyObject *py_nic_name = NULL; -+ PyObject *py_retdict = PyDict_New(); -+ PyObject *py_ifc_info = NULL; -+ PyObject *py_is_up = NULL; -+ -+ if (py_retdict == NULL) -+ return NULL; -+ -+ pAddresses = psutil_get_nic_addresses(1); -+ if (pAddresses == NULL) -+ goto error; -+ -+ pIfTable = (MIB_IFTABLE *) malloc(sizeof (MIB_IFTABLE)); -+ if (pIfTable == NULL) { -+ PyErr_NoMemory(); -+ goto error; -+ } -+ dwSize = sizeof(MIB_IFTABLE); -+ if (GetIfTable(pIfTable, &dwSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) { -+ free(pIfTable); -+ pIfTable = (MIB_IFTABLE *) malloc(dwSize); -+ if (pIfTable == NULL) { -+ PyErr_NoMemory(); -+ goto error; -+ } -+ } -+ // Make a second call to GetIfTable to get the actual -+ // data we want. -+ if ((dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE)) != NO_ERROR) { -+ PyErr_SetString(PyExc_RuntimeError, "GetIfTable() failed"); -+ goto error; -+ } -+ -+ for (i = 0; i < (int) pIfTable->dwNumEntries; i++) { -+ pIfRow = (MIB_IFROW *) & pIfTable->table[i]; -+ -+ // GetIfTable is not able to give us NIC with "friendly names" -+ // so we determine them via GetAdapterAddresses() which -+ // provides friendly names *and* descriptions and find the -+ // ones that match. -+ ifname_found = 0; -+ pCurrAddresses = pAddresses; -+ while (pCurrAddresses) { -+ snprintf(descr, MAX_PATH, "%ls", pCurrAddresses->Description); -+ if (lstrcmp(descr, pIfRow->bDescr) == 0) { -+ py_nic_name = PyUnicode_FromWideChar( -+ pCurrAddresses->FriendlyName, -+ wcslen(pCurrAddresses->FriendlyName)); -+ if (py_nic_name == NULL) -+ goto error; -+ ifname_found = 1; -+ break; -+ } -+ pCurrAddresses = pCurrAddresses->Next; -+ } -+ if (ifname_found == 0) { -+ // Name not found means GetAdapterAddresses() doesn't list -+ // this NIC, only GetIfTable, meaning it's not really a NIC -+ // interface so we skip it. -+ continue; -+ } -+ -+ // is up? -+ if((pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED || -+ pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL) && -+ pIfRow->dwAdminStatus == 1 ) { -+ py_is_up = Py_True; -+ } -+ else { -+ py_is_up = Py_False; -+ } -+ Py_INCREF(py_is_up); -+ -+ py_ifc_info = Py_BuildValue( -+ "(Oikk)", -+ py_is_up, -+ 2, // there's no way to know duplex so let's assume 'full' -+ pIfRow->dwSpeed / 1000000, // expressed in bytes, we want Mb -+ pIfRow->dwMtu -+ ); -+ if (!py_ifc_info) -+ goto error; -+ if (PyDict_SetItem(py_retdict, py_nic_name, py_ifc_info)) -+ goto error; -+ Py_DECREF(py_nic_name); -+ Py_DECREF(py_ifc_info); -+ } -+ -+ free(pIfTable); -+ free(pAddresses); -+ return py_retdict; -+ -+error: -+ Py_XDECREF(py_is_up); -+ Py_XDECREF(py_ifc_info); -+ Py_XDECREF(py_nic_name); -+ Py_DECREF(py_retdict); -+ if (pIfTable != NULL) -+ free(pIfTable); -+ if (pAddresses != NULL) -+ free(pAddresses); -+ return NULL; -+} -+ -+ -+/* -+ * Return a Python list of named tuples with overall network I/O information -+ */ -+static PyObject * -+psutil_net_io_counters(PyObject *self, PyObject *args) { -+ DWORD dwRetVal = 0; -+ -+#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above -+ MIB_IF_ROW2 *pIfRow = NULL; -+#else // Windows XP -+ MIB_IFROW *pIfRow = NULL; -+#endif -+ -+ PIP_ADAPTER_ADDRESSES pAddresses = NULL; -+ PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; -+ PyObject *py_retdict = PyDict_New(); -+ PyObject *py_nic_info = NULL; -+ PyObject *py_nic_name = NULL; -+ -+ if (py_retdict == NULL) -+ return NULL; -+ pAddresses = psutil_get_nic_addresses(0); -+ if (pAddresses == NULL) -+ goto error; -+ pCurrAddresses = pAddresses; -+ -+ while (pCurrAddresses) { -+ py_nic_name = NULL; -+ py_nic_info = NULL; -+ -+#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above -+ pIfRow = (MIB_IF_ROW2 *) malloc(sizeof(MIB_IF_ROW2)); -+#else // Windows XP -+ pIfRow = (MIB_IFROW *) malloc(sizeof(MIB_IFROW)); -+#endif -+ -+ if (pIfRow == NULL) { -+ PyErr_NoMemory(); -+ goto error; -+ } -+ -+#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above -+ SecureZeroMemory((PVOID)pIfRow, sizeof(MIB_IF_ROW2)); -+ pIfRow->InterfaceIndex = pCurrAddresses->IfIndex; -+ dwRetVal = GetIfEntry2(pIfRow); -+#else // Windows XP -+ pIfRow->dwIndex = pCurrAddresses->IfIndex; -+ dwRetVal = GetIfEntry(pIfRow); -+#endif -+ -+ if (dwRetVal != NO_ERROR) { -+ PyErr_SetString(PyExc_RuntimeError, -+ "GetIfEntry() or GetIfEntry2() failed."); -+ goto error; -+ } -+ -+#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above -+ py_nic_info = Py_BuildValue("(KKKKKKKK)", -+ pIfRow->OutOctets, -+ pIfRow->InOctets, -+ pIfRow->OutUcastPkts, -+ pIfRow->InUcastPkts, -+ pIfRow->InErrors, -+ pIfRow->OutErrors, -+ pIfRow->InDiscards, -+ pIfRow->OutDiscards); -+#else // Windows XP -+ py_nic_info = Py_BuildValue("(kkkkkkkk)", -+ pIfRow->dwOutOctets, -+ pIfRow->dwInOctets, -+ pIfRow->dwOutUcastPkts, -+ pIfRow->dwInUcastPkts, -+ pIfRow->dwInErrors, -+ pIfRow->dwOutErrors, -+ pIfRow->dwInDiscards, -+ pIfRow->dwOutDiscards); -+#endif -+ -+ if (!py_nic_info) -+ goto error; -+ -+ py_nic_name = PyUnicode_FromWideChar( -+ pCurrAddresses->FriendlyName, -+ wcslen(pCurrAddresses->FriendlyName)); -+ -+ if (py_nic_name == NULL) -+ goto error; -+ if (PyDict_SetItem(py_retdict, py_nic_name, py_nic_info)) -+ goto error; -+ Py_XDECREF(py_nic_name); -+ Py_XDECREF(py_nic_info); -+ -+ free(pIfRow); -+ pCurrAddresses = pCurrAddresses->Next; -+ } -+ -+ free(pAddresses); -+ return py_retdict; -+ -+error: -+ Py_XDECREF(py_nic_name); -+ Py_XDECREF(py_nic_info); -+ Py_DECREF(py_retdict); -+ if (pAddresses != NULL) -+ free(pAddresses); -+ if (pIfRow != NULL) -+ free(pIfRow); -+ return NULL; -+} -+ -+ -+// TODO: Copied verbatim from the windows module, so again the usual admonition -+// about refactoring -+/* -+ * Return a Python dict of tuples for disk I/O information -+ */ -+static PyObject * -+psutil_disk_io_counters(PyObject *self, PyObject *args) { -+ DISK_PERFORMANCE_WIN_2008 diskPerformance; -+ DWORD dwSize; -+ HANDLE hDevice = NULL; -+ char szDevice[MAX_PATH]; -+ char szDeviceDisplay[MAX_PATH]; -+ int devNum; -+ PyObject *py_retdict = PyDict_New(); -+ PyObject *py_tuple = NULL; -+ -+ if (py_retdict == NULL) -+ return NULL; -+ // Apparently there's no way to figure out how many times we have -+ // to iterate in order to find valid drives. -+ // Let's assume 32, which is higher than 26, the number of letters -+ // in the alphabet (from A:\ to Z:\). -+ for (devNum = 0; devNum <= 32; ++devNum) { -+ py_tuple = NULL; -+ snprintf(szDevice, MAX_PATH, "\\\\.\\PhysicalDrive%d", devNum); -+ hDevice = CreateFile(szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, -+ NULL, OPEN_EXISTING, 0, NULL); -+ -+ if (hDevice == INVALID_HANDLE_VALUE) -+ continue; -+ if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, -+ &diskPerformance, sizeof(diskPerformance), -+ &dwSize, NULL)) -+ { -+ snprintf(szDeviceDisplay, MAX_PATH, "PhysicalDrive%d", devNum); -+ py_tuple = Py_BuildValue( -+ "(IILLKK)", -+ diskPerformance.ReadCount, -+ diskPerformance.WriteCount, -+ diskPerformance.BytesRead, -+ diskPerformance.BytesWritten, -+ (unsigned long long)(diskPerformance.ReadTime.QuadPart * 10) / 1000, -+ (unsigned long long)(diskPerformance.WriteTime.QuadPart * 10) / 1000); -+ if (!py_tuple) -+ goto error; -+ if (PyDict_SetItemString(py_retdict, szDeviceDisplay, -+ py_tuple)) -+ { -+ goto error; -+ } -+ Py_XDECREF(py_tuple); -+ } -+ else { -+ // XXX we might get here with ERROR_INSUFFICIENT_BUFFER when -+ // compiling with mingw32; not sure what to do. -+ // return PyErr_SetFromWindowsErr(0); -+ ;; -+ } -+ -+ CloseHandle(hDevice); -+ } -+ -+ return py_retdict; -+ -+error: -+ Py_XDECREF(py_tuple); -+ Py_DECREF(py_retdict); -+ if (hDevice != NULL) -+ CloseHandle(hDevice); -+ return NULL; -+} -+ -+ -+// TODO: _GetExtended(Tcp|Udp)Table are copied straight out of the windows -+// module, and really ought to live somewhere in arch/windows -+ -+ -+typedef DWORD (WINAPI * _GetExtendedTcpTable)(PVOID, PDWORD, BOOL, ULONG, -+ TCP_TABLE_CLASS, ULONG); -+ -+ -+// https://msdn.microsoft.com/library/aa365928.aspx -+static DWORD __GetExtendedTcpTable(_GetExtendedTcpTable call, -+ ULONG address_family, -+ PVOID * data, DWORD * size) -+{ -+ // Due to other processes being active on the machine, it's possible -+ // that the size of the table increases between the moment where we -+ // query the size and the moment where we query the data. Therefore, it's -+ // important to call this in a loop to retry if that happens. -+ // -+ // Also, since we may loop a theoretically unbounded number of times here, -+ // release the GIL while we're doing this. -+ DWORD error = ERROR_INSUFFICIENT_BUFFER; -+ *size = 0; -+ *data = NULL; -+ Py_BEGIN_ALLOW_THREADS; -+ error = call(NULL, size, FALSE, address_family, -+ TCP_TABLE_OWNER_PID_ALL, 0); -+ while (error == ERROR_INSUFFICIENT_BUFFER) -+ { -+ *data = malloc(*size); -+ if (*data == NULL) { -+ error = ERROR_NOT_ENOUGH_MEMORY; -+ continue; -+ } -+ error = call(*data, size, FALSE, address_family, -+ TCP_TABLE_OWNER_PID_ALL, 0); -+ if (error != NO_ERROR) { -+ free(*data); -+ *data = NULL; -+ } -+ } -+ Py_END_ALLOW_THREADS; -+ return error; -+} -+ -+ -+typedef DWORD (WINAPI * _GetExtendedUdpTable)(PVOID, PDWORD, BOOL, ULONG, -+ UDP_TABLE_CLASS, ULONG); -+ -+ -+// https://msdn.microsoft.com/library/aa365930.aspx -+static DWORD __GetExtendedUdpTable(_GetExtendedUdpTable call, -+ ULONG address_family, -+ PVOID * data, DWORD * size) -+{ -+ // Due to other processes being active on the machine, it's possible -+ // that the size of the table increases between the moment where we -+ // query the size and the moment where we query the data. Therefore, it's -+ // important to call this in a loop to retry if that happens. -+ // -+ // Also, since we may loop a theoretically unbounded number of times here, -+ // release the GIL while we're doing this. -+ DWORD error = ERROR_INSUFFICIENT_BUFFER; -+ *size = 0; -+ *data = NULL; -+ Py_BEGIN_ALLOW_THREADS; -+ error = call(NULL, size, FALSE, address_family, -+ UDP_TABLE_OWNER_PID, 0); -+ while (error == ERROR_INSUFFICIENT_BUFFER) -+ { -+ *data = malloc(*size); -+ if (*data == NULL) { -+ error = ERROR_NOT_ENOUGH_MEMORY; -+ continue; -+ } -+ error = call(*data, size, FALSE, address_family, -+ UDP_TABLE_OWNER_PID, 0); -+ if (error != NO_ERROR) { -+ free(*data); -+ *data = NULL; -+ } -+ } -+ Py_END_ALLOW_THREADS; -+ return error; -+} -+ -+ -+/* -+ * Return a list of network connections opened by a process -+ */ -+static PyObject * -+psutil_net_connections(PyObject *self, PyObject *args) { -+ static long null_address[4] = { 0, 0, 0, 0 }; -+ unsigned long pid; -+ typedef PSTR (NTAPI * _RtlIpv4AddressToStringA)(struct in_addr *, PSTR); -+ _RtlIpv4AddressToStringA rtlIpv4AddressToStringA; -+ typedef PSTR (NTAPI * _RtlIpv6AddressToStringA)(struct in6_addr *, PSTR); -+ _RtlIpv6AddressToStringA rtlIpv6AddressToStringA; -+ _GetExtendedTcpTable getExtendedTcpTable; -+ _GetExtendedUdpTable getExtendedUdpTable; -+ PVOID table = NULL; -+ DWORD tableSize; -+ DWORD error; -+ PMIB_TCPTABLE_OWNER_PID tcp4Table; -+ PMIB_UDPTABLE_OWNER_PID udp4Table; -+ PMIB_TCP6TABLE_OWNER_PID tcp6Table; -+ PMIB_UDP6TABLE_OWNER_PID udp6Table; -+ ULONG i; -+ CHAR addressBufferLocal[65]; -+ CHAR addressBufferRemote[65]; -+ -+ PyObject *py_retlist; -+ PyObject *py_conn_tuple = NULL; -+ PyObject *py_af_filter = NULL; -+ PyObject *py_type_filter = NULL; -+ PyObject *py_addr_tuple_local = NULL; -+ PyObject *py_addr_tuple_remote = NULL; -+ PyObject *_AF_INET = PyLong_FromLong((long)AF_INET); -+ PyObject *_AF_INET6 = PyLong_FromLong((long)AF_INET6); -+ PyObject *_SOCK_STREAM = PyLong_FromLong((long)SOCK_STREAM); -+ PyObject *_SOCK_DGRAM = PyLong_FromLong((long)SOCK_DGRAM); -+ -+ if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) -+ { -+ _psutil_conn_decref_objs(); -+ return NULL; -+ } -+ -+ if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { -+ _psutil_conn_decref_objs(); -+ PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); -+ return NULL; -+ } -+ -+ if (pid != -1) { -+ if (psutil_pid_is_running(pid) == 0) { -+ _psutil_conn_decref_objs(); -+ return NoSuchProcess(); -+ } -+ } -+ -+ // Import some functions. -+ { -+ HMODULE ntdll; -+ HMODULE iphlpapi; -+ -+ ntdll = LoadLibrary(TEXT("ntdll.dll")); -+ rtlIpv4AddressToStringA = (_RtlIpv4AddressToStringA)GetProcAddress( -+ ntdll, "RtlIpv4AddressToStringA"); -+ rtlIpv6AddressToStringA = (_RtlIpv6AddressToStringA)GetProcAddress( -+ ntdll, "RtlIpv6AddressToStringA"); -+ /* TODO: Check these two function pointers */ -+ -+ iphlpapi = LoadLibrary(TEXT("iphlpapi.dll")); -+ getExtendedTcpTable = (_GetExtendedTcpTable)GetProcAddress(iphlpapi, -+ "GetExtendedTcpTable"); -+ getExtendedUdpTable = (_GetExtendedUdpTable)GetProcAddress(iphlpapi, -+ "GetExtendedUdpTable"); -+ FreeLibrary(ntdll); -+ FreeLibrary(iphlpapi); -+ } -+ -+ if ((getExtendedTcpTable == NULL) || (getExtendedUdpTable == NULL)) { -+ PyErr_SetString(PyExc_NotImplementedError, -+ "feature not supported on this Windows version"); -+ _psutil_conn_decref_objs(); -+ return NULL; -+ } -+ -+ py_retlist = PyList_New(0); -+ if (py_retlist == NULL) { -+ _psutil_conn_decref_objs(); -+ return NULL; -+ } -+ -+ // TCP IPv4 -+ -+ if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) && -+ (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1)) -+ { -+ table = NULL; -+ py_conn_tuple = NULL; -+ py_addr_tuple_local = NULL; -+ py_addr_tuple_remote = NULL; -+ tableSize = 0; -+ -+ error = __GetExtendedTcpTable(getExtendedTcpTable, -+ AF_INET, &table, &tableSize); -+ if (error == ERROR_NOT_ENOUGH_MEMORY) { -+ PyErr_NoMemory(); -+ goto error; -+ } -+ -+ if (error == NO_ERROR) -+ { -+ tcp4Table = table; -+ -+ for (i = 0; i < tcp4Table->dwNumEntries; i++) -+ { -+ if (pid != -1) { -+ if (tcp4Table->table[i].dwOwningPid != pid) { -+ continue; -+ } -+ } -+ -+ if (tcp4Table->table[i].dwLocalAddr != 0 || -+ tcp4Table->table[i].dwLocalPort != 0) -+ { -+ struct in_addr addr; -+ -+ addr.S_un.S_addr = tcp4Table->table[i].dwLocalAddr; -+ rtlIpv4AddressToStringA(&addr, addressBufferLocal); -+ py_addr_tuple_local = Py_BuildValue( -+ "(si)", -+ addressBufferLocal, -+ BYTESWAP_USHORT(tcp4Table->table[i].dwLocalPort)); -+ } -+ else { -+ py_addr_tuple_local = PyTuple_New(0); -+ } -+ -+ if (py_addr_tuple_local == NULL) -+ goto error; -+ -+ // On Windows <= XP, remote addr is filled even if socket -+ // is in LISTEN mode in which case we just ignore it. -+ if ((tcp4Table->table[i].dwRemoteAddr != 0 || -+ tcp4Table->table[i].dwRemotePort != 0) && -+ (tcp4Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) -+ { -+ struct in_addr addr; -+ -+ addr.S_un.S_addr = tcp4Table->table[i].dwRemoteAddr; -+ rtlIpv4AddressToStringA(&addr, addressBufferRemote); -+ py_addr_tuple_remote = Py_BuildValue( -+ "(si)", -+ addressBufferRemote, -+ BYTESWAP_USHORT(tcp4Table->table[i].dwRemotePort)); -+ } -+ else -+ { -+ py_addr_tuple_remote = PyTuple_New(0); -+ } -+ -+ if (py_addr_tuple_remote == NULL) -+ goto error; -+ -+ py_conn_tuple = Py_BuildValue( -+ "(iiiNNiI)", -+ -1, -+ AF_INET, -+ SOCK_STREAM, -+ py_addr_tuple_local, -+ py_addr_tuple_remote, -+ tcp4Table->table[i].dwState, -+ tcp4Table->table[i].dwOwningPid); -+ if (!py_conn_tuple) -+ goto error; -+ if (PyList_Append(py_retlist, py_conn_tuple)) -+ goto error; -+ Py_DECREF(py_conn_tuple); -+ } -+ } -+ else { -+ PyErr_SetFromWindowsErr(error); -+ goto error; -+ } -+ -+ free(table); -+ table = NULL; -+ tableSize = 0; -+ } -+ -+ // TCP IPv6 -+ if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) && -+ (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1)) -+ { -+ table = NULL; -+ py_conn_tuple = NULL; -+ py_addr_tuple_local = NULL; -+ py_addr_tuple_remote = NULL; -+ tableSize = 0; -+ -+ error = __GetExtendedTcpTable(getExtendedTcpTable, -+ AF_INET6, &table, &tableSize); -+ if (error == ERROR_NOT_ENOUGH_MEMORY) { -+ PyErr_NoMemory(); -+ goto error; -+ } -+ -+ if (error == NO_ERROR) -+ { -+ tcp6Table = table; -+ -+ for (i = 0; i < tcp6Table->dwNumEntries; i++) -+ { -+ if (pid != -1) { -+ if (tcp6Table->table[i].dwOwningPid != pid) { -+ continue; -+ } -+ } -+ -+ if (memcmp(tcp6Table->table[i].ucLocalAddr, null_address, 16) -+ != 0 || tcp6Table->table[i].dwLocalPort != 0) -+ { -+ struct in6_addr addr; -+ -+ memcpy(&addr, tcp6Table->table[i].ucLocalAddr, 16); -+ rtlIpv6AddressToStringA(&addr, addressBufferLocal); -+ py_addr_tuple_local = Py_BuildValue( -+ "(si)", -+ addressBufferLocal, -+ BYTESWAP_USHORT(tcp6Table->table[i].dwLocalPort)); -+ } -+ else { -+ py_addr_tuple_local = PyTuple_New(0); -+ } -+ -+ if (py_addr_tuple_local == NULL) -+ goto error; -+ -+ // On Windows <= XP, remote addr is filled even if socket -+ // is in LISTEN mode in which case we just ignore it. -+ if ((memcmp(tcp6Table->table[i].ucRemoteAddr, null_address, 16) -+ != 0 || -+ tcp6Table->table[i].dwRemotePort != 0) && -+ (tcp6Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) -+ { -+ struct in6_addr addr; -+ -+ memcpy(&addr, tcp6Table->table[i].ucRemoteAddr, 16); -+ rtlIpv6AddressToStringA(&addr, addressBufferRemote); -+ py_addr_tuple_remote = Py_BuildValue( -+ "(si)", -+ addressBufferRemote, -+ BYTESWAP_USHORT(tcp6Table->table[i].dwRemotePort)); -+ } -+ else { -+ py_addr_tuple_remote = PyTuple_New(0); -+ } -+ -+ if (py_addr_tuple_remote == NULL) -+ goto error; -+ -+ py_conn_tuple = Py_BuildValue( -+ "(iiiNNiI)", -+ -1, -+ AF_INET6, -+ SOCK_STREAM, -+ py_addr_tuple_local, -+ py_addr_tuple_remote, -+ tcp6Table->table[i].dwState, -+ tcp6Table->table[i].dwOwningPid); -+ if (!py_conn_tuple) -+ goto error; -+ if (PyList_Append(py_retlist, py_conn_tuple)) -+ goto error; -+ Py_DECREF(py_conn_tuple); -+ } -+ } -+ else { -+ PyErr_SetFromWindowsErr(error); -+ goto error; -+ } -+ -+ free(table); -+ table = NULL; -+ tableSize = 0; -+ } -+ -+ // UDP IPv4 -+ -+ if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) && -+ (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1)) -+ { -+ table = NULL; -+ py_conn_tuple = NULL; -+ py_addr_tuple_local = NULL; -+ py_addr_tuple_remote = NULL; -+ tableSize = 0; -+ error = __GetExtendedUdpTable(getExtendedUdpTable, -+ AF_INET, &table, &tableSize); -+ if (error == ERROR_NOT_ENOUGH_MEMORY) { -+ PyErr_NoMemory(); -+ goto error; -+ } -+ -+ if (error == NO_ERROR) -+ { -+ udp4Table = table; -+ -+ for (i = 0; i < udp4Table->dwNumEntries; i++) -+ { -+ if (pid != -1) { -+ if (udp4Table->table[i].dwOwningPid != pid) { -+ continue; -+ } -+ } -+ -+ if (udp4Table->table[i].dwLocalAddr != 0 || -+ udp4Table->table[i].dwLocalPort != 0) -+ { -+ struct in_addr addr; -+ -+ addr.S_un.S_addr = udp4Table->table[i].dwLocalAddr; -+ rtlIpv4AddressToStringA(&addr, addressBufferLocal); -+ py_addr_tuple_local = Py_BuildValue( -+ "(si)", -+ addressBufferLocal, -+ BYTESWAP_USHORT(udp4Table->table[i].dwLocalPort)); -+ } -+ else { -+ py_addr_tuple_local = PyTuple_New(0); -+ } -+ -+ if (py_addr_tuple_local == NULL) -+ goto error; -+ -+ py_conn_tuple = Py_BuildValue( -+ "(iiiNNiI)", -+ -1, -+ AF_INET, -+ SOCK_DGRAM, -+ py_addr_tuple_local, -+ PyTuple_New(0), -+ PSUTIL_CONN_NONE, -+ udp4Table->table[i].dwOwningPid); -+ if (!py_conn_tuple) -+ goto error; -+ if (PyList_Append(py_retlist, py_conn_tuple)) -+ goto error; -+ Py_DECREF(py_conn_tuple); -+ } -+ } -+ else { -+ PyErr_SetFromWindowsErr(error); -+ goto error; -+ } -+ -+ free(table); -+ table = NULL; -+ tableSize = 0; -+ } -+ -+ // UDP IPv6 -+ -+ if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) && -+ (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1)) -+ { -+ table = NULL; -+ py_conn_tuple = NULL; -+ py_addr_tuple_local = NULL; -+ py_addr_tuple_remote = NULL; -+ tableSize = 0; -+ error = __GetExtendedUdpTable(getExtendedUdpTable, -+ AF_INET6, &table, &tableSize); -+ if (error == ERROR_NOT_ENOUGH_MEMORY) { -+ PyErr_NoMemory(); -+ goto error; -+ } -+ -+ if (error == NO_ERROR) -+ { -+ udp6Table = table; -+ -+ for (i = 0; i < udp6Table->dwNumEntries; i++) { -+ if (pid != -1) { -+ if (udp6Table->table[i].dwOwningPid != pid) { -+ continue; -+ } -+ } -+ -+ if (memcmp(udp6Table->table[i].ucLocalAddr, null_address, 16) -+ != 0 || udp6Table->table[i].dwLocalPort != 0) -+ { -+ struct in6_addr addr; -+ -+ memcpy(&addr, udp6Table->table[i].ucLocalAddr, 16); -+ rtlIpv6AddressToStringA(&addr, addressBufferLocal); -+ py_addr_tuple_local = Py_BuildValue( -+ "(si)", -+ addressBufferLocal, -+ BYTESWAP_USHORT(udp6Table->table[i].dwLocalPort)); -+ } -+ else { -+ py_addr_tuple_local = PyTuple_New(0); -+ } -+ -+ if (py_addr_tuple_local == NULL) -+ goto error; -+ -+ py_conn_tuple = Py_BuildValue( -+ "(iiiNNiI)", -+ -1, -+ AF_INET6, -+ SOCK_DGRAM, -+ py_addr_tuple_local, -+ PyTuple_New(0), -+ PSUTIL_CONN_NONE, -+ udp6Table->table[i].dwOwningPid); -+ if (!py_conn_tuple) -+ goto error; -+ if (PyList_Append(py_retlist, py_conn_tuple)) -+ goto error; -+ Py_DECREF(py_conn_tuple); -+ } -+ } -+ else { -+ PyErr_SetFromWindowsErr(error); -+ goto error; -+ } -+ -+ free(table); -+ table = NULL; -+ tableSize = 0; -+ } -+ -+ _psutil_conn_decref_objs(); -+ return py_retlist; -+ -+error: -+ _psutil_conn_decref_objs(); -+ Py_XDECREF(py_conn_tuple); -+ Py_XDECREF(py_addr_tuple_local); -+ Py_XDECREF(py_addr_tuple_remote); -+ Py_DECREF(py_retlist); -+ if (table != NULL) -+ free(table); -+ return NULL; -+} -+ -+ -+static char *get_region_protection_string(ULONG protection) { -+ switch (protection & 0xff) { -+ case PAGE_NOACCESS: -+ return ""; -+ case PAGE_READONLY: -+ return "r"; -+ case PAGE_READWRITE: -+ return "rw"; -+ case PAGE_WRITECOPY: -+ return "wc"; -+ case PAGE_EXECUTE: -+ return "x"; -+ case PAGE_EXECUTE_READ: -+ return "xr"; -+ case PAGE_EXECUTE_READWRITE: -+ return "xrw"; -+ case PAGE_EXECUTE_WRITECOPY: -+ return "xwc"; -+ default: -+ return "?"; -+ } -+} -+ -+ -+/* TODO: Copied verbatim from the windows module; this should be refactored -+ * as well -+ */ -+/* -+ * Return a list of process's memory mappings. -+ */ -+static PyObject * -+psutil_proc_memory_maps(PyObject *self, PyObject *args) { -+#ifdef _WIN64 -+ MEMORY_BASIC_INFORMATION64 basicInfo; -+#else -+ MEMORY_BASIC_INFORMATION basicInfo; -+#endif -+ DWORD pid; -+ HANDLE hProcess = NULL; -+ PVOID baseAddress; -+ PVOID previousAllocationBase; -+ CHAR mappedFileName[MAX_PATH]; -+ SYSTEM_INFO system_info; -+ LPVOID maxAddr; -+ PyObject *py_retlist = PyList_New(0); -+ PyObject *py_tuple = NULL; -+ -+ if (py_retlist == NULL) -+ return NULL; -+ if (! PyArg_ParseTuple(args, "l", &pid)) -+ goto error; -+ hProcess = psutil_handle_from_pid(pid); -+ if (NULL == hProcess) -+ goto error; -+ -+ GetSystemInfo(&system_info); -+ maxAddr = system_info.lpMaximumApplicationAddress; -+ baseAddress = NULL; -+ previousAllocationBase = NULL; -+ -+ while (VirtualQueryEx(hProcess, baseAddress, &basicInfo, -+ sizeof(MEMORY_BASIC_INFORMATION))) -+ { -+ py_tuple = NULL; -+ if (baseAddress > maxAddr) -+ break; -+ if (GetMappedFileNameA(hProcess, baseAddress, mappedFileName, -+ sizeof(mappedFileName))) -+ { -+#ifdef _WIN64 -+ py_tuple = Py_BuildValue( -+ "(KssI)", -+ (unsigned long long)baseAddress, -+#else -+ py_tuple = Py_BuildValue( -+ "(kssI)", -+ (unsigned long)baseAddress, -+#endif -+ get_region_protection_string(basicInfo.Protect), -+ mappedFileName, -+ basicInfo.RegionSize); -+ -+ if (!py_tuple) -+ goto error; -+ if (PyList_Append(py_retlist, py_tuple)) -+ goto error; -+ Py_DECREF(py_tuple); -+ } -+ previousAllocationBase = basicInfo.AllocationBase; -+ baseAddress = (PCHAR)baseAddress + basicInfo.RegionSize; -+ } -+ -+ CloseHandle(hProcess); -+ return py_retlist; -+ -+error: -+ Py_XDECREF(py_tuple); -+ Py_DECREF(py_retlist); -+ if (hProcess != NULL) -+ CloseHandle(hProcess); -+ return NULL; -+} -+ -+ -+/* -+ * Return battery usage stats. -+ */ -+static PyObject * -+psutil_sensors_battery(PyObject *self, PyObject *args) { -+ SYSTEM_POWER_STATUS sps; -+ -+ if (GetSystemPowerStatus(&sps) == 0) { -+ PyErr_SetFromWindowsErr(0); -+ return NULL; -+ } -+ return Py_BuildValue( -+ "iiiI", -+ sps.ACLineStatus, // whether AC is connected: 0=no, 1=yes, 255=unknown -+ // status flag: -+ // 1, 2, 4 = high, low, critical -+ // 8 = charging -+ // 128 = no battery -+ sps.BatteryFlag, -+ sps.BatteryLifePercent, // percent -+ sps.BatteryLifeTime // remaining secs -+ ); -+} -+ -+ -+/* -+ * define the psutil C module methods and initialize the module. -+ */ -+static PyMethodDef -+PsutilMethods[] = { -+ {"cygpath_to_winpath", psutil_cygpath_to_winpath, METH_VARARGS, -+ "Convert a Cygwin path to a Windows path"}, -+ {"winpath_to_cygpath", psutil_winpath_to_cygpath, METH_VARARGS, -+ "Convert a Windows path to a Cygwin path"}, -+ {"boot_time", psutil_boot_time, METH_VARARGS, -+ "Return the system boot time expressed in seconds since the epoch."}, -+ {"disk_partitions", psutil_disk_partitions, METH_VARARGS, -+ "Return disk mounted partitions as a list of tuples including " -+ "device, mount point and filesystem type"}, -+ {"net_connections", psutil_net_connections, METH_VARARGS, -+ "Return system-wide connections"}, -+ {"net_if_stats", psutil_net_if_stats, METH_VARARGS, -+ "Return NICs stats."}, -+ {"net_io_counters", psutil_net_io_counters, METH_VARARGS, -+ "Return dict of tuples of networks I/O information."}, -+ {"sensors_battery", psutil_sensors_battery, METH_VARARGS, -+ "Return battery metrics usage."}, -+ {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS, -+ "Return dict of tuples of disks I/O information."}, -+ {"proc_memory_info", psutil_proc_memory_info, METH_VARARGS, -+ "Return a tuple of process memory information"}, -+ {"proc_memory_info_2", psutil_proc_memory_info_2, METH_VARARGS, -+ "Alternate implementation"}, -+ {"proc_memory_uss", psutil_proc_memory_uss, METH_VARARGS, -+ "Return the USS of the process"}, -+ {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS, -+ "Return process CPU affinity as a bitmask."}, -+ {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS, -+ "Set process CPU affinity."}, -+ {"proc_io_counters", psutil_proc_io_counters, METH_VARARGS, -+ "Get process I/O counters."}, -+ {"proc_threads", psutil_proc_threads, METH_VARARGS, -+ "Return process threads information as a list of tuple"}, -+ {"proc_create_time", psutil_proc_create_time, METH_VARARGS, -+ "Return a float indicating the process create time expressed in " -+ "seconds since the epoch"}, -+ // --- alternative pinfo interface -+ {"proc_info", psutil_proc_info, METH_VARARGS, -+ "Various process information"}, -+ {"users", psutil_users, METH_VARARGS, -+ "Return currently connected users as a list of tuples"}, -+ {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, -+ "Return a list of process's memory mappings"}, -+ -+ // --- windows API bindings -+ {"win32_QueryDosDevice", psutil_win32_QueryDosDevice, METH_VARARGS, -+ "QueryDosDevice binding"}, -+ {NULL, NULL, 0, NULL} -+}; -+ -+struct module_state { -+ PyObject *error; -+}; -+ -+#if PY_MAJOR_VERSION >= 3 -+#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) -+#else -+#define GETSTATE(m) (&_state) -+#endif -+ -+#if PY_MAJOR_VERSION >= 3 -+ -+static int -+psutil_cygwin_traverse(PyObject *m, visitproc visit, void *arg) { -+ Py_VISIT(GETSTATE(m)->error); -+ return 0; -+} -+ -+static int -+psutil_cygwin_clear(PyObject *m) { -+ Py_CLEAR(GETSTATE(m)->error); -+ return 0; -+} -+ -+static struct PyModuleDef moduledef = { -+ PyModuleDef_HEAD_INIT, -+ "psutil_cygwin", -+ NULL, -+ sizeof(struct module_state), -+ PsutilMethods, -+ NULL, -+ psutil_cygwin_traverse, -+ psutil_cygwin_clear, -+ NULL -+}; -+ -+#define INITERROR return NULL -+ -+PyMODINIT_FUNC PyInit__psutil_cygwin(void) -+ -+#else -+#define INITERROR return -+ -+void init_psutil_cygwin(void) -+#endif -+{ -+#if PY_MAJOR_VERSION >= 3 -+ PyObject *module = PyModule_Create(&moduledef); -+#else -+ PyObject *module = Py_InitModule("_psutil_cygwin", PsutilMethods); -+#endif -+ -+ PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); -+ -+ // TODO: Copied verbatim from the Windows module; there ought to be a -+ // a function implementing these constants that can be shared between -+ // the two modules... -+ // connection status constants -+ // http://msdn.microsoft.com/en-us/library/cc669305.aspx -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_CLOSED", MIB_TCP_STATE_CLOSED); -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_CLOSING", MIB_TCP_STATE_CLOSING); -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_CLOSE_WAIT", MIB_TCP_STATE_CLOSE_WAIT); -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_LISTEN", MIB_TCP_STATE_LISTEN); -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_ESTAB", MIB_TCP_STATE_ESTAB); -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_SYN_SENT", MIB_TCP_STATE_SYN_SENT); -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_SYN_RCVD", MIB_TCP_STATE_SYN_RCVD); -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_FIN_WAIT1", MIB_TCP_STATE_FIN_WAIT1); -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_FIN_WAIT2", MIB_TCP_STATE_FIN_WAIT2); -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_LAST_ACK", MIB_TCP_STATE_LAST_ACK); -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_TIME_WAIT", MIB_TCP_STATE_TIME_WAIT); -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_TIME_WAIT", MIB_TCP_STATE_TIME_WAIT); -+ PyModule_AddIntConstant( -+ module, "MIB_TCP_STATE_DELETE_TCB", MIB_TCP_STATE_DELETE_TCB); -+ PyModule_AddIntConstant( -+ module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); -+ -+ /* TODO: More Windows constants that are defined as module constants -+ * Used both in the cygwin module (for now) and the windows module */ -+ PyModule_AddIntConstant( -+ module, "ERROR_ACCESS_DENIED", ERROR_ACCESS_DENIED); -+ -+ if (module == NULL) -+ INITERROR; -+#if PY_MAJOR_VERSION >= 3 -+ return module; -+#endif -+} -diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c -index 707c55a..ce4970e 100644 ---- a/psutil/_psutil_posix.c -+++ b/psutil/_psutil_posix.c -@@ -34,6 +34,9 @@ - #elif defined(PSUTIL_SUNOS) - #include - #include -+#elif defined(PSUTIL_CYGWIN) -+ #include -+ #include - #endif - - -@@ -167,6 +170,7 @@ static PyObject* - psutil_net_if_addrs(PyObject* self, PyObject* args) { - struct ifaddrs *ifaddr, *ifa; - int family; -+ char *name; - - PyObject *py_retlist = PyList_New(0); - PyObject *py_tuple = NULL; -@@ -185,6 +189,14 @@ psutil_net_if_addrs(PyObject* self, PyObject* args) { - for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { - if (!ifa->ifa_addr) - continue; -+#ifdef __CYGWIN__ -+ // Support using the Cygwin-specific ifaddrs_hwdata struct to get -+ // the interface's "friendly name" rather than its more opaque -+ // UUID name -+ name = ((struct ifaddrs_hwdata *) (ifa->ifa_data))->ifa_frndlyname.ifrf_friendlyname; -+#else -+ name = ifa->ifa_name; -+#endif - family = ifa->ifa_addr->sa_family; - py_address = psutil_convert_ipaddr(ifa->ifa_addr, family); - // If the primary address can't be determined just skip it. -@@ -218,7 +230,7 @@ psutil_net_if_addrs(PyObject* self, PyObject* args) { - goto error; - py_tuple = Py_BuildValue( - "(siOOOO)", -- ifa->ifa_name, -+ name, - family, - py_address, - py_netmask, -diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py -index 0105d6c..dfa8e63 100644 ---- a/psutil/_pswindows.py -+++ b/psutil/_pswindows.py -@@ -32,6 +32,7 @@ except ImportError as err: - raise - - from ._common import conn_tmap -+from ._common import encode - from ._common import isfile_strict - from ._common import parse_environ_block - from ._common import sockfam_to_enum -@@ -188,21 +189,6 @@ def convert_dos_path(s): - return os.path.join(driveletter, s[len(rawdrive):]) - - --def py2_strencode(s, encoding=sys.getfilesystemencoding()): -- """Encode a string in the given encoding. Falls back on returning -- the string as is if it can't be encoded. -- """ -- if PY3 or isinstance(s, str): -- return s -- else: -- try: -- return s.encode(encoding) -- except UnicodeEncodeError: -- # Filesystem codec failed, return the plain unicode -- # string (this should never happen). -- return s -- -- - # ===================================================================== - # --- memory - # ===================================================================== -@@ -343,7 +329,7 @@ def net_if_stats(): - """Get NIC stats (isup, duplex, speed, mtu).""" - ret = cext.net_if_stats() - for name, items in ret.items(): -- name = py2_strencode(name) -+ name = encode(name) - isup, duplex, speed, mtu = items - if hasattr(_common, 'NicDuplex'): - duplex = _common.NicDuplex(duplex) -@@ -356,7 +342,7 @@ def net_io_counters(): - installed on the system as a dict of raw tuples. - """ - ret = cext.net_io_counters() -- return dict([(py2_strencode(k), v) for k, v in ret.items()]) -+ return dict([(encode(k), v) for k, v in ret.items()]) - - - def net_if_addrs(): -@@ -364,7 +350,7 @@ def net_if_addrs(): - ret = [] - for items in cext.net_if_addrs(): - items = list(items) -- items[0] = py2_strencode(items[0]) -+ items[0] = encode(items[0]) - ret.append(items) - return ret - -@@ -410,7 +396,7 @@ def users(): - rawlist = cext.users() - for item in rawlist: - user, hostname, tstamp = item -- user = py2_strencode(user) -+ user = encode(user) - nt = _common.suser(user, None, hostname, tstamp) - retlist.append(nt) - return retlist -@@ -669,9 +655,9 @@ class Process(object): - try: - # Note: this will fail with AD for most PIDs owned - # by another user but it's faster. -- return py2_strencode(os.path.basename(self.exe())) -+ return encode(os.path.basename(self.exe())) - except AccessDenied: -- return py2_strencode(cext.proc_name(self.pid)) -+ return encode(cext.proc_name(self.pid)) - - @wrap_exceptions - def exe(self): -@@ -683,7 +669,7 @@ class Process(object): - # see https://github.com/giampaolo/psutil/issues/528 - if self.pid in (0, 4): - raise AccessDenied(self.pid, self._name) -- return py2_strencode(convert_dos_path(cext.proc_exe(self.pid))) -+ return encode(convert_dos_path(cext.proc_exe(self.pid))) - - @wrap_exceptions - def cmdline(self): -@@ -691,7 +677,7 @@ class Process(object): - if PY3: - return ret - else: -- return [py2_strencode(s) for s in ret] -+ return [encode(s) for s in ret] - - @wrap_exceptions - def environ(self): -@@ -838,7 +824,7 @@ class Process(object): - # return a normalized pathname since the native C function appends - # "\\" at the and of the path - path = cext.proc_cwd(self.pid) -- return py2_strencode(os.path.normpath(path)) -+ return encode(os.path.normpath(path)) - - @wrap_exceptions - def open_files(self): -@@ -854,7 +840,7 @@ class Process(object): - _file = convert_dos_path(_file) - if isfile_strict(_file): - if not PY3: -- _file = py2_strencode(_file) -+ _file = encode(_file) - ntuple = _common.popenfile(_file, -1) - ret.add(ntuple) - return list(ret) -diff --git a/psutil/arch/windows/ntextapi.h b/psutil/arch/windows/ntextapi.h -index 1bbbf2a..0d50f5b 100644 ---- a/psutil/arch/windows/ntextapi.h -+++ b/psutil/arch/windows/ntextapi.h -@@ -121,6 +121,7 @@ typedef enum _KTHREAD_STATE { - } KTHREAD_STATE, *PKTHREAD_STATE; - - -+#ifndef __MINGW64_VERSION_MAJOR - typedef enum _KWAIT_REASON { - Executive = 0, - FreePage = 1, -@@ -168,7 +169,10 @@ typedef struct _CLIENT_ID { - HANDLE UniqueThread; - } CLIENT_ID, *PCLIENT_ID; - -+#endif - -+ -+#if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 7 - typedef struct _SYSTEM_THREAD_INFORMATION { - LARGE_INTEGER KernelTime; - LARGE_INTEGER UserTime; -@@ -182,6 +186,7 @@ typedef struct _SYSTEM_THREAD_INFORMATION { - ULONG ThreadState; - KWAIT_REASON WaitReason; - } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; -+#endif - - - typedef struct _TEB *PTEB; -@@ -287,6 +292,7 @@ typedef NTSTATUS (NTAPI *_NtSetInformationProcess)( - ); - - -+#ifndef __CYGWIN__ - typedef enum _PROCESSINFOCLASS2 { - _ProcessBasicInformation, - ProcessQuotaLimits, -@@ -338,4 +344,6 @@ typedef enum _PROCESSINFOCLASS2 { - #define ProcessImageFileName _ProcessImageFileName - #define ProcessBreakOnTermination _ProcessBreakOnTermination - -+#endif -+ - #endif // __NTEXTAPI_H__ -diff --git a/psutil/arch/windows/process_info.c b/psutil/arch/windows/process_info.c -index e29f216..868f947 100644 ---- a/psutil/arch/windows/process_info.c -+++ b/psutil/arch/windows/process_info.c -@@ -39,6 +39,8 @@ psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess) { - if (hProcess == NULL) { - if (GetLastError() == ERROR_INVALID_PARAMETER) - NoSuchProcess(); -+ else if (GetLastError() == ERROR_ACCESS_DENIED) -+ AccessDenied(); - else - PyErr_SetFromWindowsErr(0); - return NULL; -diff --git a/psutil/arch/windows/process_info.h b/psutil/arch/windows/process_info.h -index 7c2c9c2..3275372 100644 ---- a/psutil/arch/windows/process_info.h -+++ b/psutil/arch/windows/process_info.h -@@ -15,6 +15,9 @@ - #define HANDLE_TO_PYNUM(handle) PyLong_FromUnsignedLong((unsigned long) handle) - #define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLong(obj)) - -+#ifdef PSUTIL_CYGWIN -+ #include "py_error.h" -+#endif - - DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs); - HANDLE psutil_handle_from_pid(DWORD pid); -diff --git a/psutil/arch/windows/py_error.c b/psutil/arch/windows/py_error.c -new file mode 100644 -index 0000000..c7a6bf6 ---- /dev/null -+++ b/psutil/arch/windows/py_error.c -@@ -0,0 +1,59 @@ -+#include -+#include -+ -+/* TODO: This does not actually work as intended per the comment further down -+ that the OSError constructor performs the Windows error to POSIX error -+ translation, and that logic probably does not exist in Cygwin's Python */ -+PyObject *PyErr_SetFromWindowsErr(int ierr) -+{ -+ int len; -+ WCHAR *s_buf = NULL; /* Free via LocalFree */ -+ PyObject *message; -+ PyObject *args, *v; -+ DWORD err = (DWORD)ierr; -+ if (err==0) err = GetLastError(); -+ len = FormatMessageW( -+ /* Error API error */ -+ FORMAT_MESSAGE_ALLOCATE_BUFFER | -+ FORMAT_MESSAGE_FROM_SYSTEM | -+ FORMAT_MESSAGE_IGNORE_INSERTS, -+ NULL, /* no message source */ -+ err, -+ MAKELANGID(LANG_NEUTRAL, -+ SUBLANG_DEFAULT), /* Default language */ -+ (LPWSTR) &s_buf, -+ 0, /* size not used */ -+ NULL); /* no args */ -+ if (len==0) { -+ /* Only seen this in out of mem situations */ -+ message = PyUnicode_FromFormat("Windows Error 0x%x", err); -+ s_buf = NULL; -+ } else { -+ /* remove trailing cr/lf and dots */ -+ while (len > 0 && (s_buf[len-1] <= L' ' || s_buf[len-1] == L'.')) -+ s_buf[--len] = L'\0'; -+ message = PyUnicode_FromWideChar(s_buf, len); -+ } -+ -+ if (message == NULL) -+ { -+ LocalFree(s_buf); -+ return NULL; -+ } -+ -+ /* This is the constructor signature for OSError. -+ The POSIX translation will be figured out by the constructor. */ -+ args = Py_BuildValue("(iO)", err, message); -+ Py_DECREF(message); -+ -+ if (args != NULL) { -+ v = PyObject_Call(PyExc_OSError, args, NULL); -+ Py_DECREF(args); -+ if (v != NULL) { -+ PyErr_SetObject((PyObject *) Py_TYPE(v), v); -+ Py_DECREF(v); -+ } -+ } -+ LocalFree(s_buf); -+ return NULL; -+} -diff --git a/psutil/arch/windows/py_error.h b/psutil/arch/windows/py_error.h -new file mode 100644 -index 0000000..a3852b7 ---- /dev/null -+++ b/psutil/arch/windows/py_error.h -@@ -0,0 +1,8 @@ -+#ifndef __PY_ERROR_H__ -+#define __PY_ERROR_H__ -+ -+#include -+ -+PyObject *PyErr_SetFromWindowsErr(int); -+ -+#endif -diff --git a/psutil/tests/__init__.py b/psutil/tests/__init__.py -index 13c4cfc..9db7235 100644 ---- a/psutil/tests/__init__.py -+++ b/psutil/tests/__init__.py -@@ -21,6 +21,7 @@ import socket - import stat - import subprocess - import sys -+import sysconfig - import tempfile - import textwrap - import threading -@@ -36,6 +37,7 @@ except ImportError: - import mock # NOQA - requires "pip install mock" - - import psutil -+from psutil import CYGWIN - from psutil import LINUX - from psutil import POSIX - from psutil import WINDOWS -@@ -101,6 +103,12 @@ GLOBAL_TIMEOUT = 3 - AF_INET6 = getattr(socket, "AF_INET6") - AF_UNIX = getattr(socket, "AF_UNIX", None) - PYTHON = os.path.realpath(sys.executable) -+EXE_SUFFIX = sysconfig.get_config_var('EXE') or '' -+ -+if CYGWIN and EXE_SUFFIX: -+ if PYTHON.endswith(EXE_SUFFIX): -+ PYTHON = PYTHON[:-len(EXE_SUFFIX)] -+ - DEVNULL = open(os.devnull, 'r+') - - TESTFILE_PREFIX = '$testfn' -@@ -182,6 +190,104 @@ class ThreadTask(threading.Thread): - - - # =================================================================== -+# --- sync primitives -+# =================================================================== -+ -+ -+class retry(object): -+ """A retry decorator.""" -+ -+ def __init__(self, -+ exception=Exception, -+ timeout=None, -+ retries=None, -+ interval=0.001, -+ logfun=lambda s: print(s, file=sys.stderr), -+ ): -+ if timeout and retries: -+ raise ValueError("timeout and retries args are mutually exclusive") -+ self.exception = exception -+ self.timeout = timeout -+ self.retries = retries -+ self.interval = interval -+ self.logfun = logfun -+ -+ def __iter__(self): -+ if self.timeout: -+ stop_at = time.time() + self.timeout -+ while time.time() < stop_at: -+ yield -+ elif self.retries: -+ for _ in range(self.retries): -+ yield -+ else: -+ while True: -+ yield -+ -+ def sleep(self): -+ if self.interval is not None: -+ time.sleep(self.interval) -+ -+ def __call__(self, fun): -+ @functools.wraps(fun) -+ def wrapper(*args, **kwargs): -+ exc = None -+ for _ in self: -+ try: -+ return fun(*args, **kwargs) -+ except self.exception as _: -+ exc = _ -+ if self.logfun is not None: -+ self.logfun(exc) -+ self.sleep() -+ else: -+ if PY3: -+ raise exc -+ else: -+ raise -+ -+ # This way the user of the decorated function can change config -+ # parameters. -+ wrapper.decorator = self -+ return wrapper -+ -+ -+@retry(exception=psutil.NoSuchProcess, logfun=None, timeout=GLOBAL_TIMEOUT, -+ interval=0.001) -+def wait_for_pid(pid): -+ """Wait for pid to show up in the process list then return. -+ Used in the test suite to give time the sub process to initialize. -+ """ -+ psutil.Process(pid) -+ if WINDOWS: -+ # give it some more time to allow better initialization -+ time.sleep(0.01) -+ -+ -+@retry(exception=(EnvironmentError, AssertionError), logfun=None, -+ timeout=GLOBAL_TIMEOUT, interval=0.001) -+def wait_for_file(fname, delete_file=True, empty=False): -+ """Wait for a file to be written on disk with some content.""" -+ with open(fname, "rb") as f: -+ data = f.read() -+ if not empty: -+ assert data -+ if delete_file: -+ os.remove(fname) -+ return data -+ -+ -+@retry(exception=AssertionError, logfun=None, timeout=GLOBAL_TIMEOUT, -+ interval=0.001) -+def call_until(fun, expr): -+ """Keep calling function for timeout secs and exit if eval() -+ expression is True. -+ """ -+ ret = fun() -+ assert eval(expr) -+ return ret -+ -+# =================================================================== - # --- subprocesses - # =================================================================== - -@@ -189,6 +295,7 @@ class ThreadTask(threading.Thread): - _subprocesses_started = set() - - -+@retry(exception=EnvironmentError, timeout=GLOBAL_TIMEOUT, interval=1) - def get_test_subprocess(cmd=None, **kwds): - """Return a subprocess.Popen object to use in tests. - By default stdout and stderr are redirected to /dev/null and the -@@ -369,105 +476,6 @@ else: - - - # =================================================================== --# --- sync primitives --# =================================================================== -- -- --class retry(object): -- """A retry decorator.""" -- -- def __init__(self, -- exception=Exception, -- timeout=None, -- retries=None, -- interval=0.001, -- logfun=lambda s: print(s, file=sys.stderr), -- ): -- if timeout and retries: -- raise ValueError("timeout and retries args are mutually exclusive") -- self.exception = exception -- self.timeout = timeout -- self.retries = retries -- self.interval = interval -- self.logfun = logfun -- -- def __iter__(self): -- if self.timeout: -- stop_at = time.time() + self.timeout -- while time.time() < stop_at: -- yield -- elif self.retries: -- for _ in range(self.retries): -- yield -- else: -- while True: -- yield -- -- def sleep(self): -- if self.interval is not None: -- time.sleep(self.interval) -- -- def __call__(self, fun): -- @functools.wraps(fun) -- def wrapper(*args, **kwargs): -- exc = None -- for _ in self: -- try: -- return fun(*args, **kwargs) -- except self.exception as _: -- exc = _ -- if self.logfun is not None: -- self.logfun(exc) -- self.sleep() -- else: -- if PY3: -- raise exc -- else: -- raise -- -- # This way the user of the decorated function can change config -- # parameters. -- wrapper.decorator = self -- return wrapper -- -- --@retry(exception=psutil.NoSuchProcess, logfun=None, timeout=GLOBAL_TIMEOUT, -- interval=0.001) --def wait_for_pid(pid): -- """Wait for pid to show up in the process list then return. -- Used in the test suite to give time the sub process to initialize. -- """ -- psutil.Process(pid) -- if WINDOWS: -- # give it some more time to allow better initialization -- time.sleep(0.01) -- -- --@retry(exception=(EnvironmentError, AssertionError), logfun=None, -- timeout=GLOBAL_TIMEOUT, interval=0.001) --def wait_for_file(fname, delete_file=True, empty=False): -- """Wait for a file to be written on disk with some content.""" -- with open(fname, "rb") as f: -- data = f.read() -- if not empty: -- assert data -- if delete_file: -- os.remove(fname) -- return data -- -- --@retry(exception=AssertionError, logfun=None, timeout=GLOBAL_TIMEOUT, -- interval=0.001) --def call_until(fun, expr): -- """Keep calling function for timeout secs and exit if eval() -- expression is True. -- """ -- ret = fun() -- assert eval(expr) -- return ret -- -- --# =================================================================== - # --- fs - # =================================================================== - -diff --git a/psutil/tests/test_misc.py b/psutil/tests/test_misc.py -index 84215d3..1c10a71 100755 ---- a/psutil/tests/test_misc.py -+++ b/psutil/tests/test_misc.py -@@ -19,6 +19,7 @@ import socket - import stat - import sys - -+from psutil import CYGWIN - from psutil import LINUX - from psutil import NETBSD - from psutil import OPENBSD -@@ -442,7 +443,8 @@ class TestScripts(unittest.TestCase): - def test_pmap(self): - self.assert_stdout('pmap.py', args=str(os.getpid())) - -- @unittest.skipUnless(OSX or WINDOWS or LINUX, "platform not supported") -+ @unittest.skipUnless(OSX or WINDOWS or LINUX or CYGWIN, -+ "platform not supported") - def test_procsmem(self): - self.assert_stdout('procsmem.py') - -diff --git a/psutil/tests/test_posix.py b/psutil/tests/test_posix.py -index 16d1eb7..0b934a8 100755 ---- a/psutil/tests/test_posix.py -+++ b/psutil/tests/test_posix.py -@@ -10,12 +10,14 @@ - import datetime - import errno - import os -+import re - import subprocess - import sys - import time - - import psutil - from psutil import BSD -+from psutil import CYGWIN - from psutil import LINUX - from psutil import OSX - from psutil import POSIX -@@ -37,25 +39,123 @@ from psutil.tests import unittest - from psutil.tests import wait_for_pid - - --def ps(cmd): -- """Expects a ps command with a -o argument and parse the result -- returning only the value of interest. -- """ -- if not LINUX: -- cmd = cmd.replace(" --no-headers ", " ") -- if SUNOS: -- cmd = cmd.replace("-o command", "-o comm") -- cmd = cmd.replace("-o start", "-o stime") -- p = subprocess.Popen(cmd, shell=1, stdout=subprocess.PIPE) -+def run(cmd): -+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, -+ stderr=subprocess.PIPE) - output = p.communicate()[0].strip() -+ - if PY3: - output = str(output, sys.stdout.encoding) -- if not LINUX: -- output = output.split('\n')[1].strip() -- try: -- return int(output) -- except ValueError: -- return output -+ -+ return output -+ -+ -+def ps(fmt, pid=None): -+ """ -+ Wrapper for calling the ps command with a little bit of cross-platform -+ support for a narrow range of features. -+ """ -+ -+ # The ps on Cygwin bears only small resemblance to the *nix ps, and -+ # probably shouldn't even be used for these tests; this tries as -+ # best as possible to emulate it as used currently by these tests -+ cmd = ['ps'] -+ -+ if LINUX: -+ cmd.append('--no-headers') -+ -+ if pid is not None: -+ cmd.extend(['-p', str(pid)]) -+ else: -+ if SUNOS: -+ cmd.append('-A') -+ elif CYGWIN: -+ cmd.append('-a') -+ else: -+ cmd.append('ax') -+ -+ if SUNOS: -+ fmt_map = {'command', 'comm', -+ 'start', 'stime'} -+ fmt = fmt_map.get(fmt, fmt) -+ -+ if not CYGWIN: -+ cmd.extend(['-o', fmt]) -+ else: -+ cmd.append('-l') -+ -+ output = run(cmd) -+ -+ if LINUX: -+ output = output.splitlines() -+ else: -+ output = output.splitlines()[1:] -+ -+ if CYGWIN: -+ cygwin_ps_re = re.compile(r'I?\s*(?P\d+)\s*(?P\d+)\s*' -+ '(?P\d+)\s*(?P\d+)\s*' -+ '(?P[a-z0-9?]+)\s*(?P\d+)\s*' -+ '(?:(?P\d{2}:\d{2}:\d{2})|' -+ ' (?P[A-Za-z]+\s+\d+))\s*' -+ '(?P/.+)') -+ -+ def cygwin_output(line, fmt): -+ # NOTE: Cygwin's ps is very limited in what it outputs, so we work -+ # around that by looking to various other sources for some -+ # information -+ fmt_map = {'start': 'stime'} -+ fmt = fmt_map.get(fmt, fmt) -+ -+ m = cygwin_ps_re.match(line) -+ if not m: -+ return '' -+ -+ if fmt in cygwin_ps_re.groupindex: -+ output = m.group(fmt) -+ if output is None: -+ output = '' -+ elif fmt == 'rgid': -+ pid = m.group('pid') -+ output = open('/proc/{0}/gid'.format(pid)).readline().strip() -+ elif fmt == 'user': -+ # Cygwin's ps only returns UID -+ uid = m.group('uid') -+ output = run(['getent', 'passwd', uid]) -+ output = output.splitlines()[0].split(':')[0] -+ elif fmt == 'rss': -+ winpid = m.group('winpid') -+ output = run(['wmic', 'process', winpid, 'get', -+ 'WorkingSetSize']) -+ output = int(output.split('\n')[-1].strip()) / 1024 -+ elif fmt == 'vsz': -+ winpid = m.group('winpid') -+ output = run(['wmic', 'process', winpid, 'get', -+ 'PrivatePageCount']) -+ output = int(output.split('\n')[-1].strip()) / 1024 -+ else: -+ raise ValueError('format %s not supported on Cygwin' % fmt) -+ -+ return output -+ -+ all_output = [] -+ for line in output: -+ if CYGWIN: -+ output = cygwin_output(line, fmt) -+ -+ if not output: -+ continue -+ -+ try: -+ output = int(output) -+ except ValueError: -+ pass -+ -+ all_output.append(output) -+ -+ if pid is None: -+ return all_output -+ else: -+ return all_output[0] - - - @unittest.skipUnless(POSIX, "POSIX only") -@@ -75,49 +175,50 @@ class TestProcess(unittest.TestCase): - # for ps -o arguments see: http://unixhelp.ed.ac.uk/CGI/man-cgi?ps - - def test_ppid(self): -- ppid_ps = ps("ps --no-headers -o ppid -p %s" % self.pid) -+ ppid_ps = ps('ppid', self.pid) - ppid_psutil = psutil.Process(self.pid).ppid() - self.assertEqual(ppid_ps, ppid_psutil) - - def test_uid(self): -- uid_ps = ps("ps --no-headers -o uid -p %s" % self.pid) -+ uid_ps = ps('uid', self.pid) - uid_psutil = psutil.Process(self.pid).uids().real - self.assertEqual(uid_ps, uid_psutil) - - def test_gid(self): -- gid_ps = ps("ps --no-headers -o rgid -p %s" % self.pid) -+ gid_ps = ps('rgid', self.pid) - gid_psutil = psutil.Process(self.pid).gids().real - self.assertEqual(gid_ps, gid_psutil) - - def test_username(self): -- username_ps = ps("ps --no-headers -o user -p %s" % self.pid) -+ username_ps = ps('user', self.pid) - username_psutil = psutil.Process(self.pid).username() - self.assertEqual(username_ps, username_psutil) - -+ @unittest.skipIf(APPVEYOR and CYGWIN, "test not reliable on appveyor") - @skip_on_access_denied() - @retry_before_failing() - def test_rss_memory(self): - # give python interpreter some time to properly initialize - # so that the results are the same - time.sleep(0.1) -- rss_ps = ps("ps --no-headers -o rss -p %s" % self.pid) -+ rss_ps = ps('rss', self.pid) - rss_psutil = psutil.Process(self.pid).memory_info()[0] / 1024 - self.assertEqual(rss_ps, rss_psutil) - -+ @unittest.skipIf(APPVEYOR and CYGWIN, "test not reliable on appveyor") - @skip_on_access_denied() - @retry_before_failing() - def test_vsz_memory(self): - # give python interpreter some time to properly initialize - # so that the results are the same - time.sleep(0.1) -- vsz_ps = ps("ps --no-headers -o vsz -p %s" % self.pid) -+ vsz_ps = ps('vsz', self.pid) - vsz_psutil = psutil.Process(self.pid).memory_info()[1] / 1024 - self.assertEqual(vsz_ps, vsz_psutil) - - def test_name(self): - # use command + arg since "comm" keyword not supported on all platforms -- name_ps = ps("ps --no-headers -o command -p %s" % ( -- self.pid)).split(' ')[0] -+ name_ps = ps('command', self.pid).split(' ')[0] - # remove path if there is any, from the command - name_ps = os.path.basename(name_ps).lower() - name_psutil = psutil.Process(self.pid).name().lower() -@@ -125,7 +226,7 @@ class TestProcess(unittest.TestCase): - - @unittest.skipIf(OSX or BSD, 'ps -o start not available') - def test_create_time(self): -- time_ps = ps("ps --no-headers -o start -p %s" % self.pid).split(' ')[0] -+ time_ps = ps('start', self.pid) - time_psutil = psutil.Process(self.pid).create_time() - time_psutil_tstamp = datetime.datetime.fromtimestamp( - time_psutil).strftime("%H:%M:%S") -@@ -137,8 +238,7 @@ class TestProcess(unittest.TestCase): - self.assertIn(time_ps, [time_psutil_tstamp, round_time_psutil_tstamp]) - - def test_exe(self): -- ps_pathname = ps("ps --no-headers -o command -p %s" % -- self.pid).split(' ')[0] -+ ps_pathname = ps('command', self.pid).split(' ')[0] - psutil_pathname = psutil.Process(self.pid).exe() - try: - self.assertEqual(ps_pathname, psutil_pathname) -@@ -153,15 +253,27 @@ class TestProcess(unittest.TestCase): - self.assertEqual(ps_pathname, adjusted_ps_pathname) - - def test_cmdline(self): -- ps_cmdline = ps("ps --no-headers -o command -p %s" % self.pid) -+ ps_cmdline = ps('command', self.pid) - psutil_cmdline = " ".join(psutil.Process(self.pid).cmdline()) -- if SUNOS: -- # ps on Solaris only shows the first part of the cmdline -+ if SUNOS or CYGWIN: -+ # ps on Solaris and Cygwin only shows the first part of the cmdline - psutil_cmdline = psutil_cmdline.split(" ")[0] -+ if CYGWIN: -+ # resolve symlinks -+ if os.path.islink(psutil_cmdline): -+ psutil_cmdline = os.path.splitext( -+ os.path.realpath(psutil_cmdline))[0] - self.assertEqual(ps_cmdline, psutil_cmdline) - -+ # To be more specific, process priorities are complicated in Windows and -+ # there's no simple way, from the command line, to get the information -+ # needed to reproduce the way Cygwin maps Windows process priorties to -+ # 'nice' values (not even through Cygwin's /proc API, which only returns -+ # the "base priority" which actually is not sufficient because what we -+ # really need is the process's "priority class" which is different -+ @unittest.skipIf(CYGWIN, "this is not supported by Cygwin") - def test_nice(self): -- ps_nice = ps("ps --no-headers -o nice -p %s" % self.pid) -+ ps_nice = ps('nice', self.pid) - psutil_nice = psutil.Process().nice() - self.assertEqual(ps_nice, psutil_nice) - -@@ -220,22 +332,7 @@ class TestSystemAPIs(unittest.TestCase): - def test_pids(self): - # Note: this test might fail if the OS is starting/killing - # other processes in the meantime -- if SUNOS: -- cmd = ["ps", "-A", "-o", "pid"] -- else: -- cmd = ["ps", "ax", "-o", "pid"] -- p = get_test_subprocess(cmd, stdout=subprocess.PIPE) -- output = p.communicate()[0].strip() -- assert p.poll() == 0 -- if PY3: -- output = str(output, sys.stdout.encoding) -- pids_ps = [] -- for line in output.split('\n')[1:]: -- if line: -- pid = int(line.split()[0].strip()) -- pids_ps.append(pid) -- # remove ps subprocess pid which is supposed to be dead in meantime -- pids_ps.remove(p.pid) -+ pids_ps = ps('pid') - pids_psutil = psutil.pids() - pids_ps.sort() - pids_psutil.sort() -@@ -244,7 +341,8 @@ class TestSystemAPIs(unittest.TestCase): - if OSX and 0 not in pids_ps: - pids_ps.insert(0, 0) - -- if pids_ps != pids_psutil: -+ # There will often be one more process in pids_ps for ps itself -+ if len(pids_ps) - len(pids_psutil) > 1: - difference = [x for x in pids_psutil if x not in pids_ps] + \ - [x for x in pids_ps if x not in pids_psutil] - self.fail("difference: " + str(difference)) -@@ -254,6 +352,11 @@ class TestSystemAPIs(unittest.TestCase): - @unittest.skipIf(SUNOS, "unreliable on SUNOS") - @unittest.skipIf(TRAVIS, "unreliable on TRAVIS") - def test_nic_names(self): -+ if CYGWIN: -+ # On Cygwin perform the version of this test that uses ipconfig -+ from psutil.tests.test_windows import TestSystemAPIs -+ return TestSystemAPIs._test_nic_names(self) -+ - p = subprocess.Popen("ifconfig -a", shell=1, stdout=subprocess.PIPE) - output = p.communicate()[0].strip() - if p.returncode != 0: -@@ -274,14 +377,23 @@ class TestSystemAPIs(unittest.TestCase): - "unreliable on APPVEYOR or TRAVIS") - @retry_before_failing() - def test_users(self): -- out = sh("who") -- lines = out.split('\n') -- users = [x.split()[0] for x in lines] -- self.assertEqual(len(users), len(psutil.users())) -- terminals = [x.split()[1] for x in lines] -+ if CYGWIN: -+ # NOTE: For reasons I haven't been able to figure out (possibly a -+ # bug in Cygwin) `who` sometimes fails without explicitly -+ # specifying the utmp file. -+ out = sh("who /var/run/utmp") -+ else: -+ out = sh("who") -+ lines = [x.strip() for x in out.split('\n')] -+ self.assertEqual(len(lines), len(psutil.users())) - for u in psutil.users(): -- self.assertTrue(u.name in users, u.name) -- self.assertTrue(u.terminal in terminals, u.terminal) -+ for line in lines: -+ if line.startswith(u.name): -+ rest = line[len(u.name):].split() -+ if u.terminal == rest[0].strip(): -+ break -+ else: -+ self.fail("couldn't find %s in who output" % u.name) - - def test_pid_exists_let_raise(self): - # According to "man 2 kill" possible error values for kill -@@ -330,6 +442,9 @@ class TestSystemAPIs(unittest.TestCase): - - tolerance = 4 * 1024 * 1024 # 4MB - for part in psutil.disk_partitions(all=False): -+ if not os.path.exists(part.mountpoint): -+ continue -+ - usage = psutil.disk_usage(part.mountpoint) - try: - total, used, free, percent = df(part.device) -diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py -index 6580fe9..434cb3a 100755 ---- a/psutil/tests/test_process.py -+++ b/psutil/tests/test_process.py -@@ -29,6 +29,7 @@ from socket import SOCK_STREAM - import psutil - - from psutil import BSD -+from psutil import CYGWIN - from psutil import FREEBSD - from psutil import LINUX - from psutil import NETBSD -@@ -37,6 +38,7 @@ from psutil import OSX - from psutil import POSIX - from psutil import SUNOS - from psutil import WINDOWS -+from psutil._common import encode - from psutil._common import supports_ipv6 - from psutil._compat import callable - from psutil._compat import long -@@ -128,22 +130,30 @@ class TestProcess(unittest.TestCase): - self.assertFalse(psutil.pid_exists(p.pid)) - if POSIX: - self.assertEqual(exit_sig, -sig) -- # -- sproc = get_test_subprocess() -- p = psutil.Process(sproc.pid) -- p.send_signal(sig) -- with mock.patch('psutil.os.kill', -- side_effect=OSError(errno.ESRCH, "")): -- with self.assertRaises(psutil.NoSuchProcess): -- p.send_signal(sig) -- # -- sproc = get_test_subprocess() -- p = psutil.Process(sproc.pid) -- p.send_signal(sig) -- with mock.patch('psutil.os.kill', -- side_effect=OSError(errno.EPERM, "")): -- with self.assertRaises(psutil.AccessDenied): -- psutil.Process().send_signal(sig) -+ -+ if not CYGWIN: -+ # NOTE: This portion of the test is not reliable on Cygwin due -+ # to an apparent bug (?) in Cygwin that prevents zombie -+ # processes from remaining accessible before wait() in some -+ # cases. See -+ # https://www.cygwin.com/ml/cygwin/2017-02/msg00187.html -+ -+ sproc = get_test_subprocess() -+ p = psutil.Process(sproc.pid) -+ p.send_signal(sig) -+ with mock.patch('psutil.os.kill', -+ side_effect=OSError(errno.ESRCH, "")): -+ with self.assertRaises(psutil.NoSuchProcess): -+ p.send_signal(sig) -+ # -+ sproc = get_test_subprocess() -+ p = psutil.Process(sproc.pid) -+ p.send_signal(sig) -+ with mock.patch('psutil.os.kill', -+ side_effect=OSError(errno.EPERM, "")): -+ with self.assertRaises(psutil.AccessDenied): -+ psutil.Process().send_signal(sig) -+ - # Sending a signal to process with PID 0 is not allowed as - # it would affect every process in the process group of - # the calling process (os.getpid()) instead of PID 0"). -@@ -278,10 +288,18 @@ class TestProcess(unittest.TestCase): - # Use os.times()[:2] as base values to compare our results - # using a tolerance of +/- 0.1 seconds. - # It will fail if the difference between the values is > 0.1s. -- if (max([user_time, utime]) - min([user_time, utime])) > 0.1: -+ # On cygwin there seems to be enough overhead differece between -+ # os.times() and reading /proc/stat that the tolerance should -+ # be a bit higher -+ if CYGWIN: -+ tol = 0.2 -+ else: -+ tol = 0.1 -+ -+ if (max([user_time, utime]) - min([user_time, utime])) > tol: - self.fail("expected: %s, found: %s" % (utime, user_time)) - -- if (max([kernel_time, ktime]) - min([kernel_time, ktime])) > 0.1: -+ if (max([kernel_time, ktime]) - min([kernel_time, ktime])) > tol: - self.fail("expected: %s, found: %s" % (ktime, kernel_time)) - - @unittest.skipUnless(hasattr(psutil.Process, "cpu_num"), -@@ -317,7 +335,10 @@ class TestProcess(unittest.TestCase): - terminal = psutil.Process().terminal() - if sys.stdin.isatty() or sys.stdout.isatty(): - tty = os.path.realpath(sh('tty')) -- self.assertEqual(terminal, tty) -+ if CYGWIN and terminal == '/dev/console': -+ self.assertTrue(tty.startswith('/dev/cons')) -+ else: -+ self.assertEqual(terminal, tty) - else: - self.assertIsNone(terminal) - -@@ -1086,7 +1107,8 @@ class TestProcess(unittest.TestCase): - psutil.CONN_NONE, - ("all", "inet", "inet6", "udp", "udp6")) - -- @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'AF_UNIX not supported') -+ @unittest.skipUnless(hasattr(socket, 'AF_UNIX') and not CYGWIN, -+ 'AF_UNIX is not supported') - @skip_on_access_denied(only_if=OSX) - def test_connections_unix(self): - def check(type): -@@ -1115,6 +1137,8 @@ class TestProcess(unittest.TestCase): - 'socket.fromfd() not supported') - @unittest.skipIf(WINDOWS or SUNOS, - 'connection fd not available on this platform') -+ @unittest.skipIf(CYGWIN, -+ 'cannot map sockets to their fds on Cygwin') - def test_connection_fromfd(self): - with contextlib.closing(socket.socket()) as sock: - sock.bind(('localhost', 0)) -@@ -1191,8 +1215,10 @@ class TestProcess(unittest.TestCase): - for p in psutil.process_iter(): - if p.pid == sproc.pid: - continue -- # XXX: sometimes this fails on Windows; not sure why. -- self.assertNotEqual(p.ppid(), this_parent, msg=p) -+ try: -+ self.assertNotEqual(p.ppid(), this_parent, msg=p) -+ except psutil.AccessDenied: -+ pass - - def test_children(self): - p = psutil.Process() -@@ -1236,8 +1262,18 @@ class TestProcess(unittest.TestCase): - except psutil.Error: - pass - # this is the one, now let's make sure there are no duplicates -- pid = sorted(table.items(), key=lambda x: x[1])[-1][0] -- p = psutil.Process(pid) -+ for pid, _ in sorted(table.items(), key=lambda x: x[1], reverse=True): -+ try: -+ # Just make sure the process can be accessed and still actually -+ # exists (or exists in the first place--e.g. there is no such -+ # process with pid=1 on Cygwin even though it is the default -+ # ppid -+ p = psutil.Process(pid) -+ except (psutil.AccessDenied, psutil.NoSuchProcess): -+ continue -+ -+ break -+ - try: - c = p.children(recursive=True) - except psutil.AccessDenied: # windows -@@ -1351,7 +1387,7 @@ class TestProcess(unittest.TestCase): - p = psutil.Process(sproc.pid) - p.terminate() - p.wait() -- if WINDOWS: -+ if WINDOWS or CYGWIN: - call_until(psutil.pids, "%s not in ret" % p.pid) - self.assertFalse(p.is_running()) - # self.assertFalse(p.pid in psutil.pids(), msg="retcode = %s" % -@@ -1394,6 +1430,8 @@ class TestProcess(unittest.TestCase): - except psutil.AccessDenied: - if OPENBSD and name in ('threads', 'num_threads'): - pass -+ elif APPVEYOR and CYGWIN and name == 'cpu_affinity': -+ pass - else: - raise - except NotImplementedError: -@@ -1403,7 +1441,14 @@ class TestProcess(unittest.TestCase): - "NoSuchProcess exception not raised for %r, retval=%s" % ( - name, ret)) - -- @unittest.skipUnless(POSIX, 'POSIX only') -+ @unittest.skipUnless(POSIX and not CYGWIN, 'POSIX only') -+ # This test can't really work on Cygwin since some psutil interfaces -+ # (such as create_time, currently) rely on the Windows API, and while -+ # Cygwin does support zombie processes, the real Windows processes are -+ # already gone in that case, and the zombie "processes" only remain -+ # in Cygwin's internal process table -+ # TODO: In the future it would be nice to have cleaner handling of -+ # zombie processes on Cygwin - def test_zombie_process(self): - def succeed_or_zombie_p_exc(fun, *args, **kwargs): - try: -@@ -1806,17 +1851,17 @@ class TestFetchAllProcesses(unittest.TestCase): - def memory_info(self, ret, proc): - for name in ret._fields: - self.assertGreaterEqual(getattr(ret, name), 0) -- if POSIX and ret.vms != 0: -+ if WINDOWS or CYGWIN: -+ assert ret.peak_wset >= ret.wset, ret -+ assert ret.peak_paged_pool >= ret.paged_pool, ret -+ assert ret.peak_nonpaged_pool >= ret.nonpaged_pool, ret -+ assert ret.peak_pagefile >= ret.pagefile, ret -+ elif POSIX and ret.vms != 0: - # VMS is always supposed to be the highest - for name in ret._fields: - if name != 'vms': - value = getattr(ret, name) - assert ret.vms > value, ret -- elif WINDOWS: -- assert ret.peak_wset >= ret.wset, ret -- assert ret.peak_paged_pool >= ret.paged_pool, ret -- assert ret.peak_nonpaged_pool >= ret.nonpaged_pool, ret -- assert ret.peak_pagefile >= ret.pagefile, ret - - def memory_full_info(self, ret, proc): - total = psutil.virtual_memory().total -@@ -1855,6 +1900,11 @@ class TestFetchAllProcesses(unittest.TestCase): - - def cwd(self, ret, proc): - if ret is not None: # BSD may return None -+ if CYGWIN and ret == '': -+ # This can happen on Cygwin for processes that we can't access -+ # without elevation -+ return -+ - assert os.path.isabs(ret), ret - try: - st = os.stat(ret) -@@ -2025,9 +2075,7 @@ class TestUnicode(unittest.TestCase): - def test_proc_name(self): - subp = get_test_subprocess(cmd=[self.uexe]) - if WINDOWS: -- # XXX: why is this like this? -- from psutil._pswindows import py2_strencode -- name = py2_strencode(psutil._psplatform.cext.proc_name(subp.pid)) -+ name = encode(psutil._psplatform.cext.proc_name(subp.pid)) - else: - name = psutil.Process(subp.pid).name() - if not OSX and TRAVIS: -@@ -2098,6 +2146,16 @@ class TestInvalidUnicode(TestUnicode): - uexe = TESTFN + b"f\xc0\x80" - udir = TESTFN + b"d\xc0\x80" - -+ # NOTE: Cygwin uses its own scheme for encoding characters in filenames -+ # that are not valid unicode codepoints (such as \x80) (specifically, it -+ # converts them to codepoints in a private use area, e.g. u+f080). So -+ # the filename ends up being reported as the utf-8 encoding of u+f080 -+ # This seems to be handled better on a problem on Python 3, however. -+ @unittest.skipIf(not PY3 and CYGWIN, -+ "Cygwin does not treat arbitrary bytes as on POSIX") -+ def test_proc_exe(self): -+ return super(TestInvalidUnicode, self).test_proc_exe() -+ - - if __name__ == '__main__': - run_test_module_by_name(__file__) -diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py -index 013ae8e..1daf41a 100755 ---- a/psutil/tests/test_system.py -+++ b/psutil/tests/test_system.py -@@ -20,6 +20,7 @@ import time - - import psutil - from psutil import BSD -+from psutil import CYGWIN - from psutil import FREEBSD - from psutil import LINUX - from psutil import NETBSD -@@ -469,7 +470,7 @@ class TestSystemAPIs(unittest.TestCase): - if SUNOS: - # on solaris apparently mount points can also be files - assert os.path.exists(disk.mountpoint), disk -- else: -+ elif not CYGWIN: - assert os.path.isdir(disk.mountpoint), disk - assert disk.fstype, disk - -@@ -477,7 +478,7 @@ class TestSystemAPIs(unittest.TestCase): - ls = psutil.disk_partitions(all=True) - self.assertTrue(ls, msg=ls) - for disk in psutil.disk_partitions(all=True): -- if not WINDOWS: -+ if not (WINDOWS or CYGWIN): - try: - os.stat(disk.mountpoint) - except OSError as err: -@@ -519,7 +520,7 @@ class TestSystemAPIs(unittest.TestCase): - - from psutil._common import conn_tmap - for kind, groups in conn_tmap.items(): -- if SUNOS and kind == 'unix': -+ if (SUNOS or CYGWIN) and kind == 'unix': - continue - families, types_ = groups - cons = psutil.net_connections(kind) -diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py -index 3fcc20e..ba25e28 100755 ---- a/psutil/tests/test_windows.py -+++ b/psutil/tests/test_windows.py -@@ -68,7 +68,13 @@ def wrap_exceptions(fun): - @unittest.skipUnless(WINDOWS, "WINDOWS only") - class TestSystemAPIs(unittest.TestCase): - -+ # Note: Implemented as a staticmethod for ease of sharing with test_posix -+ # for running this test on Cygwin - def test_nic_names(self): -+ return self._test_nic_names(self) -+ -+ @staticmethod -+ def _test_nic_names(test_case): - p = subprocess.Popen(['ipconfig', '/all'], stdout=subprocess.PIPE) - out = p.communicate()[0] - if PY3: -@@ -78,7 +84,7 @@ class TestSystemAPIs(unittest.TestCase): - if "pseudo-interface" in nic.replace(' ', '-').lower(): - continue - if nic not in out: -- self.fail( -+ test_case.fail( - "%r nic wasn't found in 'ipconfig /all' output" % nic) - - @unittest.skipUnless('NUMBER_OF_PROCESSORS' in os.environ, -diff --git a/scripts/disk_usage.py b/scripts/disk_usage.py -index 37f4da0..a0924ce 100755 ---- a/scripts/disk_usage.py -+++ b/scripts/disk_usage.py -@@ -48,7 +48,12 @@ def main(): - # ENOENT, pop-up a Windows GUI error for a non-ready - # partition or just hang. - continue -+ if not os.path.exists(part.mountpoint): -+ # In case the mount point itself has been deleted -+ continue -+ - usage = psutil.disk_usage(part.mountpoint) -+ - print(templ % ( - part.device, - bytes2human(usage.total), -diff --git a/scripts/procsmem.py b/scripts/procsmem.py -index a28794b..287a800 100755 ---- a/scripts/procsmem.py -+++ b/scripts/procsmem.py -@@ -41,7 +41,7 @@ import sys - import psutil - - --if not (psutil.LINUX or psutil.OSX or psutil.WINDOWS): -+if not (psutil.LINUX or psutil.OSX or psutil.WINDOWS or psutil.CYGWIN): - sys.exit("platform not supported") - - -diff --git a/setup.py b/setup.py -index 47772da..bd6b5ae 100755 ---- a/setup.py -+++ b/setup.py -@@ -26,6 +26,7 @@ HERE = os.path.abspath(os.path.dirname(__file__)) - sys.path.insert(0, os.path.join(HERE, "psutil")) - - from _common import BSD # NOQA -+from _common import CYGWIN # NOQA - from _common import FREEBSD # NOQA - from _common import LINUX # NOQA - from _common import NETBSD # NOQA -@@ -230,7 +231,33 @@ elif SUNOS: - sources=['psutil/_psutil_sunos.c'], - define_macros=macros, - libraries=['kstat', 'nsl', 'socket']) -+elif CYGWIN: -+ macros.extend([ -+ ("PSUTIL_CYGWIN", 1), -+ ("PSAPI_VERSION", 1) -+ ]) -+ -+ # sys.getwindowsversion() is not available in Cygwin's Python -+ import re -+ winver_re = re.compile(r'CYGWIN_NT-(?P\d+)\.(?P\d+)') - -+ def get_winver(): -+ verstr = os.uname()[0] -+ m = winver_re.search(verstr) -+ maj = int(m.group('major')) -+ min = int(m.group('minor')) -+ return '0x0%s' % ((maj * 100) + min) -+ -+ macros.append(("_WIN32_WINNT", get_winver())) -+ -+ ext = Extension( -+ 'psutil._psutil_cygwin', -+ sources=['psutil/_psutil_cygwin.c', -+ 'psutil/_psutil_common.c', -+ 'psutil/arch/windows/py_error.c', -+ 'psutil/arch/windows/process_info.c'], -+ define_macros=macros, -+ libraries=["psapi", "iphlpapi"]) - else: - sys.exit('platform %s is not supported' % sys.platform) - diff --git a/build/pkgs/psutil/spkg-install.in b/build/pkgs/psutil/spkg-install.in deleted file mode 100644 index 79b1568770f..00000000000 --- a/build/pkgs/psutil/spkg-install.in +++ /dev/null @@ -1,7 +0,0 @@ -if [ "$UNAME" = "Darwin" ] && [ $MACOSX_VERSION -ge 16 ]; then - echo "OS X 10.$[$MACOSX_VERSION-4] Building with clang." - CC=clang - export CFLAGS="$CFLAGS_NON_NATIVE" -fi - -cd src && sdh_pip_install . diff --git a/build/pkgs/psutil/type b/build/pkgs/psutil/type deleted file mode 100644 index a6a7b9cd726..00000000000 --- a/build/pkgs/psutil/type +++ /dev/null @@ -1 +0,0 @@ -standard diff --git a/src/requirements.txt.m4 b/src/requirements.txt.m4 index b12c71acb45..57dca4227a6 100644 --- a/src/requirements.txt.m4 +++ b/src/requirements.txt.m4 @@ -34,7 +34,6 @@ dnl pynac # after converting to a pip-installable package dnl From Makefile.in: SAGERUNTIME ipython==esyscmd(`printf $(sed "s/[.]p.*//;" ../ipython/package-version.txt)') pexpect==esyscmd(`printf $(sed "s/[.]p.*//;" ../pexpect/package-version.txt)') -psutil==esyscmd(`printf $(sed "s/[.]p.*//;" ../psutil/package-version.txt)') dnl From Makefile.in: DOC_DEPENDENCIES sphinx==esyscmd(`printf $(sed "s/[.]p.*//;" ../sphinx/package-version.txt)') diff --git a/src/setup.cfg.m4 b/src/setup.cfg.m4 index 60ff8b757a6..62825fc8a5b 100644 --- a/src/setup.cfg.m4 +++ b/src/setup.cfg.m4 @@ -48,7 +48,6 @@ dnl From Makefile.in: SAGERUNTIME esyscmd(`sage-get-system-packages install-requires \ ipython \ pexpect \ - psutil \ | sed "2,\$s/^/ /;"')dnl dnl From Makefile.in: DOC_DEPENDENCIES esyscmd(`sage-get-system-packages install-requires \ From 15884f325b3d4c9d62035e470e67093d7d42575d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 28 Sep 2021 21:36:48 -0700 Subject: [PATCH 347/511] src/sage/matrix/matrix_space.py: Import element classes on demand, fall back to generic on ImportError --- src/sage/matrix/matrix_space.py | 157 ++++++++++++++++++++++---------- 1 file changed, 108 insertions(+), 49 deletions(-) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index eabba820926..2dfb022ff32 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -40,33 +40,16 @@ from . import matrix_generic_dense from . import matrix_generic_sparse -from . import matrix_modn_sparse - -from . import matrix_mod2_dense -from . import matrix_gf2e_dense - -from . import matrix_integer_dense -from . import matrix_integer_sparse - -from . import matrix_rational_dense -from . import matrix_rational_sparse - -from . import matrix_polynomial_dense -from . import matrix_mpolynomial_dense - # Sage imports import sage.structure.coerce from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation import sage.rings.integer as integer -import sage.rings.number_field.all -import sage.rings.finite_rings.integer_mod_ring import sage.rings.finite_rings.finite_field_constructor -import sage.rings.polynomial.multi_polynomial_ring_base import sage.misc.latex as latex import sage.modules.free_module -from sage.misc.all import lazy_attribute +from sage.misc.lazy_attribute import lazy_attribute from sage.categories.rings import Rings from sage.categories.fields import Fields @@ -209,25 +192,54 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): if implementation is None: # Choose default implementation: if R is sage.rings.integer_ring.ZZ: - return matrix_integer_dense.Matrix_integer_dense + try: + from . import matrix_integer_dense + except ImportError: + pass + else: + return matrix_integer_dense.Matrix_integer_dense - if R is sage.rings.rational_field.QQ: - return matrix_rational_dense.Matrix_rational_dense + elif R is sage.rings.rational_field.QQ: + try: + from . import matrix_rational_dense + except ImportError: + pass + else: + return matrix_rational_dense.Matrix_rational_dense - if R is sage.rings.real_double.RDF: - from . import matrix_real_double_dense - return matrix_real_double_dense.Matrix_real_double_dense + elif isinstance(R, sage.rings.abc.RealDoubleField): + try: + from . import matrix_real_double_dense + except ImportError: + pass + else: + return matrix_real_double_dense.Matrix_real_double_dense - if R is sage.rings.complex_double.CDF: + elif isinstance(R, sage.rings.abc.ComplexDoubleField): if implementation is None or implementation == 'numpy': - from . import matrix_complex_double_dense - return matrix_complex_double_dense.Matrix_complex_double_dense + try: + from . import matrix_complex_double_dense + except ImportError: + pass + else: + return matrix_complex_double_dense.Matrix_complex_double_dense - if sage.rings.finite_rings.finite_field_constructor.is_FiniteField(R): + elif sage.rings.finite_rings.finite_field_constructor.is_FiniteField(R): if R.order() == 2: - return matrix_mod2_dense.Matrix_mod2_dense + try: + from . import matrix_mod2_dense + except ImportError: + pass + else: + return matrix_mod2_dense.Matrix_mod2_dense + if R.characteristic() == 2 and R.order() <= 65536: # 65536 == 2^16 - return matrix_gf2e_dense.Matrix_gf2e_dense + try: + from . import matrix_gf2e_dense + except ImportError: + pass + else: + return matrix_gf2e_dense.Matrix_gf2e_dense if (not R.is_prime_field()) and R.order() < 256: try: @@ -247,21 +259,47 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): from . import matrix_cyclo_dense return matrix_cyclo_dense.Matrix_cyclo_dense - from sage.symbolic.ring import SR - if R is SR: - from . import matrix_symbolic_dense - return matrix_symbolic_dense.Matrix_symbolic_dense + try: + from sage.symbolic.ring import SR + except ImportError: + pass + else: + if R is SR: + try: + from . import matrix_symbolic_dense + except ImportError: + pass + else: + return matrix_symbolic_dense.Matrix_symbolic_dense - from sage.rings.complex_arb import ComplexBallField - if isinstance(R, ComplexBallField): - from . import matrix_complex_ball_dense - return matrix_complex_ball_dense.Matrix_complex_ball_dense + if isinstance(R, sage.rings.abc.ComplexBallField): + try: + from . import matrix_complex_ball_dense + except ImportError: + pass + else: + return matrix_complex_ball_dense.Matrix_complex_ball_dense - if sage.rings.polynomial.polynomial_ring.is_PolynomialRing(R) and R.base_ring() in _Fields: - return matrix_polynomial_dense.Matrix_polynomial_dense + try: + from sage.rings.polynomial import polynomial_ring, multi_polynomial_ring_base + except ImportError: + pass + else: + if polynomial_ring.is_PolynomialRing(R) and R.base_ring() in _Fields: + try: + from . import matrix_polynomial_dense + except ImportError: + pass + else: + return matrix_polynomial_dense.Matrix_polynomial_dense - if sage.rings.polynomial.multi_polynomial_ring_base.is_MPolynomialRing(R) and R.base_ring() in _Fields: - return matrix_mpolynomial_dense.Matrix_mpolynomial_dense + elif multi_polynomial_ring_base.is_MPolynomialRing(R) and R.base_ring() in _Fields: + try: + from . import matrix_mpolynomial_dense + except ImportError: + pass + else: + return matrix_mpolynomial_dense.Matrix_mpolynomial_dense # The fallback return matrix_generic_dense.Matrix_generic_dense @@ -269,15 +307,19 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): # Deal with request for a specific implementation if implementation == 'flint': if R is sage.rings.integer_ring.ZZ: + from . import matrix_integer_dense return matrix_integer_dense.Matrix_integer_dense if R is sage.rings.rational_field.QQ: + from . import matrix_rational_dense return matrix_rational_dense.Matrix_rational_dense raise ValueError("'flint' matrices are only available over the integers or the rationals") if implementation == 'm4ri': if R.is_field() and R.characteristic() == 2 and R.order() <= 65536: if R.order() == 2: + from . import matrix_mod2_dense return matrix_mod2_dense.Matrix_mod2_dense + from . import matrix_gf2e_dense return matrix_gf2e_dense.Matrix_gf2e_dense raise ValueError("'m4ri' matrices are only available for fields of characteristic 2 and order <= 65536") @@ -326,14 +368,30 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): if implementation is not None: raise ValueError("cannot choose an implementation for sparse matrices") - if isinstance(R, sage.rings.abc.IntegerModRing) and R.order() < matrix_modn_sparse.MAX_MODULUS: - return matrix_modn_sparse.Matrix_modn_sparse + if isinstance(R, sage.rings.abc.IntegerModRing): + try: + from . import matrix_modn_sparse + except ImportError: + pass + else: + if R.order() < matrix_modn_sparse.MAX_MODULUS: + return matrix_modn_sparse.Matrix_modn_sparse if sage.rings.rational_field.is_RationalField(R): - return matrix_rational_sparse.Matrix_rational_sparse + try: + from . import matrix_rational_sparse + except ImportError: + pass + else: + return matrix_rational_sparse.Matrix_rational_sparse if sage.rings.integer_ring.is_IntegerRing(R): - return matrix_integer_sparse.Matrix_integer_sparse + try: + from . import matrix_integer_sparse + except ImportError: + pass + else: + return matrix_integer_sparse.Matrix_integer_sparse # the fallback return matrix_generic_sparse.Matrix_generic_sparse @@ -2454,8 +2512,8 @@ def test_trivial_matrices_inverse(ring, sparse=True, implementation=None, checkr # Fix unpickling Matrix_modn_dense and Matrix_integer_2x2 -from sage.matrix.matrix_modn_dense_double import Matrix_modn_dense_double -from sage.matrix.matrix_integer_dense import Matrix_integer_dense +lazy_import('sage.matrix.matrix_modn_dense_double', 'Matrix_modn_dense_double') +lazy_import('sage.matrix.matrix_integer_dense', 'Matrix_integer_dense') from sage.misc.persist import register_unpickle_override def _MatrixSpace_ZZ_2x2(): from sage.rings.integer_ring import ZZ @@ -2468,5 +2526,6 @@ def _MatrixSpace_ZZ_2x2(): 'MatrixSpace_ZZ_2x2_class', MatrixSpace) register_unpickle_override('sage.matrix.matrix_integer_2x2', 'MatrixSpace_ZZ_2x2', _MatrixSpace_ZZ_2x2) +lazy_import('sage.matrix.matrix_gf2e_dense', 'unpickle_matrix_gf2e_dense_v0') register_unpickle_override('sage.matrix.matrix_mod2e_dense', - 'unpickle_matrix_mod2e_dense_v0', matrix_gf2e_dense.unpickle_matrix_gf2e_dense_v0) + 'unpickle_matrix_mod2e_dense_v0', unpickle_matrix_gf2e_dense_v0) From ac58286892b17ccac976e24fe67aaff436743941 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 22:27:17 -0700 Subject: [PATCH 348/511] Matrix.gram_schmidt: Use sage.rings.abc --- src/sage/matrix/matrix2.pyx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 74e01aa7241..c89931c018f 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -10646,10 +10646,8 @@ cdef class Matrix(Matrix1): sage: mu*G == A True """ - import sage.rings.real_double - import sage.rings.complex_double R = self.base_ring() - if R in [sage.rings.real_double.RDF, sage.rings.complex_double.CDF]: + if instance(R, (sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)): Q, R = self.transpose().QR() m = R.nrows(); n = R.ncols() if m > n: From 6d4ee6e7e645fcee216113f8cf86de7e6cc5e833 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Oct 2021 22:30:16 -0700 Subject: [PATCH 349/511] Matrix.gram_schmidt: Use sage.rings.abc (fixup) --- src/sage/matrix/matrix2.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index c89931c018f..d9bf52e7bb4 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -10647,7 +10647,7 @@ cdef class Matrix(Matrix1): True """ R = self.base_ring() - if instance(R, (sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)): + if isinstance(R, (sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)): Q, R = self.transpose().QR() m = R.nrows(); n = R.ncols() if m > n: From 056558f11e6f8d141ecfd05896e9f45763d8675d Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 8 Oct 2021 15:57:07 -0400 Subject: [PATCH 350/511] Trac #32656: shift argc/argv down during GAP initialization. There used to be between 14 and 18 arguments passed to GAP. Now there are between 10 and 14. Tweak argc/argv appropriately. --- src/sage/libs/gap/util.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/libs/gap/util.pyx b/src/sage/libs/gap/util.pyx index c501a26140e..08c4c40cc01 100644 --- a/src/sage/libs/gap/util.pyx +++ b/src/sage/libs/gap/util.pyx @@ -239,7 +239,7 @@ cdef initialize(): # Define argv variable, which we will pass in to # initialize GAP. - cdef char* argv[18] + cdef char* argv[14] argv[0] = "sage" argv[1] = "-l" s = str_to_bytes(gap_root(), FS_ENCODING, "surrogateescape") @@ -256,7 +256,7 @@ cdef initialize(): # 4096 unfortunately is the hard-coded max, but should # be long enough for most cases - cdef int argc = 14 # argv[argc] must be NULL + cdef int argc = 10 # argv[argc] must be NULL from .saved_workspace import workspace workspace, workspace_is_up_to_date = workspace() From 32c87b932eef87707d1acf6c5965a2850df39f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 9 Oct 2021 11:16:24 +0200 Subject: [PATCH 351/511] fix doctests in doc/ --- src/doc/de/tutorial/tour_advanced.rst | 1 + src/doc/en/constructions/modular_forms.rst | 3 +-- src/doc/en/tutorial/tour_advanced.rst | 1 + src/doc/fr/tutorial/tour_advanced.rst | 1 + src/doc/ja/tutorial/tour_advanced.rst | 1 + src/doc/pt/tutorial/tour_advanced.rst | 1 + src/doc/ru/tutorial/tour_advanced.rst | 1 + 7 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/doc/de/tutorial/tour_advanced.rst b/src/doc/de/tutorial/tour_advanced.rst index b36e8ae8fff..7ee92b357df 100644 --- a/src/doc/de/tutorial/tour_advanced.rst +++ b/src/doc/de/tutorial/tour_advanced.rst @@ -405,6 +405,7 @@ Räumen von Modulformen zur Verfügung. Zum Beispiel, :: + sage: from sage.modular.dims import dimension_cusp_forms sage: dimension_cusp_forms(Gamma0(11),2) 1 sage: dimension_cusp_forms(Gamma0(1),12) diff --git a/src/doc/en/constructions/modular_forms.rst b/src/doc/en/constructions/modular_forms.rst index d3c76fd2d33..7979214859d 100644 --- a/src/doc/en/constructions/modular_forms.rst +++ b/src/doc/en/constructions/modular_forms.rst @@ -32,8 +32,6 @@ dimensions of newforms), ``dimension_modular_forms`` (for modular forms), and ``dimension_eis`` (for Eisenstein series). The syntax is similar - see the Reference Manual for examples. -In future versions of Sage, more related commands will be added. - .. index:: cosets of Gamma_0 Coset representatives @@ -116,6 +114,7 @@ and related curves. Here are some examples of the syntax: :: + sage: from sage.modular.dims import dimension_cusp_forms sage: dimension_cusp_forms(Gamma0(22)) 2 sage: dimension_cusp_forms(Gamma0(30)) diff --git a/src/doc/en/tutorial/tour_advanced.rst b/src/doc/en/tutorial/tour_advanced.rst index db8f363d5bc..a34bb01f5e4 100644 --- a/src/doc/en/tutorial/tour_advanced.rst +++ b/src/doc/en/tutorial/tour_advanced.rst @@ -402,6 +402,7 @@ spaces of modular forms. For example, :: + sage: from sage.modular.dims import dimension_cusp_forms sage: dimension_cusp_forms(Gamma0(11),2) 1 sage: dimension_cusp_forms(Gamma0(1),12) diff --git a/src/doc/fr/tutorial/tour_advanced.rst b/src/doc/fr/tutorial/tour_advanced.rst index d9ec556934a..c6a0f2078e8 100644 --- a/src/doc/fr/tutorial/tour_advanced.rst +++ b/src/doc/fr/tutorial/tour_advanced.rst @@ -402,6 +402,7 @@ d'espaces de formes modulaires. Par exemple, :: + sage: from sage.modular.dims import dimension_cusp_forms sage: dimension_cusp_forms(Gamma0(11),2) 1 sage: dimension_cusp_forms(Gamma0(1),12) diff --git a/src/doc/ja/tutorial/tour_advanced.rst b/src/doc/ja/tutorial/tour_advanced.rst index 431cb2a8a16..a2b53ffc07a 100644 --- a/src/doc/ja/tutorial/tour_advanced.rst +++ b/src/doc/ja/tutorial/tour_advanced.rst @@ -383,6 +383,7 @@ Sageを使ってモジュラー空間の次元,モジュラー・シンポル :: + sage: from sage.modular.dims import dimension_cusp_forms sage: dimension_cusp_forms(Gamma0(11),2) 1 sage: dimension_cusp_forms(Gamma0(1),12) diff --git a/src/doc/pt/tutorial/tour_advanced.rst b/src/doc/pt/tutorial/tour_advanced.rst index dcd0969fb8e..075b3b1551e 100644 --- a/src/doc/pt/tutorial/tour_advanced.rst +++ b/src/doc/pt/tutorial/tour_advanced.rst @@ -402,6 +402,7 @@ de formas modulares. Por exemplo, :: + sage: from sage.modular.dims import dimension_cusp_forms sage: dimension_cusp_forms(Gamma0(11),2) 1 sage: dimension_cusp_forms(Gamma0(1),12) diff --git a/src/doc/ru/tutorial/tour_advanced.rst b/src/doc/ru/tutorial/tour_advanced.rst index 6d1d3bbb34c..69eb42dfd4c 100644 --- a/src/doc/ru/tutorial/tour_advanced.rst +++ b/src/doc/ru/tutorial/tour_advanced.rst @@ -364,6 +364,7 @@ Sage может выполнять вычисления, связанные с :: + sage: from sage.modular.dims import dimension_cusp_forms sage: dimension_cusp_forms(Gamma0(11),2) 1 sage: dimension_cusp_forms(Gamma0(1),12) From 2d852ad84c878ec529300db0e2825f1460b2e0bc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 9 Oct 2021 21:25:04 -0700 Subject: [PATCH 352/511] build/bin/sage-dist-helpers (sdh_pip_uninstall): Use build/bin/sage-pip-uninstall, resurrected in simplified form --- build/bin/sage-dist-helpers | 6 +----- build/bin/sage-pip-uninstall | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) create mode 100755 build/bin/sage-pip-uninstall diff --git a/build/bin/sage-dist-helpers b/build/bin/sage-dist-helpers index 4a8862d50f6..993bc9c65b7 100644 --- a/build/bin/sage-dist-helpers +++ b/build/bin/sage-dist-helpers @@ -316,11 +316,7 @@ sdh_store_and_pip_install_wheel() { } sdh_pip_uninstall() { - # --disable-pip-version-check: Don't periodically check PyPI to determine whether a new version of pip is available - # --no-input: Disable prompting for input. - # --yes: Don't ask for confirmation of uninstall deletions - # See sage-pip-install for a discussion of the other flags. - python3 -m pip uninstall --isolated --disable-pip-version-check --yes --no-input "$@" + sage-pip-uninstall "$@" if [ $? -ne 0 ]; then echo "Warning: pip exited with status $?" >&2 fi diff --git a/build/bin/sage-pip-uninstall b/build/bin/sage-pip-uninstall new file mode 100755 index 00000000000..3017627dbbc --- /dev/null +++ b/build/bin/sage-pip-uninstall @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# This command ensures that any previous installations of the same package +# are uninstalled. + +# Note: "sage-pip-uninstall" is meant to be run after $(PYTHON) has +# been installed (either as an spkg or as a venv over a system python3). +# It is then guaranteed by sage-env that PATH is set in a way that "python3" +# refers to the correct python3. +PYTHON=python3 + +# The PIP variable is only used to determine the name of the lock file. +PIP=pip3 + +# We should avoid running pip while uninstalling a package because that +# is prone to race conditions. Therefore, we use a lockfile while +# running pip. This is implemented in the Python script sage-flock +LOCK="$SAGE_LOCAL/var/lock/$PIP.lock" + + # --disable-pip-version-check: Don't periodically check PyPI to determine whether a new version of pip is available + # --no-input: Disable prompting for input. + # --yes: Don't ask for confirmation of uninstall deletions + # See sage-pip-install for a discussion of the other flags. +sage-flock -x $LOCK $PYTHON -m pip uninstall --isolated --disable-pip-version-check --yes --no-input "$@" From b5a89ad82614300cef196fb0d4eed4a07a591235 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 9 Oct 2021 21:26:00 -0700 Subject: [PATCH 353/511] build/bin/sage-dist-helpers (sdh_store_and_pip_install_wheel): Uninstall before installing, to ensure the wheel is installed even if the version is the same --- build/bin/sage-dist-helpers | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/build/bin/sage-dist-helpers b/build/bin/sage-dist-helpers index 993bc9c65b7..a9639b26871 100644 --- a/build/bin/sage-dist-helpers +++ b/build/bin/sage-dist-helpers @@ -306,6 +306,17 @@ sdh_store_and_pip_install_wheel() { local sudo="" local root="" fi + # Trac #32659: pip no longer reinstalls local wheels if the version is the same. + # Because neither (1) applying patches nor (2) local changes (in the case + # of sage-conf, sage-setup, etc.) bump the version number, we need to + # override this behavior. The pip install option --force-reinstall does too + # much -- it also reinstalls all dependencies, which we do not want. + wheel_basename="${wheel##*/}" + distname="${wheel_basename%%-*}" + $sudo python3 -m pip uninstall --isolated --disable-pip-version-check --yes --no-input $distname + if [ $? -ne 0 ]; then + echo "(ignoring error)" >&2 + fi $sudo sage-pip-install $root $pip_options "$wheel" || \ sdh_die "Error installing ${wheel##*/}" if [ -n "${SAGE_PKG_DIR}" ]; then From 30a272e613ecf63b12702bc7fa1d630f2502ce83 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 9 Oct 2021 21:26:49 -0700 Subject: [PATCH 354/511] build/pkgs/sage_setup/dependencies: Add interpreter specs as dependencies --- build/pkgs/sage_setup/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/sage_setup/dependencies b/build/pkgs/sage_setup/dependencies index 99553f0cc9b..d99d4aed55e 100644 --- a/build/pkgs/sage_setup/dependencies +++ b/build/pkgs/sage_setup/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cython pkgconfig | $(PYTHON_TOOLCHAIN) +$(PYTHON) cython pkgconfig $(SAGE_ROOT)/pkgs/sage-setup/sage_setup/autogen/interpreters/specs/*.py | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. From 4a8f4096e3bdd9b0845a2fd17a19983b00caca3c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 9 Oct 2021 22:15:13 -0700 Subject: [PATCH 355/511] src/sage/misc/lazy_import.pyx: Warnings suppress duplicates, so use a different import for the repeated test --- src/sage/misc/lazy_import.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index fb06fa01f56..c7c9c5400a5 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -234,11 +234,11 @@ cdef class LazyImport(object): Integer Ring sage: my_integer_ring._object is None False - sage: my_integer_ring = LazyImport('sage.rings.all', 'ZZ', at_startup=True) - sage: my_integer_ring + sage: my_rats = LazyImport('sage.rings.rational_field', 'QQ', at_startup=True) + sage: my_rats doctest:warning... - UserWarning: Option ``at_startup=True`` for lazy import ZZ not needed anymore - Integer Ring + UserWarning: Option ``at_startup=True`` for lazy import QQ not needed anymore + Rational Field """ if self._object is not None: return self._object From cf5d26697d96fcee871f6393491c241e8ab83522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 10 Oct 2021 10:15:36 +0200 Subject: [PATCH 356/511] fix some annotations in combinat --- src/sage/combinat/gelfand_tsetlin_patterns.py | 6 ++-- src/sage/combinat/parking_functions.py | 29 +++++++++++-------- src/sage/combinat/plane_partition.py | 17 ++++++----- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/sage/combinat/gelfand_tsetlin_patterns.py b/src/sage/combinat/gelfand_tsetlin_patterns.py index a7c245f13ea..b8b79764817 100644 --- a/src/sage/combinat/gelfand_tsetlin_patterns.py +++ b/src/sage/combinat/gelfand_tsetlin_patterns.py @@ -150,7 +150,7 @@ def __classcall_private__(self, gt): """ return GelfandTsetlinPatterns()(gt) - def check(self) -> bool: + def check(self): """ Check that this is a valid Gelfand-Tsetlin pattern. @@ -159,8 +159,8 @@ def check(self) -> bool: sage: G = GelfandTsetlinPatterns() sage: G([[3,2,1],[2,1],[1]]).check() """ - assert all( self[i-1][j] >= self[i][j] >= self[i-1][j+1] - for i in range(1, len(self)) for j in range(len(self[i])) ) + assert all(self[i - 1][j] >= self[i][j] >= self[i - 1][j + 1] + for i in range(1, len(self)) for j in range(len(self[i]))) def _hash_(self) -> int: """ diff --git a/src/sage/combinat/parking_functions.py b/src/sage/combinat/parking_functions.py index d1a551ffc40..3a859dbaf6b 100644 --- a/src/sage/combinat/parking_functions.py +++ b/src/sage/combinat/parking_functions.py @@ -62,7 +62,8 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from typing import NewType, Iterator, Tuple +from __future__ import annotations +from typing import Iterator from sage.rings.integer import Integer from sage.rings.rational_field import QQ @@ -81,9 +82,6 @@ from sage.structure.unique_representation import UniqueRepresentation -PF = NewType('PF', 'ParkingFunction') - - def is_a(x, n=None) -> bool: r""" Check whether a list is a parking function. @@ -108,6 +106,7 @@ def is_a(x, n=None) -> bool: A = sorted(x) return check_NDPF(A, n) + class ParkingFunction(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" A Parking Function. @@ -308,8 +307,9 @@ def diagonal_reading_word(self) -> Permutation: L = self.to_labelling_permutation() D = self.to_area_sequence() m = max(D) - return Permutation([L[-j - 1] for i in range(m + 1) - for j in range(len(L)) if D[-j - 1] == m - i]) + data = [L[-j - 1] for i in range(m + 1) + for j in range(len(L)) if D[-j - 1] == m - i] + return Permutation(data) # type: ignore diagonal_word = diagonal_reading_word @@ -385,7 +385,8 @@ def cars_permutation(self) -> Permutation: while self[i] + j in out: j += 1 out[self[i] + j] = i - return Permutation([out[i + 1] + 1 for i in range(len(self))]) + data = [out[i + 1] + 1 for i in range(len(self))] + return Permutation(data) # type: ignore def jump_list(self) -> list: # cars displacements r""" @@ -893,7 +894,7 @@ def to_dyck_word(self) -> DyckWord: sage: ParkingFunction([2,1,4,1]).to_dyck_word() [1, 1, 0, 1, 0, 0, 1, 0] """ - return DyckWord(area_sequence=self.to_area_sequence()) + return DyckWord(area_sequence=self.to_area_sequence()) # type: ignore def to_labelled_dyck_word(self): r""" @@ -930,7 +931,7 @@ def to_labelled_dyck_word(self): out.insert(i, 0) return out - def to_labelling_dyck_word_pair(self) -> Tuple[Permutation, DyckWord]: + def to_labelling_dyck_word_pair(self) -> tuple[Permutation, DyckWord]: r""" Return the pair ``(L, D)`` where ``L`` is a labelling and ``D`` is the Dyck word of the parking function. @@ -988,7 +989,7 @@ def to_NonDecreasingParkingFunction(self) -> PF: sage: ParkingFunction([4,1,2,1]).to_NonDecreasingParkingFunction() [1, 1, 2, 4] """ - return ParkingFunction(sorted(self)) + return ParkingFunction(sorted(self)) # type: ignore def characteristic_quasisymmetric_function(self, q=None, R=QQ['q', 't'].fraction_field()): @@ -1138,6 +1139,9 @@ def pretty_print(self, underpath=True): else: dw.pretty_print(labelling=L, underpath=False) + +PF = ParkingFunction + # ***************************************************************************** # CONSTRUCTIONS # ***************************************************************************** @@ -1218,9 +1222,10 @@ def from_labelled_dyck_word(LDW) -> PF: [2, 1, 4, 1] """ L = [ell for ell in LDW if ell != 0] - D = DyckWord([Integer(not x.is_zero()) for x in LDW]) + D = DyckWord([Integer(not x.is_zero()) for x in LDW]) # type: ignore return from_labelling_and_area_sequence(L, D.to_area_sequence()) + class ParkingFunctions(UniqueRepresentation, Parent): r""" Return the combinatorial class of Parking Functions. @@ -1319,6 +1324,7 @@ def __classcall_private__(cls, n=None): raise ValueError("%s is not a non-negative integer" % n) return ParkingFunctions_n(n) + class ParkingFunctions_all(ParkingFunctions): def __init__(self): """ @@ -1606,4 +1612,3 @@ def random_element(self) -> PF: position += Zm.one() free.remove(position) return self.element_class(self, [(i - free[0]).lift() for i in fun]) - diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 0675a1000c4..865dd2cb3d4 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -22,7 +22,8 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from typing import NewType, Iterator, Tuple +from __future__ import annotations +from typing import Iterator from sage.structure.list_clone import ClonableArray from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass @@ -36,9 +37,6 @@ from sage.plot.plot3d.platonic import cube -PP = NewType('PP', 'PlanePartition') - - class PlanePartition(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" @@ -141,7 +139,7 @@ def to_tableau(self) -> Tableau: sage: PP.to_tableau() [[4, 3, 3, 1], [2, 1, 1], [1, 1]] """ - return Tableau(self) + return Tableau(self) # type: ignore def z_tableau(self): r""" @@ -768,6 +766,9 @@ def is_TSSCPP(self) -> bool: return self.is_TSPP() and self.is_SCPP() +PP = PlanePartition + + class PlanePartitions(UniqueRepresentation, Parent): r""" All plane partitions inside a rectangular box of given side lengths. @@ -832,7 +833,7 @@ def _repr_(self) -> str: return "Plane partitions inside a {} x {} x {} box".format( self._box[0], self._box[1], self._box[2]) - def __iter__(self) -> Iterator: + def __iter__(self) -> Iterator[PP]: """ Iterate over ``self``. @@ -848,7 +849,7 @@ def __iter__(self) -> Iterator: C = self._box[2] from sage.combinat.tableau import SemistandardTableaux for T in SemistandardTableaux([B for i in range(A)], max_entry=C + A): - PP = [[0 for i in range(B)] for j in range(A)] + PP = [[0 for _ in range(B)] for _ in range(A)] for r in range(A): for c in range(B): PP[A - 1 - r][B - 1 - c] = T[r][c] - r - 1 @@ -880,7 +881,7 @@ def cardinality(self) -> Integer: for j in range(1, B + 1) for k in range(1, C + 1))) - def box(self) -> Tuple: + def box(self) -> tuple: """ Return the sizes of the box of the plane partitions of ``self`` are contained in. From 1eb5b843970c47f2bad9e720da5da7c78c35b9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 10 Oct 2021 10:54:35 +0200 Subject: [PATCH 357/511] more conversions for trig functions, pep8 cleanup --- src/sage/functions/hyperbolic.py | 24 +++++++++++--- src/sage/functions/trig.py | 57 +++++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/sage/functions/hyperbolic.py b/src/sage/functions/hyperbolic.py index 58f3eb0c846..2ca5284f505 100644 --- a/src/sage/functions/hyperbolic.py +++ b/src/sage/functions/hyperbolic.py @@ -80,6 +80,7 @@ def __init__(self): """ GinacFunction.__init__(self, "sinh", latex_name=r"\sinh") + sinh = Function_sinh() @@ -116,6 +117,7 @@ def __init__(self): """ GinacFunction.__init__(self, "cosh", latex_name=r"\cosh") + cosh = Function_cosh() @@ -180,6 +182,7 @@ def __init__(self): """ GinacFunction.__init__(self, "tanh", latex_name=r"\tanh") + tanh = Function_tanh() @@ -235,6 +238,7 @@ def _eval_numpy_(self, x): """ return 1.0 / tanh(x) + coth = Function_coth() @@ -288,6 +292,7 @@ def _eval_numpy_(self, x): """ return 1.0 / cosh(x) + sech = Function_sech() @@ -339,6 +344,7 @@ def _eval_numpy_(self, x): """ return 1.0 / sinh(x) + csch = Function_csch() @@ -403,7 +409,8 @@ def __init__(self): GinacFunction.__init__(self, "arcsinh", latex_name=r"\operatorname{arsinh}", conversions=dict(maxima='asinh', sympy='asinh', fricas='asinh', - giac='asinh')) + giac='asinh', mathematica='ArcSinh')) + arcsinh = asinh = Function_arcsinh() @@ -488,7 +495,8 @@ def __init__(self): GinacFunction.__init__(self, "arccosh", latex_name=r"\operatorname{arcosh}", conversions=dict(maxima='acosh', sympy='acosh', fricas='acosh', - giac='acosh')) + giac='acosh', mathematica='ArcCosh')) + arccosh = acosh = Function_arccosh() @@ -547,7 +555,8 @@ def __init__(self): GinacFunction.__init__(self, "arctanh", latex_name=r"\operatorname{artanh}", conversions=dict(maxima='atanh', sympy='atanh', fricas='atanh', - giac='atanh')) + giac='atanh', mathematica='ArcTanh')) + arctanh = atanh = Function_arctanh() @@ -594,7 +603,8 @@ def __init__(self): """ GinacFunction.__init__(self, "arccoth", latex_name=r"\operatorname{arcoth}", - conversions=dict(maxima='acoth', sympy='acoth', fricas='acoth')) + conversions=dict(maxima='acoth', sympy='acoth', + giac='acoth', fricas='acoth')) def _eval_numpy_(self, x): """ @@ -607,6 +617,7 @@ def _eval_numpy_(self, x): """ return arctanh(1.0 / x) + arccoth = acoth = Function_arccoth() @@ -637,7 +648,8 @@ def __init__(self): """ GinacFunction.__init__(self, "arcsech", latex_name=r"\operatorname{arsech}", - conversions=dict(maxima='asech', sympy='asech', fricas='asech')) + conversions=dict(maxima='asech', sympy='asech', + fricas='asech')) def _eval_numpy_(self, x): """ @@ -651,6 +663,7 @@ def _eval_numpy_(self, x): """ return arccosh(1.0 / x) + arcsech = asech = Function_arcsech() @@ -702,4 +715,5 @@ def _eval_numpy_(self, x): """ return arcsinh(1.0 / x) + arccsch = acsch = Function_arccsch() diff --git a/src/sage/functions/trig.py b/src/sage/functions/trig.py index fbee1cd0cc8..a705648a8ce 100644 --- a/src/sage/functions/trig.py +++ b/src/sage/functions/trig.py @@ -118,7 +118,9 @@ def __init__(self): sin(1/42*pi) """ GinacFunction.__init__(self, 'sin', latex_name=r"\sin", - conversions=dict(maxima='sin',mathematica='Sin',giac='sin')) + conversions=dict(maxima='sin', mathematica='Sin', + giac='sin', fricas='sin', sympy='sin')) + sin = Function_sin() @@ -181,7 +183,9 @@ def __init__(self): -cos(1/42*pi) """ GinacFunction.__init__(self, 'cos', latex_name=r"\cos", - conversions=dict(maxima='cos',mathematica='Cos',giac='cos')) + conversions=dict(maxima='cos', mathematica='Cos', + giac='cos', fricas='cos', sympy='cos')) + cos = Function_cos() @@ -243,8 +247,10 @@ def __init__(self): """ GinacFunction.__init__(self, 'tan', latex_name=r"\tan") + tan = Function_tan() + class Function_cot(GinacFunction): def __init__(self): r""" @@ -337,6 +343,7 @@ def _eval_numpy_(self, x): """ return 1.0 / tan(x) + cot = Function_cot() @@ -406,8 +413,10 @@ def _eval_numpy_(self, x): """ return 1 / cos(x) + sec = Function_sec() + class Function_csc(GinacFunction): def __init__(self): r""" @@ -474,8 +483,10 @@ def _eval_numpy_(self, x): """ return 1 / sin(x) + csc = Function_csc() + ################################### # Inverse Trigonometric Functions # ################################### @@ -535,10 +546,14 @@ def __init__(self): 1.57079632679490 - 1.37285914424258*I """ GinacFunction.__init__(self, 'arcsin', latex_name=r"\arcsin", - conversions=dict(maxima='asin', sympy='asin', fricas="asin", giac="asin")) + conversions=dict(maxima='asin', sympy='asin', + mathematica='ArcSin', + fricas="asin", giac="asin")) + arcsin = asin = Function_arcsin() + class Function_arccos(GinacFunction): def __init__(self): """ @@ -596,10 +611,14 @@ def __init__(self): 1.37285914424258*I """ GinacFunction.__init__(self, 'arccos', latex_name=r"\arccos", - conversions=dict(maxima='acos', sympy='acos', fricas='acos', giac='acos')) + conversions=dict(maxima='acos', sympy='acos', + mathematica='ArcCos', + fricas='acos', giac='acos')) + arccos = acos = Function_arccos() + class Function_arctan(GinacFunction): def __init__(self): """ @@ -664,10 +683,14 @@ def __init__(self): 1/2*pi """ GinacFunction.__init__(self, 'arctan', latex_name=r"\arctan", - conversions=dict(maxima='atan', sympy='atan', fricas='atan', giac='atan')) + conversions=dict(maxima='atan', sympy='atan', + mathematica='ArcTan', + fricas='atan', giac='atan')) + arctan = atan = Function_arctan() + class Function_arccot(GinacFunction): def __init__(self): """ @@ -714,7 +737,8 @@ def __init__(self): """ GinacFunction.__init__(self, 'arccot', latex_name=r"\operatorname{arccot}", - conversions=dict(maxima='acot', sympy='acot', fricas='acot',giac='acot')) + conversions=dict(maxima='acot', sympy='acot', + fricas='acot', giac='acot')) def _eval_numpy_(self, x): """ @@ -725,10 +749,12 @@ def _eval_numpy_(self, x): sage: arccot(a) array([0.46364761, 0.32175055, 0.24497866]) """ - return math.pi/2 - arctan(x) + return math.pi / 2 - arctan(x) + arccot = acot = Function_arccot() + class Function_arccsc(GinacFunction): def __init__(self): """ @@ -770,7 +796,8 @@ def __init__(self): (0.45227844715119064-0.5306375309525178j) """ GinacFunction.__init__(self, 'arccsc', latex_name=r"\operatorname{arccsc}", - conversions=dict(maxima='acsc', sympy='acsc', fricas='acsc', giac='acsc')) + conversions=dict(maxima='acsc', sympy='acsc', + fricas='acsc', giac='acsc')) def _eval_numpy_(self, x): """ @@ -781,10 +808,12 @@ def _eval_numpy_(self, x): sage: arccsc(a) array([0.52359878, 0.33983691, 0.25268026]) """ - return arcsin(1.0/x) + return arcsin(1.0 / x) + arccsc = acsc = Function_arccsc() + class Function_arcsec(GinacFunction): def __init__(self): """ @@ -828,7 +857,8 @@ def __init__(self): (1.118517879643706+0.5306375309525178j) """ GinacFunction.__init__(self, 'arcsec', latex_name=r"\operatorname{arcsec}", - conversions=dict(maxima='asec', sympy='asec', fricas='asec', giac='asec')) + conversions=dict(maxima='asec', sympy='asec', + fricas='asec', giac='asec')) def _eval_numpy_(self, x): """ @@ -839,10 +869,12 @@ def _eval_numpy_(self, x): sage: arcsec(a) array([1.04719755, 1.23095942, 1.31811607]) """ - return arccos(1.0/x) + return arccos(1.0 / x) + arcsec = asec = Function_arcsec() + class Function_arctan2(GinacFunction): def __init__(self): r""" @@ -961,6 +993,7 @@ def __init__(self): pi """ GinacFunction.__init__(self, 'arctan2', nargs=2, latex_name=r"\arctan", - conversions=dict(maxima='atan2', sympy='atan2')) + conversions=dict(maxima='atan2', sympy='atan2', giac='atan2')) + arctan2 = atan2 = Function_arctan2() From bc62348b32e1a06d88a66359c977fac9e15c68a5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 10 Oct 2021 13:54:33 -0700 Subject: [PATCH 358/511] src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx: Add some missing # optional - sage.combinat --- .../geometry/polyhedron/combinatorial_polyhedron/base.pyx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 612a4da19b9..fe2ae912c0b 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -607,8 +607,9 @@ cdef class CombinatorialPolyhedron(SageObject): sage: it1 = C1.face_iter() # optional - sage.combinat sage: tup = tuple((face.ambient_Vrepresentation(), # optional - sage.combinat ....: face.ambient_Hrepresentation()) for face in it) - sage: tup1 = tuple((face.ambient_Vrepresentation(), face.ambient_Hrepresentation()) for face in it1) - sage: tup == tup1 + sage: tup1 = tuple((face.ambient_Vrepresentation(), # optional - sage.combinat + ....: face.ambient_Hrepresentation()) for face in it1) + sage: tup == tup1 # optional - sage.combinat True sage: P = polytopes.cyclic_polytope(4,10) @@ -2738,7 +2739,7 @@ cdef class CombinatorialPolyhedron(SageObject): [A 0-dimensional face of a 3-dimensional combinatorial polyhedron, A 1-dimensional face of a 3-dimensional combinatorial polyhedron, A 2-dimensional face of a 3-dimensional combinatorial polyhedron] - sage: [face.ambient_V_indices() for face in chain] + sage: [face.ambient_V_indices() for face in chain] # optional - sage.combinat [(16,), (15, 16), (8, 9, 14, 15, 16, 17)] sage: P = Polyhedron(rays=[[1,0]], lines=[[0,1]]) From 1dee580c54c956d81f17f0fadd80e6e6ed9947f0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 10 Oct 2021 13:58:34 -0700 Subject: [PATCH 359/511] src/sage/geometry/polyhedron/{base,backend_field}.py: Add some missing # optional --- src/sage/geometry/polyhedron/backend_field.py | 2 +- src/sage/geometry/polyhedron/base.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_field.py b/src/sage/geometry/polyhedron/backend_field.py index 17cba0ed2ef..4ddf271143e 100644 --- a/src/sage/geometry/polyhedron/backend_field.py +++ b/src/sage/geometry/polyhedron/backend_field.py @@ -284,7 +284,7 @@ def _init_Hrepresentation(self, inequalities, equations): sage: Hrep = [[[0, 1], [1, -1]], []] sage: p = Polyhedron_field(parent, Vrep, Hrep, # indirect doctest # optional - sage.rings.number_field ....: Vrep_minimal=True, Hrep_minimal=True) - sage: p.inequalities_list() + sage: p.inequalities_list() # optional - sage.rings.number_field [[0, 1], [1, -1]] """ self._Hrepresentation = [] diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 49b3b645c3d..34f0fd50083 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -10626,7 +10626,9 @@ def is_combinatorially_isomorphic(self, other, algorithm='bipartite_graph'): sage: H = polytopes.regular_polygon(6) # optional - sage.rings.number_field sage: S = polytopes.hypercube(2) sage: P = polytopes.permutahedron(4) - sage: all(F.as_polyhedron().is_combinatorially_isomorphic(S) or F.as_polyhedron().is_combinatorially_isomorphic(H) for F in P.faces(2)) + sage: all(F.as_polyhedron().is_combinatorially_isomorphic(S) # optional - sage.rings.number_field + ....: or F.as_polyhedron().is_combinatorially_isomorphic(H) + ....: for F in P.faces(2)) True Checking that a regular simplex intersected with its reflection From c1bf35690044b88f2cfec4b6879c4669c138aeaf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 10 Oct 2021 17:28:16 -0700 Subject: [PATCH 360/511] m4/sage_spkg_collect.m4: Fix up in_sdist logic --- m4/sage_spkg_collect.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/m4/sage_spkg_collect.m4 b/m4/sage_spkg_collect.m4 index 9eccc15ff7f..40ef945e295 100644 --- a/m4/sage_spkg_collect.m4 +++ b/m4/sage_spkg_collect.m4 @@ -144,7 +144,7 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do SPKG_NAME=$(basename $DIR) SPKG_VERSION=$(newest_version $SPKG_NAME) - in_sdist=no + in_sdist=yes dnl Determine package source dnl @@ -221,9 +221,9 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do case "$SPKG_TYPE" in standard) - in_sdist=yes ;; optional|experimental) + in_sdist=no uninstall_message=", use \"$srcdir/configure --disable-$SPKG_NAME\" to uninstall" stampfile="" for f in "$SAGE_SPKG_INST/$SPKG_NAME"-*; do From 8cf915089c3d4d18f2c2def8f093fa6d75902dcc Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Sat, 2 Oct 2021 21:31:35 +0200 Subject: [PATCH 361/511] fix mistake from #32498 --- src/sage/graphs/generic_graph.py | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 6a966a01e3f..6b597dd2a69 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -23480,18 +23480,18 @@ def edge_polytope(self, backend=None): sage: P.is_combinatorially_isomorphic(polytopes.cross_polytope(3)) True - The EP of a graph with edges is isomorphic - to the product of it's connected components with edges:: + The EP of a graph is isomorphic to the subdirect sum of + it's connected components EPs:: sage: n = randint(5, 12) - sage: G = Graph() - sage: while not G.num_edges(): - ....: G = graphs.RandomGNP(n, 0.2) + sage: G1 = graphs.RandomGNP(n, 0.2) + sage: n = randint(5, 12) + sage: G2 = graphs.RandomGNP(n, 0.2) + sage: G = G1.disjoint_union(G2) sage: P = G.edge_polytope() - sage: components = [G.subgraph(c).edge_polytope() - ....: for c in G.connected_components() - ....: if G.subgraph(c).num_edges()] - sage: P.is_combinatorially_isomorphic(product(components)) + sage: P1 = G1.edge_polytope() + sage: P2 = G2.edge_polytope() + sage: P.is_combinatorially_isomorphic(P1.subdirect_sum(P2)) True All trees on `n` vertices have isomorphic EPs:: @@ -23582,18 +23582,18 @@ def symmetric_edge_polytope(self, backend=None): sage: P.dim() == n - G.connected_components_number() True - The SEP of a graph with edges is isomorphic - to the product of it's connected components with edges:: + The SEP of a graph is isomorphic to the subdirect sum of + it's connected components SEP's:: sage: n = randint(5, 12) - sage: G = Graph() - sage: while not G.num_edges(): - ....: G = graphs.RandomGNP(n, 0.2) + sage: G1 = graphs.RandomGNP(n, 0.2) + sage: n = randint(5, 12) + sage: G2 = graphs.RandomGNP(n, 0.2) + sage: G = G1.disjoint_union(G2) sage: P = G.symmetric_edge_polytope() - sage: components = [G.subgraph(c).symmetric_edge_polytope() - ....: for c in G.connected_components() - ....: if G.subgraph(c).num_edges()] - sage: P.is_combinatorially_isomorphic(product(components)) + sage: P1 = G1.symmetric_edge_polytope() + sage: P2 = G2.symmetric_edge_polytope() + sage: P.is_combinatorially_isomorphic(P1.subdirect_sum(P2)) True All trees on `n` vertices have isomorphic SEPs:: From dccd8a29e4777aa229607b5eda36d3026932b359 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 4 Oct 2021 10:16:25 +0200 Subject: [PATCH 362/511] reasonable graph size for doctets --- 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 6b597dd2a69..8efe2ee7f77 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -23483,9 +23483,9 @@ def edge_polytope(self, backend=None): The EP of a graph is isomorphic to the subdirect sum of it's connected components EPs:: - sage: n = randint(5, 12) + sage: n = randint(3, 6) sage: G1 = graphs.RandomGNP(n, 0.2) - sage: n = randint(5, 12) + sage: n = randint(3, 6) sage: G2 = graphs.RandomGNP(n, 0.2) sage: G = G1.disjoint_union(G2) sage: P = G.edge_polytope() @@ -23585,9 +23585,9 @@ def symmetric_edge_polytope(self, backend=None): The SEP of a graph is isomorphic to the subdirect sum of it's connected components SEP's:: - sage: n = randint(5, 12) + sage: n = randint(3, 6) sage: G1 = graphs.RandomGNP(n, 0.2) - sage: n = randint(5, 12) + sage: n = randint(3, 6) sage: G2 = graphs.RandomGNP(n, 0.2) sage: G = G1.disjoint_union(G2) sage: P = G.symmetric_edge_polytope() From 1bb9d96fce8964851245aee75d25a1ab793878cb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 10 Oct 2021 22:42:30 -0700 Subject: [PATCH 363/511] src/sage/geometry/polyhedron/constructor.py: More # optional - sage.symbolic --- src/sage/geometry/polyhedron/constructor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/constructor.py b/src/sage/geometry/polyhedron/constructor.py index e97a72a4aa3..b3986c501c7 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -177,8 +177,8 @@ exact way to work with roots in Sage is the :mod:`Algebraic Real Field ` :: - sage: triangle = Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)], base_ring=AA) # optional - sage.rings.number_field - sage: triangle.Hrepresentation() # optional - sage.rings.number_field + sage: triangle = Polyhedron([(0,0), (1,0), (1/2, sqrt(3)/2)], base_ring=AA) # optional - sage.rings.number_field # optional - sage.symbolic + sage: triangle.Hrepresentation() # optional - sage.rings.number_field # optional - sage.symbolic (An inequality (-1, -0.5773502691896258?) x + 1 >= 0, An inequality (1, -0.5773502691896258?) x + 0 >= 0, An inequality (0, 1.154700538379252?) x + 0 >= 0) From cf86501d9edb82a4a50871adf95fa105335af3bf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 10 Oct 2021 22:44:39 -0700 Subject: [PATCH 364/511] src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx: Fix some # optional --- .../combinatorial_polyhedron/base.pyx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index fe2ae912c0b..4ae37f27804 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -2384,38 +2384,38 @@ cdef class CombinatorialPolyhedron(SageObject): EXAMPLES:: - sage: P = polytopes.permutahedron(5) # optional - sage.rings.number_field - sage: C = CombinatorialPolyhedron(P) # optional - sage.rings.number_field - sage: it = C.face_iter(dimension=2) # optional - sage.rings.number_field - sage: face = next(it); face # optional - sage.rings.number_field + sage: P = polytopes.permutahedron(5) # optional - sage.combinat + sage: C = CombinatorialPolyhedron(P) # optional - sage.combinat + sage: it = C.face_iter(dimension=2) # optional - sage.combinat + sage: face = next(it); face # optional - sage.combinat A 2-dimensional face of a 4-dimensional combinatorial polyhedron - sage: face.ambient_Vrepresentation() # optional - sage.rings.number_field + sage: face.ambient_Vrepresentation() # optional - sage.combinat (A vertex at (1, 3, 2, 5, 4), A vertex at (2, 3, 1, 5, 4), A vertex at (3, 1, 2, 5, 4), A vertex at (3, 2, 1, 5, 4), A vertex at (2, 1, 3, 5, 4), A vertex at (1, 2, 3, 5, 4)) - sage: face = next(it); face # optional - sage.rings.number_field + sage: face = next(it); face # optional - sage.combinat A 2-dimensional face of a 4-dimensional combinatorial polyhedron - sage: face.ambient_Vrepresentation() # optional - sage.rings.number_field + sage: face.ambient_Vrepresentation() # optional - sage.combinat (A vertex at (2, 1, 4, 5, 3), A vertex at (3, 2, 4, 5, 1), A vertex at (3, 1, 4, 5, 2), A vertex at (1, 3, 4, 5, 2), A vertex at (1, 2, 4, 5, 3), A vertex at (2, 3, 4, 5, 1)) - sage: face.ambient_Hrepresentation() # optional - sage.rings.number_field + sage: face.ambient_Hrepresentation() # optional - sage.combinat (An inequality (0, 0, -1, -1, 0) x + 9 >= 0, An inequality (0, 0, 0, -1, 0) x + 5 >= 0, An equation (1, 1, 1, 1, 1) x - 15 == 0) - sage: face.ambient_H_indices() # optional - sage.rings.number_field + sage: face.ambient_H_indices() # optional - sage.combinat (25, 29, 30) - sage: face = next(it); face # optional - sage.rings.number_field + sage: face = next(it); face # optional - sage.combinat A 2-dimensional face of a 4-dimensional combinatorial polyhedron - sage: face.ambient_H_indices() # optional - sage.rings.number_field + sage: face.ambient_H_indices() # optional - sage.combinat (24, 29, 30) - sage: face.ambient_V_indices() # optional - sage.rings.number_field + sage: face.ambient_V_indices() # optional - sage.combinat (32, 89, 90, 94) sage: C = CombinatorialPolyhedron([[0,1,2],[0,1,3],[0,2,3],[1,2,3]]) From 73a4ca698825c3937a68d2c3a91502c6d736082f Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 11 Oct 2021 08:03:05 +0200 Subject: [PATCH 365/511] the affine tangent cone of the empty face should be empty --- src/sage/geometry/polyhedron/face.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/geometry/polyhedron/face.py b/src/sage/geometry/polyhedron/face.py index 2d127ceda1c..476072f35fc 100644 --- a/src/sage/geometry/polyhedron/face.py +++ b/src/sage/geometry/polyhedron/face.py @@ -952,7 +952,17 @@ def affine_tangent_cone(self): A ray in the direction (0, 0, 1), A vertex at (1, 0, -1), A ray in the direction (-1, 0, 0)) + + TESTS: + + Check that :trac:`32658` is fixed:: + + sage: P = polytopes.hypercube(2) + sage: P.faces(-1)[0].affine_tangent_cone() + The empty polyhedron in ZZ^2 """ + if self.dim() == -1: + return self.as_polyhedron() parent = self.polyhedron().parent() new_ieqs = [H for H in self.ambient_Hrepresentation() if H.is_inequality()] From 4340762275c36e14ec1fc7dda2d5f477de2150b5 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 11 Oct 2021 08:11:39 +0200 Subject: [PATCH 366/511] throw an error, because it is not a cone --- src/sage/geometry/polyhedron/face.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/face.py b/src/sage/geometry/polyhedron/face.py index 476072f35fc..9d1f53343e7 100644 --- a/src/sage/geometry/polyhedron/face.py +++ b/src/sage/geometry/polyhedron/face.py @@ -959,10 +959,12 @@ def affine_tangent_cone(self): sage: P = polytopes.hypercube(2) sage: P.faces(-1)[0].affine_tangent_cone() - The empty polyhedron in ZZ^2 + Traceback (most recent call last): + ... + ValueError: affine tangent cone of the empty face not defined """ if self.dim() == -1: - return self.as_polyhedron() + raise ValueError("affine tangent cone of the empty face not defined") parent = self.polyhedron().parent() new_ieqs = [H for H in self.ambient_Hrepresentation() if H.is_inequality()] From ca963074e9a932c5f3d28e7a72b8df3d5ddd5d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 10 Oct 2021 21:08:11 +0200 Subject: [PATCH 367/511] more conversions for Bessel functions --- src/sage/functions/bessel.py | 94 +++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index 3adee3b0c94..6de793a1545 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -332,7 +332,8 @@ def __init__(self): besselj(x, x) """ BuiltinFunction.__init__(self, 'bessel_J', nargs=2, - conversions=dict(mathematica='BesselJ', + conversions=dict(maple='BesselJ', + mathematica='BesselJ', maxima='bessel_j', sympy='besselj', fricas='besselJ', @@ -366,10 +367,10 @@ def _eval_(self, n, x): return ZZ(0) elif n.real() < 0: return unsigned_infinity - if n == QQ(1)/2: - return sqrt(2/pi/x) * sin(x) - elif n == QQ(-1)/2: - return sqrt(2/pi/x) * cos(x) + if n == QQ(1) / 2: + return sqrt(2 / pi / x) * sin(x) + elif n == QQ(-1) / 2: + return sqrt(2 / pi / x) * cos(x) def _evalf_(self, n, x, parent=None, algorithm=None): """ @@ -437,6 +438,7 @@ def _print_latex_(self, n, z): """ return r"J_{%s}(%s)" % (latex(n), latex(z)) + bessel_J = Function_Bessel_J() @@ -549,7 +551,8 @@ def __init__(self): bessely(x, x) """ BuiltinFunction.__init__(self, 'bessel_Y', nargs=2, - conversions=dict(mathematica='BesselY', + conversions=dict(maple='BesselY', + mathematica='BesselY', maxima='bessel_y', sympy='bessely', fricas='besselY', @@ -579,10 +582,10 @@ def _eval_(self, n, x): return -infinity elif n.real() > 0 or n.real() < 0: return unsigned_infinity - if n == QQ(1)/2: - return -sqrt(2/pi/x) * cos(x) - elif n == QQ(-1)/2: - return sqrt(2/pi/x) * sin(x) + if n == QQ((1, 2)): + return -sqrt(2 / pi / x) * cos(x) + elif n == QQ(-1) / 2: + return sqrt(2 / pi / x) * sin(x) def _evalf_(self, n, x, parent=None, algorithm=None): """ @@ -649,6 +652,7 @@ def _print_latex_(self, n, z): """ return r"Y_{%s}(%s)" % (latex(n), latex(z)) + bessel_Y = Function_Bessel_Y() @@ -755,7 +759,8 @@ def __init__(self): besseli(x, x) """ BuiltinFunction.__init__(self, 'bessel_I', nargs=2, - conversions=dict(mathematica='BesselI', + conversions=dict(maple='BesselI', + mathematica='BesselI', maxima='bessel_i', sympy='besseli', fricas='besselI')) @@ -788,12 +793,11 @@ def _eval_(self, n, x): return ZZ(0) elif n.real() < 0: return unsigned_infinity - if n == QQ(1)/2: + if n == QQ(1) / 2: return sqrt(2 / (pi * x)) * sinh(x) - elif n == -QQ(1)/2: + elif n == -QQ(1) / 2: return sqrt(2 / (pi * x)) * cosh(x) - def _evalf_(self, n, x, parent=None, algorithm=None): """ EXAMPLES:: @@ -838,6 +842,7 @@ def _print_latex_(self, n, z): """ return r"I_{%s}(%s)" % (latex(n), latex(z)) + bessel_I = Function_Bessel_I() @@ -955,7 +960,8 @@ def __init__(self): besselk(x, x) """ BuiltinFunction.__init__(self, 'bessel_K', nargs=2, - conversions=dict(mathematica='BesselK', + conversions=dict(maple='BesselK', + mathematica='BesselK', maxima='bessel_k', sympy='besselk', fricas='besselK')) @@ -983,10 +989,9 @@ def _eval_(self, n, x): return infinity elif n.real() > 0 or n.real() < 0: return unsigned_infinity - if n == QQ(1)/2 or n == -QQ(1)/2 and x > 0: + if n == QQ(1) / 2 or n == -QQ(1) / 2 and x > 0: return sqrt(pi / 2) * exp(-x) * x ** (-Integer(1) / Integer(2)) - def _evalf_(self, n, x, parent=None, algorithm=None): """ EXAMPLES:: @@ -1032,6 +1037,7 @@ def _print_latex_(self, n, z): """ return r"K_{%s}(%s)" % (latex(n), latex(z)) + bessel_K = Function_Bessel_K() @@ -1246,7 +1252,8 @@ def __init__(self): conversions=dict(maple='StruveH', mathematica='StruveH', maxima='struve_h', - fricas='struveH')) + fricas='struveH', + sympy='struveh')) def _eval_(self, a, z): """ @@ -1271,17 +1278,17 @@ def _eval_(self, a, z): if z.is_zero() \ and (SR(a).is_numeric() or SR(a).is_constant()) \ and a.real() >= -1: - return ZZ(0) - if a == -Integer(1)/2: + return ZZ(0) + from sage.rings.rational_field import QQ + if a == -QQ((1, 2)): from sage.functions.trig import sin - return sqrt(2/(pi*z)) * sin(z) - if a == Integer(1)/2: + return sqrt(2 / (pi * z)) * sin(z) + if a == QQ((1, 2)): from sage.functions.trig import cos - return sqrt(2/(pi*z)) * (1-cos(z)) - if a < 0 and not SR(a).is_integer() and SR(2*a).is_integer(): - from sage.rings.rational_field import QQ - n = (a*(-2) - 1)/2 - return Integer(-1)**n * bessel_J(n+QQ(1)/2, z) + return sqrt(2 / (pi * z)) * (1 - cos(z)) + if a < 0 and not SR(a).is_integer() and SR(2 * a).is_integer(): + n = (a * (-2) - 1) / 2 + return Integer(-1)**n * bessel_J(n + QQ(1) / 2, z) def _evalf_(self, a, z, parent=None, algorithm=None): """ @@ -1307,7 +1314,7 @@ def _derivative_(self, a, z, diff_param=None): from .gamma import gamma from .other import sqrt - return (z**a/(sqrt(pi)*2**a*gamma(a+Integer(3)/Integer(2)))-struve_H(a+1,z)+struve_H(a-1,z))/2 + return (z**a / (sqrt(pi) * 2**a * gamma(a + Integer(3) / Integer(2))) - struve_H(a + 1, z) + struve_H(a - 1, z)) / 2 def _print_latex_(self, a, z): """ @@ -1318,8 +1325,10 @@ def _print_latex_(self, a, z): """ return r"H_{{%s}}({%s})" % (a, z) + struve_H = Function_Struve_H() + class Function_Struve_L(BuiltinFunction): r""" The modified Struve functions. @@ -1361,7 +1370,8 @@ def __init__(self): conversions=dict(maple='StruveL', mathematica='StruveL', maxima='struve_l', - fricas='struveL')) + fricas='struveL', + sympy='struvel')) def _eval_(self, a, z): """ @@ -1386,17 +1396,17 @@ def _eval_(self, a, z): if z.is_zero() \ and (SR(a).is_numeric() or SR(a).is_constant()) \ and a.real() >= -1: - return ZZ(0) - if a == -Integer(1)/2: + return ZZ(0) + if a == -Integer(1) / 2: from sage.functions.hyperbolic import sinh - return sqrt(2/(pi*z)) * sinh(z) - if a == Integer(1)/2: + return sqrt(2 / (pi * z)) * sinh(z) + if a == Integer(1) / 2: from sage.functions.hyperbolic import cosh - return sqrt(2/(pi*z)) * (cosh(z)-1) - if a < 0 and not SR(a).is_integer() and SR(2*a).is_integer(): + return sqrt(2 / (pi * z)) * (cosh(z) - 1) + if a < 0 and not SR(a).is_integer() and SR(2 * a).is_integer(): from sage.rings.rational_field import QQ - n = (a*(-2) - 1)/2 - return Integer(-1)**n * bessel_I(n+QQ(1)/2, z) + n = (a * (-2) - 1) / 2 + return Integer(-1)**n * bessel_I(n + QQ(1) / 2, z) def _evalf_(self, a, z, parent=None, algorithm=None): """ @@ -1422,7 +1432,7 @@ def _derivative_(self, a, z, diff_param=None): from .gamma import gamma from .other import sqrt - return (z**a/(sqrt(pi)*2**a*gamma(a+Integer(3)/Integer(2)))-struve_L(a+1,z)+struve_L(a-1,z))/2 + return (z**a / (sqrt(pi) * 2**a * gamma(a + Integer(3) / Integer(2))) - struve_L(a + 1, z) + struve_L(a - 1, z)) / 2 def _print_latex_(self, a, z): """ @@ -1431,6 +1441,7 @@ def _print_latex_(self, a, z): """ return r"L_{{%s}}({%s})" % (a, z) + struve_L = Function_Struve_L() @@ -1518,6 +1529,7 @@ def _derivative_(self, nu, z, diff_param): else: raise NotImplementedError('derivative with respect to order') + hankel1 = Function_Hankel1() @@ -1605,6 +1617,7 @@ def _derivative_(self, nu, z, diff_param): else: raise NotImplementedError('derivative with respect to order') + hankel2 = Function_Hankel2() @@ -1704,6 +1717,7 @@ def _derivative_(self, n, z, diff_param): else: raise NotImplementedError('derivative with respect to order') + spherical_bessel_J = SphericalBesselJ() @@ -1803,6 +1817,7 @@ def _derivative_(self, n, z, diff_param): else: raise NotImplementedError('derivative with respect to order') + spherical_bessel_Y = SphericalBesselY() @@ -1899,6 +1914,7 @@ def _derivative_(self, n, z, diff_param): else: raise NotImplementedError('derivative with respect to order') + spherical_hankel1 = SphericalHankel1() @@ -2007,6 +2023,7 @@ def _derivative_(self, n, z, diff_param): else: raise NotImplementedError('derivative with respect to order') + spherical_hankel2 = SphericalHankel2() @@ -2053,4 +2070,3 @@ def spherical_bessel_f(F, n, z): return quotient * Fz finally: ctx.prec = prec - From 7db923eba8e39a66672c58be42ecc727043c6581 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 11 Oct 2021 09:12:41 +0200 Subject: [PATCH 368/511] compute vertex adjacency matrix from edges --- src/sage/geometry/polyhedron/base.py | 35 +---------- .../combinatorial_polyhedron/base.pyx | 60 +++++++++++++++++++ 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 47063568802..80ba3d0f2a4 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -469,39 +469,6 @@ def set_adjacent(h1, h2): M.set_immutable() return M - def _vertex_adjacency_matrix(self): - """ - Compute the vertex adjacency matrix in case it has not been - computed during initialization. - - EXAMPLES:: - - sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)]) - sage: p._vertex_adjacency_matrix() - [0 1 1] - [1 0 1] - [1 1 0] - """ - # TODO: This implementation computes the whole face lattice, - # which is much more information than necessary. - M = matrix(ZZ, self.n_Vrepresentation(), self.n_Vrepresentation(), 0) - - def set_adjacent(v1, v2): - if v1 is v2: - return - i = v1.index() - j = v2.index() - M[i, j] = 1 - M[j, i] = 1 - - face_lattice = self.face_lattice() - for face in face_lattice: - Vrep = face.ambient_Vrepresentation() - if len(Vrep) == 2: - set_adjacent(Vrep[0], Vrep[1]) - M.set_immutable() - return M - def _delete(self): """ Delete this polyhedron. @@ -2785,7 +2752,7 @@ def vertex_adjacency_matrix(self): sage: P.adjacency_matrix().is_immutable() True """ - return self._vertex_adjacency_matrix() + return self.combinatorial_polyhedron().vertex_adjacency_matrix() adjacency_matrix = vertex_adjacency_matrix diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index dd1a2ba54d7..f024355796c 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -1245,6 +1245,66 @@ cdef class CombinatorialPolyhedron(SageObject): graph = vertex_graph + @cached_method + def vertex_adjacency_matrix(self): + """ + Return the binary matrix of vertex adjacencies. + + .. SEEALSO:: + + :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.vertex_adjacency_matrix`. + + EXAMPLES:: + + sage: P = polytopes.cube() + sage: C = P.combinatorial_polyhedron() + sage: C.vertex_adjacency_matrix() + [0 1 0 1 0 1 0 0] + [1 0 1 0 0 0 1 0] + [0 1 0 1 0 0 0 1] + [1 0 1 0 1 0 0 0] + [0 0 0 1 0 1 0 1] + [1 0 0 0 1 0 1 0] + [0 1 0 0 0 1 0 1] + [0 0 1 0 1 0 1 0] + + TESTS:: + + sage: CombinatorialPolyhedron(-1).vertex_adjacency_matrix() + [] + sage: CombinatorialPolyhedron(0).vertex_adjacency_matrix() + [0] + sage: polytopes.cube().vertex_adjacency_matrix().is_immutable() + True + """ + from sage.rings.all import ZZ + from sage.matrix.constructor import matrix + cdef Matrix_integer_dense adjacency_matrix = matrix( + ZZ, self.n_Vrepresentation(), self.n_Vrepresentation(), 0) + + if self._edges is NULL: + # compute the edges. + if not self.is_bounded(): + self._compute_edges(dual=False) + elif self.n_Vrepresentation() > self.n_facets()*self.n_facets(): + # This is a wild estimate + # that in this case it is better not to use the dual. + self._compute_edges(dual=False) + else: + # In most bounded cases, one should use the dual. + self._compute_edges(dual=True) + if self._edges is NULL: + raise ValueError('could not determine edges') + + cdef size_t i, a, b + for i in range(self._n_edges): + a = self._get_edge(self._edges, i, 0) + b = self._get_edge(self._edges, i, 1) + adjacency_matrix.set_unsafe_si(a, b, 1) + adjacency_matrix.set_unsafe_si(b, a, 1) + adjacency_matrix.set_immutable() + return adjacency_matrix + def edge_graph(self, names=True): r""" Return the edge graph. From 21a6c945088d0b4467e2a02d0028743f2ca402c2 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 11 Oct 2021 09:30:14 +0200 Subject: [PATCH 369/511] remove code duplications --- .../combinatorial_polyhedron/base.pxd | 2 +- .../combinatorial_polyhedron/base.pyx | 75 ++++++++----------- 2 files changed, 34 insertions(+), 43 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd index 4fc293961c5..2d88b7c7496 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd @@ -71,7 +71,7 @@ cdef class CombinatorialPolyhedron(SageObject): cdef inline int _compute_ridges(self, dual) except -1: return self._compute_edges_or_ridges(dual, False) - cdef int _compute_edges_or_ridges(self, bint dual, bint do_edges) except -1 + cdef int _compute_edges_or_ridges(self, int dual, bint do_edges) except -1 cdef size_t _compute_edges_or_ridges_with_iterator( self, FaceIterator face_iter, const bint do_atom_rep, const bint do_f_vector, size_t ***edges_pt, size_t *counter_pt, size_t *current_length_pt, diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index f024355796c..9cff71d08b7 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -1183,19 +1183,7 @@ cdef class CombinatorialPolyhedron(SageObject): ('a', 'c'), ('a', 'b')) """ - if self._edges is NULL: - # compute the edges. - if not self.is_bounded(): - self._compute_edges(dual=False) - elif self.n_Vrepresentation() > self.n_facets()*self.n_facets(): - # This is a wild estimate - # that in this case it is better not to use the dual. - self._compute_edges(dual=False) - else: - # In most bounded cases, one should use the dual. - self._compute_edges(dual=True) - if self._edges is NULL: - raise ValueError('could not determine edges') + self._compute_edges(-1) # Mapping the indices of the Vrep to the names, if requested. if self.Vrep() is not None and names is True: @@ -1281,22 +1269,9 @@ cdef class CombinatorialPolyhedron(SageObject): from sage.matrix.constructor import matrix cdef Matrix_integer_dense adjacency_matrix = matrix( ZZ, self.n_Vrepresentation(), self.n_Vrepresentation(), 0) - - if self._edges is NULL: - # compute the edges. - if not self.is_bounded(): - self._compute_edges(dual=False) - elif self.n_Vrepresentation() > self.n_facets()*self.n_facets(): - # This is a wild estimate - # that in this case it is better not to use the dual. - self._compute_edges(dual=False) - else: - # In most bounded cases, one should use the dual. - self._compute_edges(dual=True) - if self._edges is NULL: - raise ValueError('could not determine edges') - cdef size_t i, a, b + + self._compute_edges(-1) for i in range(self._n_edges): a = self._get_edge(self._edges, i, 0) b = self._get_edge(self._edges, i, 1) @@ -1429,19 +1404,7 @@ cdef class CombinatorialPolyhedron(SageObject): from sage.misc.superseded import deprecation deprecation(31834, "the keyword ``add_equalities`` is deprecated; use ``add_equations``", 3) add_equations = True - if self._ridges is NULL: - # compute the ridges. - if not self.is_bounded(): - self._compute_ridges(dual=False) - elif self.n_Vrepresentation()*self.n_Vrepresentation() < self.n_facets(): - # This is a wild estimate - # that in this case it is better to use the dual. - self._compute_ridges(dual=True) - else: - # In most bounded cases, one should not use the dual. - self._compute_ridges(dual=False) - if self._ridges is NULL: - raise ValueError('could not determine ridges') + self._compute_ridges(-1) n_ridges = self._n_ridges # Mapping the indices of the Vepr to the names, if requested. @@ -3267,11 +3230,12 @@ cdef class CombinatorialPolyhedron(SageObject): self._f_vector = tuple(smallInteger(f_vector[i]) for i in range(dim+2)) - cdef int _compute_edges_or_ridges(self, bint dual, bint do_edges) except -1: + cdef int _compute_edges_or_ridges(self, int dual, bint do_edges) except -1: r""" Compute the edges of the polyhedron if ``edges`` else the ridges. If ``dual``, use the face iterator in dual mode, else in non-dual. + If ``dual`` is ``-1`` determine this automatically. If the ``f_vector`` is unkown computes it as well if computing the edges in non-dual mode or the ridges in dual-mode. @@ -3281,6 +3245,27 @@ cdef class CombinatorialPolyhedron(SageObject): if (self._edges is not NULL and do_edges) or (self._ridges is not NULL and not do_edges): return 0 # There is no need to recompute. + if dual == -1: + # Determine whether to use dual mode or not. + if not self.is_bounded(): + dual = 0 + elif do_edges: + if self.n_Vrepresentation() > self.n_facets()*self.n_facets(): + # This is a wild estimate + # that in this case it is better not to use the dual. + dual = 0 + else: + # In most bounded cases, one should use the dual. + dual = 1 + else: + if self.n_Vrepresentation()*self.n_Vrepresentation() < self.n_facets(): + # This is a wild estimate + # that in this case it is better to use the dual. + dual = 1 + else: + # In most bounded cases, one should not use the dual. + dual = 0 + cdef MemoryAllocator mem = MemoryAllocator() cdef FaceIterator face_iter cdef int dim = self.dimension() @@ -3355,6 +3340,12 @@ cdef class CombinatorialPolyhedron(SageObject): self._mem_tuple += (mem,) sig_unblock() + if do_edges and self._edges is NULL: + raise ValueError('could not determine edges') + elif not do_edges and self._ridges is NULL: + raise ValueError('could not determine ridges') + + cdef size_t _compute_edges_or_ridges_with_iterator( self, FaceIterator face_iter, const bint do_atom_rep, const bint do_f_vector, size_t ***edges_pt, size_t *counter_pt, size_t *current_length_pt, From 595c41cdc28bb30281849adadfd64389ae11fe1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 11 Oct 2021 09:49:29 +0200 Subject: [PATCH 370/511] replace + Auch eine Funktion (siehe unten) ist ein symbolischer Ausdruck:: sage: f(x) = x + 1 sage: type(f) - + Benutzen wir jedoch eine Variable, um etwas zu speichern und nicht als symbolischen Parameter, so ist ein Ausdruck, welcher sie enthält, nicht mehr ein symbolischer @@ -329,7 +329,7 @@ Ausdruck:: sage: x = 3 sage: type(x*2) - + Terme können auch in Variablen gespeichert werden. Dazu benutzen wir wie bei Zahlenwerten den Operator ``=`` für die Zuordnung:: diff --git a/src/doc/de/tutorial/interactive_shell.rst b/src/doc/de/tutorial/interactive_shell.rst index 048f1c6f0ac..b62b865330f 100644 --- a/src/doc/de/tutorial/interactive_shell.rst +++ b/src/doc/de/tutorial/interactive_shell.rst @@ -410,7 +410,7 @@ Zum Beispiel: Automatic pdb calling has been turned ON sage: EllipticCurve([1,infinity]) --------------------------------------------------------------------------- - Traceback (most recent call last) + Traceback (most recent call last) ... ipdb> @@ -519,7 +519,7 @@ Funktionsnamen ein ``?`` an, um die Dokumentation dazu aufzurufen. sage: V = QQ^3 sage: V.coordinates? Type: instancemethod - Base Class: + Base Class: String Form: Namespace: Interactive diff --git a/src/doc/de/tutorial/interfaces.rst b/src/doc/de/tutorial/interfaces.rst index 68e4ea2994f..edb4f383363 100644 --- a/src/doc/de/tutorial/interfaces.rst +++ b/src/doc/de/tutorial/interfaces.rst @@ -61,7 +61,7 @@ mehr referenziert wird. Die Objekte haben außerdem verschiedene Typen: sage: type(gp('znprimroot(10007)')) sage: type(pari('znprimroot(10007)')) - + Welche Variante sollten Sie also nutzen? Das kommt darauf an was Sie tun. Die GP-Schnittstelle kann alles was ein normales @@ -98,7 +98,7 @@ Zuerst erstellen wir eine PARI-Liste aus einer Python-Liste. sage: v [1, 2, 3, 4, 5] sage: type(v) - + Jedes PARI-Objekt ist vom Typ ``Gen``. Den PARI Typ des vorliegenden Objekts können Sie mit der ``type`` Unterfunktion herausfinden. diff --git a/src/doc/de/tutorial/programming.rst b/src/doc/de/tutorial/programming.rst index 236fb8e9c29..7d86c01e30b 100644 --- a/src/doc/de/tutorial/programming.rst +++ b/src/doc/de/tutorial/programming.rst @@ -396,7 +396,7 @@ Folge haben einen gemeinsamen Obertyp, der das Folgenuniversum genannt wird. sage: type(v) sage: type(v[1]) - + sage: v.universe() Rational Field sage: v.is_immutable() diff --git a/src/doc/de/tutorial/tour_assignment.rst b/src/doc/de/tutorial/tour_assignment.rst index e406ab4621c..2bc72cae3e1 100644 --- a/src/doc/de/tutorial/tour_assignment.rst +++ b/src/doc/de/tutorial/tour_assignment.rst @@ -91,10 +91,10 @@ beliebigen Python-Typs innerhalb eines Sichtbarkeitsbereich aufnehmen. sage: a = 5 # a ist eine ganze Zahl sage: type(a) - + sage: a = 5/3 # jetzt ist a eine rationale Zahl sage: type(a) - + sage: a = 'hello' # jetzt ist a ein String sage: type(a) <... 'str'> diff --git a/src/doc/de/tutorial/tour_functions.rst b/src/doc/de/tutorial/tour_functions.rst index 501a2f9dbd9..18cbbf00ced 100644 --- a/src/doc/de/tutorial/tour_functions.rst +++ b/src/doc/de/tutorial/tour_functions.rst @@ -61,7 +61,7 @@ können geplottet, differenziert und integriert werden. sage: Dg(3) 6 sage: type(g) - + sage: plot(g, 0, 2) Graphics object consisting of 1 graphics primitive @@ -78,7 +78,7 @@ Erläuterung zu erhalten. sage: g(x) x^2 sage: type(g(x)) - + sage: g(x).derivative() 2*x sage: plot(g(x), 0, 2) @@ -95,7 +95,7 @@ werden. sage: plot(sin, 0, 2) Graphics object consisting of 1 graphics primitive sage: type(sin(x)) - + sage: plot(sin(x), 0, 2) Graphics object consisting of 1 graphics primitive @@ -143,7 +143,7 @@ wird, was wiederum bedeutet, dass ``x<2`` ausgewertet wird. :: sage: type(x<2) - + Wenn eine symbolische Gleichung ausgewertet wird, wie in der Definition von ``h``, wird falls sie nicht offensichtlicherweise wahr @@ -176,9 +176,9 @@ Das Problem: ``g(3)``, zum Beispiel, gibt folgenden Fehler zurück: :: sage: type(f) - + sage: type(g) - + ``g`` ist keine Funktion, es ist eine Konstante, hat also keine zugehörigen Variablen, und man kann in sie nichts einsetzen. @@ -196,7 +196,7 @@ Die Lösung: Es gibt mehrere Möglichkeiten. sage: g(3) 1 sage: type(g) - + - Oder mit der ursprünglichen Definition von ``f``, definieren Sie ``g`` als symbolischen Ausdruck. @@ -210,7 +210,7 @@ Die Lösung: Es gibt mehrere Möglichkeiten. sage: g(3) 1 sage: type(g) - + - Oder mit den ursprünglichen Definitionen von ``f`` and ``g``, geben Sie die Variable an, in diese Sie den Wert einsetzen. diff --git a/src/doc/en/constructions/interface_issues.rst b/src/doc/en/constructions/interface_issues.rst index e6cb1c30da6..efe93c7edbc 100644 --- a/src/doc/en/constructions/interface_issues.rst +++ b/src/doc/en/constructions/interface_issues.rst @@ -382,7 +382,7 @@ help interface to find the file name: sage: PermutationGroup.center? Type: instancemethod - Base Class: + Base Class: String Form: Namespace: Interactive File: /home/wdj/sage/local/lib/python2.4/site-packages/sage/groups/permgroup.py diff --git a/src/doc/en/developer/coding_in_python.rst b/src/doc/en/developer/coding_in_python.rst index 1d8b7c1d3bf..09b7c831b4b 100644 --- a/src/doc/en/developer/coding_in_python.rst +++ b/src/doc/en/developer/coding_in_python.rst @@ -261,7 +261,7 @@ replacements are made: <... 'int'> sage: b = 393939 sage: type(b) - + sage: a == b True diff --git a/src/doc/en/prep/Programming.rst b/src/doc/en/prep/Programming.rst index d74ed1e9f42..f495c872f48 100644 --- a/src/doc/en/prep/Programming.rst +++ b/src/doc/en/prep/Programming.rst @@ -524,12 +524,12 @@ Luckily, it's possible to restore symbolic constants. :: sage: type(e) - + :: sage: type(pi) - + Variables are another thing to keep in mind. As mentioned briefly in earlier tutorials, in order to maintain maximum flexibility while not @@ -539,7 +539,7 @@ nothing else. :: sage: type(x) - + :: diff --git a/src/doc/en/prep/Quickstarts/Linear-Algebra.rst b/src/doc/en/prep/Quickstarts/Linear-Algebra.rst index 666e4b48765..58cb44edd3c 100644 --- a/src/doc/en/prep/Quickstarts/Linear-Algebra.rst +++ b/src/doc/en/prep/Quickstarts/Linear-Algebra.rst @@ -192,7 +192,7 @@ for our purposes. sage: type( ring_vec ) sage: type( field_vec ) - + Left\-Handed or Right\-handed? ------------------------------- diff --git a/src/doc/en/prep/Quickstarts/Number-Theory.rst b/src/doc/en/prep/Quickstarts/Number-Theory.rst index 5b1f73d8138..aa46ee12a86 100644 --- a/src/doc/en/prep/Quickstarts/Number-Theory.rst +++ b/src/doc/en/prep/Quickstarts/Number-Theory.rst @@ -31,7 +31,7 @@ For instance, we can create a number in :math:`\ZZ/11\ZZ`. The sage: a = mod(2,11); a; type(a); a^10; a^1000000 2 - + 1 1 diff --git a/src/doc/en/reference/coercion/index.rst b/src/doc/en/reference/coercion/index.rst index 04666bda51b..d8d7c2ade79 100644 --- a/src/doc/en/reference/coercion/index.rst +++ b/src/doc/en/reference/coercion/index.rst @@ -74,9 +74,9 @@ There is an important distinction between Parents and types:: sage: a = GF(5).random_element() sage: b = GF(7).random_element() sage: type(a) - + sage: type(b) - + sage: type(a) == type(b) True sage: parent(a) diff --git a/src/doc/en/thematic_tutorials/sandpile.rst b/src/doc/en/thematic_tutorials/sandpile.rst index 7dd7091415a..282889a9f15 100644 --- a/src/doc/en/thematic_tutorials/sandpile.rst +++ b/src/doc/en/thematic_tutorials/sandpile.rst @@ -5002,7 +5002,7 @@ Documentation for each method is available through the Sage online help system: :: sage: SandpileConfig.fire_vertex? - Base Class: + Base Class: String Form: Namespace: Interactive File: /usr/local/sage-4.7/local/lib/python2.6/site-packages/sage/sandpiles/sandpile.py diff --git a/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst b/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst index cbaff12746b..a295508e0ab 100644 --- a/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst +++ b/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst @@ -314,7 +314,7 @@ http://docs.python.org/library/ for a complete list. :: sage: e = Integer(9) sage: type(e) - + sage: e.__dict__ Traceback (most recent call last): ... @@ -322,7 +322,7 @@ http://docs.python.org/library/ for a complete list. :: sage: id4 = SymmetricGroup(4).one() sage: type(id4) - + sage: id4.__dict__ Traceback (most recent call last): ... diff --git a/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_cartesian.rst b/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_cartesian.rst index d7eed347d92..978aa129395 100644 --- a/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_cartesian.rst +++ b/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_cartesian.rst @@ -38,7 +38,7 @@ Thanks to the notation ```` in the above declaration, the coordinates sage: z is E.cartesian_coordinates()[3] True sage: type(z) - + Besides, `\mathbb{E}^3` is endowed with the *orthonormal vector frame* `(e_x, e_y, e_z)` associated with Cartesian coordinates:: diff --git a/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_change.rst b/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_change.rst index 188b65ed596..d7164e7c363 100644 --- a/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_change.rst +++ b/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_change.rst @@ -59,7 +59,7 @@ type ``x, y, z = var('x y z')``; they are immediately available:: sage: y is cartesian[2] True sage: type(y) - + Each of the Cartesian coordinates spans the entire real line:: diff --git a/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_curvilinear.rst b/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_curvilinear.rst index a244b427839..96617135972 100644 --- a/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_curvilinear.rst +++ b/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_curvilinear.rst @@ -36,7 +36,7 @@ type ``r, th, ph = var('r th ph')``):: sage: (r, th, ph) == E.spherical_coordinates()[:] True sage: type(r) - + Moreover, the coordinate LaTeX symbols are already set:: diff --git a/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_plane.rst b/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_plane.rst index 0286c70c467..d5e35cc552d 100644 --- a/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_plane.rst +++ b/src/doc/en/thematic_tutorials/vector_calculus/vector_calc_plane.rst @@ -32,7 +32,7 @@ the Cartesian coordinates (there is no need to declare them via :func:`var`, i.e. to type ``x, y = var('x y')``):: sage: type(y) - + Instead of using the variables ``x`` and ``y``, one may also access to the coordinates by their indices in the chart of Cartesian coordinates:: diff --git a/src/doc/en/tutorial/interactive_shell.rst b/src/doc/en/tutorial/interactive_shell.rst index 564de65aa24..68c9a17f17a 100644 --- a/src/doc/en/tutorial/interactive_shell.rst +++ b/src/doc/en/tutorial/interactive_shell.rst @@ -488,7 +488,7 @@ execution stack. For example, Automatic pdb calling has been turned ON sage: EllipticCurve([1,infinity]) --------------------------------------------------------------------------- - Traceback (most recent call last) + Traceback (most recent call last) ... ipdb> @@ -597,7 +597,7 @@ followed by ? for the documentation for that function. sage: V = QQ^3 sage: V.coordinates? Type: instancemethod - Base Class: + Base Class: String Form: Namespace: Interactive diff --git a/src/doc/en/tutorial/interfaces.rst b/src/doc/en/tutorial/interfaces.rst index 4ddbb146db3..b0e55345669 100644 --- a/src/doc/en/tutorial/interfaces.rst +++ b/src/doc/en/tutorial/interfaces.rst @@ -64,7 +64,7 @@ objects have different types: sage: type(gp('znprimroot(10007)')) sage: type(pari('znprimroot(10007)')) - + So which should you use? It depends on what you're doing. The GP interface can do absolutely anything you could do in the usual @@ -100,7 +100,7 @@ First we create a PARI list from a Python list. sage: v [1, 2, 3, 4, 5] sage: type(v) - + Every PARI object is of type ``Gen``. The PARI type of the underlying object can be obtained using the ``type`` member diff --git a/src/doc/en/tutorial/programming.rst b/src/doc/en/tutorial/programming.rst index e7ce161cc4f..56ecb369559 100644 --- a/src/doc/en/tutorial/programming.rst +++ b/src/doc/en/tutorial/programming.rst @@ -378,7 +378,7 @@ a common parent, called the sequences universe. sage: type(v) sage: type(v[1]) - + sage: v.universe() Rational Field sage: v.is_immutable() diff --git a/src/doc/en/tutorial/tour_assignment.rst b/src/doc/en/tutorial/tour_assignment.rst index b7194a7d81d..6d863b15893 100644 --- a/src/doc/en/tutorial/tour_assignment.rst +++ b/src/doc/en/tutorial/tour_assignment.rst @@ -89,10 +89,10 @@ hold values of any Python type within a given scope: sage: a = 5 # a is an integer sage: type(a) - + sage: a = 5/3 # now a is a rational number sage: type(a) - + sage: a = 'hello' # now a is a string sage: type(a) <... 'str'> diff --git a/src/doc/en/tutorial/tour_coercion.rst b/src/doc/en/tutorial/tour_coercion.rst index 0ee15f3c808..65b28fa0968 100644 --- a/src/doc/en/tutorial/tour_coercion.rst +++ b/src/doc/en/tutorial/tour_coercion.rst @@ -55,9 +55,9 @@ providing different implementations of the same mathematical structure sage: Q. = PolynomialRing(ZZ, sparse=True) sage: R. = PolynomialRing(ZZ, implementation='NTL') sage: type(a); type(b); type(c) - + - + That poses two problems: On the one hand, if one has elements that are two instances of the same class, then one may expect that their diff --git a/src/doc/en/tutorial/tour_functions.rst b/src/doc/en/tutorial/tour_functions.rst index 6c006f5180a..f00991813c2 100644 --- a/src/doc/en/tutorial/tour_functions.rst +++ b/src/doc/en/tutorial/tour_functions.rst @@ -59,7 +59,7 @@ differentiated, and integrated. sage: Dg(3) 6 sage: type(g) - + sage: plot(g, 0, 2) Graphics object consisting of 1 graphics primitive @@ -75,7 +75,7 @@ illustration. sage: g(x) x^2 sage: type(g(x)) - + sage: g(x).derivative() 2*x sage: plot(g(x), 0, 2) @@ -91,7 +91,7 @@ and with a little help, differentiated, and integrated. sage: plot(sin, 0, 2) Graphics object consisting of 1 graphics primitive sage: type(sin(x)) - + sage: plot(sin(x), 0, 2) Graphics object consisting of 1 graphics primitive @@ -174,9 +174,9 @@ The problem: ``g(3)``, for example, returns an error, saying :: sage: type(f) - + sage: type(g) - + ``g`` is not a function, it's a constant, so it has no variables associated to it, and you can't plug anything into it. @@ -194,7 +194,7 @@ The solution: there are several options. sage: g(3) 1 sage: type(g) - + - Or with ``f`` as defined originally, define ``g`` to be a symbolic expression. @@ -208,7 +208,7 @@ The solution: there are several options. sage: g(3) 1 sage: type(g) - + - Or with ``f`` and ``g`` as defined originally, specify the variable for which you are substituting. diff --git a/src/doc/es/tutorial/tour_assignment.rst b/src/doc/es/tutorial/tour_assignment.rst index d5144f74e29..12297921cc2 100644 --- a/src/doc/es/tutorial/tour_assignment.rst +++ b/src/doc/es/tutorial/tour_assignment.rst @@ -88,10 +88,10 @@ contener valores de cualquier tipo Python dentro de un ámbito dado: sage: a = 5 # a es un entero sage: type(a) - + sage: a = 5/3 # ahora es un número racional sage: type(a) - + sage: a = 'hello' # ahora es una cadena sage: type(a) <... 'str'> diff --git a/src/doc/fr/tutorial/interactive_shell.rst b/src/doc/fr/tutorial/interactive_shell.rst index 3f28f110c3a..43cdd051014 100644 --- a/src/doc/fr/tutorial/interactive_shell.rst +++ b/src/doc/fr/tutorial/interactive_shell.rst @@ -495,7 +495,7 @@ pile d'exécution. Par exemple : Automatic pdb calling has been turned ON sage: EllipticCurve([1,infinity]) --------------------------------------------------------------------------- - Traceback (most recent call last) + Traceback (most recent call last) ... ipdb> @@ -604,7 +604,7 @@ d'une fonction, tapez son nom suivi d'un point d'interrogation. sage: V = QQ^3 sage: V.coordinates? Type: instancemethod - Base Class: + Base Class: String Form: Namespace: Interactive diff --git a/src/doc/fr/tutorial/interfaces.rst b/src/doc/fr/tutorial/interfaces.rst index 647189f65d7..1cd662f3083 100644 --- a/src/doc/fr/tutorial/interfaces.rst +++ b/src/doc/fr/tutorial/interfaces.rst @@ -64,7 +64,7 @@ commandes sont de types différents : sage: type(gp('znprimroot(10007)')) sage: type(pari('znprimroot(10007)')) - + Alors, laquelle des interfaces utiliser ? Tout dépend de ce que vous cherchez à faire. L'interface GP permet de faire absolument tout ce que @@ -102,7 +102,7 @@ Commençons par créer une liste PARI à partir d'une liste Python. sage: v [1, 2, 3, 4, 5] sage: type(v) - + En Sage, les objets PARI sont de type ``Gen``. Le type PARI de l'objet sous-jacent est donné par la méthode ``type``. diff --git a/src/doc/fr/tutorial/programming.rst b/src/doc/fr/tutorial/programming.rst index 4e1b372a070..69b4182508e 100644 --- a/src/doc/fr/tutorial/programming.rst +++ b/src/doc/fr/tutorial/programming.rst @@ -391,7 +391,7 @@ l'univers de la séquence. sage: type(v) sage: type(v[1]) - + sage: v.universe() Rational Field sage: v.is_immutable() diff --git a/src/doc/fr/tutorial/tour_assignment.rst b/src/doc/fr/tutorial/tour_assignment.rst index 70e0767586a..6607ebc5a62 100644 --- a/src/doc/fr/tutorial/tour_assignment.rst +++ b/src/doc/fr/tutorial/tour_assignment.rst @@ -93,10 +93,10 @@ sein d'une même portée : sage: a = 5 # a est un entier sage: type(a) - + sage: a = 5/3 # a est maintenant un rationnel... sage: type(a) - + sage: a = 'hello' # ...et maintenant une chaîne sage: type(a) <... 'str'> diff --git a/src/doc/fr/tutorial/tour_coercion.rst b/src/doc/fr/tutorial/tour_coercion.rst index 72846896985..9d666684313 100644 --- a/src/doc/fr/tutorial/tour_coercion.rst +++ b/src/doc/fr/tutorial/tour_coercion.rst @@ -57,9 +57,9 @@ contre matrices creuses par exemple). sage: Q. = PolynomialRing(ZZ, sparse=True) sage: R. = PolynomialRing(ZZ, implementation='NTL') sage: type(a); type(b); type(c) - + - + Deux problèmes se posent alors. D'une part, si deux éléments sont instances de la même classe, on s'attend à ce que leur méthode ``__add__`` soit capable de diff --git a/src/doc/fr/tutorial/tour_functions.rst b/src/doc/fr/tutorial/tour_functions.rst index 4465b92413c..cc88b77a071 100644 --- a/src/doc/fr/tutorial/tour_functions.rst +++ b/src/doc/fr/tutorial/tour_functions.rst @@ -59,7 +59,7 @@ et que l'on peut aussi dériver ou intégrer symboliquement :: sage: Dg(3) 6 sage: type(g) - + sage: plot(g, 0, 2) Graphics object consisting of 1 graphics primitive @@ -76,7 +76,7 @@ illustrées dans le point 5 ci-dessous. sage: g(x) x^2 sage: type(g(x)) - + sage: g(x).derivative() 2*x sage: plot(g(x), 0, 2) @@ -90,7 +90,7 @@ servir à tracer des courbes, et, indirectement, être dérivées ou intégrées sage: plot(sin, 0, 2) Graphics object consisting of 1 graphics primitive sage: type(sin(x)) - + sage: plot(sin(x), 0, 2) Graphics object consisting of 1 graphics primitive @@ -132,7 +132,7 @@ est donc évaluée. :: sage: type(x < 2) - + Or, l'évaluation d'une inégalité symbolique renvoie ``False`` quand la condition n'est pas clairement vraie. Ainsi, ``h(x)`` s'évalue en @@ -167,9 +167,9 @@ the number of arguments must be less than or equal to 0 ». :: sage: type(f) - + sage: type(g) - + En effet, ``g`` n'est pas une fonction, mais une constante, sans variable en laquelle on peut l'évaluer. @@ -185,7 +185,7 @@ Solution : il y a plusieurs possibilités. sage: g(3) 1 sage: type(g) - + - Ou, sans changer la définition de ``f``, définir ``g`` comme une expression symbolique fonctionnelle :: @@ -197,7 +197,7 @@ Solution : il y a plusieurs possibilités. sage: g(3) 1 sage: type(g) - + - Ou encore, avec ``f`` et ``g`` définies comme dans l'exemple de départ, donner explicitement la variable à remplacer par sa valeur :: diff --git a/src/doc/ja/tutorial/interactive_shell.rst b/src/doc/ja/tutorial/interactive_shell.rst index eae3aeaaafc..452914bd12a 100644 --- a/src/doc/ja/tutorial/interactive_shell.rst +++ b/src/doc/ja/tutorial/interactive_shell.rst @@ -442,7 +442,7 @@ IPythonのクイック レファレンスガイドを見たければ, ``%quick Automatic pdb calling has been turned ON sage: EllipticCurve([1,infinity]) --------------------------------------------------------------------------- - Traceback (most recent call last) + Traceback (most recent call last) ... ipdb> @@ -542,7 +542,7 @@ Sageの特長の一つは,総合的なヘルプ機能の装備である. sage: V = QQ^3 sage: V.coordinates? Type: instancemethod - Base Class: + Base Class: String Form: Namespace: Interactive diff --git a/src/doc/ja/tutorial/interfaces.rst b/src/doc/ja/tutorial/interfaces.rst index 1254d297be7..9c16b2eba08 100644 --- a/src/doc/ja/tutorial/interfaces.rst +++ b/src/doc/ja/tutorial/interfaces.rst @@ -55,7 +55,7 @@ GPは送られて来た文字列を評価し,結果を変数に格納する( sage: type(gp('znprimroot(10007)')) sage: type(pari('znprimroot(10007)')) - + では,どちらの方法を選ぶべきだろうか? 答は目的による、としか言えない. @@ -84,7 +84,7 @@ PARI Cライブラリ インターフェイスについて言うと,こちら sage: v [1, 2, 3, 4, 5] sage: type(v) - + PARIのオブジェクトは全て ``Gen`` 型になる. diff --git a/src/doc/ja/tutorial/programming.rst b/src/doc/ja/tutorial/programming.rst index 245dee89b3f..9edd5f80a6d 100644 --- a/src/doc/ja/tutorial/programming.rst +++ b/src/doc/ja/tutorial/programming.rst @@ -357,7 +357,7 @@ Sageで使われる第三のリスト類似データ型が,シーケンスで sage: type(v) sage: type(v[1]) - + sage: v.universe() Rational Field sage: v.is_immutable() diff --git a/src/doc/ja/tutorial/tour_assignment.rst b/src/doc/ja/tutorial/tour_assignment.rst index be04ba7f6f1..ea8673689cc 100644 --- a/src/doc/ja/tutorial/tour_assignment.rst +++ b/src/doc/ja/tutorial/tour_assignment.rst @@ -79,10 +79,10 @@ Pythonのデータはダイナミックに型付けされ,変数を通して sage: a = 5 # aは整数 sage: type(a) - + sage: a = 5/3 # aは有理数になった sage: type(a) - + sage: a = 'hello' # ここでaは文字列 sage: type(a) <... 'str'> diff --git a/src/doc/ja/tutorial/tour_coercion.rst b/src/doc/ja/tutorial/tour_coercion.rst index 15c3ce07c3d..fd125a81987 100644 --- a/src/doc/ja/tutorial/tour_coercion.rst +++ b/src/doc/ja/tutorial/tour_coercion.rst @@ -42,9 +42,9 @@ Pythonは(ダイナミックではあっても)強い型付けがなされる言 sage: Q. = PolynomialRing(ZZ, sparse=True) sage: R. = PolynomialRing(ZZ, implementation='NTL') sage: type(a); type(b); type(c) - + - + 以上から,解決すべき問題は二系統あることが分る. diff --git a/src/doc/ja/tutorial/tour_functions.rst b/src/doc/ja/tutorial/tour_functions.rst index 159ffca4c51..2c210a9da7d 100644 --- a/src/doc/ja/tutorial/tour_functions.rst +++ b/src/doc/ja/tutorial/tour_functions.rst @@ -59,7 +59,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り sage: Dg(3) 6 sage: type(g) - + sage: plot(g, 0, 2) Graphics object consisting of 1 graphics primitive @@ -74,7 +74,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り sage: g(x) x^2 sage: type(g(x)) - + sage: g(x).derivative() 2*x sage: plot(g(x), 0, 2) @@ -92,7 +92,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り sage: plot(sin, 0, 2) Graphics object consisting of 1 graphics primitive sage: type(sin(x)) - + sage: plot(sin(x), 0, 2) Graphics object consisting of 1 graphics primitive @@ -142,7 +142,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り :: sage: type(x<2) - + シンボリック式が評価される際, ``h`` の定義の場合と同じように,その式が明らかに真でないかぎり戻り値は偽になる. @@ -181,9 +181,9 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り :: sage: type(f) - + sage: type(g) - + ``g`` は関数ではなく定数になっているので,変数を持たないから何も値を受けつけない. @@ -202,7 +202,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り sage: g(3) 1 sage: type(g) - + - または ``f`` の定義は元のまま ``g`` をシンボリック表式として定義する. @@ -216,7 +216,7 @@ Sageで「関数」と呼ばれるべきものを定義する方法は何通り sage: g(3) 1 sage: type(g) - + - または ``f`` と ``g`` の定義は元のまま,代入すべき変数を特定する. diff --git a/src/doc/pt/tutorial/interactive_shell.rst b/src/doc/pt/tutorial/interactive_shell.rst index cba3f29cfcd..d2f9e24fc4a 100644 --- a/src/doc/pt/tutorial/interactive_shell.rst +++ b/src/doc/pt/tutorial/interactive_shell.rst @@ -475,7 +475,7 @@ cima e para baixo. Por exemplo, Automatic pdb calling has been turned ON sage: EllipticCurve([1,infinity]) --------------------------------------------------------------------------- - Traceback (most recent call last) + Traceback (most recent call last) ... ipdb> @@ -582,7 +582,7 @@ seguido de ? para ver informações sobre a função. sage: V = QQ^3 sage: V.coordinates? Type: instancemethod - Base Class: + Base Class: String Form: Namespace: Interactive diff --git a/src/doc/pt/tutorial/interfaces.rst b/src/doc/pt/tutorial/interfaces.rst index 8515f18a74c..3c080cc3cfc 100644 --- a/src/doc/pt/tutorial/interfaces.rst +++ b/src/doc/pt/tutorial/interfaces.rst @@ -63,7 +63,7 @@ diferentes: sage: type(gp('znprimroot(10007)')) sage: type(pari('znprimroot(10007)')) - + Então qual eu devo usar? Depende do que você está fazendo. A interface GP pode fazer absolutamente tudo o que você poderia fazer na linha de @@ -101,7 +101,7 @@ Primeiro criamos uma lista do PARI a partir de uma lista do Python. sage: v [1, 2, 3, 4, 5] sage: type(v) - + Cada objeto do PARI é do tipo ``Gen``. O tipo PARI do objeto subjacente pode ser obtido usando a função ``type``. diff --git a/src/doc/pt/tutorial/programming.rst b/src/doc/pt/tutorial/programming.rst index 7e65233dead..fd082952410 100644 --- a/src/doc/pt/tutorial/programming.rst +++ b/src/doc/pt/tutorial/programming.rst @@ -407,7 +407,7 @@ sequência possuem um parente comum, chamado o universo da sequência. sage: type(v) sage: type(v[1]) - + sage: v.universe() Rational Field sage: v.is_immutable() diff --git a/src/doc/pt/tutorial/tour_assignment.rst b/src/doc/pt/tutorial/tour_assignment.rst index 5ba8651dc07..001856d1349 100644 --- a/src/doc/pt/tutorial/tour_assignment.rst +++ b/src/doc/pt/tutorial/tour_assignment.rst @@ -89,10 +89,10 @@ variável pode possuir valores de qualquer tipo em determinado escopo: sage: a = 5 # a is an integer sage: type(a) - + sage: a = 5/3 # now a is a rational number sage: type(a) - + sage: a = 'hello' # now a is a string sage: type(a) <... 'str'> diff --git a/src/doc/pt/tutorial/tour_functions.rst b/src/doc/pt/tutorial/tour_functions.rst index dc3ebe3fa9c..2a7cac13969 100644 --- a/src/doc/pt/tutorial/tour_functions.rst +++ b/src/doc/pt/tutorial/tour_functions.rst @@ -61,7 +61,7 @@ integradas. sage: Dg(3) 6 sage: type(g) - + sage: plot(g, 0, 2) Graphics object consisting of 1 graphics primitive @@ -77,7 +77,7 @@ embora com algumas ressalvas: veja o item 5 abaixo. sage: g(x) x^2 sage: type(g(x)) - + sage: g(x).derivative() 2*x sage: plot(g(x), 0, 2) @@ -93,7 +93,7 @@ gráfico, e com uma pequena ajuda, diferenciadas e integradas. sage: plot(sin, 0, 2) Graphics object consisting of 1 graphics primitive sage: type(sin(x)) - + sage: plot(sin(x), 0, 2) Graphics object consisting of 1 graphics primitive @@ -140,7 +140,7 @@ na função ``h``, o que significa que ``x<2`` é calculado. :: sage: type(x<2) - + Quando uma equação simbólica é calculada, como na definição de ``h``, se ela não é obviamente verdadeira, então ela retorna False. Logo @@ -173,9 +173,9 @@ number of arguments must be less than or equal to 0." :: sage: type(f) - + sage: type(g) - + ``g`` não é uma função, é uma constante, logo não possui variáveis associadas, e você não pode substituir nenhum valor em ``g``. @@ -193,7 +193,7 @@ Solução: existem vária opções. sage: g(3) 1 sage: type(g) - + - Ou com ``f`` como definida originalmente, defina ``g`` como uma expressão simbólica. @@ -207,7 +207,7 @@ Solução: existem vária opções. sage: g(3) 1 sage: type(g) - + - Ou com ``f`` e ``g`` como definidas originalmente, especifique a variável para a qual você está substituindo. diff --git a/src/doc/ru/tutorial/interactive_shell.rst b/src/doc/ru/tutorial/interactive_shell.rst index 51dffa1c923..62e9b9f694f 100644 --- a/src/doc/ru/tutorial/interactive_shell.rst +++ b/src/doc/ru/tutorial/interactive_shell.rst @@ -392,7 +392,7 @@ Wall time. Однако, если существует существенная Automatic pdb calling has been turned ON sage: EllipticCurve([1,infinity]) --------------------------------------------------------------------------- - Traceback (most recent call last) + Traceback (most recent call last) ... ipdb> @@ -498,7 +498,7 @@ Sage обладает встроенной справочной системой sage: V = QQ^3 sage: V.coordinates? Type: instancemethod - Base Class: + Base Class: String Form: Namespace: Interactive diff --git a/src/doc/ru/tutorial/interfaces.rst b/src/doc/ru/tutorial/interfaces.rst index 2210f9c0a5b..ea84527f478 100644 --- a/src/doc/ru/tutorial/interfaces.rst +++ b/src/doc/ru/tutorial/interfaces.rst @@ -59,7 +59,7 @@ GP, и результат записывается в переменную в GP sage: type(gp('znprimroot(10007)')) sage: type(pari('znprimroot(10007)')) - + Так какой же способ использовать? Это зависит от того, что вы делаете. Интерфейс GP может делать все, что может делать программа GP/PARI, запускаемая @@ -92,7 +92,7 @@ Sage использует С-библиотеку PARI, чтобы поддер sage: v [1, 2, 3, 4, 5] sage: type(v) - + Каждый объект PARI является объектом типа ``Gen``. Тип PARI может быть получен с помощью функции-члена ``type``. diff --git a/src/doc/ru/tutorial/programming.rst b/src/doc/ru/tutorial/programming.rst index e0a58e26071..4550f32717a 100644 --- a/src/doc/ru/tutorial/programming.rst +++ b/src/doc/ru/tutorial/programming.rst @@ -367,7 +367,7 @@ Python, сработает нормально. sage: type(v) sage: type(v[1]) - + sage: v.universe() Rational Field sage: v.is_immutable() diff --git a/src/doc/ru/tutorial/tour_assignment.rst b/src/doc/ru/tutorial/tour_assignment.rst index 7f8612cac9b..9ad9b1d715d 100644 --- a/src/doc/ru/tutorial/tour_assignment.rst +++ b/src/doc/ru/tutorial/tour_assignment.rst @@ -87,10 +87,10 @@ Python имеет динамический контроль типов, так sage: a = 5 # a - целое число sage: type(a) - + sage: a = 5/3 # теперь a - рациональное число sage: type(a) - + sage: a = 'hello' # теперь a - строка sage: type(a) <... 'str'> diff --git a/src/doc/ru/tutorial/tour_functions.rst b/src/doc/ru/tutorial/tour_functions.rst index 6cc4d9c73c2..1f87c843415 100644 --- a/src/doc/ru/tutorial/tour_functions.rst +++ b/src/doc/ru/tutorial/tour_functions.rst @@ -58,7 +58,7 @@ sage: Dg(3) 6 sage: type(g) - + sage: plot(g, 0, 2) Graphics object consisting of 1 graphics primitive @@ -73,7 +73,7 @@ sage: g(x) x^2 sage: type(g(x)) - + sage: g(x).derivative() 2*x sage: plot(g(x), 0, 2) @@ -90,7 +90,7 @@ sage: plot(sin, 0, 2) Graphics object consisting of 1 graphics primitive sage: type(sin(x)) - + sage: plot(sin(x), 0, 2) Graphics object consisting of 1 graphics primitive @@ -135,7 +135,7 @@ :: sage: type(x<2) - + Решение: Не используйте ``plot(h(x), 0, 4)``; используйте: @@ -163,9 +163,9 @@ :: sage: type(f) - + sage: type(g) - + ``g`` не является функцией, это константа, поэтому она не имеет переменных, и вы можете вставлять что угодно в нее. @@ -183,7 +183,7 @@ sage: g(3) 1 sage: type(g) - + - Либо вместе с ``f``, определенной выше, определить ``g`` как символьное выражение. @@ -196,7 +196,7 @@ sage: g(3) 1 sage: type(g) - + - Либо с ``f`` и ``g``, заданными, как показано выше, создать переменную, под которую подставляются значения. From 617c1732ae45800226849ff70c69dacb360f44fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 11 Oct 2021 14:52:15 +0200 Subject: [PATCH 371/511] remove last trace of TransitiveIdeal --- src/sage/combinat/backtrack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/backtrack.py b/src/sage/combinat/backtrack.py index 60df7b7eb05..2ec84286ea3 100644 --- a/src/sage/combinat/backtrack.py +++ b/src/sage/combinat/backtrack.py @@ -41,7 +41,7 @@ class GenericBacktracker(object): A generic backtrack tool for exploring a search space organized as a tree, with branch pruning, etc. - See also :class:`RecursivelyEnumeratedSet_forest` and :class:`TransitiveIdeal` for + See also :class:`RecursivelyEnumeratedSet_forest` for handling simple special cases. """ def __init__(self, initial_data, initial_state): From 95921411b2f06f9ff6477f4f3d5e77621cc8ac52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 11 Oct 2021 16:35:43 +0200 Subject: [PATCH 372/511] fix some doc in posets --- src/sage/combinat/posets/posets.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 3c5b56dedf2..9a1f7a536f4 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -6885,8 +6885,10 @@ def maximal_chains(self, partial=None): INPUT: - - ``partial`` -- list (optional); if present, find all maximal - chains starting with the elements in partial + - ``partial`` -- list (optional); if given, the list + ``partial`` is assumed to be the start of a maximal chain, + and the function will find all maximal chains starting with + the elements in ``partial`` This is used in constructing the order complex for the poset. @@ -6913,8 +6915,10 @@ def maximal_chains_iterator(self, partial=None): INPUT: - - ``partial`` -- list (optional); if present, yield all maximal - chains starting with the elements in partial + - ``partial`` -- list (optional); if given, the list + ``partial`` is assumed to be the start of a maximal chain, + and the function will yield all maximal chains starting with + the elements in ``partial`` EXAMPLES:: @@ -6923,6 +6927,13 @@ def maximal_chains_iterator(self, partial=None): sage: next(it) [0, 1, 3, 7] + TESTS:: + + sage: P = posets.BooleanLattice(3) + sage: it = P.maximal_chains_iterator([0, 4]) + sage: next(it) + [0, 4, 5, 7] + .. SEEALSO:: :meth:`antichains_iterator` From 2cd253c1b7d2b6cb6b8ca0254087565652b9d723 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 11 Oct 2021 21:58:26 +0200 Subject: [PATCH 373/511] more specific import --- src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 9cff71d08b7..902a1551974 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -1265,7 +1265,7 @@ cdef class CombinatorialPolyhedron(SageObject): sage: polytopes.cube().vertex_adjacency_matrix().is_immutable() True """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix cdef Matrix_integer_dense adjacency_matrix = matrix( ZZ, self.n_Vrepresentation(), self.n_Vrepresentation(), 0) From 2101b8cccc8b0b2fc782dbeb8c476e6a52243498 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 11 Oct 2021 20:06:14 -0700 Subject: [PATCH 374/511] build/pkgs/python3/spkg-build.in: Make sure that python finds sqlite3 when determining which extension modules to build --- build/pkgs/python3/spkg-build.in | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build/pkgs/python3/spkg-build.in b/build/pkgs/python3/spkg-build.in index c8c02917cbc..b75958ab0fd 100644 --- a/build/pkgs/python3/spkg-build.in +++ b/build/pkgs/python3/spkg-build.in @@ -84,8 +84,13 @@ sdh_configure --enable-shared $PYTHON_CONFIGURE # Make sure -L. is placed before -L$SAGE_LOCAL/lib so that python and extension # modules are linked with the right libpython; we pass this in at make time # only, since we don't want -L. to be saved as one of the default LDFLAGS -# used for building third-party extension modules -sdh_make LDFLAGS="-L. $LDFLAGS" +# used for building third-party extension modules. +# +# Trac #32442: As we now install python in SAGE_VENV, not SAGE_LOCAL, +# we need to provide paths into $SAGE_LOCAL, so that setup.py finds +# the libraries needed for the extension modules - in particular sqlite3. +# (The search code there does not know about CPATH and LIBRARY_PATH.) +sdh_make LDFLAGS="-L. -L$SAGE_LOCAL/lib $LDFLAGS" CPPFLAGS="-I$SAGE_LOCAL/include $CPPFLAGS" if [ "$UNAME" = "Darwin" ]; then export DYLD_LIBRARY_PATH="." From f3776fa32dc435a6e4c33ee3ce6cc221acf06703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 12 Oct 2021 09:46:35 +0200 Subject: [PATCH 375/511] more details --- src/sage/functions/bessel.py | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index 6de793a1545..3ba9ece2359 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -362,14 +362,14 @@ def _eval_(self, n, x): from sage.rings.infinity import unsigned_infinity if not isinstance(x, Expression) and x == 0: if n == 0: - return ZZ(1) + return ZZ.one() elif n.real() > 0 or n in ZZ: - return ZZ(0) + return ZZ.zero() elif n.real() < 0: return unsigned_infinity - if n == QQ(1) / 2: + if n == QQ((1, 2)): return sqrt(2 / pi / x) * sin(x) - elif n == QQ(-1) / 2: + elif n == QQ((-1, 2)): return sqrt(2 / pi / x) * cos(x) def _evalf_(self, n, x, parent=None, algorithm=None): @@ -584,7 +584,7 @@ def _eval_(self, n, x): return unsigned_infinity if n == QQ((1, 2)): return -sqrt(2 / pi / x) * cos(x) - elif n == QQ(-1) / 2: + elif n == QQ((-1, 2)): return sqrt(2 / pi / x) * sin(x) def _evalf_(self, n, x, parent=None, algorithm=None): @@ -788,14 +788,14 @@ def _eval_(self, n, x): from sage.rings.infinity import unsigned_infinity if not isinstance(x, Expression) and x == 0: if n == 0: - return ZZ(1) + return ZZ.one() elif n.real() > 0 or n in ZZ: - return ZZ(0) + return ZZ.zero() elif n.real() < 0: return unsigned_infinity - if n == QQ(1) / 2: + if n == QQ((1, 2)): return sqrt(2 / (pi * x)) * sinh(x) - elif n == -QQ(1) / 2: + elif n == QQ((-1, 2)): return sqrt(2 / (pi * x)) * cosh(x) def _evalf_(self, n, x, parent=None, algorithm=None): @@ -989,7 +989,7 @@ def _eval_(self, n, x): return infinity elif n.real() > 0 or n.real() < 0: return unsigned_infinity - if n == QQ(1) / 2 or n == -QQ(1) / 2 and x > 0: + if n == QQ((1, 2)) or n == QQ((-1, 2)) and x > 0: return sqrt(pi / 2) * exp(-x) * x ** (-Integer(1) / Integer(2)) def _evalf_(self, n, x, parent=None, algorithm=None): @@ -1274,13 +1274,11 @@ def _eval_(self, a, z): sage: struve_H(-3/2,x) -bessel_J(3/2, x) """ - from sage.symbolic.ring import SR if z.is_zero() \ and (SR(a).is_numeric() or SR(a).is_constant()) \ and a.real() >= -1: - return ZZ(0) - from sage.rings.rational_field import QQ - if a == -QQ((1, 2)): + return ZZ.zero() + if a == QQ((-1, 2)): from sage.functions.trig import sin return sqrt(2 / (pi * z)) * sin(z) if a == QQ((1, 2)): @@ -1288,7 +1286,7 @@ def _eval_(self, a, z): return sqrt(2 / (pi * z)) * (1 - cos(z)) if a < 0 and not SR(a).is_integer() and SR(2 * a).is_integer(): n = (a * (-2) - 1) / 2 - return Integer(-1)**n * bessel_J(n + QQ(1) / 2, z) + return Integer(-1)**n * bessel_J(n + QQ((1, 2)), z) def _evalf_(self, a, z, parent=None, algorithm=None): """ @@ -1392,11 +1390,10 @@ def _eval_(self, a, z): sage: struve_L(-3/2,x) -bessel_I(3/2, x) """ - from sage.symbolic.ring import SR if z.is_zero() \ and (SR(a).is_numeric() or SR(a).is_constant()) \ and a.real() >= -1: - return ZZ(0) + return ZZ.zero() if a == -Integer(1) / 2: from sage.functions.hyperbolic import sinh return sqrt(2 / (pi * z)) * sinh(z) @@ -1404,9 +1401,8 @@ def _eval_(self, a, z): from sage.functions.hyperbolic import cosh return sqrt(2 / (pi * z)) * (cosh(z) - 1) if a < 0 and not SR(a).is_integer() and SR(2 * a).is_integer(): - from sage.rings.rational_field import QQ n = (a * (-2) - 1) / 2 - return Integer(-1)**n * bessel_I(n + QQ(1) / 2, z) + return Integer(-1)**n * bessel_I(n + QQ((1, 2)), z) def _evalf_(self, a, z, parent=None, algorithm=None): """ From 17acb7bc892c9ca59408aa14740ff6304690e42a Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Tue, 12 Oct 2021 12:58:14 +0200 Subject: [PATCH 376/511] Do not need Cython for sdist or egg_info --- src/setup.py | 89 +++++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/src/setup.py b/src/setup.py index 686f25aec36..7737465a96f 100755 --- a/src/setup.py +++ b/src/setup.py @@ -52,7 +52,7 @@ # ## Configuration # ######################################################## -if len(sys.argv) > 1 and sys.argv[1] == "sdist": +if len(sys.argv) > 1 and (sys.argv[1] == "sdist" or sys.argv[1] == "egg_info"): sdist = True else: sdist = False @@ -69,52 +69,55 @@ # ######################################################## # ## Discovering Sources # ######################################################## - -log.info("Discovering Python/Cython source code....") -t = time.time() - -# Exclude a few files if the corresponding distribution is not loaded -optional_packages = ['mcqd', 'bliss', 'tdlib', 'primecount', - 'coxeter3', 'fes', 'sirocco', 'meataxe'] -not_installed_packages = [package for package in optional_packages - if not is_package_installed_and_updated(package)] - -distributions_to_exclude = [f"sagemath-{pkg}" - for pkg in not_installed_packages] -files_to_exclude = filter_cython_sources(SAGE_SRC, distributions_to_exclude) - -log.debug(f"files_to_exclude = {files_to_exclude}") - -python_packages = find_namespace_packages(where=SAGE_SRC, include=['sage', 'sage.*']) -log.debug(f"python_packages = {python_packages}") - -log.info(f"Discovered Python/Cython sources, time: {(time.time() - t):.2f} seconds.") - -# from sage_build_cython: -import Cython.Compiler.Options -Cython.Compiler.Options.embed_pos_in_docstring = True -gdb_debug = os.environ.get('SAGE_DEBUG', None) != 'no' - -try: +if sdist: + extensions = [] + python_packages = [] +else: log.info("Generating auto-generated sources") from sage_setup.autogen import autogen_all autogen_all() - from Cython.Build import cythonize - from sage.env import cython_aliases, sage_include_directories - extensions = cythonize( - ["**/*.pyx"], - exclude=files_to_exclude, - include_path=sage_include_directories(use_sources=True) + ['.'], - compile_time_env=compile_time_env_variables(), - compiler_directives=compiler_directives(False), - aliases=cython_aliases(), - create_extension=create_extension, - gdb_debug=gdb_debug, - nthreads=4) -except Exception as exception: - log.warn(f"Exception while generating and cythonizing source files: {exception}") - raise + log.info("Discovering Python/Cython source code....") + t = time.time() + + # Exclude a few files if the corresponding distribution is not loaded + optional_packages = ['mcqd', 'bliss', 'tdlib', 'primecount', + 'coxeter3', 'fes', 'sirocco', 'meataxe'] + not_installed_packages = [package for package in optional_packages + if not is_package_installed_and_updated(package)] + + distributions_to_exclude = [f"sagemath-{pkg}" + for pkg in not_installed_packages] + files_to_exclude = filter_cython_sources(SAGE_SRC, distributions_to_exclude) + + log.debug(f"files_to_exclude = {files_to_exclude}") + + python_packages = find_namespace_packages(where=SAGE_SRC, include=['sage', 'sage.*']) + log.debug(f"python_packages = {python_packages}") + + log.info(f"Discovered Python/Cython sources, time: {(time.time() - t):.2f} seconds.") + + # from sage_build_cython: + import Cython.Compiler.Options + Cython.Compiler.Options.embed_pos_in_docstring = True + gdb_debug = os.environ.get('SAGE_DEBUG', None) != 'no' + + try: + from Cython.Build import cythonize + from sage.env import cython_aliases, sage_include_directories + extensions = cythonize( + ["**/*.pyx"], + exclude=files_to_exclude, + include_path=sage_include_directories(use_sources=True) + ['.'], + compile_time_env=compile_time_env_variables(), + compiler_directives=compiler_directives(False), + aliases=cython_aliases(), + create_extension=create_extension, + gdb_debug=gdb_debug, + nthreads=4) + except Exception as exception: + log.warn(f"Exception while cythonizing source files: {repr(exception)}") + raise # ######################################################## # ## Distutils From ff2a35241c54a1442a3d18ad60929f6efea0ef24 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 12 Oct 2021 09:39:55 -0700 Subject: [PATCH 377/511] src/setup.py: Restrict cythonize to sage/** --- src/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setup.py b/src/setup.py index 7737465a96f..81ee8babd19 100755 --- a/src/setup.py +++ b/src/setup.py @@ -106,7 +106,7 @@ from Cython.Build import cythonize from sage.env import cython_aliases, sage_include_directories extensions = cythonize( - ["**/*.pyx"], + ["sage/**/*.pyx"], exclude=files_to_exclude, include_path=sage_include_directories(use_sources=True) + ['.'], compile_time_env=compile_time_env_variables(), From 46cf0677157aef4c208034b339797d39ca846b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 12 Oct 2021 21:37:43 +0200 Subject: [PATCH 378/511] convert some + """ proj = self.projection() if self.ambient_dim() == 3: diff --git a/src/sage/geometry/polyhedron/constructor.py b/src/sage/geometry/polyhedron/constructor.py index 2df40ce6c59..e09a3d27d88 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -131,7 +131,7 @@ sage: type(v) sage: type( v() ) - + sage: v.polyhedron() A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays sage: r = next(trunc_quadr.ray_generator()) diff --git a/src/sage/geometry/polyhedron/palp_database.py b/src/sage/geometry/polyhedron/palp_database.py index a9bd90eca8b..1ec027f9482 100644 --- a/src/sage/geometry/polyhedron/palp_database.py +++ b/src/sage/geometry/polyhedron/palp_database.py @@ -88,7 +88,7 @@ class PALPreader(SageObject): [-1, -1] in Ambient free module of rank 2 over the principal ideal domain Integer Ring sage: type(_) - + """ def __init__(self, dim, data_basename=None, output='Polyhedron'): diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index a7976de6d2e..9a6a759eb93 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1009,7 +1009,7 @@ def render_solid_3d(self, **kwds): sage: p = polytopes.hypercube(3).projection() sage: p_solid = p.render_solid_3d(opacity = .7) sage: type(p_solid) - + """ polys = self.polygons N = max([-1] + [i for p in polys for i in p]) + 1 diff --git a/src/sage/geometry/polyhedron/representation.py b/src/sage/geometry/polyhedron/representation.py index 9b4cb1586d2..443bea9224a 100644 --- a/src/sage/geometry/polyhedron/representation.py +++ b/src/sage/geometry/polyhedron/representation.py @@ -231,7 +231,7 @@ def vector(self, base_ring=None): sage: v() (-1, -1, 0) sage: type(v()) - + Conversion to a different base ring can be forced with the optional argument:: diff --git a/src/sage/groups/abelian_gps/abelian_group.py b/src/sage/groups/abelian_gps/abelian_group.py index 00cf0f3c9d7..1c9ce29e858 100644 --- a/src/sage/groups/abelian_gps/abelian_group.py +++ b/src/sage/groups/abelian_gps/abelian_group.py @@ -974,9 +974,9 @@ def gens_orders(self): sage: F = AbelianGroup(3, [2], names='abc') sage: list(map(type, F.gens_orders())) - [, - , - ] + [, + , + ] """ return self._gens_orders @@ -1022,9 +1022,9 @@ def invariants(self): sage: F = AbelianGroup(3, [2], names='abc') sage: list(map(type, F.gens_orders())) - [, - , - ] + [, + , + ] """ # TODO: deprecate return self.gens_orders() diff --git a/src/sage/groups/conjugacy_classes.py b/src/sage/groups/conjugacy_classes.py index c3a3a8460c7..fd79d60ee5b 100644 --- a/src/sage/groups/conjugacy_classes.py +++ b/src/sage/groups/conjugacy_classes.py @@ -437,7 +437,7 @@ def cardinality(self): sage: cc.cardinality() 3840 sage: type(cc.cardinality()) - + """ return self._gap_().Size().sage() diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index ee364c289b0..10f52fc6d80 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -75,7 +75,7 @@ sage: a.gap().Order() 2 sage: type(_) # note that the above output is not a Sage integer - + You can use call syntax to replace the generators with a set of arbitrary ring elements. For example, take the free abelian group @@ -397,7 +397,7 @@ def wrap_FpGroup(libgap_fpgroup): sage: P = F / libgap([ a_cubed ]); P sage: type(P) - + Now wrap it:: @@ -775,7 +775,7 @@ class FinitelyPresentedGroup(GroupMixinLibGAP, UniqueRepresentation, sage: H.gap() sage: type(_) - + """ Element = FinitelyPresentedGroupElement diff --git a/src/sage/groups/free_group.py b/src/sage/groups/free_group.py index e3c3f785b7b..68c0f909bf0 100644 --- a/src/sage/groups/free_group.py +++ b/src/sage/groups/free_group.py @@ -322,7 +322,7 @@ def Tietze(self): sage: type(a.Tietze()) <... 'tuple'> sage: type(a.Tietze()[0]) - + """ tl = self.gap().TietzeWordAbstractWord() return tuple(tl.sage()) @@ -709,7 +709,7 @@ def wrap_FreeGroup(libgap_free_group): sage: F = libgap.FreeGroup(['a', 'b']) sage: type(F) - + Now wrap it:: diff --git a/src/sage/groups/libgap_morphism.py b/src/sage/groups/libgap_morphism.py index 86a16984e0c..75785e2e382 100644 --- a/src/sage/groups/libgap_morphism.py +++ b/src/sage/groups/libgap_morphism.py @@ -133,7 +133,7 @@ class GroupMorphism_libgap(Morphism): CompositionMapping( [ (6,7,8,10,9)(11,13,14,12,15)(16,19,20,18,17)(21,25,22,24,23) ] -> [ [ [ Z(5)^0, 0*Z(5) ], [ Z(5)^0, Z(5)^0 ] ] ], ) sage: type(_) - + sage: F = GF(7); MS = MatrixSpace(F,2,2) sage: F.multiplicative_generator() diff --git a/src/sage/groups/libgap_wrapper.pyx b/src/sage/groups/libgap_wrapper.pyx index 451cb5c65c2..01776f0df18 100644 --- a/src/sage/groups/libgap_wrapper.pyx +++ b/src/sage/groups/libgap_wrapper.pyx @@ -27,7 +27,7 @@ its output via LibGAP:: sage: FooGroup() sage: type(FooGroup().gap()) - + The element class is a subclass of :class:`~sage.structure.element.MultiplicativeGroupElement`. To use @@ -285,7 +285,7 @@ class ParentLibGAP(SageObject): sage: G.gap().parent() C library interface to GAP sage: type(G.gap()) - + This can be useful, for example, to call GAP functions that are not wrapped in Sage:: @@ -325,7 +325,7 @@ class ParentLibGAP(SageObject): TESTS:: sage: type(G.ngens()) - + """ return Integer(len(self.gens())) @@ -504,14 +504,14 @@ cdef class ElementLibGAP(MultiplicativeGroupElement): sage: xg a*b*a^-1*b^-1 sage: type(xg) - + TESTS:: sage: libgap(FreeGroup('a, b').an_element()) a*b sage: type(libgap(FreeGroup('a, b').an_element())) - + """ return self._libgap diff --git a/src/sage/groups/misc_gps/argument_groups.py b/src/sage/groups/misc_gps/argument_groups.py index 818185f783e..1cf801fad85 100644 --- a/src/sage/groups/misc_gps/argument_groups.py +++ b/src/sage/groups/misc_gps/argument_groups.py @@ -1534,7 +1534,7 @@ def _act_on_(self, other, is_left): sage: S(-1) * int(4) -4 sage: type(_) - + sage: S(-1) * QQ(4) -4 sage: _.parent() @@ -1641,7 +1641,7 @@ def __init__(self, category): sage: from sage.groups.misc_gps.argument_groups import SignGroup sage: S = SignGroup() sage: S.base() # indirect doctest - + """ return super(SignGroup, self).__init__(base=int, category=category) diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 11b640c7c45..f91dcd8fcca 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -2852,7 +2852,7 @@ def _subgroup_constructor(self, libgap_group): sage: g = g1*g2 sage: Hgap = G.gap().Subgroup([g.gap()]) sage: type(Hgap) - + sage: H = G._subgroup_constructor(Hgap); H Subgroup generated by [(1,6,21,12,20,17)(2,10,15,9,11,5)(3,14,8)(4,18)(7,16)] of (The projective general unitary group of degree 3 over Finite Field of size 2) """ diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index 31e6ccce5ec..33057e459ef 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -1560,7 +1560,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): sage: t=PermutationGroupElement(L).multiplicative_order(); t 1492182350939279320058875736615841068547583863326864530410 sage: type(t) - + """ order = None cdef long long order_c = 1 diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index f1c8c715889..5010e958a3c 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -2127,9 +2127,9 @@ def cardinality(self): TESTS:: sage: type(TransitiveGroups(12).cardinality()) - + sage: type(TransitiveGroups(0).cardinality()) - + """ # gap.NrTransitiveGroups(0) fails, so Sage needs to handle this @@ -2519,9 +2519,9 @@ def cardinality(self): TESTS:: sage: type(PrimitiveGroups(12).cardinality()) - + sage: type(PrimitiveGroups(0).cardinality()) - + Check for :trac:`31774`:: diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 3c2aefc0ab9..471386f3575 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -774,7 +774,7 @@ def invariants(self): ... ValueError: object is immutable; please change a copy instead. sage: type(v[0]) - + :: diff --git a/src/sage/modular/abvar/morphism.py b/src/sage/modular/abvar/morphism.py index 99bbd68af9d..670fff0fef8 100644 --- a/src/sage/modular/abvar/morphism.py +++ b/src/sage/modular/abvar/morphism.py @@ -796,7 +796,7 @@ def index(self): sage: t.index() 997 sage: type(t.index()) - + """ return self.__n diff --git a/src/sage/modular/abvar/torsion_point.py b/src/sage/modular/abvar/torsion_point.py index 56150c69943..a7cdd54ff3a 100644 --- a/src/sage/modular/abvar/torsion_point.py +++ b/src/sage/modular/abvar/torsion_point.py @@ -87,7 +87,7 @@ def element(self): sage: v = (G.0-G.1).element(); v (1/3, -1/5) sage: type(v) - + """ return self.__element diff --git a/src/sage/modular/arithgroup/arithgroup_element.pyx b/src/sage/modular/arithgroup/arithgroup_element.pyx index 1fff86aa7ab..b2e034bb5e7 100644 --- a/src/sage/modular/arithgroup/arithgroup_element.pyx +++ b/src/sage/modular/arithgroup/arithgroup_element.pyx @@ -254,7 +254,7 @@ cdef class ArithmeticSubgroupElement(MultiplicativeGroupElement): [4 5] [3 4] sage: type(x.matrix()) - + """ return self.__x diff --git a/src/sage/modular/arithgroup/congroup_gamma0.py b/src/sage/modular/arithgroup/congroup_gamma0.py index f1fc3f493d8..16390a280ab 100644 --- a/src/sage/modular/arithgroup/congroup_gamma0.py +++ b/src/sage/modular/arithgroup/congroup_gamma0.py @@ -75,7 +75,7 @@ class Gamma0_class(GammaH_class): sage: a = Gamma0(1).dimension_cusp_forms(2); a 0 sage: type(a) - + sage: Gamma0(5).dimension_cusp_forms(0) 0 sage: Gamma0(20).dimension_cusp_forms(1) diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 1cb1a7dd803..b090be1f579 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -787,7 +787,7 @@ def conductor(self): sage: G. = DirichletGroup(20) sage: type(G(1).conductor()) - + """ if self.modulus() == 1 or self.is_trivial(): return rings.Integer(1) diff --git a/src/sage/modular/hecke/element.py b/src/sage/modular/hecke/element.py index 35053b87675..7f0ca936ccf 100644 --- a/src/sage/modular/hecke/element.py +++ b/src/sage/modular/hecke/element.py @@ -113,7 +113,7 @@ def element(self): sage: z = BrandtModule(37)([0,1,-1]).element(); z (0, 1, -1) sage: type(z) - + """ try: return self.__element @@ -130,11 +130,11 @@ def _vector_(self, R=None): sage: v = BrandtModule(37)([0,1,-1]); v (0, 1, -1) sage: type(v._vector_()) - + sage: type(vector(v)) - + sage: type(vector(v, GF(2))) - + """ if R is None: return self.__element diff --git a/src/sage/modular/local_comp/liftings.py b/src/sage/modular/local_comp/liftings.py index e862031f4b2..f3bf799ae88 100644 --- a/src/sage/modular/local_comp/liftings.py +++ b/src/sage/modular/local_comp/liftings.py @@ -53,7 +53,7 @@ def lift_to_gamma1(g, m, n): sage: assert matrix(Zmod(11), 2, n) == matrix(Zmod(11),2,m) sage: assert matrix(Zmod(17), 2, [n[0], 0, n[2], n[3]]) == 1 sage: type(lift_to_gamma1([10,11,3,11],19,5)[0]) - + Tests with `m = 1` and with `n = 1`:: @@ -95,7 +95,7 @@ def lift_matrix_to_sl2z(A, N): sage: lift_matrix_to_sl2z([10, 11, 3, 11], 19) [29, 106, 3, 11] sage: type(_[0]) - + sage: lift_matrix_to_sl2z([2,0,0,1], 5) Traceback (most recent call last): ... @@ -130,7 +130,7 @@ def lift_gen_to_gamma1(m, n): [1 6] [0 1] sage: type(lift_gen_to_gamma1(9, 8)[0]) - + """ return lift_to_gamma1([0,-1,1,0], m, n) @@ -150,7 +150,7 @@ def lift_uniformiser_odd(p, u, n): sage: lift_uniformiser_odd(3, 2, 11) [432, 377, 165, 144] sage: type(lift_uniformiser_odd(3, 2, 11)[0]) - + """ g = lift_gen_to_gamma1(p**u, n) return [p * g[0], g[1], p * g[2], g[3]] @@ -175,7 +175,7 @@ def lift_ramified(g, p, u, n): sage: lift_ramified([8,2,12,2], 3, 2, 23) [323, 110, -133584, -45493] sage: type(lift_ramified([8,2,12,2], 3, 2, 23)[0]) - + """ a, b, c, d = lift_to_gamma1(g, p**u, n) r = crt((c - g[2]) / p**u * inverse_mod(a, p), 0, p, n) diff --git a/src/sage/modular/modform/constructor.py b/src/sage/modular/modform/constructor.py index e330afb2361..2b9b59085f3 100644 --- a/src/sage/modular/modform/constructor.py +++ b/src/sage/modular/modform/constructor.py @@ -83,10 +83,10 @@ def canonical_parameters(group, level, weight, base_ring): sage: v = canonical_parameters(5, 5, int(7), ZZ); v (5, Congruence Subgroup Gamma0(5), 7, Integer Ring) sage: type(v[0]), type(v[1]), type(v[2]), type(v[3]) - (, + (, , - , - ) + , + ) sage: canonical_parameters( 5, 7, 7, ZZ ) Traceback (most recent call last): ... diff --git a/src/sage/modular/modform/space.py b/src/sage/modular/modform/space.py index afeb682bca2..497fb2e78bf 100644 --- a/src/sage/modular/modform/space.py +++ b/src/sage/modular/modform/space.py @@ -394,7 +394,7 @@ def __normalize_prec(self, prec): :: sage: type(N._ModularFormsSpace__normalize_prec(int(3))) - + """ if prec is None: prec = self.prec() diff --git a/src/sage/modular/modsym/boundary.py b/src/sage/modular/modsym/boundary.py index 89357424952..f8550d0f05f 100644 --- a/src/sage/modular/modsym/boundary.py +++ b/src/sage/modular/modsym/boundary.py @@ -541,7 +541,7 @@ def __call__(self, x): sage: B(7) Traceback (most recent call last): ... - TypeError: Coercion of 7 (of type ) into Space of Boundary Modular Symbols for Congruence Subgroup Gamma0(15) of weight 2 over Rational Field not (yet) defined. + TypeError: Coercion of 7 (of type ) into Space of Boundary Modular Symbols for Congruence Subgroup Gamma0(15) of weight 2 over Rational Field not (yet) defined. """ from .ambient import ModularSymbolsAmbient if isinstance(x, int) and x == 0: diff --git a/src/sage/modular/modsym/manin_symbol_list.py b/src/sage/modular/modsym/manin_symbol_list.py index 6dae77db4c7..dc4226b5db5 100644 --- a/src/sage/modular/modsym/manin_symbol_list.py +++ b/src/sage/modular/modsym/manin_symbol_list.py @@ -351,7 +351,7 @@ def manin_symbol(self, i): sage: s = m.manin_symbol(3); s [Y^2,(1,2)] sage: type(s) - + """ return self.element_class(self, self._symbol_list[i]) diff --git a/src/sage/modular/modsym/modsym.py b/src/sage/modular/modsym/modsym.py index 58a0d64b8b5..ee49b9c9abd 100644 --- a/src/sage/modular/modsym/modsym.py +++ b/src/sage/modular/modsym/modsym.py @@ -112,7 +112,7 @@ def canonical_parameters(group, weight, sign, base_ring): sage: p1 == p2 True sage: type(p1[1]) - + """ sign = rings.Integer(sign) if not (sign in [-1,0,1]): diff --git a/src/sage/modular/overconvergent/weightspace.py b/src/sage/modular/overconvergent/weightspace.py index 08aacc88588..14515dda101 100644 --- a/src/sage/modular/overconvergent/weightspace.py +++ b/src/sage/modular/overconvergent/weightspace.py @@ -447,7 +447,7 @@ def one_over_Lvalue(self): sage: pAdicWeightSpace(11)(0).one_over_Lvalue() 0 sage: type(_) - + """ if self.is_trivial(): return ZZ(0) diff --git a/src/sage/modular/pollack_stevens/sigma0.py b/src/sage/modular/pollack_stevens/sigma0.py index 687b3c0644e..fa2f4ac7d81 100644 --- a/src/sage/modular/pollack_stevens/sigma0.py +++ b/src/sage/modular/pollack_stevens/sigma0.py @@ -288,7 +288,7 @@ def matrix(self): sage: type(s) sage: type(sm) - + sage: s == sm True """ diff --git a/src/sage/modular/pollack_stevens/space.py b/src/sage/modular/pollack_stevens/space.py index e4cb161ce07..f52d609b6e7 100644 --- a/src/sage/modular/pollack_stevens/space.py +++ b/src/sage/modular/pollack_stevens/space.py @@ -823,7 +823,7 @@ def cusps_from_mat(g): You can also just give the matrix of ``g``:: sage: type(g) - + sage: cusps_from_mat(g.matrix()) (+Infinity, 0) diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index 81a775c99c4..6e170fe8c45 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -1023,7 +1023,7 @@ def hecke_matrix(self, n, algorithm='default', sparse=False, B=None): [ 6 6] [ 2 10] sage: type(t) - + sage: B.hecke_matrix(19, algorithm='direct', B=2) [ 8 12] [ 4 16] @@ -1079,9 +1079,9 @@ def _compute_hecke_matrix_prime(self, p, sparse=False, B=None): [1 0 2] [1 2 0] sage: type(t) - + sage: type(B._compute_hecke_matrix_prime(2,sparse=True)) - + """ return self._compute_hecke_matrix_directly(n=p, B=B, sparse=sparse) @@ -1106,9 +1106,9 @@ def _compute_hecke_matrix_directly(self, n, B=None, sparse=False): [1 0 2] [1 2 0] sage: type(t) - + sage: type(B._compute_hecke_matrix_directly(2,sparse=True)) - + You can't compute the Hecke operator for n not coprime to the level using this function:: diff --git a/src/sage/modules/fg_pid/fgp_element.py b/src/sage/modules/fg_pid/fgp_element.py index f6f03acd16c..3395225529b 100644 --- a/src/sage/modules/fg_pid/fgp_element.py +++ b/src/sage/modules/fg_pid/fgp_element.py @@ -440,7 +440,7 @@ def additive_order(self): sage: Q.0.additive_order() 12 sage: type(Q.0.additive_order()) - + sage: Q.1.additive_order() +Infinity """ diff --git a/src/sage/modules/filtered_vector_space.py b/src/sage/modules/filtered_vector_space.py index 4d0e451806e..dd6608c6161 100644 --- a/src/sage/modules/filtered_vector_space.py +++ b/src/sage/modules/filtered_vector_space.py @@ -218,7 +218,7 @@ def normalize_degree(deg): sage: from sage.modules.filtered_vector_space import normalize_degree sage: type(normalize_degree(int(1))) - + sage: normalize_degree(oo) +Infinity """ diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index 2075d07c0ae..fb1937e4da6 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -914,7 +914,7 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: v = sage.modules.free_module_element.FreeModuleElement(QQ^3) sage: type(v) - + """ self._parent = parent self._degree = parent.degree() @@ -1735,7 +1735,7 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: F. = PolynomialRing(QQ, 'y') sage: type(vector(F, [0]*4, sparse=True)) - + sage: vector(F, [0,0,0,y]) == vector(F, [0,0,0,y]) True sage: vector(F, [0,0,0,0]) == vector(F, [0,2,0,y]) @@ -1928,7 +1928,7 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: P. = QQ[] sage: v = vector([x,y,z], sparse=True) sage: type(v) - + sage: a = v.list(); a [x, y, z] sage: a[0] = x*y; v @@ -4012,7 +4012,7 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: vec (0.5, 0.3333333333333334, 0.4596976941318602) sage: type(vec) - + sage: answers [(0.5, 5.55111512312578...e-15, 21, 0), (0.3333333333333..., 3.70074341541719...e-15, 21, 0), (0.45969769413186..., 5.10366964392284...e-15, 21, 0)] @@ -4169,7 +4169,7 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): EXAMPLES:: sage: type(vector(RR, [-1,0,2/3,pi,oo])) - + We can initialize with lists, tuples and derived types:: @@ -4418,7 +4418,7 @@ cdef class FreeModuleElement_generic_dense(FreeModuleElement): sage: P. = QQ[] sage: v = vector([x,y,z]) sage: type(v) - + sage: a = v.list(); a [x, y, z] sage: a[0] = x*y; v @@ -5114,7 +5114,7 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): sage: M = FreeModule(R, 3, sparse=True) * (1/x) sage: v = M([-x^2, 3/x, 0]) sage: type(v) - + sage: a = v.list() sage: a [-x^2, 3/x, 0] diff --git a/src/sage/modules/module.pyx b/src/sage/modules/module.pyx index 5f3b4e0d467..62c6636fe0b 100644 --- a/src/sage/modules/module.pyx +++ b/src/sage/modules/module.pyx @@ -120,7 +120,7 @@ cdef class Module(Parent): sage: from sage.modules.module import Module sage: M = Module(ZZ) sage: type(M) - + """ from sage.categories.modules import Modules diff --git a/src/sage/modules/tensor_operations.py b/src/sage/modules/tensor_operations.py index 3550946581b..ce3bd555434 100644 --- a/src/sage/modules/tensor_operations.py +++ b/src/sage/modules/tensor_operations.py @@ -171,7 +171,7 @@ class VectorCollection(FreeModule_ambient_field): ((1, 0), (0, 1), (1, 2)) sage: r = R._vectors[0] sage: type(r) - + sage: r.parent() is R True sage: r.is_immutable() diff --git a/src/sage/modules/vector_complex_double_dense.pyx b/src/sage/modules/vector_complex_double_dense.pyx index 74c9dd75b11..c823e685abd 100644 --- a/src/sage/modules/vector_complex_double_dense.pyx +++ b/src/sage/modules/vector_complex_double_dense.pyx @@ -7,7 +7,7 @@ EXAMPLES:: sage: v (1.0 - 1.0*I, 2.0 + 3.141592653589793*I, 3.0 + 5.0*I) sage: type(v) - + sage: parent(v) Vector space of dimension 3 over Complex Double Field sage: v[0] = 5 diff --git a/src/sage/modules/vector_double_dense.pyx b/src/sage/modules/vector_double_dense.pyx index 83334163bea..d5559a07fb0 100644 --- a/src/sage/modules/vector_double_dense.pyx +++ b/src/sage/modules/vector_double_dense.pyx @@ -10,7 +10,7 @@ EXAMPLES:: sage: v (1.0 - 1.0*I, 2.0 + 3.141592653589793*I, 3.0 + 5.0*I) sage: type(v) - + sage: parent(v) Vector space of dimension 3 over Complex Double Field sage: v[0] = 5 diff --git a/src/sage/modules/vector_mod2_dense.pyx b/src/sage/modules/vector_mod2_dense.pyx index 3c08d14f2d7..47f41853f98 100644 --- a/src/sage/modules/vector_mod2_dense.pyx +++ b/src/sage/modules/vector_mod2_dense.pyx @@ -59,7 +59,7 @@ cdef class Vector_mod2_dense(free_module_element.FreeModuleElement): sage: VS([0,0,1]) (0, 0, 1) sage: type(_) - + """ cdef Vector_mod2_dense y y = Vector_mod2_dense.__new__(Vector_mod2_dense) @@ -114,7 +114,7 @@ cdef class Vector_mod2_dense(free_module_element.FreeModuleElement): sage: VS([0,0,1]) (0, 0, 1) sage: type(_) - + """ self._degree = degree self._parent = parent @@ -131,7 +131,7 @@ cdef class Vector_mod2_dense(free_module_element.FreeModuleElement): sage: VS((0,0,1/3)) (0, 0, 1) sage: type(_) - + """ self._entries = NULL self._is_immutable = 0 @@ -146,7 +146,7 @@ cdef class Vector_mod2_dense(free_module_element.FreeModuleElement): sage: VS((0,0,1/3)) (0, 0, 1) sage: type(_) - + sage: VS((0,0,int(3))) (0, 0, 1) sage: VS((0,0,3)) diff --git a/src/sage/modules/vector_modn_dense.pyx b/src/sage/modules/vector_modn_dense.pyx index d04604c5be3..9efa2d09753 100644 --- a/src/sage/modules/vector_modn_dense.pyx +++ b/src/sage/modules/vector_modn_dense.pyx @@ -5,7 +5,7 @@ EXAMPLES:: sage: v = vector(Integers(8),[1,2,3,4,5]) sage: type(v) - + sage: v (1, 2, 3, 4, 5) sage: 3*v @@ -64,13 +64,13 @@ TESTS:: sage: K = GF(previous_prime(2^31)) sage: v = vector(K, [42]); type(v[0]) - + sage: ~v[0] 2096353084 sage: K = GF(next_prime(2^31)) sage: v = vector(K, [42]); type(v[0]) - + sage: ~v[0] 1482786336 diff --git a/src/sage/modules/vector_real_double_dense.pyx b/src/sage/modules/vector_real_double_dense.pyx index 883a6195ca3..59bb8f4e23a 100644 --- a/src/sage/modules/vector_real_double_dense.pyx +++ b/src/sage/modules/vector_real_double_dense.pyx @@ -7,7 +7,7 @@ EXAMPLES:: sage: v (1.0, 3.141592653589793, 1.414213562373095) sage: type(v) - + sage: parent(v) Vector space of dimension 3 over Real Double Field sage: v[0] = 5 diff --git a/src/sage/stats/time_series.pyx b/src/sage/stats/time_series.pyx index 1f267685b69..234925fb478 100644 --- a/src/sage/stats/time_series.pyx +++ b/src/sage/stats/time_series.pyx @@ -2579,7 +2579,7 @@ def unpickle_time_series_v1(bytes v, Py_ssize_t n): sage: v = stats.TimeSeries([1,2,3]) sage: s = v.__reduce__()[1][0] sage: type(s) - + sage: sage.stats.time_series.unpickle_time_series_v1(s,3) [1.0000, 2.0000, 3.0000] sage: sage.stats.time_series.unpickle_time_series_v1(s+s,6) diff --git a/src/sage/structure/coerce_actions.pyx b/src/sage/structure/coerce_actions.pyx index 4f1c4cdf45b..82a5eaf356c 100644 --- a/src/sage/structure/coerce_actions.pyx +++ b/src/sage/structure/coerce_actions.pyx @@ -63,7 +63,7 @@ cdef class GenericAction(Action): sage: sage.structure.coerce_actions.GenericAction(QQ, Z6, True) Traceback (most recent call last): ... - NotImplementedError: action for not implemented + NotImplementedError: action for not implemented This will break if we tried to use it:: diff --git a/src/sage/structure/dynamic_class.py b/src/sage/structure/dynamic_class.py index 6ff4bc7990c..434c2968f8d 100644 --- a/src/sage/structure/dynamic_class.py +++ b/src/sage/structure/dynamic_class.py @@ -201,11 +201,11 @@ def dynamic_class(name, bases, cls=None, reduction=None, doccls=None, '__main__' sage: Foo.__bases__ - (,) + (,) sage: FooBar.__bases__ (,) sage: Foo.mro() - [, ] + [, ] sage: FooBar.mro() [, , ] @@ -238,7 +238,7 @@ class also has a zero ``__dictoffset__``. This means that the sage: BarFoo = dynamic_class("BarFoo", (Foo,), Bar, reduction = (str, (3,))) sage: type(BarFoo).__reduce__(BarFoo) - (, (3,)) + (, (3,)) sage: loads(dumps(BarFoo)) '3' @@ -280,7 +280,7 @@ class also has a zero ``__dictoffset__``. This means that the first class:: sage: dynamic_class("BarFoo", (Foo,), Bar, reduction = (str, (2,)), cache="ignore_reduction")._reduction - (, (3,)) + (, (3,)) .. WARNING:: @@ -502,7 +502,7 @@ def __reduce__(self): sage: C = sage.structure.dynamic_class.dynamic_class_internal("bla", (object,), Foo, doccls = DocClass) sage: type(C).__reduce__(C) (, - ('bla', (,), , None, )) + ('bla', (,), , None, )) sage: C = sage.structure.dynamic_class.dynamic_class_internal("bla", (object,), Foo, doccls = DocClass, reduction = "blah") sage: type(C).__reduce__(C) 'blah' diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index 7cdddb22644..9561ae9a899 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -2453,7 +2453,7 @@ cdef class ModuleElementWithMutability(ModuleElement): sage: v = sage.modules.free_module_element.FreeModuleElement(QQ^3) sage: type(v) - + """ self._parent = parent self._is_immutable = is_immutable diff --git a/src/sage/structure/sequence.py b/src/sage/structure/sequence.py index 0c8440da8e0..4925e24ce8a 100644 --- a/src/sage/structure/sequence.py +++ b/src/sage/structure/sequence.py @@ -116,7 +116,7 @@ def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=Non sage: v = Sequence(range(10)) sage: v.universe() - + sage: v [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] @@ -298,7 +298,7 @@ class Sequence_generic(sage.structure.sage_object.SageObject, list): sage: v = Sequence(range(10)) sage: v.universe() - + sage: v [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] @@ -485,7 +485,7 @@ def __setitem__(self, n, value): sage: v [1, 5, 3, 4] sage: type(v[2]) - + """ self._require_mutable() if isinstance(n, slice): @@ -539,7 +539,7 @@ def append(self, x): sage: v = Sequence([1/3,2,3,4]) sage: v.append(4) sage: type(v[4]) - + """ self._require_mutable() y = self.__universe(x) @@ -776,7 +776,7 @@ def is_mutable(self): True sage: a[0] = 100 sage: type(a[0]) - + sage: a.set_immutable() sage: a[0] = 50 Traceback (most recent call last): diff --git a/src/sage/symbolic/constants.py b/src/sage/symbolic/constants.py index a4b43b2a9f3..29c43eb64c5 100644 --- a/src/sage/symbolic/constants.py +++ b/src/sage/symbolic/constants.py @@ -717,7 +717,7 @@ def _mpfr_(self,R): sage: NaN._mpfr_(RealField(53)) NaN sage: type(_) - + """ return R('NaN') #??? nan in mpfr: void mpfr_set_nan (mpfr_t x) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 34145c0fad4..1c084ee9dc2 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -1476,7 +1476,7 @@ cdef class Expression(CommutativeRingElement): sage: ZZ(f.coefficient(x,0)) -3 sage: type(ZZ(f.coefficient(x,0))) - + Coercion is done if necessary:: @@ -1484,7 +1484,7 @@ cdef class Expression(CommutativeRingElement): sage: ZZ(f.coefficient(x)) 17 sage: type(ZZ(f.coefficient(x))) - + If the symbolic expression is just a wrapper around an integer, that very same integer is not preserved, but a new one returned:: @@ -1549,7 +1549,7 @@ cdef class Expression(CommutativeRingElement): sage: a = QQ(f.coefficient(x)); a 17 sage: type(a) - + sage: QQ(f.coefficient(x,0)) -3/8 @@ -1679,7 +1679,7 @@ cdef class Expression(CommutativeRingElement): sage: SR(CBF(1+I))._convert({'parent':RDF}) 1.0 + 1.0*I sage: type(_.pyobject()) - + sage: SR(CBF(1+I))._convert({'parent':CDF}) 1.0 + 1.0*I sage: SR(RBF(1))._convert({'parent':RDF}) @@ -1687,7 +1687,7 @@ cdef class Expression(CommutativeRingElement): sage: SR(CBF(1))._convert({'parent':RDF}) 1.0 sage: type(_.pyobject()) - + """ cdef GEx res = self._gobj.evalf(0, kwds) return new_Expression_from_GEx(self._parent, res) @@ -6270,7 +6270,7 @@ cdef class Expression(CommutativeRingElement): sage: type(t._unpack_operands()) <... 'tuple'> sage: list(map(type, t._unpack_operands())) - [, , , , ] + [, , , , ] sage: u = SR._force_pyobject((t, x^2)) sage: u._unpack_operands() ((1, 2, x, x + 1, x + 2), x^2) @@ -8264,7 +8264,7 @@ cdef class Expression(CommutativeRingElement): sage: abs(SR(-5)) 5 sage: type(abs(SR(-5))) - + Because this overrides a Python builtin function, we do not currently support a ``hold`` parameter to prevent automatic @@ -10361,7 +10361,7 @@ cdef class Expression(CommutativeRingElement): sage: res = t.maxima_methods().logcontract(); res log((sqrt(2) + 1)*(sqrt(2) - 1)) sage: type(res) - + """ from sage.symbolic.maxima_wrapper import MaximaWrapper return MaximaWrapper(self) @@ -13538,7 +13538,7 @@ cdef Expression new_Expression_from_GEx(parent, GEx juice): if is_exactly_a_function(juice): # if the function defines any dynamic methods these are made # available through a dynamic class - cls = get_dynamic_class_for_function(ex_to_function(juice).get_serial()) + cls = get_dynamic_class_for_function(ex_to_function(juice).get_serial()) else: cls = Expression @@ -13559,7 +13559,7 @@ cpdef new_Expression(parent, x): sage: a = SR(-3/4); a -3/4 sage: type(a) - + sage: a.parent() Symbolic Ring sage: K. = QuadraticField(-3) @@ -13654,7 +13654,7 @@ cpdef new_Expression_from_pyobject(parent, x, bint force=True, bint recursive=Tr sage: t = SR._force_pyobject(QQ); t # indirect doctest Rational Field sage: type(t) - + sage: from sage.symbolic.expression import new_Expression_from_pyobject sage: t = new_Expression_from_pyobject(SR, 17); t diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index d2c7d8e468f..faac362f426 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -446,7 +446,7 @@ cdef class Function(SageObject): sage: arctan(float(1)) 0.7853981633974483 sage: type(lambert_w(SR(0))) - + Precision of the result depends on the precision of the input:: @@ -955,7 +955,7 @@ cdef class BuiltinFunction(Function): sage: sin(numpy.int32(0)) 0.0 sage: type(_) - + TESTS:: diff --git a/src/sage/symbolic/pynac_impl.pxi b/src/sage/symbolic/pynac_impl.pxi index 01a51af2997..880a07faf17 100644 --- a/src/sage/symbolic/pynac_impl.pxi +++ b/src/sage/symbolic/pynac_impl.pxi @@ -101,9 +101,9 @@ cdef exprseq_to_PyTuple(GEx seq): sage: tfunc = TFunc() sage: u = SR._force_pyobject((1, x+1, 2)) sage: tfunc(u, x, SR._force_pyobject((3.0, 2^x))) - len(args): 3, types: [<... 'tuple'>, , <... 'tuple'>] - argument 0 is a tuple, with types [, , ] - argument 2 is a tuple, with types [, ] + len(args): 3, types: [<... 'tuple'>, , <... 'tuple'>] + argument 0 is a tuple, with types [, , ] + argument 2 is a tuple, with types [, ] tfunc((1, x + 1, 2), x, (3.00000000000000, 2^x)) """ from sage.symbolic.ring import SR @@ -128,7 +128,7 @@ def unpack_operands(Expression ex): sage: type(unpack_operands(t)) <... 'tuple'> sage: list(map(type, unpack_operands(t))) - [, , , , ] + [, , , , ] sage: u = SR._force_pyobject((t, x^2)) sage: unpack_operands(u) ((1, 2, x, x + 1, x + 2), x^2) @@ -159,7 +159,7 @@ cdef exvector_to_PyTuple(GExVector seq): sage: tfunc = TFunc() sage: u = SR._force_pyobject((1, x+1, 2)) sage: tfunc(u, x, 3.0, 5.0r) - len(args): 4, types: [<... 'tuple'>, , , <... 'float'>] + len(args): 4, types: [<... 'tuple'>, , , <... 'float'>] tfunc((1, x + 1, 2), x, 3.00000000000000, 5.0) TESTS: @@ -167,8 +167,8 @@ cdef exvector_to_PyTuple(GExVector seq): Check if symbolic functions in the arguments are preserved:: sage: tfunc(sin(x), tfunc(1, x^2)) - len(args): 2, types: [, ] - len(args): 2, types: [, ] + len(args): 2, types: [, ] + len(args): 2, types: [, ] tfunc(sin(x), tfunc(1, x^2)) """ @@ -1343,11 +1343,11 @@ cdef py_float(n, PyObject* kwds): sage: py_float(10, {'parent':CDF}) 10.0 sage: type(py_float(10, {'parent':CDF})) - + sage: py_float(1/2, {'parent':CC}) 0.500000000000000 sage: type(py_float(1/2, {'parent':CC})) - + """ if kwds is not NULL: p = (kwds)['parent'] @@ -2420,9 +2420,9 @@ def init_pynac_I(): sage: sage.symbolic.expression.init_pynac_I() sage: type(sage.symbolic.expression.I) - + sage: type(sage.symbolic.expression.I.pyobject()) - + Check that :trac:`10064` is fixed:: diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index a07d43d2aec..7789e1c4095 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -248,7 +248,7 @@ cdef class SymbolicRing(CommutativeRing): sage: a = SR(-3/4); a -3/4 sage: type(a) - + sage: a.parent() Symbolic Ring sage: K. = QuadraticField(-3) @@ -402,7 +402,7 @@ cdef class SymbolicRing(CommutativeRing): sage: t = SR._force_pyobject(QQ); t Rational Field sage: type(t) - + Testing tuples:: @@ -525,7 +525,7 @@ cdef class SymbolicRing(CommutativeRing): sage: c = SR.characteristic(); c 0 sage: type(c) - + """ return Integer(0) @@ -795,7 +795,7 @@ cdef class SymbolicRing(CommutativeRing): The return type is a symbolic expression:: sage: type(zz) - + We can specify the domain as well:: @@ -1177,7 +1177,7 @@ cdef class NumpyToSRMorphism(Morphism): sage: a = f(numpy.int8('2')).pyobject() sage: type(a) - + This behavior also applies to standard functions:: From 2bd108b56aec4bea04d1143f4e0710abf235679c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 12 Oct 2021 21:50:49 +0200 Subject: [PATCH 379/511] removing src/sage/combinat/integer_list_old.py --- src/sage/combinat/integer_list_old.py | 1214 ------------------------- 1 file changed, 1214 deletions(-) delete mode 100644 src/sage/combinat/integer_list_old.py diff --git a/src/sage/combinat/integer_list_old.py b/src/sage/combinat/integer_list_old.py deleted file mode 100644 index cdd420bb79e..00000000000 --- a/src/sage/combinat/integer_list_old.py +++ /dev/null @@ -1,1214 +0,0 @@ -r""" -Tools for generating lists of integers in lexicographic order - -IMPORTANT NOTE (2009/02): -The internal functions in this file will be deprecated soon. -Please only use them through :class:`IntegerListsLex`. - -AUTHORS: - -- Mike Hansen - -- Travis Scrimshaw (2012-05-12): Fixed errors when returning ``None`` from - first. Added checks to make sure ``max_slope`` is satisfied. - -- Travis Scrimshaw (2012-10-29): Made ``IntegerListsLex`` into a parent with - the element class ``IntegerListsLexElement``. -""" -# **************************************************************************** -# Copyright (C) 2007 Mike Hansen , -# Copyright (C) 2012 Travis Scrimshaw -# -# Distributed under the terms of the GNU General Public License (GPL) -# -# This code is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# The full text of the GPL is available at: -# -# https://www.gnu.org/licenses/ -# **************************************************************************** - -from sage.arith.all import binomial -from sage.rings.integer_ring import ZZ -from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.structure.parent import Parent -from sage.structure.list_clone import ClonableArray -from sage.misc.stopgap import stopgap - - -def first(n, min_length, max_length, floor, ceiling, min_slope, max_slope): - """ - Return the lexicographically smallest valid composition of ``n`` - satisfying the conditions. - - .. warning:: - - INTERNAL FUNCTION! DO NOT USE DIRECTLY! - - .. TODO:: - - Move this into Cython. - - Preconditions: - - - ``floor`` and ``ceiling`` need to satisfy the slope constraints, - e.g. be obtained ``fromcomp2floor`` or ``comp2ceil`` - - - ``floor`` must be below ``ceiling`` to ensure - the existence a valid composition - - TESTS:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: f = lambda l: lambda i: l[i-1] - sage: f([0,1,2,3,4,5])(1) - 0 - sage: integer_list.first(12, 4, 4, f([0,0,0,0]), f([4,4,4,4]), -1, 1) - [4, 3, 3, 2] - sage: integer_list.first(36, 9, 9, f([3,3,3,2,1,1,0,0,0]), f([7,6,5,5,5,5,5,4,4]), -1, 1) - [7, 6, 5, 5, 4, 3, 3, 2, 1] - sage: integer_list.first(25, 9, 9, f([3,3,3,2,1,1,0,0,0]), f([7,6,5,5,5,5,5,4,4]), -2, 1) - [7, 6, 5, 4, 2, 1, 0, 0, 0] - sage: integer_list.first(36, 9, 9, f([3,3,3,2,1,4,2,0,0]), f([7,6,5,5,5,5,5,4,4]), -2, 1) - [7, 6, 5, 5, 5, 4, 3, 1, 0] - - :: - - sage: I = integer_list.IntegerListsLex(6, max_slope=2, min_slope=2) - sage: list(I) - [[6], [2, 4], [0, 2, 4]] - """ - stopgap("First uses the old implementation of IntegerListsLex, which does not allow for arbitrary input;" - " non-allowed input can return wrong results," - " please see the documentation for IntegerListsLex for details.", - 17548) - # Check trivial cases, and standardize min_length to be at least 1 - if n < 0: - return None - if max_length <= 0: - if n == 0: - return [] - return None - if min_length <= 0: - if n == 0: - return [] - min_length = 1 - - # Increase min_length until n <= sum([ceiling(i) for i in range(min_length)]) - # This may run forever! - # Find the actual length the list needs to be - N = 0 - for i in range(1, min_length + 1): - ceil = ceiling(i) - if ceil < floor(i): - return None - N += ceil - while N < n: - min_length += 1 - if min_length > max_length: - return None - - ceil = ceiling(min_length) - if ceil == 0 and max_slope <= 0 or ceil < floor(min_length): - return None - - N += ceil - - # Trivial case - if min_length == 1: - if n < floor(1): - return None - return [n] - - if max_slope < min_slope: - return None - - # Compute the minimum values - # We are constrained below by the max slope - result = [floor(min_length)] - n -= floor(min_length) - for i in reversed(range(1, min_length)): - result.insert(0, max(floor(i), result[0] - max_slope)) - n -= result[0] - if n < 0: - return None - - if n == 0: # There is nothing more to do - return result - - if min_slope == float('-inf'): - for i in range(1, min_length+1): - if n <= ceiling(i) - result[i-1]: # -1 for indexing - result[i-1] += n - break - else: - n -= ceiling(i) - result[i-1] - result[i-1] = ceiling(i) - else: - low_x = 1 - low_y = result[0] - high_x = 1 - high_y = result[0] - - while n > 0: - # invariant after each iteration of the loop: - # [low_x, low_y] is the coordinate of the rightmost point of the - # current diagonal s.t. result[low_x] < low_y - low_y += 1 - while low_x < min_length and low_y + min_slope > result[low_x]: - low_x += 1 - low_y += min_slope - - high_y += 1 - while high_y > ceiling(high_x): - high_x += 1 - high_y += min_slope - - n -= low_x - high_x + 1 - - for j in range(1, high_x): - result[j-1] = ceiling(j) - for i in range(0, -n): - result[high_x+i-1] = high_y + min_slope * i - 1 - for i in range(-n, low_x-high_x+1): - result[high_x+i-1] = high_y + min_slope * i - - # Special check for equal slopes - if min_slope == max_slope and any(val + min_slope != result[i + 1] - for i, val in enumerate(result[:-1])): - return None - - return result - - -def lower_regular(comp, min_slope, max_slope): - """ - Return the uppest regular composition below ``comp`` - - TESTS:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: integer_list.lower_regular([4,2,6], -1, 1) - [3, 2, 3] - sage: integer_list.lower_regular([4,2,6], -1, infinity) - [3, 2, 6] - sage: integer_list.lower_regular([1,4,2], -1, 1) - [1, 2, 2] - sage: integer_list.lower_regular([4,2,6,3,7], -2, 1) - [4, 2, 3, 3, 4] - sage: integer_list.lower_regular([4,2,infinity,3,7], -2, 1) - [4, 2, 3, 3, 4] - sage: integer_list.lower_regular([1, infinity, 2], -1, 1) - [1, 2, 2] - sage: integer_list.lower_regular([infinity, 4, 2], -1, 1) - [4, 3, 2] - """ - new_comp = comp[:] - for i in range(1, len(new_comp)): - new_comp[i] = min(new_comp[i], new_comp[i-1] + max_slope) - - for i in reversed(range(len(new_comp)-1)): - new_comp[i] = min(new_comp[i], new_comp[i+1] - min_slope) - - return new_comp - - -def rightmost_pivot(comp, min_length, max_length, floor, ceiling, min_slope, max_slope): - """ - TESTS:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: f = lambda l: lambda i: l[i-1] - sage: integer_list.rightmost_pivot([7,6,5,5,4,3,3,2,1], 9, 9, f([3,3,3,2,1,1,0,0,0]), f([7,6,5,5,5,5,5,4,4]), -1, 0) - [7, 2] - sage: integer_list.rightmost_pivot([7,6,5,5,4,3,3,2,1], 9, 9,f([3,3,3,2,1,1,0,0,0]), f([7,6,5,5,5,5,5,4,4]), -2, 0) - [7, 1] - sage: integer_list.rightmost_pivot([7,6,5,5,4,3,3,2,1], 9, 9,f([3,3,3,2,1,1,0,0,0]), f([7,6,5,5,5,5,5,4,4]), -2, 4) - [8, 1] - sage: integer_list.rightmost_pivot([7,6,5,5,4,3,3,2,1], 9, 9,f([3,3,3,2,1,1,0,0,0]), f([7,6,5,5,5,5,5,4,4]), -2, 1) - [8, 1] - sage: integer_list.rightmost_pivot([7,6,5,5,5,5,5,4,4], 9, 9,f([3,3,3,2,1,1,0,0,0]), f([7,6,5,5,5,5,5,4,4]), -2, 1) - sage: integer_list.rightmost_pivot([3,3,3,2,1,1,0,0,0], 9, 9,f([3,3,3,2,1,1,0,0,0]), f([7,6,5,5,5,5,5,4,4]), -2, 1) - sage: g = lambda x: lambda i: x - sage: integer_list.rightmost_pivot([1],1,1,g(0),g(2),-10, 10) - sage: integer_list.rightmost_pivot([1,2],2,2,g(0),g(2),-10, 10) - sage: integer_list.rightmost_pivot([1,2],2,2,g(1),g(2), -10, 10) - sage: integer_list.rightmost_pivot([1,2],2,3,g(1),g(2), -10, 10) - [2, 1] - sage: integer_list.rightmost_pivot([2,2],2,3,g(2),g(2),-10, 10) - sage: integer_list.rightmost_pivot([2,3],2,3,g(2),g(2),-10,+10) - sage: integer_list.rightmost_pivot([3,2],2,3,g(2),g(2),-10,+10) - sage: integer_list.rightmost_pivot([3,3],2,3,g(2),g(2),-10,+10) - [1, 2] - sage: integer_list.rightmost_pivot([6],1,3,g(0),g(6),-1,0) - [1, 0] - sage: integer_list.rightmost_pivot([6],1,3,g(0),g(6),-2,0) - [1, 0] - sage: integer_list.rightmost_pivot([7,9,8,7],1,5,g(0),g(10),-1,10) - [2, 6] - sage: integer_list.rightmost_pivot([7,9,8,7],1,5,g(5),g(10),-10,10) - [3, 5] - sage: integer_list.rightmost_pivot([7,9,8,7],1,5,g(5),g(10),-1,10) - [2, 6] - sage: integer_list.rightmost_pivot([7,9,8,7],1,5,g(4),g(10),-2,10) - [3, 7] - sage: integer_list.rightmost_pivot([9,8,7],1,4,g(4),g(10),-2,0) - [1, 4] - sage: integer_list.rightmost_pivot([1,3],1,5,lambda i: i,g(10),-10,10) - sage: integer_list.rightmost_pivot([1,4],1,5,lambda i: i,g(10),-10,10) - sage: integer_list.rightmost_pivot([2,4],1,5,lambda i: i,g(10),-10,10) - [1, 1] - """ - if max_slope < min_slope: - return None - - x = len(comp) - if x == 0: - return None - - y = len(comp) + 1 - while y <= max_length: - if ceiling(y) > 0: - break - if max_slope <= 0: - y = max_length + 1 - break - y += 1 - - ceilingx_x = comp[x - 1]-1 - floorx_x = floor(x) - if x > 1: - floorx_x = max(floorx_x, comp[x - 2] + min_slope) - - F = comp[x - 1] - floorx_x - G = ceilingx_x - comp[x - 1] # this is -1 - - highX = x - lowX = x - - while not (ceilingx_x >= floorx_x and - (G >= 0 or - (y < max_length + 1 and - F - max(floor(y), floorx_x + (y - x) * min_slope) >= 0 and - G + min(ceiling(y), ceilingx_x + (y - x) * max_slope) >= 0))): - - if x == 1: - return None - - x -= 1 - - oldfloorx_x = floorx_x - ceilingx_x = comp[x-1] - 1 - floorx_x = floor(x) - if x > 1: - floorx_x = max(floorx_x, comp[x-2] + min_slope) - - min_slope_lowX = min_slope * (lowX - x) - max_slope_highX = max_slope * (highX - x) - - # Update G - if max_slope == float('+inf'): - # In this case, we have - # -- ceiling_x(i) = ceiling(i) for i > x - # --G >= 0 or G = -1 - G += ceiling(x + 1) - comp[x] - else: - G += (highX - x) * ((comp[x-1] + max_slope) - comp[x]) - 1 - temp = (ceilingx_x + max_slope_highX) - ceiling(highX) - while highX > x and temp >= 0: - G -= temp - highX -= 1 - max_slope_highX = max_slope * (highX-x) - temp = (ceilingx_x + max_slope_highX) - ceiling(highX) - - if G >= 0 and comp[x-1] > floorx_x: - # By case 1, x is at the rightmost pivot position - break - - # Update F - if y < max_length+1: - F += comp[x-1] - floorx_x - if min_slope != float('-inf'): - F += (lowX - x) * (oldfloorx_x - (floorx_x + min_slope)) - temp = floor(lowX) - (floorx_x + min_slope_lowX) - while lowX > x and temp >= 0: - F -= temp - lowX -= 1 - min_slope_lowX = min_slope * (lowX-x) - temp = floor(lowX) - (floorx_x + min_slope_lowX) - - return [x, floorx_x] - - -def next(comp, min_length, max_length, floor, ceiling, min_slope, max_slope): - """ - Return the next integer list after ``comp`` that satisfies the - constraints. - - .. WARNING:: - - INTERNAL FUNCTION! DO NOT USE DIRECTLY! - - EXAMPLES:: - - sage: from sage.combinat.integer_list_old import next - sage: IV = sage.combinat.integer_list_old.IntegerListsLex(n=2,length=3,min_slope=0) - sage: next([0,1,1], 3, 3, lambda i: 0, lambda i: 5, 0, 10) - [0, 0, 2] - """ - stopgap("Next uses the old implementation of IntegerListsLex, which does not allow for arbitrary input;" - " non-allowed input can return wrong results," - " please see the documentation for IntegerListsLex for details.", - 17548) - x = rightmost_pivot(comp, min_length, max_length, floor, ceiling, min_slope, max_slope) - if x is None: - return None - [x, low] = x - high = comp[x-1] - 1 - -# // Build wrappers around floor and ceiling to take into -# // account the new constraints on the value of compo[x]. -# // -# // Efficiency note: they are not wrapped more than once, since -# // the method Next calls first, but not the converse. - - if min_slope == float('-inf'): - new_floor = lambda i: floor(x+(i-1)) - else: - new_floor = lambda i: max(floor(x+(i-1)), low+(i-1)*min_slope) - - if max_slope == float('+inf'): - new_ceiling = lambda i: comp[x-1] - 1 if i == 1 else ceiling(x+(i-1)) - else: - new_ceiling = lambda i: min(ceiling(x+(i-1)), high+(i-1)*max_slope) - - res = [] - res += comp[:x-1] - f = first(sum(comp[x-1:]), max(min_length-x+1, 0), max_length-x+1, - new_floor, new_ceiling, min_slope, max_slope) - if f is None: # Check to make sure it is valid - return None - res += f - return res - - -def iterator(n, min_length, max_length, floor, ceiling, min_slope, max_slope): - """ - .. WARNING:: - - INTERNAL FUNCTION! DO NOT USE DIRECTLY! - - EXAMPLES:: - - sage: from sage.combinat.integer_list_old import iterator - sage: IV = sage.combinat.integer_list_old.IntegerListsLex(n=2,length=3,min_slope=0) - sage: list(iterator(2, 3, 3, lambda i: 0, lambda i: 5, 0, 10)) - [[0, 1, 1], [0, 0, 2]] - """ - stopgap("Iterator uses the old implementation of IntegerListsLex, which does not allow for arbitrary input;" - " non-allowed input can return wrong results," - " please see the documentation for IntegerListsLex for details.", - 17548) - succ = lambda x: next(x, min_length, max_length, floor, ceiling, min_slope, max_slope) - - # Handle the case where n is a list of integers - if isinstance(n, list): - for i in range(n[0], min(n[1]+1, upper_bound(min_length, max_length, floor, ceiling, min_slope, max_slope))): - for el in iterator(i, min_length, max_length, floor, ceiling, min_slope, max_slope): - yield el - else: - f = first(n, min_length, max_length, floor, ceiling, min_slope, max_slope) - while f is not None: - yield f - f = succ(f) - - -def upper_regular(comp, min_slope, max_slope): - """ - Return the uppest regular composition above ``comp``. - - TESTS:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: integer_list.upper_regular([4,2,6],-1,1) - [4, 5, 6] - sage: integer_list.upper_regular([4,2,6],-2, 1) - [4, 5, 6] - sage: integer_list.upper_regular([4,2,6,3,7],-2, 1) - [4, 5, 6, 6, 7] - sage: integer_list.upper_regular([4,2,6,1], -2, 1) - [4, 5, 6, 4] - """ - - new_comp = comp[:] - for i in range(1, len(new_comp)): - new_comp[i] = max(new_comp[i], new_comp[i-1] + min_slope) - - for i in reversed(range(len(new_comp)-1)): - new_comp[i] = max(new_comp[i], new_comp[i+1] - max_slope) - - return new_comp - - -def comp2floor(f, min_slope, max_slope): - """ - Given a composition, returns the lowest regular function N->N above - it. - - EXAMPLES:: - - sage: from sage.combinat.integer_list_old import comp2floor - sage: f = comp2floor([2, 1, 1],-1,0) - sage: [f(i) for i in range(10)] - [2, 1, 1, 1, 2, 3, 4, 5, 6, 7] - """ - if not f: - return lambda i: 0 - floor = upper_regular(f, min_slope, max_slope) - return lambda i: floor[i] if i < len(floor) else max(0, floor[-1]-(i-len(floor))*min_slope) - - -def comp2ceil(c, min_slope, max_slope): - """ - Given a composition, return the lowest regular function N->N below it. - - EXAMPLES:: - - sage: from sage.combinat.integer_list_old import comp2ceil - sage: f = comp2ceil([2, 1, 1],-1,0) - sage: [f(i) for i in range(10)] - [2, 1, 1, 1, 2, 3, 4, 5, 6, 7] - """ - if not c: - return lambda i: 0 - ceil = lower_regular(c, min_slope, max_slope) - return lambda i: ceil[i] if i < len(ceil) else max(0, ceil[-1]-(i-len(ceil))*min_slope) - - -def upper_bound(min_length, max_length, floor, ceiling, min_slope, max_slope): - """ - Compute a coarse upper bound on the size of a vector satisfying the - constraints. - - TESTS:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: f = lambda x: lambda i: x - sage: integer_list.upper_bound(0,4,f(0), f(1),-infinity,infinity) - 4 - sage: integer_list.upper_bound(0, infinity, f(0), f(1), -infinity, infinity) - inf - sage: integer_list.upper_bound(0, infinity, f(0), f(1), -infinity, -1) - 1 - sage: integer_list.upper_bound(0, infinity, f(0), f(5), -infinity, -1) - 15 - sage: integer_list.upper_bound(0, infinity, f(0), f(5), -infinity, -2) - 9 - """ - from sage.functions.all import floor as flr - if max_length < float('inf'): - return sum([ceiling(j) for j in range(max_length)]) - elif max_slope < 0 and ceiling(1) < float('inf'): - maxl = flr(-ceiling(1) / max_slope) - return ceiling(1) * (maxl + 1) + binomial(maxl + 1, 2) * max_slope - # FIXME: only checking the first 10000 values, but that should generally - # be enough - elif [ceiling(j) for j in range(10000)] == [0] * 10000: - return 0 - else: - return float('inf') - - -def is_a(comp, min_length, max_length, floor, ceiling, min_slope, max_slope): - """ - Return ``True`` if ``comp`` meets the constraints imposed by the - arguments. - - .. WARNING:: - - INTERNAL FUNCTION! DO NOT USE DIRECTLY! - - EXAMPLES:: - - sage: from sage.combinat.integer_list_old import is_a - sage: IV = sage.combinat.integer_list_old.IntegerListsLex(n=2,length=3,min_slope=0) - sage: all(is_a(iv, 3, 3, lambda i: 0, lambda i: 5, 0, 10) for iv in IV) - True - """ - if not(min_length <= len(comp) <= max_length): - return False - for i in range(len(comp)): - if not(floor(i + 1) <= comp[i] <= ceiling(i + 1)): - return False - for i in range(len(comp) - 1): - slope = comp[i + 1] - comp[i] - if not(min_slope <= slope <= max_slope): - return False - return True - - -class IntegerListsLexElement(ClonableArray): - """ - Element class for :class:`IntegerListsLex`. - """ - def check(self): - """ - Check to make sure this is a valid element in its - :class:`IntegerListsLex` parent. - - .. TODO:: Placeholder. Implement a proper check. - - EXAMPLES:: - - sage: C = IntegerListsLex(4) - sage: C([4]).check() - True - """ - return True - - -class IntegerListsLex(Parent): - r""" - A combinatorial class `C` for integer lists satisfying certain - sum, length, upper/lower bound and regularity constraints. The - purpose of this tool is mostly to provide a Constant Amortized - Time iterator through those lists, in lexicographic order. - - INPUT: - - - ``n`` -- a non negative integer - - ``min_length`` -- a non negative integer - - ``max_length`` -- an integer or `\infty` - - ``length`` -- an integer; overrides min_length and max_length if - specified - - ``min_part`` -- the minimum value of each part; defaults to ``0`` - - ``max_part`` -- the maximum value of each part; defaults to `+\infty` - - ``floor`` -- a function `f` (or list); defaults to - ``lambda i: min_part`` - - ``ceiling`` -- a function `f` (or list); defaults to - ``lambda i: max_part`` - - ``min_slope`` -- an integer or `-\infty`; defaults to `-\infty` - - ``max_slope`` -- an integer or `+\infty`; defaults to `+\infty` - - An *integer list* is a list `l` of nonnegative integers, its - *parts*. The *length* of `l` is the number of its parts; - the *sum* of `l` is the sum of its parts. - - .. NOTE:: - - Two valid integer lists are considered equivalent if they only - differ by trailing zeroes. In this case, only the list with the - least number of trailing zeroes will be produced. - - The constraints on the lists are as follow: - - - Sum: `sum(l) == n` - - - Length: ``min_length <= len(l) <= max_length`` - - - Lower and upper bounds: ``floor(i) <= l[i] <= ceiling(i)``, for - ``i`` from 0 to ``len(l)`` - - - Regularity condition: ``minSlope <= l[i+1]-l[i] <= maxSlope``, - for ``i`` from 0 to ``len(l)-1`` - - This is a generic low level tool. The interface has been designed - with efficiency in mind. It is subject to incompatible changes in - the future. More user friendly interfaces are provided by high - level tools like :class:`Partitions` or :class:`Compositions`. - - EXAMPLES: - - We create the combinatorial class of lists of length 3 and sum 2:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(2, length=3) - sage: C - Integer lists of sum 2 satisfying certain constraints - sage: C.cardinality() - 6 - sage: [p for p in C] - [[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]] - - sage: [2, 0, 0] in C - True - sage: [2, 0, 1] in C - False - sage: "a" in C - False - sage: ["a"] in C - False - - sage: C.first() - [2, 0, 0] - - One can specify lower and upper bound on each part:: - - sage: list(integer_list.IntegerListsLex(5, length = 3, floor = [1,2,0], ceiling = [3,2,3])) - [[3, 2, 0], [2, 2, 1], [1, 2, 2]] - - Using the slope condition, one can generate integer partitions - (but see :mod:`sage.combinat.partition.Partitions`):: - - sage: list(integer_list.IntegerListsLex(4, max_slope=0)) - [[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]] - - This is the list of all partitions of `7` with parts at least `2`:: - - sage: list(integer_list.IntegerListsLex(7, max_slope = 0, min_part = 2)) - [[7], [5, 2], [4, 3], [3, 2, 2]] - - This is the list of all partitions of `5` and length at most 3 - which are bounded below by [2,1,1]:: - - sage: list(integer_list.IntegerListsLex(5, max_slope = 0, max_length = 3, floor = [2,1,1])) - [[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1]] - - Note that ``[5]`` is considered valid, because the lower bound - constraint only apply to existing positions in the list. To - obtain instead the partitions containing ``[2,1,1]``, one need to - use ``min_length``:: - - sage: list(integer_list.IntegerListsLex(5, max_slope = 0, min_length = 3, max_length = 3, floor = [2,1,1])) - [[3, 1, 1], [2, 2, 1]] - - This is the list of all partitions of `5` which are contained in - ``[3,2,2]``:: - - sage: list(integer_list.IntegerListsLex(5, max_slope = 0, max_length = 3, ceiling = [3,2,2])) - [[3, 2], [3, 1, 1], [2, 2, 1]] - - This is the list of all compositions of `4` (but see Compositions):: - - sage: list(integer_list.IntegerListsLex(4, min_part = 1)) - [[4], [3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]] - - This is the list of all integer vectors of sum `4` and length `3`:: - - sage: list(integer_list.IntegerListsLex(4, length = 3)) - [[4, 0, 0], [3, 1, 0], [3, 0, 1], [2, 2, 0], [2, 1, 1], - [2, 0, 2], [1, 3, 0], [1, 2, 1], [1, 1, 2], [1, 0, 3], - [0, 4, 0], [0, 3, 1], [0, 2, 2], [0, 1, 3], [0, 0, 4]] - - There are all the lists of sum 4 and length 4 such that l[i] <= i:: - - sage: list(integer_list.IntegerListsLex(4, length=4, ceiling=lambda i: i)) - [[0, 1, 2, 1], [0, 1, 1, 2], [0, 1, 0, 3], [0, 0, 2, 2], [0, 0, 1, 3]] - - This is the list of all monomials of degree `4` which divide the - monomial `x^3y^1z^2` (a monomial being identified with its - exponent vector):: - - sage: R. = QQ[] - sage: m = [3,1,2] - sage: def term(exponents): - ....: return x^exponents[0] * y^exponents[1] * z^exponents[2] - sage: list( integer_list.IntegerListsLex(4, length = len(m), ceiling = m, element_constructor = term) ) - [x^3*y, x^3*z, x^2*y*z, x^2*z^2, x*y*z^2] - - Note the use of the element_constructor feature. - - In general, the complexity of the iteration algorithm is constant - time amortized for each integer list produced. There is one - degenerate case though where the algorithm may run forever without - producing anything. If max_length is `+\infty` and max_slope `>0`, - testing whether there exists a valid integer list of sum `n` may - be only semi-decidable. In the following example, the algorithm - will enter an infinite loop, because it needs to decide whether - `ceiling(i)` is nonzero for some `i`:: - - sage: list( integer_list.IntegerListsLex(1, ceiling = lambda i: 0) ) # todo: not implemented - - .. NOTE:: - - Caveat: counting is done by brute force generation. In some - special cases, it would be possible to do better by counting - techniques for integral point in polytopes. - - .. NOTE:: - - Caveat: with the current implementation, the constraints should - satisfy the following conditions: - - - The upper and lower bounds themselves should satisfy the - slope constraints. - - - The maximal and minimal part values should not be equal. - - Those conditions are not always checked by the algorithm, and the - result may be completely incorrect if they are not satisfied: - - In the following example, the floor conditions do not satisfy the - slope conditions since the floor for the third part is also 3:: - - sage: I = integer_list.IntegerListsLex(16, min_length=2, min_part=3, max_slope=-1, floor=[5,3]) - Traceback (most recent call last): - ... - ValueError: floor does not satisfy the max slope condition - - Compare this with the following input, which is equivalent - but it bypasses the checks because the floor is a function:: - - sage: f = lambda x: 5 if x == 0 else 3 - sage: I = integer_list.IntegerListsLex(16, min_length=2, max_slope=-1, floor=f) - sage: list(I) - [[13, 3], [12, 4], [11, 5], [10, 6]] - - With some work, this could be fixed without affecting the overall - complexity and efficiency. Also, the generation algorithm could be - extended to deal with non-constant slope constraints and with - negative parts, as well as to accept a range parameter instead of - a single integer for the sum `n` of the lists (the later was - readily implemented in MuPAD-Combinat). Encouragements, - suggestions, and help are welcome. - - .. TODO:: - - Integrate all remaining tests from - http://mupad-combinat.svn.sourceforge.net/viewvc/mupad-combinat/trunk/MuPAD-Combinat/lib/COMBINAT/TEST/MachineIntegerListsLex.tst - - TESTS:: - - sage: g = lambda x: lambda i: x - sage: list(integer_list.IntegerListsLex(0, floor = g(1), min_slope = 0)) - [[]] - sage: list(integer_list.IntegerListsLex(0, floor = g(1), min_slope = 0, max_slope = 0)) - [[]] - sage: list(integer_list.IntegerListsLex(0, max_length=0, floor = g(1), min_slope = 0, max_slope = 0)) - [[]] - sage: list(integer_list.IntegerListsLex(0, max_length=0, floor = g(0), min_slope = 0, max_slope = 0)) - [[]] - sage: list(integer_list.IntegerListsLex(0, min_part = 1, min_slope = 0)) - [[]] - sage: list(integer_list.IntegerListsLex(1, min_part = 1, min_slope = 0)) - [[1]] - sage: list(integer_list.IntegerListsLex(0, min_length = 1, min_part = 1, min_slope = 0)) - [] - sage: list(integer_list.IntegerListsLex(0, min_length = 1, min_slope = 0)) - [[0]] - sage: list(integer_list.IntegerListsLex(3, max_length=2, )) - [[3], [2, 1], [1, 2], [0, 3]] - sage: partitions = {"min_part": 1, "max_slope": 0} - sage: partitions_min_2 = {"floor": g(2), "max_slope": 0} - sage: compositions = {"min_part": 1} - sage: integer_vectors = lambda l: {"length": l} - sage: lower_monomials = lambda c: {"length": c, "floor": lambda i: c[i]} - sage: upper_monomials = lambda c: {"length": c, "ceiling": lambda i: c[i]} - sage: constraints = { "min_part":1, "min_slope": -1, "max_slope": 0} - sage: list(integer_list.IntegerListsLex(6, **partitions)) - [[6], - [5, 1], - [4, 2], - [4, 1, 1], - [3, 3], - [3, 2, 1], - [3, 1, 1, 1], - [2, 2, 2], - [2, 2, 1, 1], - [2, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1]] - sage: list(integer_list.IntegerListsLex(6, **constraints)) - [[6], - [3, 3], - [3, 2, 1], - [2, 2, 2], - [2, 2, 1, 1], - [2, 1, 1, 1, 1], - [1, 1, 1, 1, 1, 1]] - sage: list(integer_list.IntegerListsLex(1, **partitions_min_2)) - [] - sage: list(integer_list.IntegerListsLex(2, **partitions_min_2)) - [[2]] - sage: list(integer_list.IntegerListsLex(3, **partitions_min_2)) - [[3]] - sage: list(integer_list.IntegerListsLex(4, **partitions_min_2)) - [[4], [2, 2]] - sage: list(integer_list.IntegerListsLex(5, **partitions_min_2)) - [[5], [3, 2]] - sage: list(integer_list.IntegerListsLex(6, **partitions_min_2)) - [[6], [4, 2], [3, 3], [2, 2, 2]] - sage: list(integer_list.IntegerListsLex(7, **partitions_min_2)) - [[7], [5, 2], [4, 3], [3, 2, 2]] - sage: list(integer_list.IntegerListsLex(9, **partitions_min_2)) - [[9], [7, 2], [6, 3], [5, 4], [5, 2, 2], [4, 3, 2], [3, 3, 3], [3, 2, 2, 2]] - sage: list(integer_list.IntegerListsLex(10, **partitions_min_2)) - [[10], - [8, 2], - [7, 3], - [6, 4], - [6, 2, 2], - [5, 5], - [5, 3, 2], - [4, 4, 2], - [4, 3, 3], - [4, 2, 2, 2], - [3, 3, 2, 2], - [2, 2, 2, 2, 2]] - sage: list(integer_list.IntegerListsLex(4, **compositions)) - [[4], [3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]] - sage: list(integer_list.IntegerListsLex(6, min_length=1, floor=[7])) - [] - - Noted on :trac:`17898`:: - - sage: list(integer_list.IntegerListsLex(4, min_part=1, length=3, min_slope=1)) - [] - sage: integer_list.IntegerListsLex(6, ceiling=[4,2], floor=[3,3]).list() - [] - sage: integer_list.IntegerListsLex(6, min_part=1, max_part=3, max_slope=-4).list() - [] - """ - def __init__(self, - n, - length = None, min_length=0, max_length=float('+inf'), - floor=None, ceiling = None, - min_part = 0, max_part = float('+inf'), - min_slope=float('-inf'), max_slope=float('+inf'), - name = None, - element_constructor = None, - element_class = None, - global_options = None): - """ - Initialize ``self``. - - TESTS:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(2, length=3) - sage: C == loads(dumps(C)) - True - sage: C == loads(dumps(C)) # this did fail at some point, really! - True - sage: C is loads(dumps(C)) # todo: not implemented - True - sage: C.cardinality().parent() is ZZ - True - sage: TestSuite(C).run() - """ - stopgap("The old implementation of IntegerListsLex does not allow for arbitrary input;" - " non-allowed input can return wrong results," - " please see the documentation for IntegerListsLex for details.", - 17548) - # Convert to float infinity - from sage.rings.infinity import infinity - if max_slope == infinity: - max_slope = float('+inf') - if min_slope == -infinity: - min_slope = float('-inf') - if max_length == infinity: - max_length = float('inf') - if max_part == infinity: - max_part = float('+inf') - - if floor is None: - self.floor_list = [] - else: - try: - # Is ``floor`` an iterable? - # Not ``floor[:]`` because we want ``self.floor_list`` - # mutable, and applying [:] to a tuple gives a tuple. - self.floor_list = list(floor) - # Make sure the floor list will make the list satisfy the constraints - if min_slope != float('-inf'): - for i in range(1, len(self.floor_list)): - self.floor_list[i] = max(self.floor_list[i], self.floor_list[i-1] + min_slope) - - # Some input checking - for i in range(1, len(self.floor_list)): - if self.floor_list[i] - self.floor_list[i-1] > max_slope: - raise ValueError("floor does not satisfy the max slope condition") - if self.floor_list and min_part - self.floor_list[-1] > max_slope: - raise ValueError("floor does not satisfy the max slope condition") - except TypeError: - self.floor = floor - if ceiling is None: - self.ceiling_list = [] - else: - try: - # Is ``ceiling`` an iterable? - self.ceiling_list = list(ceiling) - # Make sure the ceiling list will make the list satisfy the constraints - if max_slope != float('+inf'): - for i in range(1, len(self.ceiling_list)): - self.ceiling_list[i] = min(self.ceiling_list[i], self.ceiling_list[i-1] + max_slope) - - # Some input checking - for i in range(1, len(self.ceiling_list)): - if self.ceiling_list[i] - self.ceiling_list[i-1] < min_slope: - raise ValueError("ceiling does not satisfy the min slope condition") - if self.ceiling_list and max_part - self.ceiling_list[-1] < min_slope: - raise ValueError("ceiling does not satisfy the min slope condition") - except TypeError: - # ``ceiling`` is not an iterable. - self.ceiling = ceiling - if name is not None: - self.rename(name) - if n in ZZ: - self.n = n - self.n_range = [n] - else: - self.n_range = n - if length is not None: - min_length = length - max_length = length - self.min_length = min_length - self.max_length = max_length - self.min_part = min_part - self.max_part = max_part - # FIXME: the internal functions currently assume that floor and ceiling start at 1 - # this is a workaround - self.max_slope = max_slope - self.min_slope = min_slope - if element_constructor is not None: - self._element_constructor_ = element_constructor - if element_class is not None: - self.Element = element_class - if global_options is not None: - self.global_options = global_options - Parent.__init__(self, category=FiniteEnumeratedSets()) - - Element = IntegerListsLexElement - - def _element_constructor_(self, lst): - """ - Construct an element with ``self`` as parent. - - EXAMPLES:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(4) - sage: C([4]) - [4] - """ - return self.element_class(self, lst) - - def __eq__(self, x): - """ - Compare two different :class:`IntegerListsLex`. - - For now, the comparison is done just on their repr's which is - not robust! - - EXAMPLES:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(2, length=3) - sage: D = integer_list.IntegerListsLex(4, length=3) - sage: repr(C) == repr(D) - False - sage: C == D - False - """ - return repr(self) == repr(x) - - def __ne__(self, other): - """ - Compare two different :class:`IntegerListsLex`. - - For now, the comparison is done just on their repr's which is - not robust! - - EXAMPLES:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(2, length=3) - sage: D = integer_list.IntegerListsLex(4, length=3) - sage: C != D - True - """ - return not self.__eq__(other) - - def __hash__(self): - """ - Compute a hash for ``self``. - - EXAMPLES:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(2, length=3) - sage: h = hash(C) - """ - return hash(repr(self)) ^ 53397379531 - - def _repr_(self): - """ - Return the name of this combinatorial class. - - EXAMPLES:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(2, length=3) - sage: C # indirect doctest - Integer lists of sum 2 satisfying certain constraints - - sage: C = integer_list.IntegerListsLex([1,2,4], length=3) - sage: C # indirect doctest - Integer lists of sum in [1, 2, 4] satisfying certain constraints - - sage: C = integer_list.IntegerListsLex([1,2,4], length=3, name="A given name") - sage: C - A given name - """ - if hasattr(self, "n"): - return "Integer lists of sum %s satisfying certain constraints" % self.n - - return "Integer lists of sum in %s satisfying certain constraints" % self.n_range - - def floor(self, i): - """ - Return the minimum part that can appear at the `i^{th}` position of - any list produced. - - EXAMPLES:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(4, length=2, min_part=1) - sage: C.floor(0) - 1 - sage: C = integer_list.IntegerListsLex(4, length=2, floor=[1,2]) - sage: C.floor(0) - 1 - sage: C.floor(1) - 2 - """ - if i < len(self.floor_list): - return max(self.min_part, self.floor_list[i]) - if self.min_slope != float('-inf') and self.min_slope > 0: - return self.min_part + (i - len(self.floor_list)) * self.min_slope - return self.min_part - - def ceiling(self, i): - """ - Return the maximum part that can appear in the `i^{th}` - position in any list produced. - - EXAMPLES:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(4, length=2, max_part=3) - sage: C.ceiling(0) - 3 - sage: C = integer_list.IntegerListsLex(4, length=2, ceiling=[3,2]) - sage: C.ceiling(0) - 3 - sage: C.ceiling(1) - 2 - """ - if i < len(self.ceiling_list): - return min(self.max_part, self.ceiling_list[i]) - if self.max_slope != float('inf') and self.max_slope < 0: - return self.max_part + (i - len(self.ceiling_list)) * self.max_slope - return self.max_part - - # Temporary adapter to use the preexisting list/iterator/is_a function above. - # FIXME: fix their specs so that floor and ceiling start from 0 instead of 1... - # FIXME: integrate them as methods of this class - def build_args(self): - """ - Return a list of arguments that can be passed into the pre-existing - ``first``, ``next``, ``is_a``, ... functions in this module. - - ``n`` is currently not included in this list. - - EXAMPLES:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(2, length=3) - sage: C.build_args() - [3, - 3, - at 0x...>, - at 0x...>, - -inf, - inf] - """ - return [self.min_length, self.max_length, - lambda i: self.floor(i - 1), lambda i: self.ceiling(i - 1), - self.min_slope, self.max_slope] - - def first(self): - """ - Return the lexicographically maximal element in ``self``. - - EXAMPLES:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(2, length=3) - sage: C.first() - [2, 0, 0] - """ - # Make sure we have a valid return - f = first(self.n_range[0], *(self.build_args())) - if f is None: - return None - return self._element_constructor_(f) - - def __iter__(self): - """ - Return an iterator for the elements of ``self``. - - EXAMPLES:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(2, length=3) - sage: list(C) #indirect doctest - [[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]] - """ - args = self.build_args() - for n in self.n_range: - l = first(n, *args) - while l is not None: - yield self._element_constructor_(l) - l = next(l, *args) - - def count(self): - """ - Default brute force implementation of count by iteration - through all the objects. - - Note that this skips the call to ``_element_constructor_``, - unlike the default implementation. - - .. TODO:: - - Do the iteration in place to save on copying time - - EXAMPLES:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(2, length=3) - sage: C.cardinality() == C.count() - True - """ - args = self.build_args() - c = ZZ(0) - for n in self.n_range: - l = first(n, *args) - while l is not None: - c += 1 - l = next(l, *args) - return c - - def __contains__(self, v): - """ - Return ``True`` if and only if ``v`` is in ``self``. - - EXAMPLES:: - - sage: import sage.combinat.integer_list_old as integer_list - sage: C = integer_list.IntegerListsLex(2, length=3) - sage: [2, 0, 0] in C - True - sage: [2, 0] in C - False - sage: [3, 0, 0] in C - False - sage: all(v in C for v in C) - True - """ - if isinstance(v, (self.element_class, list)): - return is_a(v, *(self.build_args())) and sum(v) in self.n_range - return False From bfe5108094e6dc2e6b0dc9ad2e6d9dce76d206f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 13 Oct 2021 08:36:47 +0200 Subject: [PATCH 380/511] fix pycodestyle warnings again --- src/sage/combinat/posets/posets.py | 2 +- src/sage/combinat/words/morphic.py | 4 ++-- src/sage/tests/finite_poset.py | 8 ++++---- src/tox.ini | 3 ++- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 3c5b56dedf2..32b64020004 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -5693,7 +5693,7 @@ def lexicographic_sum(self, P): True """ # P might be defaultdict, hence the test - if type(P) == type({}): + if isinstance(P, dict): if set(P) != set(self): raise ValueError("keys of dict P does not match to elements of the poset") diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 3311872c50c..b6085868ee9 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -124,8 +124,8 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): self._morphism = morphism self._letter = letter self._alphabet = self._morphism.domain().alphabet() - if coding == None: - self._coding = {a:a for a in self._alphabet} + if coding is None: + self._coding = {a: a for a in self._alphabet} else: self._coding = coding diff --git a/src/sage/tests/finite_poset.py b/src/sage/tests/finite_poset.py index c4112cf9f95..56495b04492 100644 --- a/src/sage/tests/finite_poset.py +++ b/src/sage/tests/finite_poset.py @@ -209,7 +209,7 @@ def test_finite_lattice(L): p = "is_"+p_ if 'certificate' in sage_getargspec(getattr(L, p)).args: res = attrcall(p, certificate=True)(L) - if type(res) != type((1,2)) or len(res) != 2: + if not isinstance(res, tuple) or len(res) != 2: raise ValueError("certificate-option does not return a pair in %s" % p) if P[p_] != res[0]: raise ValueError("certificate-option changes result in %s" % p) @@ -609,11 +609,11 @@ def test_finite_poset(P): 'jump_critical', 'meet_semilattice', 'slender'] for p in bool_with_cert: try: # some properties are not always defined for all posets - res1 = attrcall('is_'+p)(P) + res1 = attrcall('is_' + p)(P) except ValueError: continue - res2 = attrcall('is_'+p, certificate=True)(P) - if type(res2) != type((1,2)) or len(res2) != 2: + res2 = attrcall('is_' + p, certificate=True)(P) + if not isinstance(res2, tuple) or len(res2) != 2: raise ValueError("certificate-option does not return a pair in %s" % p) if res1 != res2[0]: raise ValueError("certificate-option changes result in %s" % p) diff --git a/src/tox.ini b/src/tox.ini index 668483ce6a4..08abc70e5f6 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -83,9 +83,10 @@ description = # W605: invalid escape sequence ‘x’ # E711: comparison to None should be ‘if cond is None:’ # E712: comparison to True should be ‘if cond is True:’ or ‘if cond:’ + # E721: do not compare types, use isinstance() # See https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes deps = pycodestyle -commands = pycodestyle --select E401,E70,W605,E711,E712 {posargs:{toxinidir}/sage/} +commands = pycodestyle --select E401,E70,W605,E711,E712,E721 {posargs:{toxinidir}/sage/} [pycodestyle] max-line-length = 160 From fee15659e1d8b0de44b03564bb347d743c333f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 11 Oct 2021 20:56:07 +0200 Subject: [PATCH 381/511] using itertools.chain in abstact_tree + remove long doctest in ncsf --- src/sage/combinat/abstract_tree.py | 56 +++++++++++++---------------- src/sage/combinat/ncsf_qsym/ncsf.py | 2 -- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/src/sage/combinat/abstract_tree.py b/src/sage/combinat/abstract_tree.py index 90b278a05ef..65fec9cacdd 100644 --- a/src/sage/combinat/abstract_tree.py +++ b/src/sage/combinat/abstract_tree.py @@ -62,6 +62,7 @@ - Florent Hivert (2010-2011): initial revision - Frédéric Chapoton (2011): contributed some methods """ +import itertools from sage.structure.list_clone import ClonableArray from sage.rings.integer import Integer @@ -195,15 +196,8 @@ def pre_order_traversal_iter(self): if self.is_empty(): return yield self - # TODO:: PYTHON 3 - # import itertools - # yield from itertools.chain(map( - # lambda c: c.pre_order_traversal_iter(), - # self - # )) - for children in self: - for node in children.pre_order_traversal_iter(): - yield node + yield from itertools.chain(*[c.pre_order_traversal_iter() + for c in self]) def iterative_pre_order_traversal(self, action=None): r""" @@ -275,7 +269,8 @@ def iterative_pre_order_traversal(self, action=None): if self.is_empty(): return if action is None: - action = lambda x: None + def action(x): + return None stack = [] stack.append(self) while stack: @@ -390,7 +385,8 @@ def pre_order_traversal(self, action=None): 7 """ if action is None: - action = lambda x: None + def action(x): + return None for node in self.pre_order_traversal_iter(): action(node) @@ -484,15 +480,8 @@ def post_order_traversal_iter(self): """ if self.is_empty(): return - # TODO:: PYTHON 3 - # import itertools - # yield from itertools.chain(map( - # lambda c: c.post_order_traversal_iter(), - # self - # )) - for children in self: - for node in children.post_order_traversal_iter(): - yield node + yield from itertools.chain(*[c.post_order_traversal_iter() + for c in self]) yield self def post_order_traversal(self, action=None): @@ -563,7 +552,8 @@ def post_order_traversal(self, action=None): 7 """ if action is None: - action = lambda x: None + def action(x): + return None for node in self.post_order_traversal_iter(): action(node) @@ -638,7 +628,8 @@ def iterative_post_order_traversal(self, action=None): if self.is_empty(): return if action is None: - action = lambda x: None + def action(x): + return None stack = [self] while stack: node = stack[-1] @@ -725,7 +716,8 @@ def breadth_first_order_traversal(self, action=None): if self.is_empty(): return if action is None: - action = lambda x: None + def action(x): + return None queue = [] queue.append(self) while queue: @@ -1179,10 +1171,10 @@ def node_to_str(t): return t_repr if len(self) == 1: repr_child = self[0]._ascii_art_() - sep = AsciiArt([" "*(repr_child._root-1)]) + sep = AsciiArt([" " * (repr_child._root - 1)]) t_repr = AsciiArt([node_to_str(self)]) t_repr._root = 1 - repr_root = (sep + t_repr)*(sep + AsciiArt(["|"])) + repr_root = (sep + t_repr) * (sep + AsciiArt(["|"])) t_repr = repr_root * repr_child t_repr._root = repr_child._root t_repr._baseline = t_repr._h - 1 @@ -1190,9 +1182,9 @@ def node_to_str(t): # General case l_repr = [subtree._ascii_art_() for subtree in self] acc = l_repr.pop(0) - whitesep = acc._root+1 - lf_sep = " "*(acc._root+1) + "_"*(acc._l-acc._root) - ls_sep = " "*(acc._root) + "/" + " "*(acc._l-acc._root) + whitesep = acc._root + 1 + lf_sep = " " * (acc._root + 1) + "_" * (acc._l - acc._root) + ls_sep = " " * (acc._root) + "/" + " " * (acc._l - acc._root) while l_repr: t_repr = l_repr.pop(0) acc += AsciiArt([" "]) + t_repr @@ -1200,10 +1192,10 @@ def node_to_str(t): lf_sep += "_" * (t_repr._root + 1) else: lf_sep += "_" * (t_repr._l + 1) - ls_sep += " "*(t_repr._root) + "/" + " "*(t_repr._l-t_repr._root) + ls_sep += " " * (t_repr._root) + "/" + " " * (t_repr._l - t_repr._root) mid = whitesep + (len(lf_sep) - whitesep) // 2 node = node_to_str(self) - t_repr = AsciiArt([lf_sep[:mid-1] + node + lf_sep[mid+len(node)-1:], ls_sep]) * acc + t_repr = AsciiArt([lf_sep[:mid - 1] + node + lf_sep[mid + len(node) - 1:], ls_sep]) * acc t_repr._root = mid t_repr._baseline = t_repr._h - 1 return t_repr @@ -1485,7 +1477,7 @@ def _latex_(self): new_cmd4 = "$}\n;}" # some variables to simplify code sep = "\\&" - space = " "*9 + space = " " * 9 sepspace = sep + space spacesep = space + sep @@ -1952,7 +1944,7 @@ def __setitem_rec__(self, idx, i, value): self._setitem(idx[-1], value) else: with self[idx[i]].clone() as child: - child.__setitem_rec__(idx, i+1, value) + child.__setitem_rec__(idx, i + 1, value) self[idx[i]] = child def __getitem__(self, idx): diff --git a/src/sage/combinat/ncsf_qsym/ncsf.py b/src/sage/combinat/ncsf_qsym/ncsf.py index f145ecde76d..a746239b155 100644 --- a/src/sage/combinat/ncsf_qsym/ncsf.py +++ b/src/sage/combinat/ncsf_qsym/ncsf.py @@ -3795,8 +3795,6 @@ def internal_product_on_basis_by_bracketing(self, I, J): True sage: psi_int_test(4) # long time True - sage: psi_int_test(5) # long time - True """ # The algorithm used here is described in # :meth:`generic_basis_code.GradedModulesWithInternalProduct.ElementMethods.internal_product`. From 471b52f8221e93d19ceafaf922742dcc6ba5f86f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 13 Oct 2021 11:43:42 +0200 Subject: [PATCH 382/511] fix wrong change --- src/sage/symbolic/expression.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 1c084ee9dc2..3bb7e6a6fe3 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -13538,7 +13538,7 @@ cdef Expression new_Expression_from_GEx(parent, GEx juice): if is_exactly_a_function(juice): # if the function defines any dynamic methods these are made # available through a dynamic class - cls = get_dynamic_class_for_function(ex_to_function(juice).get_serial()) + cls = get_dynamic_class_for_function(ex_to_function(juice).get_serial()) else: cls = Expression From 8eb9c501163ce25d614203114112c693c6c750f8 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 13 Oct 2021 14:19:17 +0200 Subject: [PATCH 383/511] typo it's -> its --- 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 8efe2ee7f77..81908f634ae 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -3492,7 +3492,7 @@ def antisymmetric(self): True """ if not self._directed: - # An undirected graph is antisymmetric only if all it's edges are + # An undirected graph is antisymmetric only if all its edges are # loops return self.size() == len(self.loop_edges()) if self.has_loops(): @@ -23481,7 +23481,7 @@ def edge_polytope(self, backend=None): True The EP of a graph is isomorphic to the subdirect sum of - it's connected components EPs:: + its connected components EPs:: sage: n = randint(3, 6) sage: G1 = graphs.RandomGNP(n, 0.2) @@ -23583,7 +23583,7 @@ def symmetric_edge_polytope(self, backend=None): True The SEP of a graph is isomorphic to the subdirect sum of - it's connected components SEP's:: + its connected components SEP's:: sage: n = randint(3, 6) sage: G1 = graphs.RandomGNP(n, 0.2) From 3cfe23594c0962cd8ff76147462711a57087d79d Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 16 Sep 2021 10:47:01 +0200 Subject: [PATCH 384/511] implicitly fuzz RNG-dependent doctests --- src/bin/sage | 2 +- src/bin/sage-runtests | 4 +-- src/doc/en/developer/doctesting.rst | 28 ++++++++++++++++++- src/sage/arith/misc.py | 25 +++++++++++++---- src/sage/crypto/util.py | 2 ++ src/sage/doctest/control.py | 4 ++- src/sage/functions/exp_integral.py | 2 +- src/sage/functions/orthogonal_polys.py | 2 ++ src/sage/misc/misc.py | 2 ++ src/sage/modular/modform/numerical.py | 4 +-- src/sage/stats/hmm/chmm.pyx | 2 +- src/sage/symbolic/random_tests.py | 2 +- .../linalg_doctest.py | 2 ++ 13 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/bin/sage b/src/bin/sage index 8a5bfafd8e2..fcd263029d0 100755 --- a/src/bin/sage +++ b/src/bin/sage @@ -466,7 +466,7 @@ usage_advanced() { echo " labeled \"# optional\" or labeled" echo " \"# optional tag\" for any of the tags given." echo " --randorder[=seed] -- randomize order of tests" - echo " --random-seed[=seed] -- random seed for fuzzing doctests" + echo " --random-seed[=seed] -- random seed (integer) for fuzzing doctests" echo " --new -- only test files modified since last commit" echo " --initial -- only show the first failure per block" echo " --debug -- drop into PDB after an unexpected error" diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 16d3295b922..d1fe6567e74 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -65,7 +65,7 @@ if __name__ == "__main__": 'if "build" is listed, will also run tests specific to Sage\'s build/packaging system; ' 'if set to "all", then all tests will be run') parser.add_option("--randorder", type=int, metavar="SEED", help="randomize order of tests") - parser.add_option("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed for fuzzing doctests") + parser.add_option("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed (integer) for fuzzing doctests") parser.add_option("--global-iterations", "--global_iterations", type=int, default=0, help="repeat the whole testing process this many times") parser.add_option("--file-iterations", "--file_iterations", type=int, default=0, help="repeat each file this many times, stopping on the first failure") parser.add_option("--environment", type=str, default="sage.repl.ipython_kernel.all_jupyter", help="name of a module that provides the global environment for tests") @@ -132,7 +132,7 @@ if __name__ == "__main__": # Limit the number of threads to 2 to save system resources. # See Trac #23713, #23892, #30351 - if sys.platform == 'darwin': + if sys.platform == 'darwin': os.environ["OMP_NUM_THREADS"] = "1" else: os.environ["OMP_NUM_THREADS"] = "2" diff --git a/src/doc/en/developer/doctesting.rst b/src/doc/en/developer/doctesting.rst index f5fec4590f3..e26d7329095 100644 --- a/src/doc/en/developer/doctesting.rst +++ b/src/doc/en/developer/doctesting.rst @@ -803,7 +803,33 @@ You can also pass in an explicit amount of time:: Finally, you can disable any warnings about long tests with ``--warn-long 0``. -Doctests may start from a random seed:: +Doctests start from a random seed:: + + [kliem@sage sage-9.2]$ sage -t src/sage/doctest/tests/random_seed.rst + Running doctests with ID 2020-06-23-23-22-59-49f37a55. + ... + Doctesting 1 file. + sage -t --warn-long 89.5 --random-seed=112986622569797306072457879734474628454 src/sage/doctest/tests/random_seed.rst + ********************************************************************** + File "src/sage/doctest/tests/random_seed.rst", line 3, in sage.doctest.tests.random_seed + Failed example: + randint(5, 10) + Expected: + 9 + Got: + 8 + ********************************************************************** + 1 item had failures: + 1 of 2 in sage.doctest.tests.random_seed + [1 test, 1 failure, 0.00 s] + ---------------------------------------------------------------------- + sage -t --warn-long 89.5 --random-seed=112986622569797306072457879734474628454 src/sage/doctest/tests/random_seed.rst # 1 doctest failed + ---------------------------------------------------------------------- + Total time for all tests: 0.0 seconds + cpu time: 0.0 seconds + cumulative wall time: 0.0 seconds + +This seed can be set explicitly to reproduce possible failures:: [kliem@sage sage-9.2]$ sage -t --warn-long 89.5 --random-seed=112986622569797306072457879734474628454 src/sage/doctest/tests/random_seed.rst Running doctests with ID 2020-06-23-23-24-28-14a52269. diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 039e786aff7..ccf442967f3 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -5660,12 +5660,25 @@ def sort_complex_numbers_for_display(nums): ....: RDF.random_element())) sage: shuffle(nums) sage: nums = sort_c(nums) - sage: nums[:3] - [0.0, 1.0, 2.0] - sage: for i in range(3, len(nums)-1): - ....: assert nums[i].real() <= nums[i+1].real() + 1e-10 - ....: if abs(nums[i].real() - nums[i+1].real()) < 1e-10: - ....: assert nums[i].imag() <= nums[i+1].imag() + 1e-10 + sage: for i in range(len(nums)): + ....: if nums[i].imag(): + ....: first_non_real = i + ....: break + ....: else: + ....: first_non_real = len(nums) + sage: assert first_non_real >= 3 + sage: for i in range(first_non_real - 1): + ....: assert nums[i].real() <= nums[i + 1].real() + + sage: def truncate(n): + ....: if n.real() < 1e-10: + ....: return 0 + ....: else: + ....: return n.real().n(digits=9) + sage: for i in range(first_non_real, len(nums)-1): + ....: assert truncate(nums[i]) <= truncate(nums[i + 1]) + ....: if truncate(nums[i]) == truncate(nums[i + 1]): + ....: assert nums[i].imag() <= nums[i+1].imag() """ if not nums: return nums diff --git a/src/sage/crypto/util.py b/src/sage/crypto/util.py index 1d1e375e6cc..cb7b6a12138 100644 --- a/src/sage/crypto/util.py +++ b/src/sage/crypto/util.py @@ -334,6 +334,8 @@ def carmichael_lambda(n): ....: L = coprime(n) ....: return list(map(power_mod, L, [k]*len(L), [n]*len(L))) sage: def my_carmichael(n): + ....: if n == 1: + ....: return 1 ....: for k in range(1, n): ....: L = znpower(n, k) ....: ones = [1] * len(L) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index afb0d6cbcf1..8c8c91f2c00 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -28,6 +28,7 @@ import re import types import sage.misc.flatten +import sage.misc.randstate as randstate from sage.structure.sage_object import SageObject from sage.env import DOT_SAGE, SAGE_LIB, SAGE_SRC, SAGE_VENV, SAGE_EXTCODE from sage.misc.temporary_file import tmp_dir @@ -417,7 +418,8 @@ def __init__(self, options, args): self._init_warn_long() if self.options.random_seed is None: - self.options.random_seed = 0 + randstate.set_random_seed() + self.options.random_seed = randstate.initial_seed() def __del__(self): if getattr(self, 'logfile', None) is not None: diff --git a/src/sage/functions/exp_integral.py b/src/sage/functions/exp_integral.py index b20f7779f1a..21dcfa9f471 100644 --- a/src/sage/functions/exp_integral.py +++ b/src/sage/functions/exp_integral.py @@ -1497,7 +1497,7 @@ def exponential_integral_1(x, n=0): ....: n = 2^ZZ.random_element(14) ....: x = exponential_integral_1(a, n) ....: y = exponential_integral_1(S(a), n) - ....: c = RDF(2 * max(1.0, y[0])) + ....: c = RDF(4 * max(1.0, y[0])) ....: for i in range(n): ....: e = float(abs(S(x[i]) - y[i]) << prec) ....: if e >= c: diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 9b5636f3fdc..2a5ed971550 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -2084,6 +2084,8 @@ class Func_ultraspherical(GinacFunction): sage: _ = var('x') sage: for N in range(100): ....: n = ZZ.random_element().abs() + 5 + ....: if n > 5000: # avoid timeouts + ....: continue ....: a = QQ.random_element().abs() + 5 ....: assert ((n+1)*ultraspherical(n+1,a,x) - 2*x*(n+a)*ultraspherical(n,a,x) + (n+2*a-1)*ultraspherical(n-1,a,x)).expand().is_zero() sage: ultraspherical(5,9/10,3.1416) diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index efaa182f0d9..fbebd99b3a3 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -803,6 +803,8 @@ def __rmul__(self, left): EXAMPLES:: sage: A = random_matrix(ZZ, 4) + sage: while A.rank() != 4: + ....: A = random_matrix(ZZ, 4) sage: B = random_matrix(ZZ, 4) sage: temp = A * BackslashOperator() sage: temp.left is A diff --git a/src/sage/modular/modform/numerical.py b/src/sage/modular/modform/numerical.py index 0d467ef2c0b..f09aca90239 100644 --- a/src/sage/modular/modform/numerical.py +++ b/src/sage/modular/modform/numerical.py @@ -444,7 +444,7 @@ def systems_of_eigenvalues(self, bound): EXAMPLES:: - sage: numerical_eigenforms(61).systems_of_eigenvalues(10) # rel tol 1e-12 + sage: numerical_eigenforms(61).systems_of_eigenvalues(10) # rel tol 1e-11 [ [-1.4811943040920152, 0.8060634335253695, 3.1563251746586642, 0.6751308705666477], [-1.0, -2.0000000000000027, -3.000000000000003, 1.0000000000000044], @@ -471,7 +471,7 @@ def systems_of_abs(self, bound): EXAMPLES:: - sage: numerical_eigenforms(61).systems_of_abs(10) # rel tol 1e-12 + sage: numerical_eigenforms(61).systems_of_abs(10) # rel tol 1e-11 [ [0.3111078174659775, 2.903211925911551, 2.525427560843529, 3.214319743377552], [1.0, 2.0000000000000027, 3.000000000000003, 1.0000000000000044], diff --git a/src/sage/stats/hmm/chmm.pyx b/src/sage/stats/hmm/chmm.pyx index 0f9837745ad..6cc2d42adb3 100644 --- a/src/sage/stats/hmm/chmm.pyx +++ b/src/sage/stats/hmm/chmm.pyx @@ -903,7 +903,7 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): sage: m = hmm.GaussianHiddenMarkovModel([[.1,.9],[.5,.5]], [(1,.5), (-1,3)], [.1,.9]) sage: v = m.sample(10) sage: l = stats.TimeSeries([m.baum_welch(v,max_iter=1)[0] for _ in range(len(v))]) - sage: all(l[i] <= l[i+1] for i in range(9)) + sage: all(l[i] <= l[i+1] + 0.0001 for i in range(9)) True sage: l # random [-20.1167, -17.7611, -16.9814, -16.9364, -16.9314, -16.9309, -16.9309, -16.9309, -16.9309, -16.9309] diff --git a/src/sage/symbolic/random_tests.py b/src/sage/symbolic/random_tests.py index 9e50acd181b..35e6edcbb4b 100644 --- a/src/sage/symbolic/random_tests.py +++ b/src/sage/symbolic/random_tests.py @@ -426,7 +426,7 @@ def test_symbolic_expression_order(repetitions=100): sage: from sage.symbolic.random_tests import test_symbolic_expression_order sage: test_symbolic_expression_order(200) - sage: test_symbolic_expression_order(10000) # long time + sage: test_symbolic_expression_order(10000) # long time, # not tested, known bug (see :trac:`32185`) """ rnd_length = 50 nvars = 10 diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py index e3c78e66202..902b3c1aec2 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py @@ -269,6 +269,8 @@ sage: A = random_matrix(R,2,3); A # random [ 3*x^2 + x x^2 + 2*x 2*x^2 + 2] [ x^2 + x + 2 2*x^2 + 4*x + 3 x^2 + 4*x + 3] + sage: while A.rank() < 2: + ....: A = random_matrix(R,2,3) Sage example in ./linalg.tex, line 1830:: From 1980561fa6749e0ed70d944a6e9784422fd777f9 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 16 Sep 2021 10:54:31 +0200 Subject: [PATCH 385/511] reduce vertices for edge disjoint spanning trees --- src/sage/graphs/generic_graph.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 81908f634ae..a44d1aac6e6 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -6262,8 +6262,11 @@ def edge_disjoint_spanning_trees(self, k, root=None, solver=None, verbose=0): By Edmond's theorem, a graph which is `k`-connected always has `k` edge-disjoint arborescences, regardless of the root we pick:: - sage: g = digraphs.RandomDirectedGNP(28, .3) # reduced from 30 to 28, cf. #9584 + sage: g = digraphs.RandomDirectedGNP(11, .3) # reduced from 30 to 11, cf. #32169 sage: k = Integer(g.edge_connectivity()) + sage: while not k: + ....: g = digraphs.RandomDirectedGNP(28, .3) # + ....: k = Integer(g.edge_connectivity()) sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s on sage.math, 2011) sage: all(a.is_directed_acyclic() for a in arborescences) # long time True From e6dd0270513299c1c6ff813093510b88471c5695 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 16 Sep 2021 16:53:13 +0200 Subject: [PATCH 386/511] do not remove fixed doctest --- src/sage/symbolic/random_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/symbolic/random_tests.py b/src/sage/symbolic/random_tests.py index 35e6edcbb4b..9e50acd181b 100644 --- a/src/sage/symbolic/random_tests.py +++ b/src/sage/symbolic/random_tests.py @@ -426,7 +426,7 @@ def test_symbolic_expression_order(repetitions=100): sage: from sage.symbolic.random_tests import test_symbolic_expression_order sage: test_symbolic_expression_order(200) - sage: test_symbolic_expression_order(10000) # long time, # not tested, known bug (see :trac:`32185`) + sage: test_symbolic_expression_order(10000) # long time """ rnd_length = 50 nvars = 10 From 22c2b66adc903abae40e517d44a117dca2d41756 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 16 Sep 2021 16:53:21 +0200 Subject: [PATCH 387/511] simplify doctest --- src/sage/functions/orthogonal_polys.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 2a5ed971550..9a1078049b4 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -2083,9 +2083,7 @@ class Func_ultraspherical(GinacFunction): 32*t^3 - 12*t sage: _ = var('x') sage: for N in range(100): - ....: n = ZZ.random_element().abs() + 5 - ....: if n > 5000: # avoid timeouts - ....: continue + ....: n = ZZ.random_element(5, 5001) ....: a = QQ.random_element().abs() + 5 ....: assert ((n+1)*ultraspherical(n+1,a,x) - 2*x*(n+a)*ultraspherical(n,a,x) + (n+2*a-1)*ultraspherical(n-1,a,x)).expand().is_zero() sage: ultraspherical(5,9/10,3.1416) From e32986c1d5a0bede049a9023c8c651270e0dc43c Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 16 Sep 2021 17:20:17 +0200 Subject: [PATCH 388/511] fix unstable doctests --- src/sage/graphs/tutte_polynomial.py | 4 +++- src/sage/groups/perm_gps/permgroup_morphism.py | 9 ++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/tutte_polynomial.py b/src/sage/graphs/tutte_polynomial.py index f01a21437f9..297b1347481 100644 --- a/src/sage/graphs/tutte_polynomial.py +++ b/src/sage/graphs/tutte_polynomial.py @@ -544,10 +544,12 @@ def tutte_polynomial(G, edge_selector=None, cache=None): + 105*x^2*y^2 + 65*x*y^3 + 35*y^4 + 180*x^3 + 240*x^2*y + 171*x*y^2 + 75*y^3 + 120*x^2 + 168*x*y + 84*y^2 + 36*x + 36*y - The Tutte polynomial of `G` evaluated at (1,1) is the number of + The Tutte polynomial of a connected graph `G` evaluated at (1,1) is the number of spanning trees of `G`:: sage: G = graphs.RandomGNP(10,0.6) + sage: while not G.is_connected(): + ....: G = graphs.RandomGNP(10,0.6) sage: G.tutte_polynomial()(1,1) == G.spanning_trees_count() True diff --git a/src/sage/groups/perm_gps/permgroup_morphism.py b/src/sage/groups/perm_gps/permgroup_morphism.py index 29521593601..55ceb218817 100644 --- a/src/sage/groups/perm_gps/permgroup_morphism.py +++ b/src/sage/groups/perm_gps/permgroup_morphism.py @@ -117,11 +117,10 @@ def image(self, J): sage: G = L.galois_group() sage: D4 = DihedralGroup(4) sage: h = D4.isomorphism_to(G) - sage: h.image(D4) - Subgroup generated by [(1,2)(3,4)(5,7)(6,8), (1,6,4,7)(2,5,3,8)] of (Galois group 8T4 ([4]2) with order 8 of x^8 + 4*x^7 + 12*x^6 + 22*x^5 + 23*x^4 + 14*x^3 + 28*x^2 + 24*x + 16) - sage: r, s = D4.gens() - sage: h.image(r) - (1,6,4,7)(2,5,3,8) + sage: h.image(D4).is_isomorphic(G) + True + sage: all(h.image(g) in G for g in D4.gens()) + True """ H = self.codomain() if J in self.domain(): From 7b1bd36084abebcab724b9a0157b43e0394b5e85 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 17 Sep 2021 11:00:44 +0200 Subject: [PATCH 389/511] fixed some doctests for disjoint spanning trees --- src/sage/graphs/generic_graph.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index a44d1aac6e6..983f9c9bdc9 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -6265,7 +6265,7 @@ def edge_disjoint_spanning_trees(self, k, root=None, solver=None, verbose=0): sage: g = digraphs.RandomDirectedGNP(11, .3) # reduced from 30 to 11, cf. #32169 sage: k = Integer(g.edge_connectivity()) sage: while not k: - ....: g = digraphs.RandomDirectedGNP(28, .3) # + ....: g = digraphs.RandomDirectedGNP(11, .3) ....: k = Integer(g.edge_connectivity()) sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s on sage.math, 2011) sage: all(a.is_directed_acyclic() for a in arborescences) # long time @@ -6276,6 +6276,8 @@ def edge_disjoint_spanning_trees(self, k, root=None, solver=None, verbose=0): In the undirected case, we can only ensure half of it:: sage: g = graphs.RandomGNP(30, .3) + sage: while not g.is_connected(): + ....: g = graphs.RandomGNP(30, .3) sage: k = Integer(g.edge_connectivity()) // 2 sage: trees = g.edge_disjoint_spanning_trees(k) sage: all(t.is_tree() for t in trees) From 812b5559b06b4fb9ade7b325a83c1385ea24a58e Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 20 Sep 2021 09:11:51 +0200 Subject: [PATCH 390/511] fix unstable doctest in book_stein_ent --- src/sage/tests/book_stein_ent.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/tests/book_stein_ent.py b/src/sage/tests/book_stein_ent.py index cd6d4f7f179..5041f7ea4cf 100644 --- a/src/sage/tests/book_stein_ent.py +++ b/src/sage/tests/book_stein_ent.py @@ -267,8 +267,9 @@ ....: if g != 1 and g != n: ....: return g sage: n=32295194023343; e=29468811804857; d=11127763319273 -sage: crack_given_decrypt(n, e*d - 1) -737531 +sage: p = crack_given_decrypt(n, e*d - 1) +sage: p in (737531, n/737531) # could be other prime divisor +True sage: factor(n) 737531 * 43788253 sage: e = 22601762315966221465875845336488389513 From 74e505b8b769247b91482298aeebfa19fc64995b Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 4 Oct 2021 11:59:22 +0200 Subject: [PATCH 391/511] edge disjoint spanning tree not as fast as claimed, see #32169 --- 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 983f9c9bdc9..be2e927f40e 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -6262,7 +6262,7 @@ def edge_disjoint_spanning_trees(self, k, root=None, solver=None, verbose=0): By Edmond's theorem, a graph which is `k`-connected always has `k` edge-disjoint arborescences, regardless of the root we pick:: - sage: g = digraphs.RandomDirectedGNP(11, .3) # reduced from 30 to 11, cf. #32169 + sage: g = digraphs.RandomDirectedGNP(11, .3) # reduced from 30 to 11, cf. #32169 sage: k = Integer(g.edge_connectivity()) sage: while not k: ....: g = digraphs.RandomDirectedGNP(11, .3) @@ -6275,9 +6275,9 @@ def edge_disjoint_spanning_trees(self, k, root=None, solver=None, verbose=0): In the undirected case, we can only ensure half of it:: - sage: g = graphs.RandomGNP(30, .3) - sage: while not g.is_connected(): - ....: g = graphs.RandomGNP(30, .3) + sage: g = graphs.RandomGNP(14, .3) # reduced from 30 to 14, see #32169 + sage: while not g.is_biconnected(): + ....: g = graphs.RandomGNP(14, .3) sage: k = Integer(g.edge_connectivity()) // 2 sage: trees = g.edge_disjoint_spanning_trees(k) sage: all(t.is_tree() for t in trees) From 44cd7ae08c998e19b0e8d31c88c657a2993ff1ce Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 8 Oct 2021 09:49:35 +0200 Subject: [PATCH 392/511] fix doctest failure for random matrix --- src/sage/matrix/matrix0.pyx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix0.pyx b/src/sage/matrix/matrix0.pyx index 41b8da5f415..763a9c3d0c4 100644 --- a/src/sage/matrix/matrix0.pyx +++ b/src/sage/matrix/matrix0.pyx @@ -4830,7 +4830,10 @@ cdef class Matrix(sage.structure.element.Matrix): sage: B.multiplicative_order() 1 - sage: E = MatrixSpace(GF(11^2,'e'),5).random_element() + sage: M = MatrixSpace(GF(11^2,'e'),5) + sage: E = M.random_element() + sage: while E.det() == 0: + ....: E = M.random_element() sage: (E^E.multiplicative_order()).is_one() True From 2c478d1c375f10f4e6f7e95fcb71feff74d13653 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 8 Oct 2021 16:22:00 +0200 Subject: [PATCH 393/511] one more unstable doctest --- .../sol/graphique_doctest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/graphique_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/graphique_doctest.py index 95e7f328255..549f48e1b77 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/graphique_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/graphique_doctest.py @@ -42,7 +42,7 @@ sage: g = plot([c*e^(-1/x) for c in srange(-8, 8, 0.4)], (x, -3, 3)) sage: y = var('y') sage: g += plot_vector_field((x^2, y), (x,-3,3), (y,-5,5)) - sage: g.show() + sage: g.show() # not tested, known bug, see :trac:`32657` Sage example in ./sol/graphique.tex, line 124:: From a6c9428a04d5acb20e601cc367539816bcb24dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 13 Oct 2021 14:42:58 +0200 Subject: [PATCH 394/511] change : Ctrl-c pressed while running Axiom + : Ctrl-c pressed while running Axiom :: diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index 98e452513cf..514f02fccd4 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -1308,7 +1308,7 @@ def _parse_and_eval(s, start=0): sage: FriCASElement._parse_and_eval('(a "(b c)")') Traceback (most recent call last): ... - TypeError: cannot coerce arguments: no canonical coercion from to Symbolic Ring + TypeError: cannot coerce arguments: no canonical coercion from to Symbolic Ring """ a = start diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index 0a2fc56812a..8e0ff6843fb 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -856,7 +856,7 @@ def __float__(self): sage: float(giac(1/2)) 0.5 sage: type(_) - + """ return float(giac.eval('evalf(%s)' % self.name())) diff --git a/src/sage/interfaces/gp.py b/src/sage/interfaces/gp.py index 7a4c1b90603..48fe1a16158 100644 --- a/src/sage/interfaces/gp.py +++ b/src/sage/interfaces/gp.py @@ -913,7 +913,7 @@ def _sage_(self): sage: s.sage() 'foo' sage: type(s.sage()) - + """ if self.is_string(): return str(self) diff --git a/src/sage/interfaces/lie.py b/src/sage/interfaces/lie.py index deb16fdfe27..43c3ec3fdd2 100644 --- a/src/sage/interfaces/lie.py +++ b/src/sage/interfaces/lie.py @@ -209,7 +209,7 @@ sage: b = a.sage(); b # optional - lie 1234 sage: type(b) # optional - lie - + Vectors:: @@ -226,7 +226,7 @@ [1 2] [3 4] sage: type(b) # optional - lie - + Polynomials:: @@ -234,7 +234,7 @@ sage: b = a.sage(); b # optional - lie -2*x0^2*x1 + x0*x1^2 sage: type(b) # optional - lie - + Text:: diff --git a/src/sage/interfaces/maxima_abstract.py b/src/sage/interfaces/maxima_abstract.py index 3fe2dd7bbab..917059de0ab 100644 --- a/src/sage/interfaces/maxima_abstract.py +++ b/src/sage/interfaces/maxima_abstract.py @@ -1216,18 +1216,18 @@ def _sage_(self): sage: b = a._sage_(); b sqrt(2) + 2.5 sage: type(b) - + We illustrate an automatic coercion:: sage: c = b + sqrt(3); c sqrt(3) + sqrt(2) + 2.5 sage: type(c) - + sage: d = sqrt(3) + b; d sqrt(3) + sqrt(2) + 2.5 sage: type(d) - + sage: a = sage.calculus.calculus.maxima('x^(sqrt(y)+%pi) + sin(%e + %pi)') sage: a._sage_() diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index d9c0a90fb08..3a0fafaf4fa 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -1994,7 +1994,7 @@ def _sage_(self, R=None): sage: singular(5).sage() 5 sage: type(singular(int(5)).sage()) - + """ typ = self.type() diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index b4118ca9592..a9127b88da1 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -393,7 +393,7 @@ def parabolic_kazhdan_lusztig_polynomial(self, u, v, J, constant_term_one=True): sage: W = CoxeterGroup(['A', 3], implementation='coxeter3') # optional - coxeter3 sage: type(W.parabolic_kazhdan_lusztig_polynomial([2],[],[1])) # optional - coxeter3 - + """ u = self(u) v = self(v) diff --git a/src/sage/libs/ecl.pyx b/src/sage/libs/ecl.pyx index a0237505d91..85dc3d1e564 100644 --- a/src/sage/libs/ecl.pyx +++ b/src/sage/libs/ecl.pyx @@ -1296,7 +1296,7 @@ cdef class EclListIterator: sage: from sage.libs.ecl import * sage: I=EclListIterator(EclObject("(1 2 3)")) sage: type(I) - + sage: [i for i in I] [, , ] sage: [i for i in EclObject("(1 2 3)")] @@ -1318,7 +1318,7 @@ cdef class EclListIterator: sage: from sage.libs.ecl import * sage: I=EclListIterator(EclObject("(1 2 3)")) sage: type(I) - + """ if not o.listp(): diff --git a/src/sage/libs/eclib/homspace.pyx b/src/sage/libs/eclib/homspace.pyx index 900aa7834a9..d12f35dc82f 100644 --- a/src/sage/libs/eclib/homspace.pyx +++ b/src/sage/libs/eclib/homspace.pyx @@ -23,7 +23,7 @@ cdef class ModularSymbols: sage: M = CremonaModularSymbols(225) sage: type(M) - + """ def __init__(self, long level, int sign=0, bint cuspidal=False, int verbose=0): """ @@ -242,7 +242,7 @@ cdef class ModularSymbols: sage: M = CremonaModularSymbols(37) sage: t = M.sparse_hecke_matrix(2); type(t) - + sage: print(t) [ 3 0 0 0 0] [-1 -1 1 1 0] diff --git a/src/sage/libs/eclib/mat.pyx b/src/sage/libs/eclib/mat.pyx index d740a695654..2ad3474b221 100644 --- a/src/sage/libs/eclib/mat.pyx +++ b/src/sage/libs/eclib/mat.pyx @@ -21,7 +21,7 @@ cdef class Matrix: sage: M = CremonaModularSymbols(225) sage: t = M.hecke_matrix(2) sage: type(t) - + sage: t 61 x 61 Cremona matrix over Rational Field @@ -30,7 +30,7 @@ cdef class Matrix: sage: t = CremonaModularSymbols(11).hecke_matrix(2); t 3 x 3 Cremona matrix over Rational Field sage: type(t) - + """ def __repr__(self): """ @@ -204,12 +204,12 @@ cdef class Matrix: [ 0 1] [ 1 -1] sage: type(s) - + sage: s = t.sage_matrix_over_ZZ(sparse=False); s [ 0 1] [ 1 -1] sage: type(s) - + """ cdef long n = self.nrows() cdef long i, j, k diff --git a/src/sage/libs/eclib/mwrank.pyx b/src/sage/libs/eclib/mwrank.pyx index 2d10fd76180..0c20771d558 100644 --- a/src/sage/libs/eclib/mwrank.pyx +++ b/src/sage/libs/eclib/mwrank.pyx @@ -202,7 +202,7 @@ cdef class _bigint: sage: _bigint('123') 123 sage: type(_bigint(123)) - + """ s = str(x) if s.isdigit() or s[0] == "-" and s[1:].isdigit(): @@ -357,7 +357,7 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class sage: E.silverman_bound() 6.52226179519101... sage: type(E.silverman_bound()) - + """ return Curvedata_silverman_bound(self.x) @@ -570,7 +570,7 @@ cdef class _mw: sage: EQ [] sage: type(EQ) - + sage: E = _Curvedata(0,0,1,-7,6) sage: EQ = _mw(E) diff --git a/src/sage/libs/gap/libgap.pyx b/src/sage/libs/gap/libgap.pyx index 9f9f62be13a..6a9d4b2ceee 100644 --- a/src/sage/libs/gap/libgap.pyx +++ b/src/sage/libs/gap/libgap.pyx @@ -12,7 +12,7 @@ EXAMPLES:: sage: a 10 sage: type(a) - + sage: a*a 100 sage: timeit('a*a') # random output @@ -35,7 +35,7 @@ objects to GAP objects, for example strings to strings:: sage: libgap('List([1..10], i->i^2)') "List([1..10], i->i^2)" sage: type(_) - + You can usually use the :meth:`~sage.libs.gap.element.GapElement.sage` method to convert the resulting GAP element back to its Sage @@ -44,7 +44,7 @@ equivalent:: sage: a.sage() 10 sage: type(_) - + sage: libgap.eval('5/3 + 7*E(3)').sage() 7*zeta3 + 5/3 @@ -93,7 +93,7 @@ can be used as follows:: sage: lst = libgap([1,5,7]); lst [ 1, 5, 7 ] sage: type(lst) - + sage: len(lst) 3 sage: lst[0] @@ -101,7 +101,7 @@ can be used as follows:: sage: [ x^2 for x in lst ] [1, 25, 49] sage: type(_[0]) - + Note that you can access the elements of GAP ``List`` objects as you would expect from Python (with indexing starting at 0), but the @@ -637,7 +637,7 @@ class Gap(Parent): EXAMPLES:: sage: type(libgap) - + sage: type(libgap._get_object()) """ diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index abd6438744e..916b66f3bd1 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -1457,7 +1457,7 @@ cdef class Pygen(GiacMethods_base): sage: a=libgiac('10'); b=libgiac('2**300') sage: a;type(ZZ(a)) 10 - + sage: next_prime(b) 2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397533 sage: c=libgiac('2 % nextprime(2**40)') diff --git a/src/sage/libs/lcalc/lcalc_Lfunction.pyx b/src/sage/libs/lcalc/lcalc_Lfunction.pyx index 7e54d7e78d5..58deb827aa9 100644 --- a/src/sage/libs/lcalc/lcalc_Lfunction.pyx +++ b/src/sage/libs/lcalc/lcalc_Lfunction.pyx @@ -455,7 +455,7 @@ cdef class Lfunction_I(Lfunction): sage: chi = DirichletGroup(5)[2] #This is a quadratic character sage: L=Lfunction_from_character(chi, type="int") sage: type(L) - + """ Lfunction.__init__(self, name, what_type_L, dirichlet_coefficient, period, Q, OMEGA, gamma,lambd, pole,residue) self._repr += " with integer Dirichlet coefficients" @@ -591,7 +591,7 @@ cdef class Lfunction_D(Lfunction): sage: chi = DirichletGroup(5)[2] #This is a quadratic character sage: L=Lfunction_from_character(chi, type="double") sage: type(L) - + """ Lfunction.__init__(self, name, what_type_L, dirichlet_coefficient, period, Q, OMEGA, gamma,lambd, pole,residue) self._repr += " with real Dirichlet coefficients" @@ -731,7 +731,7 @@ cdef class Lfunction_C: sage: chi = DirichletGroup(5)[1] sage: L=Lfunction_from_character(chi, type="complex") sage: type(L) - + """ Lfunction.__init__(self, name, what_type_L, dirichlet_coefficient, period, Q, OMEGA, gamma,lambd, pole,residue) self._repr += " with complex Dirichlet coefficients" diff --git a/src/sage/libs/lrcalc/lrcalc.pyx b/src/sage/libs/lrcalc/lrcalc.pyx index 1cf67dc15ab..b591081ec4c 100644 --- a/src/sage/libs/lrcalc/lrcalc.pyx +++ b/src/sage/libs/lrcalc/lrcalc.pyx @@ -297,7 +297,7 @@ def test_skewtab_to_SkewTableau(outer, inner): cdef dict sf_hashtab_to_dict(hashtab *ht): """ Return a dictionary representing a Schur function. The keys are - partitions and the values are integers . + partitions and the values are integers . EXAMPLES:: @@ -320,7 +320,7 @@ cdef dict sf_hashtab_to_dict(hashtab *ht): cdef dict schubert_hashtab_to_dict(hashtab *ht): """ Return a dictionary corresponding to a Schubert polynomial whose keys - are permutations and whose values are integers . + are permutations and whose values are integers . EXAMPLES:: @@ -341,7 +341,7 @@ cdef dict schubert_hashtab_to_dict(hashtab *ht): cdef dict vp_hashtab_to_dict(hashtab *ht): """ Return a dictionary corresponding to the coproduct of a Schur function whose keys are - pairs of partitions and whose values are integers . + pairs of partitions and whose values are integers . EXAMPLES:: diff --git a/src/sage/libs/mpmath/ext_main.pyx b/src/sage/libs/mpmath/ext_main.pyx index 5821be79073..379971de1a3 100644 --- a/src/sage/libs/mpmath/ext_main.pyx +++ b/src/sage/libs/mpmath/ext_main.pyx @@ -1965,7 +1965,7 @@ cdef class mpf(mpf_base): sage: mpf(-500.5).man 1001 sage: type(_) - + """ return self._mpf_[1] diff --git a/src/sage/libs/mpmath/utils.pyx b/src/sage/libs/mpmath/utils.pyx index d6c9eeea75d..ea5aa54bfc8 100644 --- a/src/sage/libs/mpmath/utils.pyx +++ b/src/sage/libs/mpmath/utils.pyx @@ -402,11 +402,11 @@ def call(func, *args, **kwargs): sage: a.call(a.polylog, 2, 1/2, parent=CC) 0.582240526465012 sage: type(_) - + sage: a.call(a.polylog, 2, 1/2, parent=RDF) 0.5822405264650125 sage: type(_) - + Check that :trac:`11885` is fixed:: diff --git a/src/sage/libs/ntl/ntl_GF2.pyx b/src/sage/libs/ntl/ntl_GF2.pyx index 2a03e7723b4..b899f21548f 100644 --- a/src/sage/libs/ntl/ntl_GF2.pyx +++ b/src/sage/libs/ntl/ntl_GF2.pyx @@ -250,7 +250,7 @@ def unpickle_class_value(cls, x): sage: sage.libs.ntl.ntl_GF2.unpickle_class_value(ntl.GF2,1) 1 sage: type(sage.libs.ntl.ntl_GF2.unpickle_class_value(ntl.GF2,1)) - + """ return cls(x) @@ -263,7 +263,7 @@ def unpickle_class_args(cls, x): sage: sage.libs.ntl.ntl_GF2.unpickle_class_args(ntl.GF2,[1]) 1 sage: type(sage.libs.ntl.ntl_GF2.unpickle_class_args(ntl.GF2,[1])) - + """ return cls(*x) diff --git a/src/sage/libs/ntl/ntl_GF2E.pyx b/src/sage/libs/ntl/ntl_GF2E.pyx index 748449f9c25..252851d40ed 100644 --- a/src/sage/libs/ntl/ntl_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_GF2E.pyx @@ -403,7 +403,7 @@ cdef class ntl_GF2E(object): sage: a.rep() [1 0 0 0 0 0 1 1] sage: type(a.rep()) - + """ cdef ntl_GF2X x = ntl_GF2X.__new__(ntl_GF2X) x.x = GF2E_rep(self.x) diff --git a/src/sage/libs/ntl/ntl_ZZ.pyx b/src/sage/libs/ntl/ntl_ZZ.pyx index 16d04663efa..e132e997e01 100644 --- a/src/sage/libs/ntl/ntl_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_ZZ.pyx @@ -293,7 +293,7 @@ cdef class ntl_ZZ(object): sage: n=ntl.ZZ(2983) sage: type(n._integer_()) - + AUTHOR: Joel B. Mohler """ @@ -403,7 +403,7 @@ def unpickle_class_value(cls, x): sage: sage.libs.ntl.ntl_ZZ.unpickle_class_value(ntl.ZZ, 3) 3 sage: type(sage.libs.ntl.ntl_ZZ.unpickle_class_value(ntl.ZZ, 3)) - + """ return cls(x) @@ -416,7 +416,7 @@ def unpickle_class_args(cls, x): sage: sage.libs.ntl.ntl_ZZ.unpickle_class_args(ntl.ZZ, [3]) 3 sage: type(sage.libs.ntl.ntl_ZZ.unpickle_class_args(ntl.ZZ, [3])) - + """ return cls(*x) diff --git a/src/sage/libs/ntl/ntl_ZZX.pyx b/src/sage/libs/ntl/ntl_ZZX.pyx index 3aea4aca9fc..cee8c5422e6 100644 --- a/src/sage/libs/ntl/ntl_ZZX.pyx +++ b/src/sage/libs/ntl/ntl_ZZX.pyx @@ -226,7 +226,7 @@ cdef class ntl_ZZX(object): sage: x[0] 129381729371289371237128318293718237 sage: type(x[0]) - + sage: x[1] 2 sage: x[2] @@ -278,7 +278,7 @@ cdef class ntl_ZZX(object): sage: L = x.list(); L [129381729371289371237128318293718237, 2, -3, 0, 4] sage: type(L[0]) - + sage: x = ntl.ZZX() sage: L = x.list(); L [] diff --git a/src/sage/libs/ntl/ntl_ZZ_p.pyx b/src/sage/libs/ntl/ntl_ZZ_p.pyx index 4fab1d1a7cb..114963b1882 100644 --- a/src/sage/libs/ntl/ntl_ZZ_p.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_p.pyx @@ -414,7 +414,7 @@ cdef class ntl_ZZ_p(object): sage: x.lift() 8 sage: type(x.lift()) - + """ cdef ntl_ZZ r = ntl_ZZ() self.c.restore_c() @@ -452,12 +452,12 @@ cdef class ntl_ZZ_p(object): sage: x.lift_centered() 8 sage: type(x.lift_centered()) - + sage: x = ntl.ZZ_p(12, 18) sage: x.lift_centered() -6 sage: type(x.lift_centered()) - + """ cdef ntl_ZZ r = self.lift() cdef ntl_ZZ m = self.modulus() @@ -476,7 +476,7 @@ cdef class ntl_ZZ_p(object): 8 sage: type(x._integer_()) - + """ self.c.restore_c() cdef ZZ_c rep = ZZ_p_rep(self.x) @@ -493,7 +493,7 @@ cdef class ntl_ZZ_p(object): sage: c = ntl.ZZ_pContext(20) sage: n = ntl.ZZ_p(2983, c) sage: type(n._sage_()) - + sage: n 3 diff --git a/src/sage/libs/ntl/ntl_ZZ_pContext.pyx b/src/sage/libs/ntl/ntl_ZZ_pContext.pyx index 0c8995608fd..008e6abd8eb 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pContext.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pContext.pyx @@ -95,7 +95,7 @@ cdef class ntl_ZZ_pContext_class(object): sage: c = ntl.ZZ_pContext(10^30) sage: type(c.modulus()) - + sage: c.modulus() == 10^30 True """ diff --git a/src/sage/libs/ntl/ntl_ZZ_pE.pyx b/src/sage/libs/ntl/ntl_ZZ_pE.pyx index f46b28f95b5..c2802a3391b 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pE.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pE.pyx @@ -296,7 +296,7 @@ cdef class ntl_ZZ_pE(object): sage: i [9 1] sage: type(i) - + """ return self.get_as_ZZ_pX() @@ -350,6 +350,6 @@ def make_ZZ_pE(x, c): sage: sage.libs.ntl.ntl_ZZ_pE.make_ZZ_pE([4,3], c) [4 3] sage: type(sage.libs.ntl.ntl_ZZ_pE.make_ZZ_pE([4,3], c)) - + """ return ntl_ZZ_pE(x, c) diff --git a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx index 983bbbe826a..4d48f32025b 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx @@ -1251,6 +1251,6 @@ def make_ZZ_pEX(v, modulus): sage: sage.libs.ntl.ntl_ZZ_pEX.make_ZZ_pEX([a,b,b], c) [[3 2] [1 2] [1 2]] sage: type(sage.libs.ntl.ntl_ZZ_pEX.make_ZZ_pEX([a,b,b], c)) - + """ return ntl_ZZ_pEX(v, modulus) diff --git a/src/sage/libs/ntl/ntl_ZZ_pX.pyx b/src/sage/libs/ntl/ntl_ZZ_pX.pyx index d7fb124c62a..bd34a79c85c 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pX.pyx @@ -312,7 +312,7 @@ cdef class ntl_ZZ_pX(object): sage: x.list() [1, 3, 5] sage: type(x.list()[0]) - + """ # could be sped up. self.c.restore_c() diff --git a/src/sage/libs/ntl/ntl_mat_ZZ.pyx b/src/sage/libs/ntl/ntl_mat_ZZ.pyx index db14f86b71d..c9f054602e8 100644 --- a/src/sage/libs/ntl/ntl_mat_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_mat_ZZ.pyx @@ -453,7 +453,7 @@ cdef class ntl_mat_ZZ(object): sage: M.charpoly() [-2 -5 1] sage: type(_) - + sage: M.determinant() -2 """ diff --git a/src/sage/libs/pari/convert_sage.pyx b/src/sage/libs/pari/convert_sage.pyx index c8918beb653..62fe5185cfb 100644 --- a/src/sage/libs/pari/convert_sage.pyx +++ b/src/sage/libs/pari/convert_sage.pyx @@ -251,7 +251,7 @@ cpdef gen_to_sage(Gen z, locals=None): sage: s = pari('"foo"').sage(); s 'foo' sage: type(s) - + """ cdef GEN g = z.g cdef long t = typ(g) diff --git a/src/sage/libs/singular/ring.pyx b/src/sage/libs/singular/ring.pyx index 63b63070cd2..0ed2ff8e04a 100644 --- a/src/sage/libs/singular/ring.pyx +++ b/src/sage/libs/singular/ring.pyx @@ -422,7 +422,7 @@ cdef class ring_wrapper_Py(object): sage: from sage.libs.singular.ring import ring_wrapper_Py sage: ring_wrapper_Py - + """ cdef ring* _ring diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index c736d56b0c0..cba2147c0ab 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -58,7 +58,7 @@ cdef Rational si2sa_QQ(number *n, number **nn, ring *_ring): sage: P(-1/3).lc() -1/3 sage: type(P(3).lc()) - + """ cdef number *nom cdef number *denom @@ -115,7 +115,7 @@ cdef Integer si2sa_ZZ(number *n, ring *_ring): sage: P(-1234567890).lc() -1234567890 sage: type(P(3).lc()) - + """ cdef Integer z z = Integer() @@ -172,7 +172,7 @@ cdef FFgf2eE si2sa_GFqNTLGF2E(number *n, ring *_ring, Cache_ntl_gf2e cache): sage: f.lc() a^11 + a^10 + a^8 + a^7 + a^6 + a^5 + a^2 + a sage: type(f.lc()) - + """ cdef poly *z cdef long c @@ -207,7 +207,7 @@ cdef object si2sa_GFq_generic(number *n, ring *_ring, object base): sage: f.lc() a^12 + a^11 + a^9 + a^8 + a^7 + 2*a^6 + a^5 sage: type(f.lc()) - + Try the largest characteristic which Singular supports:: diff --git a/src/sage/manifolds/calculus_method.py b/src/sage/manifolds/calculus_method.py index e4d3919e67c..f5830c0bc45 100644 --- a/src/sage/manifolds/calculus_method.py +++ b/src/sage/manifolds/calculus_method.py @@ -52,7 +52,7 @@ def _SR_to_Sympy(expression): sage: a = x^2 + sin(x)^2; a x^2 + sin(x)^2 sage: type(a) - + sage: b = _SR_to_Sympy(a); b x**2 + sin(x)**2 sage: type(b) @@ -89,7 +89,7 @@ def _Sympy_to_SR(expression): sage: from sage.manifolds.calculus_method import _Sympy_to_SR, _SR_to_Sympy sage: a = x^2 + sin(x)^2 sage: type(a) - + sage: b = _SR_to_Sympy(a); b x**2 + sin(x)**2 sage: type(b) diff --git a/src/sage/manifolds/chart.py b/src/sage/manifolds/chart.py index e0630722d3e..8c4e2028aa6 100644 --- a/src/sage/manifolds/chart.py +++ b/src/sage/manifolds/chart.py @@ -206,7 +206,7 @@ class Chart(UniqueRepresentation, SageObject): :mod:`sage.symbolic.expression`):: sage: type(z1) - + In addition to the Python variable name provided in the operator ``<.,.>``, the coordinates are accessible by their indices:: @@ -1502,7 +1502,7 @@ def calculus_method(self): sage: f.expr() x^2 + cos(y)*sin(x) sage: type(f.expr()) - + sage: parent(f.expr()) Symbolic Ring sage: f.display() @@ -1733,7 +1733,7 @@ class RealChart(Chart): :mod:`sage.symbolic.expression`):: sage: type(th) - + sage: latex(th) {\theta} sage: assumptions(th) diff --git a/src/sage/manifolds/chart_func.py b/src/sage/manifolds/chart_func.py index 1c4bf0080c1..6ffc287ca09 100644 --- a/src/sage/manifolds/chart_func.py +++ b/src/sage/manifolds/chart_func.py @@ -134,7 +134,7 @@ class ChartFunction(AlgebraElement, ModuleElementWithMutability): expression:: sage: type(f.expr()) - + A SymPy expression can also be asked for:: @@ -207,7 +207,7 @@ class ChartFunction(AlgebraElement, ModuleElementWithMutability): sage: f0(x,y) = x^2 + 3*y + 1 sage: type(f0) - + sage: f0 (x, y) |--> x^2 + 3*y + 1 sage: f0(x,y) @@ -495,7 +495,7 @@ def expr(self, method=None): sage: f.expr() x^2 + y sage: type(f.expr()) - + Asking for the SymPy expression:: @@ -3057,7 +3057,7 @@ def expr(self, method=None): sage: f.expr() (x - y, x*y, cos(x)*e^y) sage: type(f.expr()[0]) - + A SymPy output:: diff --git a/src/sage/manifolds/continuous_map.py b/src/sage/manifolds/continuous_map.py index 6f060ca13b9..a6356e77f11 100644 --- a/src/sage/manifolds/continuous_map.py +++ b/src/sage/manifolds/continuous_map.py @@ -1503,7 +1503,7 @@ def expr(self, chart1=None, chart2=None): sage: Phi.expr() # equivalent to above since 'uv' and 'xyz' are default charts (u*v, u/v, u + v) sage: type(Phi.expr()[0]) - + Expressions in other charts:: diff --git a/src/sage/manifolds/differentiable/chart.py b/src/sage/manifolds/differentiable/chart.py index 47dd4efd2ec..86a39667cd8 100644 --- a/src/sage/manifolds/differentiable/chart.py +++ b/src/sage/manifolds/differentiable/chart.py @@ -198,7 +198,7 @@ class DiffChart(Chart): :mod:`sage.symbolic.expression`):: sage: type(z1) - + In addition to the Python variable name provided in the operator ``<.,.>``, the coordinates are accessible by their indices:: @@ -829,7 +829,7 @@ class RealDiffChart(DiffChart, RealChart): :mod:`sage.symbolic.expression`):: sage: type(th) - + sage: latex(th) {\theta} sage: assumptions(th) diff --git a/src/sage/manifolds/differentiable/diff_map.py b/src/sage/manifolds/differentiable/diff_map.py index fce91145ed5..7f0c09a6b7c 100644 --- a/src/sage/manifolds/differentiable/diff_map.py +++ b/src/sage/manifolds/differentiable/diff_map.py @@ -760,7 +760,7 @@ def differential_functions(self, chart1=None, chart2=None): sage: JJ[2,0] 2*x sage: type(JJ[2,0]) - + sage: bool( JJ[2,0] == J[2][0].expr() ) True diff --git a/src/sage/manifolds/differentiable/examples/euclidean.py b/src/sage/manifolds/differentiable/examples/euclidean.py index bedc6ece275..b0659787b0e 100644 --- a/src/sage/manifolds/differentiable/examples/euclidean.py +++ b/src/sage/manifolds/differentiable/examples/euclidean.py @@ -57,7 +57,7 @@ sage: y y sage: type(y) - + sage: assumptions() [x is real, y is real] diff --git a/src/sage/manifolds/differentiable/examples/real_line.py b/src/sage/manifolds/differentiable/examples/real_line.py index 09c38be8f8d..15b11a84dc1 100644 --- a/src/sage/manifolds/differentiable/examples/real_line.py +++ b/src/sage/manifolds/differentiable/examples/real_line.py @@ -123,7 +123,7 @@ class OpenInterval(DifferentiableManifold): t sage: t = I.canonical_coordinate() sage: type(t) - + However, it can be obtained in the same step as the interval construction by means of the shortcut ``I.``:: @@ -132,7 +132,7 @@ class OpenInterval(DifferentiableManifold): sage: t t sage: type(t) - + The trick is performed by the Sage preparser:: @@ -577,7 +577,7 @@ def canonical_coordinate(self): sage: I.canonical_coordinate() t sage: type(I.canonical_coordinate()) - + sage: I.canonical_coordinate().is_real() True @@ -777,7 +777,7 @@ class RealLine(OpenInterval): t sage: t = R.canonical_coordinate() sage: type(t) - + However, it can be obtained in the same step as the real line construction by means of the shortcut ``R.``:: @@ -786,7 +786,7 @@ class RealLine(OpenInterval): sage: t t sage: type(t) - + The trick is performed by Sage preparser:: diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index 7766ebb6543..659c84b2d0c 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -70,7 +70,7 @@ sage: y y sage: type(y) - + The South pole is the point of coordinates `(x,y)=(0,0)` in the above chart:: diff --git a/src/sage/manifolds/differentiable/scalarfield.py b/src/sage/manifolds/differentiable/scalarfield.py index 5885f1fb624..ba66d50ad20 100644 --- a/src/sage/manifolds/differentiable/scalarfield.py +++ b/src/sage/manifolds/differentiable/scalarfield.py @@ -209,7 +209,7 @@ class DiffScalarField(ScalarField): sage: f.expr(c_uv) (u^2 + v^2)/(u^2 + v^2 + 1) sage: type(f.expr(c_uv)) - + The method :meth:`~sage.manifolds.scalarfield.ScalarField.coord_function` returns instead a function of the chart coordinates, i.e. an instance of diff --git a/src/sage/manifolds/manifold.py b/src/sage/manifolds/manifold.py index 2645de657c9..1b62341fc84 100644 --- a/src/sage/manifolds/manifold.py +++ b/src/sage/manifolds/manifold.py @@ -60,7 +60,7 @@ sage: y y sage: type(y) - + The South pole is the point of coordinates `(x, y) = (0, 0)` in the above chart:: @@ -1550,7 +1550,7 @@ def chart(self, coordinates='', names=None, calc_method=None, sage: y y sage: type(y) - + But a shorter way to proceed is to use the operator ``<,>`` in the left-hand side of the chart declaration (there is then no need to @@ -2511,7 +2511,7 @@ def set_calculus_method(self, method): sage: f.expr() x^2 + cos(y)*sin(x) sage: type(f.expr()) - + sage: parent(f.expr()) Symbolic Ring sage: f.display() diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py index 29378d6a872..8409ed656b3 100644 --- a/src/sage/manifolds/scalarfield.py +++ b/src/sage/manifolds/scalarfield.py @@ -211,7 +211,7 @@ class ScalarField(CommutativeAlgebraElement, ModuleElementWithMutability): sage: f.expr(c_uv) (u^2 + v^2)/(u^2 + v^2 + 1) sage: type(f.expr(c_uv)) - + The method :meth:`coord_function` returns instead a function of the chart coordinates, i.e. an instance of @@ -1844,7 +1844,7 @@ def expr(self, chart=None, from_chart=None): backend used for coordinate computations:: sage: type(f.expr()) - + sage: M.set_calculus_method('sympy') sage: type(f.expr()) diff --git a/src/sage/matrix/matrix0.pyx b/src/sage/matrix/matrix0.pyx index 41b8da5f415..8a3ea5918c4 100644 --- a/src/sage/matrix/matrix0.pyx +++ b/src/sage/matrix/matrix0.pyx @@ -78,7 +78,7 @@ cdef class Matrix(sage.structure.element.Matrix): [1.0 2.0 3.0] [4.0 5.0 6.0] sage: type(a) - + sage: parent(a) Full MatrixSpace of 2 by 3 dense matrices over Complex Double Field @@ -112,7 +112,7 @@ cdef class Matrix(sage.structure.element.Matrix): sage: import sage.matrix.matrix0 sage: A = sage.matrix.matrix0.Matrix(MatrixSpace(QQ,2)) sage: type(A) - + """ P = parent self._parent = P @@ -885,11 +885,11 @@ cdef class Matrix(sage.structure.element.Matrix): sage: M = MatrixSpace(GF(2), 3, 3, implementation='generic') sage: m = M(range(9)) sage: type(m) - + sage: parent(m) Full MatrixSpace of 3 by 3 dense matrices over Finite Field of size 2 (using Matrix_generic_dense) sage: type(m[:2,:2]) - + sage: parent(m[:2,:2]) Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 2 (using Matrix_generic_dense) """ @@ -5563,13 +5563,13 @@ cdef class Matrix(sage.structure.element.Matrix): sage: m = matrix(Zmod(49),2,[2,1,3,3]) sage: type(m) - + sage: ~m [ 1 16] [48 17] sage: m = matrix(Zmod(2^100),2,[2,1,3,3]) sage: type(m) - + sage: (~m)*m [1 0] [0 1] diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index d4a8ec9d3a1..b951e962342 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -2851,7 +2851,7 @@ cdef class Matrix(Matrix1): sage: M = MatrixSpace(RR, 2) sage: A = M(range(2^2)) sage: type(A) - + sage: A.charpoly('x') x^2 - 3.00000000000000*x - 2.00000000000000 sage: A.charpoly('y') @@ -15150,7 +15150,7 @@ cdef class Matrix(Matrix1): [ 1/11*(sqrt(33)*e^sqrt(33) - sqrt(33))*e^(-1/2*sqrt(33) + 5/2) 1/22*((sqrt(33) + 11)*e^sqrt(33) - sqrt(33) + 11)*e^(-1/2*sqrt(33) + 5/2)] sage: type(a.exp()) - + sage: a=matrix([[1/2,2/3],[3/4,4/5]]) sage: a.exp() diff --git a/src/sage/matrix/matrix_complex_ball_dense.pyx b/src/sage/matrix/matrix_complex_ball_dense.pyx index 4a3fd675681..4bd1313506d 100644 --- a/src/sage/matrix/matrix_complex_ball_dense.pyx +++ b/src/sage/matrix/matrix_complex_ball_dense.pyx @@ -143,7 +143,7 @@ cdef class Matrix_complex_ball_dense(Matrix_dense): sage: a = Matrix_complex_ball_dense.__new__( # indirect doctest ....: Matrix_complex_ball_dense, Mat(CBF, 2), 0, 0, 0) sage: type(a) - + """ sig_str("Arb exception") acb_mat_init(self.value, self._nrows, self._ncols) diff --git a/src/sage/matrix/matrix_cyclo_dense.pyx b/src/sage/matrix/matrix_cyclo_dense.pyx index eef7a331ee7..1845be41cbd 100644 --- a/src/sage/matrix/matrix_cyclo_dense.pyx +++ b/src/sage/matrix/matrix_cyclo_dense.pyx @@ -96,7 +96,7 @@ cdef class Matrix_cyclo_dense(Matrix_dense): sage: from sage.matrix.matrix_cyclo_dense import Matrix_cyclo_dense sage: A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, MatrixSpace(CyclotomicField(3),2), [0,1,2,3], True, True) sage: type(A) - + Note that the entries of A haven't even been set yet above; that doesn't happen until ``__init__`` is called:: diff --git a/src/sage/matrix/matrix_gap.pyx b/src/sage/matrix/matrix_gap.pyx index 0fff7a1f006..4a19dd4904e 100644 --- a/src/sage/matrix/matrix_gap.pyx +++ b/src/sage/matrix/matrix_gap.pyx @@ -27,13 +27,13 @@ cdef class Matrix_gap(Matrix_dense): sage: m1 = M([1, 0, 2, -3]) sage: m2 = M([2, 2, 5, -1]) sage: type(m1) - + sage: m1 * m2 [ 2 2] [-11 7] sage: type(m1 * m2) - + sage: M = MatrixSpace(QQ, 5, 3, implementation='gap') sage: m = M(range(15)) @@ -94,11 +94,11 @@ cdef class Matrix_gap(Matrix_dense): [2 0] [0 2] sage: type(M(0)) - + sage: type(M(1)) - + sage: type(M(2)) - + sage: M = MatrixSpace(QQ, 2, 3, implementation='gap') sage: M(0) @@ -175,7 +175,7 @@ cdef class Matrix_gap(Matrix_dense): sage: m [ [ 1, 2 ], [ 2, 1 ] ] sage: type(m) - + sage: m.MatrixAutomorphisms() Group([ (1,2) ]) diff --git a/src/sage/matrix/matrix_generic_dense.pyx b/src/sage/matrix/matrix_generic_dense.pyx index 3f01179dd14..7c0058db1d2 100644 --- a/src/sage/matrix/matrix_generic_dense.pyx +++ b/src/sage/matrix/matrix_generic_dense.pyx @@ -27,7 +27,7 @@ cdef class Matrix_generic_dense(matrix_dense.Matrix_dense): sage: A = random_matrix(Integers(25)['x'], 2) sage: type(A) - + sage: TestSuite(A).run() Test comparisons:: @@ -270,7 +270,7 @@ cdef class Matrix_generic_dense(matrix_dense.Matrix_dense): [ x y] [x^2 y^2] sage: type(a) - + sage: a*a [ x^2*y + x^2 y^3 + x*y] [x^2*y^2 + x^3 y^4 + x^2*y] diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index 32b77a861fa..1115e7b2c87 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -345,7 +345,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): [1 2 3] [4 0 1] sage: type(M) - + The documentation of the ``__init__`` methods shows further ways of creating a :class:`Matrix_gfpn_dense` instance. @@ -565,7 +565,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: F. = GF(9) sage: M = MatrixSpace(F,3)(sorted(list(F))) sage: type(M) - + sage: M # indirect doctest [ 0 1 2] [ z z + 1 z + 2] @@ -709,7 +709,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): [ 2*z^2 + z 2*z 2*z^2 + 2*z + 1 2*z^2 + 1 2*z^2 + 2*z + 1 2*z^2 + z] [ 2*z + 1 z^2 + z z^2 z^2 2*z^2 + 2*z z + 1] sage: type(M) - + sage: MS.random_element(nonzero=True) [ 2*z 1 z^2 + 2*z + 1 2*z^2 + z + 1 z^2 z^2 + z + 1] [ 2*z^2 + 2*z 2*z^2 + z + 2 2*z + 1 z^2 + 2*z 2*z^2 + 2*z z^2] @@ -1732,11 +1732,11 @@ cdef class Matrix_gfpn_dense(Matrix_dense): implementation of dense matrices:: sage: type(M) - + sage: MS = MatrixSpace(M.base_ring(), M.nrows(), M.ncols(), implementation='generic') sage: X = MS(M) sage: type(X) - + sage: X.echelon_form() [ 0 1 0 0 0 0 0 0 0 4*x + 4] [ 0 0 1 0 0 0 0 0 0 4*x + 2] @@ -1876,7 +1876,7 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): [ 6 7 8 9 10] [12 11 10 9 8] sage: type(N) - + We demonstrate that a slightly different pickle format can be understood as well, that was at some point used by some optional package:: diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index 5422d985eee..c9dcecdef47 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -216,7 +216,7 @@ cdef class Matrix_integer_dense(Matrix_dense): sage: from sage.matrix.matrix_integer_dense import Matrix_integer_dense sage: a = Matrix_integer_dense.__new__(Matrix_integer_dense, Mat(ZZ,3), 0,0,0) sage: type(a) - + TESTS:: @@ -1303,7 +1303,7 @@ cdef class Matrix_integer_dense(Matrix_dense): sage: M = MatrixSpace(ZZ, 2) sage: A = M(range(0, 2^2)) sage: type(A) - + sage: A.charpoly('x') x^2 - 3*x - 2 sage: A.charpoly('y') @@ -5546,7 +5546,7 @@ cdef class Matrix_integer_dense(Matrix_dense): sage: A = matrix(ZZ, 2, 3, range(6)) sage: type(A) - + sage: B = A.transpose() sage: print(B) [0 3] @@ -5592,7 +5592,7 @@ cdef class Matrix_integer_dense(Matrix_dense): sage: A = matrix(2,3,range(6)) sage: type(A) - + sage: A.antitranspose() [5 2] [4 1] @@ -5645,7 +5645,7 @@ cdef class Matrix_integer_dense(Matrix_dense): sage: pari(a) [1, 2; 3, 4] sage: type(pari(a)) - + """ return integer_matrix(self._matrix, 0) diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 8f1374eb39f..d583e5fa2e7 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -17,7 +17,7 @@ EXAMPLES:: sage: a.rank() 2 sage: type(a) - + sage: a[0,0] = 1 sage: a.rank() 3 @@ -237,7 +237,7 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse EXAMPLES:: sage: type(random_matrix(GF(2),2,2)) - + sage: Matrix(GF(2),3,3,1) [1 0 0] @@ -1528,7 +1528,7 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse Traceback (most recent call last): ... TypeError: right must either be a matrix or a vector. Not - + """ cdef Matrix_mod2_dense other diff --git a/src/sage/matrix/matrix_modn_dense_double.pyx b/src/sage/matrix/matrix_modn_dense_double.pyx index cb8f2a09e24..dfd27b78db2 100644 --- a/src/sage/matrix/matrix_modn_dense_double.pyx +++ b/src/sage/matrix/matrix_modn_dense_double.pyx @@ -68,7 +68,7 @@ cdef class Matrix_modn_dense_double(Matrix_modn_dense_template): sage: A = random_matrix(IntegerModRing(2^16), 4, 4) sage: type(A[0,0]) - + """ self._get_template = self._base_ring.zero() # note that INTEGER_MOD_INT32_LIMIT is ceil(sqrt(2^31-1)) < 2^23 diff --git a/src/sage/matrix/matrix_modn_dense_float.pyx b/src/sage/matrix/matrix_modn_dense_float.pyx index 8a215de6f66..9435794c4c1 100644 --- a/src/sage/matrix/matrix_modn_dense_float.pyx +++ b/src/sage/matrix/matrix_modn_dense_float.pyx @@ -63,7 +63,7 @@ cdef class Matrix_modn_dense_float(Matrix_modn_dense_template): sage: A = random_matrix(GF(7), 4, 4) sage: type(A[0,0]) - + """ self._get_template = self._base_ring.zero() diff --git a/src/sage/matrix/matrix_modn_dense_template.pxi b/src/sage/matrix/matrix_modn_dense_template.pxi index a04d3874a0f..010365d76f5 100644 --- a/src/sage/matrix/matrix_modn_dense_template.pxi +++ b/src/sage/matrix/matrix_modn_dense_template.pxi @@ -475,13 +475,13 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sage: A = random_matrix(GF(3),1000,1000) sage: type(A) - + sage: A = random_matrix(Integers(10),1000,1000) sage: type(A) - + sage: A = random_matrix(Integers(2^16),1000,1000) sage: type(A) - + TESTS:: @@ -1350,7 +1350,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sage: M = MatrixSpace(Integers(37), 2) sage: A = M(range(0, 2^2)) sage: type(A) - + sage: A.charpoly('x').variables() (x,) sage: A.charpoly('y').variables() diff --git a/src/sage/matrix/matrix_modn_sparse.pyx b/src/sage/matrix/matrix_modn_sparse.pyx index 9762f857e7c..fb9c6736ea0 100644 --- a/src/sage/matrix/matrix_modn_sparse.pyx +++ b/src/sage/matrix/matrix_modn_sparse.pyx @@ -16,7 +16,7 @@ EXAMPLES:: [3 4 5] [6 7 8] sage: type(a) - + sage: parent(a) Full MatrixSpace of 3 by 3 sparse matrices over Ring of integers modulo 37 sage: a^2 @@ -359,13 +359,13 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): [ 9 12 15] [19 26 33] sage: type(c) - + sage: a = matrix(GF(2), 20, 20, sparse=True) sage: a*a == a._matrix_times_matrix_dense(a) True sage: type(a._matrix_times_matrix_dense(a)) - + """ cdef Matrix_modn_sparse right cdef matrix_dense.Matrix_dense ans diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index bf343014db5..b54751066f4 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -139,7 +139,7 @@ cdef class Matrix_rational_dense(Matrix_dense): sage: from sage.matrix.matrix_rational_dense import Matrix_rational_dense sage: a = Matrix_rational_dense.__new__(Matrix_rational_dense, Mat(ZZ,3), 0,0,0) sage: type(a) - + .. WARNING:: @@ -1022,7 +1022,7 @@ cdef class Matrix_rational_dense(Matrix_dense): sage: M = MatrixSpace(QQ, 2) sage: A = M(range(0, 2^2)) sage: type(A) - + sage: A.charpoly('x') x^2 - 3*x - 2 sage: A.charpoly('y') @@ -2548,7 +2548,7 @@ cdef class Matrix_rational_dense(Matrix_dense): sage: A = matrix(QQ, 2, 3, range(6)) sage: type(A) - + sage: B = A.transpose() sage: print(B) [0 3] @@ -2599,7 +2599,7 @@ cdef class Matrix_rational_dense(Matrix_dense): sage: A = matrix(QQ,2,3,range(6)) sage: type(A) - + sage: A.antitranspose() [5 2] [4 1] diff --git a/src/sage/matrix/matrix_rational_sparse.pyx b/src/sage/matrix/matrix_rational_sparse.pyx index b00416b8e92..aa92bf206a7 100644 --- a/src/sage/matrix/matrix_rational_sparse.pyx +++ b/src/sage/matrix/matrix_rational_sparse.pyx @@ -229,7 +229,7 @@ cdef class Matrix_rational_sparse(Matrix_sparse): [ 9 12 15] [19 26 33] sage: type(c) - + """ cdef Matrix_rational_sparse right cdef Matrix_rational_dense ans @@ -620,9 +620,9 @@ cdef class Matrix_rational_sparse(Matrix_sparse): EXAMPLES:: sage: a = matrix(QQ,2,[1..4],sparse=True); type(a) - + sage: type(a.dense_matrix()) - + sage: a.dense_matrix() [1 2] [3 4] diff --git a/src/sage/matrix/matrix_sparse.pyx b/src/sage/matrix/matrix_sparse.pyx index ac795c9b71e..0d8c4abb46e 100644 --- a/src/sage/matrix/matrix_sparse.pyx +++ b/src/sage/matrix/matrix_sparse.pyx @@ -176,7 +176,7 @@ cdef class Matrix_sparse(matrix.Matrix): sage: A = matrix(QQ['x,y'], 2, [0,-1,2,-2], sparse=True) sage: type(A) - + sage: B = matrix(QQ['x,y'], 2, [-1,-1,-2,-2], sparse=True) sage: A * B [2 2] @@ -239,7 +239,7 @@ cdef class Matrix_sparse(matrix.Matrix): sage: A = matrix(QQ['x,y'], 2, [0,-1,2,-2], sparse=True) sage: type(A) - + sage: B = matrix(QQ['x,y'], 2, [-1,-1,-2,-2], sparse=True) sage: A._multiply_classical_with_cache(B) [2 2] diff --git a/src/sage/matrix/matrix_symbolic_dense.pyx b/src/sage/matrix/matrix_symbolic_dense.pyx index f67a25e9ccb..ded3a0dc0a1 100644 --- a/src/sage/matrix/matrix_symbolic_dense.pyx +++ b/src/sage/matrix/matrix_symbolic_dense.pyx @@ -264,7 +264,7 @@ cdef class Matrix_symbolic_dense(Matrix_generic_dense): sage: spectrum = am.eigenvectors_left() sage: symbolic_evalue = spectrum[2][0] sage: type(symbolic_evalue) - + sage: symbolic_evalue 1/2*sqrt(5) - 1/2 @@ -484,7 +484,7 @@ cdef class Matrix_symbolic_dense(Matrix_generic_dense): sage: M = MatrixSpace(SR, 2) sage: A = M(range(0, 2^2)) sage: type(A) - + sage: A.charpoly('x') x^2 - 3*x - 2 sage: A.charpoly('y') diff --git a/src/sage/matrix/special.py b/src/sage/matrix/special.py index 5e56ddeebea..bcb0b0293af 100644 --- a/src/sage/matrix/special.py +++ b/src/sage/matrix/special.py @@ -399,9 +399,9 @@ def random_matrix(ring, nrows, ncols=None, algorithm='randomize', implementation sage: K. = FiniteField(2^8) sage: type(random_matrix(K, 2, 5)) - + sage: type(random_matrix(K, 2, 5, implementation="generic")) - + Random rational matrices. Now ``num_bound`` and ``den_bound`` control the generation of random elements, by specifying limits on the absolute value of diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index a474bf4d1eb..f7e3d0c235e 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -2601,7 +2601,7 @@ def substitute(self, rules=None, domain=None, **kwds): ... TypeError: Cannot substitute u in u since it is neither an asymptotic expansion nor a string - (but a ). + (but a ). :: diff --git a/src/sage/rings/cfinite_sequence.py b/src/sage/rings/cfinite_sequence.py index c7821c2a387..b73764ce5d2 100644 --- a/src/sage/rings/cfinite_sequence.py +++ b/src/sage/rings/cfinite_sequence.py @@ -776,7 +776,7 @@ def series(self, n): sage: s = r.series(4); s x + 2*x^2 + 3*x^3 + 4*x^4 + O(x^5) sage: type(s) - + """ R = LaurentSeriesRing(QQ, 'x', default_prec=n) return R(self.ogf()) diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index 9aa6ba15d7b..da6aac2dab5 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -2476,7 +2476,7 @@ cdef class ComplexBall(RingElement): sage: CBF(sqrt(2)).contains_exact(sqrt(2)) Traceback (most recent call last): ... - TypeError: unsupported type: + TypeError: unsupported type: """ cdef fmpz_t tmpz cdef fmpq_t tmpq diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index aa45ef96602..fb56eb43da2 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -23,7 +23,7 @@ EXAMPLES:: sage: CDF Complex Double Field sage: type(CDF.0) - + sage: ComplexDoubleElement(sqrt(2),3) 1.4142135623730951 + 3.0*I sage: parent(CDF(-2)) diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index 04e8019bb2e..e7f287aa9c9 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -409,7 +409,7 @@ cdef class MPComplexField_class(sage.rings.ring.Field): sage: C20(i*4, 7) Traceback (most recent call last): ... - TypeError: unable to coerce to a ComplexNumber: + TypeError: unable to coerce to a ComplexNumber: Each part can be set with strings (written in base ten):: diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index e3f609a43c6..d36f24a6fd5 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -1382,11 +1382,11 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): sage: pari(a).type() 't_COMPLEX' sage: type(pari(a)) - + sage: a.__pari__() 2.00000000000000 + 1.00000000000000*I sage: type(a.__pari__()) - + sage: a = CC(pi) sage: pari(a) 3.14159265358979 diff --git a/src/sage/rings/continued_fraction.py b/src/sage/rings/continued_fraction.py index 7e4611e435f..cf5f8b1f9eb 100644 --- a/src/sage/rings/continued_fraction.py +++ b/src/sage/rings/continued_fraction.py @@ -2051,7 +2051,7 @@ def __init__(self, w, value=None, check=True): sage: w = words.ThueMorseWord([int(1), int(2)]) sage: t = continued_fraction(w) sage: type(t.quotient(1)) - + """ ContinuedFraction_base.__init__(self) self._w = w @@ -2157,7 +2157,7 @@ def _Integer_quotient(self, n): sage: t.quotient(1) 2 sage: type(t.quotient(1)) # indirect doctest - + """ return Integer(self._w[n]) @@ -2407,7 +2407,7 @@ def continued_fraction_list(x, type="std", partial_convergents=False, sage: a = 1.575709393346379 sage: type(a) - + sage: continued_fraction_list(a) [1, 1, 1, 2, 1, 4, 18, 1, 5, 2, 25037802, 7, 1, 3, 1, 28, 1, 8, 2] diff --git a/src/sage/rings/fast_arith.pyx b/src/sage/rings/fast_arith.pyx index aecfdf6bb0f..1eab26ba803 100644 --- a/src/sage/rings/fast_arith.pyx +++ b/src/sage/rings/fast_arith.pyx @@ -96,9 +96,9 @@ cpdef prime_range(start, stop=None, algorithm=None, bint py_ints=False): sage: prime_range(10**30,10**30+100,"pari_isprime") [1000000000000000000000000000057, 1000000000000000000000000000099] sage: type(prime_range(8)[0]) - + sage: type(prime_range(8,algorithm="pari_isprime")[0]) - + .. NOTE:: diff --git a/src/sage/rings/finite_rings/element_base.pyx b/src/sage/rings/finite_rings/element_base.pyx index d4c06183317..492a30983c9 100755 --- a/src/sage/rings/finite_rings/element_base.pyx +++ b/src/sage/rings/finite_rings/element_base.pyx @@ -339,7 +339,7 @@ cdef class FinitePolyExtElement(FiniteRingElement): sage: t_element 3*b^2 + 2*b + 4 sage: type(t_element) - + """ if var is None: var = self.parent().variable_name() diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index 82f4bb2e99a..e28808d84bf 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -300,7 +300,7 @@ cdef class Cache_givaro(Cache_base): sage: e.parent() is k True sage: type(e) - + sage: P. = PowerSeriesRing(GF(3^3, 'a')) sage: P.random_element(5).parent() is P @@ -1413,7 +1413,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): sage: b._log_to_int() 5 sage: type(b._log_to_int()) - + """ return Integer(self._cache.log_to_int(self.element)) @@ -1494,7 +1494,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): sage: f = (b^2+1).polynomial(); f b + 4 sage: type(f) - + sage: parent(f) Univariate Polynomial Ring in b over Finite Field of size 5 """ diff --git a/src/sage/rings/finite_rings/element_pari_ffelt.pyx b/src/sage/rings/finite_rings/element_pari_ffelt.pyx index 57baa162b0b..95922cd42d0 100644 --- a/src/sage/rings/finite_rings/element_pari_ffelt.pyx +++ b/src/sage/rings/finite_rings/element_pari_ffelt.pyx @@ -98,7 +98,7 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): sage: a = K.gen(); a a sage: type(a) - + TESTS:: diff --git a/src/sage/rings/finite_rings/finite_field_constructor.py b/src/sage/rings/finite_rings/finite_field_constructor.py index 0980ff8dbdf..d7b4e15985f 100644 --- a/src/sage/rings/finite_rings/finite_field_constructor.py +++ b/src/sage/rings/finite_rings/finite_field_constructor.py @@ -284,7 +284,7 @@ class FiniteFieldFactory(UniqueFactory): sage: f = K.modulus(); f x^5 + 4*x + 1 sage: type(f) - + By default, the given generator is not guaranteed to be primitive (a generator of the multiplicative group), use diff --git a/src/sage/rings/finite_rings/finite_field_givaro.py b/src/sage/rings/finite_rings/finite_field_givaro.py index e686ef8424b..dbeddd8705e 100644 --- a/src/sage/rings/finite_rings/finite_field_givaro.py +++ b/src/sage/rings/finite_rings/finite_field_givaro.py @@ -152,7 +152,7 @@ def characteristic(self): sage: p = GF(19^5,'a').characteristic(); p 19 sage: type(p) - + """ return Integer(self._cache.characteristic()) @@ -169,7 +169,7 @@ def order(self): sage: n = GF(19^5,'a').order(); n 2476099 sage: type(n) - + """ return self._cache.order() @@ -218,7 +218,7 @@ def random_element(self, *args, **kwds): sage: e.parent() is k True sage: type(e) - + sage: P. = PowerSeriesRing(GF(3^3, 'a')) sage: P.random_element(5).parent() is P diff --git a/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx b/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx index 28c8b3935c0..698c54e71b5 100644 --- a/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx +++ b/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx @@ -204,13 +204,13 @@ cdef class FrobeniusEndomorphism_givaro(FrobeniusEndomorphism_finite_field): sage: Frob = k.frobenius_endomorphism(); Frob Frobenius endomorphism t |--> t^5 on Finite Field in t of size 5^3 sage: type(Frob) - + sage: k. = GF(5^20) sage: Frob = k.frobenius_endomorphism(); Frob Frobenius endomorphism t |--> t^5 on Finite Field in t of size 5^20 sage: type(Frob) - + """ if not isinstance(domain, FiniteField_givaro): raise TypeError("The domain is not an instance of FiniteField_givaro") diff --git a/src/sage/rings/finite_rings/residue_field.pyx b/src/sage/rings/finite_rings/residue_field.pyx index 007a68e4c0f..62bebc2303b 100644 --- a/src/sage/rings/finite_rings/residue_field.pyx +++ b/src/sage/rings/finite_rings/residue_field.pyx @@ -963,7 +963,7 @@ cdef class ReductionMap(Map): sage: K = R.fraction_field() sage: f = k.convert_map_from(K) sage: type(f) - + sage: f(1/t) a^4 + a sage: f(1/h) @@ -1143,7 +1143,7 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): From: Maximal Order in Cyclotomic Field of order 5 and degree 4 To: Residue field in a of Fractional ideal (7) sage: type(phi) - + sage: R. = GF(2)[]; P = R.ideal(t^7 + t^6 + t^5 + t^4 + 1) sage: k = P.residue_field(); f = k.coerce_map_from(R) @@ -1606,7 +1606,7 @@ class ResidueFiniteField_prime_modn(ResidueField_generic, FiniteField_prime_modn 2 sage: V = k.vector_space(map=False); v = V([3]) sage: type(k.convert_map_from(V)) - + sage: k(v) # indirect doctest 3 @@ -1698,7 +1698,7 @@ class ResidueFiniteField_pari_ffelt(ResidueField_generic, FiniteField_pari_ffelt 6677 sage: V = ff.vector_space(map=False); v = V([3,-2]) sage: type(ff.convert_map_from(V)) - + sage: ff(v) # indirect doctest 10005*alpha + 3 @@ -1800,7 +1800,7 @@ class ResidueFiniteField_givaro(ResidueField_generic, FiniteField_givaro): 2*abar + 4 sage: V = k.vector_space(map=False); v = V([3,-2]) sage: type(k.convert_map_from(V)) - + sage: k(v) # indirect doctest 59*abar + 3 @@ -1906,7 +1906,7 @@ class ResidueFiniteField_ntl_gf2e(ResidueField_generic, FiniteField_ntl_gf2e): 2*abar + 4 sage: V = k.vector_space(map=False); v = V([3,-2]) sage: type(k.convert_map_from(V)) - + sage: k(v) # indirect doctest 59*abar + 3 diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index c5b5c55a785..8d8d4c49c80 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -948,7 +948,7 @@ def __init__(self, R, sage: R. = QQ[]; K = R.fraction_field() sage: K._element_class - + """ FractionField_generic.__init__(self, R, element_class) diff --git a/src/sage/rings/fraction_field_FpT.pyx b/src/sage/rings/fraction_field_FpT.pyx index 7ad2a7359ab..b81535fe5bd 100644 --- a/src/sage/rings/fraction_field_FpT.pyx +++ b/src/sage/rings/fraction_field_FpT.pyx @@ -1033,7 +1033,7 @@ cdef class Polyring_FpT_coerce(RingHomomorphism): From: Univariate Polynomial Ring in t over Finite Field of size 5 To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 sage: type(f) - + TESTS:: @@ -1222,7 +1222,7 @@ cdef class FpT_Polyring_section(Section): From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 To: Univariate Polynomial Ring in t over Finite Field of size 5 sage: type(f) - + .. WARNING:: @@ -1351,7 +1351,7 @@ cdef class Fp_FpT_coerce(RingHomomorphism): From: Finite Field of size 5 To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 sage: type(f) - + TESTS:: @@ -1524,7 +1524,7 @@ cdef class FpT_Fp_section(Section): From: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5 To: Finite Field of size 5 sage: type(f) - + .. WARNING:: @@ -1673,7 +1673,7 @@ cdef class ZZ_FpT_coerce(RingHomomorphism): From: Integer Ring To: Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 17 sage: type(f) - + TESTS:: diff --git a/src/sage/rings/fraction_field_element.pyx b/src/sage/rings/fraction_field_element.pyx index 4206b1dd4d8..4d1235c88c4 100644 --- a/src/sage/rings/fraction_field_element.pyx +++ b/src/sage/rings/fraction_field_element.pyx @@ -861,15 +861,15 @@ cdef class FractionFieldElement(FieldElement): sage: a = x^2; a x^2 sage: type(a.numerator()) - + sage: type(a.denominator()) - + sage: a = x^(-2); a 1/x^2 sage: type(a.numerator()) - + sage: type(a.denominator()) - + sage: x^0 1 sage: ((x+y)/(x-y))^2 diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index f468b59bf68..f88a4d4ea89 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -2132,7 +2132,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 2^I sage: r = 2 ^ int(-3); r; type(r) 1/8 - + sage: f = 2^(sin(x)-cos(x)); f 2^(-cos(x) + sin(x)) sage: f(x=3) @@ -5948,7 +5948,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: m = n.__pari__(); m 9390823 sage: type(m) - + TESTS:: @@ -6187,13 +6187,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): TESTS:: sage: type(5.sqrt()) - + sage: type(5.sqrt(prec=53)) - + sage: type((-5).sqrt(prec=53)) - + sage: type(0.sqrt(prec=53)) - + Check that :trac:`9466` and :trac:`26509` are fixed:: @@ -7058,7 +7058,7 @@ def GCD_list(v): sage: w = GCD_list([3,9,30]); w 3 sage: type(w) - + Check that the bug reported in :trac:`3118` has been fixed:: @@ -7072,7 +7072,7 @@ def GCD_list(v): sage: w = GCD_list([int(3), int(9), '30']); w 3 sage: type(w) - + Check that the GCD of the empty list is zero (:trac:`17257`):: @@ -7137,11 +7137,11 @@ cdef class int_to_Z(Morphism): sage: f(5r) 5 sage: type(f(5r)) - + sage: 1 + 2r 3 sage: type(1 + 2r) - + This is intended for internal use by the coercion system, to facilitate fast expressions mixing ints and more complex diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index 99befbb94a7..f6308251e80 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -26,7 +26,7 @@ other types will also coerce to the integers, when it makes sense. sage: b = Z(5678); b 5678 sage: type(a) - + sage: a + b 6912 sage: Z('94803849083985934859834583945394') @@ -183,7 +183,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): sage: b = Z(5678); b 5678 sage: type(a) - + sage: a + b 6912 sage: b + a @@ -206,18 +206,18 @@ cdef class IntegerRing_class(PrincipalIdealDomain): sage: a / b 617/2839 sage: type(a/b) - + sage: a/a 1 sage: type(a/a) - + For floor division, use the ``//`` operator instead:: sage: a // b 0 sage: type(a//b) - + Next we illustrate arithmetic with automatic coercion. The types that coerce are: str, int, long, Integer. @@ -1046,7 +1046,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): (1,) 1 sage: type(ZZ.gens()[0]) - + """ return (self(1), ) @@ -1066,7 +1066,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): sage: ZZ.gen() 1 sage: type(ZZ.gen()) - + """ if n == 0: return self(1) diff --git a/src/sage/rings/multi_power_series_ring.py b/src/sage/rings/multi_power_series_ring.py index 2b8639ed2a3..a8f8cc47d57 100644 --- a/src/sage/rings/multi_power_series_ring.py +++ b/src/sage/rings/multi_power_series_ring.py @@ -163,7 +163,7 @@ sage: S = PowerSeriesRing(GF(11),2,'x,y'); S Multivariate Power Series Ring in x, y over Finite Field of size 11 sage: type(x) - + sage: type(S(x)) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 3ad7ffa26ef..2e0b86df657 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -8050,7 +8050,7 @@ def _coerce_map_from_(self, R): sage: S.coerce(-Integer(2)) -2 sage: z = S.coerce(-7/8); z, type(z) - (-7/8, ) + (-7/8, ) sage: S.coerce(y) is y True @@ -8106,13 +8106,13 @@ def _coerce_map_from_(self, R): sage: K. = NumberField(polygen(QQ)^3-2) sage: type(K.coerce_map_from(QQ)) - + Make sure we still get our optimized morphisms for special fields:: sage: K. = NumberField(polygen(QQ)^2-2) sage: type(K.coerce_map_from(QQ)) - + """ if R is int: @@ -10397,12 +10397,12 @@ class NumberField_cyclotomic(NumberField_absolute): sage: cf6(z3) zeta6 - 1 sage: type(cf6(z3)) - + sage: cf1 = CyclotomicField(1) ; z1 = cf1.0 sage: cf3(z1) 1 sage: type(cf3(z1)) - + """ def __init__(self, n, names, embedding=None, assume_disc_small=False, maximize_at_primes=None): """ @@ -10432,13 +10432,13 @@ def __init__(self, n, names, embedding=None, assume_disc_small=False, maximize_a :: sage: type(CyclotomicField(4).zero()) - + sage: type(CyclotomicField(6).one()) - + sage: type(CyclotomicField(6).an_element()) - + sage: type(CyclotomicField(15).zero()) - + """ f = QQ['x'].cyclotomic_polynomial(n) if names[0].startswith('zeta'): @@ -11744,9 +11744,9 @@ def __init__(self, polynomial, name=None, latex_name=None, check=True, embedding sage: k. = QuadraticField(7) sage: type(k.zero()) - + sage: type(k.one()) - + sage: TestSuite(k).run() @@ -11958,13 +11958,13 @@ def class_number(self, proof=None): TESTS:: sage: type(QuadraticField(-23,'a').class_number()) - + sage: type(NumberField(x^3 + 23, 'a').class_number()) - + sage: type(NumberField(x^3 + 23, 'a').extension(x^2 + 5, 'b').class_number()) - + sage: type(CyclotomicField(10).class_number()) - + """ proof = proof_flag(proof) diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index c34cfc9e42f..9dbbf6f2be7 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -359,7 +359,7 @@ cdef class NumberFieldElement(FieldElement): sage: cf4(one) 1 sage: type(cf4(1)) - + sage: cf33 = CyclotomicField(33) ; z33 = cf33.0 sage: cf66 = CyclotomicField(66) ; z66 = cf66.0 sage: z33._lift_cyclotomic_element(cf66) @@ -574,7 +574,7 @@ cdef class NumberFieldElement(FieldElement): sage: libgap(E8 + 3/2*E8^2 + 100*E8^7) E(8)+3/2*E(8)^2-100*E(8)^3 sage: type(_) - + Check that :trac:`15276` is fixed:: @@ -3807,7 +3807,7 @@ cdef class NumberFieldElement(FieldElement): sage: b.ord(P) 1 sage: type(b.valuation(P)) - + The function can be applied to elements in relative number fields:: @@ -4829,7 +4829,7 @@ cdef class NumberFieldElement_relative(NumberFieldElement): sage: L. = NumberField([x^2 + 1, x^2 + 2]) sage: type(a) # indirect doctest - + """ NumberFieldElement.__init__(self, parent, f) @@ -5126,7 +5126,7 @@ cdef class OrderElement_absolute(NumberFieldElement_absolute): sage: K. = NumberField(x^3 + 2) sage: O2 = K.order(2*a) sage: type(O2.1) # indirect doctest - + """ K = order.number_field() NumberFieldElement_absolute.__init__(self, K, f) @@ -5230,7 +5230,7 @@ cdef class OrderElement_relative(NumberFieldElement_relative): sage: c = O.1; c (-2*b^2 - 2)*a - 2*b^2 - b sage: type(c) - + """ def __init__(self, order, f): r""" @@ -5238,7 +5238,7 @@ cdef class OrderElement_relative(NumberFieldElement_relative): sage: O = EquationOrder([x^2 + x + 1, x^3 - 2],'a,b') sage: type(O.1) # indirect doctest - + """ K = order.number_field() NumberFieldElement_relative.__init__(self, K, f) diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index afe40d7ffdb..510d0a4a3ec 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -173,7 +173,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: F. = QuadraticField(-7) sage: c = a + 7 sage: type(c) # indirect doctest - + """ self.D = parent._D cdef Integer a, b, denom @@ -2612,7 +2612,7 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): sage: OK. = EquationOrder(x^2 + 5) sage: v = OK.1 # indirect doctest sage: type(v) - + """ K = order.number_field() NumberFieldElement_quadratic.__init__(self, K, f) @@ -2878,14 +2878,14 @@ cdef class Z_to_quadratic_field_element(Morphism): sage: K. = QuadraticField(3) sage: phi = K.coerce_map_from(ZZ) # indirect doctest sage: type(phi) - + sage: phi == loads(dumps(phi)) # todo: comparison not implemented True sage: R. = CyclotomicField(6) sage: psi = R.coerce_map_from(ZZ) # indirect doctest sage: type(psi) - + sage: psi == loads(dumps(psi)) # todo: comparison not implemented True """ @@ -2980,14 +2980,14 @@ cdef class Q_to_quadratic_field_element(Morphism): sage: K. = QuadraticField(3) sage: phi = K.coerce_map_from(QQ) # indirect doctest sage: type(phi) - + sage: phi == loads(dumps(phi)) # todo: comparison not implemented True sage: R. = CyclotomicField(6) sage: psi = R.coerce_map_from(QQ) sage: type(psi) - + sage: psi == loads(dumps(psi)) # todo: comparison not implemented True """ diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index 8a27624e577..1f5bca3ce33 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -3214,7 +3214,7 @@ def __init__(self, K, M_OK_change, Q, I): From: Number Field in a with defining polynomial x^3 + 4 To: Residue field of Fractional ideal (1/2*a^2 + 1) sage: f.__class__ - + """ self.__M_OK_change = M_OK_change self.__Q = Q @@ -3270,7 +3270,7 @@ def __init__(self, OK, M_OK_map, Q, I): sage: I = K.ideal(1 + a^2/2) sage: f = I.residue_field().lift_map() sage: f.__class__ - + """ self.__I = I self.__OK = OK diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index 3097a98002d..71760700442 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -1686,7 +1686,7 @@ def pari_absolute_base_polynomial(self): sage: K.pari_absolute_base_polynomial() y^2 + 3 sage: type(K.pari_absolute_base_polynomial()) - + sage: z = ZZ['z'].0 sage: K. = NumberField([z^2 + 2, z^2 + 3, z^2 + 5]); K Number Field in a with defining polynomial z^2 + 2 over its base field @@ -1697,7 +1697,7 @@ def pari_absolute_base_polynomial(self): sage: len(QQ['y'](K.pari_absolute_base_polynomial()).roots(K.base_field())) 4 sage: type(K.pari_absolute_base_polynomial()) - + """ abs_base, from_abs_base, to_abs_base = self.absolute_base_field() return abs_base.pari_polynomial('y') diff --git a/src/sage/rings/number_field/totallyreal.pyx b/src/sage/rings/number_field/totallyreal.pyx index 0512f0559fc..69a1103ce9d 100644 --- a/src/sage/rings/number_field/totallyreal.pyx +++ b/src/sage/rings/number_field/totallyreal.pyx @@ -237,7 +237,7 @@ def enumerate_totallyreal_fields_prim(n, B, a = [], verbose=0, return_seqs=False sage: enumerate_totallyreal_fields_prim(2, 10) [[5, x^2 - x - 1], [8, x^2 - 2]] sage: type(enumerate_totallyreal_fields_prim(2, 10)[0][1]) - + sage: enumerate_totallyreal_fields_prim(2, 10, return_pari_objects=False)[0][0].parent() Integer Ring sage: enumerate_totallyreal_fields_prim(2, 10, return_pari_objects=False)[0][1].parent() diff --git a/src/sage/rings/number_field/totallyreal_rel.py b/src/sage/rings/number_field/totallyreal_rel.py index e531dcaa126..4211a2a4769 100644 --- a/src/sage/rings/number_field/totallyreal_rel.py +++ b/src/sage/rings/number_field/totallyreal_rel.py @@ -706,7 +706,7 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, is set to ``False``:: sage: type(enumerate_totallyreal_fields_rel(F, 2, 2000)[0][1]) - + sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][0].parent() Integer Ring sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][1].parent() @@ -938,7 +938,7 @@ def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False, sage: enumerate_totallyreal_fields_all(2, 10) [[5, x^2 - x - 1], [8, x^2 - 2]] sage: type(enumerate_totallyreal_fields_all(2, 10)[0][1]) - + sage: enumerate_totallyreal_fields_all(2, 10, return_pari_objects=False)[0][1].parent() Univariate Polynomial Ring in x over Rational Field diff --git a/src/sage/rings/padics/CA_template.pxi b/src/sage/rings/padics/CA_template.pxi index 5a3065ff10a..e4c5966ad3a 100644 --- a/src/sage/rings/padics/CA_template.pxi +++ b/src/sage/rings/padics/CA_template.pxi @@ -189,7 +189,7 @@ cdef class CAElement(pAdicTemplateElement): sage: a = ZpCA(5)(-3) sage: type(a) - + sage: loads(dumps(a)) == a True """ @@ -1005,7 +1005,7 @@ cdef class CAElement(pAdicTemplateElement): sage: a.unit_part() 18 + O(17^3) sage: type(a) - + sage: R(0).unit_part() O(17^0) """ @@ -1105,7 +1105,7 @@ cdef class pAdicCoercion_ZZ_CA(RingHomomorphism): EXAMPLES:: sage: f = ZpCA(5).coerce_map_from(ZZ); type(f) - + """ RingHomomorphism.__init__(self, ZZ.Hom(R)) self._zero = R.element_class(R, 0) @@ -1181,7 +1181,7 @@ cdef class pAdicCoercion_ZZ_CA(RingHomomorphism): sage: R = ZpCA(5,4) sage: type(R(10,2)) - + sage: R(10,2) # indirect doctest 2*5 + O(5^2) sage: R(10,3,1) @@ -1255,7 +1255,7 @@ cdef class pAdicConvert_CA_ZZ(RingMap): EXAMPLES:: sage: f = ZpCA(5).coerce_map_from(ZZ).section(); type(f) - + sage: f.category() Category of homsets of sets """ @@ -1300,7 +1300,7 @@ cdef class pAdicConvert_QQ_CA(Morphism): EXAMPLES:: sage: f = ZpCA(5).convert_map_from(QQ); type(f) - + """ Morphism.__init__(self, Hom(QQ, R, SetsWithPartialMaps())) self._zero = R.element_class(R, 0) @@ -1371,7 +1371,7 @@ cdef class pAdicConvert_QQ_CA(Morphism): sage: R = ZpCA(5,4) sage: type(R(10/3,2)) - + sage: R(10/3,2) # indirect doctest 4*5 + O(5^2) sage: R(10/3,3,1) @@ -1436,7 +1436,7 @@ cdef class pAdicCoercion_CA_frac_field(RingHomomorphism): sage: R. = ZqCA(27, implementation='FLINT') sage: K = R.fraction_field() sage: f = K.coerce_map_from(R); type(f) - + """ RingHomomorphism.__init__(self, R.Hom(K)) self._zero = K(0) @@ -1652,7 +1652,7 @@ cdef class pAdicConvert_CA_frac_field(Morphism): sage: R. = ZqCA(27, implementation='FLINT') sage: K = R.fraction_field() sage: f = R.convert_map_from(K); type(f) - + """ Morphism.__init__(self, Hom(K, R, SetsWithPartialMaps())) self._zero = R(0) diff --git a/src/sage/rings/padics/CR_template.pxi b/src/sage/rings/padics/CR_template.pxi index 68c0dc9d194..7318873f9c5 100644 --- a/src/sage/rings/padics/CR_template.pxi +++ b/src/sage/rings/padics/CR_template.pxi @@ -299,7 +299,7 @@ cdef class CRElement(pAdicTemplateElement): sage: a = ZpCR(5)(-3) sage: type(a) - + sage: loads(dumps(a)) == a # indirect doctest True """ @@ -1423,13 +1423,13 @@ cdef class CRElement(pAdicTemplateElement): sage: a.unit_part() 1 + 17 + O(17^4) sage: type(a) - + sage: R = Qp(17,4,'capped-rel') sage: a = R(18*17) sage: a.unit_part() 1 + 17 + O(17^4) sage: type(a) - + sage: a = R(2*17^2); a 2*17^2 + O(17^6) sage: a.unit_part() @@ -1562,7 +1562,7 @@ cdef class pAdicCoercion_ZZ_CR(RingHomomorphism): EXAMPLES:: sage: f = Zp(5).coerce_map_from(ZZ); type(f) - + """ RingHomomorphism.__init__(self, ZZ.Hom(R)) self._zero = R.element_class(R, 0) @@ -1652,7 +1652,7 @@ cdef class pAdicCoercion_ZZ_CR(RingHomomorphism): sage: R = Zp(5,4) sage: type(R(10,2)) - + sage: R(10,2) # indirect doctest 2*5 + O(5^2) sage: R(10,3,1) @@ -1724,7 +1724,7 @@ cdef class pAdicConvert_CR_ZZ(RingMap): EXAMPLES:: sage: f = Qp(5).coerce_map_from(ZZ).section(); type(f) - + sage: f.category() Category of homsets of sets with partial maps sage: Zp(5).coerce_map_from(ZZ).section().category() @@ -1780,7 +1780,7 @@ cdef class pAdicCoercion_QQ_CR(RingHomomorphism): EXAMPLES:: sage: f = Qp(5).coerce_map_from(QQ); type(f) - + """ RingHomomorphism.__init__(self, QQ.Hom(R)) self._zero = R.element_class(R, 0) @@ -1872,7 +1872,7 @@ cdef class pAdicCoercion_QQ_CR(RingHomomorphism): sage: R = Qp(5,4) sage: type(R(10/3,2)) - + sage: R(10/3,2) # indirect doctest 4*5 + O(5^2) sage: R(10/3,3,1) @@ -1944,7 +1944,7 @@ cdef class pAdicConvert_CR_QQ(RingMap): EXAMPLES:: sage: f = Qp(5).coerce_map_from(QQ).section(); type(f) - + sage: f.category() Category of homsets of sets """ @@ -1994,7 +1994,7 @@ cdef class pAdicConvert_QQ_CR(Morphism): EXAMPLES:: sage: f = Zp(5).convert_map_from(QQ); type(f) - + """ Morphism.__init__(self, Hom(QQ, R, SetsWithPartialMaps())) self._zero = R.element_class(R, 0) @@ -2073,7 +2073,7 @@ cdef class pAdicConvert_QQ_CR(Morphism): sage: R = Zp(5,4) sage: type(R(10/3,2)) - + sage: R(10/3,2) # indirect doctest 4*5 + O(5^2) sage: R(10/3,3,1) @@ -2156,7 +2156,7 @@ cdef class pAdicCoercion_CR_frac_field(RingHomomorphism): sage: R. = ZqCR(27, implementation='FLINT') sage: K = R.fraction_field() sage: f = K.coerce_map_from(R); type(f) - + """ RingHomomorphism.__init__(self, R.Hom(K)) self._zero = K(0) @@ -2377,7 +2377,7 @@ cdef class pAdicConvert_CR_frac_field(Morphism): sage: R. = ZqCR(27, implementation='FLINT') sage: K = R.fraction_field() sage: f = R.convert_map_from(K); type(f) - + """ Morphism.__init__(self, Hom(K, R, SetsWithPartialMaps())) self._zero = R(0) diff --git a/src/sage/rings/padics/FM_template.pxi b/src/sage/rings/padics/FM_template.pxi index 16926c3fe86..1dc94645c75 100644 --- a/src/sage/rings/padics/FM_template.pxi +++ b/src/sage/rings/padics/FM_template.pxi @@ -173,7 +173,7 @@ cdef class FMElement(pAdicTemplateElement): sage: a = ZpFM(5)(-3) sage: type(a) - + sage: loads(dumps(a)) == a True """ @@ -795,7 +795,7 @@ cdef class FMElement(pAdicTemplateElement): sage: R(0).unit_part() 0 sage: type(R(5).unit_part()) - + sage: R = ZpFM(5, 5); a = R(75); a.unit_part() 3 """ @@ -890,7 +890,7 @@ cdef class pAdicCoercion_ZZ_FM(RingHomomorphism): EXAMPLES:: sage: f = ZpFM(5).coerce_map_from(ZZ); type(f) - + """ RingHomomorphism.__init__(self, ZZ.Hom(R)) self._zero = R.element_class(R, 0) @@ -972,7 +972,7 @@ cdef class pAdicCoercion_ZZ_FM(RingHomomorphism): sage: R = ZpFM(5,4) sage: type(R(10,2)) - + sage: R(30,2) 5 + 5^2 sage: R(30,3,1) @@ -1030,7 +1030,7 @@ cdef class pAdicConvert_FM_ZZ(RingMap): EXAMPLES:: sage: f = ZpFM(5).coerce_map_from(ZZ).section(); type(f) - + sage: f.category() Category of homsets of sets """ @@ -1075,7 +1075,7 @@ cdef class pAdicConvert_QQ_FM(Morphism): EXAMPLES:: sage: f = ZpFM(5).convert_map_from(QQ); type(f) - + """ Morphism.__init__(self, Hom(QQ, R, SetsWithPartialMaps())) self._zero = R.element_class(R, 0) @@ -1154,7 +1154,7 @@ cdef class pAdicConvert_QQ_FM(Morphism): sage: R = ZpFM(5,4) sage: type(R(1/7,2)) - + sage: R(1/7,2) 3 + 3*5 + 2*5^3 sage: R(1/7,3,1) @@ -1201,7 +1201,7 @@ cdef class pAdicCoercion_FM_frac_field(RingHomomorphism): sage: R. = ZqFM(27) sage: K = R.fraction_field() sage: f = K.coerce_map_from(R); type(f) - + """ RingHomomorphism.__init__(self, R.Hom(K)) self._zero = K(0) @@ -1408,7 +1408,7 @@ cdef class pAdicConvert_FM_frac_field(Morphism): sage: R. = ZqFM(27) sage: K = R.fraction_field() sage: f = R.convert_map_from(K); type(f) - + """ Morphism.__init__(self, Hom(K, R, SetsWithPartialMaps())) self._zero = R(0) diff --git a/src/sage/rings/padics/FP_template.pxi b/src/sage/rings/padics/FP_template.pxi index c7ce3937c0d..a4eed73ced7 100644 --- a/src/sage/rings/padics/FP_template.pxi +++ b/src/sage/rings/padics/FP_template.pxi @@ -290,7 +290,7 @@ cdef class FPElement(pAdicTemplateElement): sage: a = ZpFP(5)(-3) sage: type(a) - + sage: loads(dumps(a)) == a True """ @@ -1152,7 +1152,7 @@ cdef class FPElement(pAdicTemplateElement): ... ValueError: unit part of 0 and infinity not defined sage: type(R(5).unit_part()) - + sage: R = ZpFP(5, 5); a = R(75); a.unit_part() 3 """ @@ -1268,7 +1268,7 @@ cdef class pAdicCoercion_ZZ_FP(RingHomomorphism): EXAMPLES:: sage: f = ZpFP(5).coerce_map_from(ZZ); type(f) - + """ RingHomomorphism.__init__(self, ZZ.Hom(R)) self._zero = R.element_class(R, 0) @@ -1350,7 +1350,7 @@ cdef class pAdicCoercion_ZZ_FP(RingHomomorphism): sage: R = ZpFP(5,4) sage: type(R(10,2)) - + sage: R(30,2) 5 sage: R(30,3,2) @@ -1416,7 +1416,7 @@ cdef class pAdicConvert_FP_ZZ(RingMap): EXAMPLES:: sage: f = ZpFP(5).coerce_map_from(ZZ).section(); type(f) - + sage: f.category() Category of homsets of sets """ @@ -1480,7 +1480,7 @@ cdef class pAdicCoercion_QQ_FP(RingHomomorphism): EXAMPLES:: sage: f = QpFP(5).coerce_map_from(QQ); type(f) - + """ RingHomomorphism.__init__(self, QQ.Hom(R)) self._zero = R.element_class(R, 0) @@ -1571,7 +1571,7 @@ cdef class pAdicCoercion_QQ_FP(RingHomomorphism): sage: R = QpFP(5,4) sage: type(R(10/3,2)) - + sage: R(10/3,2) 4*5 sage: R(10/3,3,1) @@ -1636,7 +1636,7 @@ cdef class pAdicConvert_FP_QQ(RingMap): EXAMPLES:: sage: f = QpFP(5).coerce_map_from(QQ).section(); type(f) - + sage: f.category() Category of homsets of sets with partial maps """ @@ -1684,7 +1684,7 @@ cdef class pAdicConvert_QQ_FP(Morphism): EXAMPLES:: sage: f = ZpFP(5).convert_map_from(QQ); type(f) - + """ Morphism.__init__(self, Hom(QQ, R, SetsWithPartialMaps())) self._zero = R.element_class(R, 0) @@ -1765,7 +1765,7 @@ cdef class pAdicConvert_QQ_FP(Morphism): sage: R = ZpFP(5,4) sage: type(R(1/7,2)) - + sage: R(1/7,2) 3 + 3*5 sage: R(1/7,3,2) @@ -1820,7 +1820,7 @@ cdef class pAdicCoercion_FP_frac_field(RingHomomorphism): sage: R. = ZqFP(27, implementation='FLINT') sage: K = R.fraction_field() sage: f = K.coerce_map_from(R); type(f) - + """ RingHomomorphism.__init__(self, R.Hom(K)) self._zero = K(0) @@ -1997,7 +1997,7 @@ cdef class pAdicConvert_FP_frac_field(Morphism): sage: R. = ZqFP(27, implementation='FLINT') sage: K = R.fraction_field() sage: f = R.convert_map_from(K); type(f) - + """ Morphism.__init__(self, Hom(K, R, SetsWithPartialMaps())) self._zero = R(0) 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 8d44034b121..9d678d0f11d 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx @@ -1905,7 +1905,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): sage: f = x^5 + 75*x^3 - 15*x^2 +125*x - 5 sage: W. = R.ext(f) sage: type(W(0)) - + sage: W(0)^0 1 + O(w^25) sage: W(0)^0 == W(1) 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 c58954582ea..9b660621dea 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx @@ -718,7 +718,7 @@ cdef class pAdicZZpXFMElement(pAdicZZpXElement): sage: f = x^5 + 75*x^3 - 15*x^2 +125*x - 5 sage: W. = R.ext(f) sage: type(W(0)) - + sage: W(0)^0 1 sage: W(0)^0 == W(1) diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index 4c525237c4f..2a567fce5d4 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -92,11 +92,11 @@ sage: (a * b) // 5^3 1 + 2*5 + O(5^2) sage: type((a * b) // 5^3) - + sage: (a * b) / 5^3 1 + 2*5 + O(5^2) sage: type((a * b) / 5^3) - + The fixed modulus type is the leanest of the p-adic rings: it is basically just a wrapper around `\ZZ / p^n \ZZ` diff --git a/src/sage/rings/padics/padic_capped_absolute_element.pyx b/src/sage/rings/padics/padic_capped_absolute_element.pyx index a34e1b27d77..387dd7c8b65 100644 --- a/src/sage/rings/padics/padic_capped_absolute_element.pyx +++ b/src/sage/rings/padics/padic_capped_absolute_element.pyx @@ -44,7 +44,7 @@ cdef class PowComputer_(PowComputer_base): sage: R = ZpCA(5) sage: type(R.prime_pow) - + sage: R.prime_pow._prec_type 'capped-abs' """ diff --git a/src/sage/rings/padics/padic_capped_relative_element.pyx b/src/sage/rings/padics/padic_capped_relative_element.pyx index c59c8e3573b..bea6c17af19 100644 --- a/src/sage/rings/padics/padic_capped_relative_element.pyx +++ b/src/sage/rings/padics/padic_capped_relative_element.pyx @@ -47,7 +47,7 @@ cdef class PowComputer_(PowComputer_base): sage: R = ZpCR(5) sage: type(R.prime_pow) - + sage: R.prime_pow._prec_type 'capped-rel' """ diff --git a/src/sage/rings/padics/padic_fixed_mod_element.pyx b/src/sage/rings/padics/padic_fixed_mod_element.pyx index 4b2723b7a8a..e012cbba9fc 100644 --- a/src/sage/rings/padics/padic_fixed_mod_element.pyx +++ b/src/sage/rings/padics/padic_fixed_mod_element.pyx @@ -44,7 +44,7 @@ cdef class PowComputer_(PowComputer_base): sage: R = ZpFM(5) sage: type(R.prime_pow) - + sage: R.prime_pow._prec_type 'fixed-mod' """ @@ -152,7 +152,7 @@ cdef class pAdicFixedModElement(FMElement): sage: R = Zp(7,4,'fixed-mod'); a = R(8); a.lift() 8 sage: type(a.lift()) - + """ return self.lift_c() diff --git a/src/sage/rings/padics/padic_floating_point_element.pyx b/src/sage/rings/padics/padic_floating_point_element.pyx index 89132c93025..b3eb407918e 100644 --- a/src/sage/rings/padics/padic_floating_point_element.pyx +++ b/src/sage/rings/padics/padic_floating_point_element.pyx @@ -42,7 +42,7 @@ cdef class PowComputer_(PowComputer_base): sage: R = ZpFP(5) sage: type(R.prime_pow) - + sage: R.prime_pow._prec_type 'floating-point' """ diff --git a/src/sage/rings/padics/padic_template_element.pxi b/src/sage/rings/padics/padic_template_element.pxi index f4629a5d598..b30d8cf0ae9 100644 --- a/src/sage/rings/padics/padic_template_element.pxi +++ b/src/sage/rings/padics/padic_template_element.pxi @@ -89,7 +89,7 @@ cdef class pAdicTemplateElement(pAdicGenericElement): sage: a = Zp(5)(1/2,3); a 3 + 2*5 + 2*5^2 + O(5^3) sage: type(a) - + sage: TestSuite(a).run() TESTS:: @@ -888,7 +888,7 @@ cdef class ExpansionIter(object): sage: E = Zp(5,4)(373).expansion() sage: I = iter(E) # indirect doctest sage: type(I) - + """ cdef pAdicTemplateElement elt cdef celement tmp @@ -1021,7 +1021,7 @@ cdef class ExpansionIterable(object): sage: E = Zp(5,4)(373).expansion() # indirect doctest sage: type(E) - + """ cdef pAdicTemplateElement elt cdef celement tmp @@ -1076,13 +1076,13 @@ cdef class ExpansionIterable(object): sage: E = Zp(5,4)(373).expansion() sage: type(iter(E)) - + sage: E = Zp(5,4)(373).expansion(start_val=-1) sage: type(iter(E)) - + sage: E = Zp(5,4)(373).expansion(start_val=1) sage: type(iter(E)) - + """ cdef ExpansionIter expansion = ExpansionIter(self.elt, self.prec, self.mode) if self.val_shift == 0: diff --git a/src/sage/rings/padics/pow_computer_ext.pyx b/src/sage/rings/padics/pow_computer_ext.pyx index f4e60ee393b..8c08b52e6d8 100644 --- a/src/sage/rings/padics/pow_computer_ext.pyx +++ b/src/sage/rings/padics/pow_computer_ext.pyx @@ -1813,7 +1813,7 @@ cdef class PowComputer_ZZ_pX_small_Eis(PowComputer_ZZ_pX_small): sage: A = PowComputer_ext_maker(5, 10, 10, 40, False, ntl.ZZ_pX([-5,75,15,0,1],5^10), 'small', 'e',ntl.ZZ_pX([1,-15,-3],5^10)) sage: type(A) - + sage: TestSuite(A).run() """ self._ext_type = 'e' @@ -2244,7 +2244,7 @@ cdef class PowComputer_ZZ_pX_big_Eis(PowComputer_ZZ_pX_big): sage: A = PowComputer_ext_maker(5, 3, 10, 40, False, ntl.ZZ_pX([-5,75,15,0,1],5^10), 'big', 'e',ntl.ZZ_pX([1,-15,-3],5^10)) sage: type(A) - + sage: TestSuite(A).run() """ self._ext_type = 'e' diff --git a/src/sage/rings/padics/pow_computer_flint.pyx b/src/sage/rings/padics/pow_computer_flint.pyx index 4d64096e4ee..9f914defcc6 100644 --- a/src/sage/rings/padics/pow_computer_flint.pyx +++ b/src/sage/rings/padics/pow_computer_flint.pyx @@ -41,7 +41,7 @@ cdef class PowComputer_flint(PowComputer_class): sage: from sage.rings.padics.pow_computer_flint import PowComputer_flint sage: type(PowComputer_flint(5, 20, 20, 20, False)) - + """ # fmpz_init does not allocate memory @@ -204,7 +204,7 @@ cdef class PowComputer_flint_1step(PowComputer_flint): sage: R. = ZZ[]; f = x^3 - 8*x - 2 sage: A = PowComputer_flint_1step(5, 20, 20, 20, False, f) sage: type(A) - + """ cdef Polynomial_integer_dense_flint poly = _poly @@ -467,7 +467,7 @@ cdef class PowComputer_flint_unram(PowComputer_flint_1step): sage: R. = ZZ[]; f = x^3 - 8*x - 2 sage: A = PowComputer_flint_unram(5, 20, 20, 20, False, f) sage: type(A) - + """ # fmpz_init does not allocate memory @@ -579,7 +579,7 @@ cdef class PowComputer_flint_eis(PowComputer_flint_1step): sage: R. = ZZ[]; f = x^3 - 25*x + 5 sage: A = PowComputer_flint_eis(5, 20, 20, 60, False, f) sage: type(A) - + """ PowComputer_flint_1step.__init__(self, prime, cache_limit, prec_cap, ram_prec_cap, in_field, poly) @@ -633,11 +633,11 @@ def PowComputer_flint_maker(prime, cache_limit, prec_cap, ram_prec_cap, in_field sage: from sage.rings.padics.pow_computer_flint import PowComputer_flint_maker sage: R. = ZZ[] sage: A = PowComputer_flint_maker(3, 20, 20, 20, False, x^3 + 2*x + 1, 'capped-rel'); type(A) - + sage: A = PowComputer_flint_maker(3, 20, 20, 20, False, x^3 + 2*x + 1, 'capped-abs'); type(A) - + sage: A = PowComputer_flint_maker(3, 20, 20, 20, False, x^3 + 2*x + 1, 'fixed-mod'); type(A) - + """ if prec_type == 'capped-rel': diff --git a/src/sage/rings/padics/qadic_flint_CA.pyx b/src/sage/rings/padics/qadic_flint_CA.pyx index a1ae9a48c0e..d10e4b3eaff 100644 --- a/src/sage/rings/padics/qadic_flint_CA.pyx +++ b/src/sage/rings/padics/qadic_flint_CA.pyx @@ -14,7 +14,7 @@ cdef class PowComputer_(PowComputer_flint_unram): sage: R. = ZqCA(125) sage: type(R.prime_pow) - + sage: R.prime_pow._prec_type 'capped-abs' """ diff --git a/src/sage/rings/padics/qadic_flint_CR.pyx b/src/sage/rings/padics/qadic_flint_CR.pyx index eaedb7a6c12..dfadaa2f053 100644 --- a/src/sage/rings/padics/qadic_flint_CR.pyx +++ b/src/sage/rings/padics/qadic_flint_CR.pyx @@ -14,7 +14,7 @@ cdef class PowComputer_(PowComputer_flint_unram): sage: R. = ZqCR(125) sage: type(R.prime_pow) - + sage: R.prime_pow._prec_type 'capped-rel' """ diff --git a/src/sage/rings/padics/qadic_flint_FM.pyx b/src/sage/rings/padics/qadic_flint_FM.pyx index 9d192addf2a..4f3afe77e81 100644 --- a/src/sage/rings/padics/qadic_flint_FM.pyx +++ b/src/sage/rings/padics/qadic_flint_FM.pyx @@ -14,7 +14,7 @@ cdef class PowComputer_(PowComputer_flint_unram): sage: R. = ZqFM(125) sage: type(R.prime_pow) - + sage: R.prime_pow._prec_type 'fixed-mod' """ diff --git a/src/sage/rings/padics/qadic_flint_FP.pyx b/src/sage/rings/padics/qadic_flint_FP.pyx index 949e132199c..1e250990c4e 100644 --- a/src/sage/rings/padics/qadic_flint_FP.pyx +++ b/src/sage/rings/padics/qadic_flint_FP.pyx @@ -16,7 +16,7 @@ cdef class PowComputer_(PowComputer_flint_unram): sage: R. = ZqFP(125) sage: type(R.prime_pow) - + sage: R.prime_pow._prec_type 'floating-point' """ diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index c0229a7b935..78d63fcf8e5 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1990,7 +1990,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: k = tuple(D)[0] sage: v = D[k] sage: type(k), type(v) - (<... 'tuple'>, ) + (<... 'tuple'>, ) sage: LQ(D) x^-1*y sage: tuple(D)[0] is k diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index e4b64c26a68..3f838d69a30 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -273,9 +273,9 @@ cdef class MPolynomial(CommutativeRingElement): sage: v = K(0) sage: vf = fast_callable(v) sage: type(v(0r, 0r, 0r)) - + sage: type(vf(0r, 0r, 0r)) - + sage: K. = QQ[] sage: from sage.ext.fast_eval import fast_float sage: fast_float(K(0)).op_list() @@ -313,7 +313,7 @@ cdef class MPolynomial(CommutativeRingElement): sage: R. = PolynomialRing(FiniteField(5)) sage: f = x^3*y^5 + x^7*y sage: type(f) - + sage: f.derivative(x) 2*x^6*y - 2*x^2*y^5 sage: f.derivative(y) @@ -1776,9 +1776,9 @@ cdef class MPolynomial(CommutativeRingElement): sage: x.denominator() 1 sage: type(x.denominator()) - + sage: type(a.denominator()) - + sage: from sage.rings.polynomial.multi_polynomial_element import MPolynomial sage: isinstance(a / b, MPolynomial) False diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index cbade28354c..05ba8094a42 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -1002,7 +1002,7 @@ def exponents(self, as_ETuples=True): By default the list of exponents is a list of ETuples:: sage: type(f.exponents()[0]) - + sage: type(f.exponents(as_ETuples=False)[0]) <... 'tuple'> diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index ec706f3129d..49297b16088 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -62,7 +62,7 @@ We show how to construct various multivariate polynomial rings:: sage: P. = Zmod(2521352)[]; P Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 2521352 sage: type(P) - + sage: P. = Zmod(25213521351515232)[]; P Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 25213521351515232 @@ -267,12 +267,12 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: MPolynomialRing_libsingular(QQ, 3, ('x', 'y', 'z'), TermOrder('degrevlex', 3)) Multivariate Polynomial Ring in x, y, z over Rational Field sage: type(_) - + sage: P. = QQ[]; P Multivariate Polynomial Ring in x, y, z over Rational Field sage: type(P) - + """ self._ring = NULL @@ -336,7 +336,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: P. = Zmod(2521352)[]; P Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 2521352 sage: type(P) - + sage: P. = Zmod(25213521351515232)[]; P Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 25213521351515232 @@ -470,7 +470,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): sage: R. = QQ[] sage: type(R) - + sage: R.has_coerce_map_from(ZZ['t']) False sage: R.coerce_map_from(ZZ['x']) @@ -2380,7 +2380,7 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: g = f^(-1); g 1/(x^3 + y) sage: type(g) - + sage: P. = PolynomialRing(ZZ) sage: P(2)**(-1) diff --git a/src/sage/rings/polynomial/multi_polynomial_ring.py b/src/sage/rings/polynomial/multi_polynomial_ring.py index d4c91fbc3f0..88f7fc4ca51 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring.py +++ b/src/sage/rings/polynomial/multi_polynomial_ring.py @@ -251,13 +251,13 @@ def __call__(self, x=0, check=True): sage: x,y,z = var('x,y,z') sage: R = QQ['x,y,z'] sage: type(x) - + sage: type(R(x)) - + sage: f = R(x^3 + y^3 - z^3); f x^3 + y^3 - z^3 sage: type(f) - + sage: parent(f) Multivariate Polynomial Ring in x, y, z over Rational Field diff --git a/src/sage/rings/polynomial/pbori/pbori.pyx b/src/sage/rings/polynomial/pbori/pbori.pyx index b98e726945e..615357f9aac 100644 --- a/src/sage/rings/polynomial/pbori/pbori.pyx +++ b/src/sage/rings/polynomial/pbori/pbori.pyx @@ -1901,7 +1901,7 @@ class BooleanMonomialMonoid(UniqueRepresentation, Monoid_class): sage: M.gens() (x, y) sage: type(M.gen(0)) - + Since :trac:`9138`, boolean monomial monoids are unique parents and are fit into the category framework:: diff --git a/src/sage/rings/polynomial/polynomial_complex_arb.pyx b/src/sage/rings/polynomial/polynomial_complex_arb.pyx index 6f6e45d81ac..3d1f3bebb00 100644 --- a/src/sage/rings/polynomial/polynomial_complex_arb.pyx +++ b/src/sage/rings/polynomial/polynomial_complex_arb.pyx @@ -16,7 +16,7 @@ version 2, or later. TESTS: sage: type(polygen(ComplexBallField(140))) - + sage: Pol. = CBF[] sage: (x+1/2)^3 x^3 + 1.500000000000000*x^2 + 0.7500000000000000*x + 0.1250000000000000 @@ -45,7 +45,7 @@ cdef class Polynomial_complex_arb(Polynomial): sage: Pol. = CBF[] sage: type(x) - + sage: Pol(), Pol(1), Pol([0,1,2]), Pol({1: pi, 3: i}) (0, diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 31fc3613876..680644fcf5a 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -213,7 +213,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: f = x*y; f y*x sage: type(f) - + sage: p = (y+1)^10; p(1) 1024 @@ -3489,7 +3489,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: x.denominator() 1 sage: type(x.denominator()) - + sage: isinstance(x.numerator() / x.denominator(), Polynomial) True sage: isinstance(x.numerator() / R(1), Polynomial) @@ -5711,7 +5711,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: f = y^3 + x*y -3*x; f y^3 + x*y - 3*x sage: type(f) - + sage: v = f.list(); v [-3*x, x, 0, 1] sage: v[0] = 10 @@ -9680,9 +9680,9 @@ cdef class Polynomial(CommutativeAlgebraElement): Test the output type when ``certificate=True``:: sage: type((x^2 - 2).is_cyclotomic(certificate=True)) - + sage: type((x -1).is_cyclotomic(certificate=True)) - + Check that the arguments are forwarded when the input is not a polynomial with coefficients in `\ZZ`:: @@ -10992,7 +10992,7 @@ cdef class Polynomial_generic_dense(Polynomial): Make sure we're testing the right method:: sage: type(f) - + """ return make_generic_polynomial, (self._parent, self.__coeffs) @@ -11300,7 +11300,7 @@ cdef class Polynomial_generic_dense(Polynomial): Check that :trac:`12552` is fixed:: sage: type(f.degree()) - + """ return smallInteger(len(self.__coeffs) - 1) @@ -11317,7 +11317,7 @@ cdef class Polynomial_generic_dense(Polynomial): sage: R. = PolynomialRing(PolynomialRing(QQ,'y'), 'x') sage: p = x^2 + 2*x + 4 sage: type(p) - + sage: p.shift(0) x^2 + 2*x + 4 sage: p.shift(-1) @@ -11474,7 +11474,7 @@ cdef class Polynomial_generic_dense(Polynomial): :: sage: type(f) - + """ l = len(self.__coeffs) if n > l: @@ -11779,7 +11779,7 @@ cdef class ConstantPolynomialSection(Map): From: Univariate Polynomial Ring in y_1 over Finite Field of size 3 To: Finite Field of size 3 sage: type(phi) - + sage: phi(P0.one()) 1 sage: phi(y_1) @@ -11971,7 +11971,7 @@ cdef class PolynomialBaseringInjection(Morphism): From: Univariate Polynomial Ring in x over Real Double Field To: Real Double Field sage: type(m.section()) - + """ return ConstantPolynomialSection(self._codomain, self.domain()) diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx index 112b17e8d24..75f61f37a46 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx @@ -182,11 +182,11 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sage: f = R([-1, 2, 5]); f 5*x^2 + 2*x - 1 sage: type(f) - + sage: type(pari(f)) - + sage: type(R(pari(f))) - + sage: R(pari(f)) 5*x^2 + 2*x - 1 @@ -205,7 +205,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sage: f = (x^3 - 1) / (x - 1) sage: type(f) - + sage: g = R(f); g x^2 + x + 1 @@ -1389,7 +1389,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): TESTS:: sage: type(x.degree()) - + """ return smallInteger(fmpz_poly_degree(self.__poly)) diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx index 75227af230f..160899b6d64 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx @@ -127,11 +127,11 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): sage: f = R([-1, 2, 5]); f 5*x^2 + 2*x - 1 sage: type(f) - + sage: type(pari(f)) - + sage: type(R(pari(f))) - + sage: R(pari(f)) 5*x^2 + 2*x - 1 @@ -150,7 +150,7 @@ cdef class Polynomial_integer_dense_ntl(Polynomial): sage: f = (x^3 - 1) / (x - 1) sage: type(f) - + sage: g = R(f); g x^2 + x + 1 diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring.py b/src/sage/rings/polynomial/polynomial_quotient_ring.py index 4c89ef22db1..b069cdd749c 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring.py @@ -1333,7 +1333,7 @@ def S_class_group(self, S, proof=True): sage: type(CG[0][0][1]) sage: type(CG[0][1]) - + TESTS: @@ -1493,7 +1493,7 @@ def class_group(self, proof=True): sage: type(CG[0][0][1]) sage: type(CG[0][1]) - + """ return self.S_class_group((), proof=proof) @@ -1559,7 +1559,7 @@ def S_units(self, S, proof=True): sage: type(U[0][0]) sage: type(U[0][1]) - + sage: type(U[1][1]) @@ -1645,7 +1645,7 @@ def units(self, proof=True): sage: type(U[0][0]) sage: type(U[0][1]) - + sage: type(U[1][1]) diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pyx b/src/sage/rings/polynomial/polynomial_rational_flint.pyx index 8fd36a34dd0..7c71af6fb75 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pyx @@ -392,7 +392,7 @@ cdef class Polynomial_rational_flint(Polynomial): TESTS:: sage: type(f.degree()) - + """ return smallInteger(fmpq_poly_degree(self.__poly)) diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index 10e852d52f3..e806ae2d228 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -248,7 +248,7 @@ cdef class PolynomialRealDense(Polynomial): TESTS:: sage: type(f.degree()) - + """ return smallInteger(self._degree) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 7cef097c1a8..bab1c470ccb 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -219,7 +219,7 @@ def is_PolynomialRing(x): sage: is_PolynomialRing(R) False sage: type(R) - + """ return isinstance(x, PolynomialRing_general) @@ -1794,12 +1794,12 @@ def __init__(self, base_ring, name="x", sparse=False, implementation=None, sage: R = PRing(ZZ, 'x'); R Univariate Polynomial Ring in x over Integer Ring sage: type(R.gen()) - + sage: R = PRing(ZZ, 'x', implementation='NTL'); R Univariate Polynomial Ring in x over Integer Ring (using NTL) sage: type(R.gen()) - + """ self._implementation_repr = '' if element_class is None: @@ -1964,7 +1964,7 @@ def __init__(self, base_ring, name="x", sparse=False, element_class=None, catego sage: R = PRing(QQ, 'x'); R Univariate Polynomial Ring in x over Rational Field sage: type(R.gen()) - + sage: R = PRing(QQ, 'x', sparse=True); R Sparse Univariate Polynomial Ring in x over Rational Field sage: type(R.gen()) @@ -2384,7 +2384,7 @@ def __init__(self, base_ring, name="x", element_class=None, implementation=None) sage: S = PolynomialRing_dense_finite_field(GF(25, 'a'), implementation='NTL') sage: type(S(0)) - + sage: S = PolynomialRing_dense_finite_field(GF(64), implementation='superfast') Traceback (most recent call last): @@ -2976,17 +2976,17 @@ def __init__(self, base_ring, name=None, element_class=None, sage: R = PRing(Zmod(15), 'x'); R Univariate Polynomial Ring in x over Ring of integers modulo 15 sage: type(R.gen()) - + sage: R = PRing(Zmod(15), 'x', implementation='NTL'); R Univariate Polynomial Ring in x over Ring of integers modulo 15 (using NTL) sage: type(R.gen()) - + sage: R = PRing(Zmod(2**63*3), 'x', implementation='NTL'); R Univariate Polynomial Ring in x over Ring of integers modulo 27670116110564327424 (using NTL) sage: type(R.gen()) - + sage: R = PRing(Zmod(2**63*3), 'x', implementation='FLINT') Traceback (most recent call last): @@ -2996,7 +2996,7 @@ def __init__(self, base_ring, name=None, element_class=None, sage: R = PRing(Zmod(2**63*3), 'x'); R Univariate Polynomial Ring in x over Ring of integers modulo 27670116110564327424 (using NTL) sage: type(R.gen()) - + """ if element_class is None: implementation = self._implementation_names(implementation, base_ring)[0] @@ -3131,24 +3131,24 @@ def __init__(self, base_ring, name="x", implementation=None, category=None): sage: P = GF(2)['x']; P Univariate Polynomial Ring in x over Finite Field of size 2 (using GF2X) sage: type(P.gen()) - + sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_dense_mod_p sage: P = PolynomialRing_dense_mod_p(GF(5), 'x'); P Univariate Polynomial Ring in x over Finite Field of size 5 sage: type(P.gen()) - + sage: P = PolynomialRing_dense_mod_p(GF(5), 'x', implementation='NTL'); P Univariate Polynomial Ring in x over Finite Field of size 5 (using NTL) sage: type(P.gen()) - + sage: P = PolynomialRing_dense_mod_p(GF(9223372036854775837), 'x') sage: P Univariate Polynomial Ring in x over Finite Field of size 9223372036854775837 (using NTL) sage: type(P.gen()) - + This caching bug was fixed in :trac:`24264`:: diff --git a/src/sage/rings/polynomial/polynomial_ring_constructor.py b/src/sage/rings/polynomial/polynomial_ring_constructor.py index c88f6705ccd..0c96760861c 100644 --- a/src/sage/rings/polynomial/polynomial_ring_constructor.py +++ b/src/sage/rings/polynomial/polynomial_ring_constructor.py @@ -426,7 +426,7 @@ def PolynomialRing(base_ring, *args, **kwds): sage: R = PolynomialRing(ZZ, 'x,y', implementation="generic"); type(R) sage: S = PolynomialRing(ZZ, 'x,y'); type(S) - + Sparse univariate polynomials only support a generic implementation:: diff --git a/src/sage/rings/polynomial/polynomial_zmod_flint.pyx b/src/sage/rings/polynomial/polynomial_zmod_flint.pyx index fc7898dde64..18d04f404d8 100644 --- a/src/sage/rings/polynomial/polynomial_zmod_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_zmod_flint.pyx @@ -16,10 +16,10 @@ EXAMPLES:: sage: R. = PolynomialRing(Integers(100)) sage: type(a) - + sage: R. = PolynomialRing(Integers(5*2^64)) sage: type(a) - + sage: R. = PolynomialRing(Integers(5*2^64), implementation="FLINT") Traceback (most recent call last): ... diff --git a/src/sage/rings/power_series_pari.pyx b/src/sage/rings/power_series_pari.pyx index b4d32da0b98..038c66dd1b7 100644 --- a/src/sage/rings/power_series_pari.pyx +++ b/src/sage/rings/power_series_pari.pyx @@ -18,21 +18,21 @@ not the type of the parents:: sage: type(R) sage: type(q) - + sage: type(S) sage: type(t) - + If `k` is a finite field implemented using PARI, this is the default implementation for power series over `k`:: sage: k. = GF(5^12) sage: type(c) - + sage: A. = k[[]] sage: type(x) - + .. WARNING:: diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index a021390d012..71ff6407c18 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -1005,7 +1005,7 @@ cdef class PowerSeries(AlgebraElement): sage: t.inverse() t^-1 sage: type(_) - + sage: (1-t).inverse() 1 + t + t^2 + t^3 + t^4 + t^5 + t^6 + t^7 + t^8 + ... """ diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index e75d09d58f0..87e59a14ab1 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -5210,7 +5210,7 @@ def _ensure_real(self): sage: b._value 0.7071067811865475244? sage: type(b._value) - + """ if is_ComplexIntervalFieldElement(self._value): self._value = self._value.real() diff --git a/src/sage/rings/quotient_ring_element.py b/src/sage/rings/quotient_ring_element.py index af2b3d43bb4..8d09a28f6ba 100644 --- a/src/sage/rings/quotient_ring_element.py +++ b/src/sage/rings/quotient_ring_element.py @@ -506,7 +506,7 @@ def _rational_(self): TESTS:: sage: type(S(-2/3)._rational_()) - + """ from sage.rings.rational_field import QQ return QQ(self.lift()) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 2be63156923..6e02cf4387d 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -404,7 +404,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: a = -2/3 sage: type(a) - + sage: parent(a) Rational Field sage: Rational('1/0') @@ -2526,7 +2526,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: a = (0/1)^(0/1); a 1 sage: type(a) - + If the result is rational, it is returned as a rational:: @@ -2562,7 +2562,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: a = int(2)^(3/1); a 8 sage: type(a) - + The exponent must fit in a long unless the base is -1, 0, or 1:: @@ -3482,7 +3482,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: (0/1)._lcm(0/1) 0 sage: type((2/3)._lcm(3/5)) - + """ if mpz_cmp_si(mpq_numref(self.value), 0) == 0 and \ mpz_cmp_si(mpq_numref(other.value), 0) == 0: @@ -3773,7 +3773,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: m = n.__pari__(); m 9390823/17 sage: type(m) - + sage: m.type() 't_FRAC' """ @@ -4148,7 +4148,7 @@ cdef class Q_to_Z(Map): TESTS:: sage: type(ZZ.convert_map_from(QQ)) - + """ cpdef Element _call_(self, x): """ diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 059593e3836..fbd0fd79d65 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -173,7 +173,7 @@ def __init__(self): sage: Q('49/7') 7 sage: type(Q('49/7')) - + sage: a = Q('19/374'); a 19/374 sage: b = Q('17/371'); b diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 72164d0ec13..eb0e513c70a 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -2548,7 +2548,7 @@ cdef class RealBall(RingElement): sage: RBF(sqrt(2)).contains_exact(sqrt(2)) Traceback (most recent call last): ... - TypeError: unsupported type: + TypeError: unsupported type: TESTS:: diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index 7356600a482..4e0a8136cdb 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -1223,7 +1223,7 @@ cdef class RealDoubleElement(FieldElement): sage: a = r.integer_part(); a -1 sage: type(a) - + sage: r = RDF(0.0/0.0) sage: a = r.integer_part() Traceback (most recent call last): diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index 24b679f8935..1ac123cfdb3 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -1709,7 +1709,7 @@ cdef class LazyWrapperMorphism(Morphism): sage: a = f(3); a 3 sage: type(a) - + sage: a._value 3 sage: a._value.parent() @@ -1727,7 +1727,7 @@ cdef class LazyWrapperMorphism(Morphism): sage: a = f(1/3); a # indirect doctest 0.3333333333333334? sage: type(a) - + sage: Reals(100)(a) 0.33333333333333333333333333333 diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index 5d4557a6d37..326a071b655 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -5366,7 +5366,7 @@ cdef class RealNumber(sage.structure.element.RingElement): :: sage: type(z) - + sage: R(z) 1.64493406684823 """ @@ -5753,9 +5753,9 @@ cdef class RealLiteral(RealNumber): The result is a non-literal:: sage: type(1.3) - + sage: type(n(1.3)) - + """ if prec is None: prec = digits_to_bits(digits) diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 7cc9c6d3f70..562dd5cd2ff 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -1406,9 +1406,9 @@ cdef class CommutativeRing(Ring): sage: ZZ.krull_dimension() 1 sage: type(R); type(QQ); type(ZZ) - + - + All orders in number fields have Krull dimension 1, including non-maximal orders:: @@ -2049,7 +2049,7 @@ cdef class PrincipalIdealDomain(IntegralDomain): sage: QQ.gcd(ZZ(42), ZZ(48)); type(QQ.gcd(ZZ(42), ZZ(48))) 6 - + sage: QQ.gcd(1/2, 1/3) 1/6 @@ -2091,7 +2091,7 @@ cdef class PrincipalIdealDomain(IntegralDomain): sage: QQ.content(ZZ(42), ZZ(48)); type(QQ.content(ZZ(42), ZZ(48))) 6 - + sage: QQ.content(1/2, 1/3) 1/6 sage: factor(1/2); factor(1/3); factor(1/6) diff --git a/src/sage/rings/ring_extension.pyx b/src/sage/rings/ring_extension.pyx index 754b8c2ca63..640971fb47e 100644 --- a/src/sage/rings/ring_extension.pyx +++ b/src/sage/rings/ring_extension.pyx @@ -507,7 +507,7 @@ cdef class RingExtension_generic(CommutativeAlgebra): Rational Field over its base sage: type(Q) - + sage: TestSuite(Q).run() @@ -705,7 +705,7 @@ cdef class RingExtension_generic(CommutativeAlgebra): sage: K = GF(7^3).over() sage: type(K) - + sage: loads(dumps(K)) is K True """ @@ -841,7 +841,7 @@ cdef class RingExtension_generic(CommutativeAlgebra): sage: E.print_options(over=ZZ) Traceback (most recent call last): ... - TypeError: unable to coerce to an integer + TypeError: unable to coerce to an integer """ if over is not None and over is not Infinity: over = ZZ(over) @@ -1900,7 +1900,7 @@ cdef class RingExtensionFractionField(RingExtension_generic): Fraction Field of Integer Ring over its base sage: type(Q) - + sage: TestSuite(Q).run() @@ -2457,7 +2457,7 @@ cdef class RingExtensionWithGen(RingExtensionWithBasis): sage: K = A.over() sage: type(K) - + sage: TestSuite(K).run() diff --git a/src/sage/rings/ring_extension_conversion.pyx b/src/sage/rings/ring_extension_conversion.pyx index f432faf8bb2..36e12b8fcac 100644 --- a/src/sage/rings/ring_extension_conversion.pyx +++ b/src/sage/rings/ring_extension_conversion.pyx @@ -198,7 +198,7 @@ cdef _backend_morphism(f): sage: K. = GF(7^3).over() sage: f = End(K)(Frob) sage: type(f) - + sage: backend_morphism(f) == Frob # indirect doctest True @@ -219,7 +219,7 @@ cdef _backend_morphism(f): sage: iota = End(K).identity() sage: type(iota) - + sage: backend_morphism(iota) Identity endomorphism of Finite Field in z3 of size 7^3 """ diff --git a/src/sage/rings/ring_extension_element.pyx b/src/sage/rings/ring_extension_element.pyx index 1f34ba48078..610291dc620 100644 --- a/src/sage/rings/ring_extension_element.pyx +++ b/src/sage/rings/ring_extension_element.pyx @@ -91,7 +91,7 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): sage: K = GF(5^3).over() sage: x = K.random_element() sage: type(x) - + sage: loads(dumps(x)) == x True """ @@ -566,7 +566,7 @@ cdef class RingExtensionFractionFieldElement(RingExtensionElement): sage: Q = Z.fraction_field() sage: x = Q.random_element() sage: type(x) - + sage: TestSuite(x).run() """ def __hash__(self): @@ -733,7 +733,7 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): sage: K. = GF(5^3).over() sage: L. = GF(5^9).over(K) sage: type(b) - + sage: TestSuite(b).run() """ def __hash__(self): diff --git a/src/sage/rings/ring_extension_morphism.pyx b/src/sage/rings/ring_extension_morphism.pyx index 463a07276a6..c5e6b556e56 100644 --- a/src/sage/rings/ring_extension_morphism.pyx +++ b/src/sage/rings/ring_extension_morphism.pyx @@ -93,7 +93,7 @@ cdef class RingExtensionHomomorphism(RingMap): a |--> 1 - a sage: type(phi) - + sage: TestSuite(phi).run() @@ -546,7 +546,7 @@ cdef class RingExtensionBackendIsomorphism(RingExtensionHomomorphism): To: Field in z9 with defining polynomial x^3 + (9*z3^2 + 5*z3 + 1)*x^2 + (4*z3 + 3)*x + 10*z3 over its base sage: type(f) - + sage: TestSuite(f).run() """ @@ -637,7 +637,7 @@ cdef class RingExtensionBackendReverseIsomorphism(RingExtensionHomomorphism): To: Finite Field in z9 of size 11^9 sage: type(f) - + sage: TestSuite(f).run() @@ -723,7 +723,7 @@ cdef class MapFreeModuleToRelativeRing(Map): sage: K = GF(5^2).over() sage: V, i, j = K.free_module() sage: type(i) - + """ def __init__(self, E, K): @@ -810,7 +810,7 @@ cdef class MapRelativeRingToFreeModule(Map): sage: K = GF(5^2).over() sage: V, i, j = K.free_module() sage: type(j) - + """ def __init__(self, E, K): diff --git a/src/sage/rings/semirings/non_negative_integer_semiring.py b/src/sage/rings/semirings/non_negative_integer_semiring.py index 6f80d4749c9..ea3bce495d9 100644 --- a/src/sage/rings/semirings/non_negative_integer_semiring.py +++ b/src/sage/rings/semirings/non_negative_integer_semiring.py @@ -53,7 +53,7 @@ class NonNegativeIntegerSemiring(NonNegativeIntegers): Sage ``Integers`` with ``Integer Ring`` as parent:: sage: x = NN(15); type(x) - + sage: x.parent() Integer Ring sage: x+3 diff --git a/src/sage/rings/universal_cyclotomic_field.py b/src/sage/rings/universal_cyclotomic_field.py index 9c7ed719378..61d21e1acb9 100644 --- a/src/sage/rings/universal_cyclotomic_field.py +++ b/src/sage/rings/universal_cyclotomic_field.py @@ -1477,7 +1477,7 @@ def _element_constructor_(self, elt): Traceback (most recent call last): ... TypeError: [ [ 0, 1 ], [ 0, 2 ] ] - of type not valid + of type not valid to initialize an element of the universal cyclotomic field Some conversions from symbolic functions are possible:: From 119f105d5fe385f11f55c7e632006e9fe49d4806 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Wed, 13 Oct 2021 22:25:02 +0200 Subject: [PATCH 395/511] Trac 32685: Fix y label in set_axes_labels --- src/sage/manifolds/utilities.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/manifolds/utilities.py b/src/sage/manifolds/utilities.py index ae729e33206..a95c9e8d13d 100644 --- a/src/sage/manifolds/utilities.py +++ b/src/sage/manifolds/utilities.py @@ -1270,11 +1270,10 @@ def set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds): y1 = ymin + dy / 2 z1 = zmin + dz / 2 xmin1 = xmin - dx / 20 - xmax1 = xmax + dx / 20 ymin1 = ymin - dy / 20 zmin1 = zmin - dz / 20 graph += text3d(' ' + xlabel, (x1, ymin1, zmin1), **kwds) - graph += text3d(' ' + ylabel, (xmax1, y1, zmin1), **kwds) + graph += text3d(' ' + ylabel, (xmin1, y1, zmin1), **kwds) graph += text3d(' ' + zlabel, (xmin1, ymin1, z1), **kwds) return graph From 8cc350081bebd83ea605e62adde3bb07347bbfca Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 13 Oct 2021 14:35:27 -0700 Subject: [PATCH 396/511] src/sage/rings/polynomial/polynomial_singular_interface.py: Fixup merge --- src/sage/rings/polynomial/polynomial_singular_interface.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index b0e067f1f78..cd0ff7a33a1 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -384,7 +384,6 @@ def can_convert_to_singular(R): if (base_ring is ZZ or sage.rings.finite_rings.finite_field_constructor.is_FiniteField(base_ring) or is_RationalField(base_ring) - or is_IntegerModRing(base_ring) or isinstance(base_ring, (sage.rings.abc.RealField, sage.rings.abc.ComplexField, sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField, sage.rings.abc.IntegerModRing))): From d314399aeb258a26bdc3e5540b3db13f147dd644 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 26 Jul 2021 22:00:43 -0400 Subject: [PATCH 397/511] Trac #15219: add test for numerical_integral() of symbolic functions. The switch from fast_float() to fast_callable() in Trac 32234 also happened to fix the issue reported in Trac 15219, namely the inability to integrate symbolic functions by name. Here we add a doctest for the correct behavior. --- src/sage/calculus/integration.pyx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index 93a3681854d..eab8d3834ba 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -250,6 +250,14 @@ def numerical_integral(func, a, b=None, Traceback (most recent call last): ... ValueError: integral does not converge at -infinity + + Symbolic functions can be integrated as conveniently as symbolic + expressions, as in :trac:`15219`:: + + sage: h(x) = x + sage: numerical_integral(h,0,1)[0] # abs tol 1e-8 + 0.5 + """ cdef double abs_err # step size cdef double result From 3bbc5d8fb9aa3abc81fe2a46da52312b843c796e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 13 Oct 2021 19:30:46 -0700 Subject: [PATCH 398/511] build/pkgs/python3/spkg-build.in: Set rpath --- build/pkgs/python3/spkg-build.in | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/build/pkgs/python3/spkg-build.in b/build/pkgs/python3/spkg-build.in index b75958ab0fd..e45e4805ff6 100644 --- a/build/pkgs/python3/spkg-build.in +++ b/build/pkgs/python3/spkg-build.in @@ -90,7 +90,18 @@ sdh_configure --enable-shared $PYTHON_CONFIGURE # we need to provide paths into $SAGE_LOCAL, so that setup.py finds # the libraries needed for the extension modules - in particular sqlite3. # (The search code there does not know about CPATH and LIBRARY_PATH.) -sdh_make LDFLAGS="-L. -L$SAGE_LOCAL/lib $LDFLAGS" CPPFLAGS="-I$SAGE_LOCAL/include $CPPFLAGS" +make_LDFLAGS="-L. -L$SAGE_LOCAL/lib $LDFLAGS" +make_CPPFLAGS="-I$SAGE_LOCAL/include $CPPFLAGS" + +# Also, we need to add an rpath, like we do for SAGE_LOCAL in src/bin/sage-env. +# SAGE_INST_LOCAL is the installation hierarchy for the current package +# -- for python3, this is SAGE_VENV. +make_LDFLAGS="-Wl,-rpath,$SAGE_INST_LOCAL/lib $make_LDFLAGS" +if [ "$UNAME" = "Linux" ]; then + make_LDFLAGS="-Wl,-rpath-link,$SAGE_INST_LOCAL/lib $make_LDFLAGS" +fi + +sdh_make LDFLAGS="$make_LDFLAGS" CPPFLAGS="$make_CPPFLAGS" if [ "$UNAME" = "Darwin" ]; then export DYLD_LIBRARY_PATH="." From 565546641bf8690e5a3da04f9d0d7819d2de50e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 14 Oct 2021 09:49:22 +0200 Subject: [PATCH 399/511] add factor method to Tamari Interval Poset --- src/sage/combinat/interval_posets.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index ed2de3bd9ce..98abeaa6427 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -597,6 +597,34 @@ def _mul_(self, other: TIP) -> TIP: format='vertices_and_edges')) return TamariIntervalPoset(P, check=False) # type:ignore + def factor(self) -> list[TamariIntervalPoset]: + """ + Return the decomposition as a list of connected components. + + EXAMPLES:: + + sage: factor(TamariIntervalPoset(2,[])) # indirect doctest + [The Tamari interval of size 1 induced by relations [], + The Tamari interval of size 1 induced by relations []] + + .. SEEALSO:: :meth:`is_connected` + + TESTS:: + + sage: T = TamariIntervalPosets(20).random_element() + sage: T == prod(factor(T)) + True + """ + hasse = self.poset().hasse_diagram() + cc = hasse.connected_components_subgraphs() + resu = [] + for comp in sorted(cc, key=min): + shift = 1 - min(comp) + comp.relabel(lambda i: i + shift) + resu.append(TamariIntervalPoset(len(comp), + comp.edges(labels=False))) + return resu + def __hash__(self): """ Return the hash of ``self``. From f630951d2366b48e073e2fa57cc7f2e398cf88e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 13 Oct 2021 20:16:04 +0200 Subject: [PATCH 400/511] various details in combinat and functions --- .../combinat/crystals/elementary_crystals.py | 60 ++++++++++--------- src/sage/combinat/words/abstract_word.py | 27 ++++----- src/sage/combinat/words/suffix_trees.py | 13 ++-- src/sage/functions/generalized.py | 11 ++-- src/sage/functions/jacobi.py | 13 ++-- src/sage/manifolds/subsets/pullback.py | 3 +- 6 files changed, 62 insertions(+), 65 deletions(-) diff --git a/src/sage/combinat/crystals/elementary_crystals.py b/src/sage/combinat/crystals/elementary_crystals.py index 83f1f1fd86a..632623f39c4 100644 --- a/src/sage/combinat/crystals/elementary_crystals.py +++ b/src/sage/combinat/crystals/elementary_crystals.py @@ -53,7 +53,7 @@ - [NZ1997]_ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Ben Salisbury # # Distributed under the terms of the GNU General Public License (GPL) @@ -65,8 +65,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#**************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** from sage.categories.crystals import Crystals from sage.categories.finite_crystals import FiniteCrystals @@ -88,7 +88,7 @@ class AbstractSingleCrystalElement(Element): r""" Abstract base class for elements in crystals with a single element. """ - def __lt__(self,other): + def __lt__(self, other): r""" EXAMPLES:: @@ -113,7 +113,7 @@ def __hash__(self): """ return hash(self.parent()) - def __eq__(self,other): + def __eq__(self, other): r""" EXAMPLES:: @@ -141,7 +141,7 @@ def __eq__(self,other): return self.parent() is other.parent() return False - def __ne__(self,other): + def __ne__(self, other): r""" EXAMPLES:: @@ -154,7 +154,7 @@ def __ne__(self,other): """ return not self == other - def e(self,i): + def e(self, i): r""" Return `e_i` of ``self``, which is ``None`` for all `i`. @@ -173,7 +173,7 @@ def e(self,i): """ return None - def f(self,i): + def f(self, i): r""" Return `f_i` of ``self``, which is ``None`` for all `i`. @@ -192,6 +192,7 @@ def f(self,i): """ return None + class TCrystal(UniqueRepresentation, Parent): r""" The crystal `T_{\lambda}`. @@ -289,7 +290,7 @@ def _repr_(self): sage: B The T crystal of type ['E', 6] and weight Lambda[6] """ - return "The T crystal of type {1!s} and weight {0!s}".format(self._weight,self._cartan_type) + return "The T crystal of type {1!s} and weight {0!s}".format(self._weight, self._cartan_type) def _element_constructor_(self, weight): r""" @@ -307,7 +308,7 @@ def _element_constructor_(self, weight): Lambda[7] + Lambda[8] """ if weight != self._weight: - raise ValueError("Only element is t(%s)"%self._weight) + raise ValueError("Only element is t(%s)" % self._weight) return self.element_class(self) def cardinality(self): @@ -375,9 +376,9 @@ def _latex_(self): sage: latex(t) {t_{-e_{0} - 3e_{1} - 3e_{2} - 3e_{deltacheck}}} """ - return "{t_{"+self.parent()._weight._latex_()+"}}" + return "{t_{" + self.parent()._weight._latex_() + "}}" - def epsilon(self,i): + def epsilon(self, i): r""" Return `\varepsilon_i` of ``self``, which is `-\infty` for all `i`. @@ -396,7 +397,7 @@ def epsilon(self,i): """ return float("-inf") - def phi(self,i): + def phi(self, i): r""" Return `\varphi_i` of ``self``, which is `-\infty` for all `i`. @@ -430,6 +431,7 @@ def weight(self): """ return self.parent()._weight + class RCrystal(UniqueRepresentation, Parent): r""" The crystal `R_{\lambda}`. @@ -568,7 +570,7 @@ def _element_constructor_(self, weight): Lambda[7] + Lambda[8] """ if weight != self._weight: - raise ValueError("Only element is r(%s)"%self._weight) + raise ValueError("Only element is r(%s)" % self._weight) return self.element_class(self) def cardinality(self): @@ -640,8 +642,8 @@ def _latex_(self): {r^{\vee}_{\Lambda_{1}}} """ if self.parent()._dual: - return r"{r^{\vee}_{"+self.parent()._weight._latex_()+"}}" - return "{r_{"+self.parent()._weight._latex_()+"}}" + return r"{r^{\vee}_{" + self.parent()._weight._latex_() + "}}" + return "{r_{" + self.parent()._weight._latex_() + "}}" def epsilon(self, i): r""" @@ -798,10 +800,10 @@ def __init__(self, cartan_type, i): sage: B = crystals.elementary.Elementary("D4",3) sage: TestSuite(B).run() """ - Parent.__init__(self, category = (Crystals(), InfiniteEnumeratedSets())) + Parent.__init__(self, category=(Crystals(), InfiniteEnumeratedSets())) self._i = i self._cartan_type = cartan_type - self.module_generators = (self.element_class(self,0),) + self.module_generators = (self.element_class(self, 0),) def _repr_(self): r""" @@ -813,7 +815,7 @@ def _repr_(self): sage: B The 4-elementary crystal of type ['B', 5, 1] """ - return "The {0!s}-elementary crystal of type {1!s}".format(self._i,self._cartan_type) + return "The {0!s}-elementary crystal of type {1!s}".format(self._i, self._cartan_type) def _element_constructor_(self, m): r""" @@ -883,7 +885,7 @@ def _repr_(self): """ return repr(self._m) - def __lt__(self,other): + def __lt__(self, other): r""" EXAMPLES:: @@ -899,7 +901,7 @@ def __lt__(self,other): return False return Integer(self._m) < Integer(other._m) - def __eq__(self,other): + def __eq__(self, other): r""" EXAMPLES:: @@ -915,7 +917,7 @@ def __eq__(self,other): return self.parent() is other.parent() and self._m == other._m return False - def __ne__(self,other): + def __ne__(self, other): r""" EXAMPLES:: @@ -937,9 +939,9 @@ def _latex_(self): sage: latex(B(26)) {b_{6}(26)} """ - return "{b_{%s}(%s)}"%(self.parent()._i, self._m) + return "{b_{%s}(%s)}" % (self.parent()._i, self._m) - def e(self,i): + def e(self, i): r""" Return the action of `e_i` on ``self``. @@ -957,7 +959,7 @@ def e(self,i): sage: B(0).e(2) """ if i == self.parent()._i: - return self.__class__(self.parent(), self._m+1) + return self.__class__(self.parent(), self._m + 1) else: return None @@ -979,7 +981,7 @@ def f(self, i): sage: B(0).e(2) """ if i == self.parent()._i: - return self.__class__(self.parent(), self._m-1) + return self.__class__(self.parent(), self._m - 1) else: return None @@ -1042,6 +1044,7 @@ def weight(self): Q = self.parent().weight_lattice_realization() return self._m * Q.simple_root(self.parent()._i) + class ComponentCrystal(UniqueRepresentation, Parent): r""" The component crystal. @@ -1193,7 +1196,7 @@ def _latex_(self): """ return "{c}" - def epsilon(self,i): + def epsilon(self, i): r""" Return `\varepsilon_i` of ``self``, which is `0` for all `i`. @@ -1210,7 +1213,7 @@ def epsilon(self,i): """ return 0 - def phi(self,i): + def phi(self, i): r""" Return `\varphi_i` of ``self``, which is `0` for all `i`. @@ -1239,4 +1242,3 @@ def weight(self): (0, 0, 0, 0) """ return self.parent().weight_lattice_realization().zero() - diff --git a/src/sage/combinat/words/abstract_word.py b/src/sage/combinat/words/abstract_word.py index fc0b731ac12..33261cad6f2 100644 --- a/src/sage/combinat/words/abstract_word.py +++ b/src/sage/combinat/words/abstract_word.py @@ -6,7 +6,7 @@ AUTHORS: -- Sebastien Labbe +- Sébastien Labbé - Franco Saliola EXAMPLES:: @@ -20,7 +20,7 @@ sage: p.length() 231 """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008-2010 Sebastien Labbe , # 2008-2010 Franco Saliola # @@ -28,8 +28,8 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.sage_object import SageObject from sage.combinat.words.word_options import word_options @@ -127,7 +127,7 @@ def string_rep(self): if word_options['display'] == 'string': ls = word_options['letter_separator'] letters = [str(_) for _ in letters] - if all(len(a)==1 for a in letters): + if all(len(a) == 1 for a in letters): return ''.join(letters) + suffix elif suffix == "...": return ls.join(letters) + ls + suffix @@ -349,7 +349,7 @@ def __richcmp__(self, other, op): cs = next(self_it) except StopIteration: try: - co = next(other_it) + next(other_it) except StopIteration: # If both self_it and other_it are exhausted then # self == other. Return 0. @@ -631,7 +631,7 @@ def _to_integer_iterator(self, use_parent_alphabet=False): """ from sage.combinat.words.words import FiniteWords, InfiniteWords if use_parent_alphabet and\ - isinstance(self.parent(), (FiniteWords,InfiniteWords)): + isinstance(self.parent(), (FiniteWords, InfiniteWords)): A = self.parent().alphabet() for letter in self: yield A.rank(letter) @@ -1161,8 +1161,8 @@ def prefixes_iterator(self, max_length=None): """ to_consider = self if max_length is None else self[:max_length] yield self[:0] - for (i,a) in enumerate(to_consider): - yield self[:i+1] + for (i, a) in enumerate(to_consider): + yield self[:i + 1] def palindrome_prefixes_iterator(self, max_length=None): r""" @@ -1244,7 +1244,7 @@ def _partial_sums_iterator(self, start, mod=None): sum = Zn(start) else: - raise TypeError('mod(=%s) must be None or an integer'%mod) + raise TypeError('mod(=%s) must be None or an integer' % mod) yield sum for letter in self: @@ -1385,7 +1385,7 @@ def _finite_differences_iterator(self, mod=None): return else: - raise TypeError('mod(=%s) must be None or an integer'%mod) + raise TypeError('mod(=%s) must be None or an integer' % mod) def finite_differences(self, mod=None): r""" @@ -1529,7 +1529,7 @@ def sum_digits(self, base=2, mod=None): elif mod in ZZ and mod >= 2: alphabet = list(range(mod)) else: - raise ValueError("base (=%s) and mod (=%s) must be integers greater or equal to 2"%(base, mod)) + raise ValueError("base (=%s) and mod (=%s) must be integers greater or equal to 2" % (base, mod)) # The iterator f = partial(words._ThueMorseWord_nth_digit, alphabet=alphabet, base=base) @@ -1609,7 +1609,7 @@ def first_occurrence(self, other, start=0): for j in range(lf-1, -1, -1): a = self[s+j] if other[j] != a: - s += max(suff[j + 1], j - occ.get(a,-1)) + s += max(suff[j + 1], j - occ.get(a, -1)) break else: return s @@ -1754,4 +1754,3 @@ def complete_return_words_iterator(self, fact): i = j except StopIteration: return - diff --git a/src/sage/combinat/words/suffix_trees.py b/src/sage/combinat/words/suffix_trees.py index 3eebe3efe08..de5761e2901 100644 --- a/src/sage/combinat/words/suffix_trees.py +++ b/src/sage/combinat/words/suffix_trees.py @@ -1186,34 +1186,33 @@ def number_of_factors(self,n=None): """ if n is None: length_word = self.word().length() - num_factors = 1 # empty word - for (u,v,(i,j)) in self.edge_iterator(): + num_factors = 1 # empty word + for (u, v, (i, j)) in self.edge_iterator(): if j is None: num_factors += length_word - i else: num_factors += j - i elif isinstance(n, (int, Integer)): - length_word = self.word().length() num_factors = 0 queue = [(0, 0)] while queue: - (v,l) = queue.pop() + (v, l) = queue.pop() if l == n: num_factors += 1 if l < n: if self._transition_function[v] != {}: - for ((i,j),u) in self._transition_function[v].items(): + for ((i, j), u) in self._transition_function[v].items(): if j is None: j = self.word().length() if j - i >= n - l: num_factors += 1 else: - queue.append((u,l+j-i+1)) + queue.append((u, l + j - i + 1)) else: raise TypeError("not an integer or None: %s" % n) return num_factors - def factor_iterator(self,n=None): + def factor_iterator(self, n=None): r""" Generate distinct factors of ``self``. diff --git a/src/sage/functions/generalized.py b/src/sage/functions/generalized.py index 6c38ef5621c..8c3f3fcf9b9 100644 --- a/src/sage/functions/generalized.py +++ b/src/sage/functions/generalized.py @@ -592,7 +592,7 @@ def _eval_(self, m, n): Kronecker delta is a symmetric function. We keep arguments sorted to ensure that k_d(m, n) - k_d(n, m) cancels automatically:: - sage: x,y=var('x,y') + sage: x,y = var('x,y') sage: kronecker_delta(x, y) kronecker_delta(x, y) sage: kronecker_delta(y, x) @@ -621,17 +621,14 @@ def _evalf_(self, m, n, **kwds): """ if bool(repr(m) > repr(n)): return kronecker_delta(n, m) - x = m - n approx_x = ComplexIntervalField()(x) - if bool(approx_x.imag() == 0): # x is real - if bool(approx_x.real() == 0): # x is zero + if approx_x.imag() == 0: # x is real + if approx_x.real() == 0: # x is zero return 1 else: return 0 - else: - return 0 # x is complex - raise ValueError("Numeric evaluation of symbolic expression") + return 0 # x is complex def _derivative_(self, *args, **kwds): """ diff --git a/src/sage/functions/jacobi.py b/src/sage/functions/jacobi.py index b61892dda09..39db1ed8efb 100644 --- a/src/sage/functions/jacobi.py +++ b/src/sage/functions/jacobi.py @@ -136,17 +136,15 @@ - Eviatar Bach (2013): complete rewrite, new numerical evaluation, and addition of the Jacobi amplitude function """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 David Joyner # Copyright (C) 2013 Eviatar Bach # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** - +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.symbolic.function import BuiltinFunction from sage.functions.trig import (arctan, arcsin, arccos, arccot, arcsec, arccsc, csc, sec, sin, cos, tan, cot) @@ -977,6 +975,7 @@ def jacobi(kind, z, m, **kwargs): raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") + def inverse_jacobi(kind, x, m, **kwargs): r""" The inverses of the 12 Jacobi elliptic functions. They have the property @@ -1135,6 +1134,7 @@ def _print_latex_(self, x, m): return r"\operatorname{{am}}\left({}\middle|{}\right)".format(latex(x), latex(m)) + jacobi_am = JacobiAmplitude() @@ -1293,7 +1293,7 @@ def inverse_jacobi_f(kind, x, m): ctx.prec += 10 phi = ctx.asin(x) return sign * ctx.ellipf(phi, m) - elif 1 < x <= 1 / ctx.sqrt(m): + elif x <= 1 / ctx.sqrt(m): K = ctx.ellipk(m) ctx.prec += 10 xpn2 = x ** (-2) @@ -1682,4 +1682,3 @@ def jacobi_am_f(x, m): return ctx.atan2(snz, cnz) + npi finally: ctx.prec = prec - diff --git a/src/sage/manifolds/subsets/pullback.py b/src/sage/manifolds/subsets/pullback.py index 8453e346b29..0205222fd2a 100644 --- a/src/sage/manifolds/subsets/pullback.py +++ b/src/sage/manifolds/subsets/pullback.py @@ -15,7 +15,7 @@ from sage.categories.sets_cat import Sets, EmptySetError from sage.categories.metric_spaces import MetricSpaces -from sage.modules.free_module import is_FreeModule, FreeModule +from sage.modules.free_module import is_FreeModule from sage.rings.infinity import infinity, minus_infinity from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -573,6 +573,7 @@ def __init__(self, map, codomain_subset, inverse, name, latex_name): if chart.domain().dimension() != 1: raise ValueError('to pull back a set of scalars by a chart, the manifold must be 1-dimensional') map = chart.domain().scalar_field({chart: chart[0]}) + def _inverse(coord): return self.point((coord,), chart=chart) else: From 09aabf429b7c8e5c132368e1b5deb97132fce75b Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 14 Oct 2021 12:29:54 -0400 Subject: [PATCH 401/511] Trac #32691: remove obsolete easy_install lockfile patch. The easy_install mechanism is obsolete, and was replaced by pip. None of our SPKGs require it, so the patch to allow simultaneous installs is also obsolete. We remove it. --- build/pkgs/setuptools/SPKG.rst | 2 -- .../patches/easy_install_lock.patch | 31 ------------------- 2 files changed, 33 deletions(-) delete mode 100644 build/pkgs/setuptools/patches/easy_install_lock.patch diff --git a/build/pkgs/setuptools/SPKG.rst b/build/pkgs/setuptools/SPKG.rst index 0b2d042f946..10e732330c6 100644 --- a/build/pkgs/setuptools/SPKG.rst +++ b/build/pkgs/setuptools/SPKG.rst @@ -37,5 +37,3 @@ applied during the build process. - pkg_resources.py.patch: silence warning about permissions. -- easy_install_lock.patch: lock the easy_install.pth file to allow - simultaneous installation diff --git a/build/pkgs/setuptools/patches/easy_install_lock.patch b/build/pkgs/setuptools/patches/easy_install_lock.patch deleted file mode 100644 index 0acc44aff37..00000000000 --- a/build/pkgs/setuptools/patches/easy_install_lock.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff -ru src/setuptools/command/easy_install.py b/setuptools/command/easy_install.py ---- src/setuptools/command/easy_install.py 2014-10-31 14:42:35.779973945 +0100 -+++ b/setuptools/command/easy_install.py 2014-10-31 15:07:53.067034724 +0100 -@@ -1446,6 +1446,11 @@ - list(map(self.add, find_distributions(path, True))) - - def _load(self): -+ # Lock self.filename until save() is called -+ import fcntl -+ self.lock = open(self.filename, 'a') -+ fcntl.flock(self.lock, fcntl.LOCK_EX) -+ - self.paths = [] - saw_import = False - seen = dict.fromkeys(self.sitedirs) -@@ -1479,6 +1484,7 @@ - def save(self): - """Write changed .pth file back to disk""" - if not self.dirty: -+ self.lock.close() - return - - data = '\n'.join(map(self.make_relative,self.paths)) -@@ -1504,6 +1510,7 @@ - os.unlink(self.filename) - - self.dirty = False -+ self.lock.close() - - def add(self, dist): - """Add `dist` to the distribution map""" From 4376f03e0dbdf4ff238535c100fe1f311449e8b7 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 14 Oct 2021 12:31:55 -0400 Subject: [PATCH 402/511] Trac #32691: remove description of a nonexistent patch in SPKG.rst. --- build/pkgs/setuptools/SPKG.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/build/pkgs/setuptools/SPKG.rst b/build/pkgs/setuptools/SPKG.rst index 10e732330c6..8d510960f1d 100644 --- a/build/pkgs/setuptools/SPKG.rst +++ b/build/pkgs/setuptools/SPKG.rst @@ -27,13 +27,3 @@ Dependencies ------------ - python - - -Build Instructions/Changes --------------------------- - -The following patches are in the patches subdirectory. The patches are -applied during the build process. - -- pkg_resources.py.patch: silence warning about permissions. - From bc3ef1f650dcb6c0406ebb6bc2b920d771d4bd22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 14 Oct 2021 21:10:07 +0200 Subject: [PATCH 403/511] 32693: fixing failing internet doctest --- src/sage/calculus/calculus.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 19966cfb8b6..d3a035e2a36 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1462,10 +1462,17 @@ def mma_free_limit(expression, v, a, dir=None): """ Limit using Mathematica's online interface. + INPUT: + + - ``expression`` -- symbolic expression + - ``v`` -- variable + - ``a`` -- value where the variable goes to + - ``dir`` -- ``'+'``, ``'-'`` or ``None`` (optional, default:``None``) + EXAMPLES:: sage: from sage.calculus.calculus import mma_free_limit - sage: mma_free_limit(sin(x)/x, x=0) # optional - internet + sage: mma_free_limit(sin(x)/x, x, a=0) # optional - internet 1 Another simple limit:: From cc028a3e0354ee879f0129f41b7828592d522b3f Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 14 Oct 2021 15:19:45 -0400 Subject: [PATCH 404/511] Trac #32691: upgrade setuptools to v58.2.0. --- build/pkgs/setuptools/checksums.ini | 6 +++--- build/pkgs/setuptools/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/setuptools/checksums.ini b/build/pkgs/setuptools/checksums.ini index 854f0a9f02b..6a280871e78 100644 --- a/build/pkgs/setuptools/checksums.ini +++ b/build/pkgs/setuptools/checksums.ini @@ -1,5 +1,5 @@ tarball=setuptools-VERSION.tar.gz -sha1=527fb70bfac4a7396d052843a6f2ec70f9f45f68 -md5=f81a78919878159a2fd677591f7b8ac3 -cksum=2062383309 +sha1=5d97de0e774b2269c85685a4aa8fd5956bcfd2bb +md5=ff20ab7e0d51c5ad0a9438c50e598c06 +cksum=3564252314 upstream_url=https://pypi.io/packages/source/s/setuptools/setuptools-VERSION.tar.gz diff --git a/build/pkgs/setuptools/package-version.txt b/build/pkgs/setuptools/package-version.txt index 5d46e1226e1..e6ea6360512 100644 --- a/build/pkgs/setuptools/package-version.txt +++ b/build/pkgs/setuptools/package-version.txt @@ -1 +1 @@ -58.0.2 +58.2.0 From c872d69fe936caa1b002585d8a769a4120823f45 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 15 Oct 2021 09:49:29 +0900 Subject: [PATCH 405/511] Add description to features --- src/sage/databases/cremona.py | 2 +- src/sage/features/__init__.py | 13 +++++++++++-- src/sage/features/databases.py | 11 +++++++---- src/sage/features/join_feature.py | 4 ++-- src/sage/features/latte.py | 3 ++- 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index 345867606a3..8440a4811b1 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -1696,7 +1696,7 @@ def CremonaDatabase(name=None,mini=None,set_global=None): Verify that :trac:`12341` has been resolved:: - sage: c = CremonaDatabase('should not exist',mini=True) + sage: c = CremonaDatabase('should not exist', mini=True) Traceback (most recent call last): ... FeatureNotPresentError: database_should_not_exist_ellcurve is not available. diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 5771971cc3e..25e4a40dcd2 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -100,6 +100,8 @@ class Feature(TrivialUniqueRepresentation): - ``spkg`` -- (string) name of the SPKG providing the feature + - ``description`` -- (string) optional; plain English description of the feature + - ``url`` -- a URL for the upstream package providing the feature Overwrite :meth:`_is_present` to add feature checks. @@ -115,7 +117,7 @@ class Feature(TrivialUniqueRepresentation): sage: GapPackage("grape") is GapPackage("grape") True """ - def __init__(self, name, spkg=None, url=None): + def __init__(self, name, spkg=None, url=None, description=None): r""" TESTS:: @@ -127,6 +129,8 @@ def __init__(self, name, spkg=None, url=None): self.name = name self.spkg = spkg self.url = url + self.description = description + self._cache_is_present = None self._cache_resolution = None @@ -209,8 +213,13 @@ def __repr__(self): sage: from sage.features.gap import GapPackage sage: GapPackage("grape") # indirect doctest Feature('gap_package_grape') + + sage: from sage.features.databases import DatabaseConwayPolynomials + sage: DatabaseConwayPolynomials() # indirect doctest + Feature('conway_polynomials': Frank Luebeck's database of Conway polynomials) """ - return 'Feature({name!r})'.format(name=self.name) + description = f'{self.name!r}: {self.description}' if self.description else f'{self.name!r}' + return f'Feature({description})' def resolution(self): r""" diff --git a/src/sage/features/databases.py b/src/sage/features/databases.py index 8e9b4b1a5c0..7fff8075914 100644 --- a/src/sage/features/databases.py +++ b/src/sage/features/databases.py @@ -37,7 +37,8 @@ def __init__(self): StaticFile.__init__(self, "conway_polynomials", filename='conway_polynomials.p', search_path=search_path, - spkg='conway_polynomials') + spkg='conway_polynomials', + description="Frank Luebeck's database of Conway polynomials") CREMONA_DATA_DIRS = set([CREMONA_MINI_DATA_DIR, CREMONA_LARGE_DATA_DIR]) @@ -59,7 +60,7 @@ class DatabaseCremona(StaticFile): sage: DatabaseCremona('cremona_mini').is_present() FeatureTestResult('database_cremona_mini_ellcurve', True) sage: DatabaseCremona().is_present() # optional: database_cremona_ellcurve - FeatureTestResult("database_cremona_ellcurve", True) + FeatureTestResult('database_cremona_ellcurve', True) """ def __init__(self, name="cremona", spkg="database_cremona_ellcurve"): r""" @@ -73,7 +74,8 @@ def __init__(self, name="cremona", spkg="database_cremona_ellcurve"): filename='{}.db'.format(name.replace(' ', '_')), search_path=CREMONA_DATA_DIRS, spkg=spkg, - url="https://github.com/JohnCremona/ecdata") + url="https://github.com/JohnCremona/ecdata", + description="Cremona's database of elliptic curves") class DatabaseJones(StaticFile): @@ -96,7 +98,8 @@ def __init__(self): """ StaticFile.__init__(self, "database_jones_numfield", filename='jones/jones.sobj', - spkg="database_jones_numfield") + spkg="database_jones_numfield", + description="John Jones's tables of number fields") class DatabaseKnotInfo(PythonModule): diff --git a/src/sage/features/join_feature.py b/src/sage/features/join_feature.py index f011b40a7f6..bdbd74c2e8d 100644 --- a/src/sage/features/join_feature.py +++ b/src/sage/features/join_feature.py @@ -24,7 +24,7 @@ class JoinFeature(Feature): sage: F.is_present() FeatureTestResult('xxyyyy', False) """ - def __init__(self, name, features, spkg=None, url=None): + def __init__(self, name, features, spkg=None, url=None, description=None): """ TESTS: @@ -46,7 +46,7 @@ def __init__(self, name, features, spkg=None, url=None): raise ValueError('given features have more than one url; provide url argument') elif len(urls) == 1: url = next(iter(urls)) - super().__init__(name, spkg=spkg, url=url) + super().__init__(name, spkg=spkg, url=url, description=description) self._features = features def _is_present(self): diff --git a/src/sage/features/latte.py b/src/sage/features/latte.py index 1beb43f179a..d37a0d436e0 100644 --- a/src/sage/features/latte.py +++ b/src/sage/features/latte.py @@ -49,4 +49,5 @@ def __init__(self): True """ JoinFeature.__init__(self, "latte_int", - (Latte_count(), Latte_integrate())) + (Latte_count(), Latte_integrate()), + description="LattE") From 87d5e6143a93f19d0102420b964449d068ee561e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 15 Oct 2021 09:21:38 +0200 Subject: [PATCH 406/511] fix --- src/sage/combinat/posets/posets.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 32b64020004..9ebe89e468e 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -281,7 +281,7 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** - +from collections import defaultdict from copy import copy, deepcopy from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute @@ -2011,7 +2011,6 @@ def plot(self, label_elements=True, element_labels=None, sage: P.plot() Graphics object consisting of 0 graphics primitives """ - from collections import defaultdict graph = self.hasse_diagram() rename = {'element_color': 'vertex_color', @@ -5693,7 +5692,7 @@ def lexicographic_sum(self, P): True """ # P might be defaultdict, hence the test - if isinstance(P, dict): + if isinstance(P, dict) and not isinstance(P, defaultdict): if set(P) != set(self): raise ValueError("keys of dict P does not match to elements of the poset") From 08248a17ab2eea2b2ca843b06ee83947deda88e3 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 15 Oct 2021 18:02:29 +0900 Subject: [PATCH 407/511] Fix for doctest failures --- src/sage/features/join_feature.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/features/join_feature.py b/src/sage/features/join_feature.py index bdbd74c2e8d..a4f9aaca47f 100644 --- a/src/sage/features/join_feature.py +++ b/src/sage/features/join_feature.py @@ -57,7 +57,7 @@ def _is_present(self): sage: from sage.features.latte import Latte sage: Latte()._is_present() # optional - latte_int - FeatureTestResult('LattE', True) + FeatureTestResult('latte_int', True) """ for f in self._features: test = f._is_present() @@ -73,7 +73,7 @@ def is_functional(self): sage: from sage.features.latte import Latte sage: Latte().is_functional() # optional - latte_int - FeatureTestResult('LattE', True) + FeatureTestResult('latte_int', True) """ for f in self._features: test = f.is_functional() From cf83e77ac6b99b5c012ad3e56f8697dcfe312b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 15 Oct 2021 14:04:36 +0200 Subject: [PATCH 408/511] more doc for factor in interval_posets --- src/sage/combinat/interval_posets.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 98abeaa6427..b9d16ccc4df 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -599,7 +599,7 @@ def _mul_(self, other: TIP) -> TIP: def factor(self) -> list[TamariIntervalPoset]: """ - Return the decomposition as a list of connected components. + Return the unique decomposition as a list of connected components. EXAMPLES:: @@ -612,7 +612,10 @@ def factor(self) -> list[TamariIntervalPoset]: TESTS:: sage: T = TamariIntervalPosets(20).random_element() - sage: T == prod(factor(T)) + sage: facs = factor(T) + sage: all(U.is_connected() for U in facs) + True + sage: T == prod(facs) True """ hasse = self.poset().hasse_diagram() @@ -2807,7 +2810,7 @@ def is_connected(self) -> bool: This condition is invariant under complementation. - .. SEEALSO:: :meth:`is_indecomposable` + .. SEEALSO:: :meth:`is_indecomposable`, :meth:`factor` EXAMPLES:: From 759c88b08ed38cea181f6cf568cab5054f536bdb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 15 Oct 2021 13:07:05 -0700 Subject: [PATCH 409/511] sage.doctest, sage.control: Remove unused imports --- src/sage/doctest/external.py | 4 ---- src/sage/features/graphviz.py | 2 +- src/sage/features/latte.py | 2 +- src/sage/features/rubiks.py | 2 +- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index e4ef6fb55b5..3b22670ec61 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -35,10 +35,6 @@ multiprocessing.set_start_method('fork', force=True) Array = multiprocessing.Array -import urllib.error -from urllib.request import Request, urlopen -from ssl import SSLContext - # Functions in this module whose name is of the form 'has_xxx' tests if the # software xxx is available to Sage. prefix = 'has_' diff --git a/src/sage/features/graphviz.py b/src/sage/features/graphviz.py index ac6445c44e4..8df3c8002bc 100644 --- a/src/sage/features/graphviz.py +++ b/src/sage/features/graphviz.py @@ -11,7 +11,7 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from . import Feature, Executable, FeatureTestResult +from . import Executable from .join_feature import JoinFeature diff --git a/src/sage/features/latte.py b/src/sage/features/latte.py index d37a0d436e0..1e90208e6ba 100644 --- a/src/sage/features/latte.py +++ b/src/sage/features/latte.py @@ -2,7 +2,7 @@ r""" Check for LattE """ -from . import Executable, Feature, FeatureTestResult +from . import Executable from .join_feature import JoinFeature diff --git a/src/sage/features/rubiks.py b/src/sage/features/rubiks.py index 19c478888f5..9074fe58c81 100644 --- a/src/sage/features/rubiks.py +++ b/src/sage/features/rubiks.py @@ -9,7 +9,7 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from . import Feature, Executable, FeatureTestResult +from . import Executable from .join_feature import JoinFeature From 15729dcf018e6059c1ff127438b076aa35fe872c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 15 Oct 2021 13:16:10 -0700 Subject: [PATCH 410/511] src/sage/features/mcqd.py: Add doctests --- src/sage/features/mcqd.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/features/mcqd.py b/src/sage/features/mcqd.py index 6539af1d6d5..5fe2f26e881 100644 --- a/src/sage/features/mcqd.py +++ b/src/sage/features/mcqd.py @@ -3,8 +3,24 @@ class Mcqd(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of :mod:`~sage.graphs.mcqd` + + EXAMPLES:: + + sage: from sage.features.mcqd import Mcqd + sage: Mcqd().is_present() # optional: mcqd + FeatureTestResult('mcqd', True) + """ def __init__(self): + """ + TESTS:: + + sage: from sage.features.mcqd import Mcqd + sage: isinstance(Mcqd(), Mcqd) + True + """ # Currently part of sagemath_standard, conditionally built. # Will be changed to spkg='sagemath_mcqd' later JoinFeature.__init__(self, 'mcqd', From 1d02bd06da66b6e8b5f5b28121dcc8d0cf4b209c Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sat, 16 Oct 2021 12:13:40 +0900 Subject: [PATCH 411/511] More doctests for coverage --- src/sage/features/four_ti_2.py | 14 +++++ src/sage/features/gap.py | 2 +- src/sage/features/internet.py | 3 +- src/sage/features/latte.py | 14 +++++ src/sage/features/meataxe.py | 15 ++++++ src/sage/features/mip_backends.py | 43 +++++++++++++-- src/sage/features/sagemath.py | 90 +++++++++++++++++++++++++++++++ src/sage/features/tdlib.py | 11 +++- 8 files changed, 184 insertions(+), 8 deletions(-) diff --git a/src/sage/features/four_ti_2.py b/src/sage/features/four_ti_2.py index 7f53a1135b9..83ac7b6d2ab 100644 --- a/src/sage/features/four_ti_2.py +++ b/src/sage/features/four_ti_2.py @@ -7,6 +7,13 @@ class FourTi2Executable(Executable): Feature for the 4ti2 executables. """ def __init__(self, name): + r""" + TESTS:: + + sage: from sage.features.four_ti_2 import FourTi2Executable + sage: isinstance(FourTi2Executable('hilbert'), FourTi2Executable) + True + """ from sage.env import SAGE_ENV Executable.__init__(self, name="4ti2-" + name, @@ -25,6 +32,13 @@ class FourTi2(JoinFeature): FeatureTestResult('4ti2', True) """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.four_ti_2 import FourTi2 + sage: isinstance(FourTi2(), FourTi2) + True + """ JoinFeature.__init__(self, '4ti2', [FourTi2Executable(x) # same list is tested in build/pkgs/4ti2/spkg-configure.m4 diff --git a/src/sage/features/gap.py b/src/sage/features/gap.py index 24b62689459..2e4263de22e 100644 --- a/src/sage/features/gap.py +++ b/src/sage/features/gap.py @@ -36,7 +36,7 @@ def _is_present(self): EXAMPLES:: sage: from sage.features.gap import GapPackage - sage: GapPackage("grape", spkg="gap_packages").is_present() # optional: gap_packages + sage: GapPackage("grape", spkg="gap_packages")._is_present() # optional - gap_packages FeatureTestResult('gap_package_grape', True) """ from sage.libs.gap.libgap import libgap diff --git a/src/sage/features/internet.py b/src/sage/features/internet.py index 19cd6689253..77fa6f0046b 100644 --- a/src/sage/features/internet.py +++ b/src/sage/features/internet.py @@ -14,7 +14,6 @@ class Internet(Feature): sage: Internet() Feature('internet') """ - def __init__(self): r""" TESTS:: @@ -32,7 +31,7 @@ def _is_present(self): EXAMPLES:: sage: from sage.features.internet import Internet - sage: Internet().is_present() # random, optional -- internet + sage: Internet()._is_present() # random, optional - internet FeatureTestResult('internet', True) """ import urllib.error diff --git a/src/sage/features/latte.py b/src/sage/features/latte.py index 1e90208e6ba..7b4d9dda756 100644 --- a/src/sage/features/latte.py +++ b/src/sage/features/latte.py @@ -14,6 +14,13 @@ class Latte_count(Executable): Feature for the executable ``count`` from the LattE suite. """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.latte import Latte_count + sage: isinstance(Latte_count(), Latte_count) + True + """ Executable.__init__(self, "count", executable="count", spkg="latte_int", url=LATTE_URL) @@ -24,6 +31,13 @@ class Latte_integrate(Executable): Feature for the executable ``integrate`` from the LattE suite. """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.latte import Latte_integrate + sage: isinstance(Latte_integrate(), Latte_integrate) + True + """ Executable.__init__(self, "integrate", executable="integrate", spkg="latte_int", url=LATTE_URL) diff --git a/src/sage/features/meataxe.py b/src/sage/features/meataxe.py index a8b65d166dc..eb32016ac3e 100644 --- a/src/sage/features/meataxe.py +++ b/src/sage/features/meataxe.py @@ -3,8 +3,23 @@ class Meataxe(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of ``MeatAxe``. + EXAMPLES:: + + sage: from sage.features.meataxe import Meataxe + sage: Meataxe().is_present() # optional - meataxe + FeatureTestResult('meataxe', True) + """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.meataxe import Meataxe + sage: isinstance(Meataxe(), Meataxe) + True + """ # Currently part of sagemath_standard, conditionally built. # Will be changed to spkg='sagemath_meataxe' later JoinFeature.__init__(self, 'meataxe', diff --git a/src/sage/features/mip_backends.py b/src/sage/features/mip_backends.py index a72c054a857..bec5d958247 100644 --- a/src/sage/features/mip_backends.py +++ b/src/sage/features/mip_backends.py @@ -6,8 +6,16 @@ class MIPBackend(Feature): r""" A feature describing whether a :class:`MixedIntegerLinearProgram` backend is available. """ - def _is_present(self): + r""" + Test for the presence of a :class:`MixedIntegerLinearProgram` backend. + + EXAMPLES:: + + sage: from sage.features.mip_backends import CPLEX + sage: CPLEX()._is_present() # optional - cplex + FeatureTestResult('cplex', True) + """ try: from sage.numerical.mip import MixedIntegerLinearProgram MixedIntegerLinearProgram(solver=self.name) @@ -17,22 +25,49 @@ def _is_present(self): class CPLEX(MIPBackend): - + r""" + A feature describing whether a :class:`MixedIntegerLinearProgram` backend ``CPLEX`` is available. + """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.mip_backends import CPLEX + sage: CPLEX()._is_present() # optional - cplex + FeatureTestResult('cplex', True) + """ MIPBackend.__init__(self, 'cplex', spkg='sage_numerical_backends_cplex') class Gurobi(MIPBackend): - + r""" + A feature describing whether a :class:`MixedIntegerLinearProgram` backend ``Gurobi`` is available. + """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.mip_backends import Gurobi + sage: Gurobi()._is_present() # optional - gurobi + FeatureTestResult('gurobi', True) + """ MIPBackend.__init__(self, 'gurobi', spkg='sage_numerical_backends_gurobi') class COIN(JoinFeature): - + r""" + A feature describing whether a :class:`MixedIntegerLinearProgram` backend ``COIN`` is available. + """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.mip_backends import COIN + sage: COIN()._is_present() # optional - sage_numerical_backends_coin + FeatureTestResult('sage_numerical_backends_coin', True) + """ JoinFeature.__init__(self, 'sage_numerical_backends_coin', [MIPBackend('coin')], spkg='sage_numerical_backends_coin') diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index 2af7def3668..52321820370 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -6,8 +6,23 @@ class sage__combinat(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of ``sage.combinat``. + EXAMPLES:: + + sage: from sage.features.sagemath import sage__combinat + sage: sage__combinat().is_present() # optional - sage.combinat + FeatureTestResult('sage.combinat', True) + """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__combinat + sage: isinstance(sage__combinat(), sage__combinat) + True + """ # sage.combinat will be a namespace package. # Testing whether sage.combinat itself can be imported is meaningless. # Hence, we test a Python module within the package. @@ -16,35 +31,110 @@ def __init__(self): class sage__graphs(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of ``sage.graphs``. + + EXAMPLES:: + sage: from sage.features.sagemath import sage__graphs + sage: sage__graphs().is_present() # optional - sage.graphs + FeatureTestResult('sage.graphs', True) + """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__graphs + sage: isinstance(sage__graphs(), sage__graphs) + True + """ JoinFeature.__init__(self, 'sage.graphs', [PythonModule('sage.graphs.graph')]) class sage__plot(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of ``sage.plot``. + + EXAMPLES:: + sage: from sage.features.sagemath import sage__plot + sage: sage__plot().is_present() # optional - sage.plot + FeatureTestResult('sage.plot', True) + """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__plot + sage: isinstance(sage__plot(), sage__plot) + True + """ JoinFeature.__init__(self, 'sage.plot', [PythonModule('sage.plot.plot')]) class sage__rings__number_field(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of ``sage.rings.number_field``. + EXAMPLES:: + + sage: from sage.features.sagemath import sage__rings__number_field + sage: sage__rings__number_field().is_present() # optional - sage.rings.number_field + FeatureTestResult('sage.rings.number_field', True) + """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__rings__number_field + sage: isinstance(sage__rings__number_field(), sage__rings__number_field) + True + """ JoinFeature.__init__(self, 'sage.rings.number_field', [PythonModule('sage.rings.number_field.number_field_element')]) class sage__rings__real_double(PythonModule): + r""" + A :class:`sage.features.Feature` describing the presence of ``sage.rings.real_double``. + + EXAMPLES:: + sage: from sage.features.sagemath import sage__rings__real_double + sage: sage__rings__real_double().is_present() # optional - sage.rings.real_double + FeatureTestResult('sage.rings.real_double', True) + """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__rings__real_double + sage: isinstance(sage__rings__real_double(), sage__rings__real_double) + True + """ PythonModule.__init__(self, 'sage.rings.real_double') class sage__symbolic(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of ``sage.symbolic``. + + EXAMPLES:: + sage: from sage.features.sagemath import sage__symbolic + sage: sage__symbolic().is_present() # optional - sage.symbolic + FeatureTestResult('sage.symbolic', True) + """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__symbolic + sage: isinstance(sage__symbolic(), sage__symbolic) + True + """ JoinFeature.__init__(self, 'sage.symbolic', [PythonModule('sage.symbolic.expression')], spkg="sagemath_symbolics") diff --git a/src/sage/features/tdlib.py b/src/sage/features/tdlib.py index e01e1bdfdf6..cae1f5abc78 100644 --- a/src/sage/features/tdlib.py +++ b/src/sage/features/tdlib.py @@ -3,8 +3,17 @@ class Tdlib(JoinFeature): - + r""" + A :class:`sage.features.Feature` describing the presence of the ``TDLib``. + """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.tdlib import Tdlib + sage: isinstance(Tdlib(), Tdlib) + True + """ # Currently part of sagemath_standard, conditionally built. # Will be changed to spkg='sagemath_tdlib' later JoinFeature.__init__(self, 'tdlib', From a990a14062bd7ad8ddade5804585804e2db7e34e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 15 Oct 2021 23:33:03 -0700 Subject: [PATCH 412/511] Add sage.rings.abc.AlgebraicField etc., deprecate is_AlgebraicField --- src/sage/modular/dirichlet.py | 5 ++- src/sage/rings/abc.pyx | 24 +++++++++++++ .../rings/polynomial/polynomial_element.pyx | 30 +++++----------- src/sage/rings/qqbar.py | 36 ++++++++++++++++--- src/sage/rings/qqbar_decorators.py | 6 ++-- src/sage/symbolic/expression.pyx | 26 +++++++------- 6 files changed, 81 insertions(+), 46 deletions(-) diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 74345c67e5d..c35e712de21 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -69,7 +69,6 @@ from sage.categories.map import Map from sage.rings.rational_field import is_RationalField import sage.rings.abc -from sage.rings.qqbar import is_AlgebraicField from sage.rings.ring import is_Ring from sage.misc.functional import round @@ -1347,7 +1346,7 @@ def gauss_sum(self, a=1): m = G.modulus() if isinstance(K, sage.rings.abc.ComplexField): return self.gauss_sum_numerical(a=a) - elif is_AlgebraicField(K): + elif isinstance(K, sage.rings.abc.AlgebraicField): L = K zeta = L.zeta(m) elif number_field.is_CyclotomicField(K) or is_RationalField(K): @@ -1427,7 +1426,7 @@ def gauss_sum_numerical(self, prec=53, a=1): def phi(t): return t CC = K - elif is_AlgebraicField(K): + elif isinstance(K, sage.rings.abc.AlgebraicField): from sage.rings.complex_mpfr import ComplexField CC = ComplexField(prec) phi = CC.coerce_map_from(K) diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index 2c5e2253150..15e195a4e1a 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -2,6 +2,30 @@ Abstract base classes for rings """ +class AlgebraicField_common(Field): + r""" + Abstract base class for :class:`~sage.rings.qqbar.AlgebraicField_common`. + """ + + pass + + +class AlgebraicField(AlgebraicField_common): + r""" + Abstract base class for :class:`~sage.rings.qqbar.AlgebraicField`. + """ + + pass + + +class AlgebraicRealField(AlgebraicField_common): + r""" + Abstract base class for :class:`~sage.rings.qqbar.AlgebraicRealField`. + """ + + pass + + cdef class RealField(Field): r""" Abstract base class for :class:`~sage.rings.real_mpfr.RealField_class`. diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 3b944b50ce6..7d47f0dbeb1 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -171,31 +171,17 @@ from .polynomial_compiled cimport CompiledPolynomialFunction from sage.rings.polynomial.polydict cimport ETuple -cdef object is_AlgebraicRealField -cdef object is_AlgebraicField -cdef object is_AlgebraicField_common cdef object NumberField_quadratic -cdef object is_ComplexIntervalField cdef void late_import(): # A hack to avoid circular imports. - global is_AlgebraicRealField - global is_AlgebraicField - global is_AlgebraicField_common global NumberField_quadratic - global is_ComplexIntervalField - if is_AlgebraicRealField is not None: + if NumberField_quadratic is not None: return - import sage.rings.qqbar - is_AlgebraicRealField = sage.rings.qqbar.is_AlgebraicRealField - is_AlgebraicField = sage.rings.qqbar.is_AlgebraicField - is_AlgebraicField_common = sage.rings.qqbar.is_AlgebraicField_common import sage.rings.number_field.number_field NumberField_quadratic = sage.rings.number_field.number_field.NumberField_quadratic - import sage.rings.complex_interval_field - is_ComplexIntervalField = sage.rings.complex_interval_field.is_ComplexIntervalField cdef class Polynomial(CommutativeAlgebraElement): @@ -7964,16 +7950,16 @@ cdef class Polynomial(CommutativeAlgebraElement): else: return [rt.rhs() for rt in rts] - if L != K or is_AlgebraicField_common(L): + if L != K or isinstance(L, sage.rings.abc.AlgebraicField_common): # So far, the only "special" implementations are for real # and complex root isolation and for p-adic factorization if (is_IntegerRing(K) or is_RationalField(K) - or is_AlgebraicRealField(K)) and \ - (is_AlgebraicRealField(L) or isinstance(L, sage.rings.abc.RealIntervalField)): + or isinstance(K, sage.rings.abc.AlgebraicRealField)) and \ + isinstance(L, (sage.rings.abc.AlgebraicRealField, sage.rings.abc.RealIntervalField)): from sage.rings.polynomial.real_roots import real_roots - if is_AlgebraicRealField(L): + if isinstance(L, sage.rings.abc.AlgebraicRealField): rts = real_roots(self, retval='algebraic_real') else: diam = ~(ZZ(1) << L.prec()) @@ -7998,14 +7984,14 @@ cdef class Polynomial(CommutativeAlgebraElement): return [rt for (rt, mult) in rts] if (is_IntegerRing(K) or is_RationalField(K) - or is_AlgebraicField_common(K) or input_gaussian) and \ - (isinstance(L, sage.rings.abc.ComplexIntervalField) or is_AlgebraicField_common(L)): + or isinstance(K, sage.rings.abc.AlgebraicField_common) or input_gaussian) and \ + isinstance(L, (sage.rings.abc.ComplexIntervalField, sage.rings.abc.AlgebraicField_common)): from sage.rings.polynomial.complex_roots import complex_roots if isinstance(L, sage.rings.abc.ComplexIntervalField): rts = complex_roots(self, min_prec=L.prec()) - elif is_AlgebraicField(L): + elif isinstance(L, sage.rings.abc.AlgebraicField): rts = complex_roots(self, retval='algebraic') else: rts = complex_roots(self, retval='algebraic_real') diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 3c3343e5354..3e7b39c896e 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -555,6 +555,7 @@ import operator import sage.rings.ring +import sage.rings.abc import sage.rings.number_field.number_field_base from sage.misc.fast_methods import Singleton from sage.misc.cachefunc import cached_method @@ -583,7 +584,7 @@ CC = ComplexField() CIF = ComplexIntervalField() -class AlgebraicField_common(sage.rings.ring.Field): +class AlgebraicField_common(sage.rings.abc.AlgebraicField_common): r""" Common base class for the classes :class:`~AlgebraicRealField` and :class:`~AlgebraicField`. @@ -1013,7 +1014,7 @@ def NF_elem_map(e): return Factorization(factorization, unit = f.lc() / trial.lc()) -class AlgebraicRealField(Singleton, AlgebraicField_common): +class AlgebraicRealField(Singleton, AlgebraicField_common, sage.rings.abc.AlgebraicRealField): r""" The field of algebraic reals. @@ -1449,12 +1450,21 @@ def is_AlgebraicRealField(F): r""" Check whether ``F`` is an :class:`~AlgebraicRealField` instance. For internal use. + This function is deprecated. Use :func:`isinstance` with + :class:`~sage.rings.abc.AlgebraicRealField` instead. + EXAMPLES:: sage: from sage.rings.qqbar import is_AlgebraicRealField sage: [is_AlgebraicRealField(x) for x in [AA, QQbar, None, 0, "spam"]] + doctest:warning... + DeprecationWarning: is_AlgebraicRealField is deprecated; + use isinstance(..., sage.rings.abc.AlgebraicRealField instead + See https://trac.sagemath.org/32660 for details. [True, False, False, False, False] """ + from sage.misc.superseded import deprecation + deprecation(32660, 'is_AlgebraicRealField is deprecated; use isinstance(..., sage.rings.abc.AlgebraicRealField instead') return isinstance(F, AlgebraicRealField) @@ -1462,7 +1472,7 @@ def is_AlgebraicRealField(F): AA = AlgebraicRealField() -class AlgebraicField(Singleton, AlgebraicField_common): +class AlgebraicField(Singleton, AlgebraicField_common, sage.rings.abc.AlgebraicField): """ The field of all algebraic complex numbers. """ @@ -1993,12 +2003,21 @@ def is_AlgebraicField(F): r""" Check whether ``F`` is an :class:`~AlgebraicField` instance. + This function is deprecated. Use :func:`isinstance` with + :class:`~sage.rings.abc.AlgebraicField` instead. + EXAMPLES:: sage: from sage.rings.qqbar import is_AlgebraicField sage: [is_AlgebraicField(x) for x in [AA, QQbar, None, 0, "spam"]] + doctest:warning... + DeprecationWarning: is_AlgebraicField is deprecated; + use isinstance(..., sage.rings.abc.AlgebraicField instead + See https://trac.sagemath.org/32660 for details. [False, True, False, False, False] """ + from sage.misc.superseded import deprecation + deprecation(32660, 'is_AlgebraicField is deprecated; use isinstance(..., sage.rings.abc.AlgebraicField instead') return isinstance(F, AlgebraicField) @@ -2010,12 +2029,21 @@ def is_AlgebraicField_common(F): r""" Check whether ``F`` is an :class:`~AlgebraicField_common` instance. + This function is deprecated. Use :func:`isinstance` with + :class:`~sage.rings.abc.AlgebraicField_common` instead. + EXAMPLES:: sage: from sage.rings.qqbar import is_AlgebraicField_common sage: [is_AlgebraicField_common(x) for x in [AA, QQbar, None, 0, "spam"]] + doctest:warning... + DeprecationWarning: is_AlgebraicField_common is deprecated; + use isinstance(..., sage.rings.abc.AlgebraicField_common) instead + See https://trac.sagemath.org/32610 for details. [True, True, False, False, False] """ + from sage.misc.superseded import deprecation + deprecation(32610, 'is_AlgebraicField_common is deprecated; use isinstance(..., sage.rings.abc.AlgebraicField_common) instead') return isinstance(F, AlgebraicField_common) @@ -6551,7 +6579,7 @@ def __init__(self, poly): poly = QQy(poly) complex = False elif isinstance(B, AlgebraicField_common): - complex = is_AlgebraicField(poly.base_ring()) + complex = isinstance(poly.base_ring(), AlgebraicField) else: try: poly = poly.change_ring(AA) diff --git a/src/sage/rings/qqbar_decorators.py b/src/sage/rings/qqbar_decorators.py index 621e5ded0d7..e18fac73cdc 100644 --- a/src/sage/rings/qqbar_decorators.py +++ b/src/sage/rings/qqbar_decorators.py @@ -87,12 +87,12 @@ def wrapper(*args, **kwds): from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence, is_PolynomialSequence from sage.rings.ideal import Ideal, Ideal_generic - from sage.rings.qqbar import is_AlgebraicField_common, number_field_elements_from_algebraics + from sage.rings.qqbar import AlgebraicField_common, number_field_elements_from_algebraics if not any(isinstance(a, (Polynomial, MPolynomial, Ideal_generic)) - and is_AlgebraicField_common(a.base_ring()) + and isinstance(a.base_ring(), AlgebraicField_common) or is_PolynomialSequence(a) - and is_AlgebraicField_common(a.ring().base_ring()) for a in args): + and isinstance(a.ring().base_ring(), AlgebraicField_common) for a in args): return func(*args, **kwds) polynomials = [] diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 5aab78bcb7b..4d7bd8f22cd 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -1524,8 +1524,9 @@ cdef class Expression(CommutativeRingElement): ValueError: cannot convert sqrt(-3) to int """ from sage.functions.all import floor, ceil + from sage.rings.real_mpfi import RIF try: - rif_self = sage.rings.all.RIF(self) + rif_self = RIF(self) except TypeError: raise ValueError("cannot convert %s to int" % self) if rif_self > 0 or (rif_self.contains_zero() and self > 0): @@ -3548,27 +3549,22 @@ cdef class Expression(CommutativeRingElement): if not self.is_relational(): raise ValueError("self must be a relation") cdef operators op = relational_operator(self._gobj) - from sage.rings.real_mpfi import is_RealIntervalField - from sage.rings.complex_interval_field import is_ComplexIntervalField - from sage.rings.all import RIF, CIF - from sage.rings.qqbar import is_AlgebraicField, is_AlgebraicRealField, AA, QQbar if domain is None: is_interval = True if self.lhs().is_algebraic() and self.rhs().is_algebraic(): if op == equal or op == not_equal: - domain = QQbar + from sage.rings.qqbar import QQbar as domain else: - domain = AA + from sage.rings.qqbar import AA as domain else: if op == equal or op == not_equal: - domain = CIF + from sage.rings.qqbar import CIF as domain else: - domain = RIF + from sage.rings.real_mpfi import RIF as domain else: - is_interval = (isinstance(domain, (sage.rings.abc.RealIntervalField, - sage.rings.abc.ComplexIntervalField)) - or is_AlgebraicField(domain) - or is_AlgebraicRealField(domain)) + is_interval = isinstance(domain, (sage.rings.abc.RealIntervalField, + sage.rings.abc.ComplexIntervalField, + sage.rings.abc.AlgebraicField_common)) zero = domain(0) diff = self.lhs() - self.rhs() vars = diff.variables() @@ -3621,6 +3617,7 @@ cdef class Expression(CommutativeRingElement): except (TypeError, ValueError, ArithmeticError, AttributeError) as ex: errors += 1 if k == errors > 3 and isinstance(domain, sage.rings.abc.ComplexIntervalField): + from sage.rings.real_mpfi import RIF domain = RIF.to_prec(domain.prec()) # we are plugging in random values above, don't be surprised # if something goes wrong... @@ -6644,8 +6641,9 @@ cdef class Expression(CommutativeRingElement): except (TypeError, AttributeError): pass from sage.functions.all import floor, ceil + from sage.rings.real_mpfi import RIF try: - rif_self = sage.rings.all.RIF(self) + rif_self = RIF(self) except TypeError: raise ValueError("could not convert %s to a real number" % self) half = 1 / sage.rings.integer.Integer(2) From 8d74803e163dc81648ec84813d5805ce8bf94eb5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Oct 2021 00:08:46 -0700 Subject: [PATCH 413/511] Add sage.rings.abc.NumberField_quadratic, deprecate is_QuadraticField --- src/sage/combinat/root_system/coxeter_type.py | 4 ++-- src/sage/groups/matrix_gps/coxeter_group.py | 5 +++-- src/sage/interfaces/polymake.py | 7 ++++--- src/sage/rings/abc.pyx | 14 +++++++------- src/sage/rings/complex_mpfr.pyx | 6 ++---- src/sage/rings/number_field/number_field.py | 11 ++++++++++- src/sage/rings/polynomial/polynomial_element.pyx | 16 +--------------- src/sage/rings/real_mpfi.pyx | 4 ++-- src/sage/schemes/elliptic_curves/heegner.py | 3 ++- 9 files changed, 33 insertions(+), 37 deletions(-) diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index 4c29231d549..5130d33ad8f 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -21,12 +21,12 @@ from sage.misc.cachefunc import cached_method from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.combinat.root_system.cartan_type import CartanType +import sage.rings.abc from sage.matrix.args import SparseEntry from sage.matrix.all import Matrix from sage.symbolic.ring import SR from sage.structure.unique_representation import UniqueRepresentation from sage.structure.sage_object import SageObject -from sage.rings.number_field.number_field import is_QuadraticField class CoxeterType(SageObject, metaclass=ClasscallMetaclass): @@ -391,7 +391,7 @@ def val(x): return (E(2*x) + ~E(2*x)) / R(-2) else: return R(x) - elif is_QuadraticField(R): + elif isinstance(R, sage.rings.abc.NumberField_quadratic): def val(x): if x > -1: diff --git a/src/sage/groups/matrix_gps/coxeter_group.py b/src/sage/groups/matrix_gps/coxeter_group.py index 3a2781d8c24..ddf4136a223 100644 --- a/src/sage/groups/matrix_gps/coxeter_group.py +++ b/src/sage/groups/matrix_gps/coxeter_group.py @@ -27,10 +27,11 @@ from sage.matrix.args import SparseEntry from sage.matrix.matrix_space import MatrixSpace +import sage.rings.abc from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField -from sage.rings.number_field.number_field import QuadraticField, is_QuadraticField +from sage.rings.number_field.number_field import QuadraticField from sage.misc.cachefunc import cached_method @@ -280,7 +281,7 @@ def val(x): return 2 else: return E(2 * x) + ~E(2 * x) - elif is_QuadraticField(base_ring): + elif isinstance(base_ring, sage.rings.abc.NumberField_quadratic): def val(x): if x == -1: diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index 4111116598c..b4183a8ba31 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -332,8 +332,9 @@ def convert(y): r.__sage_dict = z # do this to avoid having the entries of the list be garbage collected return r - from sage.rings.all import Integer, Rational, RDF - from sage.rings.number_field.number_field import is_QuadraticField + from sage.rings.integer import Integer + from sage.rings.rational import Rational + from sage.rings.real_double import RDF def to_str(x): if isinstance(x, list): @@ -350,7 +351,7 @@ def to_str(x): except AttributeError: pass - if is_QuadraticField(parent): + if isinstance(parent, sage.rings.abc.NumberField_quadratic): return x._polymake_init_() try: if x.parent().is_exact(): diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index 15e195a4e1a..764f88ade61 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -2,31 +2,31 @@ Abstract base classes for rings """ -class AlgebraicField_common(Field): +class NumberField_quadratic(Field): r""" - Abstract base class for :class:`~sage.rings.qqbar.AlgebraicField_common`. + Abstract base class for :class:`~sage.rings.number_field.number_field.NumberField_quadratic`. """ pass -class AlgebraicField(AlgebraicField_common): +class AlgebraicField_common(Field): r""" - Abstract base class for :class:`~sage.rings.qqbar.AlgebraicField`. + Abstract base class for :class:`~sage.rings.qqbar.AlgebraicField_common`. """ pass -class AlgebraicRealField(AlgebraicField_common): +class AlgebraicField(AlgebraicField_common): r""" - Abstract base class for :class:`~sage.rings.qqbar.AlgebraicRealField`. + Abstract base class for :class:`~sage.rings.qqbar.AlgebraicField`. """ pass -cdef class RealField(Field): +class AlgebraicRealField(AlgebraicField_common): r""" Abstract base class for :class:`~sage.rings.real_mpfr.RealField_class`. """ diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index 012344ea2a9..7cf9fd9f215 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -46,6 +46,7 @@ from sage.structure.parent_gens import ParentWithGens from sage.misc.sage_eval import sage_eval +import sage.rings.abc from sage.arith.constants cimport LOG_TEN_TWO_PLUS_EPSILON from . import ring, infinity from .integer cimport Integer @@ -63,7 +64,6 @@ gmpy2.import_gmpy2() # Some objects that are note imported at startup in order to break # circular imports -NumberField_quadratic = None NumberFieldElement_quadratic = None AlgebraicNumber_base = None AlgebraicNumber = None @@ -80,7 +80,6 @@ def late_import(): sage: sage.rings.complex_mpfr.late_import() """ - global NumberField_quadratic global NumberFieldElement_quadratic global AlgebraicNumber_base global AlgebraicNumber @@ -91,7 +90,6 @@ def late_import(): if NumberFieldElement_quadratic is None: import sage.rings.number_field.number_field import sage.rings.number_field.number_field_element_quadratic as nfeq - NumberField_quadratic = sage.rings.number_field.number_field.NumberField_quadratic NumberFieldElement_quadratic = nfeq.NumberFieldElement_quadratic import sage.rings.qqbar AlgebraicNumber_base = sage.rings.qqbar.AlgebraicNumber_base @@ -511,7 +509,7 @@ class ComplexField_class(sage.rings.abc.ComplexField): late_import() if isinstance(x, NumberFieldElement_quadratic): - if isinstance(x.parent(), NumberField_quadratic) and list(x.parent().polynomial()) == [1, 0, 1]: + if isinstance(x.parent(), sage.rings.abc.NumberField_quadratic) and list(x.parent().polynomial()) == [1, 0, 1]: (re, im) = list(x) return ComplexNumber(self, re, im) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 4b188823ac3..1b8ec5874c0 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -1041,10 +1041,17 @@ def is_QuadraticField(x): r""" Return True if x is of the quadratic *number* field type. + This function is deprecated. Use :func:`isinstance` with + :class:`~sage.rings.abc.NumberField_quadratic` instead. + EXAMPLES:: sage: from sage.rings.number_field.number_field import is_QuadraticField sage: is_QuadraticField(QuadraticField(5,'a')) + doctest:warning... + DeprecationWarning: is_QuadraticField is deprecated; + use isinstance(..., sage.rings.abc.NumberField_quadratic instead + See https://trac.sagemath.org/32660 for details. True sage: is_QuadraticField(NumberField(x^2 - 5, 'b')) True @@ -1057,6 +1064,8 @@ def is_QuadraticField(x): sage: is_QuadraticField(GF(9,'a')) False """ + from sage.misc.superseded import deprecation + deprecation(32660, 'is_QuadraticField is deprecated; use isinstance(..., sage.rings.abc.NumberField_quadratic instead') return isinstance(x, NumberField_quadratic) @@ -11709,7 +11718,7 @@ def roots_of_unity(self): return v -class NumberField_quadratic(NumberField_absolute): +class NumberField_quadratic(NumberField_absolute, sage.rings.abc.NumberField_quadratic): r""" Create a quadratic extension of the rational field. diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 7d47f0dbeb1..6fc5c92a04f 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -171,18 +171,6 @@ from .polynomial_compiled cimport CompiledPolynomialFunction from sage.rings.polynomial.polydict cimport ETuple -cdef object NumberField_quadratic - -cdef void late_import(): - # A hack to avoid circular imports. - global NumberField_quadratic - - if NumberField_quadratic is not None: - return - - import sage.rings.number_field.number_field - NumberField_quadratic = sage.rings.number_field.number_field.NumberField_quadratic - cdef class Polynomial(CommutativeAlgebraElement): """ @@ -7836,8 +7824,6 @@ cdef class Polynomial(CommutativeAlgebraElement): L = K if ring is None else ring - late_import() - input_fp = isinstance(K, (sage.rings.abc.RealField, sage.rings.abc.ComplexField, sage.rings.abc.RealDoubleField, @@ -7848,7 +7834,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage.rings.abc.ComplexDoubleField)) input_complex = isinstance(K, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) output_complex = isinstance(L, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) - input_gaussian = (isinstance(K, NumberField_quadratic) + input_gaussian = (isinstance(K, sage.rings.abc.NumberField_quadratic) and list(K.polynomial()) == [1, 0, 1]) if input_fp and output_fp: diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index ce83e1ddf4e..78ab958c048 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -278,6 +278,7 @@ from .integer_ring import ZZ from .rational_field import QQ from sage.categories.morphism cimport Map +cimport sage.rings.abc cimport sage.rings.real_mpfr as real_mpfr import math # for log @@ -813,8 +814,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): return True if isinstance(S, RealIntervalField_class): return (S).__prec >= prec - from .number_field.number_field import NumberField_quadratic - if isinstance(S, NumberField_quadratic): + if isinstance(S, sage.rings.abc.NumberField_quadratic): return S.discriminant() > 0 # If coercion to RR is possible and there is a _real_mpfi_ diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index fc7d07086a8..1909bb54c44 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -101,6 +101,7 @@ from sage.structure.richcmp import (richcmp_method, richcmp, richcmp_not_equal, rich_to_bool) +import sage.rings.abc import sage.rings.number_field.number_field_element import sage.rings.number_field.number_field as number_field import sage.rings.all as rings @@ -1107,7 +1108,7 @@ def _base_is_quad_imag_field(self): sage: M.galois_group(heegner_points(389,-20,1).ring_class_field())._base_is_quad_imag_field() False """ - return number_field.is_QuadraticField(self.__base) + return isinstance(self.__base, sage.rings.abc.NumberField_quadratic) def is_kolyvagin(self): """ From f4369f544e7e739d0414e2d60c13f6de86aeca6b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Oct 2021 00:48:26 -0700 Subject: [PATCH 414/511] Add sage.rings.abc.NumberField_cyclotomic, deprecate is_CyclotomicField --- src/sage/groups/misc_gps/argument_groups.py | 4 ++-- src/sage/matrix/matrix_space.py | 4 ++-- src/sage/modular/dirichlet.py | 6 +++--- src/sage/rings/abc.pyx | 8 ++++++++ src/sage/rings/number_field/number_field.py | 13 +++++++++++-- src/sage/rings/universal_cyclotomic_field.py | 20 +++++++++++--------- 6 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/sage/groups/misc_gps/argument_groups.py b/src/sage/groups/misc_gps/argument_groups.py index 818185f783e..5ff64d4ddee 100644 --- a/src/sage/groups/misc_gps/argument_groups.py +++ b/src/sage/groups/misc_gps/argument_groups.py @@ -735,9 +735,9 @@ def _element_constructor_(self, data, exponent=None, **kwds): zeta2^5 """ from sage.groups.generic import discrete_log + import sage.rings.abc from sage.rings.asymptotic.misc import combine_exceptions from sage.rings.rational_field import QQ - from sage.rings.number_field.number_field import NumberField_cyclotomic if exponent is None: if isinstance(data, int) and data == 0: @@ -769,7 +769,7 @@ def _element_constructor_(self, data, exponent=None, **kwds): elif isinstance(P, UnitCircleGroup): exponent = data.exponent - elif isinstance(P, NumberField_cyclotomic): + elif isinstance(P, sage.rings.abc.NumberField_cyclotomic): zeta = P.gen() n = zeta.multiplicative_order() try: diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index eabba820926..2f7a3566333 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -243,7 +243,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): if R.order() < matrix_modn_dense_double.MAX_MODULUS: return matrix_modn_dense_double.Matrix_modn_dense_double - if sage.rings.number_field.number_field.is_CyclotomicField(R): + if isinstance(R, sage.rings.abc.NumberField_cyclotomic): from . import matrix_cyclo_dense return matrix_cyclo_dense.Matrix_cyclo_dense @@ -296,7 +296,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): raise ValueError("'numpy' matrices are only available over RDF and CDF") if implementation == 'rational': - if sage.rings.number_field.number_field.is_CyclotomicField(R): + if isinstance(R, sage.rings.abc.NumberField_cyclotomic): from . import matrix_cyclo_dense return matrix_cyclo_dense.Matrix_cyclo_dense raise ValueError("'rational' matrices are only available over a cyclotomic field") diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index c35e712de21..143157de883 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -1349,7 +1349,7 @@ def gauss_sum(self, a=1): elif isinstance(K, sage.rings.abc.AlgebraicField): L = K zeta = L.zeta(m) - elif number_field.is_CyclotomicField(K) or is_RationalField(K): + elif isinstance(K, sage.rings.abc.NumberField_cyclotomic) or is_RationalField(K): chi = chi.minimize_base_ring() n = lcm(m, G.zeta_order()) L = rings.CyclotomicField(n) @@ -1430,7 +1430,7 @@ def phi(t): from sage.rings.complex_mpfr import ComplexField CC = ComplexField(prec) phi = CC.coerce_map_from(K) - elif number_field.is_CyclotomicField(K) or is_RationalField(K): + elif isinstance(K, sage.rings.abc.NumberField_cyclotomic) or is_RationalField(K): phi = K.complex_embedding(prec) CC = phi.codomain() else: @@ -1649,7 +1649,7 @@ def kloosterman_sum_numerical(self, prec=53, a=1, b=0): """ G = self.parent() K = G.base_ring() - if not (number_field.is_CyclotomicField(K) or is_RationalField(K)): + if not (isinstance(K, sage.rings.abc.NumberField_cyclotomic) or is_RationalField(K)): raise NotImplementedError("Kloosterman sums only currently implemented when the base ring is a cyclotomic field or QQ.") phi = K.complex_embedding(prec) CC = phi.codomain() diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index 764f88ade61..10073c6bcf9 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -10,6 +10,14 @@ class NumberField_quadratic(Field): pass +class NumberField_cyclotomic(Field): + r""" + Abstract base class for :class:`~sage.rings.number_field.number_field.NumberField_cyclotomic`. + """ + + pass + + class AlgebraicField_common(Field): r""" Abstract base class for :class:`~sage.rings.qqbar.AlgebraicField_common`. diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 1b8ec5874c0..7c8272562d1 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -1238,10 +1238,17 @@ def is_CyclotomicField(x): number field that just happens to be isomorphic to a cyclotomic field. + This function is deprecated. Use :func:`isinstance` with + :class:`~sage.rings.abc.NumberField_cyclotomic` instead. + EXAMPLES:: sage: from sage.rings.number_field.number_field import is_CyclotomicField sage: is_CyclotomicField(NumberField(x^2 + 1,'zeta4')) + doctest:warning... + DeprecationWarning: is_CyclotomicField is deprecated; + use isinstance(..., sage.rings.abc.NumberField_cyclotomic instead + See https://trac.sagemath.org/32660 for details. False sage: is_CyclotomicField(CyclotomicField(4)) True @@ -1252,6 +1259,8 @@ def is_CyclotomicField(x): sage: is_CyclotomicField(7) False """ + from sage.misc.superseded import deprecation + deprecation(32660, 'is_CyclotomicField is deprecated; use isinstance(..., sage.rings.abc.NumberField_cyclotomic instead') return isinstance(x, NumberField_cyclotomic) @@ -10355,7 +10364,7 @@ def _factor_univariate_polynomial(self, poly, **kwargs): return poly._factor_pari_helper(G) -class NumberField_cyclotomic(NumberField_absolute): +class NumberField_cyclotomic(NumberField_absolute, sage.rings.abc.NumberField_cyclotomic): """ Create a cyclotomic extension of the rational field. @@ -11258,7 +11267,7 @@ def is_isomorphic(self, other): sage: K.is_isomorphic(CyclotomicField(8)) False """ - if is_CyclotomicField(other): + if isinstance(other, NumberField_cyclotomic): return self.zeta_order() == other.zeta_order() return NumberField_generic.is_isomorphic(self, other) diff --git a/src/sage/rings/universal_cyclotomic_field.py b/src/sage/rings/universal_cyclotomic_field.py index 9c7ed719378..2f5c930d9ff 100644 --- a/src/sage/rings/universal_cyclotomic_field.py +++ b/src/sage/rings/universal_cyclotomic_field.py @@ -1534,14 +1534,16 @@ def _element_constructor_(self, elt): return self.element_class(self, obj) # late import to avoid slowing down the above conversions - from sage.rings.number_field.number_field_element import NumberFieldElement - from sage.rings.number_field.number_field import NumberField_cyclotomic, CyclotomicField + import sage.rings.abc P = parent(elt) - if isinstance(elt, NumberFieldElement) and isinstance(P, NumberField_cyclotomic): - n = P.gen().multiplicative_order() - elt = CyclotomicField(n)(elt) - return sum(c * self.gen(n, i) - for i, c in enumerate(elt._coefficients())) + if isinstance(P, sage.rings.abc.NumberField_cyclotomic): + from sage.rings.number_field.number_field_element import NumberFieldElement + if isinstance(elt, NumberFieldElement): + from sage.rings.number_field.number_field import CyclotomicField + n = P.gen().multiplicative_order() + elt = CyclotomicField(n)(elt) + return sum(c * self.gen(n, i) + for i, c in enumerate(elt._coefficients())) if hasattr(elt, '_algebraic_'): return elt._algebraic_(self) @@ -1568,8 +1570,8 @@ def _coerce_map_from_(self, other): """ if other is ZZ or other is QQ: return True - from sage.rings.number_field.number_field import NumberField_cyclotomic - if isinstance(other, NumberField_cyclotomic): + import sage.rings.abc + if isinstance(other, sage.rings.abc.NumberField_cyclotomic): return True def _factor_univariate_polynomial(self, f): From 9883de7f68cc58dfd3428dd1b180a708cb27b50a Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 16 Oct 2021 12:01:38 +0200 Subject: [PATCH 415/511] trac #32695: fix internet doctests --- src/sage/databases/oeis.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index ead5a2174ef..91d2a52e501 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -344,7 +344,7 @@ class OEIS: sage: fibo.formulas()[4] # optional -- internet 'F(n) = F(n-1) + F(n-2) = -(-1)^n F(-n).' - sage: fibo.comments()[1] # optional -- internet + sage: fibo.comments()[6] # optional -- internet "F(n+2) = number of binary sequences of length n that have no consecutive 0's." @@ -539,10 +539,10 @@ def find_by_subsequence(self, subsequence, max_results=3, first_result=0): EXAMPLES:: - sage: oeis.find_by_subsequence([2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]) # optional -- internet + sage: oeis.find_by_subsequence([2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]) # optional -- internet 0: A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. 1: A212804: Expansion of (1 - x)/(1 - x - x^2). - 2: A177194: Fibonacci numbers whose decimal expansion does not contain any digit 0. + 2: A020695: Pisot sequence E(2,3). sage: fibo = _[0] ; fibo # optional -- internet A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. @@ -1504,7 +1504,7 @@ def references(self): A007540: Wilson primes: primes p such that (p-1)! == -1 (mod p^2). sage: w.references() # optional -- internet - ...A. H. Beiler, Recreations in the Theory of Numbers, Dover, NY, 1964, p. 52. + ...Albert H. Beiler, Recreations in the Theory of Numbers, Dover, NY, 1964, p. 52. ... TESTS:: @@ -1639,7 +1639,7 @@ def cross_references(self, fetch=False): sage: nbalanced.cross_references(fetch=True) # optional -- internet 0: A049703: a(0) = 0; for n>0, a(n) = A005598(n)/2. 1: A049695: Array T read by diagonals; ... - 2: A103116: a(n) = A005598(n) - 1. + 2: A103116: a(n) = Sum_{i=1..n} (n-i+1)*phi(i). 3: A000010: Euler totient function phi(n): count numbers <= n and prime to n. sage: phi = _[3] # optional -- internet @@ -1721,10 +1721,15 @@ def comments(self): sage: f = oeis(45) ; f # optional -- internet A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. - sage: f.comments()[:3] # optional -- internet - 0: Also sometimes called Lamé's sequence. - 1: F(n+2) = number of binary sequences of length n that have no consecutive 0's. - 2: F(n+2) = number of subsets of {1,2,...,n} that contain no consecutive integers. + sage: f.comments()[:8] # optional -- internet + 0: D. E. Knuth writes... + 1: In keeping with historical accounts... + 2: Susantha Goonatilake writes... + 3: Also sometimes called Hemachandra numbers. + 4: Also sometimes called Lamé's sequence. + 5: ... + 6: F(n+2) = number of binary sequences of length n that have no consecutive 0's. + 7: F(n+2) = number of subsets of {1,2,...,n} that contain no consecutive integers. TESTS:: From eac63034ac8e190c61644ec510346fee6de17ff1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Oct 2021 19:24:37 -0700 Subject: [PATCH 416/511] src/sage/interfaces/polymake.py: Add missing import --- src/sage/interfaces/polymake.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index b4183a8ba31..6e20f555a70 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -332,6 +332,7 @@ def convert(y): r.__sage_dict = z # do this to avoid having the entries of the list be garbage collected return r + import sage.rings.abc from sage.rings.integer import Integer from sage.rings.rational import Rational from sage.rings.real_double import RDF From 49dc68abd409d07fb0b73cc7c1cc159c7439b810 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Oct 2021 20:19:36 -0700 Subject: [PATCH 417/511] sage.rings.abc: Add SymbolicRing, CallableSymbolicExpressionRing --- src/sage/rings/abc.pyx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index 147dcb4f089..530408d1b18 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -47,3 +47,19 @@ class Order: """ pass + + +cdef class SymbolicRing(CommutativeRing): + r""" + Abstract base class for :class:`~sage.rings.symbolic.ring.SymbolicRing`. + """ + + pass + + +class CallableSymbolicExpressionRing(SymbolicRing): + r""" + Abstract base class for :class:`~sage.rings.symbolic.callable.CallableSymbolicExpressionRing_class`. + """ + + pass From 5d50f092e297e92f014584fe2165ce4ae01c867b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Oct 2021 20:19:06 -0700 Subject: [PATCH 418/511] sage.symbolic: Use sage.rings.abc.{SymbolicRing,CallableSymbolicExpressionRing} --- src/sage/symbolic/callable.py | 3 ++- src/sage/symbolic/ring.pxd | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/symbolic/callable.py b/src/sage/symbolic/callable.py index f1a45811db8..dd0c5e1f67b 100644 --- a/src/sage/symbolic/callable.py +++ b/src/sage/symbolic/callable.py @@ -61,6 +61,7 @@ SyntaxError: can...t assign to function call """ +import sage.rings.abc from sage.symbolic.ring import SymbolicRing, SR from sage.categories.pushout import ConstructionFunctor @@ -267,7 +268,7 @@ def unify_arguments(self, x): return tuple(new_list) -class CallableSymbolicExpressionRing_class(SymbolicRing): +class CallableSymbolicExpressionRing_class(SymbolicRing, sage.rings.abc.CallableSymbolicExpressionRing): def __init__(self, arguments): """ EXAMPLES: diff --git a/src/sage/symbolic/ring.pxd b/src/sage/symbolic/ring.pxd index ed358c4a3c7..9e628098dd1 100644 --- a/src/sage/symbolic/ring.pxd +++ b/src/sage/symbolic/ring.pxd @@ -1,4 +1,4 @@ -from sage.rings.ring cimport CommutativeRing +cimport sage.rings.abc -cdef class SymbolicRing(CommutativeRing): +cdef class SymbolicRing(sage.rings.abc.SymbolicRing): cdef public dict symbols From a862442d66f3fcfebb310c9a264fb274a26965d0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Oct 2021 20:20:17 -0700 Subject: [PATCH 419/511] src/sage/dynamics/arithmetic_dynamics/affine_ds.py: Use sage.rings.abc.SymbolicRing --- src/sage/dynamics/arithmetic_dynamics/affine_ds.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py index 116ee4e12b9..84ddb002252 100644 --- a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py @@ -56,9 +56,9 @@ class initialization directly. from sage.schemes.affine.affine_subscheme import AlgebraicScheme_subscheme_affine from sage.schemes.generic.morphism import SchemeMorphism_polynomial from sage.structure.element import get_coercion_model -from sage.symbolic.ring import is_SymbolicExpressionRing -from sage.symbolic.ring import var -from sage.symbolic.ring import SR + +import sage.rings.abc + class DynamicalSystem_affine(SchemeMorphism_polynomial_affine_space, DynamicalSystem): @@ -275,7 +275,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None): else: polys = [PR(poly) for poly in polys] if domain is None: - if PR is SR: + if isinstance(PR, sage.rings.abc.SymbolicRing): raise TypeError("Symbolic Ring cannot be the base ring") if fraction_field: PR = PR.ring() @@ -292,7 +292,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None): if len(polys) != domain.ambient_space().coordinate_ring().ngens(): raise ValueError('Number of polys does not match dimension of {}'.format(domain)) R = domain.base_ring() - if R is SR: + if isinstance(R, sage.rings.abc.SymbolicRing): raise TypeError("Symbolic Ring cannot be the base ring") if not is_AffineSpace(domain) and not isinstance(domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') @@ -529,7 +529,8 @@ def dynatomic_polynomial(self, period): F = G.dynatomic_polynomial(period) T = G.domain().coordinate_ring() S = self.domain().coordinate_ring() - if is_SymbolicExpressionRing(F.parent()): + if isinstance(F.parent(), sage.rings.abc.SymbolicRing): + from sage.symbolic.ring import var u = var(self.domain().coordinate_ring().variable_name()) return F.subs({F.variables()[0]:u,F.variables()[1]:1}) elif T(F.denominator()).degree() == 0: From 24cd270773ef77900747bb0d5a6cbf7683b79a64 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Oct 2021 20:20:31 -0700 Subject: [PATCH 420/511] src/sage/matrix/matrix2.pyx: Use sage.rings.abc.SymbolicRing --- src/sage/matrix/matrix2.pyx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index f94e77474c8..ae7be68d55a 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -1984,8 +1984,6 @@ cdef class Matrix(Matrix1): sage: A.determinant() == B.determinant() True """ - from sage.symbolic.ring import is_SymbolicExpressionRing - cdef Py_ssize_t n n = self._ncols @@ -2074,7 +2072,7 @@ cdef class Matrix(Matrix1): # is then assumed to not be a variable in the symbolic ring. But this # resulted in further exceptions/ errors. - var = 'A0123456789' if is_SymbolicExpressionRing(R) else 'x' + var = 'A0123456789' if isinstance(R, sage.rings.abc.SymbolicRing) else 'x' try: charp = self.charpoly(var, algorithm="df") except ValueError: From 5fb862e568f0635c93267847079adc8695e83295 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Oct 2021 20:49:07 -0700 Subject: [PATCH 421/511] Deprecate is_[Callable]SymbolicExpressionRing, replace uses by isinstance(..., sage.rings.abc....) --- src/sage/modules/free_module.py | 8 ++++---- src/sage/modules/free_module_element.pyx | 6 +++--- src/sage/symbolic/callable.py | 8 +++++++- src/sage/symbolic/expression.pyx | 5 ++--- src/sage/symbolic/ring.pyx | 10 +++++++++- 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 1e3c73da128..ba5e1eb6ccb 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -7448,12 +7448,12 @@ def element_class(R, is_sparse): return sage.modules.vector_real_double_dense.Vector_real_double_dense elif isinstance(R, sage.rings.abc.ComplexDoubleField) and not is_sparse: return sage.modules.vector_complex_double_dense.Vector_complex_double_dense - elif sage.symbolic.ring.is_SymbolicExpressionRing(R) and not is_sparse: - import sage.modules.vector_symbolic_dense - return sage.modules.vector_symbolic_dense.Vector_symbolic_dense - elif sage.symbolic.callable.is_CallableSymbolicExpressionRing(R) and not is_sparse: + elif isinstance(R, sage.rings.abc.CallableSymbolicExpressionRing) and not is_sparse: import sage.modules.vector_callable_symbolic_dense return sage.modules.vector_callable_symbolic_dense.Vector_callable_symbolic_dense + elif isinstance(R, sage.rings.abc.SymbolicRing) and not is_sparse: + import sage.modules.vector_symbolic_dense + return sage.modules.vector_symbolic_dense.Vector_symbolic_dense else: if is_sparse: return free_module_element.FreeModuleElement_generic_sparse diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index 21d898c117c..4be7ff4ede4 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -118,6 +118,7 @@ from sage.structure.element cimport Element, ModuleElement, RingElement, Vector from sage.structure.element import canonical_coercion from sage.structure.richcmp cimport richcmp_not_equal, richcmp, rich_to_bool +cimport sage.rings.abc from sage.rings.ring import is_Ring from sage.rings.infinity import Infinity, AnInfinity from sage.rings.integer_ring import ZZ @@ -3933,9 +3934,8 @@ cdef class FreeModuleElement(Vector): # abstract base class (r, theta) |--> r*cos(theta)^2 + r*sin(theta)^2 """ if var is None: - from sage.symbolic.callable import is_CallableSymbolicExpressionRing - from sage.calculus.all import jacobian - if is_CallableSymbolicExpressionRing(self.coordinate_ring()): + if isinstance(self.coordinate_ring(), sage.rings.abc.CallableSymbolicExpressionRing): + from sage.calculus.all import jacobian return jacobian(self, self.coordinate_ring().arguments()) else: raise ValueError("No differentiation variable specified.") diff --git a/src/sage/symbolic/callable.py b/src/sage/symbolic/callable.py index dd0c5e1f67b..42d24bbce5f 100644 --- a/src/sage/symbolic/callable.py +++ b/src/sage/symbolic/callable.py @@ -82,12 +82,18 @@ def is_CallableSymbolicExpressionRing(x): sage: from sage.symbolic.callable import is_CallableSymbolicExpressionRing sage: is_CallableSymbolicExpressionRing(QQ) + doctest:warning... + DeprecationWarning: is_CallableSymbolicExpressionRing is deprecated; + use isinstance(..., sage.rings.abc.CallableSymbolicExpressionRing instead + See https://trac.sagemath.org/32665 for details. False sage: var('x,y,z') (x, y, z) sage: is_CallableSymbolicExpressionRing(CallableSymbolicExpressionRing((x,y,z))) True """ + from sage.misc.superseded import deprecation + deprecation(32665, 'is_CallableSymbolicExpressionRing is deprecated; use isinstance(..., sage.rings.abc.CallableSymbolicExpressionRing instead') return isinstance(x, CallableSymbolicExpressionRing_class) def is_CallableSymbolicExpression(x): @@ -301,7 +307,7 @@ def _coerce_map_from_(self, R): sage: g.parent().has_coerce_map_from(f.parent()) True """ - if is_CallableSymbolicExpressionRing(R): + if isinstance(R, CallableSymbolicExpressionRing): args = self.arguments() if all(a in args for a in R.arguments()): return True diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index d7932ea3486..6966a183590 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -13080,10 +13080,8 @@ cdef class Expression(Expression_abc): """ from sage.symbolic.integration.integral import \ integral, _normalize_integral_input - from sage.symbolic.callable import \ - CallableSymbolicExpressionRing, is_CallableSymbolicExpressionRing R = self._parent - if is_CallableSymbolicExpressionRing(R): + if isinstance(R, sage.rings.abc.CallableSymbolicExpressionRing): f = SR(self) f, v, a, b = _normalize_integral_input(f, *args) # Definite integral with respect to a positional variable. @@ -13092,6 +13090,7 @@ cdef class Expression(Expression_abc): arguments.remove(v) if arguments: arguments = tuple(arguments) + from sage.symbolic.callable import CallableSymbolicExpressionRing R = CallableSymbolicExpressionRing(arguments, check=False) else: # all arguments are gone R = SR diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index ae1efb6e0aa..b5f53c07cf0 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -1309,7 +1309,13 @@ def the_SymbolicRing(): def is_SymbolicExpressionRing(R): """ - Returns True if *R* is the symbolic expression ring. + Returns True if ``R`` is the symbolic expression ring. + + This function is deprecated. Instead, either use ``R is SR`` (to + test whether ``R`` is the unique symbolic ring ``SR``); or + ``isinstance`` with :class:`~sage.rings.abc.SymbolicRing` + (when also symbolic subrings and callable symbolic rings should + be accepted). EXAMPLES:: @@ -1319,6 +1325,8 @@ def is_SymbolicExpressionRing(R): sage: is_SymbolicExpressionRing(SR) True """ + from sage.misc.superseded import deprecation + deprecation(32665, 'is_SymbolicExpressionRing is deprecated; use "... is SR" or isinstance(..., sage.rings.abc.SymbolicRing instead') return R is SR def var(name, **kwds): From ee4bd52cfa12357872281a57ec96f63eb2b96a18 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Oct 2021 21:27:05 -0700 Subject: [PATCH 422/511] sage.rings.abc, sage.symbolic.ring: Fixup --- src/sage/modules/free_module_element.pyx | 2 +- src/sage/rings/abc.pxd | 7 ++++++- src/sage/symbolic/ring.pyx | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index 4be7ff4ede4..0e3e55f4a23 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -118,7 +118,7 @@ from sage.structure.element cimport Element, ModuleElement, RingElement, Vector from sage.structure.element import canonical_coercion from sage.structure.richcmp cimport richcmp_not_equal, richcmp, rich_to_bool -cimport sage.rings.abc +import sage.rings.abc from sage.rings.ring import is_Ring from sage.rings.infinity import Infinity, AnInfinity from sage.rings.integer_ring import ZZ diff --git a/src/sage/rings/abc.pxd b/src/sage/rings/abc.pxd index 5b2aec37eff..a53b512d62f 100644 --- a/src/sage/rings/abc.pxd +++ b/src/sage/rings/abc.pxd @@ -1,4 +1,4 @@ -from .ring cimport Field +from .ring cimport CommutativeRing, Field cdef class RealField(Field): @@ -23,3 +23,8 @@ cdef class ComplexField(Field): cdef class ComplexDoubleField(Field): pass + + +cdef class SymbolicRing(CommutativeRing): + + pass diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index b5f53c07cf0..128ff05a8e1 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -32,6 +32,8 @@ The symbolic ring # **************************************************************************** from sage.rings.integer cimport Integer +from sage.rings.ring cimport CommutativeRing + import sage.rings.abc from sage.symbolic.expression cimport ( @@ -61,7 +63,7 @@ KEYWORDS = set(keyword.kwlist).union(['exec', 'print', 'None', 'True', 'False', 'nonlocal']) -cdef class SymbolicRing(CommutativeRing): +cdef class SymbolicRing(sage.rings.abc.SymbolicRing): """ Symbolic Ring, parent object for all symbolic expressions. """ From b484d51976ddc0aebd6072faa9986512a8090d53 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Oct 2021 21:55:56 -0700 Subject: [PATCH 423/511] src/sage/symbolic/callable.py: Fixup --- src/sage/symbolic/callable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/symbolic/callable.py b/src/sage/symbolic/callable.py index 42d24bbce5f..5f3a7bea659 100644 --- a/src/sage/symbolic/callable.py +++ b/src/sage/symbolic/callable.py @@ -307,7 +307,7 @@ def _coerce_map_from_(self, R): sage: g.parent().has_coerce_map_from(f.parent()) True """ - if isinstance(R, CallableSymbolicExpressionRing): + if isinstance(R, CallableSymbolicExpressionRing_class): args = self.arguments() if all(a in args for a in R.arguments()): return True From fad87c08a90d8b13ba4a48102b2faca3911c4cf6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Oct 2021 21:56:17 -0700 Subject: [PATCH 424/511] Expression.is_callable: New --- src/sage/symbolic/expression.pyx | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 6966a183590..c43196f4b48 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -3124,6 +3124,22 @@ cdef class Expression(Expression_abc): return obj.is_square() + def is_callable(self): + r""" + Return ``True`` if ``self`` is a callable symbolic expression. + + EXAMPLES:: + + sage: var('a x y z') + (a, x, y, z) + sage: f(x, y) = a + 2*x + 3*y + z + sage: f.is_callable() + True + sage: (a+2*x).is_callable() + False + """ + return isinstance(self.parent(), sage.rings.abc.CallableSymbolicExpressionRing) + def left_hand_side(self): """ If self is a relational expression, return the left hand side @@ -4632,7 +4648,7 @@ cdef class Expression(Expression_abc): symb = vars[0] elif len(vars) == 0: return self._parent(0) - elif sage.symbolic.callable.is_CallableSymbolicExpression(self): + elif self.is_callable(): return self.gradient() else: raise ValueError("No differentiation variable specified.") @@ -12714,7 +12730,6 @@ cdef class Expression(Expression_abc): sage: plot(f,0,1) Graphics object consisting of 1 graphics primitive """ - from sage.symbolic.callable import is_CallableSymbolicExpression from sage.symbolic.ring import is_SymbolicVariable from sage.plot.plot import plot @@ -12730,7 +12745,7 @@ cdef class Expression(Expression_abc): break if param is None: - if is_CallableSymbolicExpression(self): + if self.is_callable(): A = self.arguments() if len(A) == 0: raise ValueError("function has no input arguments") From 4bc059ba6807fb35cdfc04bf4d0b5a51bd9def20 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Oct 2021 21:59:07 -0700 Subject: [PATCH 425/511] src/sage/ext/fast_callable.pyx: Remove use of is_CallableSymbolicExpression --- src/sage/ext/fast_callable.pyx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index d54d501226c..da1ad9ed5b3 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -428,13 +428,11 @@ def fast_callable(x, domain=None, vars=None, et = x vars = et._etb._vars else: - from sage.symbolic.callable import is_CallableSymbolicExpression - if not vars: # fast_float passes empty list/tuple vars = None - if is_CallableSymbolicExpression(x): + if isinstance(x, Expression_abc) and x.is_callable(): if vars is None: vars = x.arguments() if expect_one_var and len(vars) != 1: From 8624925fadce22241a0e7abdc9952ee4bbcf4a0a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 09:20:31 -0700 Subject: [PATCH 426/511] src/sage/symbolic/ring.pyx: Update doctest output with deprecation warning --- src/sage/symbolic/ring.pyx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 128ff05a8e1..115c1361791 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -1323,6 +1323,10 @@ def is_SymbolicExpressionRing(R): sage: from sage.symbolic.ring import is_SymbolicExpressionRing sage: is_SymbolicExpressionRing(ZZ) + doctest:warning... + DeprecationWarning: is_SymbolicExpressionRing is deprecated; + use "... is SR" or isinstance(..., sage.rings.abc.SymbolicRing instead + See https://trac.sagemath.org/32665 for details. False sage: is_SymbolicExpressionRing(SR) True From 37da733abd71b634e542334ec2d460bff002e444 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 09:24:05 -0700 Subject: [PATCH 427/511] src/sage/sets/condition_set.py: Remove use of is_CallableSymbolicExpression --- src/sage/sets/condition_set.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/sage/sets/condition_set.py b/src/sage/sets/condition_set.py index 80ff63d2260..34265775dd3 100644 --- a/src/sage/sets/condition_set.py +++ b/src/sage/sets/condition_set.py @@ -20,14 +20,9 @@ from sage.misc.cachefunc import cached_method from sage.misc.misc import _stable_uniq from sage.structure.element import Expression - -try: - from sage.symbolic.callable import is_CallableSymbolicExpression -except ImportError: - is_CallableSymbolicExpression = lambda x: False - from .set import Set, Set_base, Set_boolean_operators, Set_add_sub_operators + class ConditionSet(Set_generic, Set_base, Set_boolean_operators, Set_add_sub_operators, UniqueRepresentation): r""" @@ -160,7 +155,7 @@ def __classcall_private__(cls, universe, *predicates, vars=None, names=None, cat other_predicates = [] for predicate in predicates: - if is_CallableSymbolicExpression(predicate): + if isinstance(predicate, Expression) and predicate.is_callable(): if names is None: names = tuple(str(var) for var in predicate.args()) elif len(names) != len(predicate.args()): @@ -271,7 +266,7 @@ def _repr_condition(self, predicate): sage: ZeroDimButNotNullary._repr_condition(ZeroDimButNotNullary._predicates[0]) 't > 0' """ - if is_CallableSymbolicExpression(predicate): + if isinstance(predicate, Expression) and predicate.is_callable(): args = self.arguments() if len(args) == 1: args = args[0] @@ -364,7 +359,7 @@ def _call_predicate(self, predicate, element): sage: Nullary._call_predicate(predicate, element) t > 0 """ - if is_CallableSymbolicExpression(predicate): + if isinstance(predicate, Expression) and predicate.is_callable(): if len(predicate.arguments()) != 1: return predicate(*element) return predicate(element) From 80a8f9ec657528c814767bfd0da0500a7d650f2f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 09:36:35 -0700 Subject: [PATCH 428/511] sage.plot: Remove use of is_CallableSymbolicExpression, is_SymbolicEquation --- src/sage/plot/contour_plot.py | 4 ++-- src/sage/plot/misc.py | 6 ++---- src/sage/plot/plot3d/plot3d.py | 6 +++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/sage/plot/contour_plot.py b/src/sage/plot/contour_plot.py index 27577d396d6..690311744e7 100644 --- a/src/sage/plot/contour_plot.py +++ b/src/sage/plot/contour_plot.py @@ -1195,8 +1195,8 @@ def f(x,y): ... ValueError: only one of color or rgbcolor should be specified """ - from sage.symbolic.expression import is_SymbolicEquation - if is_SymbolicEquation(f): + from sage.structure.element import Expression + if isinstance(f, Expression) and f.is_relational(): if f.operator() != operator.eq: raise ValueError("input to implicit plot must be function " "or equation") diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index b57976552b6..edab4ce4183 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -15,7 +15,7 @@ from sage.ext.fast_eval import fast_float -from sage.structure.element import is_Vector +from sage.structure.element import is_Vector, Expression def setup_for_eval_on_grid(funcs, ranges, plot_points=None, return_vars=False): """ @@ -187,15 +187,13 @@ def unify_arguments(funcs): sage: sage.plot.misc.unify_arguments((x+y,x-y)) ((x, y), (x, y)) """ - from sage.symbolic.callable import is_CallableSymbolicExpression - vars=set() free_variables=set() if not isinstance(funcs, (list, tuple)): funcs = [funcs] for f in funcs: - if is_CallableSymbolicExpression(f): + if isinstance(f, Expression) and f.is_callable(): f_args = set(f.arguments()) vars.update(f_args) else: diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index 9678373657c..0fccc9cb1ec 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -1046,13 +1046,13 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): Graphics3d Object """ if transformation is not None: - params=None - from sage.symbolic.callable import is_CallableSymbolicExpression + params = None + from sage.structure.element import Expression # First, determine the parameters for f (from the first item of urange # and vrange, preferably). if len(urange) == 3 and len(vrange) == 3: params = (urange[0], vrange[0]) - elif is_CallableSymbolicExpression(f): + elif isinstance(f, Expression) and f.is_callable(): params = f.variables() from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense From a287531e1dd03d32d554735a26966852c3c56057 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 09:51:50 -0700 Subject: [PATCH 429/511] src/sage/schemes/elliptic_curves/constructor.py: Remove use of SR, is_SymbolicEquation; add test for symbolic input --- .../schemes/elliptic_curves/constructor.py | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/constructor.py b/src/sage/schemes/elliptic_curves/constructor.py index 90bc4519082..bd7cfc8239d 100644 --- a/src/sage/schemes/elliptic_curves/constructor.py +++ b/src/sage/schemes/elliptic_curves/constructor.py @@ -36,10 +36,8 @@ _Fields = Fields() from sage.structure.sequence import Sequence -from sage.structure.element import parent +from sage.structure.element import parent, Expression from sage.structure.factory import UniqueFactory -from sage.symbolic.ring import SR -from sage.symbolic.expression import is_SymbolicEquation class EllipticCurveFactory(UniqueFactory): @@ -385,6 +383,20 @@ def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, incorrect data may lead to wrong results of computations instead of errors or warnings. + TESTS:: + + sage: var('x', 'y', 'v', 'w') + (x, y, v, w) + sage: EllipticCurve(y^2 + y > x^3 + x - 9) + Traceback (most recent call last): + ... + ValueError: no symbolic relations other than equalities are allowed + sage: E = EllipticCurve(y^2 + y == x^3 + x - 9) + sage: E is EllipticCurve(y^2 + y - ( x^3 + x - 9 )) + True + sage: R. = QQ[] + sage: E is EllipticCurve(y^2 + y - ( x^3 + x - 9 )) + True """ R = None if is_Ring(x): @@ -400,10 +412,13 @@ def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, raise ValueError("First parameter (if present) must be a ring when j is specified") x = coefficients_from_j(j, minimal_twist) - if is_SymbolicEquation(x): + if isinstance(x, Expression) and x.is_relational(): + import operator + if x.operator() != operator.eq: + raise ValueError("no symbolic relations other than equalities are allowed") x = x.lhs() - x.rhs() - if parent(x) is SR: + if isinstance(parent(x), sage.rings.abc.SymbolicRing): x = x._polynomial_(rings.QQ['x', 'y']) if is_MPolynomial(x): From c9861d16af2e435985ab77239f6eb5b0c775fa6b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 10:05:46 -0700 Subject: [PATCH 430/511] src/sage/interfaces/qepcad.py: Remove use of is_SymbolicEquation --- src/sage/interfaces/qepcad.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index 29baa767b4e..9317b166608 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -1924,11 +1924,9 @@ def atomic(self, lhs, op='=', rhs=0): if isinstance(lhs, qformula): return lhs - from sage.symbolic.expression import is_SymbolicEquation - if is_SymbolicEquation(lhs): - rhs = lhs.rhs() - op = lhs.operator() - lhs = lhs.lhs() + from sage.structure.element import Expression + if isinstance(lhs, Expression) and lhs.is_relational(): + lhs, op, rhs = lhs.lhs(), lhs.operator(), lhs.rhs() op = self._normalize_op(op) From 341337a0089d9f27f759f2c5a3f5b33ee795a75c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 10:08:01 -0700 Subject: [PATCH 431/511] src/sage/ext/fast_callable.pyx: Remove use of is_SymbolicVariable --- src/sage/ext/fast_callable.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index da1ad9ed5b3..10acc5e3649 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -438,7 +438,6 @@ def fast_callable(x, domain=None, vars=None, if expect_one_var and len(vars) != 1: raise ValueError(f"passed expect_one_var=True, but the callable expression takes {len(vars)} arguments") elif isinstance(x, Expression_abc): - from sage.symbolic.ring import is_SymbolicVariable if vars is None: vars = x.variables() if expect_one_var and len(vars) <= 1: @@ -447,7 +446,7 @@ def fast_callable(x, domain=None, vars=None, else: raise ValueError("list of variables must be specified for symbolic expressions") def to_var(var): - if is_SymbolicVariable(var): + if isinstance(var, Expression_abc) and var.is_symbol(): return var from sage.symbolic.ring import SR return SR.var(var) From cd1dd7489196b6ad43b3d78215d502d0913971ec Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 10:39:59 -0700 Subject: [PATCH 432/511] build/pkgs/flit_core: Update to 3.4.0 --- build/pkgs/flit_core/checksums.ini | 6 +++--- build/pkgs/flit_core/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/flit_core/checksums.ini b/build/pkgs/flit_core/checksums.ini index a6d2508fd40..5a0b6ecb0c1 100644 --- a/build/pkgs/flit_core/checksums.ini +++ b/build/pkgs/flit_core/checksums.ini @@ -1,5 +1,5 @@ tarball=flit_core-VERSION.tar.gz -sha1=cc89ef0fef30582845dc40d73dda7fa3bfa494cd -md5=697eb7da76b4eb5833bbf8bb97131879 -cksum=4051177318 +sha1=941603f1734b9b4af74954429ef51f97540f30e5 +md5=a4bb11b54bcf029ec2cd5cb981c07ded +cksum=2905595733 upstream_url=https://pypi.io/packages/source/f/flit_core/flit_core-VERSION.tar.gz diff --git a/build/pkgs/flit_core/package-version.txt b/build/pkgs/flit_core/package-version.txt index 15a27998172..18091983f59 100644 --- a/build/pkgs/flit_core/package-version.txt +++ b/build/pkgs/flit_core/package-version.txt @@ -1 +1 @@ -3.3.0 +3.4.0 From d6740651c05dc2c90fe84106461b588f7a47cf0a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 10:40:19 -0700 Subject: [PATCH 433/511] build/pkgs/tomli/dependencies: Drop toml, as flit_core now uses tomli --- build/pkgs/tomli/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/tomli/dependencies b/build/pkgs/tomli/dependencies index 31b6d3bd71c..7cd1e28759d 100644 --- a/build/pkgs/tomli/dependencies +++ b/build/pkgs/tomli/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | pip flit_core toml +$(PYTHON) | pip flit_core ---------- All lines of this file are ignored except the first. From 7100660478031cc355963056bda40ede2d538543 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 10:48:30 -0700 Subject: [PATCH 434/511] build/pkgs/backcall/dependencies: flit_core now uses tomli --- build/pkgs/backcall/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/backcall/dependencies b/build/pkgs/backcall/dependencies index 97701a95eec..35228f20368 100644 --- a/build/pkgs/backcall/dependencies +++ b/build/pkgs/backcall/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) flit_core toml +$(PYTHON) | $(PYTHON_TOOLCHAIN) flit_core tomli ---------- All lines of this file are ignored except the first. From 0f5158f08e1129758d92d2936daf5504f2895138 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 10:51:13 -0700 Subject: [PATCH 435/511] build/pkgs/setuptools_scm: Update to 6.3.2 --- build/pkgs/setuptools_scm/checksums.ini | 6 +++--- build/pkgs/setuptools_scm/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/setuptools_scm/checksums.ini b/build/pkgs/setuptools_scm/checksums.ini index 10f9425e48f..a5c492c3e2f 100644 --- a/build/pkgs/setuptools_scm/checksums.ini +++ b/build/pkgs/setuptools_scm/checksums.ini @@ -1,5 +1,5 @@ tarball=setuptools_scm-VERSION.tar.gz -sha1=6d793de55ec500f7516802830f903cbc460a7999 -md5=7e17d25fd5bc5b128cfe2964a2e4cd5b -cksum=1288889703 +sha1=a4f02fddae697614e356cadfddb6241cc7737f38 +md5=32918d8ac566360c21411e0b3556c695 +cksum=1450556136 upstream_url=https://pypi.io/packages/source/s/setuptools_scm/setuptools_scm-VERSION.tar.gz diff --git a/build/pkgs/setuptools_scm/package-version.txt b/build/pkgs/setuptools_scm/package-version.txt index dc0208aba8e..91e4a9f2622 100644 --- a/build/pkgs/setuptools_scm/package-version.txt +++ b/build/pkgs/setuptools_scm/package-version.txt @@ -1 +1 @@ -6.3.1 +6.3.2 From e053097a07f635dae83dd69379a13a6335c0b45e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 10:55:53 -0700 Subject: [PATCH 436/511] build/pkgs/importlib_metadata/dependencies: setuptools_scm[toml] uses tomli now --- build/pkgs/importlib_metadata/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/importlib_metadata/dependencies b/build/pkgs/importlib_metadata/dependencies index c136b9290b7..9fcc3b0cc65 100644 --- a/build/pkgs/importlib_metadata/dependencies +++ b/build/pkgs/importlib_metadata/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) zipp typing_extensions | $(PYTHON_TOOLCHAIN) toml +$(PYTHON) zipp typing_extensions | $(PYTHON_TOOLCHAIN) tomli ---------- All lines of this file are ignored except the first. From 1635bd3713a426939202e098e515ed5258485ab5 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Sun, 17 Oct 2021 21:09:27 +0200 Subject: [PATCH 437/511] Remove import of Chart in sage.tensor.modules (#32708) --- .../differentiable/tensorfield_paral.py | 32 +++++++++++++++++++ src/sage/tensor/modules/free_module_tensor.py | 11 ------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/sage/manifolds/differentiable/tensorfield_paral.py b/src/sage/manifolds/differentiable/tensorfield_paral.py index 17220bc4fb8..6bcd68becb6 100644 --- a/src/sage/manifolds/differentiable/tensorfield_paral.py +++ b/src/sage/manifolds/differentiable/tensorfield_paral.py @@ -304,6 +304,7 @@ # ***************************************************************************** from sage.tensor.modules.free_module_tensor import FreeModuleTensor +from sage.manifolds.chart import Chart from sage.manifolds.differentiable.tensorfield import TensorField from sage.parallel.decorate import parallel from sage.parallel.parallelism import Parallelism @@ -727,6 +728,37 @@ def _del_derived(self, del_restrictions=True): if del_restrictions: self._del_restrictions() + def _preparse_display(self, basis=None, format_spec=None): + r""" + Helper function, to be used by FreeModuleTensor.display. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: t = M.tensor_field(1, 1) + sage: t._preparse_display() + (Coordinate frame (M, (∂/∂x,∂/∂y)), None) + sage: t._preparse_display(X.frame()) + (Coordinate frame (M, (∂/∂x,∂/∂y)), None) + sage: t._preparse_display(X.frame(), X) + (Coordinate frame (M, (∂/∂x,∂/∂y)), Chart (M, (x, y))) + sage: t._preparse_display(X) # passing a chart instead of a frame + (Coordinate frame (M, (∂/∂x,∂/∂y)), Chart (M, (x, y))) + + """ + if basis is None: + basis = self._fmodule._def_basis + elif isinstance(basis, Chart): + # a coordinate chart has been passed instead of a vector frame; + # the frame is then assumed to be the coordinate frame + # associated to the chart: + if format_spec is None: + format_spec = basis + basis = basis.frame() + return (basis, format_spec) + + def _set_comp_unsafe(self, basis=None): r""" Return the components of the tensor field in a given vector frame diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index 47667bfb98c..7515fc080ce 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -200,10 +200,6 @@ class being: from sage.tensor.modules.tensor_with_indices import TensorWithIndices from sage.parallel.decorate import parallel from sage.parallel.parallelism import Parallelism -from sage.manifolds.chart import Chart - -# TODO: remove the import of Chart after _preparse_display has been redefined -# in tensor fields class FreeModuleTensor(ModuleElementWithMutability): r""" @@ -583,13 +579,6 @@ def _preparse_display(self, basis=None, format_spec=None): """ if basis is None: basis = self._fmodule._def_basis - elif isinstance(basis, Chart): - # a coordinate chart has been passed instead of a basis; - # the basis is then assumed to be the coordinate frame - # associated to the chart: - if format_spec is None: - format_spec = basis - basis = basis.frame() return (basis, format_spec) def display(self, basis=None, format_spec=None): From 502546b177c9a1bb11752e08f713c93ac6de69bb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 13:56:42 -0700 Subject: [PATCH 438/511] src/sage/geometry/abc.pyx: New --- src/sage/geometry/abc.pyx | 27 +++++++++++++++++++++++++++ src/sage/geometry/cone.py | 3 ++- src/sage/geometry/lattice_polytope.py | 3 ++- src/sage/geometry/polyhedron/base.py | 3 ++- 4 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 src/sage/geometry/abc.pyx diff --git a/src/sage/geometry/abc.pyx b/src/sage/geometry/abc.pyx new file mode 100644 index 00000000000..7c42de9e07b --- /dev/null +++ b/src/sage/geometry/abc.pyx @@ -0,0 +1,27 @@ +r""" +Abstract base classes for classes in :mod:`~sage.geometry` +""" + + +class LatticePolytope: + r""" + Abstract base class for :class:`~sage.geometry.lattice_polytope.LatticePolytopeClass` + """ + + pass + + +class ConvexRationalPolyhedralCone: + r""" + Abstract base class for :class:`~sage.geometry.cone.ConvexRationalPolyhedralCone` + """ + + pass + + +class Polyhedron: + r""" + Abstract base class for :class:`~sage.geometry.polyhedron.base.Polyhedron_base` + """ + + pass diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 177e143dd5e..5fbe3784b80 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -230,6 +230,7 @@ from sage.structure.richcmp import richcmp_method, richcmp from sage.geometry.integral_points import parallelotope_points from sage.geometry.convex_set import ConvexSet_closed +import sage.geometry.abc from sage.misc.lazy_import import lazy_import from sage.features import PythonModule @@ -1420,7 +1421,7 @@ def classify_cone_2d(ray0, ray1, check=True): # and ``ambient_ray_indices`` keyword parameters. See ``intersection`` method # for an example why this is needed. @richcmp_method -class ConvexRationalPolyhedralCone(IntegralRayCollection, Container, ConvexSet_closed): +class ConvexRationalPolyhedralCone(IntegralRayCollection, Container, ConvexSet_closed, sage.geometry.abc.ConvexRationalPolyhedralCone): r""" Create a convex rational polyhedral cone. diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 23b91ab478d..a02d9ed9d5a 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -140,6 +140,7 @@ from sage.structure.sage_object import SageObject from sage.structure.richcmp import richcmp_method, richcmp from sage.geometry.convex_set import ConvexSet_compact +import sage.geometry.abc from copy import copy from collections.abc import Hashable @@ -469,7 +470,7 @@ def is_LatticePolytope(x): return isinstance(x, LatticePolytopeClass) @richcmp_method -class LatticePolytopeClass(ConvexSet_compact, Hashable): +class LatticePolytopeClass(ConvexSet_compact, Hashable, sage.geometry.abc.LatticePolytope): r""" Create a lattice polytope. diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index d50d33b1053..46903d92a15 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -53,6 +53,7 @@ from sage.graphs.graph import Graph from sage.geometry.convex_set import ConvexSet_closed, AffineHullProjectionData +import sage.geometry.abc from .constructor import Polyhedron from sage.geometry.relative_interior import RelativeInterior from sage.categories.sets_cat import EmptySetError @@ -100,7 +101,7 @@ def is_Polyhedron(X): ######################################################################### -class Polyhedron_base(Element, ConvexSet_closed): +class Polyhedron_base(Element, ConvexSet_closed, sage.geometry.abc.Polyhedron): """ Base class for Polyhedron objects From 79a8ba4787ddab5a7318499aeba1888ed48959c4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 14:14:42 -0700 Subject: [PATCH 439/511] sage.schemes.toric: Remove use of is_Cone --- src/sage/schemes/toric/chow_group.py | 4 ++-- src/sage/schemes/toric/divisor.py | 4 ++-- src/sage/schemes/toric/sheaf/klyachko.py | 5 ++--- src/sage/schemes/toric/variety.py | 7 ++++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/schemes/toric/chow_group.py b/src/sage/schemes/toric/chow_group.py index 84d32fe373e..60677b7dc9a 100644 --- a/src/sage/schemes/toric/chow_group.py +++ b/src/sage/schemes/toric/chow_group.py @@ -128,7 +128,7 @@ from sage.structure.factory import UniqueFactory from sage.rings.all import ZZ, QQ, Infinity -from sage.geometry.cone import is_Cone +import sage.geometry.abc from sage.schemes.toric.variety import is_ToricVariety from sage.schemes.toric.divisor import is_ToricDivisor @@ -712,7 +712,7 @@ def _element_constructor_(self, x, check=True): ( 0 | -1, -2, -2, -1 | 0 ) """ fan = self._variety.fan() - if is_Cone(x): + if isinstance(x, sage.geometry.abc.ConvexRationalPolyhedralCone): cone = fan.embed(x) return self.element_class(self, self._cone_to_V(cone), False) if is_ToricDivisor(x): diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index c9ba1d4edf9..2a6f80373d0 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -167,7 +167,7 @@ #***************************************************************************** from sage.combinat.combination import Combinations -from sage.geometry.cone import is_Cone +import sage.geometry.abc from sage.geometry.polyhedron.constructor import Polyhedron from sage.geometry.toric_lattice_element import is_ToricLatticeElement from sage.topology.simplicial_complex import SimplicialComplex @@ -539,7 +539,7 @@ def ToricDivisor(toric_variety, arg=None, ring=None, check=True, reduce=True): % (arg, toric_variety.fan())) arg = toric_variety.fan().cone_containing(arg) # Divisor by a one-cone - if is_Cone(arg): + if isinstance(arg, sage.geometry.abc.ConvexRationalPolyhedralCone): fan = toric_variety.fan() cone = fan.embed(arg) if cone.dim() != 1: diff --git a/src/sage/schemes/toric/sheaf/klyachko.py b/src/sage/schemes/toric/sheaf/klyachko.py index 0539f4204d3..953bbe06d02 100644 --- a/src/sage/schemes/toric/sheaf/klyachko.py +++ b/src/sage/schemes/toric/sheaf/klyachko.py @@ -50,9 +50,8 @@ from sage.rings.integer_ring import ZZ from sage.misc.all import cached_method from sage.matrix.constructor import vector, block_matrix, zero_matrix -from sage.geometry.cone import is_Cone from sage.modules.multi_filtered_vector_space import MultiFilteredVectorSpace - +import sage.geometry.abc def is_KlyachkoBundle(X): """ @@ -299,7 +298,7 @@ def get_filtration(self, ray=None): return self._filt X = self.variety() fan = X.fan() - if is_Cone(ray): + if isinstance(ray, sage.geometry.abc.ConvexRationalPolyhedralCone): if ray.dim() != 1: raise ValueError('not a one-dimensional cone') ray = ray.ray(0) diff --git a/src/sage/schemes/toric/variety.py b/src/sage/schemes/toric/variety.py index d70e01a482d..6286947d1f6 100644 --- a/src/sage/schemes/toric/variety.py +++ b/src/sage/schemes/toric/variety.py @@ -319,7 +319,8 @@ import sys from sage.functions.all import factorial -from sage.geometry.cone import Cone, is_Cone +import sage.geometry.abc +from sage.geometry.cone import Cone from sage.geometry.fan import Fan from sage.misc.all import latex, prod, cached_method from sage.structure.unique_representation import UniqueRepresentation @@ -2714,7 +2715,7 @@ def _orbit_closure_projection(self, cone, x): result.set_immutable() return result - assert is_Cone(x) + assert isinstance(x, sage.geometry.abc.ConvexRationalPolyhedralCone) rays = [ vector(quot(r)) for r in x.rays() ] return Cone(rays) @@ -3259,7 +3260,7 @@ def _element_constructor_(self,x): return x if isinstance(x, QuotientRingElement): x = x.lift() - elif is_Cone(x): + elif isinstance(x, sage.geometry.abc.ConvexRationalPolyhedralCone): cone = fan.embed(x) assert cone.ambient() is fan mult = cone.rays().column_matrix().index_in_saturation() From 6e32262a21842d4b1f979ce84801516f00a5025d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 14:15:15 -0700 Subject: [PATCH 440/511] src/sage/matrix/matrix2.pyx: Remove use of is_Cone --- src/sage/matrix/matrix2.pyx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index d4a8ec9d3a1..36926bce666 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -16832,11 +16832,12 @@ cdef class Matrix(Matrix1): """ from sage.symbolic.ring import SR - from sage.geometry.cone import is_Cone + import sage.geometry.abc if K2 is None: K2 = K1 - if not ( is_Cone(K1) and is_Cone(K2) ): + if not (isinstance(K1, sage.geometry.abc.ConvexRationalPolyhedralCone) + and isinstance(K2, sage.geometry.abc.ConvexRationalPolyhedralCone)): raise TypeError('K1 and K2 must be cones.') if not self.base_ring().is_exact() and not self.base_ring() is SR: msg = 'The base ring of the matrix is neither symbolic nor exact.' @@ -16975,9 +16976,9 @@ cdef class Matrix(Matrix1): """ from sage.symbolic.ring import SR - from sage.geometry.cone import is_Cone + import sage.geometry.abc - if not is_Cone(K): + if not isinstance(K, sage.geometry.abc.ConvexRationalPolyhedralCone): raise TypeError('K must be a cone.') if not self.base_ring().is_exact() and not self.base_ring() is SR: msg = 'The base ring of the matrix is neither symbolic nor exact.' @@ -17242,9 +17243,9 @@ cdef class Matrix(Matrix1): """ from sage.symbolic.ring import SR - from sage.geometry.cone import is_Cone + import sage.geometry.abc - if not is_Cone(K): + if not isinstance(K, sage.geometry.abc.ConvexRationalPolyhedralCone): raise TypeError('K must be a cone.') if not self.base_ring().is_exact() and not self.base_ring() is SR: msg = 'The base ring of the matrix is neither symbolic nor exact.' From 19aee74596989e1f51fd857b0e0471beecedd7b3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 14:15:39 -0700 Subject: [PATCH 441/511] src/sage/groups/affine_gps/group_element.py: Remove use of is_Polyhedron --- src/sage/groups/affine_gps/group_element.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/affine_gps/group_element.py b/src/sage/groups/affine_gps/group_element.py index ab02e07f097..60d81530793 100644 --- a/src/sage/groups/affine_gps/group_element.py +++ b/src/sage/groups/affine_gps/group_element.py @@ -426,8 +426,8 @@ def __call__(self, v): image_coords = self._A * vector(ring, ring.gens()) + self._b return v(*image_coords) - from sage.geometry.polyhedron.base import is_Polyhedron - if is_Polyhedron(v): + import sage.geometry.abc + if isinstance(v, sage.geometry.abc.Polyhedron): return self._A*v + self._b # otherwise, coerce v into the vector space From 87ad226d6babe026e330894f1eba99aadefbafd3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 14:15:53 -0700 Subject: [PATCH 442/511] src/sage/manifolds/subsets/pullback.py: Remove use of is_Polyhedron --- src/sage/manifolds/subsets/pullback.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/subsets/pullback.py b/src/sage/manifolds/subsets/pullback.py index 8453e346b29..edb1c8f50f5 100644 --- a/src/sage/manifolds/subsets/pullback.py +++ b/src/sage/manifolds/subsets/pullback.py @@ -28,7 +28,7 @@ from sage.manifolds.chart import Chart from sage.manifolds.scalarfield import ScalarField from sage.sets.real_set import RealSet -from sage.geometry.polyhedron.base import is_Polyhedron +import sage.geometry.abc from sage.geometry.relative_interior import RelativeInterior @@ -288,7 +288,7 @@ def _is_open(codomain_subset): if isinstance(codomain_subset, RealSet): return codomain_subset.is_open() - if is_Polyhedron(codomain_subset): + if isinstance(codomain_subset, sage.geometry.abc.Polyhedron): return codomain_subset.is_empty() or codomain_subset.is_universe() if isinstance(codomain_subset, RelativeInterior): From fa561b2ecfa1899e14d55a44cf6925185e2e5d83 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 11:02:55 -0700 Subject: [PATCH 443/511] build/pkgs/tomli/spkg-install.in: Set up PYTHONPATH --- build/pkgs/tomli/spkg-install.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/pkgs/tomli/spkg-install.in b/build/pkgs/tomli/spkg-install.in index 37ac1a53437..e62010cea1e 100644 --- a/build/pkgs/tomli/spkg-install.in +++ b/build/pkgs/tomli/spkg-install.in @@ -1,2 +1,4 @@ cd src +# tomli's build system, flit_core, has a runtime dependency on tomli. +export PYTHONPATH="$(pwd)" sdh_pip_install . From 9eea50ccf4bf2db2f824c89b21a387334b1e01b4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 16:33:08 -0700 Subject: [PATCH 444/511] build/pkgs/toml/spkg-configure.m4: If system tox is used, mark as not required --- build/pkgs/toml/spkg-configure.m4 | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 build/pkgs/toml/spkg-configure.m4 diff --git a/build/pkgs/toml/spkg-configure.m4 b/build/pkgs/toml/spkg-configure.m4 new file mode 100644 index 00000000000..0dbc722cde5 --- /dev/null +++ b/build/pkgs/toml/spkg-configure.m4 @@ -0,0 +1,7 @@ +SAGE_SPKG_CONFIGURE([toml], [ + sage_spkg_install_toml=yes + ], [dnl REQUIRED-CHECK + AC_REQUIRE([SAGE_SPKG_CONFIGURE_TOX]) + dnl toml is only needed when we cannot use system tox. + AS_VAR_SET([SPKG_REQUIRE], [$sage_spkg_install_tox]) + ]) From 8b9839a860bc2c3c3e56077f129f560a5cfdd89b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 17:51:43 -0700 Subject: [PATCH 445/511] src/sage/manifolds/subsets/pullback.py: Remove more uses of is_Polyhedron --- src/sage/manifolds/subsets/pullback.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/subsets/pullback.py b/src/sage/manifolds/subsets/pullback.py index edb1c8f50f5..42dacc02fad 100644 --- a/src/sage/manifolds/subsets/pullback.py +++ b/src/sage/manifolds/subsets/pullback.py @@ -540,7 +540,7 @@ def _coord_def(map, codomain_subset): return {chart: ManifoldSubsetPullback._realset_restriction(chart[0], codomain_subset)} - if isinstance(codomain_subset, RelativeInterior) and is_Polyhedron(codomain_subset.closure()): + if isinstance(codomain_subset, RelativeInterior) and isinstance(codomain_subset.closure(), sage.geometry.abc.Polyhedron): return {chart: ManifoldSubsetPullback._polyhedron_restriction( chart, codomain_subset.closure(), relint=True)} @@ -803,7 +803,7 @@ def is_closed(self): elif isinstance(self._codomain_subset, RealSet): # RealSet can decide closedness authoritatively return self._codomain_subset.is_closed() - elif is_Polyhedron(self._codomain_subset): + elif isinstance(self._codomain_subset, sage.geometry.abc.Polyhedron): # Regardless of their base_ring, we treat polyhedra as closed # convex subsets of R^n return True From 18aa26ff345f8eeb78d63256599839dae0ba50a4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 19:51:25 -0700 Subject: [PATCH 446/511] src/sage/features/sagemath.py: Add sage.geometry.polyhedron --- src/sage/features/sagemath.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index 2af7def3668..0ae2f755dea 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -15,6 +15,12 @@ def __init__(self): [PythonModule('sage.combinat.combinations')]) +class sage__geometry__polyhedron(PythonModule): + + def __init__(self): + PythonModule.__init__(self, 'sage.geometry.polyhedron') + + class sage__graphs(JoinFeature): def __init__(self): @@ -75,6 +81,7 @@ def sage_features(): Feature('sage.rings.real_double')] """ for feature in [sage__combinat(), + sage__geometry__polyhedron(), sage__graphs(), sage__plot(), sage__rings__number_field(), From 94715701941f5eff63ff6eec4b7f1e36003efd6c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 19:51:46 -0700 Subject: [PATCH 447/511] src/sage/geometry/abc.pyx: Add doctests --- src/sage/geometry/abc.pyx | 54 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/sage/geometry/abc.pyx b/src/sage/geometry/abc.pyx index 7c42de9e07b..199db3ec6eb 100644 --- a/src/sage/geometry/abc.pyx +++ b/src/sage/geometry/abc.pyx @@ -6,6 +6,24 @@ Abstract base classes for classes in :mod:`~sage.geometry` class LatticePolytope: r""" Abstract base class for :class:`~sage.geometry.lattice_polytope.LatticePolytopeClass` + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.geometry.abc + sage: P = LatticePolytope([(1,2,3), (4,5,6)]) # optional - sage.geometry.polyhedron + sage: isinstance(P, sage.geometry.abc.LatticePolytope) # optional - sage.geometry.polyhedron + True + + By design, there is a unique direct subclass:: + + sage: sage.geometry.abc.LatticePolytope.__subclasses__() # optional - sage.geometry.polyhedron + [] + + sage: len(sage.geometry.abc.Polyhedron.__subclasses__()) <= 1 + True """ pass @@ -14,6 +32,24 @@ class LatticePolytope: class ConvexRationalPolyhedralCone: r""" Abstract base class for :class:`~sage.geometry.cone.ConvexRationalPolyhedralCone` + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.geometry.abc + sage: C = cones.nonnegative_orthant(2) # optional - sage.geometry.polyhedron + sage: isinstance(C, sage.geometry.abc.ConvexRationalPolyhedralCone) # optional - sage.geometry.polyhedron + True + + By design, there is a unique direct subclass:: + + sage: sage.geometry.abc.ConvexRationalPolyhedralCone.__subclasses__() # optional - sage.geometry.polyhedron + [] + + sage: len(sage.geometry.abc.Polyhedron.__subclasses__()) <= 1 + True """ pass @@ -22,6 +58,24 @@ class ConvexRationalPolyhedralCone: class Polyhedron: r""" Abstract base class for :class:`~sage.geometry.polyhedron.base.Polyhedron_base` + + This class is defined for the purpose of ``isinstance`` tests. It should not be + instantiated. + + EXAMPLES:: + + sage: import sage.geometry.abc + sage: P = polytopes.cube() # optional - sage.geometry.polyhedron + sage: isinstance(P, sage.geometry.abc.Polyhedron) # optional - sage.geometry.polyhedron + True + + By design, there is a unique direct subclass:: + + sage: sage.geometry.abc.Polyhedron.__subclasses__() # optional - sage.geometry.polyhedron + [] + + sage: len(sage.geometry.abc.Polyhedron.__subclasses__()) <= 1 + True """ pass From 44540f589820374bcc50227accc4a8756036d3fb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 20:37:28 -0700 Subject: [PATCH 448/511] src/sage/features/sagemath.py: Add doctests --- src/sage/features/sagemath.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index de7caacb9de..dfc138e9126 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -31,8 +31,24 @@ def __init__(self): class sage__geometry__polyhedron(PythonModule): + r""" + A :class:`sage.features.Feature` describing the presence of ``sage.geometry.polyhedron``. + + EXAMPLES:: + + sage: from sage.features.sagemath import sage__geometry__polyhedron + sage: sage__geometry__polyhedron().is_present() # optional - sage.geometry.polyhedron + FeatureTestResult('sage.geometry.polyhedron', True) + """ def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sagemath import sage__geometry__polyhedron + sage: isinstance(sage__geometry__polyhedron(), sage__geometry__polyhedron) + True + """ PythonModule.__init__(self, 'sage.geometry.polyhedron') From d4357816318a05645edfd169c6f2b08108074fb1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 Oct 2021 20:51:48 -0700 Subject: [PATCH 449/511] build/bin/sage-dist-helpers (sdh_store_and_pip_install_wheel): Use sage-pip-uninstall --- build/bin/sage-dist-helpers | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/bin/sage-dist-helpers b/build/bin/sage-dist-helpers index a9639b26871..9980b4e22d2 100644 --- a/build/bin/sage-dist-helpers +++ b/build/bin/sage-dist-helpers @@ -313,7 +313,7 @@ sdh_store_and_pip_install_wheel() { # much -- it also reinstalls all dependencies, which we do not want. wheel_basename="${wheel##*/}" distname="${wheel_basename%%-*}" - $sudo python3 -m pip uninstall --isolated --disable-pip-version-check --yes --no-input $distname + $sudo sage-pip-uninstall "$distname" if [ $? -ne 0 ]; then echo "(ignoring error)" >&2 fi From e7009bd5adf33bf2647b8322360368c6592be922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 18 Oct 2021 18:01:36 +0200 Subject: [PATCH 450/511] adding conf.py in italian tutorial --- src/doc/it/tutorial/conf.py | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/doc/it/tutorial/conf.py diff --git a/src/doc/it/tutorial/conf.py b/src/doc/it/tutorial/conf.py new file mode 100644 index 00000000000..a69378db34f --- /dev/null +++ b/src/doc/it/tutorial/conf.py @@ -0,0 +1,39 @@ +# Sage documentation build configuration file, based on that created by +# sphinx-quickstart on Thu Aug 21 20:15:55 2008. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# The contents of this file are pickled, so don't put values in the namespace +# that aren't pickleable (module imports are okay, they're removed automatically). +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +from sage.docs.conf import release, latex_elements +from sage.docs.conf import * # NOQA + +# Add any paths that contain custom static files (such as style sheets), +# relative to this directory to html_static_path. They are copied after the +# builtin static files, so a file named "default.css" will overwrite the +# builtin "default.css". html_common_static_path imported from sage.docs.conf +# contains common paths. +html_static_path = [] + html_common_static_path + +# General information about the project. +project = "Tutorial Sage" +name = 'tutorial-it' +language = "it" + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = project + " v" + release + +# Output file base name for HTML help builder. +htmlhelp_basename = name + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, document class [howto/manual]). +latex_documents = [ + ('index', name + '.tex', project, + 'The Sage Group', 'manual'), +] From c3ff5143e5d7f5b617a7678c43f4b23e7deaed06 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Mon, 18 Oct 2021 22:42:13 +0200 Subject: [PATCH 451/511] Make SR doctests optional in sage.tensor.modules (#32712) --- src/sage/tensor/modules/comp.py | 6 +++--- src/sage/tensor/modules/free_module_alt_form.py | 10 +++++----- src/sage/tensor/modules/free_module_tensor.py | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 3d775e61850..5b7eef7dc25 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -1168,9 +1168,9 @@ def display(self, symbol, latex_symbol=None, index_positions=None, Check that the bug reported in :trac:`22520` is fixed:: - sage: c = Components(SR, [1, 2], 1) - sage: c[0] = SR.var('t', domain='real') - sage: c.display('c') + sage: c = Components(SR, [1, 2], 1) # optional - sage.symbolic + sage: c[0] = SR.var('t', domain='real') # optional - sage.symbolic + sage: c.display('c') # optional - sage.symbolic c_0 = t """ diff --git a/src/sage/tensor/modules/free_module_alt_form.py b/src/sage/tensor/modules/free_module_alt_form.py index 3e4883ca398..aae1ae990c3 100644 --- a/src/sage/tensor/modules/free_module_alt_form.py +++ b/src/sage/tensor/modules/free_module_alt_form.py @@ -554,11 +554,11 @@ def display(self, basis=None, format_spec=None): Check that the bug reported in :trac:`22520` is fixed:: - sage: M = FiniteRankFreeModule(SR, 2, name='M') - sage: e = M.basis('e') - sage: a = M.alternating_form(2) - sage: a[0,1] = SR.var('t', domain='real') - sage: a.display() + sage: M = FiniteRankFreeModule(SR, 2, name='M') # optional - sage.symbolic + sage: e = M.basis('e') # optional - sage.symbolic + sage: a = M.alternating_form(2) # optional - sage.symbolic + sage: a[0,1] = SR.var('t', domain='real') # optional - sage.symbolic + sage: a.display() # optional - sage.symbolic t e^0∧e^1 """ diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index 7515fc080ce..ad17b6018b5 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -687,10 +687,10 @@ def display(self, basis=None, format_spec=None): Check that the bug reported in :trac:`22520` is fixed:: - sage: M = FiniteRankFreeModule(SR, 3, name='M') - sage: e = M.basis('e') - sage: t = SR.var('t', domain='real') - sage: (t*e[0]).display() + sage: M = FiniteRankFreeModule(SR, 3, name='M') # optional - sage.symbolic + sage: e = M.basis('e') # optional - sage.symbolic + sage: t = SR.var('t', domain='real') # optional - sage.symbolic + sage: (t*e[0]).display() # optional - sage.symbolic t e_0 """ From 16a360e2d5dbc29008f19acabd9f2003985558f0 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 18 Aug 2021 18:34:27 -0400 Subject: [PATCH 452/511] Trac #29024: put the shared library extension in sage_conf. Preparing for a system copy of Singular, we need to be able to find the name of the main shared library that Singular installs. In doing so, we avoid the need to guess in _get_shared_lib_path(). In general, the name of this library will be libSingular.$SHLIBEXT, where $SHLIBEXT represents the extension of shared libraries on the system. As such, it makes sense to factor out the "name of the library" into two parts: its base name, and $SHLIBEXT, which can be determined independently and can be used with other libraries. This commit uses an autoconf macro from gettext to determine the shared library extension, and substitutes it into sage_conf.py as SHLIBEXT. --- configure.ac | 8 ++++++++ pkgs/sage-conf/sage_conf.py.in | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/configure.ac b/configure.ac index 0e092a93853..92740cc94d9 100644 --- a/configure.ac +++ b/configure.ac @@ -49,6 +49,14 @@ dnl Make sure the path to our own m4 macros is always properly set dnl and doesn't depend on how autoconf is called. AC_CONFIG_MACRO_DIR([m4]) +dnl The AC_LIB_RPATH macro comes from gettext, which is one of our bootstrap +dnl packages. It defines, among other things, the $acl_shlibext variable that +dnl contains the shared library extension for this system. We already use the +dnl AM_ICONV macro from gettext (which ultimately calls AC_LIB_RPATH), and we +dnl avoid involving libtool by using it to get the shared library extension. +AC_LIB_RPATH +AC_SUBST(SHLIBEXT, "${acl_shlibext}") + #--------------------------------------------------------- # # This is essentially the configure part of the old "install" file. diff --git a/pkgs/sage-conf/sage_conf.py.in b/pkgs/sage-conf/sage_conf.py.in index 86375d2f286..2d5f5fd3cf7 100644 --- a/pkgs/sage-conf/sage_conf.py.in +++ b/pkgs/sage-conf/sage_conf.py.in @@ -9,6 +9,10 @@ VERSION = "@PACKAGE_VERSION@" SAGE_LOCAL = "@prefix@" SAGE_ROOT = "@SAGE_ROOT@" +# The extension (without the period) for shared libraries on this +# system. For example, this is usually "so" on Linux. +SHLIBEXT = "@SHLIBEXT@" + MAXIMA = "@prefix@/bin/maxima" # Delete this line if your ECL can load maxima without further prodding. From 29f44e1381e0819257f8f968742017ea6d0f06e2 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 18 Jul 2021 19:19:57 -0400 Subject: [PATCH 453/511] Trac #29024: new spkg-configure.m4 for singular. This new spkg-configure.m4 tries to use libSingular the way that we do in sage/libs/singular/singular.pyx: by dlopen()ing the library with some flags set. If we can guess the library's name, and if dlopen() works, and if Singular is new enough... we'll accept the system copy, and write the basename of the library into sage_conf. Otherwise, we install the SPKG and write the old SAGE_LOCAL name into sage_conf. The sage_conf variable will be used in a later commit to replace the _get_shared_lib_path() hack currently in use. --- build/pkgs/singular/spkg-configure.m4 | 50 +++++++++++++++++++++++++++ pkgs/sage-conf/sage_conf.py.in | 6 ++++ 2 files changed, 56 insertions(+) create mode 100644 build/pkgs/singular/spkg-configure.m4 diff --git a/build/pkgs/singular/spkg-configure.m4 b/build/pkgs/singular/spkg-configure.m4 new file mode 100644 index 00000000000..37621d817fe --- /dev/null +++ b/build/pkgs/singular/spkg-configure.m4 @@ -0,0 +1,50 @@ +SAGE_SPKG_CONFIGURE([singular], [ + SAGE_SPKG_DEPCHECK([gmp mpir ntl flint readline mpfr cddlib], [ + + AC_PATH_PROG([SINGULAR_BIN], [Singular]) + AS_IF([test -z "${SINGULAR_BIN}"], [sage_spkg_install_singular=yes]) + + dnl Use pkg-config to ensure that Singular is new enough. + PKG_CHECK_MODULES([SINGULAR], + [Singular >= 4.1.1], + [], + [sage_spkg_install_singular=yes]) + + dnl The acl_shlibext variable is set in the top-level configure.ac, + dnl and is ultimately substituted into sage_conf as SHLIBEXT. + SINGULAR_LIB_BASE="libSingular" + SINGULAR_LIB_FILE="${SINGULAR_LIB_BASE}.${acl_shlibext}" + + AC_MSG_CHECKING([if we can dlopen($SINGULAR_LIB_FILE)]) + ORIG_LIBS="${LIBS}" + LIBS="${LIBS} -ldl" + AC_LANG_PUSH(C) + + dnl if we can dlopen() it, substitute the name for sage_conf; + dnl otherwise, fall back to using the SPKG. + AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[void* h = dlopen("${SINGULAR_LIB_FILE}", RTLD_LAZY | RTLD_GLOBAL); + if (h == 0) { return 1; } else { return dlclose(h); }]] + )], + [AC_SUBST(SINGULAR_LIB_BASE, "${SINGULAR_LIB_BASE}")], + [sage_spkg_install_singular=yes] + ) + + AC_LANG_POP() + LIBS="${ORIG_LIBS}" + ]) +],[],[],[ + dnl Post-check phase + dnl We make the sage_conf substitutions here, because the "default" + dnl substitution needs to be made even if we skipped the system-Singular + dnl checks themselves. + + dnl If we're using the SPKG, we might as well use the FULL path to the + dnl library, because we know it. + AS_IF([test "x${sage_spkg_install_singular}" = "xyes"], + [AC_SUBST(SINGULAR_LIB_BASE, '$SAGE_LOCAL/lib/libSingular')], + [AC_SUBST(SINGULAR_LIB_BASE, "${SINGULAR_LIB_BASE}")] + ) +]) diff --git a/pkgs/sage-conf/sage_conf.py.in b/pkgs/sage-conf/sage_conf.py.in index 2d5f5fd3cf7..7aa69e92d93 100644 --- a/pkgs/sage-conf/sage_conf.py.in +++ b/pkgs/sage-conf/sage_conf.py.in @@ -59,6 +59,12 @@ THREEJS_DIR = SAGE_LOCAL + "/share/threejs-sage" OPENMP_CFLAGS = "@OPENMP_CFLAGS@" OPENMP_CXXFLAGS = "@OPENMP_CXXFLAGS@" +# The base name of the main Singular library. If the library is called +# libSingular.so, then its base name should be something like "libSingular", +# or "$SAGE_LOCAL/lib/libSingular". The extension is not needed; the value +# of SHLIBEXT will be appended automatically. +SINGULAR_LIB_BASE = "@SINGULAR_LIB_BASE@".replace('$SAGE_LOCAL', SAGE_LOCAL) + # Entry point 'sage-config'. It does not depend on any packages. def _main(): From f2ac75078aec9b01e7d644aff7f000346183a442 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 18 Aug 2021 22:08:41 -0400 Subject: [PATCH 454/511] Trac #29024: don't set SINGULARPATH in sage-env. This was never really necessary (the Singular library/executable knows where its own libs live), and is now wrong when we're using a system copy of Singular. Goodbye. --- src/bin/sage-env | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bin/sage-env b/src/bin/sage-env index ac8506ffba6..b4c0c6ea207 100644 --- a/src/bin/sage-env +++ b/src/bin/sage-env @@ -334,8 +334,6 @@ if [ -n "$SAGE_LOCAL" ]; then fi if [ -n "$SAGE_LOCAL" ]; then - SINGULARPATH="$SAGE_LOCAL/share/singular" && export SINGULARPATH - # Ensure that there is a colon at the end of $INFOPATH by # stripping the existing one (if it exists), and then adding a new # one. This forces the "info" program to check various default From cbeb23feeb6c336770bdd2a915a3438fa52f4586 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 18 Aug 2021 22:08:49 -0400 Subject: [PATCH 455/511] Trac #29024: use SINGULAR_LIB_BASE and SHLIBEXT to replace SINGULAR_SO. At this point, sage_conf contains both the "base name" of the singular library and the extension used by all shared libraries on this system. Instead of guessing at the path of the Singular library through _get_shared_lib_path() in sage.env, this commit updates the code in sage.libs.singular.singular to use the new sage_conf variables. All mentions of the earlier variable (SINGULAR_SO) have been deleted. --- src/sage/env.py | 4 ---- src/sage/libs/singular/singular.pyx | 12 ++++-------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/sage/env.py b/src/sage/env.py index 44fc8481346..876c56d742d 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -316,10 +316,6 @@ def _get_shared_lib_path(*libnames: str) -> Optional[str]: # Just return None if no files were found return None -# locate singular shared object -# On Debian it's libsingular-Singular so try that as well -SINGULAR_SO = var("SINGULAR_SO", _get_shared_lib_path("Singular", "singular-Singular")) - # locate libgap shared object GAP_SO = var("GAP_SO", _get_shared_lib_path("gap", "")) diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index c736d56b0c0..3e47c62db3b 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -768,18 +768,14 @@ cdef init_libsingular(): cdef void *handle = NULL - from sage.env import SINGULAR_SO - if not SINGULAR_SO or not os.path.exists(SINGULAR_SO): - raise RuntimeError( - "libSingular not found--a working Singular install " - "is required for Sage to work") - - lib = str_to_bytes(SINGULAR_SO, FS_ENCODING, "surrogateescape") + from sage_conf import SINGULAR_LIB_BASE, SHLIBEXT + SINGULAR_LIB_PATH = SINGULAR_LIB_BASE + "." + SHLIBEXT + lib = str_to_bytes(SINGULAR_LIB_PATH, FS_ENCODING, "surrogateescape") handle = dlopen(lib, RTLD_GLOBAL|RTLD_LAZY) if not handle: err = dlerror() - raise ImportError(f"cannot load Singular library from {SINGULAR_SO} ({err})") + raise ImportError(f"cannot load Singular library from {SINGULAR_LIB_PATH} ({err})") # load SINGULAR siInit(lib) From dfb586073a5d4cc288ef3016906f380de1330411 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 19 Aug 2021 09:11:02 -0400 Subject: [PATCH 456/511] Trac #29024: add Gentoo package information. --- build/pkgs/singular/distros/gentoo.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 build/pkgs/singular/distros/gentoo.txt diff --git a/build/pkgs/singular/distros/gentoo.txt b/build/pkgs/singular/distros/gentoo.txt new file mode 100644 index 00000000000..2c8b3567a39 --- /dev/null +++ b/build/pkgs/singular/distros/gentoo.txt @@ -0,0 +1 @@ +sci-mathematics/singular[readline] From 175e6f60242d254cd4b740f35a8a4f0279aec40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Sat, 21 Aug 2021 19:55:17 +0200 Subject: [PATCH 457/511] 29024: Add Singular distro info --- build/pkgs/singular/distros/arch.txt | 1 + build/pkgs/singular/distros/cygwin.txt | 2 ++ build/pkgs/singular/distros/fedora.txt | 1 + build/pkgs/singular/distros/homebrew.txt | 5 ++++- 4 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 build/pkgs/singular/distros/arch.txt create mode 100644 build/pkgs/singular/distros/cygwin.txt create mode 100644 build/pkgs/singular/distros/fedora.txt diff --git a/build/pkgs/singular/distros/arch.txt b/build/pkgs/singular/distros/arch.txt new file mode 100644 index 00000000000..5f0dc01955f --- /dev/null +++ b/build/pkgs/singular/distros/arch.txt @@ -0,0 +1 @@ +singular diff --git a/build/pkgs/singular/distros/cygwin.txt b/build/pkgs/singular/distros/cygwin.txt new file mode 100644 index 00000000000..774625930f9 --- /dev/null +++ b/build/pkgs/singular/distros/cygwin.txt @@ -0,0 +1,2 @@ +singular-devel +singular diff --git a/build/pkgs/singular/distros/fedora.txt b/build/pkgs/singular/distros/fedora.txt new file mode 100644 index 00000000000..b703b849699 --- /dev/null +++ b/build/pkgs/singular/distros/fedora.txt @@ -0,0 +1 @@ +Singular diff --git a/build/pkgs/singular/distros/homebrew.txt b/build/pkgs/singular/distros/homebrew.txt index 90958411e8f..ef2339d4ab5 100644 --- a/build/pkgs/singular/distros/homebrew.txt +++ b/build/pkgs/singular/distros/homebrew.txt @@ -1,2 +1,5 @@ -# As of 2021-03-20, build of homebrew's singular from source fails +# [2021-03-20] Homebrew's Singular can be built from source +# (via `brew install -s`, or implied when using `brew` with +# a non-standard prefix), but that currently fails. + #singular From dc1dcc336664e40dfda0015e19ff2999f76d1bd4 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 14 Sep 2021 12:43:44 -0400 Subject: [PATCH 458/511] Trac #29024: work around Singular issue 1113 in init_libsingular(). When we Singular with dlopen() by name, it is initially unable to determine the path to its main executable and emits a "BUG" warning. This is ultimately harmless, but is very scary and appears unexpectedly whenever Sage is invoked. Here we work around the issue temporarily by setting SINGULAR_BIN_DIR to the directory containing the "Singular" executable in the user's PATH. --- src/sage/libs/singular/singular.pyx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index 3e47c62db3b..f6ebfa01d31 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -772,6 +772,13 @@ cdef init_libsingular(): SINGULAR_LIB_PATH = SINGULAR_LIB_BASE + "." + SHLIBEXT lib = str_to_bytes(SINGULAR_LIB_PATH, FS_ENCODING, "surrogateescape") + # This is a workaround for https://github.com/Singular/Singular/issues/1113 + # and can be removed once that fix makes it into release of Singular that + # is supported by sage. + from shutil import which + from os.path import dirname + os.environ["SINGULAR_BIN_DIR"] = dirname(which("Singular")) + handle = dlopen(lib, RTLD_GLOBAL|RTLD_LAZY) if not handle: err = dlerror() From ef79af8694275ed26bab03830e6bccb2cd5c2e13 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 17 Sep 2021 23:35:12 -0400 Subject: [PATCH 459/511] Trac #29024: add missing AC_MSG_RESULTs in singular/spkg-configure.m4. --- build/pkgs/singular/spkg-configure.m4 | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/build/pkgs/singular/spkg-configure.m4 b/build/pkgs/singular/spkg-configure.m4 index 37621d817fe..02bdc2d0c42 100644 --- a/build/pkgs/singular/spkg-configure.m4 +++ b/build/pkgs/singular/spkg-configure.m4 @@ -27,10 +27,13 @@ SAGE_SPKG_CONFIGURE([singular], [ [[#include ]], [[void* h = dlopen("${SINGULAR_LIB_FILE}", RTLD_LAZY | RTLD_GLOBAL); if (h == 0) { return 1; } else { return dlclose(h); }]] - )], - [AC_SUBST(SINGULAR_LIB_BASE, "${SINGULAR_LIB_BASE}")], - [sage_spkg_install_singular=yes] - ) + )], [ + AC_MSG_RESULT(yes) + AC_SUBST(SINGULAR_LIB_BASE, "${SINGULAR_LIB_BASE}") + ], [ + AC_MSG_RESULT(no) + sage_spkg_install_singular=yes + ]) AC_LANG_POP() LIBS="${ORIG_LIBS}" From 2f32b6920d4a029d94af9e7ede5fa91bbcff612e Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 19 Sep 2021 21:43:11 -0400 Subject: [PATCH 460/511] Trac #29024: clarify a comment in singular's spkg-configure. --- build/pkgs/singular/spkg-configure.m4 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build/pkgs/singular/spkg-configure.m4 b/build/pkgs/singular/spkg-configure.m4 index 02bdc2d0c42..85bd033c6a4 100644 --- a/build/pkgs/singular/spkg-configure.m4 +++ b/build/pkgs/singular/spkg-configure.m4 @@ -44,8 +44,10 @@ SAGE_SPKG_CONFIGURE([singular], [ dnl substitution needs to be made even if we skipped the system-Singular dnl checks themselves. - dnl If we're using the SPKG, we might as well use the FULL path to the - dnl library, because we know it. + dnl If we're using the SPKG, we need to use the FULL path to the library, + dnl because the use of the SPKG is not just a fallback for when no system + dnl singular is present; it is also a fallback for when our (non-POSIX) + dnl dlopen() strategy fails. AS_IF([test "x${sage_spkg_install_singular}" = "xyes"], [AC_SUBST(SINGULAR_LIB_BASE, '$SAGE_LOCAL/lib/libSingular')], [AC_SUBST(SINGULAR_LIB_BASE, "${SINGULAR_LIB_BASE}")] From 8ec888adb74c05a078c525cf382f9a1b4bca59ca Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 20 Sep 2021 10:47:28 -0400 Subject: [PATCH 461/511] Trac #29024: fix libSingular path on Cygwin. On Cygwin, libtool.m4 uses postinstall_cmds to move DLLs out of $libdir and into $libdir/../bin. To account for that, we add a special case to Singular's spkg-configure.m4 that uses $libdir/../bin instead of $libdir as the location for libSingular on Cygwin. --- build/pkgs/singular/spkg-configure.m4 | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/build/pkgs/singular/spkg-configure.m4 b/build/pkgs/singular/spkg-configure.m4 index 85bd033c6a4..39fbda32052 100644 --- a/build/pkgs/singular/spkg-configure.m4 +++ b/build/pkgs/singular/spkg-configure.m4 @@ -48,8 +48,19 @@ SAGE_SPKG_CONFIGURE([singular], [ dnl because the use of the SPKG is not just a fallback for when no system dnl singular is present; it is also a fallback for when our (non-POSIX) dnl dlopen() strategy fails. - AS_IF([test "x${sage_spkg_install_singular}" = "xyes"], - [AC_SUBST(SINGULAR_LIB_BASE, '$SAGE_LOCAL/lib/libSingular')], - [AC_SUBST(SINGULAR_LIB_BASE, "${SINGULAR_LIB_BASE}")] + AS_IF([test "x${sage_spkg_install_singular}" = "xyes"], [ + AC_SUBST(SINGULAR_LIB_BASE, '$SAGE_LOCAL/lib/libSingular') + + dnl libtool.m4 has dedicated cygwin* code to move DLLs from + dnl $libdir to $libdir/../bin. + AS_CASE([$host_os], + [cygwin*], [ + AC_SUBST(SINGULAR_LIB_BASE, '$SAGE_LOCAL/bin/libSingular') + ] + ) + ], [ + dnl We're using the system package + AC_SUBST(SINGULAR_LIB_BASE, "${SINGULAR_LIB_BASE}") + ] ) ]) From 62065de4b44c87638b561cd7ce8b8bbc19adc6ab Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 20 Sep 2021 14:50:57 -0400 Subject: [PATCH 462/511] Trac #29024: always obtain the absolute path to libSingular. Trusting dlopen() to look up its argument in the system's library search path did not work as well as expected. At least on macOS -- and probably elsewhere -- the autoconf test succeeds but the real call in singular.pyx fails, requiring us to pass it the absolute path instead. That path can be obtained from pkg-config. We're already using pkg-config for a version check, and the name-only behavior of dlopen() is not standard, so relying on pkg-config to get singular's libdir does not seem so bad in this case. To simplify the implementation, this commit uses the libdir obtained from pkg-config unconditionally, and not just on macOS. It also adds some (untested) code in preparation for a system copy of Singular on Cygwin. --- build/pkgs/singular/spkg-configure.m4 | 42 +++++++++++++++------------ pkgs/sage-conf/sage_conf.py.in | 11 ++----- src/sage/libs/singular/singular.pyx | 7 ++--- 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/build/pkgs/singular/spkg-configure.m4 b/build/pkgs/singular/spkg-configure.m4 index 39fbda32052..eae8d9df35f 100644 --- a/build/pkgs/singular/spkg-configure.m4 +++ b/build/pkgs/singular/spkg-configure.m4 @@ -10,12 +10,24 @@ SAGE_SPKG_CONFIGURE([singular], [ [], [sage_spkg_install_singular=yes]) - dnl The acl_shlibext variable is set in the top-level configure.ac, - dnl and is ultimately substituted into sage_conf as SHLIBEXT. - SINGULAR_LIB_BASE="libSingular" - SINGULAR_LIB_FILE="${SINGULAR_LIB_BASE}.${acl_shlibext}" + dnl Use pkg-config to get singular's libdir while we're at it. As a + dnl moral compromise for using pkg-config, this ultimately allows us + dnl to pass an absolute path to dlopen(), which is the only approach + dnl that POSIX guarantees will work. + PKG_CHECK_VAR([SINGULAR_LIB_DIR], [Singular], [libdir]) - AC_MSG_CHECKING([if we can dlopen($SINGULAR_LIB_FILE)]) + dnl libtool.m4 has dedicated cygwin* code to move DLLs from + dnl $libdir to $libdir/../bin. + AS_CASE([$host_os], + [cygwin*], [ + SINGULAR_LIB_DIR="${SINGULAR_LIB_DIR}/../bin" + ] + ) + + dnl The acl_shlibext variable is set in the top-level configure.ac. + LIBSINGULAR_PATH="${SINGULAR_LIB_DIR}/libSingular.${acl_shlibext}" + + AC_MSG_CHECKING([if we can dlopen($LIBSINGULAR_PATH)]) ORIG_LIBS="${LIBS}" LIBS="${LIBS} -ldl" AC_LANG_PUSH(C) @@ -25,11 +37,10 @@ SAGE_SPKG_CONFIGURE([singular], [ AC_RUN_IFELSE( [AC_LANG_PROGRAM( [[#include ]], - [[void* h = dlopen("${SINGULAR_LIB_FILE}", RTLD_LAZY | RTLD_GLOBAL); + [[void* h = dlopen("${LIBSINGULAR_PATH}", RTLD_LAZY | RTLD_GLOBAL); if (h == 0) { return 1; } else { return dlclose(h); }]] )], [ AC_MSG_RESULT(yes) - AC_SUBST(SINGULAR_LIB_BASE, "${SINGULAR_LIB_BASE}") ], [ AC_MSG_RESULT(no) sage_spkg_install_singular=yes @@ -43,24 +54,17 @@ SAGE_SPKG_CONFIGURE([singular], [ dnl We make the sage_conf substitutions here, because the "default" dnl substitution needs to be made even if we skipped the system-Singular dnl checks themselves. - - dnl If we're using the SPKG, we need to use the FULL path to the library, - dnl because the use of the SPKG is not just a fallback for when no system - dnl singular is present; it is also a fallback for when our (non-POSIX) - dnl dlopen() strategy fails. AS_IF([test "x${sage_spkg_install_singular}" = "xyes"], [ - AC_SUBST(SINGULAR_LIB_BASE, '$SAGE_LOCAL/lib/libSingular') + LIBSINGULAR_PATH="\$SAGE_LOCAL/lib/libSingular.${acl_shlibext}" dnl libtool.m4 has dedicated cygwin* code to move DLLs from dnl $libdir to $libdir/../bin. AS_CASE([$host_os], [cygwin*], [ - AC_SUBST(SINGULAR_LIB_BASE, '$SAGE_LOCAL/bin/libSingular') + LIBSINGULAR_PATH="\$SAGE_LOCAL/bin/libSingular.${acl_shlibext}" ] ) - ], [ - dnl We're using the system package - AC_SUBST(SINGULAR_LIB_BASE, "${SINGULAR_LIB_BASE}") - ] - ) + ]) + + AC_SUBST(LIBSINGULAR_PATH, "${LIBSINGULAR_PATH}") ]) diff --git a/pkgs/sage-conf/sage_conf.py.in b/pkgs/sage-conf/sage_conf.py.in index 7aa69e92d93..fbce6947de3 100644 --- a/pkgs/sage-conf/sage_conf.py.in +++ b/pkgs/sage-conf/sage_conf.py.in @@ -9,10 +9,6 @@ VERSION = "@PACKAGE_VERSION@" SAGE_LOCAL = "@prefix@" SAGE_ROOT = "@SAGE_ROOT@" -# The extension (without the period) for shared libraries on this -# system. For example, this is usually "so" on Linux. -SHLIBEXT = "@SHLIBEXT@" - MAXIMA = "@prefix@/bin/maxima" # Delete this line if your ECL can load maxima without further prodding. @@ -59,11 +55,8 @@ THREEJS_DIR = SAGE_LOCAL + "/share/threejs-sage" OPENMP_CFLAGS = "@OPENMP_CFLAGS@" OPENMP_CXXFLAGS = "@OPENMP_CXXFLAGS@" -# The base name of the main Singular library. If the library is called -# libSingular.so, then its base name should be something like "libSingular", -# or "$SAGE_LOCAL/lib/libSingular". The extension is not needed; the value -# of SHLIBEXT will be appended automatically. -SINGULAR_LIB_BASE = "@SINGULAR_LIB_BASE@".replace('$SAGE_LOCAL', SAGE_LOCAL) +# The full absolute path to the main Singular library. +LIBSINGULAR_PATH = "@LIBSINGULAR_PATH@".replace('$SAGE_LOCAL', SAGE_LOCAL) # Entry point 'sage-config'. It does not depend on any packages. diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index f6ebfa01d31..ea6d0ab01d1 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -768,9 +768,8 @@ cdef init_libsingular(): cdef void *handle = NULL - from sage_conf import SINGULAR_LIB_BASE, SHLIBEXT - SINGULAR_LIB_PATH = SINGULAR_LIB_BASE + "." + SHLIBEXT - lib = str_to_bytes(SINGULAR_LIB_PATH, FS_ENCODING, "surrogateescape") + from sage_conf import LIBSINGULAR_PATH + lib = str_to_bytes(LIBSINGULAR_PATH, FS_ENCODING, "surrogateescape") # This is a workaround for https://github.com/Singular/Singular/issues/1113 # and can be removed once that fix makes it into release of Singular that @@ -782,7 +781,7 @@ cdef init_libsingular(): handle = dlopen(lib, RTLD_GLOBAL|RTLD_LAZY) if not handle: err = dlerror() - raise ImportError(f"cannot load Singular library from {SINGULAR_LIB_PATH} ({err})") + raise ImportError(f"cannot load Singular library from {LIBSINGULAR_PATH} ({err})") # load SINGULAR siInit(lib) From 2aa55e7fb03a6c7ad8db80c779c9fb70b17d8290 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 18 Oct 2021 20:47:37 -0400 Subject: [PATCH 463/511] Trac #29024: fully nest tests in Singular's spkg-configure.m4. This should avoid performing unnecessary checks later in the macro after an earlier check has already failed. --- build/pkgs/singular/spkg-configure.m4 | 75 ++++++++++++++------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/build/pkgs/singular/spkg-configure.m4 b/build/pkgs/singular/spkg-configure.m4 index eae8d9df35f..1eea02e9925 100644 --- a/build/pkgs/singular/spkg-configure.m4 +++ b/build/pkgs/singular/spkg-configure.m4 @@ -2,52 +2,53 @@ SAGE_SPKG_CONFIGURE([singular], [ SAGE_SPKG_DEPCHECK([gmp mpir ntl flint readline mpfr cddlib], [ AC_PATH_PROG([SINGULAR_BIN], [Singular]) - AS_IF([test -z "${SINGULAR_BIN}"], [sage_spkg_install_singular=yes]) + AS_IF([test -z "${SINGULAR_BIN}"], [sage_spkg_install_singular=yes], [ + dnl Use pkg-config to ensure that Singular is new enough. + PKG_CHECK_MODULES([SINGULAR], [Singular >= 4.1.1], [ - dnl Use pkg-config to ensure that Singular is new enough. - PKG_CHECK_MODULES([SINGULAR], - [Singular >= 4.1.1], - [], - [sage_spkg_install_singular=yes]) + dnl Use pkg-config to get singular's libdir while we're at it. As a + dnl moral compromise for using pkg-config, this ultimately allows us + dnl to pass an absolute path to dlopen(), which is the only approach + dnl that POSIX guarantees will work. + PKG_CHECK_VAR([SINGULAR_LIB_DIR], [Singular], [libdir]) - dnl Use pkg-config to get singular's libdir while we're at it. As a - dnl moral compromise for using pkg-config, this ultimately allows us - dnl to pass an absolute path to dlopen(), which is the only approach - dnl that POSIX guarantees will work. - PKG_CHECK_VAR([SINGULAR_LIB_DIR], [Singular], [libdir]) + dnl libtool.m4 has dedicated cygwin* code to move DLLs from + dnl $libdir to $libdir/../bin. + AS_CASE([$host_os], + [cygwin*], [ + SINGULAR_LIB_DIR="${SINGULAR_LIB_DIR}/../bin" + ] + ) - dnl libtool.m4 has dedicated cygwin* code to move DLLs from - dnl $libdir to $libdir/../bin. - AS_CASE([$host_os], - [cygwin*], [ - SINGULAR_LIB_DIR="${SINGULAR_LIB_DIR}/../bin" - ] - ) + dnl The acl_shlibext variable is set in the top-level configure.ac. + LIBSINGULAR_PATH="${SINGULAR_LIB_DIR}/libSingular.${acl_shlibext}" - dnl The acl_shlibext variable is set in the top-level configure.ac. - LIBSINGULAR_PATH="${SINGULAR_LIB_DIR}/libSingular.${acl_shlibext}" + AC_MSG_CHECKING([if we can dlopen($LIBSINGULAR_PATH)]) + ORIG_LIBS="${LIBS}" + LIBS="${LIBS} -ldl" + AC_LANG_PUSH(C) - AC_MSG_CHECKING([if we can dlopen($LIBSINGULAR_PATH)]) - ORIG_LIBS="${LIBS}" - LIBS="${LIBS} -ldl" - AC_LANG_PUSH(C) + dnl if we can dlopen() it, substitute the name for sage_conf; + dnl otherwise, fall back to using the SPKG. + AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[void* h = dlopen("${LIBSINGULAR_PATH}", RTLD_LAZY | RTLD_GLOBAL); + if (h == 0) { return 1; } else { return dlclose(h); }]] + )], [ + AC_MSG_RESULT(yes) + ], [ + AC_MSG_RESULT(no) + sage_spkg_install_singular=yes + ]) - dnl if we can dlopen() it, substitute the name for sage_conf; - dnl otherwise, fall back to using the SPKG. - AC_RUN_IFELSE( - [AC_LANG_PROGRAM( - [[#include ]], - [[void* h = dlopen("${LIBSINGULAR_PATH}", RTLD_LAZY | RTLD_GLOBAL); - if (h == 0) { return 1; } else { return dlclose(h); }]] - )], [ - AC_MSG_RESULT(yes) + AC_LANG_POP() + LIBS="${ORIG_LIBS}" ], [ - AC_MSG_RESULT(no) + dnl pkg-config version check failed sage_spkg_install_singular=yes + ]) ]) - - AC_LANG_POP() - LIBS="${ORIG_LIBS}" ]) ],[],[],[ dnl Post-check phase From eecd43c457228ef2b05832ba11d40bc17127e5f4 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 21 Sep 2021 20:03:47 +0100 Subject: [PATCH 464/511] Fedora needs devel pkg --- build/pkgs/singular/distros/fedora.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/build/pkgs/singular/distros/fedora.txt b/build/pkgs/singular/distros/fedora.txt index b703b849699..bb4a7a5c7bf 100644 --- a/build/pkgs/singular/distros/fedora.txt +++ b/build/pkgs/singular/distros/fedora.txt @@ -1 +1,2 @@ Singular +Singular-devel From eb3b4e559096605857584054ecdfe3556e6444ed Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 18 Oct 2021 21:26:40 -0400 Subject: [PATCH 465/511] Trac #29024: drop "mpir" from singular's DEPCHECK. Our mpir package was removed in trac 32549. --- build/pkgs/singular/spkg-configure.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/singular/spkg-configure.m4 b/build/pkgs/singular/spkg-configure.m4 index 1eea02e9925..1426d49f04e 100644 --- a/build/pkgs/singular/spkg-configure.m4 +++ b/build/pkgs/singular/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([singular], [ - SAGE_SPKG_DEPCHECK([gmp mpir ntl flint readline mpfr cddlib], [ + SAGE_SPKG_DEPCHECK([gmp ntl flint readline mpfr cddlib], [ AC_PATH_PROG([SINGULAR_BIN], [Singular]) AS_IF([test -z "${SINGULAR_BIN}"], [sage_spkg_install_singular=yes], [ From 8eda301553e82ec2aa95c61b535f540cff5ebb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 19 Oct 2021 08:59:42 +0200 Subject: [PATCH 466/511] some fixes in it tutorial --- src/doc/it/tutorial/tour_algebra.rst | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/doc/it/tutorial/tour_algebra.rst b/src/doc/it/tutorial/tour_algebra.rst index c745905ab05..cc331c5f427 100644 --- a/src/doc/it/tutorial/tour_algebra.rst +++ b/src/doc/it/tutorial/tour_algebra.rst @@ -1,5 +1,4 @@ Algebra di base e Analisi - ========================= Sage sa svolgere diversi calcoli legati all'algebra di base @@ -156,7 +155,7 @@ Si può anche calcolare la trasformata di Laplace; la trasformata di Laplace di Il successivo è un esempio più articolato. Lo scostamento dall'equilibrio (rispettivamente) per due molle accoppiate fissate ad un muro a sinistra -:: +.. CODE-BLOCK:: text |------\/\/\/\/\---|massa1|----\/\/\/\/\/----|massa2| molla1 molla2 @@ -164,11 +163,11 @@ Il successivo è un esempio più articolato. Lo scostamento dall'equilibrio è modellizzato dal sistema di equazioni differenziali del secondo ordine .. math:: + m_1 x_1'' + (k_1+k_2) x_1 - k_2 x_2 = 0 m_2 x_2''+ k_2 (x_2-x_1) = 0, - dove :math:`m_{i}` è la massa dell'oggetto *i*, :math:`x_{i}` è lo scostamento dall'equilibrio della massa *i*, e :math:`k_{i}` è la costante elastica della molla *i*. @@ -245,9 +244,7 @@ Essa può essere disegnata in forma parametrica usando ....: (0, 2*pi), rgbcolor=hue(0.9)) sage: show(P) -Le singole componenti possono essere tracciate usando: - -:: +Le singole componenti possono essere tracciate usando:: sage: t = var('t') sage: p1 = plot(cos(2*t) + 2*cos(t), 0, 2*pi, rgbcolor=hue(0.3)) From a3c53051a5961226700bdb8a40f831092f8dffcd Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 19 Oct 2021 07:16:55 -0400 Subject: [PATCH 467/511] Trac #29024: re-enable the system singular hint on homebrew. --- build/pkgs/singular/distros/homebrew.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/build/pkgs/singular/distros/homebrew.txt b/build/pkgs/singular/distros/homebrew.txt index ef2339d4ab5..5f0dc01955f 100644 --- a/build/pkgs/singular/distros/homebrew.txt +++ b/build/pkgs/singular/distros/homebrew.txt @@ -1,5 +1 @@ -# [2021-03-20] Homebrew's Singular can be built from source -# (via `brew install -s`, or implied when using `brew` with -# a non-standard prefix), but that currently fails. - -#singular +singular From b9fb2fb5b8dbc3fcce8891877c5d6aa89f71b0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 19 Oct 2021 16:31:44 +0200 Subject: [PATCH 468/511] another fix for it tutorial --- src/doc/it/tutorial/tour_algebra.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/doc/it/tutorial/tour_algebra.rst b/src/doc/it/tutorial/tour_algebra.rst index cc331c5f427..e17a93dde8a 100644 --- a/src/doc/it/tutorial/tour_algebra.rst +++ b/src/doc/it/tutorial/tour_algebra.rst @@ -286,7 +286,7 @@ per :math:`y(x+h)`: Se chiamiamo :math:`h f(x,y(x))` il "termine di correzione" (per mancanza di un termine migliore), :math:`y(x)` il "vecchio valore di *y*", e - :math:`y(x+h)` il "nuovo valore di *y*", allora questa +:math:`y(x+h)` il "nuovo valore di *y*", allora questa approssimazione può essere espressa come .. math:: y_{new} \approx y_{old} + h*f(x,y_{old}). @@ -381,9 +381,7 @@ e "Funzioni speciali", rispettivamente) del manuale di Sage. A questo punto, Sage ha soltanto incorporato queste funzioni per l'uso numerico. Per l'uso simbolico, si usi direttamente l'intefaccia di Maxima, come -nell'esempio seguente: - -:: +nell'esempio seguente:: sage: maxima.eval("f:bessel_y(v, w)") 'bessel_y(v,w)' From e1b526c6be9cfc1bcb879fadbe63fb2d56b66010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 19 Oct 2021 18:23:43 +0200 Subject: [PATCH 469/511] trying to make derivative od piecewise work --- src/sage/functions/piecewise.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index bc25aad5cd1..4ac28309a5d 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -283,6 +283,28 @@ def simplify(ex): """ raise NotImplementedError + def _tderivative_(self, parameters, variable, *args, **kwds): + """ + Return the derivative of the piecewise function by applying the + derivative to each piece. + + EXAMPLES:: + + sage: f = piecewise([ [(-1,1), x**2], [(1,3), x**3]]) + sage: f.diff() + piecewise(x|-->2*x on (-1, 1), x|-->3*x^2 on (1, 3); x) + sage: f.diff(x,x) + piecewise(x|-->2 on (-1, 1), x|-->6*x on (1, 3); x) + + TESTS:: + + sage: f = piecewise([((-oo, -1),0), ((-1, 1),exp(-1/(1 - x^2))), ((1, oo),0)]) + sage: f.diff() + piecewise(x|-->0 on (-oo, -1), x|-->-2*x*e^(1/(x^2 - 1))/(x^2 - 1)^2 on (-1, 1), x|-->0 on (1, +oo); x) + """ + return piecewise([(domain, func.derivative(*args)) + for domain, func in parameters], + var=variable) class EvaluationMethods(object): From 6800b36db28020ac40dcdf3236c661a8db4197ce Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 19 Oct 2021 18:35:32 +0200 Subject: [PATCH 470/511] trac #32723: add method _get_weight_function and show usage --- src/sage/graphs/generic_graph.py | 102 +++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 19 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 2ab81f802b2..097d450f5c0 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -16181,6 +16181,81 @@ def _check_weight_function(self, weight_function=None): raise ValueError("the weight function cannot find the " "weight of " + str(e)) + def _get_weight_function(self, by_weight=False, weight_function=None, check_weight=True): + r""" + Return an edge weight function. + + An edge weight function is a function that takes as input an edge and + outputs its weight. + + This method is a helper function for methods using the weight of edges. + It either checks the validity of an input weight function, or returns a + valid weight function on the edges. + + INPUT: + + - ``by_weight`` -- boolean (default: ``False``); if ``True``, the edges + in the graph are weighted, otherwise all edges have weight 1 + + - ``weight_function`` -- function (default: ``None``); a function that + takes as input an edge ``(u, v, l)`` and outputs its weight. If not + ``None``, ``by_weight`` is automatically set to ``True``. If ``None`` + and ``by_weight`` is ``True``, we use the edge label ``l``, if ``l`` + is not ``None``, else ``1`` as a weight. + + - ``check_weight`` -- boolean (default: ``True``); if ``True``, we check + that the weight_function outputs a number for each edge + + EXAMPLES: + + The default weight function outputs 1 for each edge:: + + sage: G = Graph([(0, 1, 1), (1, 2, 3), (2, 3, 2)]) + sage: by_weight, weight_function = G._get_weight_function() + sage: by_weight + False + sage: [weight_function(e) for e in G.edges()] + [1, 1, 1] + + The standard weight function outputs labels:: + + sage: G = Graph([(0, 1, 1), (1, 2, 3), (2, 3, 2)]) + sage: by_weight, weight_function = G._get_weight_function(by_weight=True) + sage: by_weight + True + sage: [weight_function(e) for e in G.edges()] + [1, 3, 2] + + However, it might be more complicated:: + + sage: G = Graph([(0, 1, {'name':'a', 'weight':1}), (1, 2, {'name': 'b', 'weight': 3}), (2, 3, {'name': 'c', 'weight': 2})]) + sage: by_weight, weight_function = G._get_weight_function(weight_function=lambda e:e[2]['weight']) + sage: by_weight + True + sage: [weight_function(e) for e in G.edges()] + [1, 3, 2] + + Numeric string as a weight in weight_function:: + + sage: G = Graph({0: {1: '123'}}) + sage: by_weight, weight_function = G._get_weight_function(by_weight=True) + Traceback (most recent call last): + ... + ValueError: the weight function cannot find the weight of (0, 1, '123') + """ + if weight_function is not None: + by_weight = True + if by_weight: + if weight_function is None: + def weight_function(e): + return 1 if e[2] is None else e[2] + if check_weight: + self._check_weight_function(weight_function) + else: + def weight_function(e): + return 1 + return by_weight, weight_function + def shortest_paths(self, u, by_weight=False, algorithm=None, weight_function=None, check_weight=True, cutoff=None): r""" @@ -16324,21 +16399,13 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, ... ValueError: ('Contradictory paths found:', 'negative weights?') """ - if weight_function is not None: - by_weight = True - elif by_weight: - def weight_function(e): - return 1 if e[2] is None else e[2] - else: - def weight_function(e): - return 1 + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, + weight_function=weight_function, + check_weight=check_weight) if algorithm is None and not by_weight: algorithm = 'BFS' - if by_weight and check_weight: - self._check_weight_function(weight_function) - if algorithm == 'BFS': if by_weight: raise ValueError("the 'BFS' algorithm does not work on " @@ -16440,14 +16507,11 @@ def _path_length(self, path, by_weight=False, weight_function=None): return Infinity if by_weight or weight_function is not None: - if weight_function is None: - def weight_function(e): - return 1 if e[2] is None else e[2] - wt = 0 - - for u, v in zip(path[:-1], path[1:]): - wt += weight_function((u, v, self.edge_label(u, v))) - return wt + _, weight_function = self._get_weight_function(by_weight=by_weight, + weight_function=weight_function, + check_weight=False) + return sum(weight_function((u, v, self.edge_label(u, v))) + for u, v in zip(path[:-1], path[1:])) else: return len(path) - 1 From 056b8d4e7bcdc936af39a33d3885925f1c850f80 Mon Sep 17 00:00:00 2001 From: Release Manager Date: Wed, 20 Oct 2021 00:54:28 +0200 Subject: [PATCH 471/511] Updated SageMath version to 9.5.beta4 --- .zenodo.json | 8 ++++---- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/sagelib/package-version.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index 035015bacf5..f80be3c909b 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,10 +1,10 @@ { "description": "Mirror of the Sage https://sagemath.org/ source tree", "license": "other-open", - "title": "sagemath/sage: 9.5.beta3", - "version": "9.5.beta3", + "title": "sagemath/sage: 9.5.beta4", + "version": "9.5.beta4", "upload_type": "software", - "publication_date": "2021-10-11", + "publication_date": "2021-10-19", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.5.beta3", + "identifier": "https://github.com/sagemath/sage/tree/9.5.beta4", "relation": "isSupplementTo" }, { diff --git a/VERSION.txt b/VERSION.txt index 88f7d68ebc9..d035bc57e4b 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.5.beta3, Release Date: 2021-10-11 +SageMath version 9.5.beta4, Release Date: 2021-10-19 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 4720cc7df61..ce3df02bc5b 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=bf77cf87636c32930d165719bbf5f376b2830745 -md5=dbd50992848adbd32e1eab9bc0374faf -cksum=2846351532 +sha1=1df4c487d374a7ea9eeda3a9234cc6eed81c1443 +md5=83d4327261e545f26d4ad318030823e8 +cksum=2968565921 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 901ac7cbb07..3969244814e 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -ced8aa261e9d69ddfc3e2d25de2ff9c60ed389bf +e8ab458165ec5e5832adf702099f47f4cff94596 diff --git a/build/pkgs/sagelib/package-version.txt b/build/pkgs/sagelib/package-version.txt index 173833eaf87..3fe69eb5038 100644 --- a/build/pkgs/sagelib/package-version.txt +++ b/build/pkgs/sagelib/package-version.txt @@ -1 +1 @@ -9.5.beta3 +9.5.beta4 diff --git a/src/VERSION.txt b/src/VERSION.txt index 173833eaf87..3fe69eb5038 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.5.beta3 +9.5.beta4 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 750e10d31e0..1fa6283f152 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,5 +1,5 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.5.beta3' -SAGE_RELEASE_DATE='2021-10-11' -SAGE_VERSION_BANNER='SageMath version 9.5.beta3, Release Date: 2021-10-11' +SAGE_VERSION='9.5.beta4' +SAGE_RELEASE_DATE='2021-10-19' +SAGE_VERSION_BANNER='SageMath version 9.5.beta4, Release Date: 2021-10-19' diff --git a/src/sage/version.py b/src/sage/version.py index e9950f06043..0cd77c29e31 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '9.5.beta3' -date = '2021-10-11' -banner = 'SageMath version 9.5.beta3, Release Date: 2021-10-11' +version = '9.5.beta4' +date = '2021-10-19' +banner = 'SageMath version 9.5.beta4, Release Date: 2021-10-19' From efdac8754b4b13736d1f9e4be6369ca7536113d8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 19 Oct 2021 21:07:45 -0700 Subject: [PATCH 472/511] build/pkgs/argcomplete: Make it a standard package --- build/pkgs/argcomplete/type | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/argcomplete/type b/build/pkgs/argcomplete/type index 134d9bc32d5..a6a7b9cd726 100644 --- a/build/pkgs/argcomplete/type +++ b/build/pkgs/argcomplete/type @@ -1 +1 @@ -optional +standard From 51b554fd4ee591f18daa44de447e00c037a78fe6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 19 Oct 2021 21:51:15 -0700 Subject: [PATCH 473/511] sage.misc.functional: Move sqrt here from sage.functions.other --- src/sage/functions/other.py | 154 +----------------------------------- src/sage/misc/functional.py | 154 ++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 152 deletions(-) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index bbccf43c386..bb7e5d7d7bd 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -19,7 +19,7 @@ 'gamma_inc_lower', 'psi', 'beta'), deprecation=24411) from sage.symbolic.function import GinacFunction, BuiltinFunction -from sage.symbolic.expression import Expression, register_symbol, symbol_table, I +from sage.symbolic.expression import Expression, register_symbol, symbol_table from sage.symbolic.ring import SR from sage.rings.all import Integer, Rational, RealField, ZZ, ComplexField from sage.misc.latex import latex @@ -35,7 +35,7 @@ from sage.arith.all import binomial as arith_binomial -one_half = SR.one() / SR(2) +from sage.misc.functional import sqrt class Function_abs(GinacFunction): @@ -752,156 +752,6 @@ def _eval_(self, x): frac = Function_frac() -def _do_sqrt(x, prec=None, extend=True, all=False): - r""" - Used internally to compute the square root of x. - - INPUT: - - - ``x`` - a number - - - ``prec`` - None (default) or a positive integer - (bits of precision) If not None, then compute the square root - numerically to prec bits of precision. - - - ``extend`` - bool (default: True); this is a place - holder, and is always ignored since in the symbolic ring everything - has a square root. - - - ``extend`` - bool (default: True); whether to extend - the base ring to find roots. The extend parameter is ignored if - prec is a positive integer. - - - ``all`` - bool (default: False); whether to return - a list of all the square roots of x. - - - EXAMPLES:: - - sage: from sage.functions.other import _do_sqrt - sage: _do_sqrt(3) - sqrt(3) - sage: _do_sqrt(3,prec=10) - 1.7 - sage: _do_sqrt(3,prec=100) - 1.7320508075688772935274463415 - sage: _do_sqrt(3,all=True) - [sqrt(3), -sqrt(3)] - - Note that the extend parameter is ignored in the symbolic ring:: - - sage: _do_sqrt(3,extend=False) - sqrt(3) - """ - if prec: - if x >= 0: - return RealField(prec)(x).sqrt(all=all) - else: - return ComplexField(prec)(x).sqrt(all=all) - if x == -1: - z = I - else: - z = SR(x) ** one_half - - if all: - if z: - return [z, -z] - else: - return [z] - return z - -def sqrt(x, *args, **kwds): - r""" - INPUT: - - - ``x`` - a number - - - ``prec`` - integer (default: None): if None, returns - an exact square root; otherwise returns a numerical square root if - necessary, to the given bits of precision. - - - ``extend`` - bool (default: True); this is a place - holder, and is always ignored or passed to the sqrt function for x, - since in the symbolic ring everything has a square root. - - - ``all`` - bool (default: False); if True, return all - square roots of self, instead of just one. - - EXAMPLES:: - - sage: sqrt(-1) - I - sage: sqrt(2) - sqrt(2) - sage: sqrt(2)^2 - 2 - sage: sqrt(4) - 2 - sage: sqrt(4,all=True) - [2, -2] - sage: sqrt(x^2) - sqrt(x^2) - - For a non-symbolic square root, there are a few options. - The best is to numerically approximate afterward:: - - sage: sqrt(2).n() - 1.41421356237310 - sage: sqrt(2).n(prec=100) - 1.4142135623730950488016887242 - - Or one can input a numerical type. - - sage: sqrt(2.) - 1.41421356237310 - sage: sqrt(2.000000000000000000000000) - 1.41421356237309504880169 - sage: sqrt(4.0) - 2.00000000000000 - - To prevent automatic evaluation, one can use the ``hold`` parameter - after coercing to the symbolic ring:: - - sage: sqrt(SR(4),hold=True) - sqrt(4) - sage: sqrt(4,hold=True) - Traceback (most recent call last): - ... - TypeError: ..._do_sqrt() got an unexpected keyword argument 'hold' - - This illustrates that the bug reported in :trac:`6171` has been fixed:: - - sage: a = 1.1 - sage: a.sqrt(prec=100) # this is supposed to fail - Traceback (most recent call last): - ... - TypeError: ...sqrt() got an unexpected keyword argument 'prec' - sage: sqrt(a, prec=100) - 1.0488088481701515469914535137 - sage: sqrt(4.00, prec=250) - 2.0000000000000000000000000000000000000000000000000000000000000000000000000 - - One can use numpy input as well:: - - sage: import numpy - sage: a = numpy.arange(2,5) - sage: sqrt(a) - array([1.41421356, 1.73205081, 2. ]) - """ - if isinstance(x, float): - return math.sqrt(x) - elif type(x).__module__ == 'numpy': - from numpy import sqrt - return sqrt(x) - try: - return x.sqrt(*args, **kwds) - # The following includes TypeError to catch cases where sqrt - # is called with a "prec" keyword, for example, but the sqrt - # method for x doesn't accept such a keyword. - except (AttributeError, TypeError): - pass - return _do_sqrt(x, *args, **kwds) - # register sqrt in pynac symbol_table for conversion back from other systems register_symbol(sqrt, dict(mathematica='Sqrt')) symbol_table['functions']['sqrt'] = sqrt diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index 45d74ea749a..88447abb8b8 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -1679,6 +1679,160 @@ def squarefree_part(x): return n * F.unit() +def _do_sqrt(x, prec=None, extend=True, all=False): + r""" + Used internally to compute the square root of x. + + INPUT: + + - ``x`` - a number + + - ``prec`` - None (default) or a positive integer + (bits of precision) If not None, then compute the square root + numerically to prec bits of precision. + + - ``extend`` - bool (default: True); this is a place + holder, and is always ignored since in the symbolic ring everything + has a square root. + + - ``extend`` - bool (default: True); whether to extend + the base ring to find roots. The extend parameter is ignored if + prec is a positive integer. + + - ``all`` - bool (default: False); whether to return + a list of all the square roots of x. + + + EXAMPLES:: + + sage: from sage.functions.other import _do_sqrt + sage: _do_sqrt(3) + sqrt(3) + sage: _do_sqrt(3,prec=10) + 1.7 + sage: _do_sqrt(3,prec=100) + 1.7320508075688772935274463415 + sage: _do_sqrt(3,all=True) + [sqrt(3), -sqrt(3)] + + Note that the extend parameter is ignored in the symbolic ring:: + + sage: _do_sqrt(3,extend=False) + sqrt(3) + """ + if prec: + if x >= 0: + return RealField(prec)(x).sqrt(all=all) + else: + return ComplexField(prec)(x).sqrt(all=all) + if x == -1: + from sage.symbolic.expression import I + z = I + else: + from sage.symbolic.ring import SR + z = SR(x).sqrt() + + if all: + if z: + return [z, -z] + else: + return [z] + return z + + +def sqrt(x, *args, **kwds): + r""" + INPUT: + + - ``x`` - a number + + - ``prec`` - integer (default: None): if None, returns + an exact square root; otherwise returns a numerical square root if + necessary, to the given bits of precision. + + - ``extend`` - bool (default: True); this is a place + holder, and is always ignored or passed to the sqrt function for x, + since in the symbolic ring everything has a square root. + + - ``all`` - bool (default: False); if True, return all + square roots of self, instead of just one. + + EXAMPLES:: + + sage: sqrt(-1) + I + sage: sqrt(2) + sqrt(2) + sage: sqrt(2)^2 + 2 + sage: sqrt(4) + 2 + sage: sqrt(4,all=True) + [2, -2] + sage: sqrt(x^2) + sqrt(x^2) + + For a non-symbolic square root, there are a few options. + The best is to numerically approximate afterward:: + + sage: sqrt(2).n() + 1.41421356237310 + sage: sqrt(2).n(prec=100) + 1.4142135623730950488016887242 + + Or one can input a numerical type. + + sage: sqrt(2.) + 1.41421356237310 + sage: sqrt(2.000000000000000000000000) + 1.41421356237309504880169 + sage: sqrt(4.0) + 2.00000000000000 + + To prevent automatic evaluation, one can use the ``hold`` parameter + after coercing to the symbolic ring:: + + sage: sqrt(SR(4),hold=True) + sqrt(4) + sage: sqrt(4,hold=True) + Traceback (most recent call last): + ... + TypeError: ..._do_sqrt() got an unexpected keyword argument 'hold' + + This illustrates that the bug reported in :trac:`6171` has been fixed:: + + sage: a = 1.1 + sage: a.sqrt(prec=100) # this is supposed to fail + Traceback (most recent call last): + ... + TypeError: ...sqrt() got an unexpected keyword argument 'prec' + sage: sqrt(a, prec=100) + 1.0488088481701515469914535137 + sage: sqrt(4.00, prec=250) + 2.0000000000000000000000000000000000000000000000000000000000000000000000000 + + One can use numpy input as well:: + + sage: import numpy + sage: a = numpy.arange(2,5) + sage: sqrt(a) + array([1.41421356, 1.73205081, 2. ]) + """ + if isinstance(x, float): + return math.sqrt(x) + elif type(x).__module__ == 'numpy': + from numpy import sqrt + return sqrt(x) + try: + return x.sqrt(*args, **kwds) + # The following includes TypeError to catch cases where sqrt + # is called with a "prec" keyword, for example, but the sqrt + # method for x doesn't accept such a keyword. + except (AttributeError, TypeError): + pass + return _do_sqrt(x, *args, **kwds) + + def transpose(x): """ Return the transpose of ``x``. From 71165ea7fe3d608a770eba00d6831d2b8d189f1f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 19 Oct 2021 21:54:38 -0700 Subject: [PATCH 474/511] git grep -l 'functions.*import.*sqrt' | xargs sed -i.bak 's/from sage[.]functions[.].* import sqrt *$/from sage.misc.functional import sqrt/' --- src/sage/coding/linear_code.py | 2 +- src/sage/combinat/binary_recurrence_sequences.py | 2 +- src/sage/combinat/parallelogram_polyomino.py | 2 +- src/sage/combinat/root_system/plot.py | 2 +- src/sage/combinat/symmetric_group_representations.py | 2 +- .../arithmetic_dynamics/endPN_automorphism_group.py | 2 +- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 2 +- src/sage/dynamics/arithmetic_dynamics/wehlerK3.py | 2 +- src/sage/functions/bessel.py | 2 +- src/sage/functions/orthogonal_polys.py | 2 +- .../geometry/riemannian_manifolds/parametrized_surface3d.py | 2 +- src/sage/graphs/generators/distance_regular.pyx | 2 +- src/sage/graphs/generators/smallgraphs.py | 2 +- src/sage/graphs/generic_graph.py | 2 +- src/sage/graphs/graph_plot.py | 2 +- src/sage/interacts/library.py | 2 +- src/sage/knots/knotinfo.py | 2 +- src/sage/manifolds/catalog.py | 2 +- src/sage/manifolds/differentiable/examples/euclidean.py | 2 +- src/sage/manifolds/differentiable/examples/sphere.py | 2 +- src/sage/matrix/matrix2.pyx | 4 ++-- src/sage/matrix/special.py | 2 +- src/sage/modular/modform_hecketriangle/element.py | 2 +- src/sage/modules/with_basis/representation.py | 2 +- src/sage/plot/plot3d/revolution_plot3d.py | 2 +- src/sage/plot/plot_field.py | 2 +- src/sage/plot/streamline_plot.py | 2 +- src/sage/probability/random_variable.py | 2 +- src/sage/quadratic_forms/quadratic_form__siegel_product.py | 2 +- .../asymptotics_multivariate_generating_functions.py | 2 +- src/sage/rings/number_field/number_field_element.pyx | 2 +- src/sage/rings/polynomial/polynomial_element.pyx | 2 +- src/sage/rings/rational.pyx | 2 +- src/sage/schemes/elliptic_curves/ell_modular_symbols.py | 2 +- src/sage/stats/basic_stats.py | 2 +- src/sage/symbolic/expression_conversions.py | 6 +++--- 36 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index eb50986d29e..643e7239460 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -837,7 +837,7 @@ def chinen_polynomial(self): - Chinen, K. "An abundance of invariant polynomials satisfying the Riemann hypothesis", April 2007 preprint. """ - from sage.functions.all import sqrt + from sage.misc.functional import sqrt C = self n = C.length() RT = PolynomialRing(QQ,2,"Ts") diff --git a/src/sage/combinat/binary_recurrence_sequences.py b/src/sage/combinat/binary_recurrence_sequences.py index b9ec447170a..9bd217b5d5e 100644 --- a/src/sage/combinat/binary_recurrence_sequences.py +++ b/src/sage/combinat/binary_recurrence_sequences.py @@ -67,7 +67,7 @@ from sage.rings.integer import Integer from sage.arith.all import lcm, next_prime, is_prime, next_prime_power, legendre_symbol from sage.functions.log import log -from sage.functions.other import sqrt +from sage.misc.functional import sqrt class BinaryRecurrenceSequence(SageObject): diff --git a/src/sage/combinat/parallelogram_polyomino.py b/src/sage/combinat/parallelogram_polyomino.py index 48a8de037f8..9dbdf47baf1 100644 --- a/src/sage/combinat/parallelogram_polyomino.py +++ b/src/sage/combinat/parallelogram_polyomino.py @@ -39,7 +39,7 @@ from sage.combinat.combinat import catalan_number from sage.combinat.combinatorial_map import combinatorial_map from sage.functions.trig import cos, sin -from sage.functions.other import sqrt +from sage.misc.functional import sqrt from sage.plot.graphics import Graphics from sage.plot.line import line diff --git a/src/sage/combinat/root_system/plot.py b/src/sage/combinat/root_system/plot.py index 36da0e98384..41371737f7a 100644 --- a/src/sage/combinat/root_system/plot.py +++ b/src/sage/combinat/root_system/plot.py @@ -1574,7 +1574,7 @@ def barycentric_projection_matrix(n, angle=0): """ from sage.matrix.constructor import matrix - from sage.functions.other import sqrt + from sage.misc.functional import sqrt n = ZZ(n) if n == 0: return matrix(QQ, 0, 1) diff --git a/src/sage/combinat/symmetric_group_representations.py b/src/sage/combinat/symmetric_group_representations.py index 169d0f862ef..363e1cf78a5 100644 --- a/src/sage/combinat/symmetric_group_representations.py +++ b/src/sage/combinat/symmetric_group_representations.py @@ -29,7 +29,7 @@ # **************************************************************************** from sage.symbolic.ring import SR -from sage.functions.all import sqrt +from sage.misc.functional import sqrt from sage.combinat.partition import Partition, Partitions from sage.combinat.permutation import Permutation, Permutations, from_cycles from sage.combinat.tableau import StandardTableaux, Tableau diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index e5ef59acf59..14ae3029a87 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -23,7 +23,7 @@ from copy import copy, deepcopy from sage.combinat.subset import Subsets -from sage.functions.all import sqrt +from sage.misc.functional import sqrt from itertools import permutations, combinations, product from sage.matrix.constructor import matrix from sage.structure.element import is_Matrix diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 27f9c39b583..32a3a77dadd 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -59,7 +59,7 @@ class initialization directly. from sage.categories.number_fields import NumberFields from sage.categories.homset import End from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem -from sage.functions.all import sqrt +from sage.misc.functional import sqrt from sage.functions.other import ceil from sage.libs.pari.all import PariError from sage.matrix.constructor import matrix, identity_matrix diff --git a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py index a385b8a54b9..c8ad02059fe 100644 --- a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py +++ b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py @@ -29,7 +29,7 @@ from sage.calculus.functions import jacobian from sage.categories.fields import Fields from sage.categories.number_fields import NumberFields -from sage.functions.all import sqrt +from sage.misc.functional import sqrt from sage.misc.cachefunc import cached_method from sage.misc.mrange import xmrange from sage.rings.all import CommutativeRing diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index 3ba9ece2359..b51b0b93d02 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -210,7 +210,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.functions.other import sqrt +from sage.misc.functional import sqrt from sage.functions.log import exp from sage.functions.hyperbolic import sinh, cosh from sage.functions.trig import sin, cos diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 4c6650f5311..d9cec09210d 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -1824,7 +1824,7 @@ def eval_recursive(self, n, m, x, **kwds): sage: gen_legendre_Q(2,2,x).subs(x=2).expand() 9/2*I*pi - 9/2*log(3) + 14/3 """ - from sage.functions.all import sqrt + from sage.misc.functional import sqrt if m == n + 1 or n == 0: if m.mod(2).is_zero(): denom = (1 - x**2)**(m/2) diff --git a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py index ce3e306d277..10ea1e48e2d 100644 --- a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py +++ b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py @@ -21,7 +21,7 @@ from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix from sage.calculus.functional import diff -from sage.functions.other import sqrt +from sage.misc.functional import sqrt from sage.misc.cachefunc import cached_method from sage.symbolic.ring import SR from sage.symbolic.constants import pi diff --git a/src/sage/graphs/generators/distance_regular.pyx b/src/sage/graphs/generators/distance_regular.pyx index 38c356d8863..55eee4d0a03 100644 --- a/src/sage/graphs/generators/distance_regular.pyx +++ b/src/sage/graphs/generators/distance_regular.pyx @@ -2100,7 +2100,7 @@ def graph_with_classical_parameters(int d, int b, alpha_in, beta_in, int gamma): """ from sage.rings.rational import Rational from sage.functions.log import log - from sage.functions.other import sqrt + from sage.misc.functional import sqrt from sage.graphs.generators.families import JohnsonGraph, HammingGraph from sage.graphs.generators.classical_geometries import \ UnitaryDualPolarGraph, OrthogonalDualPolarGraph, SymplecticDualPolarGraph diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index a7ddfa7c1d9..072812c75c4 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -18,7 +18,7 @@ # import from Sage library from sage.graphs.graph import Graph from sage.rings.rational_field import QQ -from sage.functions.other import sqrt +from sage.misc.functional import sqrt from math import sin, cos, pi diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index d0850f13357..33f06c06dda 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -2415,7 +2415,7 @@ def kirchhoff_matrix(self, weighted=None, indegree=True, normalized=False, signl [-4 -3 -1 8] """ from sage.matrix.constructor import diagonal_matrix - from sage.functions.all import sqrt + from sage.misc.functional import sqrt if weighted is None: weighted = self._weighted diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index 23ffeb016f0..de7086ed71f 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -799,7 +799,7 @@ def set_edges(self, **edge_options): dist = self._options['dist'] * 2 min_loop_size = self._options['loop_size'] max_dist = self._options['max_dist'] - from sage.functions.all import sqrt + from sage.misc.functional import sqrt for a, b in tmp: if a == b: # Multiple loops need varying loop radius starting at diff --git a/src/sage/interacts/library.py b/src/sage/interacts/library.py index 63b6ff674a4..153ba021b8f 100644 --- a/src/sage/interacts/library.py +++ b/src/sage/interacts/library.py @@ -42,7 +42,7 @@ from sage.calculus.integration import numerical_integral as integral_numerical from sage.ext.fast_callable import fast_callable from sage.functions.log import exp -from sage.functions.other import sqrt +from sage.misc.functional import sqrt from sage.functions.trig import (acos, cos, sin, tan) from sage.misc.decorators import sage_wraps from sage.misc.functional import N diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index 54b7812a3b0..d74b433c439 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -1499,7 +1499,7 @@ def jones_polynomial(self, variab=None, skein_normalization=False, puiseux=False elif puiseux: lc = {'x': t**(1/2)} elif use_sqrt: - from sage.functions.other import sqrt + from sage.misc.functional import sqrt lc = {'x': sqrt(t)} else: lc = {'x': t} diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index a73a93382a8..a0a04f90bce 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -159,7 +159,7 @@ def Kerr(m=1, a=0, coordinates="BL", names=None): sage: K.default_chart().coord_range() t: (-oo, +oo); r: (0, +oo); th: (0, pi); ph: [-pi, pi] (periodic) """ - from sage.functions.other import sqrt + from sage.misc.functional import sqrt from sage.functions.trig import cos, sin from sage.manifolds.manifold import Manifold M = Manifold(4, 'M', structure="Lorentzian") diff --git a/src/sage/manifolds/differentiable/examples/euclidean.py b/src/sage/manifolds/differentiable/examples/euclidean.py index b0659787b0e..e85d5c1d2c0 100644 --- a/src/sage/manifolds/differentiable/examples/euclidean.py +++ b/src/sage/manifolds/differentiable/examples/euclidean.py @@ -410,7 +410,7 @@ #***************************************************************************** from sage.functions.trig import cos, sin, atan2 -from sage.functions.other import sqrt +from sage.misc.functional import sqrt from sage.misc.latex import latex from sage.rings.real_mpfr import RR from sage.categories.manifolds import Manifolds diff --git a/src/sage/manifolds/differentiable/examples/sphere.py b/src/sage/manifolds/differentiable/examples/sphere.py index 9dbdf3bdd40..3b9df0f6c79 100644 --- a/src/sage/manifolds/differentiable/examples/sphere.py +++ b/src/sage/manifolds/differentiable/examples/sphere.py @@ -1018,7 +1018,7 @@ def _transition_spher_stereo(self): # transition: stereoN to spher... from sage.functions.trig import acos, atan2 - from sage.functions.special import sqrt + from sage.misc.functional import sqrt # get ambient coordinates and shift to coordinate origin: x = self._shift_coords(imm.expr(stereoN, cart), s='-') coordfunc = [atan2(x[1],x[0])] diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 75d8dc56424..6a1776da9ab 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -10208,7 +10208,7 @@ cdef class Matrix(Matrix1): """ from sage.modules.free_module_element import zero_vector from sage.matrix.constructor import zero_matrix, matrix - from sage.functions.other import sqrt + from sage.misc.functional import sqrt if full: QR = self.fetch('QR_factors') @@ -14666,7 +14666,7 @@ cdef class Matrix(Matrix1): True """ from sage.matrix.special import diagonal_matrix - from sage.functions.other import sqrt + from sage.misc.functional import sqrt if check_positivity and not self.is_positive_definite(): return False diff --git a/src/sage/matrix/special.py b/src/sage/matrix/special.py index bcb0b0293af..2f9b5f285a9 100644 --- a/src/sage/matrix/special.py +++ b/src/sage/matrix/special.py @@ -3402,7 +3402,7 @@ def ith_to_zero_rotation_matrix(v, i, ring=None): a, b = v[j], v[i] if b == 0: return identity_matrix(dim, sparse=True) - from sage.functions.all import sqrt + from sage.misc.functional import sqrt norm = sqrt(a * a + b * b) aa = a / norm bb = b / norm diff --git a/src/sage/modular/modform_hecketriangle/element.py b/src/sage/modular/modform_hecketriangle/element.py index 4f8114f1125..4959652a921 100644 --- a/src/sage/modular/modform_hecketriangle/element.py +++ b/src/sage/modular/modform_hecketriangle/element.py @@ -286,7 +286,7 @@ def lseries(self, num_prec=None, max_imaginary_part=0, max_asymp_coeffs=40): """ from sage.rings.integer_ring import ZZ from sage.symbolic.all import pi - from sage.functions.other import sqrt + from sage.misc.functional import sqrt from sage.lfunctions.dokchitser import Dokchitser if (not (self.is_modular() and self.is_holomorphic()) or self.weight() == 0): diff --git a/src/sage/modules/with_basis/representation.py b/src/sage/modules/with_basis/representation.py index e6f97d219a5..496dd5b0e40 100644 --- a/src/sage/modules/with_basis/representation.py +++ b/src/sage/modules/with_basis/representation.py @@ -349,7 +349,7 @@ def _test_representation(self, **options): sage: R = Representation(G, M, on_basis, side="right") sage: R._test_representation(max_runs=500) """ - from sage.functions.other import sqrt + from sage.misc.functional import sqrt tester = self._tester(**options) S = tester.some_elements() L = [] diff --git a/src/sage/plot/plot3d/revolution_plot3d.py b/src/sage/plot/plot3d/revolution_plot3d.py index 50af10cd9a4..ccf18787f48 100644 --- a/src/sage/plot/plot3d/revolution_plot3d.py +++ b/src/sage/plot/plot3d/revolution_plot3d.py @@ -211,7 +211,7 @@ def cf(u, phi): return float(2 * u / pi) % 1 """ from sage.symbolic.ring import SR from sage.symbolic.constants import pi - from sage.functions.other import sqrt + from sage.misc.functional import sqrt from sage.functions.trig import sin from sage.functions.trig import cos from sage.functions.trig import atan2 diff --git a/src/sage/plot/plot_field.py b/src/sage/plot/plot_field.py index 04a60dddcda..b57af986b59 100644 --- a/src/sage/plot/plot_field.py +++ b/src/sage/plot/plot_field.py @@ -348,7 +348,7 @@ def plot_slope_field(f, xrange, yrange, **kwds): 'pivot': 'middle'} slope_options.update(kwds) - from sage.functions.all import sqrt + from sage.misc.functional import sqrt from sage.misc.sageinspect import is_function_or_cython_function if is_function_or_cython_function(f): norm_inverse = lambda x,y: 1/sqrt(f(x, y)**2+1) diff --git a/src/sage/plot/streamline_plot.py b/src/sage/plot/streamline_plot.py index c5d992c957a..2849669f18d 100644 --- a/src/sage/plot/streamline_plot.py +++ b/src/sage/plot/streamline_plot.py @@ -271,7 +271,7 @@ def streamline_plot(f_g, xrange, yrange, **options): if isinstance(f_g, (list, tuple)): (f,g) = f_g else: - from sage.functions.all import sqrt + from sage.misc.functional import sqrt from sage.misc.sageinspect import is_function_or_cython_function if is_function_or_cython_function(f_g): f = lambda x,y: 1 / sqrt(f_g(x, y)**2 + 1) diff --git a/src/sage/probability/random_variable.py b/src/sage/probability/random_variable.py index 47d108996f0..44501d5e2e2 100644 --- a/src/sage/probability/random_variable.py +++ b/src/sage/probability/random_variable.py @@ -18,7 +18,7 @@ import sage.rings.abc from sage.structure.parent import Parent from sage.functions.log import log -from sage.functions.all import sqrt +from sage.misc.functional import sqrt from sage.rings.rational_field import is_RationalField from sage.sets.set import Set from pprint import pformat diff --git a/src/sage/quadratic_forms/quadratic_form__siegel_product.py b/src/sage/quadratic_forms/quadratic_form__siegel_product.py index fb2e72a0f4a..eb2bff7f6cc 100644 --- a/src/sage/quadratic_forms/quadratic_form__siegel_product.py +++ b/src/sage/quadratic_forms/quadratic_form__siegel_product.py @@ -13,7 +13,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.arith.all import kronecker_symbol, bernoulli, prime_divisors, fundamental_discriminant -from sage.functions.all import sqrt +from sage.misc.functional import sqrt from sage.quadratic_forms.special_values import QuadraticBernoulliNumber diff --git a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py index 06301c7633c..8a335d4f852 100644 --- a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +++ b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py @@ -4163,7 +4163,7 @@ def diff_op_simple(A, B, AB_derivs, x, v, a, N): ((1, 1), 1/4*2^(2/3)*(B(x)*diff(A(x), x, x, x, x) + 4*diff(A(x), x, x, x)*diff(B(x), x) + 6*diff(A(x), x, x)*diff(B(x), x, x) + 4*diff(A(x), x)*diff(B(x), x, x, x) + A(x)*diff(B(x), x, x, x, x)))] """ - from sage.functions.other import sqrt + from sage.misc.functional import sqrt I = sqrt(-ZZ.one()) DD = {} diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index bba2fc46afc..c1af4f13b22 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -2258,7 +2258,7 @@ cdef class NumberFieldElement(FieldElement): if extend and not roots: try: # This is what integers, rationals do... - from sage.functions.other import sqrt + from sage.misc.functional import sqrt from sage.symbolic.ring import SR root = sqrt(SR(self)) roots = [[root, 1], [-root, 1]] diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 056c39152f0..ba116954fc5 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -7935,7 +7935,7 @@ cdef class Polynomial(CommutativeAlgebraElement): from sage.symbolic.ring import SR if L is SR: if self.degree() == 2: - from sage.functions.other import sqrt + from sage.misc.functional import sqrt from sage.symbolic.expression import I coeffs = self.list() D = coeffs[1]*coeffs[1] - 4*coeffs[0]*coeffs[2] diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 6e02cf4387d..e6e7a9ff1dc 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -3263,7 +3263,7 @@ cdef class Rational(sage.structure.element.FieldElement): numer = self.numer() rat_part = Rational((numer-2).multifactorial(2)) >> ((numer-1)//2) from sage.symbolic.constants import pi - from sage.functions.all import sqrt + from sage.misc.functional import sqrt return sqrt(pi) * rat_part else: from sage.symbolic.ring import SR diff --git a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py index 30a61e1635c..cb018a51eeb 100644 --- a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py +++ b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py @@ -608,7 +608,7 @@ def __lalg__(self, D): sage: m.__lalg__(3) 5/2 """ - from sage.functions.all import sqrt + from sage.misc.functional import sqrt # the computation of the L-value could take a lot of time, # but then the conductor is so large # that the computation of modular symbols for E took even longer diff --git a/src/sage/stats/basic_stats.py b/src/sage/stats/basic_stats.py index b793d02f493..232b56f1480 100644 --- a/src/sage/stats/basic_stats.py +++ b/src/sage/stats/basic_stats.py @@ -41,7 +41,7 @@ from sage.rings.integer_ring import ZZ from sage.symbolic.constants import NaN -from sage.functions.other import sqrt +from sage.misc.functional import sqrt from sage.misc.superseded import deprecation diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index 98d2820a361..d12c5969e72 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -1782,10 +1782,10 @@ def arithmetic(self, ex, operator): if exponent == -1: return self.etb.call(_operator.truediv, 1, operands[0]) elif exponent == 0.5: - from sage.functions.all import sqrt + from sage.misc.functional import sqrt return self.etb.call(sqrt, operands[0]) elif exponent == -0.5: - from sage.functions.all import sqrt + from sage.misc.functional import sqrt return self.etb.call(_operator.truediv, 1, self.etb.call(sqrt, operands[0])) elif operator is _operator.neg: return self.etb.call(operator, operands[0]) @@ -1949,7 +1949,7 @@ def arithmetic(self, ex, operator): base, expt = operands if expt == Rational(((1,2))): - from sage.functions.all import sqrt + from sage.misc.functional import sqrt return sqrt(self(base)) try: expt = Integer(expt) From 12145412d0afc137089d163e6c4698eb1bfa6193 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 19 Oct 2021 21:55:50 -0700 Subject: [PATCH 475/511] git grep -l 'functions.*import.*sqrt' | xargs sed -i.bak 's/from sage[.]functions[.].* import _do_sqrt *$/from sage.misc.functional import _do_sqrt/' --- src/sage/misc/functional.py | 2 +- src/sage/rings/integer.pyx | 4 ++-- src/sage/rings/rational.pyx | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index 88447abb8b8..ec701dade01 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -1705,7 +1705,7 @@ def _do_sqrt(x, prec=None, extend=True, all=False): EXAMPLES:: - sage: from sage.functions.other import _do_sqrt + sage: from sage.misc.functional import _do_sqrt sage: _do_sqrt(3) sqrt(3) sage: _do_sqrt(3,prec=10) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 56de0fc858a..7e2fd3d6f19 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -6203,7 +6203,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): [] """ if prec is not None: - from sage.functions.other import _do_sqrt + from sage.misc.functional import _do_sqrt return _do_sqrt(self, prec=prec, all=all) if mpz_sgn(self.value) == 0: @@ -6225,7 +6225,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): if not is_square: if extend: - from sage.functions.other import _do_sqrt + from sage.misc.functional import _do_sqrt return _do_sqrt(self, all=all) if all: return [] diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index e6e7a9ff1dc..d4a6b69e361 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -1943,7 +1943,7 @@ cdef class Rational(sage.structure.element.FieldElement): if mpq_sgn(self.value) < 0: if not extend: raise ValueError("square root of negative number not rational") - from sage.functions.other import _do_sqrt + from sage.misc.functional import _do_sqrt return _do_sqrt(self, prec=prec, all=all) cdef Rational z = Rational.__new__(Rational) @@ -1965,11 +1965,11 @@ cdef class Rational(sage.structure.element.FieldElement): if non_square: if not extend: raise ValueError("square root of %s not a rational number" % self) - from sage.functions.other import _do_sqrt + from sage.misc.functional import _do_sqrt return _do_sqrt(self, prec=prec, all=all) if prec: - from sage.functions.other import _do_sqrt + from sage.misc.functional import _do_sqrt return _do_sqrt(self, prec=prec, all=all) if all: From 4a752e0c2c5b9ee190fa3335d8ed873243163cdf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 19 Oct 2021 22:03:00 -0700 Subject: [PATCH 476/511] git grep -l 'functions.*import.*sqrt' | xargs sed -E -i.bak $'s/^( *)from (sage[.]functions[.].* import .*)(, *sqrt|sqrt, *)(.*)/\1from \2\4\\n\1from sage.misc.functional import sqrt/' --- src/sage/coding/code_bounds.py | 3 ++- src/sage/coding/guruswami_sudan/gs_decoder.py | 3 ++- src/sage/coding/guruswami_sudan/utils.py | 3 ++- src/sage/combinat/posets/poset_examples.py | 3 ++- src/sage/combinat/words/word_generators.py | 3 ++- src/sage/crypto/lwe.py | 3 ++- src/sage/functions/error.py | 3 ++- src/sage/functions/special.py | 3 ++- src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py | 3 ++- src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py | 3 ++- src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py | 3 ++- src/sage/geometry/hyperbolic_space/hyperbolic_model.py | 3 ++- src/sage/geometry/polyhedron/base.py | 3 ++- .../groups/additive_abelian/additive_abelian_wrapper.py | 3 ++- src/sage/interfaces/tides.py | 3 ++- src/sage/manifolds/utilities.py | 3 ++- src/sage/quadratic_forms/quadratic_form__theta.py | 3 ++- .../asymptotics_multivariate_generating_functions.py | 6 ++++-- src/sage/rings/invariants/reconstruction.py | 3 ++- 19 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/sage/coding/code_bounds.py b/src/sage/coding/code_bounds.py index 38244287ec5..9f5640ca1f4 100644 --- a/src/sage/coding/code_bounds.py +++ b/src/sage/coding/code_bounds.py @@ -177,7 +177,8 @@ from sage.rings.all import QQ, RR, ZZ, RDF from sage.arith.misc import is_prime_power from sage.arith.all import binomial -from sage.functions.all import log, sqrt +from sage.functions.all import log +from sage.misc.functional import sqrt from .delsarte_bounds import (delsarte_bound_hamming_space, delsarte_bound_additive_hamming_space) diff --git a/src/sage/coding/guruswami_sudan/gs_decoder.py b/src/sage/coding/guruswami_sudan/gs_decoder.py index 1a22f1e59fe..455accbbe00 100644 --- a/src/sage/coding/guruswami_sudan/gs_decoder.py +++ b/src/sage/coding/guruswami_sudan/gs_decoder.py @@ -31,7 +31,8 @@ from sage.coding.guruswami_sudan.utils import (johnson_radius, gilt, solve_degree2_to_integer_range) -from sage.functions.other import floor, sqrt +from sage.functions.other import floor +from sage.misc.functional import sqrt def n_k_params(C, n_k): r""" diff --git a/src/sage/coding/guruswami_sudan/utils.py b/src/sage/coding/guruswami_sudan/utils.py index e1b88879605..d53637d933f 100644 --- a/src/sage/coding/guruswami_sudan/utils.py +++ b/src/sage/coding/guruswami_sudan/utils.py @@ -19,7 +19,8 @@ #***************************************************************************** -from sage.functions.other import floor, sqrt +from sage.functions.other import floor +from sage.misc.functional import sqrt from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index 962f354c236..c94a00a29db 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -1924,7 +1924,8 @@ def _random_lattice(n, p): meet for `e, m` for all `m \in M`. We do that by keeping track of meet matrix and list of maximal elements. """ - from sage.functions.other import floor, sqrt + from sage.functions.other import floor + from sage.misc.functional import sqrt from sage.misc.prandom import random n = n-1 diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index 9b5c7fe08fb..ec0d44e5f8c 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -574,7 +574,8 @@ def FibonacciWord(self, alphabet=(0, 1), construction_method="recursive"): return w elif construction_method == "function": - from sage.functions.other import sqrt, floor + from sage.functions.other import floor + from sage.misc.functional import sqrt phi = (1 + sqrt(5))/2 # the golden ratio f = lambda n:a if floor((n+2)*phi) - floor((n+1)*phi) == 2 else b return W(f) diff --git a/src/sage/crypto/lwe.py b/src/sage/crypto/lwe.py index b74c2213dd3..8224caf5da7 100644 --- a/src/sage/crypto/lwe.py +++ b/src/sage/crypto/lwe.py @@ -92,7 +92,8 @@ """ from sage.functions.log import log -from sage.functions.other import sqrt, floor, ceil +from sage.functions.other import floor, ceil +from sage.misc.functional import sqrt from sage.misc.functional import cyclotomic_polynomial, round from sage.misc.randstate import set_random_seed from sage.misc.prandom import randint diff --git a/src/sage/functions/error.py b/src/sage/functions/error.py index f74395aaa04..f48d04f1c41 100644 --- a/src/sage/functions/error.py +++ b/src/sage/functions/error.py @@ -44,7 +44,8 @@ from sage.symbolic.function import BuiltinFunction from sage.libs.mpmath import utils as mpmath_utils from sage.symbolic.expression import Expression -from sage.functions.all import sqrt, exp +from sage.functions.all import exp +from sage.misc.functional import sqrt from sage.symbolic.constants import pi from sage.rings.rational import Rational from sage.rings.infinity import unsigned_infinity diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 97070d07d9e..e507844219e 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -165,7 +165,8 @@ from sage.symbolic.constants import pi from sage.symbolic.function import BuiltinFunction from sage.libs.mpmath import utils as mpmath_utils -from sage.functions.all import sqrt, sin, cot, exp +from sage.functions.all import sin, cot, exp +from sage.misc.functional import sqrt from sage.symbolic.constants import I diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py b/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py index f3eab52363b..fac28dfd161 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py @@ -25,7 +25,8 @@ from sage.modules.free_module_element import vector from sage.rings.integer import Integer from sage.rings.infinity import infinity -from sage.functions.other import real, imag, sqrt +from sage.functions.other import real, imag +from sage.misc.functional import sqrt from sage.misc.lazy_import import lazy_import lazy_import('sage.misc.call', 'attrcall') diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py index ccb1fcdd95c..bebe858bd28 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py @@ -93,7 +93,8 @@ from sage.symbolic.constants import pi from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix -from sage.functions.other import real, imag, sqrt +from sage.functions.other import real, imag +from sage.misc.functional import sqrt from sage.functions.trig import arccos from sage.functions.log import exp from sage.functions.hyperbolic import sinh, cosh, arcsinh diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py index 896dc71be58..0af1c29e0c3 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py @@ -51,7 +51,8 @@ from sage.rings.infinity import infinity from sage.misc.latex import latex from sage.rings.real_double import RDF -from sage.functions.other import imag, sqrt +from sage.functions.other import imag +from sage.misc.functional import sqrt from sage.functions.all import arccosh, sign from sage.geometry.hyperbolic_space.hyperbolic_constants import EPSILON diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py index 6a891b88046..7adb33ed6b9 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py @@ -81,7 +81,8 @@ from sage.structure.parent import Parent from sage.misc.bindable_class import BindableClass from sage.misc.lazy_import import lazy_import -from sage.functions.other import imag, real, sqrt +from sage.functions.other import imag, real +from sage.misc.functional import sqrt from sage.functions.all import arccosh from sage.rings.all import CC from sage.rings.real_double import RDF diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index e2e6772defb..c07d3ccfe3f 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -48,7 +48,8 @@ from sage.modules.free_module_element import vector from sage.modules.vector_space_morphism import linear_transformation from sage.matrix.constructor import matrix -from sage.functions.other import sqrt, floor, ceil +from sage.functions.other import floor, ceil +from sage.misc.functional import sqrt from sage.groups.matrix_gps.finitely_generated import MatrixGroup from sage.graphs.graph import Graph from sage.geometry.convex_set import ConvexSet_closed, AffineHullProjectionData diff --git a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py index 566a07c4d33..46fb03a14c4 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py +++ b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py @@ -252,7 +252,8 @@ def _discrete_log_pgroup(self, p, aa, b): (1, 17, 123, 456) """ from sage.arith.misc import valuation - from sage.functions.other import ceil, sqrt + from sage.functions.other import ceil + from sage.misc.functional import sqrt from itertools import product as iproduct vals = [valuation(a.order(), p) for a in aa] diff --git a/src/sage/interfaces/tides.py b/src/sage/interfaces/tides.py index cf7c0f354d5..66e515e874b 100644 --- a/src/sage/interfaces/tides.py +++ b/src/sage/interfaces/tides.py @@ -46,7 +46,8 @@ from sage.ext.fast_callable import fast_callable from sage.rings.semirings.non_negative_integer_semiring import NN from sage.functions.log import log, exp -from sage.functions.other import floor, sqrt, ceil +from sage.functions.other import floor, ceil +from sage.misc.functional import sqrt diff --git a/src/sage/manifolds/utilities.py b/src/sage/manifolds/utilities.py index ae729e33206..7ee44aa9093 100644 --- a/src/sage/manifolds/utilities.py +++ b/src/sage/manifolds/utilities.py @@ -30,7 +30,8 @@ from sage.symbolic.expression_conversions import ExpressionTreeWalker from sage.symbolic.ring import SR from sage.symbolic.constants import pi -from sage.functions.other import sqrt, abs_symbolic +from sage.functions.other import abs_symbolic +from sage.misc.functional import sqrt from sage.functions.trig import cos, sin from sage.rings.all import Rational diff --git a/src/sage/quadratic_forms/quadratic_form__theta.py b/src/sage/quadratic_forms/quadratic_form__theta.py index 8309142f1b5..4915205aa67 100644 --- a/src/sage/quadratic_forms/quadratic_form__theta.py +++ b/src/sage/quadratic_forms/quadratic_form__theta.py @@ -16,7 +16,8 @@ from sage.rings.real_mpfr import RealField from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.integer_ring import ZZ -from sage.functions.all import sqrt, floor, ceil +from sage.functions.all import floor, ceil +from sage.misc.functional import sqrt diff --git a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py index 8a335d4f852..909af780d77 100644 --- a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +++ b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py @@ -1757,7 +1757,8 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, """ from sage.calculus.functions import jacobian from sage.calculus.var import function - from sage.functions.other import factorial, sqrt + from sage.functions.other import factorial + from sage.misc.functional import sqrt from sage.functions.gamma import gamma from sage.functions.log import exp, log from sage.matrix.constructor import matrix @@ -2138,7 +2139,8 @@ def asymptotics_multiple(self, p, alpha, N, asy_var, coordinate=None, from sage.calculus.var import function from sage.combinat.combinat import stirling_number1 from sage.functions.log import exp, log - from sage.functions.other import factorial, sqrt + from sage.functions.other import factorial + from sage.misc.functional import sqrt from sage.matrix.constructor import matrix from sage.misc.mrange import xmrange from sage.modules.free_module_element import vector diff --git a/src/sage/rings/invariants/reconstruction.py b/src/sage/rings/invariants/reconstruction.py index b9db4e07521..f8edfc92d98 100644 --- a/src/sage/rings/invariants/reconstruction.py +++ b/src/sage/rings/invariants/reconstruction.py @@ -262,7 +262,8 @@ def binary_quintic_coefficients_from_invariants(invariants, K=None, invariant_ch N = K(2)**-1 * (A*C-B**2) R2 = -K(2)**-1 * (A*N**2-2*B*M*N+C*M**2) scale = [1,1,1,1,1,1] - from sage.functions.all import binomial, sqrt + from sage.functions.all import binomial + from sage.misc.functional import sqrt if len(invariants) == 3: if R2.is_square(): R = sqrt(R2) From 5952b370f8da06cd4b091ebefd67a0865b84604c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 19 Oct 2021 22:48:39 -0700 Subject: [PATCH 477/511] src/sage/misc/all.py: Add sqrt --- src/sage/misc/all.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/misc/all.py b/src/sage/misc/all.py index 375b8e852f1..defe3663e51 100644 --- a/src/sage/misc/all.py +++ b/src/sage/misc/all.py @@ -142,6 +142,7 @@ quo, isqrt, squarefree_part, + sqrt, symbolic_sum as sum, symbolic_prod as product, transpose) From 905e8001c378ff9001e6730e297759a73aad4e37 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 19 Oct 2021 22:48:48 -0700 Subject: [PATCH 478/511] src/sage/misc/functional.py: Fix imports --- src/sage/misc/functional.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index ec701dade01..59e9d83e460 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -21,6 +21,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** import builtins +import math from sage.rings.complex_double import CDF from sage.rings.real_double import RDF, RealDoubleElement @@ -1722,9 +1723,11 @@ def _do_sqrt(x, prec=None, extend=True, all=False): """ if prec: if x >= 0: - return RealField(prec)(x).sqrt(all=all) + from sage.rings.real_mpfr import RealField + return RealField(prec)(x).sqrt(all=all) else: - return ComplexField(prec)(x).sqrt(all=all) + from sage.rings.complex_mpfr import ComplexField + return ComplexField(prec)(x).sqrt(all=all) if x == -1: from sage.symbolic.expression import I z = I From 451ac273aa6c03f2e54d49e12a4460ff92663b54 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 19 Oct 2021 22:49:03 -0700 Subject: [PATCH 479/511] src/sage/functions/other.py: Remove import from sage.rings.all --- src/sage/functions/other.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index bb7e5d7d7bd..cd2adbb1bfb 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -21,7 +21,11 @@ from sage.symbolic.function import GinacFunction, BuiltinFunction from sage.symbolic.expression import Expression, register_symbol, symbol_table from sage.symbolic.ring import SR -from sage.rings.all import Integer, Rational, RealField, ZZ, ComplexField +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.rational import Rational +from sage.rings.complex_mpfr import ComplexField +from sage.rings.real_mpfr import RealField from sage.misc.latex import latex from sage.structure.element import Element import math From aa557a9eaa8c798d3fc4d3269c32edd68aad6ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 20 Oct 2021 09:20:20 +0200 Subject: [PATCH 480/511] one more fix for italian tutorial --- src/doc/it/tutorial/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/it/tutorial/index.rst b/src/doc/it/tutorial/index.rst index c4c4ade017a..4fb1d04c523 100644 --- a/src/doc/it/tutorial/index.rst +++ b/src/doc/it/tutorial/index.rst @@ -29,4 +29,4 @@ Indici e tabelle * :ref:`genindex` * :ref:`modindex` -* :ref:`cerca` +* :ref:`search` From 19442e760215d508656584685940731491f95590 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Wed, 20 Oct 2021 17:28:29 +0800 Subject: [PATCH 481/511] deduplicate copies of QuaternionAlgebraElement_abstract.pair() --- .../algebras/quatalg/quaternion_algebra.py | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py index 89671f93593..10d4a3166e5 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra.py +++ b/src/sage/algebras/quatalg/quaternion_algebra.py @@ -61,7 +61,11 @@ from operator import itemgetter -from . import quaternion_algebra_element +from .quaternion_algebra_element import \ + QuaternionAlgebraElement_abstract, \ + QuaternionAlgebraElement_generic, \ + QuaternionAlgebraElement_rational_field, \ + QuaternionAlgebraElement_number_field from . import quaternion_algebra_cython from sage.modular.modsym.p1list import P1List @@ -650,7 +654,7 @@ def __init__(self, base_ring, a, b, names='i,j,k'): self._a = a self._b = b if is_RationalField(base_ring) and a.denominator() == 1 and b.denominator() == 1: - self.Element = quaternion_algebra_element.QuaternionAlgebraElement_rational_field + self.Element = QuaternionAlgebraElement_rational_field elif is_NumberField(base_ring) and base_ring.degree() > 2 and base_ring.is_absolute() and \ a.denominator() == 1 and b.denominator() == 1 and base_ring.defining_polynomial().is_monic(): # This QuaternionAlgebraElement_number_field class is not @@ -660,9 +664,9 @@ def __init__(self, base_ring, a, b, names='i,j,k'): # (or more?) speedup. Much care must be taken because the # underlying representation of quadratic fields is a bit # tricky. - self.Element = quaternion_algebra_element.QuaternionAlgebraElement_number_field + self.Element = QuaternionAlgebraElement_number_field else: - self.Element = quaternion_algebra_element.QuaternionAlgebraElement_generic + self.Element = QuaternionAlgebraElement_generic self._populate_coercion_lists_(coerce_list=[base_ring]) self._gens = [self([0,1,0,0]), self([0,0,1,0]), self([0,0,0,1])] @@ -1666,7 +1670,7 @@ def discriminant(self): for d in self.basis(): MM = [] for e in self.basis(): - MM.append((d * e.conjugate()).reduced_trace()) + MM.append(d.pair(e)) L.append(MM) return (MatrixSpace(QQ, 4, 4)(L)).determinant().sqrt() @@ -1767,7 +1771,8 @@ def ternary_quadratic_form(self, include_basis=False): This function computes the positive definition quadratic form obtained by letting G be the trace zero subspace of `\ZZ` + - 2* ``self``, which has rank 3, and restricting the pairing:: + 2* ``self``, which has rank 3, and restricting the pairing + :meth:`QuaternionAlgebraElement_abstract.pair`:: (x,y) = (x.conjugate()*y).reduced_trace() @@ -2336,9 +2341,8 @@ def gram_matrix(self): [ 1920 16320 15360 19200] """ A = self.gens() - B = [z.conjugate() for z in A] two = QQ(2) - m = [two * (a * b).reduced_trace() for b in B for a in A] + m = [two * a.pair(b) for b in A for a in A] M44 = MatrixSpace(QQ, 4, 4) return M44(m, coerce=False) @@ -2811,7 +2815,7 @@ def intersection_of_row_modules_over_ZZ(v): return intersection_of_row_modules_over_ZZ([w] + v[2:]) -def normalize_basis_at_p(e, p, B = lambda x,y: (x*y.conjugate()).reduced_trace()): +def normalize_basis_at_p(e, p, B=QuaternionAlgebraElement_abstract.pair): r""" Compute a (at ``p``) normalized basis from the given basis ``e`` of a `\ZZ`-module. @@ -2835,8 +2839,8 @@ def normalize_basis_at_p(e, p, B = lambda x,y: (x*y.conjugate()).reduced_trace() - ``p`` -- prime for at which the basis should be normalized - - ``B`` -- (default: - ``lambda x,y: ((x*y).conjugate()).reduced_trace()``) + - ``B`` -- + (default: :meth:`QuaternionAlgebraElement_abstract.pair`) a bilinear form with respect to which to normalize OUTPUT: From a650a7da01550aa179490bf2fe5ebb1d806eba75 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 20 Oct 2021 11:20:10 +0100 Subject: [PATCH 482/511] remove more refs to MPIR in deps etc and few in docs too. --- build/pkgs/4ti2/spkg-configure.m4 | 2 +- build/pkgs/gfortran/SPKG.rst | 2 +- build/pkgs/mpc/spkg-install.in | 2 +- build/pkgs/mpir/distros/void.txt | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 build/pkgs/mpir/distros/void.txt diff --git a/build/pkgs/4ti2/spkg-configure.m4 b/build/pkgs/4ti2/spkg-configure.m4 index a16da8fc4b7..5b746aa1211 100644 --- a/build/pkgs/4ti2/spkg-configure.m4 +++ b/build/pkgs/4ti2/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([4ti2], [ - SAGE_SPKG_DEPCHECK([gmp mpir glpk zlib], [ + SAGE_SPKG_DEPCHECK([gmp glpk zlib], [ dnl Debian installs these programs with an executable prefix "4ti2-", dnl OpenSUSE uses the prefix "4ti2_". dnl Singular checks for unprefixed and prefixed with "4ti2-". diff --git a/build/pkgs/gfortran/SPKG.rst b/build/pkgs/gfortran/SPKG.rst index a40a1c4ce58..d66a7b0f173 100644 --- a/build/pkgs/gfortran/SPKG.rst +++ b/build/pkgs/gfortran/SPKG.rst @@ -22,7 +22,7 @@ Dependencies ------------ - zlib -- MPIR +- GMP - MPFR - MPC diff --git a/build/pkgs/mpc/spkg-install.in b/build/pkgs/mpc/spkg-install.in index 1e523e7f6f2..3ee37482fd4 100644 --- a/build/pkgs/mpc/spkg-install.in +++ b/build/pkgs/mpc/spkg-install.in @@ -1,7 +1,7 @@ cd src # Unset CC and CFLAGS. This will make mpc use the same configuration -# as MPIR, which is probably a good thing. +# as GMP, which is probably a good thing. unset CC unset CFLAGS diff --git a/build/pkgs/mpir/distros/void.txt b/build/pkgs/mpir/distros/void.txt deleted file mode 100644 index c490ad530ef..00000000000 --- a/build/pkgs/mpir/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -mpir-devel From 79651e9e07353bcf93c4915af604d17509dd4631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 20 Oct 2021 13:08:24 +0200 Subject: [PATCH 483/511] get rid of [^']+)'>") - -def normalize_type_repr(s): - r""" - Convert the repr of type objects (e.g. ``int``, ``float``) from their - Python 2 representation to their Python 3 representation. - - In Python 2, the repr of built-in types like ``int`` is like - ````, whereas user-defined pure Python classes are displayed - as ````. On Python 3 this was normalized so that - built-in types are represented the same as user-defined classes (e.g. - ````. - - This simply normalizes all class/type reprs to the Python 3 convention for - the sake of output checking. - - EXAMPLES:: - - sage: from sage.doctest.parsing import normalize_type_repr - sage: s = "" - sage: normalize_type_repr(s) - "" - sage: normalize_type_repr(repr(float)) - "" - - This can work on multi-line output as well:: - - sage: s = "The desired output was \n" - sage: s += "The received output was " - sage: print(normalize_type_repr(s)) - The desired output was - The received output was - - And should work when types are embedded in other nested expressions:: - - sage: normalize_type_repr(repr([Integer, float])) - "[, ]" - """ - - def subst(m): - return "".format(m.group('name')) - - return _type_repr_re.sub(subst, s) - - _long_repr_re = re.compile(r'([+-]?[0-9]+)[lL]') def normalize_long_repr(s): """ @@ -284,10 +239,6 @@ def subst(m): _repr_fixups = [ (lambda g, w: 'u"' in w or "u'" in w, lambda g, w: (g, remove_unicode_u(w))), - - (lambda g, w: ' + sage: marked = parse_tolerance("sage: s.update(tol = 0.1); s.rel_tol # abs tol 0.01 ", "") sage: marked.tol 0 @@ -1088,14 +1039,6 @@ def check_output(self, want, got, optionflags): [u'Fermat', u'Euler'] sage: c = u'you'; c u'you' - - Also allowance for the difference in reprs of ``type`` instances (i.e. - classes) between Python 2 and Python 3:: - - sage: int - - sage: float - """ got = self.human_readable_escape_sequences(got) got = glpk_simplex_warning_regex.sub('', got) diff --git a/src/sage/libs/eclib/newforms.pyx b/src/sage/libs/eclib/newforms.pyx index 96263cd0be9..2eebaa7b413 100644 --- a/src/sage/libs/eclib/newforms.pyx +++ b/src/sage/libs/eclib/newforms.pyx @@ -384,7 +384,7 @@ cdef class ECModularSymbol: sage: E = EllipticCurve('11a') sage: M = ECModularSymbol(E) sage: M.__reduce__() - (, + (, (Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field, 1)) """ diff --git a/src/sage/matroids/unpickling.pyx b/src/sage/matroids/unpickling.pyx index 09f781d4a2c..b37ae49a37f 100644 --- a/src/sage/matroids/unpickling.pyx +++ b/src/sage/matroids/unpickling.pyx @@ -316,7 +316,7 @@ def unpickle_plus_minus_one_matrix(version, data): sage: M PlusMinusOneMatrix instance with 2 rows and 2 columns sage: type(M) - + sage: M.__reduce__()[1][1] (2, 2, [1, 0, -1, 1]) """ diff --git a/src/sage/misc/call.py b/src/sage/misc/call.py index ddb05e44819..7b579f45a4d 100644 --- a/src/sage/misc/call.py +++ b/src/sage/misc/call.py @@ -120,7 +120,7 @@ def __hash__(self): sage: hash(x) # random # indirect doctest 210434060 sage: type(hash(x)) - + sage: y = attrcall('core', 3, blah = 1, flatten = True) sage: hash(y) == hash(x) True diff --git a/src/sage/misc/dev_tools.py b/src/sage/misc/dev_tools.py index 4eeccd1de7f..62d49bab39a 100644 --- a/src/sage/misc/dev_tools.py +++ b/src/sage/misc/dev_tools.py @@ -219,7 +219,7 @@ def find_objects_from_name(name, module_name=None): sage: import sage.misc.dev_tools as dt sage: dt.find_objects_from_name('FareySymbol') - [] + [] sage: import sympy sage: dt.find_objects_from_name('RR') diff --git a/src/sage/misc/explain_pickle.py b/src/sage/misc/explain_pickle.py index 448e641191c..bc1cefbd759 100644 --- a/src/sage/misc/explain_pickle.py +++ b/src/sage/misc/explain_pickle.py @@ -408,7 +408,7 @@ def __init__(self, klass): sage: from sage.misc.explain_pickle import * sage: PickleInstance(Integer).klass - + """ self.klass = klass diff --git a/src/sage/misc/fast_methods.pyx b/src/sage/misc/fast_methods.pyx index 1165b7caccc..eb73cb6bc3e 100644 --- a/src/sage/misc/fast_methods.pyx +++ b/src/sage/misc/fast_methods.pyx @@ -105,7 +105,7 @@ cdef class WithEqualityById: """ def __hash__(self): """ - The hash provided by this class coincides with that of ````. + The hash provided by this class coincides with that of ````. TESTS:: diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index 45d74ea749a..8eba015bc73 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -178,9 +178,9 @@ def coerce(P, x): EXAMPLES:: sage: type(5) - + sage: type(coerce(QQ,5)) - + """ try: return P._coerce_(x) @@ -1390,7 +1390,7 @@ def numerical_approx(x, prec=None, digits=None, algorithm=None): 1.41421356237309*I sage: type(numerical_approx(CC(1/2))) - + The following tests :trac:`10761`, in which ``n()`` would break when called on complex-valued algebraic numbers. :: @@ -1536,11 +1536,11 @@ def round(x, ndigits=0): sage: q = round(sqrt(2),5); q 1.41421 sage: type(q) - + sage: q = round(sqrt(2)); q 1 sage: type(q) - + sage: round(pi) 3 sage: b = 5.4999999999999999 @@ -1550,7 +1550,7 @@ def round(x, ndigits=0): This example addresses :trac:`23502`:: sage: n = round(6); type(n) - + Since we use floating-point with a limited range, some roundings can't be performed:: diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 56a47ea4513..b7dbccdbcd8 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -553,7 +553,7 @@ def has_latex_attr(x) -> bool: but calling it is broken:: sage: T = type(identity_matrix(3)); T - + sage: hasattr(T, '_latex_') True sage: T._latex_() diff --git a/src/sage/misc/lazy_attribute.pyx b/src/sage/misc/lazy_attribute.pyx index 9cee5d3c4b4..a2edb96af1a 100644 --- a/src/sage/misc/lazy_attribute.pyx +++ b/src/sage/misc/lazy_attribute.pyx @@ -454,7 +454,7 @@ class lazy_attribute(_lazy_attribute): sage: cython('\n'.join(cython_code)) sage: P = MyParent(category=Rings()) sage: P.element_class # indirect doctest - + .. rubric:: About descriptor specifications diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 4d4ee94bbe9..fcc4291ebc3 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -11,7 +11,7 @@ EXAMPLES:: sage: lazy_import('sage.rings.all', 'ZZ') sage: type(ZZ) - + sage: ZZ(4.0) 4 @@ -468,7 +468,7 @@ cdef class LazyImport(object): sage: lazy_import('sys', 'version_info') sage: type(version_info) - + sage: len(version_info) 5 """ @@ -519,7 +519,7 @@ cdef class LazyImport(object): sage: class Bar(Foo): ....: pass sage: type(Foo.__dict__['plot']) - + We access the ``plot`` method:: @@ -978,7 +978,7 @@ def lazy_import(module, names, as_=None, *, sage: lazy_import('sage.rings.all', 'ZZ') sage: type(ZZ) - + sage: ZZ(4.0) 4 sage: lazy_import('sage.rings.all', 'RDF', 'my_RDF') @@ -1011,7 +1011,7 @@ def lazy_import(module, names, as_=None, *, sage: class Bar(Foo): ....: pass sage: type(Foo.__dict__['plot']) - + sage: 'EXAMPLES' in Bar.plot.__doc__ True sage: type(Foo.__dict__['plot']) diff --git a/src/sage/misc/persist.pyx b/src/sage/misc/persist.pyx index 84db8111e27..e19dba5db83 100644 --- a/src/sage/misc/persist.pyx +++ b/src/sage/misc/persist.pyx @@ -531,19 +531,19 @@ def unpickle_global(module, name): sage: from sage.misc.persist import unpickle_override, register_unpickle_override sage: unpickle_global('sage.rings.integer', 'Integer') - + Now we horribly break the pickling system:: sage: register_unpickle_override('sage.rings.integer', 'Integer', Rational, call_name=('sage.rings.rational', 'Rational')) sage: unpickle_global('sage.rings.integer', 'Integer') - + and we reach into the internals and put it back:: sage: del unpickle_override[('sage.rings.integer', 'Integer')] sage: unpickle_global('sage.rings.integer', 'Integer') - + A meaningful error message with resolution instructions is displayed for old pickles that accidentally got broken because a class or entire module diff --git a/src/sage/misc/sage_eval.py b/src/sage/misc/sage_eval.py index 029ed54df20..f65e90fce1a 100644 --- a/src/sage/misc/sage_eval.py +++ b/src/sage/misc/sage_eval.py @@ -216,14 +216,14 @@ def sageobj(x, vars=None): EXAMPLES:: sage: type(sageobj(gp('34/56'))) - + sage: n = 5/2 sage: sageobj(n) is n True sage: k = sageobj('Z(8^3/1)', {'Z':ZZ}); k 512 sage: type(k) - + This illustrates interfaces:: @@ -233,12 +233,12 @@ def sageobj(x, vars=None): sage: f._sage_() 2/3 sage: type(f._sage_()) - + sage: a = gap(939393/2433) sage: a._sage_() 313131/811 sage: type(a._sage_()) - + """ try: return x._sage_() diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 2ff2762f156..537c763206d 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -529,7 +529,7 @@ def visit_NameConstant(self, node): sage: [vis(n) for n in ['True', 'False', 'None']] # py3 [True, False, None] sage: [type(vis(n)) for n in ['True', 'False', 'None']] # py3 - [, , ] + [, , ] """ return node.value diff --git a/src/sage/modular/arithgroup/farey_symbol.pyx b/src/sage/modular/arithgroup/farey_symbol.pyx index 384dd3400b5..83689f81bc5 100644 --- a/src/sage/modular/arithgroup/farey_symbol.pyx +++ b/src/sage/modular/arithgroup/farey_symbol.pyx @@ -571,7 +571,7 @@ cdef class Farey: Serialization for pickling:: sage: FareySymbol(Gamma0(4)).__reduce__() - (, ...)) + (, ...)) """ return Farey, (self.group, self.this_ptr.dumps()) diff --git a/src/sage/modular/pollack_stevens/dist.pyx b/src/sage/modular/pollack_stevens/dist.pyx index 65942454937..bf11fd0c6b0 100644 --- a/src/sage/modular/pollack_stevens/dist.pyx +++ b/src/sage/modular/pollack_stevens/dist.pyx @@ -815,7 +815,7 @@ cdef class Dist_vector(Dist): sage: D = sage.modular.pollack_stevens.distributions.Symk(2) sage: x = D([2,3,4]) sage: x.__reduce__() - (, ((2, 3, 4), Sym^2 Q^2, 0, False)) + (, ((2, 3, 4), Sym^2 Q^2, 0, False)) """ return (self.__class__, (self._moments, self.parent(), self.ordp, False)) diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index 5a0c9265d34..28e359dbf00 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -730,7 +730,7 @@ def split(self): ....: E((-2)^x) ....: except PartialConversionValueError as e: ....: e.element.split() - (2^x, element with parameter -1 () in Growth Group ZZ^x) + (2^x, element with parameter -1 () in Growth Group ZZ^x) TESTS:: diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index 5fc4a0e6d4d..32f418a12f6 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -82,7 +82,7 @@ cdef class FiniteField(Field): def __hash__(self): """ - The hash provided by this class coincides with that of ````. + The hash provided by this class coincides with that of ````. TESTS:: diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index bba2fc46afc..e88865f2ec9 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -425,7 +425,7 @@ cdef class NumberFieldElement(FieldElement): sage: k. = NumberField(x^3 - 17*x^2 + 1) sage: t = a.__reduce__(); t - (, + (, (Number Field in a with defining polynomial x^3 - 17*x^2 + 1, x)) sage: t[0](*t[1]) == a True diff --git a/src/sage/rings/polynomial/complex_roots.py b/src/sage/rings/polynomial/complex_roots.py index bb28bb1ee59..cf63cba4bce 100644 --- a/src/sage/rings/polynomial/complex_roots.py +++ b/src/sage/rings/polynomial/complex_roots.py @@ -228,7 +228,7 @@ def complex_roots(p, skip_squarefree=False, retval='interval', min_prec=0): ....: if tiny(x.imag()): return x.real() ....: if tiny(x.real()): return CIF(0, x.imag()) sage: rts = complex_roots(p); type(rts[0][0]), sorted(map(smash, rts)) - (, [-1.618033988749895?, -0.618033988749895?*I, 1.618033988749895?*I, 0.618033988749895?]) + (, [-1.618033988749895?, -0.618033988749895?*I, 1.618033988749895?*I, 0.618033988749895?]) sage: rts = complex_roots(p, retval='algebraic'); type(rts[0][0]), sorted(map(smash, rts)) (, [-1.618033988749895?, -0.618033988749895?*I, 1.618033988749895?*I, 0.618033988749895?]) sage: rts = complex_roots(p, retval='algebraic_real'); type(rts[0][0]), rts diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pyx b/src/sage/rings/polynomial/polynomial_rational_flint.pyx index 7c71af6fb75..25d70431aa9 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pyx @@ -308,7 +308,7 @@ cdef class Polynomial_rational_flint(Polynomial): sage: R. = QQ[] sage: f = 2/3 * t^2 + 1 sage: r = f.__reduce__(); r - (, (Univariate Polynomial Ring in t over Rational Field, [1, 0, 2/3], False, False)) + (, (Univariate Polynomial Ring in t over Rational Field, [1, 0, 2/3], False, False)) sage: r[0](*r[1]) 2/3*t^2 + 1 sage: loads(dumps(f)) == f diff --git a/src/sage/rings/ring_extension.pyx b/src/sage/rings/ring_extension.pyx index 640971fb47e..e6708a2f81f 100644 --- a/src/sage/rings/ring_extension.pyx +++ b/src/sage/rings/ring_extension.pyx @@ -378,7 +378,7 @@ class RingExtensionFactory(UniqueFactory): From: Integer Ring To: Rational Field Defn: 1 |--> 1, (), ()), - {'constructors': [(, + {'constructors': [(, {'is_backend_exposed': True, 'print_options': {'print_elements_as': None, 'print_parent_as': None}})]}) @@ -387,7 +387,7 @@ class RingExtensionFactory(UniqueFactory): From: Finite Field in z2 of size 5^2 To: Finite Field in z4 of size 5^4 Defn: z2 |--> z4^3 + z4^2 + z4 + 3, (z4,), ('a',)), - {'constructors': [(, + {'constructors': [(, {'gen': z4, 'is_backend_exposed': True, 'names': ('a',)})]}) """ use_generic_constructor = True diff --git a/src/sage/rings/semirings/tropical_semiring.pyx b/src/sage/rings/semirings/tropical_semiring.pyx index 8466b9c47b0..5ae1ea93bf7 100644 --- a/src/sage/rings/semirings/tropical_semiring.pyx +++ b/src/sage/rings/semirings/tropical_semiring.pyx @@ -72,7 +72,7 @@ cdef class TropicalSemiringElement(Element): sage: T = TropicalSemiring(QQ) sage: elt = T(2) sage: elt.__reduce__() - (, + (, (Tropical semiring over Rational Field, 2)) """ return (TropicalSemiringElement, (self.parent(), self._val)) diff --git a/src/sage/structure/list_clone.pyx b/src/sage/structure/list_clone.pyx index c3761beddbf..caa0cc58258 100644 --- a/src/sage/structure/list_clone.pyx +++ b/src/sage/structure/list_clone.pyx @@ -935,7 +935,7 @@ cdef class ClonableArray(ClonableElement): [1, 2, 4] sage: t = el.__reduce__(); t (, - (, + (, , [1, 2, 4], True, @@ -1721,7 +1721,7 @@ cdef class ClonableIntArray(ClonableElement): [1, 2, 4] sage: t = el.__reduce__(); t (, - (, + (, , [1, 2, 4], True, diff --git a/src/sage/symbolic/pynac_constant_impl.pxi b/src/sage/symbolic/pynac_constant_impl.pxi index 20a407c2241..9dd5366dcaa 100644 --- a/src/sage/symbolic/pynac_constant_impl.pxi +++ b/src/sage/symbolic/pynac_constant_impl.pxi @@ -120,7 +120,7 @@ cdef class PynacConstant: sage: f + 2 Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for +: '' and 'Integer Ring' + TypeError: unsupported operand parent(s) for +: '' and 'Integer Ring' sage: foo = f.expression(); foo foo From 2f0c8282bee61453e962f57cdc2a16be746ba097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 20 Oct 2021 13:39:32 +0200 Subject: [PATCH 484/511] describe known bugs in derivative of piecewise --- src/sage/functions/piecewise.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index 4ac28309a5d..540162de07f 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -296,6 +296,15 @@ def _tderivative_(self, parameters, variable, *args, **kwds): sage: f.diff(x,x) piecewise(x|-->2 on (-1, 1), x|-->6*x on (1, 3); x) + This still fails miserably:: + + sage: y = SR.var('y') + sage: f = piecewise([ [(-6,0), x+y], [(0,8), x*y]],var=x) + sage: f.derivative(x) # known bug + piecewise(x|-->1 on (-6, 0), x|-->y on (0, 8); x) + sage: f.derivative(y) # known bug + piecewise(x|-->1 on (-6, 0), x|-->x on (0, 8); x) + TESTS:: sage: f = piecewise([((-oo, -1),0), ((-1, 1),exp(-1/(1 - x^2))), ((1, oo),0)]) From f004d4d69923cb7277799addbb0aa6cdb3ef8960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 20 Oct 2021 16:30:10 +0200 Subject: [PATCH 485/511] work done on annotations in combinat --- .../quiver_mutation_type.py | 10 ++-- src/sage/combinat/combinat.py | 17 ++++--- src/sage/combinat/composition.py | 6 +-- src/sage/combinat/dyck_word.py | 51 +++++++++---------- src/sage/combinat/gelfand_tsetlin_patterns.py | 5 +- src/sage/combinat/growth.py | 22 ++++---- src/sage/combinat/interval_posets.py | 24 ++++----- src/sage/combinat/partition_tuple.py | 2 +- src/sage/combinat/permutation.py | 10 ++-- src/sage/combinat/plane_partition.py | 4 +- src/sage/combinat/posets/hasse_diagram.py | 10 ++-- src/sage/combinat/superpartition.py | 18 ++++--- src/sage/combinat/tamari_lattices.py | 8 +-- 13 files changed, 95 insertions(+), 92 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py index f697451a99c..6da5e19b8d8 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py @@ -2089,7 +2089,7 @@ def class_size(self): multiplicities[i]) for i in range(len(sizes))) - def dual(self) -> QuiverMutationType: + def dual(self): """ Return the QuiverMutationType which is dual to ``self``. @@ -2104,7 +2104,7 @@ def dual(self) -> QuiverMutationType: return QuiverMutationType([comp.dual() for comp in comps]) -def _construct_classical_mutation_classes(n) -> dict: +def _construct_classical_mutation_classes(n) -> dict[tuple, list | set]: r""" Return a dict with keys being tuples representing regular QuiverMutationTypes of the given rank, and with values being lists @@ -2123,7 +2123,7 @@ def _construct_classical_mutation_classes(n) -> dict: ('AO', (((0, 1), (4, -1)),))] """ from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver - data = {} + data: dict[tuple, set | list] = {} # finite A data[('A', n)] = ClusterQuiver(['A', n]).mutation_class(data_type='dig6') @@ -2161,7 +2161,7 @@ def _construct_classical_mutation_classes(n) -> dict: return data -def _construct_exceptional_mutation_classes(n) -> dict: +def _construct_exceptional_mutation_classes(n) -> dict[tuple, list | set]: r""" Return a dict with keys being tuples representing exceptional QuiverMutationTypes of the given rank, and with values being lists @@ -2185,7 +2185,7 @@ def _construct_exceptional_mutation_classes(n) -> dict: ('BP_', (((0, 1), (2, -2)), ((1, 2), (1, -3)), ((2, 0), (3, -1))))] """ from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver - data = {} + data: dict[tuple, list | set] = {} # finite E if n in [6, 7, 8]: data[('E', n)] = ClusterQuiver(['E', n]).mutation_class(data_type='dig6') diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index d366cc15930..67a2a82bd88 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -148,6 +148,7 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from __future__ import annotations from typing import Iterator from sage.rings.all import ZZ, QQ, Integer, infinity @@ -552,7 +553,7 @@ def euler_number(n, algorithm='flint') -> Integer: if n < 0: raise ValueError("n (=%s) must be a nonnegative integer" % n) if algorithm == 'maxima': - return ZZ(maxima.euler(n)) + return ZZ(maxima.euler(n)) # type:ignore elif algorithm == 'flint': import sage.libs.flint.arith return sage.libs.flint.arith.euler_number(n) @@ -990,7 +991,7 @@ def stirling_number2(n, k, algorithm=None) -> Integer: from sage.libs.gap.libgap import libgap return libgap.Stirling2(n, k).sage() elif algorithm == 'maxima': - return ZZ(maxima.stirling2(n, k)) + return ZZ(maxima.stirling2(n, k)) # type:ignore else: raise ValueError("unknown algorithm: %s" % algorithm) @@ -1691,7 +1692,7 @@ def __hash__(self): """ return hash(repr(self)) - def __cardinality_from_iterator(self) -> Integer: + def __cardinality_from_iterator(self) -> Integer | infinity: """ Default implementation of cardinality which just goes through the iterator of the combinatorial class to count the number of objects. @@ -1709,6 +1710,7 @@ def __cardinality_from_iterator(self) -> Integer: for _ in self: c += one return c + cardinality = __cardinality_from_iterator # __call__, element_class, and _element_constructor_ are poor @@ -2256,7 +2258,7 @@ def __contains__(self, x) -> bool: """ return x in self.left_cc or x in self.right_cc - def cardinality(self) -> Integer: + def cardinality(self) -> Integer | infinity: """ EXAMPLES:: @@ -2443,7 +2445,7 @@ def __repr__(self) -> str: else: return "Image of %s by %s" % (self.cc, self.f) - def cardinality(self) -> Integer: + def cardinality(self) -> Integer | infinity: """ Return the cardinality of this combinatorial class @@ -2452,7 +2454,6 @@ def cardinality(self) -> Integer: sage: R = Permutations(10).map(attrcall('reduced_word')) sage: R.cardinality() 3628800 - """ return self.cc.cardinality() @@ -2494,7 +2495,7 @@ class InfiniteAbstractCombinatorialClass(CombinatorialClass): self._infinite_cclass_slice is supposed to accept any integer as an argument and return something which is iterable. """ - def cardinality(self): + def cardinality(self) -> Integer | infinity: """ Count the elements of the combinatorial class. @@ -2945,7 +2946,7 @@ def bell_polynomial(n: Integer, k: Integer): R = PolynomialRing(ZZ, 'x', n - k + 1) vars = R.gens() result = R.zero() - for p in Partitions(n, length=k): + for p in Partitions(n, length=k): # type:ignore factorial_product = 1 power_factorial_product = 1 for part, count in p.to_exp_dict().items(): diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 930ae037346..5f899c71106 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -617,7 +617,7 @@ def join(self, other, check=True) -> Composition: if check and (sum(self) != sum(other)): raise ValueError("{} is not the same size as {}".format(self, other)) - factors = [] + factors: list[int] = [] I_iter = iter(self) i = 0 @@ -893,7 +893,7 @@ def fatter(self): """ return Compositions(len(self)).map(self.fatten) - def refinement_splitting(self, J) -> Composition: + def refinement_splitting(self, J) -> list[Composition]: r""" Return the refinement splitting of ``self`` according to ``J``. @@ -1797,7 +1797,7 @@ def from_code(self, code) -> Composition: [3, 1, 2, 3, 5] """ if code == [0]: - return [] + return self.element_class(self, []) L = [x for x in range(len(code)) if code[x] == 1] # the positions of the letter 1 c = [L[i] - L[i - 1] for i in range(1, len(L))] + [len(code) - L[-1]] diff --git a/src/sage/combinat/dyck_word.py b/src/sage/combinat/dyck_word.py index 4eb3cebf1b4..a3c80c12115 100644 --- a/src/sage/combinat/dyck_word.py +++ b/src/sage/combinat/dyck_word.py @@ -78,7 +78,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from __future__ import annotations -from typing import Union from .combinat import CombinatorialElement, catalan_number from sage.combinat.combinatorial_map import combinatorial_map @@ -1071,7 +1070,7 @@ def heights(self) -> tuple: heights[i + 1] = height return tuple(heights) - def associated_parenthesis(self, pos) -> Union[int, None]: + def associated_parenthesis(self, pos) -> int | None: r""" Report the position for the parenthesis in ``self`` that matches the one at position ``pos``. @@ -1177,12 +1176,12 @@ def ascent_prime_decomposition(self) -> list: break j += 1 else: - result.extend([DyckWord([open_symbol] * up), - DyckWord(self[i:j])]) + result.extend([DyckWord([open_symbol] * up), # type: ignore + DyckWord(self[i:j])]) # type: ignore i = j up = 0 - result.append(DyckWord([open_symbol] * up)) + result.append(DyckWord([open_symbol] * up)) # type:ignore return result def catalan_factorization(self) -> list: @@ -1219,7 +1218,7 @@ def catalan_factorization(self) -> list: result = [] while i <= n: if H[j] == h or j == i: - result.append(DyckWord(self[i:j])) + result.append(DyckWord(self[i:j])) # type:ignore h += 1 i = j + 1 j = n @@ -1959,7 +1958,7 @@ def reading_permutation(self) -> Permutation: """ alist = self.to_area_sequence() if not alist: - return Permutation([]) + return Permutation([]) # type: ignore m = max(alist) p1 = Word([m - alist[-i - 1] for i in range(len(alist))]).standard_permutation() @@ -2028,13 +2027,13 @@ def to_pair_of_standard_tableaux(self) -> tuple: from sage.combinat.tableau import Tableau n = self.semilength() if n == 0: - return (Tableau([]), Tableau([])) + return (Tableau([]), Tableau([])) # type: ignore elif self.height() == n: - T = Tableau([list(range(1, n + 1))]) + T = Tableau([list(range(1, n + 1))]) # type: ignore return (T, T) else: - left = [[], []] - right = [[], []] + left: list[list[int]] = [[], []] + right:list[list[int]] = [[], []] for pos in range(n): if self[pos] == open_symbol: left[0].append(pos + 1) @@ -2044,7 +2043,7 @@ def to_pair_of_standard_tableaux(self) -> tuple: right[0].append(pos + 1) else: right[1].append(pos + 1) - return (Tableau(left), Tableau(right)) + return (Tableau(left), Tableau(right)) # type: ignore @combinatorial_map(name='to 312 avoiding permutation') def to_312_avoiding_permutation(self) -> Permutation: @@ -2117,7 +2116,7 @@ def to_noncrossing_permutation(self) -> Permutation: """ n = self.semilength() if n == 0: - return Permutation([]) + return Permutation([]) # type: ignore D, touch_sequence = pealing(self, return_touches=True) pi = list(range(1, n + 1)) while touch_sequence: @@ -2218,7 +2217,7 @@ def to_132_avoiding_permutation(self) -> Permutation: v = min(v for v in values if v > n - i - area[n - i - 1]) pi.append(v) values.remove(v) - return Permutation(pi) + return Permutation(pi) # type: ignore def to_permutation(self, map) -> Permutation: r""" @@ -2394,7 +2393,7 @@ def to_Catalan_code(self) -> list: cut = self.associated_parenthesis(0) if cut is None: raise ValueError('not valid for incomplete Dyck words') - recdw = DyckWord(self[1:cut] + self[cut + 1:]) + recdw = DyckWord(self[1:cut] + self[cut + 1:]) # type:ignore returns = [0] + recdw.returns_to_zero() res = recdw.to_Catalan_code() res.append(returns.index(cut - 1)) @@ -2715,7 +2714,7 @@ def reverse(self) -> DyckWord: else: list.append(open_symbol) list.reverse() - return DyckWord(list) + return DyckWord(list) # type:ignore def first_return_decomposition(self) -> tuple: r""" @@ -2733,7 +2732,7 @@ def first_return_decomposition(self) -> tuple: ([], [1, 0]) """ k = self.position_of_first_return() * 2 - return DyckWord(self[1:k - 1]), DyckWord(self[k:]) + return DyckWord(self[1:k - 1]), DyckWord(self[k:]) # type:ignore def decomposition_reverse(self) -> DyckWord: r""" @@ -2756,10 +2755,10 @@ def decomposition_reverse(self) -> DyckWord: """ if not self: return self - else: - D1, D2 = self.first_return_decomposition() - return DyckWord([1] + list(D2.decomposition_reverse()) - + [0] + list(D1.decomposition_reverse())) + D1, D2 = self.first_return_decomposition() + D = [1] + list(D2.decomposition_reverse()) + D += [0] + list(D1.decomposition_reverse()) + return DyckWord(D) # type:ignore @combinatorial_map(name="Area-dinv to bounce-area") def area_dinv_to_bounce_area_map(self) -> DyckWord: @@ -2805,7 +2804,7 @@ def area_dinv_to_bounce_area_map(self) -> DyckWord: image.append(1) elif j == i + 1: image.append(0) - return DyckWord(image) + return DyckWord(image) # type:ignore @combinatorial_map(name="Bounce-area to area-dinv") def bounce_area_to_area_dinv_map(self) -> DyckWord: @@ -2846,13 +2845,13 @@ def bounce_area_to_area_dinv_map(self) -> DyckWord: [1, 1, 0, 0] """ aseq = self.to_area_sequence() - out = [] - zeros = [] + out: list[int] = [] + zeros: list[int] = [] for i in range(len(aseq)): p = (zeros + [len(out)])[aseq[i]] out = [1] + out[p:] + [0] + out[:p] zeros = [0] + [j + len(out) - p for j in zeros[:aseq[i]]] - return DyckWord(out) + return DyckWord(out) # type:ignore def area(self) -> int: r""" @@ -2964,7 +2963,7 @@ def bounce_path(self) -> DyckWord: i -= 1 area_seq[i] = area_seq[i + 1] - 1 i -= 1 - return DyckWord(area_sequence=area_seq) + return DyckWord(area_sequence=area_seq) # type:ignore def bounce(self) -> int: r""" diff --git a/src/sage/combinat/gelfand_tsetlin_patterns.py b/src/sage/combinat/gelfand_tsetlin_patterns.py index 1ab6ef536fa..ff5a145cd92 100644 --- a/src/sage/combinat/gelfand_tsetlin_patterns.py +++ b/src/sage/combinat/gelfand_tsetlin_patterns.py @@ -1415,6 +1415,5 @@ def random_element(self) -> GelfandTsetlinPattern: """ if self._strict: return self._cftp(1) - else: - l = [i for i in self._row if i > 0] - return SemistandardTableaux(l, max_entry=self._n).random_element().to_Gelfand_Tsetlin_pattern() + l = [i for i in self._row if i > 0] + return SemistandardTableaux(l, max_entry=self._n).random_element().to_Gelfand_Tsetlin_pattern() # type:ignore diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index c92608b002c..47abe8d9c93 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -470,7 +470,7 @@ # # https://www.gnu.org/licenses/ # *************************************************************************** - +from __future__ import annotations from copy import copy from itertools import zip_longest @@ -489,6 +489,7 @@ from sage.combinat.shifted_primed_tableau import ShiftedPrimedTableau from sage.graphs.digraph import DiGraph + def _make_partition(l): """ Return the list as a partition. @@ -506,6 +507,7 @@ def _make_partition(l): """ return _Partitions.element_class(_Partitions, l) + class GrowthDiagram(SageObject): r""" A generalized Schensted growth diagram in the sense of Fomin. @@ -1226,7 +1228,7 @@ def _shape_from_labels(self, labels): is_P_edge = getattr(rule, "is_P_edge", None) is_Q_edge = getattr(rule, "is_Q_edge", None) if rule.has_multiple_edges: - def right_left(la, mu, e): + def right_left_multi(la, mu, e) -> int: if rule.rank(la) < rule.rank(mu): if is_Q_edge is not None and e not in is_Q_edge(la, mu): raise ValueError("%s has smaller rank than %s but there is no edge of color %s in Q" % (la, mu, e)) @@ -1235,13 +1237,12 @@ def right_left(la, mu, e): if is_P_edge is not None and e not in is_P_edge(mu, la): raise ValueError("%s has smaller rank than %s but there is no edge of color %s in P" % (mu, la, e)) return 0 - else: - raise ValueError("can only determine the shape of the growth" - " diagram if ranks of successive labels differ") - return _Partitions.from_zero_one([right_left(labels[i], labels[i+2], labels[i+1]) + raise ValueError("can only determine the shape of the growth" + " diagram if ranks of successive labels differ") + return _Partitions.from_zero_one([right_left_multi(labels[i], labels[i+2], labels[i+1]) for i in range(0, len(labels)-2, 2)]) else: - def right_left(la, mu): + def right_left(la, mu) -> int: if rule.rank(la) < rule.rank(mu): if is_Q_edge is not None and not is_Q_edge(la, mu): raise ValueError("%s has smaller rank than %s but is not covered by it in Q" % (la, mu)) @@ -1250,9 +1251,8 @@ def right_left(la, mu): if is_P_edge is not None and not is_P_edge(mu, la): raise ValueError("%s has smaller rank than %s but is not covered by it in P" % (mu, la)) return 0 - else: - raise ValueError("can only determine the shape of the growth" - " diagram if ranks of successive labels differ") + raise ValueError("can only determine the shape of the growth" + " diagram if ranks of successive labels differ") return _Partitions.from_zero_one([right_left(labels[i], labels[i+1]) for i in range(len(labels)-1)]) @@ -2963,7 +2963,7 @@ class RuleSylvester(Rule): sage: list(Sylvester(labels=G.out_labels())) == list(G) True """ - zero = BinaryTree() + zero = BinaryTree() # type: ignore def normalize_vertex(self, v): r""" diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index ed2de3bd9ce..48fbe140f11 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -537,7 +537,7 @@ def draw_decreasing(i, j) -> str: return start + nodes + relations + end - def poset(self) -> Poset: + def poset(self): r""" Return ``self`` as a labelled poset. @@ -594,7 +594,7 @@ def _mul_(self, other: TIP) -> TIP: relations.extend([(i + n, j + n) for i, j in other._poset.cover_relations_iterator()]) P = FinitePoset(DiGraph([list(range(1, n + m + 1)), relations], - format='vertices_and_edges')) + format='vertices_and_edges')) # type:ignore return TamariIntervalPoset(P, check=False) # type:ignore def __hash__(self): @@ -1057,7 +1057,7 @@ def complement(self) -> TIP: new_covers = [[N - i, N - j] for i, j in self._poset.cover_relations_iterator()] P = FinitePoset(DiGraph([list(range(1, N)), new_covers], - format='vertices_and_edges')) + format='vertices_and_edges')) # type:ignore return TamariIntervalPoset(P, check=False) # type:ignore def left_branch_involution(self) -> TIP: @@ -1709,7 +1709,7 @@ def initial_forest(self) -> TIP: """ relations = self.increasing_cover_relations() P = FinitePoset(DiGraph([list(range(1, self._size + 1)), relations], - format='vertices_and_edges')) + format='vertices_and_edges')) # type:ignore return TamariIntervalPoset(P, check=False) # type:ignore def final_forest(self) -> TIP: @@ -1729,7 +1729,7 @@ def final_forest(self) -> TIP: """ relations = self.decreasing_cover_relations() P = FinitePoset(DiGraph([list(range(1, self._size + 1)), relations], - format='vertices_and_edges')) + format='vertices_and_edges')) # type:ignore return TamariIntervalPoset(P, check=False) # type:ignore def is_initial_interval(self) -> bool: @@ -1979,7 +1979,7 @@ def add(perm: list, i): perm: list[int] = [] for i in sorted(final_forest.sinks()): add(perm, i) - return Permutation(perm) + return Permutation(perm) # type:ignore def max_linear_extension(self) -> Permutation: r""" @@ -2029,7 +2029,7 @@ def add(perm: list, i): perm: list[int] = [] for i in sorted(initial_forest.sinks(), reverse=True): add(perm, i) - return Permutation(perm) + return Permutation(perm) # type:ignore def linear_extensions(self) -> Iterator: r""" @@ -2051,7 +2051,7 @@ def linear_extensions(self) -> Iterator: [[4, 1, 2, 3], [1, 2, 4, 3], [1, 4, 2, 3]] """ for ext in self._poset.linear_extensions(): - yield Permutation(ext) + yield Permutation(ext) # type:ignore def lower_contained_intervals(self) -> Iterator: r""" @@ -3045,7 +3045,7 @@ def get_relations(bt, start=1): roots, relations, index = get_relations(binary_tree) P = FinitePoset(DiGraph([list(range(1, index)), relations], - format='vertices_and_edges')) + format='vertices_and_edges')) # type:ignore return TamariIntervalPoset(P, check=False) # type:ignore @staticmethod @@ -3153,7 +3153,7 @@ def get_relations(bt, start=1): roots, relations, index = get_relations(binary_tree) P = FinitePoset(DiGraph([list(range(1, index)), relations], - format='vertices_and_edges')) + format='vertices_and_edges')) # type:ignore return TamariIntervalPoset(P, check=False) # type:ignore @staticmethod @@ -3470,8 +3470,8 @@ def profil(gr, vertex): if u[2] == color_b]) dyckword_top += [1] + [0] * indegree1 - dyckword_bottom = DyckWord(dyckword_bottom) - dyckword_top = DyckWord(dyckword_top) + dyckword_bottom = DyckWord(dyckword_bottom) # type:ignore + dyckword_top = DyckWord(dyckword_top) # type:ignore TIP = TamariIntervalPosets(len(dyckword_bottom) // 2) return TIP.from_dyck_words(dyckword_bottom, dyckword_top) diff --git a/src/sage/combinat/partition_tuple.py b/src/sage/combinat/partition_tuple.py index 34b5a9e46ff..825344b9e03 100644 --- a/src/sage/combinat/partition_tuple.py +++ b/src/sage/combinat/partition_tuple.py @@ -613,7 +613,7 @@ def _repr_compact_high(self): return '%s' % '|'.join(mu._repr_compact_high() for mu in self) # override default string representation which is str(self._list) - __str__ = lambda self: self._repr_() + __str__ = lambda self: self._repr_() # type: ignore def _latex_(self): r""" diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 72947e020a1..4b39eda2e2f 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -1629,8 +1629,8 @@ def stack_sort(self) -> Permutation: sage: p.stack_sort() [1] """ - stack = [] - sorted_p = [] + stack: list[int] = [] + sorted_p: list[int] = [] for j in self: if stack: for i in reversed(stack): @@ -1641,7 +1641,7 @@ def stack_sort(self) -> Permutation: break stack.append(j) sorted_p.extend(reversed(stack)) - return Permutation(sorted_p) + return Permutation(sorted_p) # type: ignore def to_digraph(self) -> DiGraph: r""" @@ -2192,7 +2192,7 @@ def longest_increasing_subsequence_length(self) -> Integer: sage: Permutation([]).longest_increasing_subsequence_length() 0 """ - r = [] + r: list[int] = [] for x in self: if max(r+[0]) > x: y = min(z for z in r if z > x) @@ -2380,7 +2380,7 @@ def foata_bijection(self) -> Permutation: sage: Permutation([1]).foata_bijection() [1] """ - M = [] + M: list[int] = [] for e in self: k = len(M) if k <= 1: diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 857924a64a5..e65625f6465 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -847,8 +847,8 @@ def __iter__(self) -> Iterator[PP]: A = self._box[0] B = self._box[1] C = self._box[2] - from sage.combinat.tableau import SemistandardTableaux - for T in SemistandardTableaux([B for i in range(A)], max_entry=C + A): + from sage.combinat.tableau import SemistandardTableaux as SST + for T in SST([B for i in range(A)], max_entry=C + A): # type:ignore PP = [[0 for _ in range(B)] for _ in range(A)] for r in range(A): for c in range(B): diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index 9d0a62a1f5a..93d254b245c 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -15,6 +15,8 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from __future__ import annotations + from sage.graphs.digraph import DiGraph from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ @@ -1852,7 +1854,7 @@ def vertical_decomposition(self, return_list=False): result.pop() # Remove the top element. return result - def is_complemented(self) -> bool: + def is_complemented(self) -> int | None: """ Return an element of the lattice that has no complement. @@ -3420,18 +3422,18 @@ def is_congruence_normal(self) -> bool: from sage.combinat.set_partition import SetPartition n = self.order() - congs_ji = {} + congs_ji: dict[SetPartition, list] = {} for ji in range(n): if self.in_degree(ji) == 1: - cong = SetPartition(self.congruence([[ji, next(self.neighbor_in_iterator(ji))]])) + cong = SetPartition(self.congruence([[ji, next(self.neighbor_in_iterator(ji))]])) # type: ignore if cong not in congs_ji: congs_ji[cong] = [] congs_ji[cong].append(ji) for mi in range(n): if self.out_degree(mi) == 1: - cong = SetPartition(self.congruence([[mi, next(self.neighbor_out_iterator(mi))]])) + cong = SetPartition(self.congruence([[mi, next(self.neighbor_out_iterator(mi))]])) # type: ignore if any(self.is_lequal(ji, mi) for ji in congs_ji[cong]): return False diff --git a/src/sage/combinat/superpartition.py b/src/sage/combinat/superpartition.py index 3de4852411d..18be88eb359 100644 --- a/src/sage/combinat/superpartition.py +++ b/src/sage/combinat/superpartition.py @@ -357,7 +357,7 @@ def to_partition(self) -> Partition: sage: SuperPartition([[2,1,0],[3,3]]).to_partition().parent() Partitions """ - return Partition(sorted(self[0] + self[1], reverse=True)) + return Partition(sorted(self[0] + self[1], reverse=True)) # type:ignore def antisymmetric_part(self) -> list: r""" @@ -508,8 +508,9 @@ def shape_circled_diagram(self) -> Partition: sage: SuperPartition([[2,1,0],[3,3]]).shape_circled_diagram() [3, 3, 3, 2, 1] """ - return Partition(sorted([a + 1 for a in self.antisymmetric_part()] - + self.symmetric_part(), reverse=True)) + pi = sorted([a + 1 for a in self.antisymmetric_part()] + + self.symmetric_part(), reverse=True) + return Partition(pi) # type:ignore @staticmethod def from_circled_diagram(shape, corners) -> SuperPartition: @@ -539,9 +540,10 @@ def from_circled_diagram(shape, corners) -> SuperPartition: sage: all(sp == from_cd(*sp.to_circled_diagram()) for sp in SuperPartitions(4)) True """ - return SuperPartition([sorted([c[1] for c in corners], reverse=True), - [shape[i] for i in range(len(shape)) - if i not in [c[0] for c in corners]]]) + data = [sorted([c[1] for c in corners], reverse=True), + [shape[i] for i in range(len(shape)) + if i not in [c[0] for c in corners]]] + return SuperPartition(data) # type: ignore def to_circled_diagram(self) -> list: r""" @@ -611,7 +613,7 @@ def zee(self) -> Integer: sage: sum(1/sp.zee() for sp in SuperPartitions(6,0)) 1 """ - return Partition(self.symmetric_part()).centralizer_size() + return Partition(self.symmetric_part()).centralizer_size() # type:ignore def sign(self) -> int: r""" @@ -755,7 +757,7 @@ def add_horizontal_border_strip_star_bar(self, h) -> list: for asp in nsp: asp = asp + [0] change_in_rows = [asp[i] - sp1[i] for i in range(len(sp1))] - moved_circ_list = [[] for i in range(len(circ_list))] + moved_circ_list: list[list[tuple]] = [[] for _ in range(len(circ_list))] for i, pos in enumerate(circ_list): if change_in_rows[pos[0]] == 0: moved_circ_list[i].append(pos) diff --git a/src/sage/combinat/tamari_lattices.py b/src/sage/combinat/tamari_lattices.py index b0b8bd96253..2f7a379a747 100644 --- a/src/sage/combinat/tamari_lattices.py +++ b/src/sage/combinat/tamari_lattices.py @@ -51,7 +51,7 @@ from sage.arith.all import gcd -def paths_in_triangle(i, j, a, b) -> list: +def paths_in_triangle(i, j, a, b) -> list[tuple]: r""" Return all Dyck paths from `(0,0)` to `(i,j)` in the `(a \times b)`-rectangle. @@ -160,7 +160,7 @@ def swap(p, i, m=1) -> tuple: return tuple(q) -def GeneralizedTamariLattice(a, b, m=1, check=True) -> LatticePoset: +def GeneralizedTamariLattice(a, b, m=1, check=True): r""" Return the `(a,b)`-Tamari lattice of parameter `m`. @@ -227,7 +227,7 @@ def covers(p): for p in paths_in_triangle(a, b, a, b)}, check=check) -def TamariLattice(n, m=1) -> LatticePoset: +def TamariLattice(n, m=1): r""" Return the `n`-th Tamari lattice. @@ -340,7 +340,7 @@ def swap_dexter(p, i) -> list: return resu -def DexterSemilattice(n) -> MeetSemilattice: +def DexterSemilattice(n): r""" Return the `n`-th Dexter meet-semilattice. From 3a66b6a1c6dd03e045d6d38a9c6ad278a003e425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 20 Oct 2021 16:43:14 +0200 Subject: [PATCH 486/511] detail --- src/sage/combinat/dyck_word.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/dyck_word.py b/src/sage/combinat/dyck_word.py index a3c80c12115..a98a29f2e26 100644 --- a/src/sage/combinat/dyck_word.py +++ b/src/sage/combinat/dyck_word.py @@ -2033,7 +2033,7 @@ def to_pair_of_standard_tableaux(self) -> tuple: return (T, T) else: left: list[list[int]] = [[], []] - right:list[list[int]] = [[], []] + right: list[list[int]] = [[], []] for pos in range(n): if self[pos] == open_symbol: left[0].append(pos + 1) From f01ff1f0f076fe550ffb6a6a657c5fda9dc0a023 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 20 Oct 2021 20:37:12 -0400 Subject: [PATCH 487/511] Trac #29024: obtain LIBSINGULAR_PATH from sage.env instead of sage_conf. On systems without sage_conf, this should keep things more or less working. The variable defaults to "libSingular.so" in the absence of divine intervention, a value that works on Linux at least. --- src/sage/env.py | 6 ++++++ src/sage/libs/singular/singular.pyx | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sage/env.py b/src/sage/env.py index 876c56d742d..e5af0374a2f 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -227,6 +227,12 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st NTL_LIBDIR = var("NTL_LIBDIR") LIE_INFO_DIR = var("LIE_INFO_DIR", join(SAGE_LOCAL, "lib", "LiE")) +# The path to libSingular, to be passed to dlopen(). This will +# typically be set to an absolute path in sage_conf, but the relative +# fallback path here works on systems where dlopen() searches the +# system's library locations. +LIBSINGULAR_PATH = var("LIBSINGULAR_PATH", "libSingular.so") + # OpenMP OPENMP_CFLAGS = var("OPENMP_CFLAGS", "") OPENMP_CXXFLAGS = var("OPENMP_CXXFLAGS", "") diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index ea6d0ab01d1..9eff1838d54 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -768,7 +768,7 @@ cdef init_libsingular(): cdef void *handle = NULL - from sage_conf import LIBSINGULAR_PATH + from sage.env import LIBSINGULAR_PATH lib = str_to_bytes(LIBSINGULAR_PATH, FS_ENCODING, "surrogateescape") # This is a workaround for https://github.com/Singular/Singular/issues/1113 From ae29c47bab2871fe740c66a802eee5c69a722074 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 21 Oct 2021 13:58:47 -0700 Subject: [PATCH 488/511] src/sage/rings/integer.pyx: Flush output in doctest --- src/sage/rings/integer.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 56de0fc858a..b24923fba6c 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -6432,7 +6432,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): TESTS:: sage: try: - ....: print('Possible error output from gmp') + ....: print('Possible error output from gmp', flush=True) ....: 1 << (2^60) ....: except (MemoryError, OverflowError, RuntimeError): ....: pass From 071121cd44319b780d1ef7c86721b701b74ad4a3 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Mon, 20 Sep 2021 08:51:25 +0200 Subject: [PATCH 489/511] add colored Jones polynomial to braids --- src/doc/en/reference/references/index.rst | 3 + src/sage/groups/braid.py | 421 ++++++++++++++++++++++ 2 files changed, 424 insertions(+) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index cecda8a5ef3..8a7e133e0ae 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -2871,6 +2871,9 @@ REFERENCES: for odd modular subgroups", LMS J. Comput. Math. 17 (2014), no. 1, 206-208, :doi:`10.1112/S1461157013000338`. +.. [HL2018] Mustafa Hajij and Jesse Levitt, "An Efficient Algorithm to Compute + the Colored Jones Polynomial" :arxiv:`1804.07910v2`. + .. [Hli2006] Petr Hlineny, "Equivalence-free exhaustive generation of matroid representations", Discrete Applied Mathematics 154 (2006), pp. 1210-1222. diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 113bf59b2c3..6a13d8cc68d 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -53,6 +53,7 @@ problem to ensure correct Cayley graph computations. - Sebastian Oehms (July and Nov 2018): add other versions for burau_matrix (unitary + simple, see :trac:`25760` and :trac:`26657`) +- Moritz Firsching (Sept 2021): Colored Jones polynomial """ ############################################################################## @@ -65,23 +66,31 @@ # https://www.gnu.org/licenses/ ############################################################################## +import itertools +import collections +from operator import index from sage.rings.integer import Integer from sage.rings.integer_ring import IntegerRing from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import lazy_import from sage.misc.cachefunc import cached_method +from sage.misc.misc_c import prod +from sage.algebras.free_algebra import FreeAlgebra from sage.categories.groups import Groups from sage.groups.free_group import FreeGroup, is_FreeGroup from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.matrix.constructor import identity_matrix, matrix from sage.combinat.permutation import Permutations +from sage.combinat.subset import Subsets from sage.categories.action import Action +from sage.knots.knot import Knot from sage.sets.set import Set from sage.groups.finitely_presented import FinitelyPresentedGroup from sage.groups.artin import FiniteTypeArtinGroup, FiniteTypeArtinGroupElement from sage.structure.richcmp import richcmp, rich_to_bool from sage.features import PythonModule + lazy_import('sage.libs.braiding', ['rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor', 'leastcommonmultiple', 'conjugatingbraid', 'ultrasummitset', @@ -1736,6 +1745,415 @@ def reverse(self): t.reverse() return self.parent()(tuple(t)) + class _RightQuantumWord: + def __init__(self, words): + r""" + An internal class representing right quantum words as in + definition 4.1 of [HL2018]_. + + INPUT: + - ``words`` -- An element in a suitable free algebra over a + Laurent polynomial ring in one variable. This input does not + need to be in reduced form, but the monomials for the input + can come in any order. + + EXAMPLES:: + sage: figure_8 = BraidGroup(3)([-1, 2, -1, 2]) + sage: ( + ....: bp_1, cp_1, ap_1, + ....: bp_3, cp_3, ap_3, + ....: bm_0, cm_0, am_0, + ....: bm_2, cm_2, am_2 + ....: ) = figure_8._deformed_burau_matrix().parent().base_ring().gens() + sage: q = bp_1.base_ring().gen() + sage: figure_8._RightQuantumWord(ap_1*cp_1 + + ....: q**3*bm_2*bp_1*am_0*cm_0) + The right quantum word represented by q*cp_1*ap_1 + q^2*bp_1*cm_0*am_0*bm_2 reduced from ap_1*cp_1 + q^3*bm_2*bp_1*am_0*cm_0 + """ + self._Alg = words.parent() + self.q = self._Alg.base_ring().gen() + self.R = self._Alg.base_ring() + self._unreduced_words = words + self._tuples = None + self._gens = self._Alg.gens() + self._minus_begin = min((i for i, gen in enumerate(self._gens) if + 'm' in str(gen)), default=len(self._gens)) + + def as_tuples(self): + r""" + Get a representation of the right quantum word as a dict, with + keys monomials in the free algebra represented as tuples and + values in elements the Laurent polynomial ring in one variable. + + This is in the reduced form as outlines in definition of 4.1 of + [HL2018]_. + + OUTPUT: + A dict of tuples of ints corresponding to the exponents in the + generators self._gens(), with values in self.R. + + EXAMPLES:: + sage: figure_8 = BraidGroup(3)([-1, 2, -1, 2]) + sage: ( + ....: bp_1, cp_1, ap_1, + ....: bp_3, cp_3, ap_3, + ....: bm_0, cm_0, am_0, + ....: bm_2, cm_2, am_2 + ....: ) = figure_8._deformed_burau_matrix().parent().base_ring().gens() + sage: q = bp_1.base_ring().gen() + sage: qw = figure_8._RightQuantumWord(ap_1*cp_1 + + ....: q**3*bm_2*bp_1*am_0*cm_0) + sage: for key, value in qw.as_tuples().items(): + ....: print(key, value) + ....: + (0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) q + (1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0) q^2 + """ + if self._tuples: + return self._tuples + self._tuples = collections.defaultdict(self.R) + for unreduced_monom, q_power in list(self._unreduced_words): + q = self.q + ret_tuple = [0] * len(self._gens) + for gen, exp in unreduced_monom: + gen_index = self._gens.index(gen) + is_minus = gen_index >= self._minus_begin + is_a = not(bool((gen_index+1) % 3)) + is_b = not(bool(gen_index % 3)) + is_c = not(bool((gen_index+2) % 3)) + index = gen_index//3 + # This uses the relations in equations (4.1) and (4.2) + # of [HL2018]_. + i, j, k = ret_tuple[3*index: 3*index + 3] + if is_a: + ret_tuple[3*index: 3*index + 3] = [i, j, k + exp] + if is_b: + ret_tuple[3*index: 3*index + 3] = [i + exp, j, k] + q_power *= q**(2*(k*exp + j*exp)) if is_minus \ + else q**(-2*j*exp) + if is_c: + ret_tuple[3*index: 3*index + 3] = [i, j + exp, k] + q_power *= q**(-k*exp) if is_minus else q**(k*exp) + self._tuples[tuple(ret_tuple)] += self._Alg(q_power) + return self._tuples + + def reduced_word(self): + r""" + Return the (reduced) right quantum word. + + OUTPUT: + An element in the free algebra self._Alg. + + EXAMPLES:: + sage: figure_8 = BraidGroup(3)([-1, 2, -1, 2]) + sage: ( + ....: bp_1, cp_1, ap_1, + ....: bp_3, cp_3, ap_3, + ....: bm_0, cm_0, am_0, + ....: bm_2, cm_2, am_2 + ....: ) = figure_8._deformed_burau_matrix().parent().base_ring().gens() + sage: q = bp_1.base_ring().gen() + sage: qw = figure_8._RightQuantumWord(ap_1*cp_1 + + ....: q**3*bm_2*bp_1*am_0*cm_0) + sage: qw.reduced_word() + q*cp_1*ap_1 + q^2*bp_1*cm_0*am_0*bm_2 + + TESTS:: + + Testing the equations (4.1) and (4.2) in [HL2018]_. + + sage: figure_8._RightQuantumWord(ap_3*bp_3).reduced_word() + bp_3*ap_3 + sage: figure_8._RightQuantumWord(ap_3*cp_3).reduced_word() + q*cp_3*ap_3 + sage: figure_8._RightQuantumWord(cp_3*bp_3).reduced_word() + (q^-2)*bp_3*cp_3 + sage: figure_8._RightQuantumWord(am_2*bm_2).reduced_word() + q^2*bm_2*am_2 + sage: figure_8._RightQuantumWord(am_2*cm_2).reduced_word() + (q^-1)*cm_2*am_2 + sage: figure_8._RightQuantumWord(cm_2*bm_2).reduced_word() + q^2*bm_2*cm_2 + + .. TODO:: + Paralellize this function, calculating all summands in the sum + in parallel. + """ + def tuple_to_word(q_tuple): + return prod(self._gens[i]**exp + for i, exp in enumerate(q_tuple)) + return sum(q_factor*tuple_to_word(q_tuple) + for q_tuple, q_factor in self.as_tuples().items()) + + def eps(self, N): + r"""Evaluate the map $\mathcal{E}_N$ for a braid. + + INPUT: + - ``N`` -- an integer; the number of colors. + + EXAMPLES:: + + sage: B = BraidGroup(3) + sage: b = B([1,-2,1,2]) + sage: db = b._deformed_burau_matrix()[:, :] + sage: q = db.parent().base_ring().base_ring().gen() + sage: (bp_0, cp_0, ap_0, + ....: bp_2, cp_2, ap_2, + ....: bp_3, cp_3, ap_3, + ....: bm_1, cm_1, am_1) = db.parent().base_ring().gens() + sage: rqw = b._RightQuantumWord( + ....: q^3*bp_2*bp_0*ap_0 + q*ap_3*bm_1*am_1*bp_0) + sage: rqw.eps(3) + -(q^-1-2*q+q^5) + sage: rqw.eps(2) + -(1-2*q+q^2-q^3+q^4) + + TESTS:: + + sage: rqw.eps(1) + 0 + + .. TODO:: + Paralellize this function, calculating all summands in the sum + in parallel. + """ + def eps_monom(q_tuple): + q = self.q + r"""Evaluate the map $\mathcal{E}_N$ for a single mononial.""" + ret_q = q**sum((N - 1 - q_tuple[3*i + 2])*q_tuple[3*i + 1] + for i in range(self._minus_begin//3)) + ret_q *= q**sum((N - 1)*(-q_tuple[rj]) + for rj in range(self._minus_begin + 1, + len(q_tuple), 3)) + ret_q *= prod(prod(1 - q**(N - 1 - q_tuple[3*i + 1] - h) + for h in range(0, q_tuple[3*i + 2])) + for i in range(self._minus_begin//3)) + ret_q *= prod(prod(1 - q**(q_tuple[3*j + 1] + l + 1 - N) + for l in range(q_tuple[3*j + 2])) + for j in range(self._minus_begin//3, + len(q_tuple)//3)) + return ret_q + + return sum(q_factor*eps_monom(q_tuple) + for q_tuple, q_factor in self.as_tuples().items()) + + def __repr__(self): + r""" + String representation of the reight quantum word. + + EXAMPLES:: + sage: b = BraidGroup(3)([1,2,-1,2,-1]) + sage: db = b._deformed_burau_matrix(); db[2,2] + cp_1*am_2*bp_3 + sage: b._RightQuantumWord(db[2,2]) + The right quantum word represented by cp_1*bp_3*am_2 reduced from cp_1*am_2*bp_3 + """ + return 'The right quantum word represented by ' + \ + f'{str(self.reduced_word())} reduced from ' + \ + f'{str(self._unreduced_words)}' + + def _deformed_burau_matrix(self, variab='q'): + r""" + Return the deformed Burau matrix of the braid. + + INPUT: + - ``variab`` -- variable (default: ``q``); the variable in the + resulting laurent polynomial, which is the base ring for the + free algebra constructed. + + OUTPUT: + A matrix with elements in the free algebra `self._Alg`. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: b = B([1, 2, -3, -2, 3, 1]) + sage: db = b._deformed_burau_matrix(); db + [ ap_0*ap_5 ap_0*bp_5 bp_0*bp_1*cm_2*cp_4 + bp_0*ap_1*cm_3*ap_4 bp_0*ap_1*cm_3*bp_4] + [ cp_0*ap_5 cp_0*bp_5 0 0] + [ 0 0 cp_1*cm_3*ap_4 cp_1*cm_3*bp_4] + [ bm_2*bm_3*cp_5 0 am_2*cp_4 + bm_2*am_3*ap_4 bm_2*am_3*bp_4] + + We check how this relates to the nondeformed Burau matrix: + sage: def subs_gen(gen, q): + ....: gen_str = str(gen) + ....: v = q if 'p' in gen_str else 1/q + ....: if 'b' in gen_str: + ....: return v + ....: elif 'a' in gen_str: + ....: return 1 - v + ....: else: + ....: return 1 + sage: q = db.parent().base_ring().base_ring().gen() + sage: db_simp = db.subs({gen: subs_gen(gen, q) for gen in db.parent().base_ring().gens()}) + sage: db_simp + [ (1-2*q+q^2) (q-q^2) (q-q^2+q^3) (q^2-q^3)] + [ (1-q) q 0 0] + [ 0 0 (1-q) q] + [ (q^-2) 0 -(q^-2-q^-1) -(q^-1-1)] + sage: burau = b.burau_matrix(); burau + [1 - 2*t + t^2 t - t^2 t - t^2 + t^3 t^2 - t^3] + [ 1 - t t 0 0] + [ 0 0 1 - t t] + [ t^-2 0 -t^-2 + t^-1 -t^-1 + 1] + sage: t = burau.parent().base_ring().gen() + sage: burau.subs({t:q}).change_ring(db.parent().base_ring()) == db_simp + True + """ + R = LaurentPolynomialRing(IntegerRing(), variab) + n = self.strands() + m = len(self.Tietze()) + Algebra = FreeAlgebra(R, m*3, [f'{s}p_{i}' + for i in range(m) for s in 'bca' + if self.Tietze()[i] > 0] + [f'{s}m_{i}' + for i in range(m) for s in 'bca' + if self.Tietze()[i] < 0]) + gen_indizes = [i for i in range(m) if self.Tietze()[i] > 0] + \ + [i for i in range(m) if self.Tietze()[i] < 0] + + M = identity_matrix(Algebra, n) + for k, i in enumerate(self.Tietze()): + A = identity_matrix(Algebra, n) + gen_index = gen_indizes.index(k) + b, c, a = Algebra.gens()[3*gen_index:3*gen_index+3] + if i > 0: + A[i-1, i-1] = a + A[i, i] = 0 + A[i, i-1] = c + A[i-1, i] = b + if i < 0: + A[-1-i, -1-i] = 0 + A[-i, -i] = a + A[-1-i, -i] = c + A[-i, -1-i] = b + M = M * A + return M + + def _quantum_determinant(self, A, q): + r""" + Return the quantum deteminant of a matrix. + + INPUT: + - ``A`` -- a square matrix + - ``q`` -- a symbolic variable or a generator for a + Laurent polynomial ring. + + EXAMPLES:: + + sage: b = BraidGroup(2)([1,1,1]) + sage: A = Matrix([[SR(f'a{i}{j}') for i in range(2)] + ....: for j in range(2)]); A + [a00 a10] + [a01 a11] + sage: b._quantum_determinant(A, SR('q')) + -a01*a10*q + a00*a11 + sage: A = Matrix([[SR(f'a{i}{j}') for i in range(3)] + ....: for j in range(3)]); A + [a00 a10 a20] + [a01 a11 a21] + [a02 a12 a22] + sage: b._quantum_determinant(A, SR('q')) + -a02*a11*a20*q^3 + a01*a12*a20*q^2 + a02*a10*a21*q^2 - a00*a12*a21*q - a01*a10*a22*q + a00*a11*a22 + """ + # We assume a square matrix as input + n = A.ncols() + return sum((-q)**(s.number_of_inversions()) * + prod(A[s(i + 1) - 1, i] for i in range(n)) + for s in Permutations(n)) + + def _colored_jones_sum(self, N, qword): + r"""Helper function to get the colored Jones polynomial. + + INPUT: + - ``N`` -- An integer; the number of colors. + - ``qword`` -- A right quantum word (possibly in unreduced form). + + EXAMPLES:: + + sage: b = BraidGroup(2)([1,1,1]) + sage: db = b._deformed_burau_matrix()[1:,1:]; db + [cp_0*ap_1*bp_2] + sage: b._colored_jones_sum(2, db[0,0]) + (1+q-q^2) + sage: b._colored_jones_sum(3, db[0,0]) + (1+q^2-q^5-q^6+q^7) + sage: b._colored_jones_sum(4, db[0,0]) + (1+q^3-q^8-q^10+q^13+q^14-q^15) + """ + rqword = self._RightQuantumWord(qword).reduced_word() + alg = qword.parent() + R = alg.base_ring() + result = R(1) + current_word = alg(1) + # This seemingly infinite sum is always finite if the qword comes + # from a sum of quantum determinants; because at some point + # the break condition will become true. + for i in itertools.count(1): + current_word *= rqword + new_rqw = self._RightQuantumWord(alg(current_word)) + current_word = new_rqw.reduced_word() + if not (new_eps := new_rqw.eps(N)): + break + result += new_eps + return result + + @cached_method + def colored_jones_polynomial(self, N, variab='q', try_inverse=True): + r""" + Return the colored Jones polynomial of the trace closure of the braid. + + INPUT: + - ``N`` -- integer; the number of colors. + - ``variab`` -- string (default: ``q``); the variable in the + resulting laurent polynomial. + - ``try_inverse`` -- boolean (default: ``True``); if ``True``, + attempt a faster calculation by using the inverse of the braid. + + EXAMPLES:: + + sage: trefoil = BraidGroup(2)([1,1,1]) + sage: trefoil.colored_jones_polynomial(2) + q + q^3 - q^4 + sage: trefoil.colored_jones_polynomial(4) + q^3 + q^7 - q^10 + q^11 - q^13 - q^14 + q^15 - q^17 + q^19 + q^20 - q^21 + sage: trefoil.inverse().colored_jones_polynomial(4) + -q^-21 + q^-20 + q^-19 - q^-17 + q^-15 - q^-14 - q^-13 + q^-11 - q^-10 + q^-7 + q^-3 + + sage: figure_eight = BraidGroup(3)([-1, 2, -1, 2]) + sage: figure_eight.colored_jones_polynomial(2) + q^-2 - q^-1 + 1 - q + q^2 + sage: figure_eight.colored_jones_polynomial(3, 'Q') + Q^-6 - Q^-5 - Q^-4 + 2*Q^-3 - Q^-2 - Q^-1 + 3 - Q - Q^2 + 2*Q^3 - Q^4 - Q^5 + Q^6 + + ALGORITHM: + + The algorithm used is described in [HL2018]_. We follow their + notation, but work in a suitable free algebra over a Laurent + polynomial ring in one variable to simplify bookkeeping. + """ + if self.components_in_closure() != 1: + raise ValueError("the number of components must be 1") + db = self._deformed_burau_matrix(variab)[1:, 1:] + q = db.parent().base_ring().base_ring().gen() + n = db.ncols() + qword = sum((-1)**(s.cardinality() - 1)*self._quantum_determinant( + q*db[list(s), list(s)], q) for s in Subsets(range(n)) if s) + inverse_shorter = try_inverse + if try_inverse: + db_inv = self.inverse()._deformed_burau_matrix(variab)[1:, 1:] + q_inv = db_inv.parent().base_ring().base_ring().gen() + qword_inv = sum((-1)**(s.cardinality() - + 1)*self._quantum_determinant(q*db_inv[list(s), + list(s)], q) + for s in Subsets(range(n)) if s) + # Check if the inverse has a shorter expression at this point + inverse_shorter = len(list(qword_inv)) < len(list(qword)) + use_inverse = try_inverse and inverse_shorter + shorter_qword = qword_inv if use_inverse else qword + knot = Knot(self.inverse()) if use_inverse else Knot(self) + cj = q**(((N - 1)*(knot.writhe() - self.strands() + 1))/2) * \ + self._colored_jones_sum(N, shorter_qword).leading_coefficient() + return cj.subs({q: 1/q}) if use_inverse else cj class BraidGroup_class(FiniteTypeArtinGroup): """ @@ -2514,6 +2932,7 @@ def _element_from_libbraiding(self, nf): from sage.misc.misc_c import prod return self.delta() ** nf[0][0] * prod(self(i) for i in nf[1:]) +<<<<<<< HEAD def mirror_involution(self): r""" Return the mirror involution of ``self``. @@ -2540,6 +2959,8 @@ def mirror_involution(self): return self.hom(gens_mirr, check=False) +======= +>>>>>>> 6e95c3a616 (add colored Jones polynomial to braids) def BraidGroup(n=None, names='s'): """ Construct a Braid Group From 775c29d307cfed4175ca3d8033a0ca9be60ad3cb Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Wed, 29 Sep 2021 08:36:10 +0200 Subject: [PATCH 490/511] remove walrus --- src/sage/groups/braid.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 6a13d8cc68d..fa7e60c4a9d 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -2092,7 +2092,8 @@ def _colored_jones_sum(self, N, qword): current_word *= rqword new_rqw = self._RightQuantumWord(alg(current_word)) current_word = new_rqw.reduced_word() - if not (new_eps := new_rqw.eps(N)): + new_eps = new_rqw.eps(N) + if not (new_eps): break result += new_eps return result From 975ab638731f311f609ecadc46fcba0a6701b68b Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Wed, 29 Sep 2021 15:50:56 +0200 Subject: [PATCH 491/511] use q_inv instead of q for clarity --- src/sage/groups/braid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index fa7e60c4a9d..949fd58dd37 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -2144,7 +2144,7 @@ def colored_jones_polynomial(self, N, variab='q', try_inverse=True): db_inv = self.inverse()._deformed_burau_matrix(variab)[1:, 1:] q_inv = db_inv.parent().base_ring().base_ring().gen() qword_inv = sum((-1)**(s.cardinality() - - 1)*self._quantum_determinant(q*db_inv[list(s), + 1)*self._quantum_determinant(q_inv*db_inv[list(s), list(s)], q) for s in Subsets(range(n)) if s) # Check if the inverse has a shorter expression at this point From bf8a4ffd041881661a7fa0c506960c49ef97fc5d Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Wed, 29 Sep 2021 21:48:28 +0200 Subject: [PATCH 492/511] add indentation for EXAMPLES --- src/sage/groups/braid.py | 89 +++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 949fd58dd37..a1c65638ee5 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -1758,6 +1758,7 @@ def __init__(self, words): can come in any order. EXAMPLES:: + sage: figure_8 = BraidGroup(3)([-1, 2, -1, 2]) sage: ( ....: bp_1, cp_1, ap_1, @@ -1793,6 +1794,7 @@ def as_tuples(self): generators self._gens(), with values in self.R. EXAMPLES:: + sage: figure_8 = BraidGroup(3)([-1, 2, -1, 2]) sage: ( ....: bp_1, cp_1, ap_1, @@ -1845,6 +1847,7 @@ def reduced_word(self): An element in the free algebra self._Alg. EXAMPLES:: + sage: figure_8 = BraidGroup(3)([-1, 2, -1, 2]) sage: ( ....: bp_1, cp_1, ap_1, @@ -1893,20 +1896,20 @@ def eps(self, N): EXAMPLES:: - sage: B = BraidGroup(3) - sage: b = B([1,-2,1,2]) - sage: db = b._deformed_burau_matrix()[:, :] - sage: q = db.parent().base_ring().base_ring().gen() - sage: (bp_0, cp_0, ap_0, - ....: bp_2, cp_2, ap_2, - ....: bp_3, cp_3, ap_3, - ....: bm_1, cm_1, am_1) = db.parent().base_ring().gens() - sage: rqw = b._RightQuantumWord( - ....: q^3*bp_2*bp_0*ap_0 + q*ap_3*bm_1*am_1*bp_0) - sage: rqw.eps(3) - -(q^-1-2*q+q^5) - sage: rqw.eps(2) - -(1-2*q+q^2-q^3+q^4) + sage: B = BraidGroup(3) + sage: b = B([1,-2,1,2]) + sage: db = b._deformed_burau_matrix()[:, :] + sage: q = db.parent().base_ring().base_ring().gen() + sage: (bp_0, cp_0, ap_0, + ....: bp_2, cp_2, ap_2, + ....: bp_3, cp_3, ap_3, + ....: bm_1, cm_1, am_1) = db.parent().base_ring().gens() + sage: rqw = b._RightQuantumWord( + ....: q^3*bp_2*bp_0*ap_0 + q*ap_3*bm_1*am_1*bp_0) + sage: rqw.eps(3) + -(q^-1-2*q+q^5) + sage: rqw.eps(2) + -(1-2*q+q^2-q^3+q^4) TESTS:: @@ -1942,11 +1945,11 @@ def __repr__(self): String representation of the reight quantum word. EXAMPLES:: - sage: b = BraidGroup(3)([1,2,-1,2,-1]) - sage: db = b._deformed_burau_matrix(); db[2,2] - cp_1*am_2*bp_3 - sage: b._RightQuantumWord(db[2,2]) - The right quantum word represented by cp_1*bp_3*am_2 reduced from cp_1*am_2*bp_3 + sage: b = BraidGroup(3)([1,2,-1,2,-1]) + sage: db = b._deformed_burau_matrix(); db[2,2] + cp_1*am_2*bp_3 + sage: b._RightQuantumWord(db[2,2]) + The right quantum word represented by cp_1*bp_3*am_2 reduced from cp_1*am_2*bp_3 """ return 'The right quantum word represented by ' + \ f'{str(self.reduced_word())} reduced from ' + \ @@ -1974,7 +1977,7 @@ def _deformed_burau_matrix(self, variab='q'): [ 0 0 cp_1*cm_3*ap_4 cp_1*cm_3*bp_4] [ bm_2*bm_3*cp_5 0 am_2*cp_4 + bm_2*am_3*ap_4 bm_2*am_3*bp_4] - We check how this relates to the nondeformed Burau matrix: + We check how this relates to the nondeformed Burau matrix: sage: def subs_gen(gen, q): ....: gen_str = str(gen) ....: v = q if 'p' in gen_str else 1/q @@ -2040,20 +2043,20 @@ def _quantum_determinant(self, A, q): EXAMPLES:: - sage: b = BraidGroup(2)([1,1,1]) - sage: A = Matrix([[SR(f'a{i}{j}') for i in range(2)] - ....: for j in range(2)]); A - [a00 a10] - [a01 a11] - sage: b._quantum_determinant(A, SR('q')) - -a01*a10*q + a00*a11 - sage: A = Matrix([[SR(f'a{i}{j}') for i in range(3)] - ....: for j in range(3)]); A - [a00 a10 a20] - [a01 a11 a21] - [a02 a12 a22] - sage: b._quantum_determinant(A, SR('q')) - -a02*a11*a20*q^3 + a01*a12*a20*q^2 + a02*a10*a21*q^2 - a00*a12*a21*q - a01*a10*a22*q + a00*a11*a22 + sage: b = BraidGroup(2)([1,1,1]) + sage: A = Matrix([[SR(f'a{i}{j}') for i in range(2)] + ....: for j in range(2)]); A + [a00 a10] + [a01 a11] + sage: b._quantum_determinant(A, SR('q')) + -a01*a10*q + a00*a11 + sage: A = Matrix([[SR(f'a{i}{j}') for i in range(3)] + ....: for j in range(3)]); A + [a00 a10 a20] + [a01 a11 a21] + [a02 a12 a22] + sage: b._quantum_determinant(A, SR('q')) + -a02*a11*a20*q^3 + a01*a12*a20*q^2 + a02*a10*a21*q^2 - a00*a12*a21*q - a01*a10*a22*q + a00*a11*a22 """ # We assume a square matrix as input n = A.ncols() @@ -2070,15 +2073,15 @@ def _colored_jones_sum(self, N, qword): EXAMPLES:: - sage: b = BraidGroup(2)([1,1,1]) - sage: db = b._deformed_burau_matrix()[1:,1:]; db - [cp_0*ap_1*bp_2] - sage: b._colored_jones_sum(2, db[0,0]) - (1+q-q^2) - sage: b._colored_jones_sum(3, db[0,0]) - (1+q^2-q^5-q^6+q^7) - sage: b._colored_jones_sum(4, db[0,0]) - (1+q^3-q^8-q^10+q^13+q^14-q^15) + sage: b = BraidGroup(2)([1,1,1]) + sage: db = b._deformed_burau_matrix()[1:,1:]; db + [cp_0*ap_1*bp_2] + sage: b._colored_jones_sum(2, db[0,0]) + (1+q-q^2) + sage: b._colored_jones_sum(3, db[0,0]) + (1+q^2-q^5-q^6+q^7) + sage: b._colored_jones_sum(4, db[0,0]) + (1+q^3-q^8-q^10+q^13+q^14-q^15) """ rqword = self._RightQuantumWord(qword).reduced_word() alg = qword.parent() From b0b1d8beef5aecc791f61f9987cf87509b7ae96e Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Wed, 29 Sep 2021 21:53:58 +0200 Subject: [PATCH 493/511] remove unused index --- src/sage/groups/braid.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index a1c65638ee5..d8e2ec1c28b 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -68,7 +68,6 @@ import itertools import collections -from operator import index from sage.rings.integer import Integer from sage.rings.integer_ring import IntegerRing from sage.misc.lazy_attribute import lazy_attribute From c01f408e147ad07aa076b9f61b22b357eb89934f Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Tue, 5 Oct 2021 13:27:07 +0200 Subject: [PATCH 494/511] first round of review comments --- src/sage/groups/braid.py | 358 +++++++++++++++++++++++++++++++-------- 1 file changed, 284 insertions(+), 74 deletions(-) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index d8e2ec1c28b..a4ede96bf0d 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -66,7 +66,6 @@ # https://www.gnu.org/licenses/ ############################################################################## -import itertools import collections from sage.rings.integer import Integer from sage.rings.integer_ring import IntegerRing @@ -1705,6 +1704,7 @@ def sliding_circuits(self): B = self.parent() return [[B._element_from_libbraiding(i) for i in s] for s in slc] +<<<<<<< HEAD def mirror_image(self): r""" Return the image of ``self`` under the mirror involution (see @@ -1955,26 +1955,30 @@ def __repr__(self): f'{str(self._unreduced_words)}' def _deformed_burau_matrix(self, variab='q'): +======= + def deformed_burau_matrix(self, variab='q'): +>>>>>>> 062a9e9a44 (first round of review comments) r""" Return the deformed Burau matrix of the braid. INPUT: + - ``variab`` -- variable (default: ``q``); the variable in the resulting laurent polynomial, which is the base ring for the free algebra constructed. OUTPUT: - A matrix with elements in the free algebra `self._Alg`. + + A matrix with elements in the free algebra `self._Alg`. EXAMPLES:: sage: B = BraidGroup(4) sage: b = B([1, 2, -3, -2, 3, 1]) - sage: db = b._deformed_burau_matrix(); db - [ ap_0*ap_5 ap_0*bp_5 bp_0*bp_1*cm_2*cp_4 + bp_0*ap_1*cm_3*ap_4 bp_0*ap_1*cm_3*bp_4] - [ cp_0*ap_5 cp_0*bp_5 0 0] - [ 0 0 cp_1*cm_3*ap_4 cp_1*cm_3*bp_4] - [ bm_2*bm_3*cp_5 0 am_2*cp_4 + bm_2*am_3*ap_4 bm_2*am_3*bp_4] + sage: db = b.deformed_burau_matrix(); db + [ ap_0*ap_5 ... bp_0*ap_1*cm_3*bp_4] + ... + [ bm_2*bm_3*cp_5 ... bm_2*am_3*bp_4] We check how this relates to the nondeformed Burau matrix: sage: def subs_gen(gen, q): @@ -1986,8 +1990,10 @@ def _deformed_burau_matrix(self, variab='q'): ....: return 1 - v ....: else: ....: return 1 - sage: q = db.parent().base_ring().base_ring().gen() - sage: db_simp = db.subs({gen: subs_gen(gen, q) for gen in db.parent().base_ring().gens()}) + sage: db_base = db.parent().base_ring() + sage: q = db_base.base_ring().gen() + sage: db_simp = db.subs({gen: subs_gen(gen, q) + ....: for gen in db_base.gens()}) sage: db_simp [ (1-2*q+q^2) (q-q^2) (q-q^2+q^3) (q^2-q^3)] [ (1-q) q 0 0] @@ -1999,7 +2005,7 @@ def _deformed_burau_matrix(self, variab='q'): [ 0 0 1 - t t] [ t^-2 0 -t^-2 + t^-1 -t^-1 + 1] sage: t = burau.parent().base_ring().gen() - sage: burau.subs({t:q}).change_ring(db.parent().base_ring()) == db_simp + sage: burau.subs({t:q}).change_ring(db_base) == db_simp True """ R = LaurentPolynomialRing(IntegerRing(), variab) @@ -2031,49 +2037,19 @@ def _deformed_burau_matrix(self, variab='q'): M = M * A return M - def _quantum_determinant(self, A, q): - r""" - Return the quantum deteminant of a matrix. - - INPUT: - - ``A`` -- a square matrix - - ``q`` -- a symbolic variable or a generator for a - Laurent polynomial ring. - - EXAMPLES:: - - sage: b = BraidGroup(2)([1,1,1]) - sage: A = Matrix([[SR(f'a{i}{j}') for i in range(2)] - ....: for j in range(2)]); A - [a00 a10] - [a01 a11] - sage: b._quantum_determinant(A, SR('q')) - -a01*a10*q + a00*a11 - sage: A = Matrix([[SR(f'a{i}{j}') for i in range(3)] - ....: for j in range(3)]); A - [a00 a10 a20] - [a01 a11 a21] - [a02 a12 a22] - sage: b._quantum_determinant(A, SR('q')) - -a02*a11*a20*q^3 + a01*a12*a20*q^2 + a02*a10*a21*q^2 - a00*a12*a21*q - a01*a10*a22*q + a00*a11*a22 - """ - # We assume a square matrix as input - n = A.ncols() - return sum((-q)**(s.number_of_inversions()) * - prod(A[s(i + 1) - 1, i] for i in range(n)) - for s in Permutations(n)) - + @cached_method def _colored_jones_sum(self, N, qword): r"""Helper function to get the colored Jones polynomial. INPUT: - - ``N`` -- An integer; the number of colors. - - ``qword`` -- A right quantum word (possibly in unreduced form). + + - ``N`` -- An integer; the number of colors. + - ``qword`` -- A right quantum word (possibly in unreduced form). EXAMPLES:: sage: b = BraidGroup(2)([1,1,1]) - sage: db = b._deformed_burau_matrix()[1:,1:]; db + sage: db = b.deformed_burau_matrix()[1:,1:]; db [cp_0*ap_1*bp_2] sage: b._colored_jones_sum(2, db[0,0]) (1+q-q^2) @@ -2082,35 +2058,38 @@ def _colored_jones_sum(self, N, qword): sage: b._colored_jones_sum(4, db[0,0]) (1+q^3-q^8-q^10+q^13+q^14-q^15) """ - rqword = self._RightQuantumWord(qword).reduced_word() + rqword = RightQuantumWord(qword).reduced_word() alg = qword.parent() R = alg.base_ring() result = R(1) current_word = alg(1) + i = 1 + continue_summing = True # This seemingly infinite sum is always finite if the qword comes # from a sum of quantum determinants; because at some point # the break condition will become true. - for i in itertools.count(1): + while continue_summing: current_word *= rqword - new_rqw = self._RightQuantumWord(alg(current_word)) + new_rqw = RightQuantumWord(alg(current_word)) current_word = new_rqw.reduced_word() new_eps = new_rqw.eps(N) - if not (new_eps): - break result += new_eps + if not (new_eps): + continue_summing = False + i += 1 return result - @cached_method - def colored_jones_polynomial(self, N, variab='q', try_inverse=True): + def colored_jones_polynomial(self, N, variab=None, try_inverse=True): r""" Return the colored Jones polynomial of the trace closure of the braid. INPUT: - - ``N`` -- integer; the number of colors. - - ``variab`` -- string (default: ``q``); the variable in the - resulting laurent polynomial. - - ``try_inverse`` -- boolean (default: ``True``); if ``True``, - attempt a faster calculation by using the inverse of the braid. + + - ``N`` -- integer; the number of colors. + - ``variab`` -- string (default: ``q``); the variable in the + resulting laurent polynomial. + - ``try_inverse`` -- boolean (default: ``True``); if ``True``, + attempt a faster calculation by using the inverse of the braid. EXAMPLES:: @@ -2118,36 +2097,40 @@ def colored_jones_polynomial(self, N, variab='q', try_inverse=True): sage: trefoil.colored_jones_polynomial(2) q + q^3 - q^4 sage: trefoil.colored_jones_polynomial(4) - q^3 + q^7 - q^10 + q^11 - q^13 - q^14 + q^15 - q^17 + q^19 + q^20 - q^21 + q^3 + q^7 - q^10 + q^11 - q^13 - q^14 + q^15 - q^17 + q^19 + q^20 + - q^21 sage: trefoil.inverse().colored_jones_polynomial(4) - -q^-21 + q^-20 + q^-19 - q^-17 + q^-15 - q^-14 - q^-13 + q^-11 - q^-10 + q^-7 + q^-3 + -q^-21 + q^-20 + q^-19 - q^-17 + q^-15 - q^-14 - q^-13 + q^-11 - + q^-10 + q^-7 + q^-3 sage: figure_eight = BraidGroup(3)([-1, 2, -1, 2]) sage: figure_eight.colored_jones_polynomial(2) q^-2 - q^-1 + 1 - q + q^2 sage: figure_eight.colored_jones_polynomial(3, 'Q') - Q^-6 - Q^-5 - Q^-4 + 2*Q^-3 - Q^-2 - Q^-1 + 3 - Q - Q^2 + 2*Q^3 - Q^4 - Q^5 + Q^6 + Q^-6 - Q^-5 - Q^-4 + 2*Q^-3 - Q^-2 - Q^-1 + 3 - Q - Q^2 + 2*Q^3 + - Q^4 - Q^5 + Q^6 ALGORITHM: - The algorithm used is described in [HL2018]_. We follow their - notation, but work in a suitable free algebra over a Laurent - polynomial ring in one variable to simplify bookkeeping. + The algorithm used is described in [HL2018]_. We follow their notation, + but work in a suitable free algebra over a Laurent polynomial ring in + one variable to simplify bookkeeping. """ if self.components_in_closure() != 1: raise ValueError("the number of components must be 1") - db = self._deformed_burau_matrix(variab)[1:, 1:] + db = self.deformed_burau_matrix('q')[1:, 1:] q = db.parent().base_ring().base_ring().gen() n = db.ncols() - qword = sum((-1)**(s.cardinality() - 1)*self._quantum_determinant( - q*db[list(s), list(s)], q) for s in Subsets(range(n)) if s) + qword = sum((-1)**(s.cardinality() - 1)*(q*db[list(s), + list(s)]).quantum_determinant(q) + for s in Subsets(range(n)) if s) inverse_shorter = try_inverse if try_inverse: - db_inv = self.inverse()._deformed_burau_matrix(variab)[1:, 1:] + db_inv = self.inverse().deformed_burau_matrix('q')[1:, 1:] q_inv = db_inv.parent().base_ring().base_ring().gen() qword_inv = sum((-1)**(s.cardinality() - - 1)*self._quantum_determinant(q_inv*db_inv[list(s), - list(s)], q) + 1)*(q_inv*db_inv[list(s), + list(s)]).quantum_determinant(q) for s in Subsets(range(n)) if s) # Check if the inverse has a shorter expression at this point inverse_shorter = len(list(qword_inv)) < len(list(qword)) @@ -2156,7 +2139,238 @@ def colored_jones_polynomial(self, N, variab='q', try_inverse=True): knot = Knot(self.inverse()) if use_inverse else Knot(self) cj = q**(((N - 1)*(knot.writhe() - self.strands() + 1))/2) * \ self._colored_jones_sum(N, shorter_qword).leading_coefficient() - return cj.subs({q: 1/q}) if use_inverse else cj + cj_with_q = cj.subs({q: 1/q}) if use_inverse else cj + + # Up to this point, we have calculated everyting with a variable named + # `q` instead of using `variab`, because this allows proper caching in + # `_colored_jones_sum`. Here we do the substitution as necessary. + if not variab: + return cj_with_q + new_q = LaurentPolynomialRing(IntegerRing(), variab).gen() + return cj_with_q.subs({q: new_q}) + + +class RightQuantumWord: + def __init__(self, words): + r""" + An internal class representing right quantum words as in + definition 4.1 of [HL2018]_. + + INPUT: + + - ``words`` -- An element in a suitable free algebra over a Laurent + polynomial ring in one variable. This input does not need to be in + reduced form, but the monomials for the input can come in any order. + + EXAMPLES:: + + sage: from sage.groups.braid import RightQuantumWord + sage: fig_8 = BraidGroup(3)([-1, 2, -1, 2]) + sage: ( + ....: bp_1, cp_1, ap_1, + ....: bp_3, cp_3, ap_3, + ....: bm_0, cm_0, am_0, + ....: bm_2, cm_2, am_2 + ....: ) = fig_8.deformed_burau_matrix().parent().base_ring().gens() + sage: q = bp_1.base_ring().gen() + sage: RightQuantumWord(ap_1*cp_1 + q**3*bm_2*bp_1*am_0*cm_0) + The right quantum word represented by + q*cp_1*ap_1 + q^2*bp_1*cm_0*am_0*bm_2 + reduced from ap_1*cp_1 + q^3*bm_2*bp_1*am_0*cm_0 + """ + self._Alg = words.parent() + self.q = self._Alg.base_ring().gen() + self.R = self._Alg.base_ring() + self._unreduced_words = words + self._tuples = None + self._gens = self._Alg.gens() + self._minus_begin = min((i for i, gen in enumerate(self._gens) if + 'm' in str(gen)), default=len(self._gens)) + + def as_tuples(self): + r""" + Get a representation of the right quantum word as a dict, with + keys monomials in the free algebra represented as tuples and + values in elements the Laurent polynomial ring in one variable. + + This is in the reduced form as outlines in definition of 4.1 of + [HL2018]_. + + OUTPUT: + + A dict of tuples of ints corresponding to the exponents in the + generators self._gens(), with values in self.R. + + EXAMPLES:: + + sage: from sage.groups.braid import RightQuantumWord + sage: fig_8 = BraidGroup(3)([-1, 2, -1, 2]) + sage: ( + ....: bp_1, cp_1, ap_1, + ....: bp_3, cp_3, ap_3, + ....: bm_0, cm_0, am_0, + ....: bm_2, cm_2, am_2 + ....: ) = fig_8.deformed_burau_matrix().parent().base_ring().gens() + sage: q = bp_1.base_ring().gen() + sage: qw = RightQuantumWord(ap_1*cp_1 + + ....: q**3*bm_2*bp_1*am_0*cm_0) + sage: for key, value in qw.as_tuples().items(): + ....: print(key, value) + ....: + (0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) q + (1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0) q^2 + """ + if self._tuples: + return self._tuples + self._tuples = collections.defaultdict(self.R) + for unreduced_monom, q_power in list(self._unreduced_words): + q = self.q + ret_tuple = [0] * len(self._gens) + for gen, exp in unreduced_monom: + gen_index = self._gens.index(gen) + is_minus = gen_index >= self._minus_begin + is_a = not(bool((gen_index+1) % 3)) + is_b = not(bool(gen_index % 3)) + is_c = not(bool((gen_index+2) % 3)) + index = gen_index//3 + # This uses the relations in equations (4.1) and (4.2) + # of [HL2018]_. + i, j, k = ret_tuple[3*index: 3*index + 3] + if is_a: + ret_tuple[3*index: 3*index + 3] = [i, j, k + exp] + if is_b: + ret_tuple[3*index: 3*index + 3] = [i + exp, j, k] + q_power *= q**(2*(k*exp + j*exp)) if is_minus \ + else q**(-2*j*exp) + if is_c: + ret_tuple[3*index: 3*index + 3] = [i, j + exp, k] + q_power *= q**(-k*exp) if is_minus else q**(k*exp) + self._tuples[tuple(ret_tuple)] += self._Alg(q_power) + return self._tuples + + def reduced_word(self): + r""" + Return the (reduced) right quantum word. + + OUTPUT: + + An element in the free algebra self._Alg. + + EXAMPLES:: + + sage: from sage.groups.braid import RightQuantumWord + sage: fig_8 = BraidGroup(3)([-1, 2, -1, 2]) + sage: ( + ....: bp_1, cp_1, ap_1, + ....: bp_3, cp_3, ap_3, + ....: bm_0, cm_0, am_0, + ....: bm_2, cm_2, am_2 + ....: ) = fig_8.deformed_burau_matrix().parent().base_ring().gens() + sage: q = bp_1.base_ring().gen() + sage: qw = RightQuantumWord(ap_1*cp_1 + + ....: q**3*bm_2*bp_1*am_0*cm_0) + sage: qw.reduced_word() + q*cp_1*ap_1 + q^2*bp_1*cm_0*am_0*bm_2 + + TESTS:: + + Testing the equations (4.1) and (4.2) in [HL2018]_. + + sage: RightQuantumWord(ap_3*bp_3).reduced_word() + bp_3*ap_3 + sage: RightQuantumWord(ap_3*cp_3).reduced_word() + q*cp_3*ap_3 + sage: RightQuantumWord(cp_3*bp_3).reduced_word() + (q^-2)*bp_3*cp_3 + sage: RightQuantumWord(am_2*bm_2).reduced_word() + q^2*bm_2*am_2 + sage: RightQuantumWord(am_2*cm_2).reduced_word() + (q^-1)*cm_2*am_2 + sage: RightQuantumWord(cm_2*bm_2).reduced_word() + q^2*bm_2*cm_2 + + .. TODO:: + Paralellize this function, calculating all summands in the sum + in parallel. + """ + def tuple_to_word(q_tuple): + return prod(self._gens[i]**exp + for i, exp in enumerate(q_tuple)) + return sum(q_factor*tuple_to_word(q_tuple) + for q_tuple, q_factor in self.as_tuples().items()) + + def eps(self, N): + r"""Evaluate the map $\mathcal{E}_N$ for a braid. + + INPUT: + + - ``N`` -- an integer; the number of colors. + + EXAMPLES:: + + sage: from sage.groups.braid import RightQuantumWord + sage: B = BraidGroup(3) + sage: b = B([1,-2,1,2]) + sage: db = b.deformed_burau_matrix()[:, :] + sage: q = db.parent().base_ring().base_ring().gen() + sage: (bp_0, cp_0, ap_0, + ....: bp_2, cp_2, ap_2, + ....: bp_3, cp_3, ap_3, + ....: bm_1, cm_1, am_1) = db.parent().base_ring().gens() + sage: rqw = RightQuantumWord( + ....: q^3*bp_2*bp_0*ap_0 + q*ap_3*bm_1*am_1*bp_0) + sage: rqw.eps(3) + -(q^-1-2*q+q^5) + sage: rqw.eps(2) + -(1-2*q+q^2-q^3+q^4) + + TESTS:: + + sage: rqw.eps(1) + 0 + + .. TODO:: + Paralellize this function, calculating all summands in the sum + in parallel. + """ + def eps_monom(q_tuple): + q = self.q + r"""Evaluate the map $\mathcal{E}_N$ for a single mononial.""" + ret_q = q**sum((N - 1 - q_tuple[3*i + 2])*q_tuple[3*i + 1] + for i in range(self._minus_begin//3)) + ret_q *= q**sum((N - 1)*(-q_tuple[rj]) + for rj in range(self._minus_begin + 1, + len(q_tuple), 3)) + ret_q *= prod(prod(1 - q**(N - 1 - q_tuple[3*i + 1] - h) + for h in range(0, q_tuple[3*i + 2])) + for i in range(self._minus_begin//3)) + ret_q *= prod(prod(1 - q**(q_tuple[3*j + 1] + l + 1 - N) + for l in range(q_tuple[3*j + 2])) + for j in range(self._minus_begin//3, + len(q_tuple)//3)) + return ret_q + + return sum(q_factor*eps_monom(q_tuple) + for q_tuple, q_factor in self.as_tuples().items()) + + def __repr__(self): + r""" + String representation of the reight quantum word. + + EXAMPLES:: + + sage: from sage.groups.braid import RightQuantumWord + sage: b = BraidGroup(3)([1,2,-1,2,-1]) + sage: db = b.deformed_burau_matrix(); db[2,2] + cp_1*am_2*bp_3 + sage: RightQuantumWord(db[2,2]) + The right quantum word represented by cp_1*bp_3*am_2 reduced from + cp_1*am_2*bp_3 + """ + return 'The right quantum word represented by ' + \ + f'{str(self.reduced_word())} reduced from ' + \ + f'{str(self._unreduced_words)}' + class BraidGroup_class(FiniteTypeArtinGroup): """ @@ -2935,7 +3149,6 @@ def _element_from_libbraiding(self, nf): from sage.misc.misc_c import prod return self.delta() ** nf[0][0] * prod(self(i) for i in nf[1:]) -<<<<<<< HEAD def mirror_involution(self): r""" Return the mirror involution of ``self``. @@ -2961,9 +3174,6 @@ def mirror_involution(self): gens_mirr = [~g for g in self.gens()] return self.hom(gens_mirr, check=False) - -======= ->>>>>>> 6e95c3a616 (add colored Jones polynomial to braids) def BraidGroup(n=None, names='s'): """ Construct a Braid Group From eca48699f69049ab305d3c42ca4fd49f2cd49399 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Wed, 6 Oct 2021 08:26:52 +0200 Subject: [PATCH 495/511] fix doc --- src/sage/groups/braid.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index a4ede96bf0d..171bba7d5b1 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -2159,8 +2159,8 @@ def __init__(self, words): INPUT: - ``words`` -- An element in a suitable free algebra over a Laurent - polynomial ring in one variable. This input does not need to be in - reduced form, but the monomials for the input can come in any order. + polynomial ring in one variable. This input does not need to be in + reduced form, but the monomials for the input can come in any order. EXAMPLES:: From 022fcde5e2c483d08300fedef34165df0ff7de21 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 8 Oct 2021 10:33:20 +0900 Subject: [PATCH 496/511] Reviewer changes to colored Jones polynomial. --- src/sage/groups/braid.py | 237 +++++++++++++++++++++------------------ 1 file changed, 127 insertions(+), 110 deletions(-) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 171bba7d5b1..fe55c7d235a 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -66,7 +66,6 @@ # https://www.gnu.org/licenses/ ############################################################################## -import collections from sage.rings.integer import Integer from sage.rings.integer_ring import IntegerRing from sage.misc.lazy_attribute import lazy_attribute @@ -1965,11 +1964,11 @@ def deformed_burau_matrix(self, variab='q'): - ``variab`` -- variable (default: ``q``); the variable in the resulting laurent polynomial, which is the base ring for the - free algebra constructed. + free algebra constructed OUTPUT: - A matrix with elements in the free algebra `self._Alg`. + A matrix with elements in the free algebra `self._algebra`. EXAMPLES:: @@ -1980,7 +1979,8 @@ def deformed_burau_matrix(self, variab='q'): ... [ bm_2*bm_3*cp_5 ... bm_2*am_3*bp_4] - We check how this relates to the nondeformed Burau matrix: + We check how this relates to the nondeformed Burau matrix:: + sage: def subs_gen(gen, q): ....: gen_str = str(gen) ....: v = q if 'p' in gen_str else 1/q @@ -1993,7 +1993,7 @@ def deformed_burau_matrix(self, variab='q'): sage: db_base = db.parent().base_ring() sage: q = db_base.base_ring().gen() sage: db_simp = db.subs({gen: subs_gen(gen, q) - ....: for gen in db_base.gens()}) + ....: for gen in db_base.gens()}) sage: db_simp [ (1-2*q+q^2) (q-q^2) (q-q^2+q^3) (q^2-q^3)] [ (1-q) q 0 0] @@ -2011,19 +2011,20 @@ def deformed_burau_matrix(self, variab='q'): R = LaurentPolynomialRing(IntegerRing(), variab) n = self.strands() m = len(self.Tietze()) - Algebra = FreeAlgebra(R, m*3, [f'{s}p_{i}' - for i in range(m) for s in 'bca' - if self.Tietze()[i] > 0] + [f'{s}m_{i}' - for i in range(m) for s in 'bca' - if self.Tietze()[i] < 0]) - gen_indizes = [i for i in range(m) if self.Tietze()[i] > 0] + \ - [i for i in range(m) if self.Tietze()[i] < 0] - - M = identity_matrix(Algebra, n) + alg = FreeAlgebra(R, m*3, [f'{s}p_{i}' + for i in range(m) if self.Tietze()[i] > 0 + for s in 'bca'] + + [f'{s}m_{i}' + for i in range(m) if self.Tietze()[i] < 0 + for s in 'bca']) + gen_indices = ([i for i in range(m) if self.Tietze()[i] > 0] + + [i for i in range(m) if self.Tietze()[i] < 0]) + + M = identity_matrix(alg, n) for k, i in enumerate(self.Tietze()): - A = identity_matrix(Algebra, n) - gen_index = gen_indizes.index(k) - b, c, a = Algebra.gens()[3*gen_index:3*gen_index+3] + A = identity_matrix(alg, n) + gen_index = gen_indices.index(k) + b, c, a = alg.gens()[3*gen_index:3*gen_index+3] if i > 0: A[i-1, i-1] = a A[i, i] = 0 @@ -2037,14 +2038,14 @@ def deformed_burau_matrix(self, variab='q'): M = M * A return M - @cached_method def _colored_jones_sum(self, N, qword): - r"""Helper function to get the colored Jones polynomial. + r""" + Helper function to get the colored Jones polynomial. INPUT: - - ``N`` -- An integer; the number of colors. - - ``qword`` -- A right quantum word (possibly in unreduced form). + - ``N`` -- integer; the number of colors + - ``qword`` -- a right quantum word (possibly in unreduced form) EXAMPLES:: @@ -2061,7 +2062,7 @@ def _colored_jones_sum(self, N, qword): rqword = RightQuantumWord(qword).reduced_word() alg = qword.parent() R = alg.base_ring() - result = R(1) + result = R.one() current_word = alg(1) i = 1 continue_summing = True @@ -2074,7 +2075,7 @@ def _colored_jones_sum(self, N, qword): current_word = new_rqw.reduced_word() new_eps = new_rqw.eps(N) result += new_eps - if not (new_eps): + if not new_eps: continue_summing = False i += 1 return result @@ -2085,11 +2086,17 @@ def colored_jones_polynomial(self, N, variab=None, try_inverse=True): INPUT: - - ``N`` -- integer; the number of colors. - - ``variab`` -- string (default: ``q``); the variable in the - resulting laurent polynomial. + - ``N`` -- integer; the number of colors + - ``variab`` -- (default: `q`) the variable in the resulting + Laurent polynomial - ``try_inverse`` -- boolean (default: ``True``); if ``True``, - attempt a faster calculation by using the inverse of the braid. + attempt a faster calculation by using the inverse of the braid + + ALGORITHM: + + The algorithm used is described in [HL2018]_. We follow their + notation, but work in a suitable free algebra over a Laurent + polynomial ring in one variable to simplify bookkeeping. EXAMPLES:: @@ -2097,70 +2104,85 @@ def colored_jones_polynomial(self, N, variab=None, try_inverse=True): sage: trefoil.colored_jones_polynomial(2) q + q^3 - q^4 sage: trefoil.colored_jones_polynomial(4) - q^3 + q^7 - q^10 + q^11 - q^13 - q^14 + q^15 - q^17 + q^19 + q^20 - - q^21 + q^3 + q^7 - q^10 + q^11 - q^13 - q^14 + q^15 - q^17 + + q^19 + q^20 - q^21 sage: trefoil.inverse().colored_jones_polynomial(4) - -q^-21 + q^-20 + q^-19 - q^-17 + q^-15 - q^-14 - q^-13 + q^-11 - - q^-10 + q^-7 + q^-3 + -q^-21 + q^-20 + q^-19 - q^-17 + q^-15 - q^-14 - q^-13 + + q^-11 - q^-10 + q^-7 + q^-3 sage: figure_eight = BraidGroup(3)([-1, 2, -1, 2]) sage: figure_eight.colored_jones_polynomial(2) q^-2 - q^-1 + 1 - q + q^2 sage: figure_eight.colored_jones_polynomial(3, 'Q') - Q^-6 - Q^-5 - Q^-4 + 2*Q^-3 - Q^-2 - Q^-1 + 3 - Q - Q^2 + 2*Q^3 - - Q^4 - Q^5 + Q^6 - - ALGORITHM: - - The algorithm used is described in [HL2018]_. We follow their notation, - but work in a suitable free algebra over a Laurent polynomial ring in - one variable to simplify bookkeeping. + Q^-6 - Q^-5 - Q^-4 + 2*Q^-3 - Q^-2 - Q^-1 + 3 - Q - Q^2 + + 2*Q^3 - Q^4 - Q^5 + Q^6 """ if self.components_in_closure() != 1: raise ValueError("the number of components must be 1") + if not hasattr(self, '_cj_with_q'): + # Move to the __init__ if this class adds one + self._cj_with_q = {} + if N in self._cj_with_q: + cj = self._cj_with_q[N] + if variab is None: + return cj + if isinstance(variab, str): + variab = LaurentPolynomialRing(IntegerRing(), variab).gen() + return cj.subs(q=variab) + db = self.deformed_burau_matrix('q')[1:, 1:] q = db.parent().base_ring().base_ring().gen() n = db.ncols() - qword = sum((-1)**(s.cardinality() - 1)*(q*db[list(s), - list(s)]).quantum_determinant(q) + qword = sum((-1)**(s.cardinality() - 1) + * (q * db[list(s), list(s)]).quantum_determinant(q) for s in Subsets(range(n)) if s) inverse_shorter = try_inverse if try_inverse: db_inv = self.inverse().deformed_burau_matrix('q')[1:, 1:] q_inv = db_inv.parent().base_ring().base_ring().gen() - qword_inv = sum((-1)**(s.cardinality() - - 1)*(q_inv*db_inv[list(s), - list(s)]).quantum_determinant(q) + qword_inv = sum((-1)**(s.cardinality() - 1) + * (q_inv*db_inv[list(s), list(s)]).quantum_determinant(q) for s in Subsets(range(n)) if s) # Check if the inverse has a shorter expression at this point inverse_shorter = len(list(qword_inv)) < len(list(qword)) use_inverse = try_inverse and inverse_shorter shorter_qword = qword_inv if use_inverse else qword knot = Knot(self.inverse()) if use_inverse else Knot(self) - cj = q**(((N - 1)*(knot.writhe() - self.strands() + 1))/2) * \ - self._colored_jones_sum(N, shorter_qword).leading_coefficient() - cj_with_q = cj.subs({q: 1/q}) if use_inverse else cj - - # Up to this point, we have calculated everyting with a variable named - # `q` instead of using `variab`, because this allows proper caching in - # `_colored_jones_sum`. Here we do the substitution as necessary. - if not variab: - return cj_with_q - new_q = LaurentPolynomialRing(IntegerRing(), variab).gen() - return cj_with_q.subs({q: new_q}) + cj = (q**((N - 1) * (knot.writhe() - self.strands() + 1) / 2) + * self._colored_jones_sum(N, shorter_qword).leading_coefficient()) + self._cj_with_q[N] = cj.subs({q: 1/q}) if use_inverse else cj + return self.colored_jones_polynomial(N, variab, try_inverse) class RightQuantumWord: - def __init__(self, words): - r""" - An internal class representing right quantum words as in - definition 4.1 of [HL2018]_. + """ + A right quantum word as in Definition 4.1 of [HL2018]_. - INPUT: + INPUT: - - ``words`` -- An element in a suitable free algebra over a Laurent - polynomial ring in one variable. This input does not need to be in - reduced form, but the monomials for the input can come in any order. + - ``words`` -- an element in a suitable free algebra over a Laurent + polynomial ring in one variable; this input does not need to be in + reduced form, but the monomials for the input can come in any order + + EXAMPLES:: + + sage: from sage.groups.braid import RightQuantumWord + sage: fig_8 = BraidGroup(3)([-1, 2, -1, 2]) + sage: ( + ....: bp_1, cp_1, ap_1, + ....: bp_3, cp_3, ap_3, + ....: bm_0, cm_0, am_0, + ....: bm_2, cm_2, am_2 + ....: ) = fig_8.deformed_burau_matrix().parent().base_ring().gens() + sage: q = bp_1.base_ring().gen() + sage: RightQuantumWord(ap_1*cp_1 + q**3*bm_2*bp_1*am_0*cm_0) + The right quantum word represented by + q*cp_1*ap_1 + q^2*bp_1*cm_0*am_0*bm_2 + reduced from ap_1*cp_1 + q^3*bm_2*bp_1*am_0*cm_0 + """ + def __init__(self, words): + r""" + Initialize ``self``. EXAMPLES:: @@ -2173,28 +2195,26 @@ def __init__(self, words): ....: bm_2, cm_2, am_2 ....: ) = fig_8.deformed_burau_matrix().parent().base_ring().gens() sage: q = bp_1.base_ring().gen() - sage: RightQuantumWord(ap_1*cp_1 + q**3*bm_2*bp_1*am_0*cm_0) - The right quantum word represented by - q*cp_1*ap_1 + q^2*bp_1*cm_0*am_0*bm_2 - reduced from ap_1*cp_1 + q^3*bm_2*bp_1*am_0*cm_0 - """ - self._Alg = words.parent() - self.q = self._Alg.base_ring().gen() - self.R = self._Alg.base_ring() + sage: Q = RightQuantumWord(ap_1*cp_1 + q**3*bm_2*bp_1*am_0*cm_0) + sage: TestSuite(Q).run(skip="_test_pickling") + """ + self._algebra = words.parent() + self.q = self._algebra.base_ring().gen() + self.R = self._algebra.base_ring() self._unreduced_words = words - self._tuples = None - self._gens = self._Alg.gens() - self._minus_begin = min((i for i, gen in enumerate(self._gens) if - 'm' in str(gen)), default=len(self._gens)) + self._gens = self._algebra.gens() + self._minus_begin = min((i for i, gen in enumerate(self._gens) if 'm' in str(gen)), + default=len(self._gens)) - def as_tuples(self): + @lazy_attribute + def tuples(self): r""" - Get a representation of the right quantum word as a dict, with + Get a representation of the right quantum word as a ``dict``, with keys monomials in the free algebra represented as tuples and values in elements the Laurent polynomial ring in one variable. - This is in the reduced form as outlines in definition of 4.1 of - [HL2018]_. + This is in the reduced form as outlined in Definition 4.1 + of [HL2018]_. OUTPUT: @@ -2214,39 +2234,34 @@ def as_tuples(self): sage: q = bp_1.base_ring().gen() sage: qw = RightQuantumWord(ap_1*cp_1 + ....: q**3*bm_2*bp_1*am_0*cm_0) - sage: for key, value in qw.as_tuples().items(): + sage: for key, value in qw.tuples.items(): ....: print(key, value) ....: (0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) q (1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0) q^2 """ - if self._tuples: - return self._tuples - self._tuples = collections.defaultdict(self.R) + from collections import defaultdict + ret = defaultdict(self.R) for unreduced_monom, q_power in list(self._unreduced_words): q = self.q ret_tuple = [0] * len(self._gens) for gen, exp in unreduced_monom: gen_index = self._gens.index(gen) - is_minus = gen_index >= self._minus_begin - is_a = not(bool((gen_index+1) % 3)) - is_b = not(bool(gen_index % 3)) - is_c = not(bool((gen_index+2) % 3)) - index = gen_index//3 + is_minus = bool(gen_index >= self._minus_begin) + index = gen_index // 3 # This uses the relations in equations (4.1) and (4.2) # of [HL2018]_. i, j, k = ret_tuple[3*index: 3*index + 3] - if is_a: + if not (gen_index + 1) % 3: # is_a ret_tuple[3*index: 3*index + 3] = [i, j, k + exp] - if is_b: + if not gen_index % 3: # is_b ret_tuple[3*index: 3*index + 3] = [i + exp, j, k] - q_power *= q**(2*(k*exp + j*exp)) if is_minus \ - else q**(-2*j*exp) - if is_c: + q_power *= q**(2*(k*exp + j*exp)) if is_minus else q**(-2*j*exp) + if not (gen_index + 2) % 3: # is_c ret_tuple[3*index: 3*index + 3] = [i, j + exp, k] q_power *= q**(-k*exp) if is_minus else q**(k*exp) - self._tuples[tuple(ret_tuple)] += self._Alg(q_power) - return self._tuples + ret[tuple(ret_tuple)] += self._algebra(q_power) + return ret def reduced_word(self): r""" @@ -2254,7 +2269,7 @@ def reduced_word(self): OUTPUT: - An element in the free algebra self._Alg. + An element in the free algebra. EXAMPLES:: @@ -2272,9 +2287,9 @@ def reduced_word(self): sage: qw.reduced_word() q*cp_1*ap_1 + q^2*bp_1*cm_0*am_0*bm_2 - TESTS:: + TESTS: - Testing the equations (4.1) and (4.2) in [HL2018]_. + Testing the equations (4.1) and (4.2) in [HL2018]_:: sage: RightQuantumWord(ap_3*bp_3).reduced_word() bp_3*ap_3 @@ -2290,21 +2305,23 @@ def reduced_word(self): q^2*bm_2*cm_2 .. TODO:: + Paralellize this function, calculating all summands in the sum in parallel. """ def tuple_to_word(q_tuple): - return prod(self._gens[i]**exp + return prod(self._gens[i] ** exp for i, exp in enumerate(q_tuple)) - return sum(q_factor*tuple_to_word(q_tuple) - for q_tuple, q_factor in self.as_tuples().items()) + return sum(q_factor * tuple_to_word(q_tuple) + for q_tuple, q_factor in self.tuples.items()) def eps(self, N): - r"""Evaluate the map $\mathcal{E}_N$ for a braid. + r""" + Evaluate the map `\mathcal{E}_N` for a braid. INPUT: - - ``N`` -- an integer; the number of colors. + - ``N`` -- an integer; the number of colors EXAMPLES:: @@ -2342,7 +2359,7 @@ def eps_monom(q_tuple): for rj in range(self._minus_begin + 1, len(q_tuple), 3)) ret_q *= prod(prod(1 - q**(N - 1 - q_tuple[3*i + 1] - h) - for h in range(0, q_tuple[3*i + 2])) + for h in range(q_tuple[3*i + 2])) for i in range(self._minus_begin//3)) ret_q *= prod(prod(1 - q**(q_tuple[3*j + 1] + l + 1 - N) for l in range(q_tuple[3*j + 2])) @@ -2350,12 +2367,12 @@ def eps_monom(q_tuple): len(q_tuple)//3)) return ret_q - return sum(q_factor*eps_monom(q_tuple) - for q_tuple, q_factor in self.as_tuples().items()) + return sum(q_factor * eps_monom(q_tuple) + for q_tuple, q_factor in self.tuples.items()) def __repr__(self): r""" - String representation of the reight quantum word. + String representation of ``self``. EXAMPLES:: @@ -2367,9 +2384,9 @@ def __repr__(self): The right quantum word represented by cp_1*bp_3*am_2 reduced from cp_1*am_2*bp_3 """ - return 'The right quantum word represented by ' + \ - f'{str(self.reduced_word())} reduced from ' + \ - f'{str(self._unreduced_words)}' + return ('The right quantum word represented by ' + + f'{str(self.reduced_word())} reduced from ' + + f'{str(self._unreduced_words)}') class BraidGroup_class(FiniteTypeArtinGroup): From bac98e5dfbd758c3f67111be6ee1a6843c40c704 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 8 Oct 2021 10:54:12 +0900 Subject: [PATCH 497/511] Adding colored Jones polynomial to knots. --- src/sage/knots/knot.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/sage/knots/knot.py b/src/sage/knots/knot.py index 358868c2565..10f0e241608 100644 --- a/src/sage/knots/knot.py +++ b/src/sage/knots/knot.py @@ -74,6 +74,8 @@ class Knot(Link, Element, metaclass=InheritComparisonClasscallMetaclass): 31 sage: K.signature() -2 + sage: K.colored_jones_polynomial(2) # long time + q^-1 - 2 + 4*q - 5*q^2 + 6*q^3 - 5*q^4 + 4*q^5 - 3*q^6 + q^7 REFERENCES: @@ -349,6 +351,44 @@ def arf_invariant(self): return 0 return 1 + def colored_jones_polynomial(self, N, variab=None, try_inverse=True): + r""" + Return the colored Jones polynomial of the trace closure of the braid. + + INPUT: + + - ``N`` -- integer; the number of colors + - ``variab`` -- (default: `q`) the variable in the resulting + Laurent polynomial + - ``try_inverse`` -- boolean (default: ``True``); if ``True``, + attempt a faster calculation by using the inverse of the braid + + ALGORITHM: + + The algorithm used is described in [HL2018]_ for the corresponding + braid representation. We follow their notation, but work in a + suitable free algebra over a Laurent polynomial ring in one + variable to simplify bookkeeping. + + EXAMPLES:: + + sage: W = Knots() + sage: K = W.from_dowker_code([-4,-6,-2]) + sage: K.colored_jones_polynomial(2) + -q^-4 + q^-3 + q^-1 + sage: K.colored_jones_polynomial(2, 't') + -t^-4 + t^-3 + t^-1 + sage: R. = LaurentPolynomialRing(ZZ) + sage: K.colored_jones_polynomial(2, -t) + -t^-4 - t^-3 - t^-1 + + sage: R. = ZZ[] + sage: K.colored_jones_polynomial(2, t+1) + (t^3 + 3*t^2 + 4*t + 1)/(t^4 + 4*t^3 + 6*t^2 + 4*t + 1) + """ + return self.braid().colored_jones_polynomial(N=N, variab=variab, + try_inverse=try_inverse) + def connected_sum(self, other): r""" Return the oriented connected sum of ``self`` and ``other``. From 93cc25eefa6587c24d05d88f8dab86c83305efce Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 8 Oct 2021 11:16:13 +0900 Subject: [PATCH 498/511] Speedup of RightQuantumWord.tuples computation. --- src/sage/groups/braid.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index fe55c7d235a..89b116f1500 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -72,7 +72,6 @@ from sage.misc.lazy_import import lazy_import from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod -from sage.algebras.free_algebra import FreeAlgebra from sage.categories.groups import Groups from sage.groups.free_group import FreeGroup, is_FreeGroup from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing @@ -2011,6 +2010,7 @@ def deformed_burau_matrix(self, variab='q'): R = LaurentPolynomialRing(IntegerRing(), variab) n = self.strands() m = len(self.Tietze()) + from sage.algebras.free_algebra import FreeAlgebra alg = FreeAlgebra(R, m*3, [f'{s}p_{i}' for i in range(m) if self.Tietze()[i] > 0 for s in 'bca'] @@ -2203,6 +2203,7 @@ def __init__(self, words): self.R = self._algebra.base_ring() self._unreduced_words = words self._gens = self._algebra.gens() + self._gens_index = {g: i for i, g in enumerate(self._algebra._indices.gens())} self._minus_begin = min((i for i, gen in enumerate(self._gens) if 'm' in str(gen)), default=len(self._gens)) @@ -2219,7 +2220,7 @@ def tuples(self): OUTPUT: A dict of tuples of ints corresponding to the exponents in the - generators self._gens(), with values in self.R. + generators with values in the algebra's base ring. EXAMPLES:: @@ -2246,7 +2247,7 @@ def tuples(self): q = self.q ret_tuple = [0] * len(self._gens) for gen, exp in unreduced_monom: - gen_index = self._gens.index(gen) + gen_index = self._gens_index[gen] is_minus = bool(gen_index >= self._minus_begin) index = gen_index // 3 # This uses the relations in equations (4.1) and (4.2) From 2121743b84b822c443a4e1d45081d39244191aa6 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 8 Oct 2021 11:33:51 +0900 Subject: [PATCH 499/511] Further speedup to colored_jones_polynomial(). --- src/sage/groups/braid.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 89b116f1500..ab9d1ad92ba 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -2053,17 +2053,17 @@ def _colored_jones_sum(self, N, qword): sage: db = b.deformed_burau_matrix()[1:,1:]; db [cp_0*ap_1*bp_2] sage: b._colored_jones_sum(2, db[0,0]) - (1+q-q^2) + 1 + q - q^2 sage: b._colored_jones_sum(3, db[0,0]) - (1+q^2-q^5-q^6+q^7) + 1 + q^2 - q^5 - q^6 + q^7 sage: b._colored_jones_sum(4, db[0,0]) - (1+q^3-q^8-q^10+q^13+q^14-q^15) + 1 + q^3 - q^8 - q^10 + q^13 + q^14 - q^15 """ rqword = RightQuantumWord(qword).reduced_word() alg = qword.parent() R = alg.base_ring() result = R.one() - current_word = alg(1) + current_word = alg.one() i = 1 continue_summing = True # This seemingly infinite sum is always finite if the qword comes @@ -2149,7 +2149,7 @@ def colored_jones_polynomial(self, N, variab=None, try_inverse=True): shorter_qword = qword_inv if use_inverse else qword knot = Knot(self.inverse()) if use_inverse else Knot(self) cj = (q**((N - 1) * (knot.writhe() - self.strands() + 1) / 2) - * self._colored_jones_sum(N, shorter_qword).leading_coefficient()) + * self._colored_jones_sum(N, shorter_qword)) self._cj_with_q[N] = cj.subs({q: 1/q}) if use_inverse else cj return self.colored_jones_polynomial(N, variab, try_inverse) @@ -2202,8 +2202,8 @@ def __init__(self, words): self.q = self._algebra.base_ring().gen() self.R = self._algebra.base_ring() self._unreduced_words = words - self._gens = self._algebra.gens() - self._gens_index = {g: i for i, g in enumerate(self._algebra._indices.gens())} + self._gens = self._algebra._indices.gens() + self._gens_index = {g: i for i, g in enumerate(self._gens)} self._minus_begin = min((i for i, gen in enumerate(self._gens) if 'm' in str(gen)), default=len(self._gens)) @@ -2261,7 +2261,7 @@ def tuples(self): if not (gen_index + 2) % 3: # is_c ret_tuple[3*index: 3*index + 3] = [i, j + exp, k] q_power *= q**(-k*exp) if is_minus else q**(k*exp) - ret[tuple(ret_tuple)] += self._algebra(q_power) + ret[tuple(ret_tuple)] += q_power return ret def reduced_word(self): @@ -2310,11 +2310,13 @@ def reduced_word(self): Paralellize this function, calculating all summands in the sum in parallel. """ + M = self._algebra._indices def tuple_to_word(q_tuple): - return prod(self._gens[i] ** exp - for i, exp in enumerate(q_tuple)) - return sum(q_factor * tuple_to_word(q_tuple) - for q_tuple, q_factor in self.tuples.items()) + return M.prod(self._gens[i] ** exp + for i, exp in enumerate(q_tuple)) + ret = {tuple_to_word(q_tuple): q_factor + for q_tuple, q_factor in self.tuples.items() if q_factor} + return self._algebra._from_dict(ret, remove_zeros=False) def eps(self, N): r""" @@ -2338,9 +2340,9 @@ def eps(self, N): sage: rqw = RightQuantumWord( ....: q^3*bp_2*bp_0*ap_0 + q*ap_3*bm_1*am_1*bp_0) sage: rqw.eps(3) - -(q^-1-2*q+q^5) + -q^-1 + 2*q - q^5 sage: rqw.eps(2) - -(1-2*q+q^2-q^3+q^4) + -1 + 2*q - q^2 + q^3 - q^4 TESTS:: @@ -2348,6 +2350,7 @@ def eps(self, N): 0 .. TODO:: + Paralellize this function, calculating all summands in the sum in parallel. """ From 524906e03f6dec6be462b7210289c2bf2a5ffcf9 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Thu, 21 Oct 2021 16:27:59 +0200 Subject: [PATCH 500/511] fix q_inv typo --- src/sage/groups/braid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index ab9d1ad92ba..b61f8f330a7 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -2141,7 +2141,7 @@ def colored_jones_polynomial(self, N, variab=None, try_inverse=True): db_inv = self.inverse().deformed_burau_matrix('q')[1:, 1:] q_inv = db_inv.parent().base_ring().base_ring().gen() qword_inv = sum((-1)**(s.cardinality() - 1) - * (q_inv*db_inv[list(s), list(s)]).quantum_determinant(q) + * (q_inv*db_inv[list(s), list(s)]).quantum_determinant(q_inv) for s in Subsets(range(n)) if s) # Check if the inverse has a shorter expression at this point inverse_shorter = len(list(qword_inv)) < len(list(qword)) From d2722d0b1128b578fc6e88d144f8a8af21cc9805 Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Thu, 21 Oct 2021 17:07:48 +0200 Subject: [PATCH 501/511] fix botched rebase --- src/sage/groups/braid.py | 214 --------------------------------------- 1 file changed, 214 deletions(-) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index b61f8f330a7..a6e53f2e1a1 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -1702,7 +1702,6 @@ def sliding_circuits(self): B = self.parent() return [[B._element_from_libbraiding(i) for i in s] for s in slc] -<<<<<<< HEAD def mirror_image(self): r""" Return the image of ``self`` under the mirror involution (see @@ -1742,220 +1741,7 @@ def reverse(self): t.reverse() return self.parent()(tuple(t)) - class _RightQuantumWord: - def __init__(self, words): - r""" - An internal class representing right quantum words as in - definition 4.1 of [HL2018]_. - - INPUT: - - ``words`` -- An element in a suitable free algebra over a - Laurent polynomial ring in one variable. This input does not - need to be in reduced form, but the monomials for the input - can come in any order. - - EXAMPLES:: - - sage: figure_8 = BraidGroup(3)([-1, 2, -1, 2]) - sage: ( - ....: bp_1, cp_1, ap_1, - ....: bp_3, cp_3, ap_3, - ....: bm_0, cm_0, am_0, - ....: bm_2, cm_2, am_2 - ....: ) = figure_8._deformed_burau_matrix().parent().base_ring().gens() - sage: q = bp_1.base_ring().gen() - sage: figure_8._RightQuantumWord(ap_1*cp_1 + - ....: q**3*bm_2*bp_1*am_0*cm_0) - The right quantum word represented by q*cp_1*ap_1 + q^2*bp_1*cm_0*am_0*bm_2 reduced from ap_1*cp_1 + q^3*bm_2*bp_1*am_0*cm_0 - """ - self._Alg = words.parent() - self.q = self._Alg.base_ring().gen() - self.R = self._Alg.base_ring() - self._unreduced_words = words - self._tuples = None - self._gens = self._Alg.gens() - self._minus_begin = min((i for i, gen in enumerate(self._gens) if - 'm' in str(gen)), default=len(self._gens)) - - def as_tuples(self): - r""" - Get a representation of the right quantum word as a dict, with - keys monomials in the free algebra represented as tuples and - values in elements the Laurent polynomial ring in one variable. - - This is in the reduced form as outlines in definition of 4.1 of - [HL2018]_. - - OUTPUT: - A dict of tuples of ints corresponding to the exponents in the - generators self._gens(), with values in self.R. - - EXAMPLES:: - - sage: figure_8 = BraidGroup(3)([-1, 2, -1, 2]) - sage: ( - ....: bp_1, cp_1, ap_1, - ....: bp_3, cp_3, ap_3, - ....: bm_0, cm_0, am_0, - ....: bm_2, cm_2, am_2 - ....: ) = figure_8._deformed_burau_matrix().parent().base_ring().gens() - sage: q = bp_1.base_ring().gen() - sage: qw = figure_8._RightQuantumWord(ap_1*cp_1 + - ....: q**3*bm_2*bp_1*am_0*cm_0) - sage: for key, value in qw.as_tuples().items(): - ....: print(key, value) - ....: - (0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0) q - (1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0) q^2 - """ - if self._tuples: - return self._tuples - self._tuples = collections.defaultdict(self.R) - for unreduced_monom, q_power in list(self._unreduced_words): - q = self.q - ret_tuple = [0] * len(self._gens) - for gen, exp in unreduced_monom: - gen_index = self._gens.index(gen) - is_minus = gen_index >= self._minus_begin - is_a = not(bool((gen_index+1) % 3)) - is_b = not(bool(gen_index % 3)) - is_c = not(bool((gen_index+2) % 3)) - index = gen_index//3 - # This uses the relations in equations (4.1) and (4.2) - # of [HL2018]_. - i, j, k = ret_tuple[3*index: 3*index + 3] - if is_a: - ret_tuple[3*index: 3*index + 3] = [i, j, k + exp] - if is_b: - ret_tuple[3*index: 3*index + 3] = [i + exp, j, k] - q_power *= q**(2*(k*exp + j*exp)) if is_minus \ - else q**(-2*j*exp) - if is_c: - ret_tuple[3*index: 3*index + 3] = [i, j + exp, k] - q_power *= q**(-k*exp) if is_minus else q**(k*exp) - self._tuples[tuple(ret_tuple)] += self._Alg(q_power) - return self._tuples - - def reduced_word(self): - r""" - Return the (reduced) right quantum word. - - OUTPUT: - An element in the free algebra self._Alg. - - EXAMPLES:: - - sage: figure_8 = BraidGroup(3)([-1, 2, -1, 2]) - sage: ( - ....: bp_1, cp_1, ap_1, - ....: bp_3, cp_3, ap_3, - ....: bm_0, cm_0, am_0, - ....: bm_2, cm_2, am_2 - ....: ) = figure_8._deformed_burau_matrix().parent().base_ring().gens() - sage: q = bp_1.base_ring().gen() - sage: qw = figure_8._RightQuantumWord(ap_1*cp_1 + - ....: q**3*bm_2*bp_1*am_0*cm_0) - sage: qw.reduced_word() - q*cp_1*ap_1 + q^2*bp_1*cm_0*am_0*bm_2 - - TESTS:: - - Testing the equations (4.1) and (4.2) in [HL2018]_. - - sage: figure_8._RightQuantumWord(ap_3*bp_3).reduced_word() - bp_3*ap_3 - sage: figure_8._RightQuantumWord(ap_3*cp_3).reduced_word() - q*cp_3*ap_3 - sage: figure_8._RightQuantumWord(cp_3*bp_3).reduced_word() - (q^-2)*bp_3*cp_3 - sage: figure_8._RightQuantumWord(am_2*bm_2).reduced_word() - q^2*bm_2*am_2 - sage: figure_8._RightQuantumWord(am_2*cm_2).reduced_word() - (q^-1)*cm_2*am_2 - sage: figure_8._RightQuantumWord(cm_2*bm_2).reduced_word() - q^2*bm_2*cm_2 - - .. TODO:: - Paralellize this function, calculating all summands in the sum - in parallel. - """ - def tuple_to_word(q_tuple): - return prod(self._gens[i]**exp - for i, exp in enumerate(q_tuple)) - return sum(q_factor*tuple_to_word(q_tuple) - for q_tuple, q_factor in self.as_tuples().items()) - - def eps(self, N): - r"""Evaluate the map $\mathcal{E}_N$ for a braid. - - INPUT: - - ``N`` -- an integer; the number of colors. - - EXAMPLES:: - - sage: B = BraidGroup(3) - sage: b = B([1,-2,1,2]) - sage: db = b._deformed_burau_matrix()[:, :] - sage: q = db.parent().base_ring().base_ring().gen() - sage: (bp_0, cp_0, ap_0, - ....: bp_2, cp_2, ap_2, - ....: bp_3, cp_3, ap_3, - ....: bm_1, cm_1, am_1) = db.parent().base_ring().gens() - sage: rqw = b._RightQuantumWord( - ....: q^3*bp_2*bp_0*ap_0 + q*ap_3*bm_1*am_1*bp_0) - sage: rqw.eps(3) - -(q^-1-2*q+q^5) - sage: rqw.eps(2) - -(1-2*q+q^2-q^3+q^4) - - TESTS:: - - sage: rqw.eps(1) - 0 - - .. TODO:: - Paralellize this function, calculating all summands in the sum - in parallel. - """ - def eps_monom(q_tuple): - q = self.q - r"""Evaluate the map $\mathcal{E}_N$ for a single mononial.""" - ret_q = q**sum((N - 1 - q_tuple[3*i + 2])*q_tuple[3*i + 1] - for i in range(self._minus_begin//3)) - ret_q *= q**sum((N - 1)*(-q_tuple[rj]) - for rj in range(self._minus_begin + 1, - len(q_tuple), 3)) - ret_q *= prod(prod(1 - q**(N - 1 - q_tuple[3*i + 1] - h) - for h in range(0, q_tuple[3*i + 2])) - for i in range(self._minus_begin//3)) - ret_q *= prod(prod(1 - q**(q_tuple[3*j + 1] + l + 1 - N) - for l in range(q_tuple[3*j + 2])) - for j in range(self._minus_begin//3, - len(q_tuple)//3)) - return ret_q - - return sum(q_factor*eps_monom(q_tuple) - for q_tuple, q_factor in self.as_tuples().items()) - - def __repr__(self): - r""" - String representation of the reight quantum word. - - EXAMPLES:: - sage: b = BraidGroup(3)([1,2,-1,2,-1]) - sage: db = b._deformed_burau_matrix(); db[2,2] - cp_1*am_2*bp_3 - sage: b._RightQuantumWord(db[2,2]) - The right quantum word represented by cp_1*bp_3*am_2 reduced from cp_1*am_2*bp_3 - """ - return 'The right quantum word represented by ' + \ - f'{str(self.reduced_word())} reduced from ' + \ - f'{str(self._unreduced_words)}' - - def _deformed_burau_matrix(self, variab='q'): -======= def deformed_burau_matrix(self, variab='q'): ->>>>>>> 062a9e9a44 (first round of review comments) r""" Return the deformed Burau matrix of the braid. From f76ae2c8207453e8ace5214861960c3f0500d1fd Mon Sep 17 00:00:00 2001 From: Moritz Firsching Date: Fri, 22 Oct 2021 09:18:30 +0200 Subject: [PATCH 502/511] chnage order of indices in quantum det doc test --- src/sage/matrix/matrix2.pyx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 75d8dc56424..6d8c3fd33e4 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -2136,15 +2136,13 @@ cdef class Matrix(Matrix1): EXAMPLES:: - sage: A = matrix([[SR(f'a{i}{j}') for i in range(2)] - ....: for j in range(2)]); A - [a00 a10] - [a01 a11] + sage: A = matrix(SR, 2, lambda i, j: f'a{i}{j}'); A + [a00 a01] + [a10 a11] sage: A.quantum_determinant() -a01*a10*q + a00*a11 - sage: A = matrix([[SR(f'a{i}{j}') for i in range(3)] - ....: for j in range(3)]) + sage: A = matrix(SR, 3, lambda i, j: f'a{i}{j}') sage: A.quantum_determinant() -a02*a11*a20*q^3 + (a01*a12*a20 + a02*a10*a21)*q^2 + (-a00*a12*a21 - a01*a10*a22)*q + a00*a11*a22 From e21c9bc0be543344e721fff2c1227a138456505d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 22 Oct 2021 15:01:49 +0200 Subject: [PATCH 503/511] remove non-existing links --- src/doc/it/tutorial/tour_algebra.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/doc/it/tutorial/tour_algebra.rst b/src/doc/it/tutorial/tour_algebra.rst index e17a93dde8a..20ee65727fa 100644 --- a/src/doc/it/tutorial/tour_algebra.rst +++ b/src/doc/it/tutorial/tour_algebra.rst @@ -251,8 +251,6 @@ Le singole componenti possono essere tracciate usando:: sage: p2 = plot(4*cos(t) - cos(2*t), 0, 2*pi, rgbcolor=hue(0.6)) sage: show(p1 + p2) -(Per ulteriori informazioni sul disegno di funzioni, si veda :ref:`section-plot`.) - BIBLIOGRAFIA: Nagle, Saff, Snider, Fundamentals of Differential Equations, 6th ed, Addison-Wesley, 2004. (si veda § 5.5). @@ -357,8 +355,6 @@ come mostrato qui in seguito: sage: show(P[0] + P[1]) -(Per ulteriori informazioni sul disegno di grafici, si veda :ref:`section-plot`.) - Funzioni speciali ----------------- From 364305235fb2b80536fc2dcb21185c84e8396250 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 23 Oct 2021 18:43:10 -0700 Subject: [PATCH 504/511] src/sage/rings/abc.pyx: Restore lost RealField --- src/sage/rings/abc.pyx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index 10073c6bcf9..e9beb3310ff 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -35,6 +35,14 @@ class AlgebraicField(AlgebraicField_common): class AlgebraicRealField(AlgebraicField_common): + r""" + Abstract base class for :class:`~sage.rings.qqbar.AlgebraicRealField`. + """ + + pass + + +cdef class RealField(Field): r""" Abstract base class for :class:`~sage.rings.real_mpfr.RealField_class`. """ From 57e8e9bc41c8e41eca5cad8879e67ba49089a4f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 19 Oct 2021 17:00:54 +0200 Subject: [PATCH 505/511] simple-minded check for string input of CC --- src/sage/interfaces/singular.py | 4 ++-- src/sage/rings/complex_mpfr.pyx | 18 +++++++++++++++++- .../schemes/elliptic_curves/period_lattice.py | 19 ++++++++++--------- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 4c5cf3dfd6b..d7718b7aaf3 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -1576,10 +1576,10 @@ def sage_global_ring(self): '' sage: R = singular('r5').sage_global_ring(); R Multivariate Polynomial Ring in a, b, c over Complex Field with 54 bits of precision - sage: R.base_ring()('j') + sage: R.base_ring()('k') Traceback (most recent call last): ... - NameError: name 'j' is not defined + ValueError: given string 'k' is not a complex number sage: R.base_ring()('I') 1.00000000000000*I diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index b419914f23f..3f072dea133 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -499,15 +499,31 @@ class ComplexField_class(sage.rings.abc.ComplexField): sage: CC(i) 1.00000000000000*I + TESTS:: + + sage: CC('1.2+3.4*j') + 1.20000000000000 + 3.40000000000000*I + sage: CC('hello') + Traceback (most recent call last): + ... + ValueError: given string 'hello' is not a complex number """ if not isinstance(x, (RealNumber, tuple)): if isinstance(x, ComplexDoubleElement): return ComplexNumber(self, x.real(), x.imag()) elif isinstance(x, str): + x = x.replace(' ', '') + x = x.replace('i', 'I') + x = x.replace('j', 'I') + x = x.replace('E', 'e') + allowed = '+-.*0123456789Ie' + if not all(letter in allowed for letter in x): + raise ValueError(f'given string {x!r} is not a complex number') + # This should rather use a proper parser to validate input. # TODO: this is probably not the best and most # efficient way to do this. -- Martin Albrecht return ComplexNumber(self, - sage_eval(x.replace(' ',''), locals={"I":self.gen(),"i":self.gen()})) + sage_eval(x, locals={"I": self.gen()})) late_import() if isinstance(x, NumberFieldElement_quadratic): diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 8ecd30c848c..812aee93b21 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -204,12 +204,12 @@ def __init__(self, E, embedding=None): K = E.base_field() if embedding is None: embs = K.embeddings(AA) - real = len(embs)>0 + real = len(embs) > 0 if not real: embs = K.embeddings(QQbar) embedding = embs[0] else: - embedding = refine_embedding(embedding,Infinity) + embedding = refine_embedding(embedding, Infinity) real = embedding(K.gen()).imag().is_zero() self.embedding = embedding @@ -1802,7 +1802,7 @@ def elliptic_exponential(self, z, to_curve=True): z = C(z) z_is_real = z.is_real() except TypeError: - raise TypeError("%s is not a complex number"%z) + raise TypeError("%s is not a complex number" % z) prec = C.precision() # test for the point at infinity: @@ -1813,7 +1813,7 @@ def elliptic_exponential(self, z, to_curve=True): if to_curve: return self.curve().change_ring(K)(0) else: - return (K('+infinity'), K('+infinity')) + return K(Infinity), K(Infinity) # general number field code (including QQ): @@ -1830,7 +1830,7 @@ def elliptic_exponential(self, z, to_curve=True): # the same precision as the input. x, y = pari(self.basis(prec=prec)).ellwp(z, flag=1) - x, y = [C(t) for t in (x,y)] + x, y = [C(t) for t in (x, y)] if self.real_flag and z_is_real: x = x.real() @@ -1839,14 +1839,15 @@ def elliptic_exponential(self, z, to_curve=True): if to_curve: K = x.parent() v = refine_embedding(self.embedding, Infinity) - a1,a2,a3,a4,a6 = [K(v(a)) for a in self.E.ainvs()] + a1, a2, a3, a4, a6 = [K(v(a)) for a in self.E.ainvs()] b2 = K(v(self.E.b2())) x = x - b2 / 12 y = (y - (a1 * x + a3)) / 2 - EK = EllipticCurve(K,[a1,a2,a3,a4,a6]) - return EK.point((x,y,K(1)), check=False) + EK = EllipticCurve(K, [a1, a2, a3, a4, a6]) + return EK.point((x, y, K.one()), check=False) else: - return (x,y) + return (x, y) + def reduce_tau(tau): r""" From 76d3bfd238e890d1fc8709c99ab9502b47f72078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 24 Oct 2021 18:54:20 +0200 Subject: [PATCH 506/511] fix pycodestyle E713 and E714 in rings --- src/sage/rings/complex_interval_field.py | 8 +++---- src/sage/rings/derivation.py | 2 +- src/sage/rings/function_field/divisor.py | 2 +- .../rings/function_field/function_field.py | 6 ++--- src/sage/rings/function_field/order.py | 2 +- src/sage/rings/function_field/place.py | 4 ++-- src/sage/rings/invariants/reconstruction.py | 3 +-- .../polynomial/infinite_polynomial_ring.py | 4 ++-- .../polynomial/multi_polynomial_ideal.py | 2 +- .../polynomial_padic_capped_relative_dense.py | 22 +++++++++---------- .../padics/polynomial_padic_flat.py | 2 +- .../polynomial/polynomial_quotient_ring.py | 4 ++-- .../polynomial_quotient_ring_element.py | 2 +- src/sage/rings/polynomial/polynomial_ring.py | 2 +- .../polynomial/polynomial_ring_constructor.py | 6 ++--- src/sage/rings/power_series_ring.py | 3 +-- src/sage/rings/quotient_ring.py | 2 +- src/sage/rings/rational_field.py | 4 ++-- 18 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index 013977aa338..991398f4735 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -25,15 +25,15 @@ ``+/-1``. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.parent import Parent @@ -94,7 +94,7 @@ def ComplexIntervalField(prec=53, names=None): if prec in cache: X = cache[prec] C = X() - if not C is None: + if C is not None: return C C = ComplexIntervalField_class(prec) cache[prec] = weakref.ref(C) diff --git a/src/sage/rings/derivation.py b/src/sage/rings/derivation.py index 39b27c5d16e..f719b711c45 100644 --- a/src/sage/rings/derivation.py +++ b/src/sage/rings/derivation.py @@ -247,7 +247,7 @@ def __init__(self, domain, codomain, twist=None): TypeError: the domain of the derivation must coerce to the domain of the twisting homomorphism """ - if not domain in Rings().Commutative(): + if domain not in Rings().Commutative(): raise TypeError("the domain must be a commutative ring") if codomain in Rings().Commutative() and codomain.has_coerce_map_from(domain): diff --git a/src/sage/rings/function_field/divisor.py b/src/sage/rings/function_field/divisor.py index 78a45efa2ea..7fd34197c1c 100644 --- a/src/sage/rings/function_field/divisor.py +++ b/src/sage/rings/function_field/divisor.py @@ -456,7 +456,7 @@ def multiplicity(self, place): sage: D.multiplicity(p2) -3 """ - if not place in self._data: + if place not in self._data: return 0 return self._data[place] diff --git a/src/sage/rings/function_field/function_field.py b/src/sage/rings/function_field/function_field.py index 6c2945fbc64..9ab0c4de872 100644 --- a/src/sage/rings/function_field/function_field.py +++ b/src/sage/rings/function_field/function_field.py @@ -2893,7 +2893,7 @@ def places_above(self, p): """ R = self.base_field() - if not p in R.place_set(): + if p not in R.place_set(): raise TypeError("not a place of the base rational function field") if p.is_infinite_place(): @@ -3372,9 +3372,9 @@ def _weierstrass_places(self): gaps = [1] while M.nrows() < d: row = vector([der._derive(basis[i], e) for i in range(d)]) - if not row in M.row_space(): + if row not in M.row_space(): M = matrix(M.rows() + [row]) - gaps.append(e+1) + gaps.append(e + 1) e += 1 # This is faster than M.determinant(). Note that Mx diff --git a/src/sage/rings/function_field/order.py b/src/sage/rings/function_field/order.py index fd6a09ff9cb..ebe610bc504 100644 --- a/src/sage/rings/function_field/order.py +++ b/src/sage/rings/function_field/order.py @@ -1997,7 +1997,7 @@ def decomposition(self, ideal): row.append( V([to(e) for e in self._mtable[i][j]]) ) mtable.append(row) - if not p in self._kummer_places: + if p not in self._kummer_places: ##################################### # Decomposition by Kummer's theorem # ##################################### diff --git a/src/sage/rings/function_field/place.py b/src/sage/rings/function_field/place.py index 43abc67a6fb..f3400e76bdb 100644 --- a/src/sage/rings/function_field/place.py +++ b/src/sage/rings/function_field/place.py @@ -759,7 +759,7 @@ def _gaps_wronskian(self): gaps = [1] while M.nrows() < d: row = vector([to_R(der._derive(basis[i], e, sep)) for i in range(d)]) - if not row in M.row_space(): + if row not in M.row_space(): M = matrix(M.rows() + [row]) M.echelonize() gaps.append(e + 1) @@ -1065,7 +1065,7 @@ def from_K(e): alpha_powered_by_ramification_index = alpha ** prime._ramification_index def to_K(f): - if not f in O: + if f not in O: den = O.coordinate_vector(f).denominator() num = den * f diff --git a/src/sage/rings/invariants/reconstruction.py b/src/sage/rings/invariants/reconstruction.py index b9db4e07521..68126305ba4 100644 --- a/src/sage/rings/invariants/reconstruction.py +++ b/src/sage/rings/invariants/reconstruction.py @@ -383,8 +383,7 @@ def _reduce_invariants(invariants, weights): for prime in gcd(invariants).factor(): p = prime[0] for D in factors: - if not p in D: + if p not in D: D[p] = 0 scalar = scalar*p**min([factors[i][p]//weights[i] for i in range(n)]) return [invariants[i]*scalar**-weights[i] for i in range(n)] - diff --git a/src/sage/rings/polynomial/infinite_polynomial_ring.py b/src/sage/rings/polynomial/infinite_polynomial_ring.py index 3cf225c8cfe..84577be8e2b 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_ring.py +++ b/src/sage/rings/polynomial/infinite_polynomial_ring.py @@ -709,11 +709,11 @@ def __init__(self, R, names, order): self._names = tuple(names) if not isinstance(order, str): raise TypeError("The monomial order must be given as a string") - if not R in Rings().Commutative(): + if R not in Rings().Commutative(): raise TypeError("The given 'base ring' (= %s) must be a commutative ring" % R) # now, the input is accepted - if hasattr(R,'_underlying_ring'): + if hasattr(R, '_underlying_ring'): self._underlying_ring = R._underlying_ring else: self._underlying_ring = R.base_ring() diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 560dcc8c25d..07e0656baa5 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2238,7 +2238,7 @@ def quotient(self, J): if not isinstance(J, MPolynomialIdeal): raise TypeError("J needs to be a multivariate polynomial ideal") - if not R is J.ring() and not R == J.ring(): + if R is not J.ring() and not R == J.ring(): raise TypeError("base rings do not match") from sage.libs.singular.function_factory import ff 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 13d09467427..1fcfa993bca 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 @@ -87,7 +87,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct = False, #We now coerce various types into lists of coefficients. There are fast pathways for some types of polynomials if isinstance(x, Polynomial): if x.parent() is self.parent(): - if not absprec is infinity or not relprec is infinity: + if absprec is not infinity or relprec is not infinity: x._normalize() self._poly = x._poly self._valbase = x._valbase @@ -95,7 +95,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct = False, self._relprecs = x._relprecs self._normalized = x._normalized self._list = x._list - if not absprec is infinity or not relprec is infinity: + if absprec is not infinity or relprec is not infinity: self._adjust_prec_info(absprec, relprec) return elif x.base_ring() is ZZ: @@ -106,7 +106,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct = False, self._comp_valaddeds() self._normalized = len(self._valaddeds) == 0 or (min(self._valaddeds) == 0) self._list = None - if not absprec is infinity or not relprec is infinity: + if absprec is not infinity or relprec is not infinity: self._adjust_prec_info(absprec, relprec) return else: @@ -147,14 +147,14 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct = False, self._relprecs = [] self._poly = PolynomialRing(ZZ, parent.variable_name())() self._normalized = True - if not absprec is infinity or not relprec is infinity: + if absprec is not infinity or relprec is not infinity: self._adjust_prec_info(absprec, relprec) else: self._valaddeds = [c - self._valbase for c in self._valaddeds] self._relprecs = [a.precision_absolute() - self._valbase for a in x] self._poly = PolynomialRing(ZZ, parent.variable_name())([a >> self._valbase for a in x]) self._normalized = True - if not absprec is infinity or not relprec is infinity: + if absprec is not infinity or relprec is not infinity: self._adjust_prec_info(absprec, relprec) def _new_constant_poly(self, a, P): @@ -702,21 +702,21 @@ def _unsafe_mutate(self, n, value): self._poly._unsafe_mutate(self, n, 0) if n < len(self._relprecs): self._relprecs[n] = value.precision_absolute() - self._valbase - if not self._valaddeds is None: + if self._valaddeds is not None: self._valaddeds[n] = value.valuation() - self._valbase - if not self._list is None: + if self._list is not None: self._list[n] = value else: self._relprecs.extend([infinity] * (n - len(self._relprecs)) + [value.precision_absolute() - self._valbase]) - if not self._valaddeds is None: + if self._valaddeds is not None: self._valaddeds.extend([infinity] * (n - len(self._relprecs)) + [value.valuation() - self._valbase]) - if not self._list is None: + if self._list is not None: zero = self.base_ring()(0) self._list.extend([zero] * (n - len(self._relprecs)) + [value]) else: basediff = self._valbase - value.valuation() self._valbase = value.valuation() - if not self._valaddeds is None: + if self._valaddeds is not None: self._valaddeds = [c + basediff for c in self._valaddeds] self._poly = self._poly * self.base_ring().prime_pow(basediff) if value != 0: @@ -728,7 +728,7 @@ def _unsafe_mutate(self, n, value): else: self._relprecs.extend([infinity] * (n - len(self._relprecs)) + [value.precision_relative()]) self._normalized = False - if not self._list is None: + if self._list is not None: if n < len(self._list): self._list[n] = value else: diff --git a/src/sage/rings/polynomial/padics/polynomial_padic_flat.py b/src/sage/rings/polynomial/padics/polynomial_padic_flat.py index 12e4104c56d..ee106a1e09a 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic_flat.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic_flat.py @@ -57,7 +57,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False, ab else: m = sage.rings.padics.misc.min(a.precision_absolute() for a in x.values()) - if not absprec is None: + if absprec is not None: m = min(m, absprec) Polynomial_generic_dense.__init__(self, parent, x, absprec=m) return diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring.py b/src/sage/rings/polynomial/polynomial_quotient_ring.py index b069cdd749c..f342447c8f0 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring.py @@ -1925,9 +1925,9 @@ def _isomorphic_ring(self): try: isomorphic_ring = self.base_ring().extension(self.modulus(), names=self.variable_names()) except ValueError: - pass # modulus is not irreducible + pass # modulus is not irreducible else: - if not isomorphic_ring in NumberFields(): + if isomorphic_ring not in NumberFields(): raise NotImplementedError("cannot handle extensions of number fields that do not produce number fields") # refine the category of self if not self.is_field(): diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index 7c8679bedd9..65d10375c06 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -132,7 +132,7 @@ def __init__(self, parent, polynomial, check=True): if not isinstance(polynomial, Polynomial): raise TypeError("polynomial must be a polynomial") - if not polynomial in parent.polynomial_ring(): + if polynomial not in parent.polynomial_ring(): raise TypeError("polynomial must be in the polynomial ring of the parent") f = parent.modulus() diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 82ff837a2b5..02b56f18f41 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1109,7 +1109,7 @@ def _mpoly_base_ring(self, variables=None): variables = self.variable_names_recursive() variables = list(variables) var = self.variable_name() - if not var in variables: + if var not in variables: return self else: try: diff --git a/src/sage/rings/polynomial/polynomial_ring_constructor.py b/src/sage/rings/polynomial/polynomial_ring_constructor.py index 289c80160c3..c07c93adb38 100644 --- a/src/sage/rings/polynomial/polynomial_ring_constructor.py +++ b/src/sage/rings/polynomial/polynomial_ring_constructor.py @@ -944,7 +944,7 @@ def BooleanPolynomialRing_constructor(n=None, names=None, order="lex"): key = ("pbori", names, n, order) R = _get_from_cache(key) - if not R is None: + if R is not None: return R from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing @@ -953,6 +953,6 @@ def BooleanPolynomialRing_constructor(n=None, names=None, order="lex"): _save_in_cache(key, R) return R -######################################################################################### +############################################################################ # END (Factory function for making polynomial rings) -######################################################################################### +############################################################################ diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index 9d0534186e1..ff5ca7aeb8d 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -383,12 +383,11 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, # if isinstance(name, (int,integer.Integer)) or isinstance(arg2,(int,integer.Integer)): # deprecation(trac_number, "This behavior of PowerSeriesRing is being deprecated in favor of constructing multivariate power series rings. (See Trac ticket #1956.)") - # the following is the original, univariate-only code if isinstance(name, (int, integer.Integer)): default_prec = name - if not names is None: + if names is not None: name = names name = normalize_names(1, name) diff --git a/src/sage/rings/quotient_ring.py b/src/sage/rings/quotient_ring.py index 1fc7b20e2fc..807dce92a9b 100644 --- a/src/sage/rings/quotient_ring.py +++ b/src/sage/rings/quotient_ring.py @@ -272,7 +272,7 @@ def QuotientRing(R, I, names=None, **kwds): #if not isinstance(R, commutative_ring.CommutativeRing): # raise TypeError, "R must be a commutative ring." from sage.all import Integers, ZZ - if not R in Rings(): + if R not in Rings(): raise TypeError("R must be a ring.") try: is_commutative = R.is_commutative() diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index fbd0fd79d65..a9c54184574 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -845,7 +845,7 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): for i in range(len(S)): if S[i] == self.places()[0]: S[i] = -1 - if not b in self: + if b not in self: raise TypeError("second argument must be a rational number") b = self(b) if b == 0: @@ -1488,7 +1488,7 @@ def quadratic_defect(self, a, p, check=True): """ from sage.rings.all import Infinity from sage.arith.misc import legendre_symbol - if not a in self: + if a not in self: raise TypeError(str(a) + " must be an element of " + str(self)) if p.parent() == ZZ.ideal_monoid(): p = p.gen() From 4ae6832b6785d51eb08c2547b79024c6f3ce3df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 24 Oct 2021 19:23:59 +0200 Subject: [PATCH 507/511] fix E714 and E713 in combinat --- src/sage/combinat/affine_permutation.py | 4 ++-- src/sage/combinat/baxter_permutations.py | 4 ++-- .../combinat/cluster_algebra_quiver/mutation_type.py | 4 ++-- src/sage/combinat/composition_tableau.py | 6 +++--- src/sage/combinat/crystals/generalized_young_walls.py | 2 +- src/sage/combinat/designs/bibd.py | 2 +- src/sage/combinat/designs/block_design.py | 3 ++- .../designs/orthogonal_arrays_build_recursive.py | 2 +- .../combinat/designs/steiner_quadruple_systems.py | 11 ++++++----- src/sage/combinat/diagram_algebras.py | 2 +- src/sage/combinat/fully_packed_loop.py | 4 ++-- src/sage/combinat/k_tableau.py | 10 +++++----- src/sage/combinat/matrices/hadamard_matrix.py | 4 ++-- src/sage/combinat/output.py | 4 +++- src/sage/combinat/partition_tuple.py | 6 +++--- src/sage/combinat/root_system/associahedron.py | 3 ++- src/sage/combinat/root_system/dynkin_diagram.py | 2 +- .../combinat/root_system/root_lattice_realizations.py | 2 +- src/sage/combinat/sf/jack.py | 2 +- src/sage/combinat/sidon_sets.py | 4 ++-- src/sage/combinat/tableau_tuple.py | 4 ++-- src/sage/combinat/words/finite_word.py | 2 +- 22 files changed, 46 insertions(+), 41 deletions(-) diff --git a/src/sage/combinat/affine_permutation.py b/src/sage/combinat/affine_permutation.py index 8caffd1a81e..0e252b85625 100644 --- a/src/sage/combinat/affine_permutation.py +++ b/src/sage/combinat/affine_permutation.py @@ -1707,7 +1707,7 @@ def apply_simple_reflection_right(self, i): EXAMPLES:: sage: G = AffinePermutationGroup(['G',2,1]) - sage: p=G([2, 10, -5, 12, -3, 5]) + sage: p = G([2, 10, -5, 12, -3, 5]) sage: p.apply_simple_reflection_right(0) Type G affine permutation with window [-9, -1, -5, 12, 8, 16] sage: p.apply_simple_reflection_right(1) @@ -1715,7 +1715,7 @@ def apply_simple_reflection_right(self, i): sage: p.apply_simple_reflection_right(2) Type G affine permutation with window [2, -5, 10, -3, 12, 5] """ - if not i in self.parent().index_set(): + if i not in self.parent().index_set(): raise ValueError('index not in index set') j = i l = self[:] diff --git a/src/sage/combinat/baxter_permutations.py b/src/sage/combinat/baxter_permutations.py index 8464f8d27b3..59d9a0256fb 100644 --- a/src/sage/combinat/baxter_permutations.py +++ b/src/sage/combinat/baxter_permutations.py @@ -117,7 +117,7 @@ def __contains__(self, x): sage: sorted([p for p in Permutations(6) if p in BaxterPermutations(6)]) == sorted(BaxterPermutations(6).list()) True """ - if not x in Permutations(self._n): + if x not in Permutations(self._n): return False for i in range(1, len(x) - 1): a = x[i] @@ -299,7 +299,7 @@ def __contains__(self, x): sage: 42 in BaxterPermutations() False """ - if not x in Permutations(): + if x not in Permutations(): return False return x in BaxterPermutations(len(x)) diff --git a/src/sage/combinat/cluster_algebra_quiver/mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/mutation_type.py index 7a843e423f3..7a728780003 100644 --- a/src/sage/combinat/cluster_algebra_quiver/mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/mutation_type.py @@ -120,7 +120,7 @@ def _triangles(dg): for e in E: v1, v2 = e for v in V: - if not v in e: + if v not in e: if (v, v1) in E: if (v2, v) in E: flat_trian = sorted([v,v1,v2]) @@ -1165,7 +1165,7 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False): connecting_vertices.append( v ) # if a vertex is of valence two and contained in an oriented 3-cycle, it is a connecting vertex elif w[0] == 1 and w[1] == 1: - if v in o_trian_verts and not v in long_cycle_verts: + if v in o_trian_verts and v not in long_cycle_verts: connecting_vertices.append( v ) # post-parsing 1: if we are in the affine type A case, the two parameters for the non-oriented long cycle are computed diff --git a/src/sage/combinat/composition_tableau.py b/src/sage/combinat/composition_tableau.py index 7c563bfffd1..0f8d70549f5 100644 --- a/src/sage/combinat/composition_tableau.py +++ b/src/sage/combinat/composition_tableau.py @@ -409,7 +409,7 @@ def __classcall_private__(cls, *args, **kwargs): if shape is not None: # use in (and not isinstance) below so that lists can be used as # shorthand - if not shape in Compositions(): + if shape not in Compositions(): raise ValueError("shape must be a composition") if any(i == 0 for i in shape): raise ValueError("shape must have non-zero parts") @@ -475,8 +475,8 @@ def _element_constructor_(self, t): ... ValueError: [[1], [1, 2]] is not an element of Composition Tableaux of size 3 and maximum entry 3. """ - if not t in self: - raise ValueError("%s is not an element of %s."%(t, self)) + if t not in self: + raise ValueError("%s is not an element of %s." % (t, self)) return self.element_class(self, t) diff --git a/src/sage/combinat/crystals/generalized_young_walls.py b/src/sage/combinat/crystals/generalized_young_walls.py index d656d27080f..60c47154c8e 100644 --- a/src/sage/combinat/crystals/generalized_young_walls.py +++ b/src/sage/combinat/crystals/generalized_young_walls.py @@ -711,7 +711,7 @@ def in_highest_weight_crystal(self,La): sage: x.in_highest_weight_crystal(La) False """ - if not La in self.parent().weight_lattice_realization(): + if La not in self.parent().weight_lattice_realization(): raise TypeError("Must be an element in the weight lattice realization") ac = self.parent().weight_lattice_realization().simple_coroots() n = self.cartan_type().classical().rank() diff --git a/src/sage/combinat/designs/bibd.py b/src/sage/combinat/designs/bibd.py index 44f8fbe70bc..f6af1e56990 100644 --- a/src/sage/combinat/designs/bibd.py +++ b/src/sage/combinat/designs/bibd.py @@ -958,7 +958,7 @@ def PBD_4_5_8_9_12(v, check=True): sage: for v in (0,1,4,5,8,9,12,13,16,17,20,21,24,25): ....: _ = PBD_4_5_8_9_12(v) """ - if not v%4 in [0,1]: + if v % 4 not in [0, 1]: raise ValueError if v <= 1: PBD = [] diff --git a/src/sage/combinat/designs/block_design.py b/src/sage/combinat/designs/block_design.py index 65f49d9a864..abdaca1e17b 100644 --- a/src/sage/combinat/designs/block_design.py +++ b/src/sage/combinat/designs/block_design.py @@ -676,7 +676,7 @@ def projective_plane_to_OA(pplane, pt=None, check=True): assert all(len(B) == n+1 for B in pplane), "pplane is not a projective plane" pplane = _relabel_bibd(pplane,n**2+n+1,p=n**2+n) - OA = [[x%n for x in sorted(X)] for X in pplane if not n**2+n in X] + OA = [[x % n for x in sorted(X)] for X in pplane if n**2+n not in X] assert len(OA) == n**2, "pplane is not a projective plane" @@ -686,6 +686,7 @@ def projective_plane_to_OA(pplane, pt=None, check=True): return OA + def projective_plane(n, check=True, existence=False): r""" Return a projective plane of order ``n`` as a 2-design. diff --git a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py index 103069b1b16..17cf84606b5 100644 --- a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py +++ b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py @@ -545,7 +545,7 @@ def construction_q_x(k,q,x,check=True,explain_construction=False): relabel = {i:j for j,i in enumerate(points_to_keep)} # PBD is a (n,[q,q-x-1,q-x+1,x+2])-PBD - PBD = [[relabel[xx] for xx in B if not xx in points_to_delete] for B in TD] + PBD = [[relabel[xx] for xx in B if xx not in points_to_delete] for B in TD] # Taking the unique block of size x+2 assert list(map(len,PBD)).count(x+2)==1 diff --git a/src/sage/combinat/designs/steiner_quadruple_systems.py b/src/sage/combinat/designs/steiner_quadruple_systems.py index 5f49cdd3daf..1cba16ea939 100644 --- a/src/sage/combinat/designs/steiner_quadruple_systems.py +++ b/src/sage/combinat/designs/steiner_quadruple_systems.py @@ -545,14 +545,15 @@ def _missing_pair(n,l): sage: _missing_pair(6, [(0,1), (4,5)]) (2, 3) """ - l = [x for X in l for x in X] + l = set(x for X in l for x in X) for x in range(n): - if not x in l: + if x not in l: break - assert not x in l - assert not x+1 in l - return (x,x+1) + assert x not in l + assert x + 1 not in l + return (x, x + 1) + def barP(eps, m): r""" diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 17a9f85bc5f..e7686fabe95 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -2771,7 +2771,7 @@ def s(self, i): sage: P2h.s(1) P{{-3, 3}, {-2, 1}, {-1, 2}} """ - if not i in ZZ or i <= 0 or i >= self._k: + if i not in ZZ or i <= 0 or i >= self._k: raise ValueError("i must be an integer between 1 and {}".format(self._k-1)) B = self.basis() SP = B.keys() diff --git a/src/sage/combinat/fully_packed_loop.py b/src/sage/combinat/fully_packed_loop.py index 05e4ab5fd25..81eb5131349 100644 --- a/src/sage/combinat/fully_packed_loop.py +++ b/src/sage/combinat/fully_packed_loop.py @@ -88,10 +88,10 @@ def _make_color_list(n, colors=None, color_map=None, randomize=False): elif color_map: from matplotlib import cm - if not color_map in cm.datad: + if color_map not in cm.datad: raise ValueError('unknown color map %s' % color_map) cmap = cm.__dict__[color_map] - colors = [cmap(i/float(n-1))[:3] for i in range(n)] + colors = [cmap(i / float(n - 1))[:3] for i in range(n)] if colors and randomize: from sage.misc.prandom import shuffle diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index 1e9e57b8d86..17fccecd104 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -812,7 +812,7 @@ def check(self): if not self.parent()._weight == WeakTableau_bounded.from_core_tableau(self,self.k).weight(): raise ValueError("The weight of the parent does not agree with the weight of the tableau!") t = SkewTableau(list(self)) - if not t in SemistandardSkewTableaux(): + if t not in SemistandardSkewTableaux(): raise ValueError("The tableau is not semistandard!") outer = Core(t.outer_shape(),self.k+1) inner = Core(t.inner_shape(),self.k+1) @@ -1538,7 +1538,7 @@ def check(self): ValueError: The tableaux is not semistandard! """ t = SkewTableau(list(self)) - if not t in SemistandardSkewTableaux(): + if t not in SemistandardSkewTableaux(): raise ValueError("The tableaux is not semistandard!") if not self.parent()._weight == tuple(t.weight()): raise ValueError("The weight of the parent does not agree with the weight of the tableau!") @@ -4449,7 +4449,7 @@ def cells_head_dictionary( cls, T ): nextv = ST.entries_by_content(i + 1) for c in ST.cells_by_content(i): v = T[c[0]][c[1]] - if not v in nextv: + if v not in nextv: if v in dout: dout[v] += [c] else: @@ -4457,7 +4457,7 @@ def cells_head_dictionary( cls, T ): return dout @classmethod - def marked_CST_to_transposition_sequence( self, T, k ): + def marked_CST_to_transposition_sequence(self, T, k): """ Return a list of transpositions corresponding to ``T``. @@ -4533,7 +4533,7 @@ def marked_CST_to_transposition_sequence( self, T, k ): MM = [[LL[a][b] for b in range(len(LL[a])) if (a,b) in mcells] for a in range(len(mP))] transeq = self.marked_CST_to_transposition_sequence(MM, k) - if not transeq is None: + if transeq is not None: return [[j-l, j+1]] + transeq @classmethod diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 6380e580448..d12f3e644c4 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -633,7 +633,7 @@ def true(): M = RSHCD_324(e) elif ( e == 1 and n%16 == 0 and - not sqn is None and + sqn is not None and is_prime_power(sqn-1) and is_prime_power(sqn+1)): if existence: @@ -641,7 +641,7 @@ def true(): M = -rshcd_from_close_prime_powers(sqn) elif ( e == 1 and - not sqn is None and + sqn is not None and sqn%4 == 2 and strongly_regular_graph(sqn-1,(sqn-2)//2,(sqn-6)//4, existence=True) is True and diff --git a/src/sage/combinat/output.py b/src/sage/combinat/output.py index 563795a49f4..95b5cd0c046 100644 --- a/src/sage/combinat/output.py +++ b/src/sage/combinat/output.py @@ -288,7 +288,9 @@ def tex_from_skew_array(array, with_lines=False, align='b'): # function end_line which puts in the required \cline's. if with_lines: # last position of None in each row - nones=[1 if not None in row else 1+len(row)-row[::-1].index(None) for row in array] + nones = [1 if None not in row else 1 + len(row) - row[::-1].index(None) + for row in array] + def end_line(r): # in a slightly unpythonic way, we label the lines as 0, 1, ..., len(array) if r==0: diff --git a/src/sage/combinat/partition_tuple.py b/src/sage/combinat/partition_tuple.py index 34b5a9e46ff..f992d013a0d 100644 --- a/src/sage/combinat/partition_tuple.py +++ b/src/sage/combinat/partition_tuple.py @@ -2706,16 +2706,16 @@ def __init__(self, level, regular): sage: RPT = PartitionTuples(level=4, regular=3) sage: TestSuite(RPT).run() """ - if not level in NN: + if level not in NN: raise ValueError('level must be a non-negative integer') if not isinstance(regular, tuple): # This should not happen if called from RegularPartitionTuples regular = (regular,) * level - if any (r != 1 for r in regular): + if any(r != 1 for r in regular): category = InfiniteEnumeratedSets() else: category = FiniteEnumeratedSets() - if any (r not in NN for r in regular): + if any(r not in NN for r in regular): raise ValueError('regular must be a tuple of non-negative integers') if len(regular) != level: raise ValueError("regular must be a tuple with length {}".format(level)) diff --git a/src/sage/combinat/root_system/associahedron.py b/src/sage/combinat/root_system/associahedron.py index 30092073473..eef083511f1 100644 --- a/src/sage/combinat/root_system/associahedron.py +++ b/src/sage/combinat/root_system/associahedron.py @@ -299,7 +299,7 @@ def Associahedra(base_ring, ambient_dim, backend='ppl'): :class:`Associahedra_base`. """ - if not base_ring is QQ: + if base_ring is not QQ: raise NotImplementedError("base ring must be QQ") if backend == 'ppl': return Associahedra_ppl(base_ring, ambient_dim, backend) @@ -314,6 +314,7 @@ def Associahedra(base_ring, ambient_dim, backend='ppl'): else: raise ValueError("unknown backend") + class Associahedra_base(object): """ Base class of parent of Associahedra of specified dimension diff --git a/src/sage/combinat/root_system/dynkin_diagram.py b/src/sage/combinat/root_system/dynkin_diagram.py index 809afeecb6f..3c889d5e0ea 100644 --- a/src/sage/combinat/root_system/dynkin_diagram.py +++ b/src/sage/combinat/root_system/dynkin_diagram.py @@ -522,7 +522,7 @@ def dual(self): result.add_vertices(self.vertices()) for source, target, label in self.edges(): result.add_edge(target, source, label) - result._cartan_type = self._cartan_type.dual() if not self._cartan_type is None else None + result._cartan_type = self._cartan_type.dual() if self._cartan_type is not None else None return result def relabel(self, *args, **kwds): diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index 95301036614..377ce53376c 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -723,7 +723,7 @@ def nonparabolic_positive_roots(self, index_set = None): if index_set is None: return [] return [x for x in self.positive_roots() - if not x in self.positive_roots(index_set)] + if x not in self.positive_roots(index_set)] @cached_method def nonparabolic_positive_root_sum(self, index_set=None): diff --git a/src/sage/combinat/sf/jack.py b/src/sage/combinat/sf/jack.py index 74d02ab7c53..5ca78639572 100644 --- a/src/sage/combinat/sf/jack.py +++ b/src/sage/combinat/sf/jack.py @@ -1215,7 +1215,7 @@ def _h_cache(self, n): to_cache_2 = self._h_to_self_cache[n] for mu in from_cache_1: for la in from_cache_1[mu]: - if not la in to_cache_1: + if la not in to_cache_1: to_cache_1[la] = {} to_cache_2[la] = {} to_cache_2[la][mu] = from_cache_1[mu][la] diff --git a/src/sage/combinat/sidon_sets.py b/src/sage/combinat/sidon_sets.py index dda3cd07d76..e9924762024 100644 --- a/src/sage/combinat/sidon_sets.py +++ b/src/sage/combinat/sidon_sets.py @@ -126,10 +126,10 @@ def sidon_sets_rec(N, g=1): sidons = set(pre_sidons) for psid in pre_sidons: psid_shift = Set([n - 1 for n in psid if n != 1] + [N - 1]) - if not psid_shift in pre_sidons: + if psid_shift not in pre_sidons: continue - if not 1 in psid: + if 1 not in psid: add_sid = True else: add_sid = True diff --git a/src/sage/combinat/tableau_tuple.py b/src/sage/combinat/tableau_tuple.py index ac3f23b1375..a7b98a63743 100644 --- a/src/sage/combinat/tableau_tuple.py +++ b/src/sage/combinat/tableau_tuple.py @@ -2243,8 +2243,8 @@ def _element_constructor_(self, t): ... ValueError: [[1, 2]] is not an element of Tableau tuples of level 3 """ - if not t in self: - raise ValueError("%s is not an element of %s"%(t, self)) + if t not in self: + raise ValueError("%s is not an element of %s" % (t, self)) # one way or another these two cases need to be treated separately if t == [] or t == [[]]: diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index e643ca9bbb3..609e701f7c7 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -3864,7 +3864,7 @@ def subword_complementaries(self, other): from sage.combinat.words.word import Word comp_words = [] for sp in selfpos: # list with positions of one occurrence of `self` - comp_pos = [i for i in range(lo) if not i in set(sp)] + comp_pos = (i for i in range(lo) if i not in set(sp)) comp_words.append(Word([other[i] for i in comp_pos])) return comp_words From 623537cc94efbab3ed1d6d0152b1b353dec26c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 24 Oct 2021 20:18:46 +0200 Subject: [PATCH 508/511] last fixes for relint : remove sagenb check and __metaclass_ --- src/.relint.yml | 4 +- src/sage/misc/bindable_class.py | 19 ++----- src/sage/misc/classcall_metaclass.pyx | 2 - src/sage/misc/nested_class.pyx | 72 +++++++++------------------ src/sage/misc/sageinspect.py | 12 ++--- src/sage_docbuild/ext/sage_autodoc.py | 3 +- 6 files changed, 36 insertions(+), 76 deletions(-) diff --git a/src/.relint.yml b/src/.relint.yml index 9d12054b982..19e935d93c0 100644 --- a/src/.relint.yml +++ b/src/.relint.yml @@ -7,8 +7,8 @@ hint: | # ifilter, imap, izip # __metaclass__ Hint: # update raise statements # except Exception, var - Hint: # sagenb # six is no longer allowed - pattern: '(import.*[, ]ifilter|import.*[, ]imap|import.*[, ]izip|^\s*raise\s*[A-Za-z]*Error\s*,|__metaclass__|except\s*[A-Za-z]\s*,|[^_]sagenb|import six|from six import)' + Hint: # six is no longer allowed + pattern: '(import.*[, ]ifilter|import.*[, ]imap|import.*[, ]izip|^\s*raise\s*[A-Za-z]*Error\s*,|__metaclass__|except\s*[A-Za-z]\s*,|import six|from six import)' filePattern: .*[.](py|pyx|rst) - name: 'foreign_latex: foreign commands in LaTeX' diff --git a/src/sage/misc/bindable_class.py b/src/sage/misc/bindable_class.py index c776faf7257..f8e557606b2 100644 --- a/src/sage/misc/bindable_class.py +++ b/src/sage/misc/bindable_class.py @@ -1,18 +1,15 @@ """ Bindable classes """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Nicolas M. Thiery # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** - - +# https://www.gnu.org/licenses/ +# **************************************************************************** import functools from sage.misc.nested_class import NestedClassMetaclass from sage.misc.classcall_metaclass import ClasscallMetaclass @@ -33,16 +30,12 @@ class BindableClass(metaclass=ClasscallMetaclass): Let us consider the following class ``Outer`` with a nested class ``Inner``:: sage: from sage.misc.nested_class import NestedClassMetaclass - sage: class Outer: - ....: __metaclass__ = NestedClassMetaclass # just a workaround for Python misnaming nested classes - ....: + sage: class Outer(metaclass=NestedClassMetaclass): ....: class Inner: ....: def __init__(self, *args): ....: print(args) - ....: ....: def f(self, *args): ....: print("{} {}".format(self, args)) - ....: ....: @staticmethod ....: def f_static(*args): ....: print(args) @@ -84,9 +77,7 @@ class BindableClass(metaclass=ClasscallMetaclass): :class:`BindableClass` gives this binding behavior to all its subclasses:: sage: from sage.misc.bindable_class import BindableClass - sage: class Outer: - ....: __metaclass__ = NestedClassMetaclass # just a workaround for Python misnaming nested classes - ....: + sage: class Outer(metaclass=NestedClassMetaclass): ....: class Inner(BindableClass): ....: " some documentation " ....: def __init__(self, outer, *args): diff --git a/src/sage/misc/classcall_metaclass.pyx b/src/sage/misc/classcall_metaclass.pyx index 464a3ea93ec..ab19a5eb7a1 100644 --- a/src/sage/misc/classcall_metaclass.pyx +++ b/src/sage/misc/classcall_metaclass.pyx @@ -217,12 +217,10 @@ cdef class ClasscallMetaclass(NestedClassMetaclass): We now show the usage of ``__classcall_private__``:: sage: class FooNoInherits(object, metaclass=ClasscallMetaclass): - ....: __metaclass__ = ClasscallMetaclass ....: @staticmethod ....: def __classcall_private__(cls): ....: print("calling private classcall") ....: return type.__call__(cls) - ... sage: FooNoInherits() calling private classcall <__main__.FooNoInherits object at ...> diff --git a/src/sage/misc/nested_class.pyx b/src/sage/misc/nested_class.pyx index 3054461a9c7..08750233543 100644 --- a/src/sage/misc/nested_class.pyx +++ b/src/sage/misc/nested_class.pyx @@ -44,24 +44,16 @@ EXAMPLES:: sage: A1.A2.A3.__name__ 'A3' - sage: A1.A2.A3 # py2 - - sage: A1.A2.A3 # py3 + sage: A1.A2.A3 - sage: nested_pickle(A1) # py2 - - sage: nested_pickle(A1) # py3 + sage: nested_pickle(A1) - sage: A1.A2 # py2 - - sage: A1.A2 # py3 + sage: A1.A2 - sage: A1.A2.A3 # py2 - - sage: A1.A2.A3 # py3 + sage: A1.A2.A3 sage: A1.A2.A3.__name__ 'A1.A2.A3' @@ -79,22 +71,13 @@ All of this is not perfect. In the following scenario:: sage: class B1: ....: A2 = A1.A2 - sage: nested_pickle(A1) # py2 - - sage: nested_pickle(B1) # py2 - - sage: A1.A2 # py2 - - sage: B1.A2 # py2 - - - sage: nested_pickle(A1) # py3 + sage: nested_pickle(A1) - sage: nested_pickle(B1) # py3 + sage: nested_pickle(B1) - sage: A1.A2 # py3 + sage: A1.A2 - sage: B1.A2 # py3 + sage: B1.A2 The name for ``"A1.A2"`` could potentially be set to ``"B1.A2"``. But that will work anyway. @@ -161,14 +144,9 @@ cpdef modify_for_nested_pickle(cls, str name_prefix, module, first_run=True): Note that the class is now found in the module under both its old and its new name:: - sage: getattr(module, 'A.B', 'Not found') # py2 - - sage: getattr(module, 'X.A.B', 'Not found') # py2 - - - sage: getattr(module, 'A.B', 'Not found') # py3 + sage: getattr(module, 'A.B', 'Not found') - sage: getattr(module, 'X.A.B', 'Not found') # py3 + sage: getattr(module, 'X.A.B', 'Not found') TESTS: @@ -253,9 +231,7 @@ def nested_pickle(cls): sage: A.B.__name__ 'A.B' - sage: getattr(module, 'A.B', 'Not found') # py2 - - sage: getattr(module, 'A.B', 'Not found') # py3 + sage: getattr(module, 'A.B', 'Not found') In Python 2.6, decorators work with classes; then ``@nested_pickle`` @@ -288,10 +264,8 @@ cdef class NestedClassMetaclass(type): derived subclass:: sage: from sage.misc.nested_class import NestedClassMetaclass - sage: class ASuperClass(object): # py2 - ....: __metaclass__ = NestedClassMetaclass # py2 - sage: class ASuperClass(object, metaclass=NestedClassMetaclass): # py3 - ....: pass # py3 + sage: class ASuperClass(object, metaclass=NestedClassMetaclass): + ....: pass sage: class A3(ASuperClass): ....: class B(object): ....: pass @@ -304,16 +278,16 @@ cdef class NestedClassMetaclass(type): r""" This invokes the nested_pickle on construction. - sage: from sage.misc.nested_class import NestedClassMetaclass - sage: class A(object): - ....: __metaclass__ = NestedClassMetaclass - ....: class B(object): - ....: pass - ... - sage: A.B - - sage: getattr(sys.modules['__main__'], 'A.B', 'Not found') - + EXAMPLES:: + + sage: from sage.misc.nested_class import NestedClassMetaclass + sage: class A(object, metaclass=NestedClassMetaclass): + ....: class B(object): + ....: pass + sage: A.B + + sage: getattr(sys.modules['__main__'], 'A.B', 'Not found') + """ modify_for_nested_pickle(self, self.__name__, sys_modules[self.__module__]) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 2ff2762f156..48c95b0f226 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -192,9 +192,9 @@ def loadable_module_extension(): def isclassinstance(obj): r""" - Checks if argument is instance of non built-in class + Check if argument is instance of non built-in class - INPUT: ``obj`` - object + INPUT: ``obj`` -- object EXAMPLES:: @@ -207,12 +207,10 @@ def isclassinstance(obj): sage: isclassinstance(myclass) False sage: class mymetaclass(type): pass - sage: class myclass2: - ....: __metaclass__ = mymetaclass + sage: class myclass2(metaclass=mymetaclass): pass sage: isclassinstance(myclass2) False """ - builtin_mods = set(['__builtin__', 'builtins', 'exceptions']) return (not inspect.isclass(obj) and @@ -1630,7 +1628,7 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return except (TypeError, AttributeError): pass if isclassinstance(obj): - if hasattr(obj,'_sage_src_'): #it may be a decorator! + if hasattr(obj, '_sage_src_'): #it may be a decorator! source = sage_getsource(obj) try: # we try to find the definition and parse it by @@ -2384,7 +2382,7 @@ class Element(object): # Check if we deal with an instance if isclassinstance(obj): - if isinstance(obj,functools.partial): + if isinstance(obj, functools.partial): return sage_getsourcelines(obj.func) else: return sage_getsourcelines(obj.__class__) diff --git a/src/sage_docbuild/ext/sage_autodoc.py b/src/sage_docbuild/ext/sage_autodoc.py index b698a6e9297..399ac1532e5 100644 --- a/src/sage_docbuild/ext/sage_autodoc.py +++ b/src/sage_docbuild/ext/sage_autodoc.py @@ -1174,8 +1174,7 @@ def import_object(self): # by using the metaclass NestedMetaclass, we change the attribute # __name__ of the nested class. For example, in # - # class A: - # __metaclass__ = NestedClassMetaclass + # class A(metaclass=NestedMetaclass): # class B(object): # pass # From c2cba3250e53ffb193c5696a6c7c7636a32d2d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 24 Oct 2021 20:29:49 +0200 Subject: [PATCH 509/511] one more fix --- .../dynamics/arithmetic_dynamics/endPN_automorphism_group.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index e5ef59acf59..75a863423eb 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -1790,8 +1790,9 @@ def which_group(list_of_elements): else: return ['A_5'] + def conjugating_set_initializer(f, g): - """ + r""" Return a conjugation invariant set together with information to reduce the combinatorics of checking all possible conjugations. From c8499d1a703a6f50e157a9270ff35b9a0a4772b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 24 Oct 2021 21:46:31 +0200 Subject: [PATCH 510/511] fix E713 and E714 in schemes --- src/sage/schemes/affine/affine_homset.py | 2 +- src/sage/schemes/affine/affine_subscheme.py | 2 +- src/sage/schemes/curves/affine_curve.py | 8 ++++---- src/sage/schemes/curves/curve.py | 4 ++-- src/sage/schemes/curves/projective_curve.py | 4 ++-- src/sage/schemes/elliptic_curves/cm.py | 3 +-- src/sage/schemes/elliptic_curves/ell_egros.py | 6 +++--- .../elliptic_curves/ell_modular_symbols.py | 10 +++++----- .../elliptic_curves/ell_rational_field.py | 11 ++++++----- .../schemes/elliptic_curves/isogeny_class.py | 9 +++++---- .../elliptic_curves/isogeny_small_degree.py | 16 ++++++++-------- src/sage/schemes/elliptic_curves/kraus.py | 2 +- src/sage/schemes/generic/scheme.py | 6 +++--- src/sage/schemes/plane_conics/con_field.py | 2 +- .../plane_quartics/quartic_constructor.py | 4 ++-- src/sage/schemes/projective/projective_homset.py | 2 +- .../schemes/projective/projective_morphism.py | 10 ++++++---- .../schemes/projective/projective_subscheme.py | 2 +- src/sage/schemes/toric/homset.py | 2 +- src/sage/schemes/toric/toric_subscheme.py | 8 ++++---- 20 files changed, 58 insertions(+), 55 deletions(-) diff --git a/src/sage/schemes/affine/affine_homset.py b/src/sage/schemes/affine/affine_homset.py index 59c842901c4..f712c0f130d 100644 --- a/src/sage/schemes/affine/affine_homset.py +++ b/src/sage/schemes/affine/affine_homset.py @@ -398,7 +398,7 @@ def numerical_points(self, F=None, **kwds): from sage.schemes.affine.affine_space import is_AffineSpace if F is None: F = CC - if not F in Fields() or not hasattr(F, 'precision'): + if F not in Fields() or not hasattr(F, 'precision'): raise TypeError('F must be a numerical field') X = self.codomain() if X.base_ring() not in NumberFields(): diff --git a/src/sage/schemes/affine/affine_subscheme.py b/src/sage/schemes/affine/affine_subscheme.py index d2938dc1dcb..92b040b9631 100644 --- a/src/sage/schemes/affine/affine_subscheme.py +++ b/src/sage/schemes/affine/affine_subscheme.py @@ -328,7 +328,7 @@ def is_smooth(self, point=None): False """ R = self.ambient_space().coordinate_ring() - if not point is None: + if point is not None: self._check_satisfies_equations(point) point_subs = dict(zip(R.gens(), point)) Jac = self.Jacobian().subs(point_subs) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 880b420b7b6..2702be6f095 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -678,7 +678,7 @@ def tangents(self, P, factor=True): # divide T by that power of vars[1] T = self.ambient_space().coordinate_ring()(dict([((v[0],v[1] - t), h) for (v,h) in T.dict().items()])) # T is homogeneous in var[0], var[1] if nonconstant, so dehomogenize - if not T in self.base_ring(): + if T not in self.base_ring(): if T.degree(vars[0]) > 0: T = T(vars[0], 1) roots = T.univariate_polynomial().roots() @@ -982,7 +982,7 @@ def projection(self, indices, AS=None): raise ValueError("(=%s) must be a list or tuple of length between 2 and (=%s), inclusive" % (indices, n - 1)) if len(set(indices)) < len(indices): raise ValueError("(=%s) must be a list or tuple of distinct indices or variables" % indices) - if not AS is None: + if AS is not None: if not is_AffineSpace(AS): raise TypeError("(=%s) must be an affine space" % AS) if AS.dimension_relative() != len(indices): @@ -2145,11 +2145,11 @@ def _nonsingular_model(self): basis = list(gbasis) syzygy = {} for i in range(n): - S = k[R._first_ngens(i+1)] + S = k[R._first_ngens(i + 1)] while basis: f = basis.pop() if f in S: - if not i in syzygy and f: + if i not in syzygy and f: syzygy[i] = f else: basis.append(f) diff --git a/src/sage/schemes/curves/curve.py b/src/sage/schemes/curves/curve.py index 2e4c41d961d..f9cea384986 100644 --- a/src/sage/schemes/curves/curve.py +++ b/src/sage/schemes/curves/curve.py @@ -320,8 +320,8 @@ def singular_points(self, F=None): if not self.base_ring() in Fields(): raise TypeError("curve must be defined over a field") F = self.base_ring() - elif not F in Fields(): - raise TypeError("(=%s) must be a field"%F) + elif F not in Fields(): + raise TypeError("(=%s) must be a field" % F) X = self.singular_subscheme() return [self.point(p, check=False) for p in X.rational_points(F=F)] diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 8d8db455481..ea49a181815 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -411,7 +411,7 @@ def projection(self, P=None, PS=None): raise TypeError("this curve is already a plane curve") if self.base_ring() not in Fields(): raise TypeError("this curve must be defined over a field") - if not PS is None: + if PS is not None: if not is_ProjectiveSpace(PS): raise TypeError("(=%s) must be a projective space" % PS) if PS.dimension_relative() != n - 1: @@ -455,7 +455,7 @@ def projection(self, P=None, PS=None): Q = self(P) except TypeError: pass - if not Q is None: + if Q is not None: raise TypeError("(=%s) must be a point not on this curve" % P) try: Q = self.ambient_space()(P) diff --git a/src/sage/schemes/elliptic_curves/cm.py b/src/sage/schemes/elliptic_curves/cm.py index 7d3d20d15ff..9556d1c8ac5 100644 --- a/src/sage/schemes/elliptic_curves/cm.py +++ b/src/sage/schemes/elliptic_curves/cm.py @@ -623,9 +623,8 @@ def is_cm_j_invariant(j, method='new'): True """ # First we check that j is an algebraic number: - from sage.rings.all import NumberFieldElement, NumberField - if not isinstance(j, NumberFieldElement) and not j in QQ: + if not isinstance(j, NumberFieldElement) and j not in QQ: raise NotImplementedError("is_cm_j_invariant() is only implemented for number field elements") # for j in ZZ we have a lookup-table: diff --git a/src/sage/schemes/elliptic_curves/ell_egros.py b/src/sage/schemes/elliptic_curves/ell_egros.py index 09ed54aa31f..bc782475f2e 100644 --- a/src/sage/schemes/elliptic_curves/ell_egros.py +++ b/src/sage/schemes/elliptic_curves/ell_egros.py @@ -447,10 +447,10 @@ def egros_get_j(S=[], proof=None, verbose=False): P = urst(P) x = P[0] y = P[1] - j = x**3 /w - assert j-1728 == y**2 /w + j = x**3 / w + assert j - 1728 == y**2 / w if is_possible_j(j, S): - if not j in jlist: + if j not in jlist: if verbose: print("Adding possible j = ", j) sys.stdout.flush() diff --git a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py index 30a61e1635c..7a0beab252f 100644 --- a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py +++ b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py @@ -129,7 +129,7 @@ def modular_symbol_space(E, sign, base_ring, bound=None): Modular Symbols space of dimension 1 for Gamma_0(11) of weight 2 with sign -1 over Finite Field of size 37 """ - if not sign in [-1,0,1]: + if sign not in [-1, 0, 1]: raise TypeError('sign must -1, 0 or 1') N = E.conductor() M = ModularSymbols(N, sign=sign, base_ring=base_ring) @@ -323,12 +323,12 @@ def __init__(self, E, sign, nap=1000): """ from sage.libs.eclib.newforms import ECModularSymbol - if not sign in [-1,1]: + if sign not in [-1, 1]: raise TypeError('sign must -1 or 1') self._sign = ZZ(sign) self._E = E self._scaling = 1 if E.discriminant()>0 else ZZ(1)/2 - self._implementation="eclib" + self._implementation = "eclib" self._base_ring = QQ # The ECModularSymbol class must be initialized with sign=0 to compute minus symbols self._modsym = ECModularSymbol(E, int(sign==1), nap) @@ -436,11 +436,11 @@ def __init__(self, E, sign, normalize="L_ratio"): [1, 1, 1, 1, 1, 1, 1, 1] """ - if not sign in [-1,1]: + if sign not in [-1, 1]: raise TypeError('sign must -1 or 1') self._sign = ZZ(sign) self._E = E - self._implementation="sage" + self._implementation = "sage" self._normalize = normalize self._modsym = E.modular_symbol_space(sign=self._sign) self._base_ring = self._modsym.base_ring() diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 847a1485f8b..b0b674a0bde 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -2376,12 +2376,12 @@ def _compute_gens(self, proof, # progress (see trac #1949). X = self.mwrank('-p 100 -S '+str(sat_bound)) verbose_verbose("Calling mwrank shell.") - if not 'The rank and full Mordell-Weil basis have been determined unconditionally' in X: + if 'The rank and full Mordell-Weil basis have been determined unconditionally' not in X: msg = 'Generators not provably computed.' if proof: - raise RuntimeError('%s\n%s'%(X,msg)) + raise RuntimeError('%s\n%s' % (X, msg)) else: - verbose_verbose("Warning -- %s"%msg, level=1) + verbose_verbose("Warning -- %s" % msg, level=1) proved = False else: proved = True @@ -4714,8 +4714,9 @@ def isogenies_prime_degree(self, l=None): if isinstance(l, list): isogs = [] i = 0 - while i """ from sage.categories.commutative_rings import CommutativeRings - if not R in CommutativeRings(): + if R not in CommutativeRings(): raise TypeError("R (={}) must be a commutative ring".format(R)) self.__R = R - if not S is None: - if not S in CommutativeRings(): + if S is not None: + if S not in CommutativeRings(): raise TypeError("S (={}) must be a commutative ring".format(S)) if not R.has_coerce_map_from(S): raise ValueError("There must be a natural map S --> R, but S = {} and R = {}".format(S, R)) diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index 0d5eb412034..1b557fcd735 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -878,7 +878,7 @@ def parametrization(self, point=None, morphism=True): ... ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization. """ - if (not self._parametrization is None) and not point: + if (self._parametrization is not None) and not point: par = self._parametrization else: if not self.is_smooth(): diff --git a/src/sage/schemes/plane_quartics/quartic_constructor.py b/src/sage/schemes/plane_quartics/quartic_constructor.py index e2a93bc7c2e..4b459b3c718 100644 --- a/src/sage/schemes/plane_quartics/quartic_constructor.py +++ b/src/sage/schemes/plane_quartics/quartic_constructor.py @@ -58,9 +58,9 @@ def QuarticCurve(F, PP=None, check=False): if not(F.is_homogeneous() and F.degree()==4): raise ValueError("Argument F (=%s) must be a homogeneous polynomial of degree 4"%F) - if not PP is None: + if PP is not None: if not is_ProjectiveSpace(PP) and PP.dimension == 2: - raise ValueError("Argument PP (=%s) must be a projective plane"%PP) + raise ValueError(f"Argument PP (={PP}) must be a projective plane") else: PP = ProjectiveSpace(P) diff --git a/src/sage/schemes/projective/projective_homset.py b/src/sage/schemes/projective/projective_homset.py index 8ed8c8af66a..e3d40a6179f 100644 --- a/src/sage/schemes/projective/projective_homset.py +++ b/src/sage/schemes/projective/projective_homset.py @@ -373,7 +373,7 @@ def numerical_points(self, F=None, **kwds): from sage.schemes.projective.projective_space import is_ProjectiveSpace if F is None: F = CC - if not F in Fields() or not hasattr(F, 'precision'): + if F not in Fields() or not hasattr(F, 'precision'): raise TypeError('F must be a numerical field') X = self.codomain() if X.base_ring() not in NumberFields(): diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 1aa7ea7f841..1224b82feed 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -1594,18 +1594,20 @@ def rational_preimages(self, Q, k=1): k = ZZ(k) if k <= 0: raise ValueError("k (=%s) must be a positive integer" % k) - #first check if subscheme + # first check if subscheme from sage.schemes.projective.projective_subscheme import AlgebraicScheme_subscheme_projective if isinstance(Q, AlgebraicScheme_subscheme_projective): return Q.preimage(self, k) - #else assume a point + # else assume a point BR = self.base_ring() if k > 1 and not self.is_endomorphism(): raise TypeError("must be an endomorphism of projective space") - if not Q in self.codomain(): + if Q not in self.codomain(): raise TypeError("point must be in codomain of self") - if isinstance(BR.base_ring(),(ComplexField_class, RealField_class,RealIntervalField_class, ComplexIntervalField_class)): + if isinstance(BR.base_ring(), (ComplexField_class, RealField_class, + RealIntervalField_class, + ComplexIntervalField_class)): raise NotImplementedError("not implemented over precision fields") PS = self.domain().ambient_space() N = PS.dimension_relative() diff --git a/src/sage/schemes/projective/projective_subscheme.py b/src/sage/schemes/projective/projective_subscheme.py index abeeda9799b..ccda38ad316 100644 --- a/src/sage/schemes/projective/projective_subscheme.py +++ b/src/sage/schemes/projective/projective_subscheme.py @@ -434,7 +434,7 @@ def is_smooth(self, point=None): sage: H.is_smooth() # one of the few cases where the cone over the subvariety is smooth True """ - if not point is None: + if point is not None: self._check_satisfies_equations(point) R = self.ambient_space().coordinate_ring() point_subs = dict(zip(R.gens(), point)) diff --git a/src/sage/schemes/toric/homset.py b/src/sage/schemes/toric/homset.py index 88516ae0b5e..31bbddde13e 100644 --- a/src/sage/schemes/toric/homset.py +++ b/src/sage/schemes/toric/homset.py @@ -400,7 +400,7 @@ def _finite_field_enumerator(self, finite_field=None): variety = self.codomain() if finite_field is None: finite_field = variety.base_ring() - if not finite_field in FiniteFields(): + if finite_field not in FiniteFields(): raise ValueError('not a finite field') return FiniteFieldPointEnumerator(variety.fan(), finite_field) diff --git a/src/sage/schemes/toric/toric_subscheme.py b/src/sage/schemes/toric/toric_subscheme.py index 728063064cb..524d6fcd657 100644 --- a/src/sage/schemes/toric/toric_subscheme.py +++ b/src/sage/schemes/toric/toric_subscheme.py @@ -324,8 +324,8 @@ def affine_algebraic_patch(self, cone=None, names=None): # inhomogenize the Cox homogeneous polynomial with respect to the given cone inhomogenize = dict( (ambient.coordinate_ring().gen(i), 1) for i in range(0,fan.nrays()) - if not i in cone.ambient_ray_indices() ) - polynomials = [ p.subs(inhomogenize) for p in self.defining_polynomials() ] + if i not in cone.ambient_ray_indices() ) + polynomials = [p.subs(inhomogenize) for p in self.defining_polynomials()] # map the monomial x^{D_m} to m, see reference. n_rho_matrix = cone.rays().matrix() @@ -581,7 +581,7 @@ def is_smooth(self, point=None): sage: Y.is_smooth() True """ - if not point is None: + if point is not None: toric_patch = self.neighborhood(point) return toric_patch.is_smooth(toric_patch.embedding_center()) @@ -886,7 +886,7 @@ def is_smooth(self, point=None): sage: Y.is_smooth([0,0]) True """ - if not point is None: + if point is not None: self._check_satisfies_equations(point) if self.ambient_space().is_smooth(): R = self.ambient_space().coordinate_ring() From f716a0b366e31bbb546230140489244cfb68390d Mon Sep 17 00:00:00 2001 From: Release Manager Date: Fri, 29 Oct 2021 00:56:37 +0200 Subject: [PATCH 511/511] Updated SageMath version to 9.5.beta5 --- .zenodo.json | 8 ++++---- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/sagelib/package-version.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index f80be3c909b..4a9c0e96236 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,10 +1,10 @@ { "description": "Mirror of the Sage https://sagemath.org/ source tree", "license": "other-open", - "title": "sagemath/sage: 9.5.beta4", - "version": "9.5.beta4", + "title": "sagemath/sage: 9.5.beta5", + "version": "9.5.beta5", "upload_type": "software", - "publication_date": "2021-10-19", + "publication_date": "2021-10-28", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.5.beta4", + "identifier": "https://github.com/sagemath/sage/tree/9.5.beta5", "relation": "isSupplementTo" }, { diff --git a/VERSION.txt b/VERSION.txt index d035bc57e4b..c79c2d06798 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.5.beta4, Release Date: 2021-10-19 +SageMath version 9.5.beta5, Release Date: 2021-10-28 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 0b799f8f36f..858bfffb8f3 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=b789b0cad7547f9b699a305d5cfe6a4b67d353df -md5=ad65b7da919dcff932eb34a98793504b -cksum=2565222951 +sha1=ab6592f2216c48049bbbcfb3a42c3e157f44d917 +md5=fc3a50e0f47802e55969eade44648af4 +cksum=3704729867 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 7038ebe859c..0d3e25199f6 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -dc6e96cb4344704cb6779ff68e024d06063d50ee +c5a87834e7e2939b878a5134cd240e6c712bd573 diff --git a/build/pkgs/sagelib/package-version.txt b/build/pkgs/sagelib/package-version.txt index 3fe69eb5038..2b08eebb761 100644 --- a/build/pkgs/sagelib/package-version.txt +++ b/build/pkgs/sagelib/package-version.txt @@ -1 +1 @@ -9.5.beta4 +9.5.beta5 diff --git a/src/VERSION.txt b/src/VERSION.txt index 3fe69eb5038..2b08eebb761 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.5.beta4 +9.5.beta5 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 1fa6283f152..ed215d6aeb0 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,5 +1,5 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.5.beta4' -SAGE_RELEASE_DATE='2021-10-19' -SAGE_VERSION_BANNER='SageMath version 9.5.beta4, Release Date: 2021-10-19' +SAGE_VERSION='9.5.beta5' +SAGE_RELEASE_DATE='2021-10-28' +SAGE_VERSION_BANNER='SageMath version 9.5.beta5, Release Date: 2021-10-28' diff --git a/src/sage/version.py b/src/sage/version.py index 0cd77c29e31..a0bf87ed037 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '9.5.beta4' -date = '2021-10-19' -banner = 'SageMath version 9.5.beta4, Release Date: 2021-10-19' +version = '9.5.beta5' +date = '2021-10-28' +banner = 'SageMath version 9.5.beta5, Release Date: 2021-10-28'