FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Expose content and zpoly of fmpq_mpoly · Issue #419 · flintlib/python-flint · GitHub

Repository navigation

Expose content and zpoly of fmpq_mpoly #419

Description

Hi, all. First of all, thanks a lot for python bindings, these are very useful. So, FLINT stores fmpq_mpoly as an fmpz_mpoly and an fmpq content; these are accessible via fmpq_mpoly_content_ref and fmpq_mpoly_zpoly_ref. Would it be possible to expose these values in python-flint?

Of course, exposing mutable references would be all sorts of complicated, but just adding content() and zpoly() methods that return copies would already be great. Currently (as of version 0.9) it seems like I can only do this conversion via to_dict/from_dict, which is infinitely slow compared to the proper solution.

Something like this maybe?

diff --git a/src/flint/types/fmpq_mpoly.pyx b/src/flint/types/fmpq_mpoly.pyx
--- 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 (
@@ -785,6 +785,16 @@ cdef class fmpq_mpoly(flint_mpoly):
         fmpq_mpoly_term_content(res.val, self.val, self.ctx.val)
         return res

+    def content(self):
+        cdef fmpq res = fmpq.__new__(fmpq)
+        fmpq_set(res.val, self.val.content)
+        return res
+
+    def zpoly(self):
+        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 resultant(self, other, var):
         """
         Return the resultant of ``self`` and ``other`` with respect to variable ``var``.

diff --git a/src/flint/types/fmpq_mpoly.pyi b/src/flint/types/fmpq_mpoly.pyi
index 6dec649..e8b3b9c 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 content(self) -> fmpq: ...
+    def zpoly(self) -> fmpz_mpoly: ...
+
     def factor(self) -> tuple[fmpq, list[tuple[fmpq_mpoly, int]]]: ...
     def factor_squarefree(self) -> tuple[fmpq, list[tuple[fmpq_mpoly, int]]]: ...

Activity

  1. oscarbenjamin commented on Aug 26, 2026

    Collaborator

    Yes, that seems reasonable. Do you want to open a PR?

  2. oscarbenjamin commented on Aug 26, 2026

    Collaborator

    If the zpoly method needs to create a context maybe it would make more sense for the fmpq_mpoly_ctx to store a reference to an associated fmpz_mpoly_ctx. The user would need to have some way of getting the context.

  3. magv commented on Aug 26, 2026

    ContributorAuthor

    Yes, ideally there should be a shortcut to get fmpz_mpoly_ctx directly from fmpq_mpoly_ctx. Maybe not the 1st priority, but still. I'll open a PR.

  4. oscarbenjamin commented on Aug 26, 2026

    Collaborator

    I'm not sure about the method names. Other poly/mpoly types have methods called content and if types have the same method name then it should have a consistent meaning.

    Another possibility is numer and denom e.g.:

    In [1]: from flint import fmpq_poly
    
    In [2]: p = fmpq_poly([2, 4]) / 7
    
    In [3]: p
    Out[3]: 4/7*x + 2/7
    
    In [4]: p.numer()
    Out[4]: 4*x + 2
    
    In [5]: type(_)
    Out[5]: flint.types.fmpz_poly.fmpz_poly
    
    In [6]: p.denom()
    Out[6]: 7
    
    In [7]: type(_)
    Out[7]: flint.types.fmpz.fmpz

    For other types content means the nonnegative gcd:

    In [11]: from flint import fmpz_poly
    
    In [12]: p = fmpz_poly([-2, -6])
    
    In [13]: p.content()
    Out[13]: 2

    The fmpz_mpoly type has content and primitive methods

    In [15]: from flint import fmpz_mpoly_ctx
    
    In [16]: R = fmpz_mpoly_ctx.get(['x', 'y'])
    
    In [17]: x, y = R.gens()
    
    In [18]: p = -2*x - 4*y
    
    In [19]: p.content()
    Out[19]: 2
    
    In [20]: p.primitive()
    Out[20]: (2, -x - 2*y)

    Again content here is nonnegative.

    Perhaps calling the methods zpoly and zcontent to keep them distinct from other methods like numer, denom, content and primitive would be better.

  5. magv commented on Aug 26, 2026

    ContributorAuthor

    I have no preference on these names, I was just going by what the C api calls them. zpoly and zcontent are fine too. Note that zcontent is still fmpq, not fmpz, as the "z" letter might imply.

    About fmpz_mpoly_ctx from fmpq_mpoly_ctx: although the C-level fmpz_mpoly_ctx is trivially accessible from fmpq_mpoly_ctx, the Python-level fmpz_mpoly_ctx still should go through the caching system. I think I won't change this part. fmpq_mpoly_ctx.__init__ also uses the same pattern when an fmpz_mpoly is passed: fmpz_mpoly_ctx.from_context(poly.ctx).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL