From dfaf9bb27f1a0598fd117696a5ae4d6ed736f837 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sun, 21 Jan 2024 00:22:39 +0100 Subject: [PATCH 01/20] Fix random polynomial bias --- src/sage/rings/polynomial/polynomial_ring.py | 76 +++++++++++++++----- 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 858df388caf..752a5a3e9f5 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1360,7 +1360,7 @@ def ngens(self): """ return 1 - def random_element(self, degree=(-1,2), *args, **kwds): + def random_element(self, degree=(-1,2), monic=False, *args, **kwds): r""" Return a random polynomial of given degree or with given degree bounds. @@ -1386,8 +1386,8 @@ def random_element(self, degree=(-1,2), *args, **kwds): sage: R.random_element(6).degree() 6 - If a tuple of two integers is given for the ``degree`` argument, a degree - is first uniformly chosen, then a polynomial of that degree is given:: + If a tuple of two integers is given for the ``degree`` argument, a polynomial is chosen + uniformly among all polynomials with degree between them:: sage: R.random_element(degree=(0, 8)).degree() in range(0, 9) True @@ -1439,6 +1439,9 @@ def random_element(self, degree=(-1,2), *args, **kwds): if degree[0] <= -2: raise ValueError("degree should be an integer greater or equal than -1") + if monic and degree[0] == -1: + raise ValueError("degree cannot include -1 when monic is set") + # If the coefficient range only contains 0, then # * if the degree range includes -1, return the zero polynomial, # * otherwise raise a value error @@ -1448,24 +1451,65 @@ def random_element(self, degree=(-1,2), *args, **kwds): else: raise ValueError("No polynomial of degree >= 0 has all coefficients zero") - # Pick a random degree - d = randint(degree[0], degree[1]) + if degree == (-1, -1): + return 0 + + if degree[0] == -1: + allow_zero = True + degree = (0, degree[1]) + else: + allow_zero = False + + while True: + # Pick random coefficients + coefs = [] + nonzero = False + + leading = degree[1] - degree[0] + 1 + if monic: + leading -= 1 + coefs.append(1) + + for _ in range(leading): + c = R.random_element(*args, **kwds) + coefs.append(c) + if c != 0: + nonzero = True + + if not (allow_zero or nonzero): + continue + + for _ in range(degree[0]): + c = R.random_element(*args, **kwds) + coefs.append(c) + + coefs.reverse() + return self(coefs) + + def random_monic_element(self, degree=(0, 2), *args, **kwargs): + r""" + Return a random monic polynomial of given degree or with given degree bounds. - # If degree is -1, return the 0 polynomial - if d == -1: - return self.zero() + Calls :meth:`random_element` with ``monic=True``. - # If degree is 0, return a random constant term - if d == 0: - return self(R._random_nonzero_element(*args, **kwds)) + INPUT: - # Pick random coefficients - p = self([R.random_element(*args, **kwds) for _ in range(d)]) + - ``degree`` - optional integer for fixing the degree + or a tuple of minimum and maximum degrees. By default set to + ``(0,2)``. Must not include -1. - # Add non-zero leading coefficient - p += R._random_nonzero_element(*args, **kwds) * self.gen() ** d + - ``*args, **kwds`` - Passed on to the ``random_element`` method for + the base ring - return p + EXAMPLES:: + + sage: R. = GF(13)[] + sage: R.random_element() # random + x^2 + 11*x + 5 + sage: all(R.random_monic_element().is_monic() for _ in range(100)) + True + """ + return self.random_element(degree=degree, monic=True, *args, **kwargs) def _monics_degree(self, of_degree): """ From d67cf847d3d46f8f4bd1e56c810bd42bc9cc6e69 Mon Sep 17 00:00:00 2001 From: grhkm21 <83517584+grhkm21@users.noreply.github.com> Date: Sun, 21 Jan 2024 00:58:57 +0100 Subject: [PATCH 02/20] Allow `degree=-1` together with `monic=True` It is more useful in practice --- src/sage/rings/polynomial/polynomial_ring.py | 26 +++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 752a5a3e9f5..2cbbe28d071 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1370,6 +1370,10 @@ def random_element(self, degree=(-1,2), monic=False, *args, **kwds): or a tuple of minimum and maximum degrees. By default set to ``(-1,2)``. + - ``monic`` - optional boolean to indicate whether the sample + polynomial should be monic or not. If degree includes -1, it is still + possible for the algorithm to return ``0``, which is not monic. + - ``*args, **kwds`` - Passed on to the ``random_element`` method for the base ring @@ -1401,6 +1405,16 @@ def random_element(self, degree=(-1,2), monic=False, *args, **kwds): sage: while R.random_element(degree=(-1,2), x=-1, y=1) != R.zero(): ....: pass + It is possible to sample a monic polynomial:: + + sage: R.random_element(5, monic=True).is_monic() + True + + Note that if the degree range includes `-1`, then the resulting polynomial might not be monic:: + + sage: all(R.random_element(degree=(-1, 1), monic=True).is_monic() for _ in range(10^3)) + False + TESTS:: sage: R.random_element(degree=[5]) @@ -1439,8 +1453,9 @@ def random_element(self, degree=(-1,2), monic=False, *args, **kwds): if degree[0] <= -2: raise ValueError("degree should be an integer greater or equal than -1") - if monic and degree[0] == -1: - raise ValueError("degree cannot include -1 when monic is set") + # Actually, it's probably more useful to let the user check this. + # if monic and degree[0] == -1: + # raise ValueError("degree cannot include -1 when monic is set") # If the coefficient range only contains 0, then # * if the degree range includes -1, return the zero polynomial, @@ -1496,18 +1511,21 @@ def random_monic_element(self, degree=(0, 2), *args, **kwargs): - ``degree`` - optional integer for fixing the degree or a tuple of minimum and maximum degrees. By default set to - ``(0,2)``. Must not include -1. + ``(0,2)``. If the bounds include ``-1``, it is still possible for the + algorithm to return ``0``, which is not monic. - ``*args, **kwds`` - Passed on to the ``random_element`` method for the base ring EXAMPLES:: - sage: R. = GF(13)[] + sage: R. = GF(3)[] sage: R.random_element() # random x^2 + 11*x + 5 sage: all(R.random_monic_element().is_monic() for _ in range(100)) True + sage: all(R.random_monic_element(degree=(-1,1)).is_monic() for _ in range(100)) + True """ return self.random_element(degree=degree, monic=True, *args, **kwargs) From e4817865bcaeeeddaa04caec236d5ab0e398d24b Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sun, 21 Jan 2024 01:05:10 +0100 Subject: [PATCH 03/20] Fix buggy sampling --- src/sage/rings/polynomial/polynomial_ring.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 2cbbe28d071..98756d26af3 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1480,15 +1480,11 @@ def random_element(self, degree=(-1,2), monic=False, *args, **kwds): coefs = [] nonzero = False - leading = degree[1] - degree[0] + 1 - if monic: - leading -= 1 - coefs.append(1) - - for _ in range(leading): + for _ in range(degree[1] - degree[0] + 1): c = R.random_element(*args, **kwds) coefs.append(c) - if c != 0: + if c != 0 and not nonzero: + coefs[-1] = 1 nonzero = True if not (allow_zero or nonzero): From f4b72cdab0ddcb4eb62be5a3230a16797bdce966 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Wed, 24 Jan 2024 03:03:57 +0000 Subject: [PATCH 04/20] =?UTF-8?q?apply=20review=20changes=20=F0=9F=93=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/rings/polynomial/polynomial_ring.py | 59 ++++++++++++-------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 98756d26af3..06116324f03 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1360,7 +1360,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_or_zero=False, *args, **kwds): r""" Return a random polynomial of given degree or with given degree bounds. @@ -1370,9 +1370,9 @@ def random_element(self, degree=(-1,2), monic=False, *args, **kwds): or a tuple of minimum and maximum degrees. By default set to ``(-1,2)``. - - ``monic`` - optional boolean to indicate whether the sample - polynomial should be monic or not. If degree includes -1, it is still - possible for the algorithm to return ``0``, which is not monic. + - ``monic_or_zero`` - optional boolean to indicate whether the sampled + polynomial should be monic or zero, or not. If ``degree`` includes + -1, the algorithm output range will also include zero. - ``*args, **kwds`` - Passed on to the ``random_element`` method for the base ring @@ -1380,7 +1380,7 @@ def random_element(self, degree=(-1,2), monic=False, *args, **kwds): EXAMPLES:: sage: R. = ZZ[] - sage: f = R.random_element(10, 5, 10) + sage: f = R.random_element(10, x=5, y=10) sage: f.degree() 10 sage: f.parent() is R @@ -1405,15 +1405,20 @@ def random_element(self, degree=(-1,2), monic=False, *args, **kwds): sage: while R.random_element(degree=(-1,2), x=-1, y=1) != R.zero(): ....: pass - It is possible to sample a monic polynomial:: + It is possible to sample a monic polynomial, but it is preferable to + use :meth:`random_monic_element`:: - sage: R.random_element(5, monic=True).is_monic() + sage: R.random_element(degree=(0, 5), monic_or_zero=True).is_monic() + True + sage: R.random_monic_element(degree=(0, 5)).is_monic() True Note that if the degree range includes `-1`, then the resulting polynomial might not be monic:: - sage: all(R.random_element(degree=(-1, 1), monic=True).is_monic() for _ in range(10^3)) + sage: all(R.random_element(degree=(-1, 1), monic_or_zero=True).is_monic() for _ in range(10^3)) False + sage: all(R.random_element(degree=(0, 1), monic_or_zero=True).is_monic() for _ in range(10^3)) + True TESTS:: @@ -1435,6 +1440,8 @@ def random_element(self, degree=(-1,2), monic=False, *args, **kwds): ....: P = R.random_element(degree=d) ....: assert P.degree() == d, "problem with {} which has not degree {}".format(P,d) + In :issue:`37118`, negative degrees no longer error. + sage: R.random_element(degree=-2) Traceback (most recent call last): ... @@ -1451,7 +1458,9 @@ def random_element(self, degree=(-1,2), monic=False, *args, **kwds): degree = (degree,degree) if degree[0] <= -2: - raise ValueError("degree should be an integer greater or equal than -1") + # This error has been removed in issue #37118. + # raise ValueError("degree should be an integer greater or equal than -1") + degree = (-1, degree[1]) # Actually, it's probably more useful to let the user check this. # if monic and degree[0] == -1: @@ -1467,7 +1476,7 @@ def random_element(self, degree=(-1,2), monic=False, *args, **kwds): raise ValueError("No polynomial of degree >= 0 has all coefficients zero") if degree == (-1, -1): - return 0 + return self.zero() if degree[0] == -1: allow_zero = True @@ -1477,38 +1486,38 @@ def random_element(self, degree=(-1,2), monic=False, *args, **kwds): while True: # Pick random coefficients - coefs = [] + coefs = [None] * (degree[1] + 1) nonzero = False - for _ in range(degree[1] - degree[0] + 1): - c = R.random_element(*args, **kwds) - coefs.append(c) - if c != 0 and not nonzero: - coefs[-1] = 1 + for i in range(degree[1] - degree[0] + 1): + coefs[i] = R.random_element(*args, **kwds) + if monic_or_zero and not nonzero and not coefs[i].is_zero(): + coefs[i] = R.one() nonzero = True if not (allow_zero or nonzero): continue - for _ in range(degree[0]): - c = R.random_element(*args, **kwds) - coefs.append(c) + for i in range(degree[1] - degree[0] + 1, degree[1] + 1): + coefs[i] = R.random_element(*args, **kwds) coefs.reverse() return self(coefs) - def random_monic_element(self, degree=(0, 2), *args, **kwargs): + def random_monic_element(self, degree=(0, 2), zero=False, *args, **kwargs): r""" Return a random monic polynomial of given degree or with given degree bounds. - Calls :meth:`random_element` with ``monic=True``. + Calls :meth:`random_element` with ``monic_or_zero=True``. INPUT: - ``degree`` - optional integer for fixing the degree or a tuple of minimum and maximum degrees. By default set to - ``(0,2)``. If the bounds include ``-1``, it is still possible for the - algorithm to return ``0``, which is not monic. + ``(0, 2)``. + + - ``zero`` - boolean, if set the algorithm may return `0`, even though + it is not a monic polynomial. By default set to ``False``. - ``*args, **kwds`` - Passed on to the ``random_element`` method for the base ring @@ -1523,7 +1532,9 @@ def random_monic_element(self, degree=(0, 2), *args, **kwargs): sage: all(R.random_monic_element(degree=(-1,1)).is_monic() for _ in range(100)) True """ - return self.random_element(degree=degree, monic=True, *args, **kwargs) + if not zero and degree[0] < 0: + degree = (0, degree[1]) + return self.random_element(degree=degree, monic_or_zero=True, *args, **kwargs) def _monics_degree(self, of_degree): """ From 388849cafe102c12ff5bddb211f52627ea1f71d8 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Wed, 24 Jan 2024 14:15:46 +0000 Subject: [PATCH 05/20] =?UTF-8?q?apply=20review=20changes=20=F0=9F=93=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/rings/polynomial/polynomial_ring.py | 178 +++++++++++++++---- 1 file changed, 139 insertions(+), 39 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 06116324f03..c8a2ebd161e 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1360,9 +1360,9 @@ def ngens(self): """ return 1 - def random_element(self, degree=(-1, 2), monic_or_zero=False, *args, **kwds): + def random_element(self, degree=(-1, 2), monic=False, _allow_zero=False, *args, **kwds): r""" - Return a random polynomial of given degree or with given degree bounds. + Return a random polynomial of given degree (bounds). INPUT: @@ -1370,17 +1370,31 @@ def random_element(self, degree=(-1, 2), monic_or_zero=False, *args, **kwds): or a tuple of minimum and maximum degrees. By default set to ``(-1,2)``. - - ``monic_or_zero`` - optional boolean to indicate whether the sampled - polynomial should be monic or zero, or not. If ``degree`` includes - -1, the algorithm output range will also include zero. + - ``monic`` - optional boolean to indicate whether the sampled + polynomial should be monic, or not. If this is set, `0` is not a + possible output of the method. If monic and `0` are both needed, + one should use :meth:`random_monic_or_zero_element`. + + - ``_allow_zero`` - optional boolean to indicate whether zero should be + included. If ``monic`` is not set, or the degree bound does not + include `-1`, then this argument does nothing. Otherwise, the + algorithm returns either monic or `0` polynomials (with uniform + probability over the range of output). This is for internal use, users + should use :meth:`random_monic_or_zero_element`. - ``*args, **kwds`` - Passed on to the ``random_element`` method for - the base ring + the base ring. + + .. SEEALSO:: + + :meth:`random_monic_element`, :meth:`random_monic_or_zero_element` EXAMPLES:: sage: R. = ZZ[] sage: f = R.random_element(10, x=5, y=10) + sage: f # random + 5*x^10 + 6*x^9 + 5*x^8 + 8*x^7 + 8*x^6 + 5*x^5 + 7*x^4 + 8*x^3 + 6*x^2 + 9*x + 6 sage: f.degree() 10 sage: f.parent() is R @@ -1406,18 +1420,18 @@ def random_element(self, degree=(-1, 2), monic_or_zero=False, *args, **kwds): ....: pass It is possible to sample a monic polynomial, but it is preferable to - use :meth:`random_monic_element`:: + use :meth:`random_monic_element` or :meth:`random_monic_or_zero_element`:: - sage: R.random_element(degree=(0, 5), monic_or_zero=True).is_monic() + sage: R.random_element(degree=(-1, 5), monic=True).is_monic() True - sage: R.random_monic_element(degree=(0, 5)).is_monic() + sage: R.random_monic_element(degree=(-1, 5)).is_monic() True - Note that if the degree range includes `-1`, then the resulting polynomial might not be monic:: + Note that if the degree range includes `-1` and ``monic`` is set, it is silently ignored:: - sage: all(R.random_element(degree=(-1, 1), monic_or_zero=True).is_monic() for _ in range(10^3)) - False - sage: all(R.random_element(degree=(0, 1), monic_or_zero=True).is_monic() for _ in range(10^3)) + sage: all(R.random_element(degree=(-1, 1), monic=True).is_monic() for _ in range(10^3)) + True + sage: all(R.random_element(degree=(0, 1), monic=True).is_monic() for _ in range(10^3)) True TESTS:: @@ -1440,12 +1454,21 @@ def random_element(self, degree=(-1, 2), monic_or_zero=False, *args, **kwds): ....: P = R.random_element(degree=d) ....: assert P.degree() == d, "problem with {} which has not degree {}".format(P,d) - In :issue:`37118`, negative degrees no longer error. + In :issue:`37118`, ranges including integers below `-1` no longer error:: - sage: R.random_element(degree=-2) - Traceback (most recent call last): - ... - ValueError: degree should be an integer greater or equal than -1 + sage: R.random_element(degree=(-2, 3)) # random + 1 + + :: + + sage: 0 in [R.random_element(degree=(-1, 2), monic=True) for _ in range(500)] + False + sage: 0 in [R.random_element(degree=(-1, 2), monic=True, _allow_zero=True) for _ in range(500)] + True + sage: 0 in [R.random_monic_element(degree=(-1, 2)) for _ in range(500)] + False + sage: 0 in [R.random_monic_or_zero_element(degree=(-1, 2)) for _ in range(500)] + True """ R = self.base_ring() @@ -1462,10 +1485,6 @@ def random_element(self, degree=(-1, 2), monic_or_zero=False, *args, **kwds): # raise ValueError("degree should be an integer greater or equal than -1") degree = (-1, degree[1]) - # Actually, it's probably more useful to let the user check this. - # if monic and degree[0] == -1: - # raise ValueError("degree cannot include -1 when monic is set") - # If the coefficient range only contains 0, then # * if the degree range includes -1, return the zero polynomial, # * otherwise raise a value error @@ -1478,35 +1497,54 @@ def random_element(self, degree=(-1, 2), monic_or_zero=False, *args, **kwds): if degree == (-1, -1): return self.zero() + # If `monic` is set and `_allow_zero` is not, zero should be ignored if degree[0] == -1: - allow_zero = True degree = (0, degree[1]) + has_zero = not monic or _allow_zero else: - allow_zero = False + has_zero = False while True: # Pick random coefficients coefs = [None] * (degree[1] + 1) nonzero = False - for i in range(degree[1] - degree[0] + 1): - coefs[i] = R.random_element(*args, **kwds) - if monic_or_zero and not nonzero and not coefs[i].is_zero(): - coefs[i] = R.one() - nonzero = True + # Pick leading coefficients, if `monic` is set it's handle here. + if monic: + for i in range(degree[1] - degree[0] + 1): + coefs[i] = R.random_element(*args, **kwds) + if not nonzero and not coefs[i].is_zero(): + coefs[i] = R.one() + nonzero = True - if not (allow_zero or nonzero): - continue + if not nonzero and not _allow_zero: + continue + else: + # Fast path + for i in range(degree[1] - degree[0] + 1): + coefs[i] = R.random_element(*args, **kwds) + nonzero |= not coefs[i].is_zero() + if not nonzero and not has_zero: + continue + + # Now we pick the remaining coefficients. Zeros still should be + # tracked to handle `has_zero`. for i in range(degree[1] - degree[0] + 1, degree[1] + 1): coefs[i] = R.random_element(*args, **kwds) + nonzero |= not coefs[i].is_zero() + + # If we don't want zero (not has_zero), but coefs is zero (not + # nonzero), then reject + if not has_zero and not nonzero: + continue coefs.reverse() return self(coefs) - def random_monic_element(self, degree=(0, 2), zero=False, *args, **kwargs): + def random_monic_element(self, degree=(0, 2), *args, **kwargs): r""" - Return a random monic polynomial of given degree or with given degree bounds. + Return a random monic polynomial of given degree (bounds). Calls :meth:`random_element` with ``monic_or_zero=True``. @@ -1520,21 +1558,83 @@ def random_monic_element(self, degree=(0, 2), zero=False, *args, **kwargs): it is not a monic polynomial. By default set to ``False``. - ``*args, **kwds`` - Passed on to the ``random_element`` method for - the base ring + the base ring. + + .. SEEALSO:: + + :meth:`random_element`, :meth:`random_monic_or_zero_element` EXAMPLES:: sage: R. = GF(3)[] - sage: R.random_element() # random - x^2 + 11*x + 5 + sage: R.random_monic_element() # random + x^2 + x + 1 sage: all(R.random_monic_element().is_monic() for _ in range(100)) True sage: all(R.random_monic_element(degree=(-1,1)).is_monic() for _ in range(100)) True + + TESTS: + + There are 7 monic polynomials of degree not exceeding 2 over GF(2). We + apply the chi-square test:: + + sage: from collections import Counter + sage: from scipy.stats import chisquare + sage: N = 10^5 + sage: R. = GF(2)[] + sage: cnts = Counter(R.random_monic_element() for _ in range(N)) + sage: chisquare(list(cnts.values()), [N / 7] * 7).pvalue < 0.1 + False + """ + return self.random_element(degree=degree, monic=True, *args, **kwargs) + + def random_monic_or_zero_element(self, degree=(-1, 2), *args, **kwargs): + r""" + Return a random polynomial that is either monic or zero of given degree (bounds). + + INPUT: + + - ``degree`` - optional integer for fixing the degree + or a tuple of minimum and maximum degrees. By default set to + ``(0, 2)``. + + - ``zero`` - boolean, if set the algorithm may return `0`, even though + it is not a monic polynomial. By default set to ``False``. + + - ``*args, **kwds`` - Passed on to the ``random_element`` method for + the base ring. + + .. SEEALSO:: + + :meth:`random_element`, :meth:`random_monic_or_zero_element` + + EXAMPLES:: + + sage: R. = GF(2)[] + sage: R.random_monic_or_zero_element() # random + x^2 + x + 1 + sage: all(R.random_monic_or_zero_element().is_monic() for _ in range(500)) + False + sage: 0 in [R.random_monic_or_zero_element().is_monic() for _ in range(500)] + True + sage: all(R.random_monic_element(degree=(-1,1)).is_monic() for _ in range(500)) + True + + TESTS: + + There are 8 monic or zero polynomials of degree not exceeding 2 over + GF(2). We apply the chi-square test:: + + sage: from collections import Counter + sage: from scipy.stats import chisquare + sage: N = 10^5 + sage: R. = GF(2)[] + sage: cnts = Counter(R.random_monic_or_zero_element() for _ in range(N)) + sage: chisquare(list(cnts.values()), [N / 8] * 8).pvalue < 0.1 + False """ - if not zero and degree[0] < 0: - degree = (0, degree[1]) - return self.random_element(degree=degree, monic_or_zero=True, *args, **kwargs) + return self.random_element(degree=degree, monic=True, _allow_zero=True, *args, **kwargs) def _monics_degree(self, of_degree): """ From efac3ca246cb9d8ec9a36abb51798b9f6ca9aaca Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Thu, 25 Jan 2024 16:48:52 +0000 Subject: [PATCH 06/20] =?UTF-8?q?apply=20review=20changes=20=F0=9F=93=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit removes all `monic_or_zero` methods. --- src/sage/rings/polynomial/polynomial_ring.py | 87 ++++---------------- 1 file changed, 14 insertions(+), 73 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index c8a2ebd161e..241b1dfe2de 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1360,34 +1360,25 @@ def ngens(self): """ return 1 - def random_element(self, degree=(-1, 2), monic=False, _allow_zero=False, *args, **kwds): + def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): r""" Return a random polynomial of given degree (bounds). INPUT: - - ``degree`` - optional integer for fixing the degree - or a tuple of minimum and maximum degrees. By default set to - ``(-1,2)``. + - ``degree`` - (default: ``(-1, 2)``) integer for fixing the degree or + a tuple of minimum and maximum degrees. - ``monic`` - optional boolean to indicate whether the sampled polynomial should be monic, or not. If this is set, `0` is not a - possible output of the method. If monic and `0` are both needed, - one should use :meth:`random_monic_or_zero_element`. - - - ``_allow_zero`` - optional boolean to indicate whether zero should be - included. If ``monic`` is not set, or the degree bound does not - include `-1`, then this argument does nothing. Otherwise, the - algorithm returns either monic or `0` polynomials (with uniform - probability over the range of output). This is for internal use, users - should use :meth:`random_monic_or_zero_element`. + possible output of the method. - ``*args, **kwds`` - Passed on to the ``random_element`` method for the base ring. .. SEEALSO:: - :meth:`random_monic_element`, :meth:`random_monic_or_zero_element` + :meth:`random_monic_element` EXAMPLES:: @@ -1420,7 +1411,7 @@ def random_element(self, degree=(-1, 2), monic=False, _allow_zero=False, *args, ....: pass It is possible to sample a monic polynomial, but it is preferable to - use :meth:`random_monic_element` or :meth:`random_monic_or_zero_element`:: + use :meth:`random_monic_element`:: sage: R.random_element(degree=(-1, 5), monic=True).is_monic() True @@ -1456,19 +1447,15 @@ def random_element(self, degree=(-1, 2), monic=False, _allow_zero=False, *args, In :issue:`37118`, ranges including integers below `-1` no longer error:: - sage: R.random_element(degree=(-2, 3)) # random + sage: R.random_element(degree=(-2, 3)) # random 1 :: sage: 0 in [R.random_element(degree=(-1, 2), monic=True) for _ in range(500)] False - sage: 0 in [R.random_element(degree=(-1, 2), monic=True, _allow_zero=True) for _ in range(500)] - True sage: 0 in [R.random_monic_element(degree=(-1, 2)) for _ in range(500)] False - sage: 0 in [R.random_monic_or_zero_element(degree=(-1, 2)) for _ in range(500)] - True """ R = self.base_ring() @@ -1497,10 +1484,10 @@ def random_element(self, degree=(-1, 2), monic=False, _allow_zero=False, *args, if degree == (-1, -1): return self.zero() - # If `monic` is set and `_allow_zero` is not, zero should be ignored + # If `monic` is set, zero should be ignored if degree[0] == -1: degree = (0, degree[1]) - has_zero = not monic or _allow_zero + has_zero = not monic else: has_zero = False @@ -1517,7 +1504,8 @@ def random_element(self, degree=(-1, 2), monic=False, _allow_zero=False, *args, coefs[i] = R.one() nonzero = True - if not nonzero and not _allow_zero: + # Leading terms must be nonzero + if not nonzero: continue else: # Fast path @@ -1546,7 +1534,7 @@ def random_monic_element(self, degree=(0, 2), *args, **kwargs): r""" Return a random monic polynomial of given degree (bounds). - Calls :meth:`random_element` with ``monic_or_zero=True``. + Calls :meth:`random_element` with ``monic=True``. INPUT: @@ -1562,7 +1550,7 @@ def random_monic_element(self, degree=(0, 2), *args, **kwargs): .. SEEALSO:: - :meth:`random_element`, :meth:`random_monic_or_zero_element` + :meth:`random_element` EXAMPLES:: @@ -1571,7 +1559,7 @@ def random_monic_element(self, degree=(0, 2), *args, **kwargs): x^2 + x + 1 sage: all(R.random_monic_element().is_monic() for _ in range(100)) True - sage: all(R.random_monic_element(degree=(-1,1)).is_monic() for _ in range(100)) + sage: all(R.random_monic_element(degree=(-1, 1)).is_monic() for _ in range(100)) True TESTS: @@ -1589,53 +1577,6 @@ def random_monic_element(self, degree=(0, 2), *args, **kwargs): """ return self.random_element(degree=degree, monic=True, *args, **kwargs) - def random_monic_or_zero_element(self, degree=(-1, 2), *args, **kwargs): - r""" - Return a random polynomial that is either monic or zero of given degree (bounds). - - INPUT: - - - ``degree`` - optional integer for fixing the degree - or a tuple of minimum and maximum degrees. By default set to - ``(0, 2)``. - - - ``zero`` - boolean, if set the algorithm may return `0`, even though - it is not a monic polynomial. By default set to ``False``. - - - ``*args, **kwds`` - Passed on to the ``random_element`` method for - the base ring. - - .. SEEALSO:: - - :meth:`random_element`, :meth:`random_monic_or_zero_element` - - EXAMPLES:: - - sage: R. = GF(2)[] - sage: R.random_monic_or_zero_element() # random - x^2 + x + 1 - sage: all(R.random_monic_or_zero_element().is_monic() for _ in range(500)) - False - sage: 0 in [R.random_monic_or_zero_element().is_monic() for _ in range(500)] - True - sage: all(R.random_monic_element(degree=(-1,1)).is_monic() for _ in range(500)) - True - - TESTS: - - There are 8 monic or zero polynomials of degree not exceeding 2 over - GF(2). We apply the chi-square test:: - - sage: from collections import Counter - sage: from scipy.stats import chisquare - sage: N = 10^5 - sage: R. = GF(2)[] - sage: cnts = Counter(R.random_monic_or_zero_element() for _ in range(N)) - sage: chisquare(list(cnts.values()), [N / 8] * 8).pvalue < 0.1 - False - """ - return self.random_element(degree=degree, monic=True, _allow_zero=True, *args, **kwargs) - def _monics_degree(self, of_degree): """ Refer to monics() for full documentation. From 2495622e4197264bc422aac5cc4701e33202633b Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Thu, 25 Jan 2024 16:49:49 +0000 Subject: [PATCH 07/20] fix docstring fullstops --- src/sage/rings/polynomial/polynomial_ring.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 241b1dfe2de..b1e522648d5 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1367,14 +1367,14 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): INPUT: - ``degree`` - (default: ``(-1, 2)``) integer for fixing the degree or - a tuple of minimum and maximum degrees. + a tuple of minimum and maximum degrees - ``monic`` - optional boolean to indicate whether the sampled polynomial should be monic, or not. If this is set, `0` is not a - possible output of the method. + possible output of the method - ``*args, **kwds`` - Passed on to the ``random_element`` method for - the base ring. + the base ring .. SEEALSO:: @@ -1540,13 +1540,13 @@ def random_monic_element(self, degree=(0, 2), *args, **kwargs): - ``degree`` - optional integer for fixing the degree or a tuple of minimum and maximum degrees. By default set to - ``(0, 2)``. + ``(0, 2)`` - ``zero`` - boolean, if set the algorithm may return `0`, even though - it is not a monic polynomial. By default set to ``False``. + it is not a monic polynomial. By default set to ``False`` - ``*args, **kwds`` - Passed on to the ``random_element`` method for - the base ring. + the base ring .. SEEALSO:: From 7d4ece61ca001501263073f500c63b99d14e8876 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Thu, 25 Jan 2024 16:50:49 +0000 Subject: [PATCH 08/20] fix styling --- src/sage/rings/polynomial/polynomial_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index b1e522648d5..b9ef769cab8 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1384,7 +1384,7 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): sage: R. = ZZ[] sage: f = R.random_element(10, x=5, y=10) - sage: f # random + sage: f # random 5*x^10 + 6*x^9 + 5*x^8 + 8*x^7 + 8*x^6 + 5*x^5 + 7*x^4 + 8*x^3 + 6*x^2 + 9*x + 6 sage: f.degree() 10 From a879ac52685f4e07b9009b341df4421d9282522c Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Tue, 30 Jan 2024 15:42:09 +0000 Subject: [PATCH 09/20] =?UTF-8?q?apply=20review=20changes=20=F0=9F=93=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/rings/polynomial/polynomial_ring.py | 69 ++++++++++++-------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index b9ef769cab8..f74674fb3b7 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1370,11 +1370,10 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): a tuple of minimum and maximum degrees - ``monic`` - optional boolean to indicate whether the sampled - polynomial should be monic, or not. If this is set, `0` is not a - possible output of the method + polynomial should be monic - - ``*args, **kwds`` - Passed on to the ``random_element`` method for - the base ring + - ``*args, **kwds`` - additional keyword parameters passed on to the + ``random_element`` method for the base ring .. SEEALSO:: @@ -1418,7 +1417,8 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): sage: R.random_monic_element(degree=(-1, 5)).is_monic() True - Note that if the degree range includes `-1` and ``monic`` is set, it is silently ignored:: + Note that if the degree range includes `-1` and ``monic`` is set, it is + silently ignored, as `0` is not a monic polynomial:: sage: all(R.random_element(degree=(-1, 1), monic=True).is_monic() for _ in range(10^3)) True @@ -1441,14 +1441,15 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): sage: R = PolynomialRing(GF(2), 'z') sage: for _ in range(100): - ....: d = randint(-1,20) + ....: d = randint(-1, 20) ....: P = R.random_element(degree=d) - ....: assert P.degree() == d, "problem with {} which has not degree {}".format(P,d) + ....: assert P.degree() == d - In :issue:`37118`, ranges including integers below `-1` no longer error:: + In :issue:`37118`, ranges including integers below `-1` no longer raise + an error:: sage: R.random_element(degree=(-2, 3)) # random - 1 + z^3 + z^2 + 1 :: @@ -1456,6 +1457,18 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): False sage: 0 in [R.random_monic_element(degree=(-1, 2)) for _ in range(500)] False + + Testing error handling:: + + sage: R.random_element(degree=-5) + Traceback (most recent call last): + ... + ValueError: degree (=-5) must be at least -1 + + sage: R.random_element(degree=(-3, -2)) + Traceback (most recent call last): + ... + ValueError: maximum degree (=-2) must be at least -1 """ R = self.base_ring() @@ -1464,8 +1477,12 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): raise ValueError("degree argument must be an integer or a tuple of 2 integers (min_degree, max_degree)") if degree[0] > degree[1]: raise ValueError("minimum degree must be less or equal than maximum degree") + if degree[1] < -1: + raise ValueError(f"maximum degree (={degree[1]}) must be at least -1") else: - degree = (degree,degree) + if degree < -1: + raise ValueError(f"degree (={degree}) must be at least -1") + degree = (degree, degree) if degree[0] <= -2: # This error has been removed in issue #37118. @@ -1481,53 +1498,47 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): else: raise ValueError("No polynomial of degree >= 0 has all coefficients zero") + degree_lb = degree[0] if degree == (-1, -1): return self.zero() # If `monic` is set, zero should be ignored - if degree[0] == -1: + if degree[0] == -1 and monic: degree = (0, degree[1]) - has_zero = not monic - else: - has_zero = False while True: # Pick random coefficients + end = degree[1] coefs = [None] * (degree[1] + 1) nonzero = False # Pick leading coefficients, if `monic` is set it's handle here. if monic: for i in range(degree[1] - degree[0] + 1): - coefs[i] = R.random_element(*args, **kwds) - if not nonzero and not coefs[i].is_zero(): - coefs[i] = R.one() + coefs[end - i] = R.random_element(*args, **kwds) + if not nonzero and not coefs[end - i].is_zero(): + coefs[end - i] = R.one() nonzero = True - - # Leading terms must be nonzero - if not nonzero: - continue else: # Fast path for i in range(degree[1] - degree[0] + 1): - coefs[i] = R.random_element(*args, **kwds) - nonzero |= not coefs[i].is_zero() + coefs[end - i] = R.random_element(*args, **kwds) + nonzero |= not coefs[end - i].is_zero() - if not nonzero and not has_zero: - continue + # Leading terms must be nonzero + if not nonzero: + continue # Now we pick the remaining coefficients. Zeros still should be # tracked to handle `has_zero`. for i in range(degree[1] - degree[0] + 1, degree[1] + 1): - coefs[i] = R.random_element(*args, **kwds) - nonzero |= not coefs[i].is_zero() + coefs[end - i] = R.random_element(*args, **kwds) # If we don't want zero (not has_zero), but coefs is zero (not # nonzero), then reject - if not has_zero and not nonzero: + if degree_lb == -1 and not nonzero: continue - coefs.reverse() return self(coefs) def random_monic_element(self, degree=(0, 2), *args, **kwargs): From 969c37d6913f019685f76ffe9b244b02fa652363 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Thu, 8 Feb 2024 12:33:51 +0000 Subject: [PATCH 10/20] =?UTF-8?q?apply=20review=20changes=20=F0=9F=93=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/rings/polynomial/polynomial_ring.py | 61 -------------------- 1 file changed, 61 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index f74674fb3b7..55dab10d8dd 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1375,10 +1375,6 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): - ``*args, **kwds`` - additional keyword parameters passed on to the ``random_element`` method for the base ring - .. SEEALSO:: - - :meth:`random_monic_element` - EXAMPLES:: sage: R. = ZZ[] @@ -1409,14 +1405,6 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): sage: while R.random_element(degree=(-1,2), x=-1, y=1) != R.zero(): ....: pass - It is possible to sample a monic polynomial, but it is preferable to - use :meth:`random_monic_element`:: - - sage: R.random_element(degree=(-1, 5), monic=True).is_monic() - True - sage: R.random_monic_element(degree=(-1, 5)).is_monic() - True - Note that if the degree range includes `-1` and ``monic`` is set, it is silently ignored, as `0` is not a monic polynomial:: @@ -1455,8 +1443,6 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): sage: 0 in [R.random_element(degree=(-1, 2), monic=True) for _ in range(500)] False - sage: 0 in [R.random_monic_element(degree=(-1, 2)) for _ in range(500)] - False Testing error handling:: @@ -1541,53 +1527,6 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): return self(coefs) - def random_monic_element(self, degree=(0, 2), *args, **kwargs): - r""" - Return a random monic polynomial of given degree (bounds). - - Calls :meth:`random_element` with ``monic=True``. - - INPUT: - - - ``degree`` - optional integer for fixing the degree - or a tuple of minimum and maximum degrees. By default set to - ``(0, 2)`` - - - ``zero`` - boolean, if set the algorithm may return `0`, even though - it is not a monic polynomial. By default set to ``False`` - - - ``*args, **kwds`` - Passed on to the ``random_element`` method for - the base ring - - .. SEEALSO:: - - :meth:`random_element` - - EXAMPLES:: - - sage: R. = GF(3)[] - sage: R.random_monic_element() # random - x^2 + x + 1 - sage: all(R.random_monic_element().is_monic() for _ in range(100)) - True - sage: all(R.random_monic_element(degree=(-1, 1)).is_monic() for _ in range(100)) - True - - TESTS: - - There are 7 monic polynomials of degree not exceeding 2 over GF(2). We - apply the chi-square test:: - - sage: from collections import Counter - sage: from scipy.stats import chisquare - sage: N = 10^5 - sage: R. = GF(2)[] - sage: cnts = Counter(R.random_monic_element() for _ in range(N)) - sage: chisquare(list(cnts.values()), [N / 7] * 7).pvalue < 0.1 - False - """ - return self.random_element(degree=degree, monic=True, *args, **kwargs) - def _monics_degree(self, of_degree): """ Refer to monics() for full documentation. From ccfdd938dfb330eda81716a1bdca020983ba7ab0 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Fri, 9 Feb 2024 16:46:22 +0000 Subject: [PATCH 11/20] =?UTF-8?q?refactor=20`.random=5Felement`=20?= =?UTF-8?q?=F0=9F=93=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/rings/polynomial/polynomial_ring.py | 61 +++++++++----------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 55dab10d8dd..a56689ae0b2 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1318,7 +1318,7 @@ def monomial(self, exponent): sage: R.monomial(m.degree()) == m True """ - return self({exponent:self.base_ring().one()}) + return self({exponent: self.base_ring().one()}) def krull_dimension(self): """ @@ -1369,7 +1369,7 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): - ``degree`` - (default: ``(-1, 2)``) integer for fixing the degree or a tuple of minimum and maximum degrees - - ``monic`` - optional boolean to indicate whether the sampled + - ``monic`` - boolean (optional); indicate whether the sampled polynomial should be monic - ``*args, **kwds`` - additional keyword parameters passed on to the @@ -1379,8 +1379,6 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): sage: R. = ZZ[] sage: f = R.random_element(10, x=5, y=10) - sage: f # random - 5*x^10 + 6*x^9 + 5*x^8 + 8*x^7 + 8*x^6 + 5*x^5 + 7*x^4 + 8*x^3 + 6*x^2 + 9*x + 6 sage: f.degree() 10 sage: f.parent() is R @@ -1391,13 +1389,14 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): 6 If a tuple of two integers is given for the ``degree`` argument, a polynomial is chosen - uniformly among all polynomials with degree between them:: + among all polynomials with degree between them. If the base ring is uniform, so is this + method:: - sage: R.random_element(degree=(0, 8)).degree() in range(0, 9) + sage: R.random_element(degree=(0, 4)).degree() in range(0, 5) True - sage: found = [False]*9 + sage: found = [False]*5 sage: while not all(found): - ....: found[R.random_element(degree=(0, 8)).degree()] = True + ....: found[R.random_element(degree=(0, 4)).degree()] = True Note that the zero polynomial has degree `-1`, so if you want to consider it set the minimum degree to `-1`:: @@ -1405,8 +1404,8 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): sage: while R.random_element(degree=(-1,2), x=-1, y=1) != R.zero(): ....: pass - Note that if the degree range includes `-1` and ``monic`` is set, it is - silently ignored, as `0` is not a monic polynomial:: + Monic polynomials are chosen among all monic polynomials with degree between the given + ``degree`` argument:: sage: all(R.random_element(degree=(-1, 1), monic=True).is_monic() for _ in range(10^3)) True @@ -1471,8 +1470,6 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): degree = (degree, degree) if degree[0] <= -2: - # This error has been removed in issue #37118. - # raise ValueError("degree should be an integer greater or equal than -1") degree = (-1, degree[1]) # If the coefficient range only contains 0, then @@ -1484,20 +1481,26 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): else: raise ValueError("No polynomial of degree >= 0 has all coefficients zero") - degree_lb = degree[0] if degree == (-1, -1): return self.zero() # If `monic` is set, zero should be ignored if degree[0] == -1 and monic: + if degree[1] == -1: + raise ValueError("the maximum degree of monic polynomials needs to be at least 0") + if degree[1] == 0: + return self.one() degree = (0, degree[1]) - while True: - # Pick random coefficients - end = degree[1] - coefs = [None] * (degree[1] + 1) - nonzero = False + # Pick random coefficients + end = degree[1] + if degree[0] == -1: + return self([R.random_element(*args, **kwds) for _ in range(end + 1)]) + nonzero = False + coefs = [None] * (end + 1) + + while not nonzero: # Pick leading coefficients, if `monic` is set it's handle here. if monic: for i in range(degree[1] - degree[0] + 1): @@ -1511,21 +1514,11 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): coefs[end - i] = R.random_element(*args, **kwds) nonzero |= not coefs[end - i].is_zero() - # Leading terms must be nonzero - if not nonzero: - continue - - # Now we pick the remaining coefficients. Zeros still should be - # tracked to handle `has_zero`. - for i in range(degree[1] - degree[0] + 1, degree[1] + 1): - coefs[end - i] = R.random_element(*args, **kwds) - - # If we don't want zero (not has_zero), but coefs is zero (not - # nonzero), then reject - if degree_lb == -1 and not nonzero: - continue + # Now we pick the remaining coefficients. + for i in range(degree[1] - degree[0] + 1, degree[1] + 1): + coefs[end - i] = R.random_element(*args, **kwds) - return self(coefs) + return self(coefs) def _monics_degree(self, of_degree): """ @@ -2471,8 +2464,8 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r # P += (F[i] * prod) # return P - # using Neville's method for recursively generating the - # Lagrange interpolation polynomial +# using Neville's method for recursively generating the +# Lagrange interpolation polynomial elif algorithm == "neville": if previous_row is None: previous_row = [] From 1b09de02ba1aa25703f1e7e10a74236566467127 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Fri, 9 Feb 2024 16:51:33 +0000 Subject: [PATCH 12/20] fix input docs format --- src/sage/rings/polynomial/polynomial_ring.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index a56689ae0b2..b5044d6fd0d 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1366,13 +1366,13 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): INPUT: - - ``degree`` - (default: ``(-1, 2)``) integer for fixing the degree or + - ``degree`` -- (default: ``(-1, 2)``) integer for fixing the degree or a tuple of minimum and maximum degrees - - ``monic`` - boolean (optional); indicate whether the sampled + - ``monic`` -- boolean (optional); indicate whether the sampled polynomial should be monic - - ``*args, **kwds`` - additional keyword parameters passed on to the + - ``*args, **kwds`` -- additional keyword parameters passed on to the ``random_element`` method for the base ring EXAMPLES:: @@ -1638,11 +1638,11 @@ def polynomials( self, of_degree=None, max_degree=None ): INPUT: Pass exactly one of: - - ``max_degree`` - an int; the iterator will generate + - ``max_degree`` -- an int; the iterator will generate all polynomials which have degree less than or equal to ``max_degree`` - - ``of_degree`` - an int; the iterator will generate + - ``of_degree`` -- an int; the iterator will generate all polynomials which have degree ``of_degree`` OUTPUT: an iterator @@ -1704,11 +1704,11 @@ def monics( self, of_degree=None, max_degree=None ): INPUT: Pass exactly one of: - - ``max_degree`` - an int; the iterator will generate + - ``max_degree`` -- an int; the iterator will generate all monic polynomials which have degree less than or equal to ``max_degree`` - - ``of_degree`` - an int; the iterator will generate + - ``of_degree`` -- an int; the iterator will generate all monic polynomials which have degree ``of_degree`` @@ -1785,7 +1785,7 @@ def quotient_by_principal_ideal(self, f, names=None, **kwds): INPUT: - - ``f`` - either a polynomial in ``self``, or a principal + - ``f`` -- either a polynomial in ``self``, or a principal ideal of ``self``. - further named arguments that are passed to the quotient constructor. From 4e1378fd049fc1bbe480709e09ffe426a2a00214 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Fri, 9 Feb 2024 16:59:23 +0000 Subject: [PATCH 13/20] I don't know what the code is trying to do here --- src/sage/rings/tests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/tests.py b/src/sage/rings/tests.py index 3eed7e1aa31..289c002d543 100644 --- a/src/sage/rings/tests.py +++ b/src/sage/rings/tests.py @@ -474,9 +474,9 @@ def test_karatsuba_multiplication(base_ring, maxdeg1, maxdeg2, R = PolynomialRing(base_ring, 'x') if verbose: print("test_karatsuba_multiplication: ring={}, threshold={}".format(R, threshold)) - for i in range(numtests): - f = R.random_element(randint(0, maxdeg1), *base_ring_random_elt_args) - g = R.random_element(randint(0, maxdeg2), *base_ring_random_elt_args) + for _ in range(numtests): + f = R.random_element(randint(0, maxdeg1), False, *base_ring_random_elt_args) + g = R.random_element(randint(0, maxdeg2), False, *base_ring_random_elt_args) if verbose: print(" ({})*({})".format(f, g)) if ref_mul(f, g) - f._mul_karatsuba(g, threshold) != 0: From 97ad0a5e9e44922bd46d49d999b03ffa82228138 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Fri, 9 Feb 2024 17:05:11 +0000 Subject: [PATCH 14/20] fix remaining doctests --- src/sage/crypto/lattice.py | 24 ++++++++++++------------ src/sage/crypto/lwe.py | 4 ++-- src/sage/misc/randstate.pyx | 28 ++++++++++++++-------------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index ce6c63f66f3..513730ff89f 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -112,10 +112,10 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] [ 0 0 0 11 0 0 0 0] - [-2 -3 -3 4 1 0 0 0] - [ 4 -2 -3 -3 0 1 0 0] - [-3 4 -2 -3 0 0 1 0] - [-3 -3 4 -2 0 0 0 1] + [-3 -3 -2 4 1 0 0 0] + [ 4 -3 -3 -2 0 1 0 0] + [-2 4 -3 -3 0 0 1 0] + [-3 -2 4 -3 0 0 0 1] Ideal bases also work with polynomials:: @@ -125,10 +125,10 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] [ 0 0 0 11 0 0 0 0] - [ 1 4 -3 3 1 0 0 0] - [ 3 1 4 -3 0 1 0 0] - [-3 3 1 4 0 0 1 0] - [ 4 -3 3 1 0 0 0 1] + [-3 4 1 4 1 0 0 0] + [ 4 -3 4 1 0 1 0 0] + [ 1 4 -3 4 0 0 1 0] + [ 4 1 4 -3 0 0 0 1] Cyclotomic bases with n=2^k are SWIFFT bases:: @@ -137,10 +137,10 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] [ 0 0 0 11 0 0 0 0] - [-2 -3 -3 4 1 0 0 0] - [-4 -2 -3 -3 0 1 0 0] - [ 3 -4 -2 -3 0 0 1 0] - [ 3 3 -4 -2 0 0 0 1] + [-3 -3 -2 4 1 0 0 0] + [-4 -3 -3 -2 0 1 0 0] + [ 2 -4 -3 -3 0 0 1 0] + [ 3 2 -4 -3 0 0 0 1] Dual modular bases are related to Regev's famous public-key encryption [Reg2005]_:: diff --git a/src/sage/crypto/lwe.py b/src/sage/crypto/lwe.py index 25bb2a3fb47..40281916b19 100644 --- a/src/sage/crypto/lwe.py +++ b/src/sage/crypto/lwe.py @@ -670,7 +670,7 @@ def __init__(self, ringlwe): sage: lwe = RingLWEConverter(RingLWE(16, 257, D, secret_dist='uniform')) sage: set_random_seed(1337) sage: lwe() - ((32, 216, 3, 125, 58, 197, 171, 43), ...) + ((171, 197, 58, 125, 3, 216, 32, 130), ...) """ self.ringlwe = ringlwe self._i = 0 @@ -686,7 +686,7 @@ def __call__(self): sage: lwe = RingLWEConverter(RingLWE(16, 257, D, secret_dist='uniform')) sage: set_random_seed(1337) sage: lwe() - ((32, 216, 3, 125, 58, 197, 171, 43), ...) + ((171, 197, 58, 125, 3, 216, 32, 130), ...) """ R_q = self.ringlwe.R_q diff --git a/src/sage/misc/randstate.pyx b/src/sage/misc/randstate.pyx index 5c883c928b4..a4b23fb97b2 100644 --- a/src/sage/misc/randstate.pyx +++ b/src/sage/misc/randstate.pyx @@ -56,22 +56,22 @@ results of these random number generators reproducible. :: sage: set_random_seed(0) sage: print(rtest()) - (303, -0.266166246380421, 1/6, (1,2), [ 0, 1, 1, 0, 0 ], 265625921, 79302, 0.2450652680687958) + (303, -0.266166246380421, 1/2*x^2 - 1/95*x - 1/2, (1,3), [ 1, 0, 0, 1, 1 ], 265625921, 5842, 0.9661911734708414) sage: set_random_seed(1) sage: print(rtest()) - (978, 0.0557699430711638, -1/8*x^2 - 1/2*x + 1/2, (1,2,3), [ 1, 0, 0, 0, 1 ], 807447831, 23865, 0.6170498912488264) + (978, 0.0557699430711638, -3*x^2 - 1/12, (1,2), [ 0, 0, 1, 1, 0 ], 807447831, 29982, 0.8335077654199736) sage: set_random_seed(2) sage: print(rtest()) - (207, -0.0141049486533456, 0, (1,3)(4,5), [ 1, 0, 1, 1, 1 ], 1642898426, 16190, 0.9343331114872127) + (207, -0.0141049486533456, 4*x^2 + 1/2, (1,2)(4,5), [ 1, 0, 0, 1, 1 ], 1642898426, 41662, 0.19982565117278328) sage: set_random_seed(0) sage: print(rtest()) - (303, -0.266166246380421, 1/6, (1,2), [ 0, 1, 1, 0, 0 ], 265625921, 79302, 0.2450652680687958) + (303, -0.266166246380421, 1/2*x^2 - 1/95*x - 1/2, (1,3), [ 1, 0, 0, 1, 1 ], 265625921, 5842, 0.9661911734708414) sage: set_random_seed(1) sage: print(rtest()) - (978, 0.0557699430711638, -1/8*x^2 - 1/2*x + 1/2, (1,2,3), [ 1, 0, 0, 0, 1 ], 807447831, 23865, 0.6170498912488264) + (978, 0.0557699430711638, -3*x^2 - 1/12, (1,2), [ 0, 0, 1, 1, 0 ], 807447831, 29982, 0.8335077654199736) sage: set_random_seed(2) sage: print(rtest()) - (207, -0.0141049486533456, 0, (1,3)(4,5), [ 1, 0, 1, 1, 1 ], 1642898426, 16190, 0.9343331114872127) + (207, -0.0141049486533456, 4*x^2 + 1/2, (1,2)(4,5), [ 1, 0, 0, 1, 1 ], 1642898426, 41662, 0.19982565117278328) Once we've set the random number seed, we can check what seed was used. (This is not the current random number state; it does not change when @@ -81,7 +81,7 @@ random numbers are generated.) :: sage: initial_seed() 12345 sage: print(rtest()) - (720, -0.612180244315804, 0, (1,3), [ 1, 0, 1, 1, 0 ], 1911581957, 65175, 0.8043027951758298) + (720, -0.612180244315804, x^2 - x, (1,2,3), [ 1, 0, 0, 0, 1 ], 1911581957, 27093, 0.9205331599518184) sage: initial_seed() 12345 @@ -216,9 +216,9 @@ that you get without intervening ``with seed``. :: sage: set_random_seed(0) sage: r1 = rtest(); print(r1) - (303, -0.266166246380421, 1/6, (1,2), [ 0, 1, 1, 0, 0 ], 265625921, 79302, 0.2450652680687958) + (303, -0.266166246380421, 1/2*x^2 - 1/95*x - 1/2, (1,3), [ 1, 0, 0, 1, 1 ], 265625921, 5842, 0.9661911734708414) sage: r2 = rtest(); print(r2) - (443, 0.185001351421963, -2, (1,3), [ 0, 0, 1, 1, 0 ], 53231108, 8171, 0.28363811590618193) + (105, 0.642309615982449, -x^2 - x - 6, (1,3)(4,5), [ 1, 0, 0, 0, 1 ], 53231108, 77132, 0.001767155077382232) We get slightly different results with an intervening ``with seed``. :: @@ -226,9 +226,9 @@ We get slightly different results with an intervening ``with seed``. :: sage: r1 == rtest() True sage: with seed(1): rtest() - (978, 0.0557699430711638, -1/8*x^2 - 1/2*x + 1/2, (1,2,3), [ 1, 0, 0, 0, 1 ], 807447831, 23865, 0.6170498912488264) + (978, 0.0557699430711638, -3*x^2 - 1/12, (1,2), [ 0, 0, 1, 1, 0 ], 807447831, 29982, 0.8335077654199736) sage: r2m = rtest(); r2m - (443, 0.185001351421963, -2, (1,3), [ 0, 0, 1, 1, 0 ], 53231108, 51295, 0.28363811590618193) + (105, 0.642309615982449, -x^2 - x - 6, (1,3)(4,5), [ 1, 0, 0, 0, 1 ], 53231108, 40267, 0.001767155077382232) sage: r2m == r2 False @@ -245,8 +245,8 @@ case, as we see in this example:: sage: with seed(1): ....: print(rtest()) ....: print(rtest()) - (978, 0.0557699430711638, -1/8*x^2 - 1/2*x + 1/2, (1,2,3), [ 1, 0, 0, 0, 1 ], 807447831, 23865, 0.6170498912488264) - (181, 0.607995392046754, -x + 1/2, (2,3)(4,5), [ 1, 0, 0, 1, 1 ], 1010791326, 9693, 0.5691716786307407) + (978, 0.0557699430711638, -3*x^2 - 1/12, (1,2), [ 0, 0, 1, 1, 0 ], 807447831, 29982, 0.8335077654199736) + (138, -0.0404945051288503, 2*x - 24, (1,2,3), [ 1, 1, 0, 1, 1 ], 1010791326, 91360, 0.0033332230808060803) sage: r2m == rtest() True @@ -258,7 +258,7 @@ NTL random numbers were generated inside the ``with seed``. True sage: with seed(1): ....: rtest() - (978, 0.0557699430711638, -1/8*x^2 - 1/2*x + 1/2, (1,2,3), [ 1, 0, 0, 0, 1 ], 807447831, 23865, 0.6170498912488264) + (978, 0.0557699430711638, -3*x^2 - 1/12, (1,2), [ 0, 0, 1, 1, 0 ], 807447831, 29982, 0.8335077654199736) sage: r2m == rtest() True From d5215d4985fe6b23099511ff52d5b85ebe893726 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sat, 10 Feb 2024 17:28:48 +0000 Subject: [PATCH 15/20] =?UTF-8?q?fix=20docs=20wording=20+=20uniformity=20t?= =?UTF-8?q?est=20=F0=9F=93=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/rings/polynomial/polynomial_ring.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index b5044d6fd0d..7d9c456b1c2 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1389,8 +1389,8 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): 6 If a tuple of two integers is given for the ``degree`` argument, a polynomial is chosen - among all polynomials with degree between them. If the base ring is uniform, so is this - method:: + among all polynomials with degree between them. If the base ring is uniform, then this is + also sampled uniformly:: sage: R.random_element(degree=(0, 4)).degree() in range(0, 5) True @@ -1454,6 +1454,16 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): Traceback (most recent call last): ... ValueError: maximum degree (=-2) must be at least -1 + + Testing uniformity:: + + sage: from collections import Counter + sage: R = GF(3)["x"] + sage: samples = [R.random_element(degree=(-1, 2)) for _ in range(27 * 1000)] # long time + sage: assert all(750 <= f <= 1250 for f in Counter(samples).values()) + + sage: samples = [R.random_element(degree=(-1, 2), monic=True) for _ in range(13 * 1000)] # long time + sage: assert all(750 <= f <= 1250 for f in Counter(samples).values()) """ R = self.base_ring() From 786d7f0065bf507dc22cd21c740737e4bd513bc9 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sat, 10 Feb 2024 17:33:02 +0000 Subject: [PATCH 16/20] Fix doctests As I noted in the discussion under :issue:`37118`, it seems that the output of `sage -t` and the REPL differ, so I am not sure if this commit is correct. --- src/sage/rings/tests.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/tests.py b/src/sage/rings/tests.py index 289c002d543..95896889970 100644 --- a/src/sage/rings/tests.py +++ b/src/sage/rings/tests.py @@ -428,16 +428,16 @@ def test_karatsuba_multiplication(base_ring, maxdeg1, maxdeg2, sage: from sage.rings.tests import test_karatsuba_multiplication sage: test_karatsuba_multiplication(ZZ, 6, 5, verbose=True, seed=42) test_karatsuba_multiplication: ring=Univariate Polynomial Ring in x over Integer Ring, threshold=2 - (2*x^6 - x^5 - x^4 - 3*x^3 + 4*x^2 + 4*x + 1)*(4*x^4 + x^3 - 2*x^2 - 20*x + 3) - (16*x^2)*(-41*x + 1) - (x^6 + 2*x^5 + 8*x^4 - x^3 + x^2 + x)*(-x^2 - 4*x + 3) - (-x^3 - x - 8)*(-1) - (x - 1)*(-x^5 + 3*x^4 - x^3 + 2*x + 1) - (x^3 + x^2 + x + 1)*(4*x^3 + 76*x^2 - x - 1) - (x^6 - 5*x^4 - x^3 + 6*x^2 + 1)*(5*x^2 - x + 4) - (3*x - 2)*(x - 1) - (21)*(14*x^5 - x^2 + 4*x + 1) - (12*x^5 - 12*x^2 + 2*x + 1)*(26*x^4 + x^3 + 1) + (x^6 + 4*x^5 + 4*x^4 - 3*x^3 - x^2 - x)*(2*x^4 + 3*x^3 - 20*x^2 - 2*x + 1) + (4*x^5 + 16*x^2 + x - 41)*(x^2 + x - 1) + (8*x^2 + 2*x + 1)*(3) + (-4*x - 1)*(-8*x^2 - x) + (-x^6 - x^3 - x^2 + x + 1)*(2*x^3 - x + 3) + (-x^2 + x + 1)*(x^4 + x^3 - x^2 - x + 76) + (4*x^3 + x^2 + 6)*(-x^2 - 5*x) + (x + 4)*(-x + 5) + (-2*x)*(3*x^2 - x) + (x^6 + 21*x^5 + x^4 + 4*x^3 - x^2)*(14*x^4 + x^3 + 2*x^2 - 12*x) Test Karatsuba multiplication of polynomials of small degree over some common rings:: From 6beda49e4e289ba65ebff0394b87385a800b44cb Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Tue, 13 Feb 2024 10:18:24 +0000 Subject: [PATCH 17/20] long time doctests --- src/sage/rings/polynomial/polynomial_ring.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 7d9c456b1c2..7e7f6c98c9e 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1459,11 +1459,11 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): sage: from collections import Counter sage: R = GF(3)["x"] - sage: samples = [R.random_element(degree=(-1, 2)) for _ in range(27 * 1000)] # long time - sage: assert all(750 <= f <= 1250 for f in Counter(samples).values()) + sage: samples = [R.random_element(degree=(-1, 2)) for _ in range(27000)] # long time + sage: assert all(750 <= f <= 1250 for f in Counter(samples).values()) # long time - sage: samples = [R.random_element(degree=(-1, 2), monic=True) for _ in range(13 * 1000)] # long time - sage: assert all(750 <= f <= 1250 for f in Counter(samples).values()) + sage: samples = [R.random_element(degree=(-1, 2), monic=True) for _ in range(13000)] # long time + sage: assert all(750 <= f <= 1250 for f in Counter(samples).values()) # long time """ R = self.base_ring() From 0ea04b1c8af93190529e6707fd80bc9b452baaf3 Mon Sep 17 00:00:00 2001 From: grhkm21 <83517584+grhkm21@users.noreply.github.com> Date: Thu, 22 Feb 2024 21:20:29 +0000 Subject: [PATCH 18/20] Small wording change --- src/sage/rings/polynomial/polynomial_ring.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 4c30b6b283f..08045542168 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1391,8 +1391,8 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): 6 If a tuple of two integers is given for the ``degree`` argument, a polynomial is chosen - among all polynomials with degree between them. If the base ring is uniform, then this is - also sampled uniformly:: + among all polynomials with degree between them. If the base ring can be sampled uniformly, + then this method also samples uniformly:: sage: R.random_element(degree=(0, 4)).degree() in range(0, 5) True From a0d5d4ab4cc66b92a3c4ed2a3ff6e5ea3ee0402d Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Fri, 23 Feb 2024 05:33:57 +0000 Subject: [PATCH 19/20] wrap some lines fix some indentation --- src/sage/rings/polynomial/polynomial_ring.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 08045542168..890b47c6be4 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -1390,9 +1390,10 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): sage: R.random_element(6).degree() 6 - If a tuple of two integers is given for the ``degree`` argument, a polynomial is chosen - among all polynomials with degree between them. If the base ring can be sampled uniformly, - then this method also samples uniformly:: + If a tuple of two integers is given for the ``degree`` argument, a + polynomial is chosen among all polynomials with degree between them. If + the base ring can be sampled uniformly, then this method also samples + uniformly:: sage: R.random_element(degree=(0, 4)).degree() in range(0, 5) True @@ -1406,8 +1407,8 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): sage: while R.random_element(degree=(-1,2), x=-1, y=1) != R.zero(): ....: pass - Monic polynomials are chosen among all monic polynomials with degree between the given - ``degree`` argument:: + Monic polynomials are chosen among all monic polynomials with degree + between the given ``degree`` argument:: sage: all(R.random_element(degree=(-1, 1), monic=True).is_monic() for _ in range(10^3)) True @@ -2477,8 +2478,8 @@ def lagrange_polynomial(self, points, algorithm="divided_difference", previous_r # P += (F[i] * prod) # return P -# using Neville's method for recursively generating the -# Lagrange interpolation polynomial + # using Neville's method for recursively generating the + # Lagrange interpolation polynomial elif algorithm == "neville": if previous_row is None: previous_row = [] From 9d1d0a1272570ba09244e61c520c24bc83130f7c Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Fri, 23 Feb 2024 14:52:32 +0000 Subject: [PATCH 20/20] wrap at 80 --- src/sage/rings/polynomial/polynomial_ring.py | 49 ++++++++++++-------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 890b47c6be4..9b2985d85af 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -281,7 +281,6 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, sage: GF(7)['x']['y'].is_finite() False - """ # We trust that, if category is given, it is useful and does not need to be joined # with the default category @@ -1626,8 +1625,8 @@ def karatsuba_threshold(self): def set_karatsuba_threshold(self, Karatsuba_threshold): """ - Changes the default threshold for this ring in the method :meth:`_mul_karatsuba` - to fall back to the schoolbook algorithm. + Changes the default threshold for this ring in the method + :meth:`_mul_karatsuba` to fall back to the schoolbook algorithm. .. warning:: @@ -1948,7 +1947,8 @@ def __init__(self, base_ring, name="x", sparse=False, implementation=None, @cached_method(key=lambda self, d, q, sign, lead: (d, q, sign, tuple([x if isinstance(x, (tuple, list)) else (x, 0) for x in lead]) if isinstance(lead, (tuple, list)) else ((lead, 0)))) def weil_polynomials(self, d, q, sign=1, lead=1): r""" - Return all integer polynomials whose complex roots all have a specified absolute value. + Return all integer polynomials whose complex roots all have a specified + absolute value. Such polynomials `f` satisfy a functional equation @@ -1956,29 +1956,34 @@ def weil_polynomials(self, d, q, sign=1, lead=1): T^d f(q/T) = s q^{d/2} f(T) - where `d` is the degree of `f`, `s` is a sign and `q^{1/2}` is the absolute value - of the roots of `f`. + where `d` is the degree of `f`, `s` is a sign and `q^{1/2}` is the + absolute value of the roots of `f`. INPUT: - ``d`` -- integer, the degree of the polynomials - - ``q`` -- integer, the square of the complex absolute value of the roots + - ``q`` -- integer, the square of the complex absolute value of the + roots - - ``sign`` -- integer (default `1`), the sign `s` of the functional equation + - ``sign`` -- integer (default `1`), the sign `s` of the functional + equation - - ``lead`` -- integer, list of integers or list of pairs of integers (default `1`), - constraints on the leading few coefficients of the generated polynomials. - If pairs `(a, b)` of integers are given, they are treated as a constraint - of the form `\equiv a \pmod{b}`; the moduli must be in decreasing order by - divisibility, and the modulus of the leading coefficient must be 0. + - ``lead`` -- integer, list of integers or list of pairs of integers + (default `1`), constraints on the leading few coefficients of the + generated polynomials. If pairs `(a, b)` of integers are given, they + are treated as a constraint of the form `\equiv a \pmod{b}`; the + moduli must be in decreasing order by divisibility, and the modulus + of the leading coefficient must be 0. .. SEEALSO:: - More documentation and additional options are available using the iterator + More documentation and additional options are available using the + iterator :class:`sage.rings.polynomial.weil.weil_polynomials.WeilPolynomials` - directly. In addition, polynomials have a method :meth:`is_weil_polynomial` to - test whether or not the given polynomial is a Weil polynomial. + directly. In addition, polynomials have a method + :meth:`is_weil_polynomial` to test whether or not the given + polynomial is a Weil polynomial. EXAMPLES:: @@ -2013,7 +2018,8 @@ def weil_polynomials(self, d, q, sign=1, lead=1): TESTS: - We check that products of Weil polynomials are also listed as Weil polynomials:: + We check that products of Weil polynomials are also listed as Weil + polynomials:: sage: all((f * g) in R.weil_polynomials(6, q) for q in [3, 4] # needs sage.libs.flint ....: for f in R.weil_polynomials(2, q) for g in R.weil_polynomials(4, q)) @@ -2028,13 +2034,15 @@ def weil_polynomials(self, d, q, sign=1, lead=1): ....: for j in range(1, (3+i)//2 + 1)) ....: for i in range(4)]) for f in simples] - Check that every polynomial in this list has 3 real roots between `-2 \sqrt{3}` and `2 \sqrt{3}`:: + Check that every polynomial in this list has 3 real roots between `-2 + \sqrt{3}` and `2 \sqrt{3}`:: sage: roots = [f.roots(RR, multiplicities=False) for f in reals] # needs sage.libs.flint sage: all(len(L) == 3 and all(x^2 <= 12 for x in L) for L in roots) # needs sage.libs.flint True - Finally, check that the original polynomials are reconstructed as CM polynomials:: + Finally, check that the original polynomials are reconstructed as CM + polynomials:: sage: all(f == T^3*r(T + 3/T) for (f, r) in zip(simples, reals)) # needs sage.libs.flint True @@ -2190,7 +2198,8 @@ def _element_class(): def _ideal_class_(self, n=0): """ - Returns the class representing ideals in univariate polynomial rings over fields. + Returns the class representing ideals in univariate polynomial rings + over fields. EXAMPLES::