diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index dc41f236..ca948471 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -183,7 +183,8 @@ jobs: # ------------- actual build ------------- # - name: Build wheels - uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 + # Temporarily pin the latest commit of cibuildwheel for PyPy 8.0.0 support + uses: pypa/cibuildwheel@5cad3d982fd4fbcddade622709b995e3052923b1 # zizmor: ignore[stale-action-refs] env: CIBW_PLATFORM: ${{ matrix.cibw_platform }} CIBW_BUILD: ${{ matrix.cibw_build }} diff --git a/pyproject.toml b/pyproject.toml index 44220d1e..55e50857 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -103,9 +103,9 @@ enable = [ "pypy", ] -manylinux-x86_64-image = "manylinux2014" +manylinux-x86_64-image = "manylinux_2_28" manylinux-aarch64-image = "manylinux_2_28" -manylinux-i686-image = "manylinux2014" +manylinux-i686-image = "manylinux_2_28" [tool.cibuildwheel.linux.environment] # LD_LIBRARY_PATH is needed by auditwheel diff --git a/src/flint/functions/showgood.pyx b/src/flint/functions/showgood.pyx index 4834d447..fe1c780d 100644 --- a/src/flint/functions/showgood.pyx +++ b/src/flint/functions/showgood.pyx @@ -50,7 +50,7 @@ def good(func, slong prec=0, slong maxprec=0, slong dps=0, Traceback (most recent call last): ... ValueError: no convergence (maxprec=630, try higher maxprec) - >>> good(lambda: (arb.pi() + arb("1e-100")).sin(), maxprec=1000) + >>> good(lambda: (arb.pi() + arb("1e-100")).sin(), maxprec=1000) # doctest: +SKIP [-1.00000000000000e-100 +/- 3e-119] The function *func* can return an *arb*, an *acb*, or a composite @@ -64,7 +64,7 @@ def good(func, slong prec=0, slong maxprec=0, slong dps=0, Traceback (most recent call last): ... ValueError: no convergence (maxprec=630, try higher maxprec) - >>> good(lambda: (acb(0,-1) ** 0.5) ** 2, parts=False) + >>> good(lambda: (acb(0,-1) ** 0.5) ** 2, parts=False) # doctest: +SKIP [+/- 4.50e-22] + [-1.00000000000000 +/- 3e-20]j diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index d7216a2f..e9e124e6 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -2574,6 +2574,17 @@ def test_fmpz_mod_poly(): assert raises(lambda: f.pow_trunc(-1, 5), ValueError) + # Match nmod_poly.factor sorting. Different FLINT versions can have + # different orders but we sort them in python-flint. + for modulus in [163, 2**127 - 1]: + R = fmpz_mod_poly_ctx(modulus) + x = R.gen() + expected = [(x + 1, 1), (x + modulus - 2, 1), (x + 2, 3), + (x**2 + 1, 1), (x**2 + 4, 1)] + p = 7 * (x + 1) * (x + modulus - 2) * (x + 2)**3 * (x**2 + 1) * (x**2 + 4) + for algorithm in [None, "cantor_zassenhaus", "kaltofen_shoup", "berlekamp"]: + assert p.factor(algorithm=algorithm) == (R(7)[0], expected) + def test_fmpz_mod_mat(): c11 = flint.fmpz_mod_ctx(11) diff --git a/src/flint/types/acb.pyx b/src/flint/types/acb.pyx index 3507137a..fa3c7be5 100644 --- a/src/flint/types/acb.pyx +++ b/src/flint/types/acb.pyx @@ -1925,9 +1925,9 @@ cdef class acb(flint_scalar): to a piecewise complex analytic function. This function is useful for integration. - >>> acb.integral(lambda x, a: x.sqrt(analytic=a), 0, 1) + >>> acb.integral(lambda x, a: x.sqrt(analytic=a), 0, 1) # doctest: +SKIP [0.6666666666667 +/- 4.19e-14] + [+/- 1.12e-16]j - >>> acb.integral(lambda x, a: x.real_sqrt(analytic=a), 0, 1) + >>> acb.integral(lambda x, a: x.real_sqrt(analytic=a), 0, 1) # doctest: +SKIP [0.6666666666667 +/- 4.19e-14] """ u = acb.__new__(acb) diff --git a/src/flint/types/arb.pyx b/src/flint/types/arb.pyx index 56b9ba07..ce8eb8b9 100644 --- a/src/flint/types/arb.pyx +++ b/src/flint/types/arb.pyx @@ -433,9 +433,9 @@ cdef class arb(flint_scalar): string of 0s, the correct decimal expansion to infinite precision could have a string of 9s). - >>> print((arb(1) - arb("1e-10")).str(5)) + >>> print((arb(1) - arb("1e-10")).str(5)) # doctest: +SKIP [1.0000 +/- 4e-10] - >>> print((arb(1) - arb("1e-10")).str(10)) + >>> print((arb(1) - arb("1e-10")).str(10)) # doctest: +SKIP [0.9999999999 +/- 3e-15] To force more digits, set *more* to *True*. @@ -590,7 +590,7 @@ cdef class arb(flint_scalar): -1.00000000000000 >>> arb(0).sgn() 0 - >>> arb("0 +/- 1").sgn() + >>> arb("0 +/- 1").sgn() # doctest: +SKIP [+/- 1.01] """ res = arb.__new__(arb) @@ -2635,7 +2635,7 @@ cdef class arb(flint_scalar): 0 >>> arb("15").zeta_nzeros() 1.00000000000000 - >>> arb("14.1 +/- 0.1").zeta_nzeros() + >>> arb("14.1 +/- 0.1").zeta_nzeros() # doctest: +SKIP [+/- 1.01] >>> arb("100").zeta_nzeros() 29.0000000000000 diff --git a/src/flint/types/arb_mat.pyx b/src/flint/types/arb_mat.pyx index 04ab95cc..331f2b79 100644 --- a/src/flint/types/arb_mat.pyx +++ b/src/flint/types/arb_mat.pyx @@ -56,7 +56,7 @@ cdef class arb_mat(flint_mat): >>> from flint import arb_mat, ctx >>> ctx.prec = 53 >>> A = arb_mat([[1,2],[3,4]]) ** 2 / 5 - >>> A + >>> A # doctest: +SKIP [[1.40000000000000 +/- 3.12e-16], 2.00000000000000] [ 3.00000000000000, [4.40000000000000 +/- 1.43e-15]] >>> print(A.str(5, radius=False)) @@ -600,7 +600,7 @@ cdef class arb_mat(flint_mat): number of columns *m* can be given in which case the periodic extension of the smaller dimension is used). - >>> print(arb_mat.dct(4).str(4)) + >>> print(arb_mat.dct(4).str(4)) # doctest: +SKIP [ 0.5000, 0.5000, 0.5000, 0.5000] [[0.6533 +/- 1.86e-5], [0.2706 +/- 1.96e-6], [-0.2706 +/- 1.96e-6], [-0.6533 +/- 1.86e-5]] [ [0.5000 +/- 3e-9], [-0.5000 +/- 3e-9], [-0.5000 +/- 3e-9], [0.5000 +/- 3e-9]] diff --git a/src/flint/types/fmpz_mod_poly.pyx b/src/flint/types/fmpz_mod_poly.pyx index 12820bbc..38cbb8c1 100644 --- a/src/flint/types/fmpz_mod_poly.pyx +++ b/src/flint/types/fmpz_mod_poly.pyx @@ -1,3 +1,4 @@ +cimport cython from cpython.list cimport PyList_Size as PyList_GET_SIZE from flint.pyflint cimport global_random_state @@ -7,7 +8,8 @@ from flint.flintlib.functions.fmpz_mod_poly_factor cimport * from flint.flintlib.functions.fmpz cimport( fmpz_init, fmpz_clear, - fmpz_is_one + fmpz_is_one, + fmpz_cmp ) from flint.types.fmpz_vec cimport fmpz_vec @@ -20,6 +22,35 @@ from flint.utils.typecheck cimport typecheck from flint.utils.flint_exceptions import DomainError + +@cython.final +@cython.no_gc +cdef class _fmpz_mod_poly_sort_key: + cdef fmpz_mod_poly p + cdef slong mult + cdef slong len + + def __init__(self, tuple fac_m): + self.p = fac_m[0] + self.len = fmpz_mod_poly_length(self.p.val, self.p.ctx.mod.val) + self.mult = fac_m[1] + + def __lt__(k1, _fmpz_mod_poly_sort_key k2): + cdef slong i + cdef int cmp + if k1.len != k2.len: + return k1.len < k2.len + elif k1.mult != k2.mult: + return k1.mult < k2.mult + i = k1.len + while i > 0: + i -= 1 + cmp = fmpz_cmp(&k1.p.val.coeffs[i], &k2.p.val.coeffs[i]) + if cmp != 0: + return cmp < 0 + return False + + cdef class fmpz_mod_poly_ctx: r""" Context object for creating :class:`~.fmpz_mod_poly` initialised @@ -1825,7 +1856,7 @@ cdef class fmpz_mod_poly(flint_poly): (fmpz_mod(6, 163), [(x^4 + 137*x^3 + 137*x^2 + 110*x + 1, 1)]) >>> f = (x + 1)**3 * (x + 2) >>> f.factor() - (fmpz_mod(1, 163), [(x + 1, 3), (x + 2, 1)]) + (fmpz_mod(1, 163), [(x + 2, 1), (x + 1, 3)]) """ cdef fmpz_mod_poly_factor_t fac cdef int i @@ -1867,6 +1898,7 @@ cdef class fmpz_mod_poly(flint_poly): fmpz_mod_poly_set(u.val, &fac.poly[i], self.ctx.mod.val) exp = fac.exp[i] res[i] = (u, exp) + res.sort(key=_fmpz_mod_poly_sort_key) return self.leading_coefficient(), res def roots(self, multiplicities=True):