diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index e60fc9dd..7c07eb8a 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -363,7 +363,6 @@ jobs: # Supported Flint versions: flint-tag: [ 'v3.0.1', - 'v3.1.3-p1', 'v3.2.2', 'v3.3.1', 'v3.4.0', diff --git a/README.md b/README.md index 45ef3a39..8cbb492e 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,7 @@ Compatible versions: | python-flint | Release date | CPython | FLINT | Cython | |--------------|---------------|-------------|------------|------------------| +| `0.10.0` | Not released | `3.10-3.15` | `3.0-3.6` | `3.1-3.3` | | `0.9.0` | 3rd Jul 2026 | `3.10-3.14` | `3.0-3.6` | `3.1-3.2` | | `0.8.0` | 29th Aug 2025 | `3.11-3.14` | `3.0-3.3` | `3.1` only | | `0.7.0` | 16th Mar 2025 | `3.11-3.13` | `3.0-3.2` | `3.0.11-3.1.0a1` | @@ -163,6 +164,22 @@ experimental. CHANGELOG ========= +0.10.0 (Not yet released) +------------------------- + +Contributors (0.10.0): + +- Vitaly Magerya (VM) +- Oscar Benjamin (OB) + +Changes (0.10.0): + +- [gh-421](https://github.com/flintlib/python-flint/pull/421), + Add `zpoly` and `zcontent` methods to `fmpq_mpoly`, to get + the primitive integer polynomial and the `fmpq` content, which + form the internal representation of the `fmpq_mpoly`. Also add + support for building with Cython 3.3. (VM, OB) + 0.9.0 ----- diff --git a/doc/source/build.rst b/doc/source/build.rst index 4fb9e3c9..11556216 100644 --- a/doc/source/build.rst +++ b/doc/source/build.rst @@ -84,6 +84,11 @@ Compatible versions: - CPython - FLINT - Cython + * - 0.10.0 + - Not released + - 3.10-3.15 + - 3.0-3.6 + - 3.1-3.3 * - 0.9.0 - 3rd Jul 2026 - 3.10-3.14 diff --git a/meson.build b/meson.build index 3392cdf7..ab150a67 100644 --- a/meson.build +++ b/meson.build @@ -18,7 +18,7 @@ project( flint_lower = '>=3.0' flint_upper = '<3.7' cython_lower = '>=3.0.11' -cython_upper = '<3.3' +cython_upper = '<3.4' py = import('python').find_installation(pure: false) diff --git a/pyproject.toml b/pyproject.toml index b940562c..44220d1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ content-type = "text/markdown" # fine. It is not possible to have a separate version constraint here for the # freethreading build only though. # -requires = ["meson-python >= 0.18", "cython >=3.1,<3.3"] +requires = ["meson-python >= 0.18", "cython >=3.1,<3.4"] build-backend = "mesonpy" [tool.meson-python] diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index 2b10111e..d7216a2f 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -3934,6 +3934,27 @@ def quick_poly(): assert False # New _mpoly types? +def test_fmpq_mpoly_zcontent_zpoly(): + ctx = flint.fmpq_mpoly_ctx.get(("x", "y")) + x, y = ctx.gens() + zctx = flint.fmpz_mpoly_ctx.from_context(ctx) + zx, zy = zctx.gens() + + f = -2*x/3 - 2*y/5 + assert f.zcontent() == flint.fmpq(-2, 15) + assert f.zpoly() == 5*zx + 3*zy + assert isinstance(f.zcontent(), flint.fmpq) + assert isinstance(f.zpoly(), flint.fmpz_mpoly) + # Can't mix fmpq_mpoly with fmpz_mpoly... + p = flint.fmpq_mpoly(f.zpoly(), ctx=ctx) + c = f.zcontent() + assert p * c == f + + f = 0*x + assert f.zcontent() == 0 + assert f.zpoly() == 0 + + def _all_mpoly_vecs(): return [(flint.fmpz_mpoly_ctx, flint.fmpz_mpoly_vec), (flint.fmpq_mpoly_ctx, flint.fmpq_mpoly_vec)] diff --git a/src/flint/types/fmpq_mpoly.pyi b/src/flint/types/fmpq_mpoly.pyi index 6dec549b..a8ed897e 100644 --- a/src/flint/types/fmpq_mpoly.pyi +++ b/src/flint/types/fmpq_mpoly.pyi @@ -102,6 +102,9 @@ class fmpq_mpoly(flint_mpoly[fmpq_mpoly_ctx, fmpq, ifmpq]): def xgcd(self, other: fmpq_mpoly, /) -> fmpq: ... def term_content(self) -> fmpq_mpoly: ... + def zpoly(self) -> fmpz_mpoly: ... + def zcontent(self) -> fmpq: ... + def factor(self) -> tuple[fmpq, list[tuple[fmpq_mpoly, int]]]: ... def factor_squarefree(self) -> tuple[fmpq, list[tuple[fmpq_mpoly, int]]]: ... diff --git a/src/flint/types/fmpq_mpoly.pyx b/src/flint/types/fmpq_mpoly.pyx index c00160b8..cbc0a9d7 100644 --- a/src/flint/types/fmpq_mpoly.pyx +++ b/src/flint/types/fmpq_mpoly.pyx @@ -17,7 +17,7 @@ from flint.types.fmpz_vec cimport fmpz_vec from flint.types.fmpq_vec cimport fmpq_vec from flint.types.fmpz cimport fmpz, any_as_fmpz -from flint.types.fmpz_mpoly cimport fmpz_mpoly +from flint.types.fmpz_mpoly cimport fmpz_mpoly, fmpz_mpoly_ctx, create_fmpz_mpoly from flint.flintlib.functions.fmpq cimport fmpq_set, fmpq_one from flint.flintlib.functions.fmpq_mpoly cimport ( @@ -215,6 +215,23 @@ cdef class fmpq_mpoly(flint_mpoly): """ The *fmpq_mpoly* type represents sparse multivariate polynomials over the rationals. + + Internally, an ``fmpq_mpoly`` is represented as the product of a signed + rational content and a primitive integer multivariate polynomial with + positive leading coefficient. The :meth:`zcontent` and :meth:`zpoly` + methods return copies of these two components, respectively. + + The original polynomial can be reconstructed from these components by + converting the integer polynomial back to an ``fmpq_mpoly`` in the + original context and multiplying by the content: + + >>> ctx = fmpq_mpoly_ctx.get(("x", "y")) + >>> x, y = ctx.gens() + >>> f = -2*x/3 - 2*y/5 + >>> zpoly = f.zpoly() + >>> content = f.zcontent() + >>> fmpq_mpoly(zpoly, ctx=f.context()) * content == f + True """ def __cinit__(self): @@ -785,6 +802,36 @@ cdef class fmpq_mpoly(flint_mpoly): fmpq_mpoly_term_content(res.val, self.val, self.ctx.val) return res + def zpoly(self): + """ + Return the integer polynomial of ``self``. The product + of this and ``self.zcontent()`` represents the whole + polynomial. + + >>> ctx = fmpq_mpoly_ctx.get(("x","y")) + >>> x, y = ctx.gens() + >>> (x*2/3 + y*2/5).zpoly() + 5*x + 3*y + """ + cdef fmpz_mpoly_ctx zctx = fmpz_mpoly_ctx.from_context(self.ctx) + cdef fmpz_mpoly res = create_fmpz_mpoly(zctx) + fmpz_mpoly_set(res.val, self.val.zpoly, zctx.val) + return res + + def zcontent(self): + """ + Return the content of ``self``. The product of this and + ``self.zpoly()`` represents the whole polynomial. + + >>> ctx = fmpq_mpoly_ctx.get(("x","y")) + >>> x, y = ctx.gens() + >>> (x*2/3 + y*2/5).zcontent() + 2/15 + """ + cdef fmpq res = fmpq.__new__(fmpq) + fmpq_set(res.val, self.val.content) + return res + def resultant(self, other, var): """ Return the resultant of ``self`` and ``other`` with respect to variable ``var``.