Skip to content

Commit 6708168

Browse files
Merge pull request #421 from magv/fmpq_mpoly_zpoly_ref
Add fmpq_mpoly.zpoly and fmpq_mpoly.zcontent (fixes #419)
2 parents 36c5f92 + 7edef2a commit 6708168

8 files changed

Lines changed: 96 additions & 4 deletions

File tree

.github/workflows/buildwheel.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,6 @@ jobs:
363363
# Supported Flint versions:
364364
flint-tag: [
365365
'v3.0.1',
366-
'v3.1.3-p1',
367366
'v3.2.2',
368367
'v3.3.1',
369368
'v3.4.0',

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ Compatible versions:
144144

145145
| python-flint | Release date | CPython | FLINT | Cython |
146146
|--------------|---------------|-------------|------------|------------------|
147+
| `0.10.0` | Not released | `3.10-3.15` | `3.0-3.6` | `3.1-3.3` |
147148
| `0.9.0` | 3rd Jul 2026 | `3.10-3.14` | `3.0-3.6` | `3.1-3.2` |
148149
| `0.8.0` | 29th Aug 2025 | `3.11-3.14` | `3.0-3.3` | `3.1` only |
149150
| `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.
163164
CHANGELOG
164165
=========
165166

167+
0.10.0 (Not yet released)
168+
-------------------------
169+
170+
Contributors (0.10.0):
171+
172+
- Vitaly Magerya (VM)
173+
- Oscar Benjamin (OB)
174+
175+
Changes (0.10.0):
176+
177+
- [gh-421](https://github.com/flintlib/python-flint/pull/421),
178+
Add `zpoly` and `zcontent` methods to `fmpq_mpoly`, to get
179+
the primitive integer polynomial and the `fmpq` content, which
180+
form the internal representation of the `fmpq_mpoly`. Also add
181+
support for building with Cython 3.3. (VM, OB)
182+
166183
0.9.0
167184
-----
168185

doc/source/build.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ Compatible versions:
8484
- CPython
8585
- FLINT
8686
- Cython
87+
* - 0.10.0
88+
- Not released
89+
- 3.10-3.15
90+
- 3.0-3.6
91+
- 3.1-3.3
8792
* - 0.9.0
8893
- 3rd Jul 2026
8994
- 3.10-3.14

meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ project(
1818
flint_lower = '>=3.0'
1919
flint_upper = '<3.7'
2020
cython_lower = '>=3.0.11'
21-
cython_upper = '<3.3'
21+
cython_upper = '<3.4'
2222

2323
py = import('python').find_installation(pure: false)
2424

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ content-type = "text/markdown"
4141
# fine. It is not possible to have a separate version constraint here for the
4242
# freethreading build only though.
4343
#
44-
requires = ["meson-python >= 0.18", "cython >=3.1,<3.3"]
44+
requires = ["meson-python >= 0.18", "cython >=3.1,<3.4"]
4545
build-backend = "mesonpy"
4646

4747
[tool.meson-python]

src/flint/test/test_all.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3934,6 +3934,27 @@ def quick_poly():
39343934
assert False # New _mpoly types?
39353935

39363936

3937+
def test_fmpq_mpoly_zcontent_zpoly():
3938+
ctx = flint.fmpq_mpoly_ctx.get(("x", "y"))
3939+
x, y = ctx.gens()
3940+
zctx = flint.fmpz_mpoly_ctx.from_context(ctx)
3941+
zx, zy = zctx.gens()
3942+
3943+
f = -2*x/3 - 2*y/5
3944+
assert f.zcontent() == flint.fmpq(-2, 15)
3945+
assert f.zpoly() == 5*zx + 3*zy
3946+
assert isinstance(f.zcontent(), flint.fmpq)
3947+
assert isinstance(f.zpoly(), flint.fmpz_mpoly)
3948+
# Can't mix fmpq_mpoly with fmpz_mpoly...
3949+
p = flint.fmpq_mpoly(f.zpoly(), ctx=ctx)
3950+
c = f.zcontent()
3951+
assert p * c == f
3952+
3953+
f = 0*x
3954+
assert f.zcontent() == 0
3955+
assert f.zpoly() == 0
3956+
3957+
39373958
def _all_mpoly_vecs():
39383959
return [(flint.fmpz_mpoly_ctx, flint.fmpz_mpoly_vec), (flint.fmpq_mpoly_ctx, flint.fmpq_mpoly_vec)]
39393960

src/flint/types/fmpq_mpoly.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ class fmpq_mpoly(flint_mpoly[fmpq_mpoly_ctx, fmpq, ifmpq]):
102102
def xgcd(self, other: fmpq_mpoly, /) -> fmpq: ...
103103
def term_content(self) -> fmpq_mpoly: ...
104104

105+
def zpoly(self) -> fmpz_mpoly: ...
106+
def zcontent(self) -> fmpq: ...
107+
105108
def factor(self) -> tuple[fmpq, list[tuple[fmpq_mpoly, int]]]: ...
106109
def factor_squarefree(self) -> tuple[fmpq, list[tuple[fmpq_mpoly, int]]]: ...
107110

src/flint/types/fmpq_mpoly.pyx

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ from flint.types.fmpz_vec cimport fmpz_vec
1717
from flint.types.fmpq_vec cimport fmpq_vec
1818

1919
from flint.types.fmpz cimport fmpz, any_as_fmpz
20-
from flint.types.fmpz_mpoly cimport fmpz_mpoly
20+
from flint.types.fmpz_mpoly cimport fmpz_mpoly, fmpz_mpoly_ctx, create_fmpz_mpoly
2121

2222
from flint.flintlib.functions.fmpq cimport fmpq_set, fmpq_one
2323
from flint.flintlib.functions.fmpq_mpoly cimport (
@@ -215,6 +215,23 @@ cdef class fmpq_mpoly(flint_mpoly):
215215
"""
216216
The *fmpq_mpoly* type represents sparse multivariate polynomials over
217217
the rationals.
218+
219+
Internally, an ``fmpq_mpoly`` is represented as the product of a signed
220+
rational content and a primitive integer multivariate polynomial with
221+
positive leading coefficient. The :meth:`zcontent` and :meth:`zpoly`
222+
methods return copies of these two components, respectively.
223+
224+
The original polynomial can be reconstructed from these components by
225+
converting the integer polynomial back to an ``fmpq_mpoly`` in the
226+
original context and multiplying by the content:
227+
228+
>>> ctx = fmpq_mpoly_ctx.get(("x", "y"))
229+
>>> x, y = ctx.gens()
230+
>>> f = -2*x/3 - 2*y/5
231+
>>> zpoly = f.zpoly()
232+
>>> content = f.zcontent()
233+
>>> fmpq_mpoly(zpoly, ctx=f.context()) * content == f
234+
True
218235
"""
219236

220237
def __cinit__(self):
@@ -785,6 +802,36 @@ cdef class fmpq_mpoly(flint_mpoly):
785802
fmpq_mpoly_term_content(res.val, self.val, self.ctx.val)
786803
return res
787804

805+
def zpoly(self):
806+
"""
807+
Return the integer polynomial of ``self``. The product
808+
of this and ``self.zcontent()`` represents the whole
809+
polynomial.
810+
811+
>>> ctx = fmpq_mpoly_ctx.get(("x","y"))
812+
>>> x, y = ctx.gens()
813+
>>> (x*2/3 + y*2/5).zpoly()
814+
5*x + 3*y
815+
"""
816+
cdef fmpz_mpoly_ctx zctx = fmpz_mpoly_ctx.from_context(self.ctx)
817+
cdef fmpz_mpoly res = create_fmpz_mpoly(zctx)
818+
fmpz_mpoly_set(res.val, self.val.zpoly, zctx.val)
819+
return res
820+
821+
def zcontent(self):
822+
"""
823+
Return the content of ``self``. The product of this and
824+
``self.zpoly()`` represents the whole polynomial.
825+
826+
>>> ctx = fmpq_mpoly_ctx.get(("x","y"))
827+
>>> x, y = ctx.gens()
828+
>>> (x*2/3 + y*2/5).zcontent()
829+
2/15
830+
"""
831+
cdef fmpq res = fmpq.__new__(fmpq)
832+
fmpq_set(res.val, self.val.content)
833+
return res
834+
788835
def resultant(self, other, var):
789836
"""
790837
Return the resultant of ``self`` and ``other`` with respect to variable ``var``.

0 commit comments

Comments
 (0)