From 357e4355e4a326ad57da9369337fb19c23997803 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Fri, 11 Aug 2023 12:46:21 -0400 Subject: [PATCH 01/21] Make it work with flint 3.0 Split nmod_poly_factor out from nmod_poly Remove arb from setup.py --- setup.py | 6 +++--- src/flint/_flint.pxd | 16 +++++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/setup.py b/setup.py index 5888fc1a..4181600a 100644 --- a/setup.py +++ b/setup.py @@ -40,11 +40,11 @@ else: arb = 'arb' - libraries = [arb, "flint"] + libraries = ["flint"] (opt,) = get_config_vars('OPT') os.environ['OPT'] = " ".join(flag for flag in opt.split() if flag != '-Wstrict-prototypes') - +default_include_dirs += ["/Users/davideinstein/opt/flint/include"] default_include_dirs += [ os.path.join(d, "flint") for d in default_include_dirs ] @@ -67,7 +67,7 @@ Extension( "flint._flint", ["src/flint/pyflint.pyx"], libraries=libraries, - library_dirs=default_lib_dirs, + library_dirs=default_lib_dirs + ["/Users/davideinstein/opt/flint/lib"], include_dirs=default_include_dirs, define_macros=define_macros, ) diff --git a/src/flint/_flint.pxd b/src/flint/_flint.pxd index 166e14a6..5f1592e8 100644 --- a/src/flint/_flint.pxd +++ b/src/flint/_flint.pxd @@ -88,13 +88,6 @@ cdef extern from "flint/nmod_poly.h": nmod_t mod ctypedef nmod_poly_struct nmod_poly_t[1] - ctypedef struct nmod_poly_factor_struct: - nmod_poly_struct *p - long *exp - long num - long alloc - ctypedef nmod_poly_factor_struct nmod_poly_factor_t[1] - void nmod_poly_init(nmod_poly_t poly, mp_limb_t n) void nmod_poly_init_preinv(nmod_poly_t poly, mp_limb_t n, mp_limb_t ninv) void nmod_poly_init2(nmod_poly_t poly, mp_limb_t n, long alloc) @@ -156,6 +149,15 @@ cdef extern from "flint/nmod_poly.h": void nmod_poly_exp_series(nmod_poly_t f, nmod_poly_t h, long n) int nmod_poly_is_irreducible(nmod_poly_t f) + +cdef extern from "flint/nmod_poly_factor.h": + ctypedef struct nmod_poly_factor_struct: + nmod_poly_struct *p + long *exp + long num + long alloc + ctypedef nmod_poly_factor_struct nmod_poly_factor_t[1] + mp_limb_t nmod_poly_factor_with_berlekamp(nmod_poly_factor_t result, nmod_poly_t poly) mp_limb_t nmod_poly_factor_with_cantor_zassenhaus(nmod_poly_factor_t result, nmod_poly_t poly) mp_limb_t nmod_poly_factor(nmod_poly_factor_t result, nmod_poly_t input) From e97310550c338b9031e5202c3df27b0736e0e629 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Fri, 11 Aug 2023 14:03:57 -0400 Subject: [PATCH 02/21] Change from distutils to setuptools Added a skeleton pyproject.toml added a simple setuptools setup.py THere is no good replacement to use instead of numpy.distutils to get the default library and include paths. Any suggestions would be welcome. --- pyproject.toml | 2 ++ setup.py | 19 +++++-------------- 2 files changed, 7 insertions(+), 14 deletions(-) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..fcc670ea --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[build-system] +requires=["setuptools", "cython", "wheel"] diff --git a/setup.py b/setup.py index 4181600a..4396cc53 100644 --- a/setup.py +++ b/setup.py @@ -2,9 +2,8 @@ import os from subprocess import check_call -from distutils.core import setup -from distutils.extension import Extension -from Cython.Distutils import build_ext +from setuptools import setup +from setuptools import Extension from Cython.Build import cythonize from numpy.distutils.system_info import default_include_dirs, default_lib_dirs @@ -29,22 +28,15 @@ elif os.getenv('PYTHON_FLINT_MINGW64_TMP'): # This would be used to build under Windows against these libraries if # they have been installed somewhere other than .local - libraries = ["arb", "flint", "mpfr", "gmp"] + libraries = ["flint", "mpfr", "gmp"] else: # For the MSVC toolchain link with mpir instead of gmp - libraries = ["arb", "flint", "mpir", "mpfr", "pthreads"] + libraries = ["flint", "mpir", "mpfr", "pthreads"] else: - # On Ubuntu libarb.so is called libflint-arb.so - if os.getenv('PYTHON_FLINT_LIBFLINT_ARB'): - arb = 'flint-arb' - else: - arb = 'arb' - libraries = ["flint"] (opt,) = get_config_vars('OPT') os.environ['OPT'] = " ".join(flag for flag in opt.split() if flag != '-Wstrict-prototypes') -default_include_dirs += ["/Users/davideinstein/opt/flint/include"] default_include_dirs += [ os.path.join(d, "flint") for d in default_include_dirs ] @@ -67,7 +59,7 @@ Extension( "flint._flint", ["src/flint/pyflint.pyx"], libraries=libraries, - library_dirs=default_lib_dirs + ["/Users/davideinstein/opt/flint/lib"], + library_dirs=default_lib_dirs, include_dirs=default_include_dirs, define_macros=define_macros, ) @@ -78,7 +70,6 @@ setup( name='python-flint', - cmdclass={'build_ext': build_ext}, ext_modules=cythonize(ext_modules, compiler_directives=compiler_directives), #ext_modules=cythonize(ext_modules, compiler_directives=compiler_directives, annotate=True), packages=['flint', 'flint.test'], From 74c5f85ee2c7a029071fd6398303da2b6d59c5e3 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Wed, 16 Aug 2023 14:52:26 -0400 Subject: [PATCH 03/21] Change include paths for flint 3.0 The arb lib is now part of flint so all paths are prefixed with flint/ --- src/flint/_flint.pxd | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/flint/_flint.pxd b/src/flint/_flint.pxd index 5f1592e8..33dcbe06 100644 --- a/src/flint/_flint.pxd +++ b/src/flint/_flint.pxd @@ -755,7 +755,7 @@ cdef extern from "flint/arith.h": void arith_chebyshev_u_polynomial(fmpz_poly_t v, ulong n) void arith_cyclotomic_polynomial(fmpz_poly_t v, ulong n) -cdef extern from "mag.h": +cdef extern from "flint/mag.h": ctypedef struct mag_struct: fmpz_struct exp mp_limb_t man @@ -770,7 +770,7 @@ cdef extern from "mag.h": void mag_set_ui_2exp_si(mag_t x, ulong v, long e) void mag_hypot(mag_t x, const mag_t y, const mag_t z) -cdef extern from "arf.h": +cdef extern from "flint/arf.h": ctypedef struct arf_struct: fmpz_struct exp long size @@ -904,7 +904,7 @@ cdef extern from "arf.h": double arf_get_d(const arf_t x, arf_rnd_t rnd) void arf_set_d(arf_t x, double v) -cdef extern from "arb.h": +cdef extern from "flint/arb.h": ctypedef struct arb_struct: arf_struct mid mag_struct rad @@ -1195,7 +1195,7 @@ cdef extern from "arb.h": cdef ulong ARB_STR_CONDENSE char * arb_get_str(const arb_t x, long n, ulong flags) -cdef extern from "acb.h": +cdef extern from "flint/acb.h": ctypedef struct acb_struct: arb_struct real arb_struct imag @@ -1386,15 +1386,15 @@ cdef extern from "acb.h": void acb_root_ui(acb_t z, const acb_t x, ulong k, long prec) -cdef extern from "partitions.h": +cdef extern from "flint/partitions.h": void partitions_fmpz_fmpz(fmpz_t, const fmpz_t, int) -cdef extern from "bernoulli.h": +cdef extern from "flint/bernoulli.h": void bernoulli_fmpq_ui(fmpq_t, ulong) void bernoulli_cache_compute(long n) -cdef extern from "arb_poly.h": +cdef extern from "flint/arb_poly.h": ctypedef struct arb_poly_struct: arb_ptr coeffs long length @@ -1602,7 +1602,7 @@ cdef extern from "arb_poly.h": void arb_poly_lambertw_series(arb_poly_t res, const arb_poly_t z, int flags, long len, long prec) -cdef extern from "arb_mat.h": +cdef extern from "flint/arb_mat.h": ctypedef struct arb_mat_struct: arb_ptr entries long r @@ -1683,7 +1683,7 @@ cdef extern from "arb_mat.h": int arb_mat_approx_solve(arb_mat_t X, const arb_mat_t A, const arb_mat_t B, long prec) -cdef extern from "acb_poly.h": +cdef extern from "flint/acb_poly.h": ctypedef struct acb_poly_struct: acb_ptr coeffs long length @@ -1888,7 +1888,7 @@ cdef extern from "acb_poly.h": void acb_poly_lambertw_series(acb_poly_t res, const acb_poly_t z, const fmpz_t k, int flags, long len, long prec) -cdef extern from "acb_mat.h": +cdef extern from "flint/acb_mat.h": ctypedef struct acb_mat_struct: acb_ptr entries long r @@ -1978,7 +1978,7 @@ cdef extern from "acb_mat.h": int acb_mat_eig_multiple(acb_ptr E, const acb_mat_t A, acb_srcptr E_approx, const acb_mat_t R_approx, long prec) -cdef extern from "acb_modular.h": +cdef extern from "flint/acb_modular.h": void acb_modular_theta(acb_t theta1, acb_t theta2, acb_t theta3, acb_t theta4, const acb_t z, const acb_t tau, long prec) void acb_modular_theta_jet(acb_ptr theta1, acb_ptr theta2, acb_ptr theta3, acb_ptr theta4, const acb_t z, const acb_t tau, long len, long prec) void acb_modular_theta_series(acb_poly_t theta1, acb_poly_t theta2, acb_poly_t theta3, acb_poly_t theta4, const acb_poly_t z, const acb_t tau, long len, long prec) @@ -1994,7 +1994,7 @@ cdef extern from "acb_modular.h": void acb_modular_elliptic_e(acb_t w, const acb_t m, long prec) void acb_modular_hilbert_class_poly(fmpz_poly_t res, long D) -cdef extern from "acb_hypgeom.h": +cdef extern from "flint/acb_hypgeom.h": void acb_hypgeom_bessel_j(acb_t res, const acb_t nu, const acb_t z, long prec) void acb_hypgeom_bessel_k(acb_t res, const acb_t nu, const acb_t z, long prec) void acb_hypgeom_bessel_i(acb_t res, const acb_t nu, const acb_t z, long prec) @@ -2072,7 +2072,7 @@ cdef extern from "acb_hypgeom.h": void acb_hypgeom_chi_series(acb_poly_t res, const acb_poly_t h, long n, long prec) void acb_hypgeom_li_series(acb_poly_t res, const acb_poly_t h, int offset, long n, long prec) -cdef extern from "arb_hypgeom.h": +cdef extern from "flint/arb_hypgeom.h": void arb_hypgeom_pfq(arb_t res, arb_srcptr a, long p, arb_srcptr b, long q, const arb_t z, int regularized, long prec) void arb_hypgeom_0f1(arb_t res, const arb_t a, const arb_t z, int regularized, long prec) void arb_hypgeom_m(arb_t res, const arb_t a, const arb_t b, const arb_t z, int regularized, long prec) @@ -2137,7 +2137,7 @@ cdef extern from "arb_hypgeom.h": void arb_hypgeom_legendre_p_ui_root(arb_t res, arb_t weight, ulong n, ulong k, long prec) -cdef extern from "dirichlet.h": +cdef extern from "flint/dirichlet.h": ctypedef struct dirichlet_group_struct: ulong q ulong q_even @@ -2196,7 +2196,7 @@ cdef extern from "dirichlet.h": int dirichlet_char_is_primitive(const dirichlet_group_t G, const dirichlet_char_t chi) ulong dirichlet_chi(const dirichlet_group_t G, const dirichlet_char_t chi, ulong n) -cdef extern from "acb_dirichlet.h": +cdef extern from "flint/acb_dirichlet.h": void acb_dirichlet_eta(acb_t res, const acb_t s, long prec) void acb_dirichlet_chi(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi, ulong n, long prec) @@ -2213,7 +2213,7 @@ cdef extern from "acb_dirichlet.h": void acb_dirichlet_zeta_zero(acb_t res, const fmpz_t n, long prec) void acb_dirichlet_zeta_zeros(acb_ptr res, const fmpz_t n, long len, long prec) -cdef extern from "acb_elliptic.h": +cdef extern from "flint/acb_elliptic.h": void acb_elliptic_rf(acb_t res, const acb_t x, const acb_t y, const acb_t z, int flags, long prec) void acb_elliptic_rj(acb_t res, const acb_t x, const acb_t y, const acb_t z, const acb_t p, int flags, long prec) void acb_elliptic_rg(acb_t res, const acb_t x, const acb_t y, const acb_t z, int flags, long prec) @@ -2228,7 +2228,7 @@ cdef extern from "acb_elliptic.h": void acb_elliptic_invariants(acb_t g2, acb_t g3, const acb_t tau, long prec) void acb_elliptic_inv_p(acb_t res, const acb_t z, const acb_t tau, long prec) -cdef extern from "acb_calc.h": +cdef extern from "flint/acb_calc.h": ctypedef int (*acb_calc_func_t)(acb_ptr out, const acb_t inp, void * param, long order, long prec) ctypedef struct acb_calc_integrate_opt_struct: @@ -2248,14 +2248,14 @@ cdef extern from "acb_calc.h": const acb_calc_integrate_opt_t options, long prec) -cdef extern from "arb_fmpz_poly.h": +cdef extern from "flint/arb_fmpz_poly.h": void arb_fmpz_poly_evaluate_arb(arb_t res, const fmpz_poly_t poly, const arb_t x, long prec) void arb_fmpz_poly_evaluate_acb(acb_t res, const fmpz_poly_t poly, const acb_t x, long prec) void arb_fmpz_poly_complex_roots(acb_ptr roots, const fmpz_poly_t poly, int flags, long prec) ulong arb_fmpz_poly_deflation(const fmpz_poly_t poly) void arb_fmpz_poly_deflate(fmpz_poly_t res, const fmpz_poly_t poly, ulong deflation) -cdef extern from "acb_dft.h": +cdef extern from "flint/acb_dft.h": void acb_dft(acb_ptr w, acb_srcptr v, long n, long prec) void acb_dft_inverse(acb_ptr w, acb_srcptr v, long n, long prec) From c24b2ff0a5983d9047e974b030677bb79d72ec7b Mon Sep 17 00:00:00 2001 From: David Einstein Date: Thu, 17 Aug 2023 08:05:49 -0400 Subject: [PATCH 04/21] Starting attack at fmpz_mpoly added missing fmpz_mpoly_sort_terms to _flint.pxd updated fmpz_mpoly_context to include names and other term orders Fixed up arithmetic to use python 3 protocol and removed automatic conversion. --- src/flint/_flint.pxd | 2 + src/flint/fmpz_mpoly.pyx | 424 ++++++++++++++++++++++++++------------- src/flint/test/test.py | 13 ++ 3 files changed, 295 insertions(+), 144 deletions(-) diff --git a/src/flint/_flint.pxd b/src/flint/_flint.pxd index 33dcbe06..dae41ce4 100644 --- a/src/flint/_flint.pxd +++ b/src/flint/_flint.pxd @@ -2397,6 +2397,8 @@ cdef extern from "flint/fmpz_mpoly.h": void fmpz_mpoly_get_term_monomial(fmpz_mpoly_t M, const fmpz_mpoly_t A, slong i, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_sort_terms(fmpz_mpoly_t A, const fmpz_mpoly_ctx_t ctx) + # Addition/Subtraction void fmpz_mpoly_add_fmpz(fmpz_mpoly_t A, const fmpz_mpoly_t B, const fmpz_t c, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_add_si(fmpz_mpoly_t A, const fmpz_mpoly_t B, slong c, const fmpz_mpoly_ctx_t ctx) diff --git a/src/flint/fmpz_mpoly.pyx b/src/flint/fmpz_mpoly.pyx index 32ed47d3..2a07705f 100644 --- a/src/flint/fmpz_mpoly.pyx +++ b/src/flint/fmpz_mpoly.pyx @@ -41,27 +41,79 @@ cdef dict _fmpz_mpoly_ctx_cache = {} @cython.auto_pickle(False) cdef class fmpz_mpoly_ctx: + """ + A class for storing the polynomial context + + :param nvars: The number of variables in the ring + :param ordering: The term order for the ring + :param names: A tuple containing the names of the variables of the ring. + + Do not construct one of these directly, use `get_fmpz_mpoly_context`. + """ cdef fmpz_mpoly_ctx_t val + cdef public object py_names + cdef char ** c_names + cdef bint _init + + def __cinit__(self): + self._init = False - def __init__(self, slong nvars, ordering="lex"): + def __init__(self, slong nvars, ordering, names): assert nvars >= 1 - fmpz_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_LEX) + assert len(names) == nvars + if ordering == "lex": + fmpz_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_LEX) + elif ordering == "deglex": + fmpz_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_DEGLEX) + elif ordering == "degrevlex": + fmpz_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_DEGREVLEX) + else: + raise ValueError("Unimplemented term order %s" % ordering) + self.py_names = tuple(bytes(name, 'utf-8') for name in names) + self.c_names = libc.stdlib.malloc(nvars * sizeof(char *)) + for i in range(nvars): + self.c_names[i] = self.py_names[i] cpdef slong nvars(self): return self.val.minfo.nvars cpdef ordering(self): - return "lex" + if self.val.minfo.ord == ordering_t.ORD_LEX: + return "lex" + if self.val.minfo.ord == ordering_t.ORD_DEGLEX: + return "deglex" + if self.val.minfo.ord == ordering_t.ORD_DEGREVLEX: + return "degrevlex" + + cpdef name(self, slong i): + assert i >= 0 and i < self.val.minfo.nvars + return self.py_names[i] + + cpdef gen(self, slong i): + cdef fmpz_mpoly res + assert i >= 0 and i < self.val.minfo.nvars + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx = self + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + fmpz_mpoly_gen(res.val, i, res.ctx.val) + return res + + def gens(self): + return tuple(self.gen(i) for i in range(self.nvars())) -cdef get_fmpz_mpoly_context(slong nvars=1, ordering=None): +def get_fmpz_mpoly_context(slong nvars=1, ordering="lex", names='x'): if nvars <= 0: nvars = 1 - if ordering is None: - ordering = "lex" - key = (nvars, ordering) + nametup = tuple(name.strip() for name in names.split(',')) + if len(nametup) != nvars: + if len(nametup) != 1: + raise ValueError("Number of variables does not equal number of names") + nametup = tuple(nametup[0] + str(i) for i in range(nvars)) + key = (nvars, ordering, nametup) ctx = _fmpz_mpoly_ctx_cache.get(key) if ctx is None: - ctx = fmpz_mpoly_ctx(nvars, ordering) + ctx = fmpz_mpoly_ctx(nvars, ordering, nametup) _fmpz_mpoly_ctx_cache[key] = ctx return ctx @@ -123,23 +175,31 @@ cdef class fmpz_mpoly(flint_mpoly): fmpz_mpoly_clear(self.val, self.ctx.val) self._init = False - def __init__(self, val=0, slong nvars=-1, ordering=None): + def __init__(self, val=0, ctx=None): if typecheck(val, fmpz_mpoly): - if nvars == -1 and ordering is None: + if ctx is None or ctx == (val).ctx: self.ctx = (val).ctx fmpz_mpoly_init(self.val, self.ctx.val) self._init = True fmpz_mpoly_set(self.val, (val).val, self.ctx.val) else: - self.ctx = get_fmpz_mpoly_context(nvars, ordering) - fmpz_mpoly_init(self.val, self.ctx.val) - self._init = True - _fmpz_mpoly_set2(self.val, self.ctx.val, (val).val, (val).ctx.val) + raise ValueError("Cannot automatically coerce contexts") + elif isinstance(val, str): + if ctx is None: + raise ValueError("Cannot parse a polynomial without context") + val = bytes(val, 'utf-8') + self.ctx = ctx + fmpz_mpoly_init(self.val, self.ctx.val) + self._init = True + fmpz_mpoly_set_str_pretty(self.val, val, self.ctx.c_names, self.ctx.val) + fmpz_mpoly_sort_terms(self.val, self.ctx.val) else: v = any_as_fmpz(val) if v is NotImplemented: raise TypeError("cannot create fmpz_mpoly from type %s" % type(val)) - self.ctx = get_fmpz_mpoly_context(nvars, ordering) + if ctx is None: + raise ValueError("Need context to convert fmpz to fmpz_mpoly") + self.ctx = ctx fmpz_mpoly_init(self.val, self.ctx.val) self._init = True fmpz_mpoly_set_fmpz(self.val, (v).val, self.ctx.val) @@ -147,6 +207,9 @@ cdef class fmpz_mpoly(flint_mpoly): def __nonzero__(self): return not fmpz_mpoly_is_zero(self.val, self.ctx.val) + def __bool__(self): + return not fmpz_mpoly_is_zero(self.val, self.ctx.val) + def is_one(self): return fmpz_mpoly_is_one(self.val, self.ctx.val) @@ -159,6 +222,11 @@ cdef class fmpz_mpoly(flint_mpoly): return bool(fmpz_mpoly_equal((self).val, (other).val, (self).ctx.val)) else: return not bool(fmpz_mpoly_equal((self).val, (other).val, (self).ctx.val)) + else: + if op == 2: + return False + else: + return True if op == 2: return not bool(self - other) else: @@ -169,8 +237,8 @@ cdef class fmpz_mpoly(flint_mpoly): def __hash__(self): s = str(self) - i = s.index("(nvars") - s = s[:i] +# i = s.index("(nvars") +# s = s[:i] return hash(s) def coefficient(self, slong i): @@ -201,27 +269,30 @@ cdef class fmpz_mpoly(flint_mpoly): libc.stdlib.free(tmp) return res - @staticmethod - def gen(slong i, slong nvars=-1, ordering=None): - cdef fmpz_mpoly res - assert i >= 0 - if nvars <= 0: - nvars = i + 1 - assert i < nvars - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = get_fmpz_mpoly_context(nvars, ordering) - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True - fmpz_mpoly_gen(res.val, i, res.ctx.val) - return res - - @staticmethod - def gens(slong n, ordering=None): - # todo: (i, n)? or just (i)? - return tuple(fmpz_mpoly.gen(i, n) for i in range(n)) + # @staticmethod + # def gen(slong i, slong nvars=-1, ordering=None): + # cdef fmpz_mpoly res + # assert i >= 0 + # if nvars <= 0: + # nvars = i + 1 + # assert i < nvars + # res = fmpz_mpoly.__new__(fmpz_mpoly) + # res.ctx = get_fmpz_mpoly_context(nvars, ordering) + # fmpz_mpoly_init(res.val, res.ctx.val) + # res._init = True + # fmpz_mpoly_gen(res.val, i, res.ctx.val) + # return res + + # @staticmethod + # def gens(slong n, ordering=None): + # # todo: (i, n)? or just (i)? + # return tuple(fmpz_mpoly.gen(i, n) for i in range(n)) def repr(self): - cdef char * s = fmpz_mpoly_get_str_pretty(self.val, NULL, self.ctx.val) + return self.str() + " (nvars=%s, ordering=%s names=%s)" % (self.ctx.nvars(), self.ctx.ordering(), self.ctx.py_names) + + def str(self): + cdef char * s = fmpz_mpoly_get_str_pretty(self.val, self.ctx.c_names, self.ctx.val) try: res = str_from_chars(s) finally: @@ -230,9 +301,8 @@ cdef class fmpz_mpoly(flint_mpoly): res = res.replace("-", " - ") if res.startswith(" - "): res = "-" + res[3:] - return res + " (nvars=%s, ordering=%s)" % (self.ctx.nvars(), self.ctx.ordering()) + return res - def str(self): return self.repr() def __neg__(self): @@ -246,150 +316,216 @@ cdef class fmpz_mpoly(flint_mpoly): def __add__(self, other): cdef fmpz_mpoly res - if typecheck(self, fmpz_mpoly): - if typecheck(other, fmpz_mpoly): - if (self).ctx is not (other).ctx: - ctx, (self, other) = coerce_fmpz_mpolys(self, other) - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True - fmpz_mpoly_add(res.val, (self).val, (other).val, res.ctx.val) - return res - else: - other = any_as_fmpz(other) - if other is not NotImplemented: - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True - fmpz_mpoly_add_fmpz(res.val, (self).val, (other).val, res.ctx.val) - return res + if typecheck(other, fmpz_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx =(self).ctx + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + fmpz_mpoly_add(res.val, (self).val, (other).val, res.ctx.val) + return res else: - self = any_as_fmpz(self) - if self is not NotImplemented: + other = any_as_fmpz(other) + if other is not NotImplemented: res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (other).ctx + res.ctx = (self).ctx fmpz_mpoly_init(res.val, res.ctx.val) res._init = True - fmpz_mpoly_add_fmpz(res.val, (other).val, (self).val, res.ctx.val) + fmpz_mpoly_add_fmpz(res.val, (self).val, (other).val, res.ctx.val) return res return NotImplemented + def __radd__(self, other): + cdef fmpz_mpoly res + other = any_as_fmpz(other) + if other is not NotImplemented: + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx = (self).ctx + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + fmpz_mpoly_add_fmpz(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + def __sub__(self, other): cdef fmpz_mpoly res - if typecheck(self, fmpz_mpoly): - if typecheck(other, fmpz_mpoly): - if (self).ctx is not (other).ctx: - ctx, (self, other) = coerce_fmpz_mpolys(self, other) - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True - fmpz_mpoly_sub(res.val, (self).val, (other).val, res.ctx.val) - return res - else: - other = any_as_fmpz(other) - if other is not NotImplemented: - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True - fmpz_mpoly_sub_fmpz(res.val, (self).val, (other).val, res.ctx.val) - return res + if typecheck(other, fmpz_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx =(self).ctx + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + fmpz_mpoly_sub(res.val, (self).val, (other).val, res.ctx.val) + return res else: - self = any_as_fmpz(self) - if self is not NotImplemented: + other = any_as_fmpz(other) + if other is not NotImplemented: res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (other).ctx + res.ctx = (self).ctx fmpz_mpoly_init(res.val, res.ctx.val) res._init = True - fmpz_mpoly_sub_fmpz(res.val, (other).val, (self).val, res.ctx.val) - fmpz_mpoly_neg(res.val, res.val, res.ctx.val) + fmpz_mpoly_sub_fmpz(res.val, (self).val, (other).val, res.ctx.val) return res return NotImplemented + def __rsub__(self, other): + cdef fmpz_mpoly res + other = any_as_fmpz(other) + if other is not NotImplemented: + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx = (self).ctx + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + fmpz_mpoly_sub_fmpz(res.val, (self).val, (other).val, res.ctx.val) + return -res + return NotImplemented + + # def __sub__(self, other): + # cdef fmpz_mpoly res + # if typecheck(self, fmpz_mpoly): + # if typecheck(other, fmpz_mpoly): + # if (self).ctx is not (other).ctx: + # ctx, (self, other) = coerce_fmpz_mpolys(self, other) + # res = fmpz_mpoly.__new__(fmpz_mpoly) + # res.ctx = (self).ctx + # fmpz_mpoly_init(res.val, res.ctx.val) + # res._init = True + # fmpz_mpoly_sub(res.val, (self).val, (other).val, res.ctx.val) + # return res + # else: + # other = any_as_fmpz(other) + # if other is not NotImplemented: + # res = fmpz_mpoly.__new__(fmpz_mpoly) + # res.ctx = (self).ctx + # fmpz_mpoly_init(res.val, res.ctx.val) + # res._init = True + # fmpz_mpoly_sub_fmpz(res.val, (self).val, (other).val, res.ctx.val) + # return res + # else: + # self = any_as_fmpz(self) + # if self is not NotImplemented: + # res = fmpz_mpoly.__new__(fmpz_mpoly) + # res.ctx = (other).ctx + # fmpz_mpoly_init(res.val, res.ctx.val) + # res._init = True + # fmpz_mpoly_sub_fmpz(res.val, (other).val, (self).val, res.ctx.val) + # fmpz_mpoly_neg(res.val, res.val, res.ctx.val) + # return res + # return NotImplemented + def __mul__(self, other): cdef fmpz_mpoly res - if typecheck(self, fmpz_mpoly): - if typecheck(other, fmpz_mpoly): - if (self).ctx is not (other).ctx: - ctx, (self, other) = coerce_fmpz_mpolys(self, other) - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True - fmpz_mpoly_mul(res.val, (self).val, (other).val, res.ctx.val) - return res - else: - other = any_as_fmpz(other) - if other is not NotImplemented: - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True - fmpz_mpoly_scalar_mul_fmpz(res.val, (self).val, (other).val, res.ctx.val) - return res + if typecheck(other, fmpz_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx =(self).ctx + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + fmpz_mpoly_mul(res.val, (self).val, (other).val, res.ctx.val) + return res else: - self = any_as_fmpz(self) - if self is not NotImplemented: + other = any_as_fmpz(other) + if other is not NotImplemented: res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (other).ctx + res.ctx = (self).ctx fmpz_mpoly_init(res.val, res.ctx.val) res._init = True - fmpz_mpoly_scalar_mul_fmpz(res.val, (other).val, (self).val, res.ctx.val) + fmpz_mpoly_scalar_mul_fmpz(res.val, (self).val, (other).val, res.ctx.val) return res return NotImplemented - def __pow__(self, other, modulus): + def __rmul__(self, other): cdef fmpz_mpoly res - if modulus is not None: - raise NotImplementedError - if typecheck(self, fmpz_mpoly): - other = any_as_fmpz(other) - if other is NotImplemented: - return other - if other < 0: - raise ValueError("cannot raise fmpz_mpoly to negative power") + other = any_as_fmpz(other) + if other is not NotImplemented: res = fmpz_mpoly.__new__(fmpz_mpoly) res.ctx = (self).ctx fmpz_mpoly_init(res.val, res.ctx.val) res._init = True - if fmpz_mpoly_pow_fmpz(res.val, (self).val, (other).val, res.ctx.val) == 0: - raise ValueError("unreasonably large polynomial") + fmpz_mpoly_scalar_mul_fmpz(res.val, (self).val, (other).val, res.ctx.val) return res return NotImplemented + # def __mul__(self, other): + # cdef fmpz_mpoly res + # if typecheck(self, fmpz_mpoly): + # if typecheck(other, fmpz_mpoly): + # if (self).ctx is not (other).ctx: + # ctx, (self, other) = coerce_fmpz_mpolys(self, other) + # res = fmpz_mpoly.__new__(fmpz_mpoly) + # res.ctx = (self).ctx + # fmpz_mpoly_init(res.val, res.ctx.val) + # res._init = True + # fmpz_mpoly_mul(res.val, (self).val, (other).val, res.ctx.val) + # return res + # else: + # other = any_as_fmpz(other) + # if other is not NotImplemented: + # res = fmpz_mpoly.__new__(fmpz_mpoly) + # res.ctx = (self).ctx + # fmpz_mpoly_init(res.val, res.ctx.val) + # res._init = True + # fmpz_mpoly_scalar_mul_fmpz(res.val, (self).val, (other).val, res.ctx.val) + # return res + # else: + # self = any_as_fmpz(self) + # if self is not NotImplemented: + # res = fmpz_mpoly.__new__(fmpz_mpoly) + # res.ctx = (other).ctx + # fmpz_mpoly_init(res.val, res.ctx.val) + # res._init = True + # fmpz_mpoly_scalar_mul_fmpz(res.val, (other).val, (self).val, res.ctx.val) + # return res + # return NotImplemented + + def __pow__(self, other, modulus): + cdef fmpz_mpoly res + if modulus is not None: + raise NotImplementedError + other = any_as_fmpz(other) + if other is NotImplemented: + return other + if other < 0: + raise ValueError("cannot raise fmpz_mpoly to negative power") + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx = (self).ctx + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + if fmpz_mpoly_pow_fmpz(res.val, (self).val, (other).val, res.ctx.val) == 0: + raise ValueError("unreasonably large polynomial") + return res + def __divmod__(self, other): cdef fmpz_mpoly res, res2 - if typecheck(self, fmpz_mpoly): - if typecheck(other, fmpz_mpoly): - if (self).ctx is not (other).ctx: - ctx, (self, other) = coerce_fmpz_mpolys(self, other) - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True - res2 = fmpz_mpoly.__new__(fmpz_mpoly) - res2.ctx = (self).ctx - fmpz_mpoly_init(res2.val, res2.ctx.val) - res2._init = True - fmpz_mpoly_divrem(res.val, res2.val, (self).val, (other).val, res.ctx.val) - return (res, res2) + if typecheck(other, fmpz_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx = (self).ctx + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + res2 = fmpz_mpoly.__new__(fmpz_mpoly) + res2.ctx = (self).ctx + fmpz_mpoly_init(res2.val, res2.ctx.val) + res2._init = True + fmpz_mpoly_divrem(res.val, res2.val, (self).val, (other).val, res.ctx.val) + return (res, res2) return NotImplemented def __floordiv__(self, other): cdef fmpz_mpoly res - if typecheck(self, fmpz_mpoly): - if typecheck(other, fmpz_mpoly): - if (self).ctx is not (other).ctx: - ctx, (self, other) = coerce_fmpz_mpolys(self, other) - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True - fmpz_mpoly_div(res.val, (self).val, (other).val, res.ctx.val) - return res + if typecheck(other, fmpz_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx = (self).ctx + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + fmpz_mpoly_div(res.val, (self).val, (other).val, res.ctx.val) + return res return NotImplemented def __mod__(self, other): @@ -399,7 +535,7 @@ cdef class fmpz_mpoly(flint_mpoly): cdef fmpz_mpoly res assert isinstance(other, fmpz_mpoly) if (self).ctx is not (other).ctx: - ctx, (self, other) = coerce_fmpz_mpolys(self, other) + return NotImplemented res = fmpz_mpoly.__new__(fmpz_mpoly) res.ctx = (self).ctx fmpz_mpoly_init(res.val, res.ctx.val) diff --git a/src/flint/test/test.py b/src/flint/test/test.py index 69c62ecc..439914a2 100644 --- a/src/flint/test/test.py +++ b/src/flint/test/test.py @@ -626,6 +626,19 @@ def set_bad(i,j): assert M6.minpoly() == flint.fmpz_poly([4,-4,1]) assert list(M6) == [2,0,0,0,2,1,0,0,2] +def test_fmpz_mpoly(): + Zp = flint.fmpz_mpoly + getctx = flint.get_fmpz_mpoly_ctx + ctx = getctx(4) + assert ctx.nvars() == 4 + assert ctx.ordering() == "lex" + assert [ctx.name(i) for i in range(4)] == ['x0', 'x1', 'x2', 'x3'] + for order in ['lex', 'deglex', 'degrevlex']: + ctx1 = getctx(4, order) + assert ctx1.ordering() == order + ctx = getctx(4, "lex", 'w,x,y,z') + + def test_fmpz_series(): Zp = flint.fmpz_poly Z = flint.fmpz_series From 048915293fc58ab30f895d9a50469a9cb8d3b071 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Thu, 17 Aug 2023 09:27:28 -0400 Subject: [PATCH 05/21] Made the tests pass. Made fmpz_mpoly_ctx return a string instead of bytes. --- src/flint/fmpz_mpoly.pyx | 94 +++------------------------------------- src/flint/test/test.py | 5 ++- 2 files changed, 11 insertions(+), 88 deletions(-) diff --git a/src/flint/fmpz_mpoly.pyx b/src/flint/fmpz_mpoly.pyx index 2a07705f..e793a670 100644 --- a/src/flint/fmpz_mpoly.pyx +++ b/src/flint/fmpz_mpoly.pyx @@ -71,9 +71,15 @@ cdef class fmpz_mpoly_ctx: raise ValueError("Unimplemented term order %s" % ordering) self.py_names = tuple(bytes(name, 'utf-8') for name in names) self.c_names = libc.stdlib.malloc(nvars * sizeof(char *)) + self._init = True for i in range(nvars): self.c_names[i] = self.py_names[i] + def __dealloc__(self): + if self._init: + libc.stdlib.free(self.c_names) + self._init = False + cpdef slong nvars(self): return self.val.minfo.nvars @@ -87,7 +93,7 @@ cdef class fmpz_mpoly_ctx: cpdef name(self, slong i): assert i >= 0 and i < self.val.minfo.nvars - return self.py_names[i] + return self.py_names[i].decode('utf-8') cpdef gen(self, slong i): cdef fmpz_mpoly res @@ -237,8 +243,6 @@ cdef class fmpz_mpoly(flint_mpoly): def __hash__(self): s = str(self) -# i = s.index("(nvars") -# s = s[:i] return hash(s) def coefficient(self, slong i): @@ -269,25 +273,6 @@ cdef class fmpz_mpoly(flint_mpoly): libc.stdlib.free(tmp) return res - # @staticmethod - # def gen(slong i, slong nvars=-1, ordering=None): - # cdef fmpz_mpoly res - # assert i >= 0 - # if nvars <= 0: - # nvars = i + 1 - # assert i < nvars - # res = fmpz_mpoly.__new__(fmpz_mpoly) - # res.ctx = get_fmpz_mpoly_context(nvars, ordering) - # fmpz_mpoly_init(res.val, res.ctx.val) - # res._init = True - # fmpz_mpoly_gen(res.val, i, res.ctx.val) - # return res - - # @staticmethod - # def gens(slong n, ordering=None): - # # todo: (i, n)? or just (i)? - # return tuple(fmpz_mpoly.gen(i, n) for i in range(n)) - def repr(self): return self.str() + " (nvars=%s, ordering=%s names=%s)" % (self.ctx.nvars(), self.ctx.ordering(), self.ctx.py_names) @@ -382,39 +367,6 @@ cdef class fmpz_mpoly(flint_mpoly): return -res return NotImplemented - # def __sub__(self, other): - # cdef fmpz_mpoly res - # if typecheck(self, fmpz_mpoly): - # if typecheck(other, fmpz_mpoly): - # if (self).ctx is not (other).ctx: - # ctx, (self, other) = coerce_fmpz_mpolys(self, other) - # res = fmpz_mpoly.__new__(fmpz_mpoly) - # res.ctx = (self).ctx - # fmpz_mpoly_init(res.val, res.ctx.val) - # res._init = True - # fmpz_mpoly_sub(res.val, (self).val, (other).val, res.ctx.val) - # return res - # else: - # other = any_as_fmpz(other) - # if other is not NotImplemented: - # res = fmpz_mpoly.__new__(fmpz_mpoly) - # res.ctx = (self).ctx - # fmpz_mpoly_init(res.val, res.ctx.val) - # res._init = True - # fmpz_mpoly_sub_fmpz(res.val, (self).val, (other).val, res.ctx.val) - # return res - # else: - # self = any_as_fmpz(self) - # if self is not NotImplemented: - # res = fmpz_mpoly.__new__(fmpz_mpoly) - # res.ctx = (other).ctx - # fmpz_mpoly_init(res.val, res.ctx.val) - # res._init = True - # fmpz_mpoly_sub_fmpz(res.val, (other).val, (self).val, res.ctx.val) - # fmpz_mpoly_neg(res.val, res.val, res.ctx.val) - # return res - # return NotImplemented - def __mul__(self, other): cdef fmpz_mpoly res if typecheck(other, fmpz_mpoly): @@ -449,38 +401,6 @@ cdef class fmpz_mpoly(flint_mpoly): return res return NotImplemented - # def __mul__(self, other): - # cdef fmpz_mpoly res - # if typecheck(self, fmpz_mpoly): - # if typecheck(other, fmpz_mpoly): - # if (self).ctx is not (other).ctx: - # ctx, (self, other) = coerce_fmpz_mpolys(self, other) - # res = fmpz_mpoly.__new__(fmpz_mpoly) - # res.ctx = (self).ctx - # fmpz_mpoly_init(res.val, res.ctx.val) - # res._init = True - # fmpz_mpoly_mul(res.val, (self).val, (other).val, res.ctx.val) - # return res - # else: - # other = any_as_fmpz(other) - # if other is not NotImplemented: - # res = fmpz_mpoly.__new__(fmpz_mpoly) - # res.ctx = (self).ctx - # fmpz_mpoly_init(res.val, res.ctx.val) - # res._init = True - # fmpz_mpoly_scalar_mul_fmpz(res.val, (self).val, (other).val, res.ctx.val) - # return res - # else: - # self = any_as_fmpz(self) - # if self is not NotImplemented: - # res = fmpz_mpoly.__new__(fmpz_mpoly) - # res.ctx = (other).ctx - # fmpz_mpoly_init(res.val, res.ctx.val) - # res._init = True - # fmpz_mpoly_scalar_mul_fmpz(res.val, (other).val, (self).val, res.ctx.val) - # return res - # return NotImplemented - def __pow__(self, other, modulus): cdef fmpz_mpoly res if modulus is not None: diff --git a/src/flint/test/test.py b/src/flint/test/test.py index 439914a2..7d30a34e 100644 --- a/src/flint/test/test.py +++ b/src/flint/test/test.py @@ -628,7 +628,7 @@ def set_bad(i,j): def test_fmpz_mpoly(): Zp = flint.fmpz_mpoly - getctx = flint.get_fmpz_mpoly_ctx + getctx = flint.get_fmpz_mpoly_context ctx = getctx(4) assert ctx.nvars() == 4 assert ctx.ordering() == "lex" @@ -637,6 +637,8 @@ def test_fmpz_mpoly(): ctx1 = getctx(4, order) assert ctx1.ordering() == order ctx = getctx(4, "lex", 'w,x,y,z') + p1 = ctx.gen(0) + ctx.gen(1) - ctx.gen(2) * ctx.gen(3) + assert p1 == Zp("w + x - y * z", ctx) def test_fmpz_series(): @@ -1581,6 +1583,7 @@ def test_pickling(): test_fmpz_poly_factor, test_fmpz_poly_functions, test_fmpz_mat, + test_fmpz_mpoly, test_fmpz_series, test_fmpq, test_fmpq_poly, From 89d567ca8fd9a64e945f8c618523ce4bc1d2600a Mon Sep 17 00:00:00 2001 From: David Einstein Date: Thu, 17 Aug 2023 14:56:44 -0400 Subject: [PATCH 06/21] Back out changes for flint3 and setuptools I hope these work for CI. I currently don't have flint 3.0 or whatever the matching arb lib is. --- pyproject.toml | 2 -- setup.py | 19 ++++++++++---- src/flint/_flint.pxd | 56 +++++++++++++++++++--------------------- src/flint/fmpz_mpoly.pyx | 2 +- 4 files changed, 41 insertions(+), 38 deletions(-) delete mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index fcc670ea..00000000 --- a/pyproject.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build-system] -requires=["setuptools", "cython", "wheel"] diff --git a/setup.py b/setup.py index ecd4267a..85b92404 100644 --- a/setup.py +++ b/setup.py @@ -2,8 +2,9 @@ import os from subprocess import check_call -from setuptools import setup -from setuptools import Extension +from distutils.core import setup +from distutils.extension import Extension +from Cython.Distutils import build_ext from Cython.Build import cythonize from numpy.distutils.system_info import default_include_dirs, default_lib_dirs @@ -28,15 +29,22 @@ elif os.getenv('PYTHON_FLINT_MINGW64_TMP'): # This would be used to build under Windows against these libraries if # they have been installed somewhere other than .local - libraries = ["flint", "mpfr", "gmp"] + libraries = ["arb", "flint", "mpfr", "gmp"] else: # For the MSVC toolchain link with mpir instead of gmp - libraries = ["flint", "mpir", "mpfr", "pthreads"] + libraries = ["arb", "flint", "mpir", "mpfr", "pthreads"] else: - libraries = ["flint"] + # On Ubuntu libarb.so is called libflint-arb.so + if os.getenv('PYTHON_FLINT_LIBFLINT_ARB'): + arb = 'flint-arb' + else: + arb = 'arb' + + libraries = [arb, "flint"] (opt,) = get_config_vars('OPT') os.environ['OPT'] = " ".join(flag for flag in opt.split() if flag != '-Wstrict-prototypes') + default_include_dirs += [ os.path.join(d, "flint") for d in default_include_dirs ] @@ -70,6 +78,7 @@ setup( name='python-flint', + cmdclass={'build_ext': build_ext}, ext_modules=cythonize(ext_modules, compiler_directives=compiler_directives), #ext_modules=cythonize(ext_modules, compiler_directives=compiler_directives, annotate=True), packages=['flint', 'flint.test'], diff --git a/src/flint/_flint.pxd b/src/flint/_flint.pxd index dae41ce4..166e14a6 100644 --- a/src/flint/_flint.pxd +++ b/src/flint/_flint.pxd @@ -88,6 +88,13 @@ cdef extern from "flint/nmod_poly.h": nmod_t mod ctypedef nmod_poly_struct nmod_poly_t[1] + ctypedef struct nmod_poly_factor_struct: + nmod_poly_struct *p + long *exp + long num + long alloc + ctypedef nmod_poly_factor_struct nmod_poly_factor_t[1] + void nmod_poly_init(nmod_poly_t poly, mp_limb_t n) void nmod_poly_init_preinv(nmod_poly_t poly, mp_limb_t n, mp_limb_t ninv) void nmod_poly_init2(nmod_poly_t poly, mp_limb_t n, long alloc) @@ -149,15 +156,6 @@ cdef extern from "flint/nmod_poly.h": void nmod_poly_exp_series(nmod_poly_t f, nmod_poly_t h, long n) int nmod_poly_is_irreducible(nmod_poly_t f) - -cdef extern from "flint/nmod_poly_factor.h": - ctypedef struct nmod_poly_factor_struct: - nmod_poly_struct *p - long *exp - long num - long alloc - ctypedef nmod_poly_factor_struct nmod_poly_factor_t[1] - mp_limb_t nmod_poly_factor_with_berlekamp(nmod_poly_factor_t result, nmod_poly_t poly) mp_limb_t nmod_poly_factor_with_cantor_zassenhaus(nmod_poly_factor_t result, nmod_poly_t poly) mp_limb_t nmod_poly_factor(nmod_poly_factor_t result, nmod_poly_t input) @@ -755,7 +753,7 @@ cdef extern from "flint/arith.h": void arith_chebyshev_u_polynomial(fmpz_poly_t v, ulong n) void arith_cyclotomic_polynomial(fmpz_poly_t v, ulong n) -cdef extern from "flint/mag.h": +cdef extern from "mag.h": ctypedef struct mag_struct: fmpz_struct exp mp_limb_t man @@ -770,7 +768,7 @@ cdef extern from "flint/mag.h": void mag_set_ui_2exp_si(mag_t x, ulong v, long e) void mag_hypot(mag_t x, const mag_t y, const mag_t z) -cdef extern from "flint/arf.h": +cdef extern from "arf.h": ctypedef struct arf_struct: fmpz_struct exp long size @@ -904,7 +902,7 @@ cdef extern from "flint/arf.h": double arf_get_d(const arf_t x, arf_rnd_t rnd) void arf_set_d(arf_t x, double v) -cdef extern from "flint/arb.h": +cdef extern from "arb.h": ctypedef struct arb_struct: arf_struct mid mag_struct rad @@ -1195,7 +1193,7 @@ cdef extern from "flint/arb.h": cdef ulong ARB_STR_CONDENSE char * arb_get_str(const arb_t x, long n, ulong flags) -cdef extern from "flint/acb.h": +cdef extern from "acb.h": ctypedef struct acb_struct: arb_struct real arb_struct imag @@ -1386,15 +1384,15 @@ cdef extern from "flint/acb.h": void acb_root_ui(acb_t z, const acb_t x, ulong k, long prec) -cdef extern from "flint/partitions.h": +cdef extern from "partitions.h": void partitions_fmpz_fmpz(fmpz_t, const fmpz_t, int) -cdef extern from "flint/bernoulli.h": +cdef extern from "bernoulli.h": void bernoulli_fmpq_ui(fmpq_t, ulong) void bernoulli_cache_compute(long n) -cdef extern from "flint/arb_poly.h": +cdef extern from "arb_poly.h": ctypedef struct arb_poly_struct: arb_ptr coeffs long length @@ -1602,7 +1600,7 @@ cdef extern from "flint/arb_poly.h": void arb_poly_lambertw_series(arb_poly_t res, const arb_poly_t z, int flags, long len, long prec) -cdef extern from "flint/arb_mat.h": +cdef extern from "arb_mat.h": ctypedef struct arb_mat_struct: arb_ptr entries long r @@ -1683,7 +1681,7 @@ cdef extern from "flint/arb_mat.h": int arb_mat_approx_solve(arb_mat_t X, const arb_mat_t A, const arb_mat_t B, long prec) -cdef extern from "flint/acb_poly.h": +cdef extern from "acb_poly.h": ctypedef struct acb_poly_struct: acb_ptr coeffs long length @@ -1888,7 +1886,7 @@ cdef extern from "flint/acb_poly.h": void acb_poly_lambertw_series(acb_poly_t res, const acb_poly_t z, const fmpz_t k, int flags, long len, long prec) -cdef extern from "flint/acb_mat.h": +cdef extern from "acb_mat.h": ctypedef struct acb_mat_struct: acb_ptr entries long r @@ -1978,7 +1976,7 @@ cdef extern from "flint/acb_mat.h": int acb_mat_eig_multiple(acb_ptr E, const acb_mat_t A, acb_srcptr E_approx, const acb_mat_t R_approx, long prec) -cdef extern from "flint/acb_modular.h": +cdef extern from "acb_modular.h": void acb_modular_theta(acb_t theta1, acb_t theta2, acb_t theta3, acb_t theta4, const acb_t z, const acb_t tau, long prec) void acb_modular_theta_jet(acb_ptr theta1, acb_ptr theta2, acb_ptr theta3, acb_ptr theta4, const acb_t z, const acb_t tau, long len, long prec) void acb_modular_theta_series(acb_poly_t theta1, acb_poly_t theta2, acb_poly_t theta3, acb_poly_t theta4, const acb_poly_t z, const acb_t tau, long len, long prec) @@ -1994,7 +1992,7 @@ cdef extern from "flint/acb_modular.h": void acb_modular_elliptic_e(acb_t w, const acb_t m, long prec) void acb_modular_hilbert_class_poly(fmpz_poly_t res, long D) -cdef extern from "flint/acb_hypgeom.h": +cdef extern from "acb_hypgeom.h": void acb_hypgeom_bessel_j(acb_t res, const acb_t nu, const acb_t z, long prec) void acb_hypgeom_bessel_k(acb_t res, const acb_t nu, const acb_t z, long prec) void acb_hypgeom_bessel_i(acb_t res, const acb_t nu, const acb_t z, long prec) @@ -2072,7 +2070,7 @@ cdef extern from "flint/acb_hypgeom.h": void acb_hypgeom_chi_series(acb_poly_t res, const acb_poly_t h, long n, long prec) void acb_hypgeom_li_series(acb_poly_t res, const acb_poly_t h, int offset, long n, long prec) -cdef extern from "flint/arb_hypgeom.h": +cdef extern from "arb_hypgeom.h": void arb_hypgeom_pfq(arb_t res, arb_srcptr a, long p, arb_srcptr b, long q, const arb_t z, int regularized, long prec) void arb_hypgeom_0f1(arb_t res, const arb_t a, const arb_t z, int regularized, long prec) void arb_hypgeom_m(arb_t res, const arb_t a, const arb_t b, const arb_t z, int regularized, long prec) @@ -2137,7 +2135,7 @@ cdef extern from "flint/arb_hypgeom.h": void arb_hypgeom_legendre_p_ui_root(arb_t res, arb_t weight, ulong n, ulong k, long prec) -cdef extern from "flint/dirichlet.h": +cdef extern from "dirichlet.h": ctypedef struct dirichlet_group_struct: ulong q ulong q_even @@ -2196,7 +2194,7 @@ cdef extern from "flint/dirichlet.h": int dirichlet_char_is_primitive(const dirichlet_group_t G, const dirichlet_char_t chi) ulong dirichlet_chi(const dirichlet_group_t G, const dirichlet_char_t chi, ulong n) -cdef extern from "flint/acb_dirichlet.h": +cdef extern from "acb_dirichlet.h": void acb_dirichlet_eta(acb_t res, const acb_t s, long prec) void acb_dirichlet_chi(acb_t res, const dirichlet_group_t G, const dirichlet_char_t chi, ulong n, long prec) @@ -2213,7 +2211,7 @@ cdef extern from "flint/acb_dirichlet.h": void acb_dirichlet_zeta_zero(acb_t res, const fmpz_t n, long prec) void acb_dirichlet_zeta_zeros(acb_ptr res, const fmpz_t n, long len, long prec) -cdef extern from "flint/acb_elliptic.h": +cdef extern from "acb_elliptic.h": void acb_elliptic_rf(acb_t res, const acb_t x, const acb_t y, const acb_t z, int flags, long prec) void acb_elliptic_rj(acb_t res, const acb_t x, const acb_t y, const acb_t z, const acb_t p, int flags, long prec) void acb_elliptic_rg(acb_t res, const acb_t x, const acb_t y, const acb_t z, int flags, long prec) @@ -2228,7 +2226,7 @@ cdef extern from "flint/acb_elliptic.h": void acb_elliptic_invariants(acb_t g2, acb_t g3, const acb_t tau, long prec) void acb_elliptic_inv_p(acb_t res, const acb_t z, const acb_t tau, long prec) -cdef extern from "flint/acb_calc.h": +cdef extern from "acb_calc.h": ctypedef int (*acb_calc_func_t)(acb_ptr out, const acb_t inp, void * param, long order, long prec) ctypedef struct acb_calc_integrate_opt_struct: @@ -2248,14 +2246,14 @@ cdef extern from "flint/acb_calc.h": const acb_calc_integrate_opt_t options, long prec) -cdef extern from "flint/arb_fmpz_poly.h": +cdef extern from "arb_fmpz_poly.h": void arb_fmpz_poly_evaluate_arb(arb_t res, const fmpz_poly_t poly, const arb_t x, long prec) void arb_fmpz_poly_evaluate_acb(acb_t res, const fmpz_poly_t poly, const acb_t x, long prec) void arb_fmpz_poly_complex_roots(acb_ptr roots, const fmpz_poly_t poly, int flags, long prec) ulong arb_fmpz_poly_deflation(const fmpz_poly_t poly) void arb_fmpz_poly_deflate(fmpz_poly_t res, const fmpz_poly_t poly, ulong deflation) -cdef extern from "flint/acb_dft.h": +cdef extern from "acb_dft.h": void acb_dft(acb_ptr w, acb_srcptr v, long n, long prec) void acb_dft_inverse(acb_ptr w, acb_srcptr v, long n, long prec) @@ -2397,8 +2395,6 @@ cdef extern from "flint/fmpz_mpoly.h": void fmpz_mpoly_get_term_monomial(fmpz_mpoly_t M, const fmpz_mpoly_t A, slong i, const fmpz_mpoly_ctx_t ctx) - void fmpz_mpoly_sort_terms(fmpz_mpoly_t A, const fmpz_mpoly_ctx_t ctx) - # Addition/Subtraction void fmpz_mpoly_add_fmpz(fmpz_mpoly_t A, const fmpz_mpoly_t B, const fmpz_t c, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_add_si(fmpz_mpoly_t A, const fmpz_mpoly_t B, slong c, const fmpz_mpoly_ctx_t ctx) diff --git a/src/flint/fmpz_mpoly.pyx b/src/flint/fmpz_mpoly.pyx index e793a670..f2f1ee97 100644 --- a/src/flint/fmpz_mpoly.pyx +++ b/src/flint/fmpz_mpoly.pyx @@ -198,7 +198,7 @@ cdef class fmpz_mpoly(flint_mpoly): fmpz_mpoly_init(self.val, self.ctx.val) self._init = True fmpz_mpoly_set_str_pretty(self.val, val, self.ctx.c_names, self.ctx.val) - fmpz_mpoly_sort_terms(self.val, self.ctx.val) +# fmpz_mpoly_sort_terms(self.val, self.ctx.val) else: v = any_as_fmpz(val) if v is NotImplemented: From 7176fe725d51da4c18d4eba63a476e61b3065d06 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Fri, 18 Aug 2023 08:41:09 -0400 Subject: [PATCH 07/21] add prototype for fmpz_mpoly_sort_terms. --- src/flint/_flint.pxd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/flint/_flint.pxd b/src/flint/_flint.pxd index 166e14a6..537c77e4 100644 --- a/src/flint/_flint.pxd +++ b/src/flint/_flint.pxd @@ -2395,6 +2395,8 @@ cdef extern from "flint/fmpz_mpoly.h": void fmpz_mpoly_get_term_monomial(fmpz_mpoly_t M, const fmpz_mpoly_t A, slong i, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_sort_terms(fmpz_mpoly_t A, const fmpz_mpoly_ctx_t ctx) + # Addition/Subtraction void fmpz_mpoly_add_fmpz(fmpz_mpoly_t A, const fmpz_mpoly_t B, const fmpz_t c, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_add_si(fmpz_mpoly_t A, const fmpz_mpoly_t B, slong c, const fmpz_mpoly_ctx_t ctx) From 3dbc6aed75bbe4cf48f7db93ab011ba7d3378a3b Mon Sep 17 00:00:00 2001 From: David Einstein Date: Fri, 18 Aug 2023 08:43:08 -0400 Subject: [PATCH 08/21] Moved generic pieces of fmpz_mpoly_context to base class. --- src/flint/fmpz_mpoly.pyx | 36 +++--------------------------------- src/flint/pyflint.pyx | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/flint/fmpz_mpoly.pyx b/src/flint/fmpz_mpoly.pyx index f2f1ee97..0755a756 100644 --- a/src/flint/fmpz_mpoly.pyx +++ b/src/flint/fmpz_mpoly.pyx @@ -40,7 +40,7 @@ cdef fmpz_poly_set_list(fmpz_poly_t poly, list val): cdef dict _fmpz_mpoly_ctx_cache = {} @cython.auto_pickle(False) -cdef class fmpz_mpoly_ctx: +cdef class fmpz_mpoly_ctx(flint_mpoly_context): """ A class for storing the polynomial context @@ -51,16 +51,8 @@ cdef class fmpz_mpoly_ctx: Do not construct one of these directly, use `get_fmpz_mpoly_context`. """ cdef fmpz_mpoly_ctx_t val - cdef public object py_names - cdef char ** c_names - cdef bint _init - - def __cinit__(self): - self._init = False def __init__(self, slong nvars, ordering, names): - assert nvars >= 1 - assert len(names) == nvars if ordering == "lex": fmpz_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_LEX) elif ordering == "deglex": @@ -69,16 +61,8 @@ cdef class fmpz_mpoly_ctx: fmpz_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_DEGREVLEX) else: raise ValueError("Unimplemented term order %s" % ordering) - self.py_names = tuple(bytes(name, 'utf-8') for name in names) - self.c_names = libc.stdlib.malloc(nvars * sizeof(char *)) - self._init = True - for i in range(nvars): - self.c_names[i] = self.py_names[i] - def __dealloc__(self): - if self._init: - libc.stdlib.free(self.c_names) - self._init = False + super().__init__(nvars, names) cpdef slong nvars(self): return self.val.minfo.nvars @@ -91,10 +75,6 @@ cdef class fmpz_mpoly_ctx: if self.val.minfo.ord == ordering_t.ORD_DEGREVLEX: return "degrevlex" - cpdef name(self, slong i): - assert i >= 0 and i < self.val.minfo.nvars - return self.py_names[i].decode('utf-8') - cpdef gen(self, slong i): cdef fmpz_mpoly res assert i >= 0 and i < self.val.minfo.nvars @@ -105,9 +85,6 @@ cdef class fmpz_mpoly_ctx: fmpz_mpoly_gen(res.val, i, res.ctx.val) return res - def gens(self): - return tuple(self.gen(i) for i in range(self.nvars())) - def get_fmpz_mpoly_context(slong nvars=1, ordering="lex", names='x'): if nvars <= 0: nvars = 1 @@ -198,7 +175,7 @@ cdef class fmpz_mpoly(flint_mpoly): fmpz_mpoly_init(self.val, self.ctx.val) self._init = True fmpz_mpoly_set_str_pretty(self.val, val, self.ctx.c_names, self.ctx.val) -# fmpz_mpoly_sort_terms(self.val, self.ctx.val) + fmpz_mpoly_sort_terms(self.val, self.ctx.val) else: v = any_as_fmpz(val) if v is NotImplemented: @@ -241,10 +218,6 @@ cdef class fmpz_mpoly(flint_mpoly): def __len__(self): return fmpz_mpoly_length(self.val, self.ctx.val) - def __hash__(self): - s = str(self) - return hash(s) - def coefficient(self, slong i): cdef fmpz v if i < 0 or i >= fmpz_mpoly_length(self.val, self.ctx.val): @@ -254,9 +227,6 @@ cdef class fmpz_mpoly(flint_mpoly): fmpz_mpoly_get_term_coeff_fmpz(v.val, self.val, i, self.ctx.val) return v - def leading_coefficient(self): - return self.coefficient(0) - def exponent_tuple(self, slong i): cdef slong j, nvars cdef fmpz_struct ** tmp diff --git a/src/flint/pyflint.pyx b/src/flint/pyflint.pyx index 63af457c..efc6261f 100644 --- a/src/flint/pyflint.pyx +++ b/src/flint/pyflint.pyx @@ -219,11 +219,51 @@ cdef class flint_poly(flint_elem): """ return acb_poly(self).roots(**kwargs) +cdef class flint_mpoly_context(flint_elem): + """ + Base class for sparse multivariate ring contexts. + """ + cdef public object py_names + cdef char ** c_names + cdef bint _init + + def __cinit__(self): + self._init = False + + def __init__(self, slong nvars, names): + assert nvars >= 1 + assert len(names) == nvars + self.py_names = tuple(bytes(name, 'utf-8') for name in names) + self.c_names = libc.stdlib.malloc(nvars * sizeof(char *)) + self._init = True + for i in range(nvars): + self.c_names[i] = self.py_names[i] + + def __dealloc__(self): + if self._init: + libc.stdlib.free(self.c_names) + self._init = False + + cpdef name(self, slong i): + assert i >= 0 and i < len(self.py_names) + return self.py_names[i].decode('utf-8') + + def gens(self): + return tuple(self.gen(i) for i in range(self.nvars())) + + cdef class flint_mpoly(flint_elem): """ Base class for multivariate polynomials. """ + def leading_coefficient(self): + return self.coefficient(0) + + def __hash__(self): + s = repr(self) + return hash(s) + cdef class flint_mat(flint_elem): """ From dc7be110baa6494339772d9e1ea59d17a34f6761 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Sat, 19 Aug 2023 15:54:17 -0400 Subject: [PATCH 09/21] doctests for fmpz_mpoly_context object --- src/flint/fmpz_mpoly.pyx | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/flint/fmpz_mpoly.pyx b/src/flint/fmpz_mpoly.pyx index 0755a756..0e92b02d 100644 --- a/src/flint/fmpz_mpoly.pyx +++ b/src/flint/fmpz_mpoly.pyx @@ -65,9 +65,23 @@ cdef class fmpz_mpoly_ctx(flint_mpoly_context): super().__init__(nvars, names) cpdef slong nvars(self): + """ + Return the number of variables in the context + + >>> ctx = get_fmpz_mpoly_context(4, "lex", 'x') + >>> ctx.nvars() + 4 + """ return self.val.minfo.nvars cpdef ordering(self): + """ + Return the term order of the context object. + + >>> ctx = get_fmpz_mpoly_context(4, "deglex", 'w') + >>> ctx.ordering() + 'deglex' + """ if self.val.minfo.ord == ordering_t.ORD_LEX: return "lex" if self.val.minfo.ord == ordering_t.ORD_DEGLEX: @@ -76,6 +90,13 @@ cdef class fmpz_mpoly_ctx(flint_mpoly_context): return "degrevlex" cpdef gen(self, slong i): + """ + Return the `i`'th generator of the polynomial ring + + >>> ctx = get_fmpz_mpoly_context(3, 'degrevlex', 'z') + >>> ctx.gen(1) + z1 + """ cdef fmpz_mpoly res assert i >= 0 and i < self.val.minfo.nvars res = fmpz_mpoly.__new__(fmpz_mpoly) @@ -85,6 +106,16 @@ cdef class fmpz_mpoly_ctx(flint_mpoly_context): fmpz_mpoly_gen(res.val, i, res.ctx.val) return res + # cpdef from_dict(self, d): + # cdef fmpz_mpoly res + # res = fmpz_mpoly.__new__(fmpz_mpoly) + # res.ctx = self + # fmpz_mpoly_init(res.val, res.ctx.val) + # res._init = True + # for k, v in d.items(): + + + def get_fmpz_mpoly_context(slong nvars=1, ordering="lex", names='x'): if nvars <= 0: nvars = 1 From 843b9f34f281ede855ad093ad806b2af6b798739 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Wed, 23 Aug 2023 17:37:46 -0400 Subject: [PATCH 10/21] Added ability to construct an fmpz_mpoly from a dictionary. Also added tests, and a few __iop__ methods to fmpz_mpoly --- src/flint/_flint.pxd | 6 +- src/flint/fmpz_mpoly.pyx | 123 +++++++++++++++++++++++++++++++++++---- src/flint/test/test.py | 17 ++++++ 3 files changed, 133 insertions(+), 13 deletions(-) diff --git a/src/flint/_flint.pxd b/src/flint/_flint.pxd index 537c77e4..92cbaa3c 100644 --- a/src/flint/_flint.pxd +++ b/src/flint/_flint.pxd @@ -2276,7 +2276,7 @@ cdef extern from "flint/mpoly.h": void mpoly_ctx_init(mpoly_ctx_t ctx, slong nvars, const ordering_t ord) void mpoly_ctx_clear(mpoly_ctx_t mctx) - + flint_bitcnt_t mpoly_exp_bits_required_ffmpz(const fmpz_struct *user_exp, const mpoly_ctx_t mctx) cdef extern from "flint/fmpz_mpoly.h": ctypedef struct fmpz_mpoly_ctx_struct: @@ -2394,7 +2394,9 @@ cdef extern from "flint/fmpz_mpoly.h": void fmpz_mpoly_get_term_monomial(fmpz_mpoly_t M, const fmpz_mpoly_t A, slong i, const fmpz_mpoly_ctx_t ctx) - + void fmpz_mpoly_push_term_fmpz_fmpz(fmpz_mpoly_t A, const fmpz_t c, fmpz_struct *const *exp, const fmpz_mpoly_ctx_t ctx) + void _fmpz_mpoly_push_exp_ffmpz(fmpz_mpoly_t A, const fmpz_struct * exp, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_set_term_coeff_fmpz(fmpz_mpoly_t A, slong i, const fmpz_t c, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_sort_terms(fmpz_mpoly_t A, const fmpz_mpoly_ctx_t ctx) # Addition/Subtraction diff --git a/src/flint/fmpz_mpoly.pyx b/src/flint/fmpz_mpoly.pyx index 1a7f3828..89fb9514 100644 --- a/src/flint/fmpz_mpoly.pyx +++ b/src/flint/fmpz_mpoly.pyx @@ -1,4 +1,6 @@ from cpython.version cimport PY_MAJOR_VERSION +from cpython.dict cimport PyDict_Size, PyDict_Check, PyDict_Next +from cpython.tuple cimport PyTuple_Check, PyTuple_GET_SIZE from flint.utils.conversion cimport str_from_chars from flint.utils.typecheck cimport typecheck @@ -96,9 +98,9 @@ cdef class fmpz_mpoly_ctx(flint_mpoly_context): if self.val.minfo.ord == ordering_t.ORD_DEGREVLEX: return "degrevlex" - cpdef gen(self, slong i): + def gen(self, slong i): """ - Return the `i`'th generator of the polynomial ring + Return the `i`th generator of the polynomial ring >>> ctx = get_fmpz_mpoly_context(3, 'degrevlex', 'z') >>> ctx.gen(1) @@ -113,14 +115,60 @@ cdef class fmpz_mpoly_ctx(flint_mpoly_context): fmpz_mpoly_gen(res.val, i, res.ctx.val) return res - # cpdef from_dict(self, d): - # cdef fmpz_mpoly res - # res = fmpz_mpoly.__new__(fmpz_mpoly) - # res.ctx = self - # fmpz_mpoly_init(res.val, res.ctx.val) - # res._init = True - # for k, v in d.items(): - + def from_dict(self, d): + """ + Create a fmpz_mpoly from a dictionary. + """ + cdef long n + cdef fmpz_t coefficient + cdef fmpz_struct *exponents + cdef int xtype + cdef int nvars = self.nvars() + cdef int i,j + cdef int count + cdef fmpz_mpoly res + + if not PyDict_Check(d): + raise ValueError("expected a dictionary") + n = PyDict_Size(d) + fmpz_init(coefficient) + exponents = libc.stdlib.calloc(nvars, sizeof(fmpz_struct)) + if exponents == NULL: + raise MemoryError() + for i in range(nvars): + fmpz_init(exponents + i) + fmpz_init(coefficient) + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx = self + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + count = 0 + for k,v in d.items(): + xtype = fmpz_set_any_ref(coefficient, v) + if xtype == FMPZ_UNKNOWN: + libc.stdlib.free(exponents) + raise TypeError("invalid coefficient type %s" % type(v)) + if not PyTuple_Check(k): + libc.stdlib.free(exponents) + raise TypeError("Expected tuple of ints as key not %s" % type(k)) + if PyTuple_GET_SIZE(k) != nvars: + libc.stdlib.free(exponents) + raise TypeError("Expected exponent tuple of length %d" % nvars) + for i,tup in enumerate(k): + xtype = fmpz_set_any_ref(exponents + i, tup) + if xtype == FMPZ_UNKNOWN: + libc.stdlib.free(exponents) + raise TypeError("Invalid exponent type %s" % type(tup)) + #Todo lobby for fmpz_mpoly_push_term_fmpz_ffmpz + if not fmpz_is_zero(coefficient): + _fmpz_mpoly_push_exp_ffmpz(res.val, exponents, self.val) + fmpz_mpoly_set_term_coeff_fmpz(res.val, count, coefficient, self.val) + count += 1 + for i in range(nvars): + fmpz_clear(exponents + i) + fmpz_clear(coefficient) + fmpz_mpoly_sort_terms(res.val, self.val) + return res def get_fmpz_mpoly_context(slong nvars=1, ordering="lex", names='x'): @@ -205,6 +253,20 @@ cdef class fmpz_mpoly(flint_mpoly): fmpz_mpoly_set(self.val, (val).val, self.ctx.val) else: raise ValueError("Cannot automatically coerce contexts") + elif isinstance(val, dict): + if ctx is None: + if len(val) == 0: + raise ValueError("Need context for zero polynomial") + k = list(val.keys())[0] + if not isinstance(k, tuple): + raise ValueError("Dict should be keyed with tuples of integers") + ctx = get_fmpz_mpoly_context(len(k)) + x = ctx.from_dict(val) + #XXX this copy is silly, have a ctx function that assigns an fmpz_mpoly_t + self.ctx = ctx + fmpz_mpoly_init(self.val, self.ctx.val) + self._init = True + fmpz_mpoly_set(self.val, (x).val, self.ctx.val) elif isinstance(val, str): if ctx is None: raise ValueError("Cannot parse a polynomial without context") @@ -341,6 +403,19 @@ cdef class fmpz_mpoly(flint_mpoly): return res return NotImplemented + def __iadd__(self, other): + if typecheck(other, fmpz_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + fmpz_mpoly_add((self).val, (self).val, (other).val, self.ctx.val) + return self + else: + other = any_as_fmpz(other) + if other is not NotImplemented: + fmpz_mpoly_add_fmpz((self).val, (self).val, (other).val, self.ctx.val) + return self + return NotImplemented + def __sub__(self, other): cdef fmpz_mpoly res if typecheck(other, fmpz_mpoly): @@ -375,6 +450,19 @@ cdef class fmpz_mpoly(flint_mpoly): return -res return NotImplemented + def __isub__(self, other): + if typecheck(other, fmpz_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + fmpz_mpoly_sub((self).val, (self).val, (other).val, self.ctx.val) + return self + else: + other = any_as_fmpz(other) + if other is not NotImplemented: + fmpz_mpoly_sub_fmpz((self).val, (self).val, (other).val, self.ctx.val) + return self + return NotImplemented + def __mul__(self, other): cdef fmpz_mpoly res if typecheck(other, fmpz_mpoly): @@ -409,6 +497,19 @@ cdef class fmpz_mpoly(flint_mpoly): return res return NotImplemented + def __imul__(self, other): + if typecheck(other, fmpz_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + fmpz_mpoly_mul((self).val, (self).val, (other).val, self.ctx.val) + return self + else: + other = any_as_fmpz(other) + if other is not NotImplemented: + fmpz_mpoly_scalar_mul_fmpz(self.val, (self).val, (other).val, self.ctx.val) + return self + return NotImplemented + def __pow__(self, other, modulus): cdef fmpz_mpoly res if modulus is not None: @@ -429,7 +530,7 @@ cdef class fmpz_mpoly(flint_mpoly): def __divmod__(self, other): cdef fmpz_mpoly res, res2 if typecheck(other, fmpz_mpoly): - if (self).ctx is not (other).ctx: + if (self).ctx is not (other).ctx return NotImplemented res = fmpz_mpoly.__new__(fmpz_mpoly) res.ctx = (self).ctx diff --git a/src/flint/test/test.py b/src/flint/test/test.py index f865163b..4f3f1da9 100644 --- a/src/flint/test/test.py +++ b/src/flint/test/test.py @@ -639,6 +639,23 @@ def test_fmpz_mpoly(): ctx = getctx(4, "lex", 'w,x,y,z') p1 = ctx.gen(0) + ctx.gen(1) - ctx.gen(2) * ctx.gen(3) assert p1 == Zp("w + x - y * z", ctx) + ctx = getctx(2, "lex", "x,y") + assert ctx.from_dict({(1,0):1, (0,1):2}) == Zp("x + 2*y", ctx) + assert raises(lambda: ctx.from_dict("b"), ValueError) + assert raises(lambda: ctx.from_dict({(1,2):"b"}), TypeError) + assert raises(lambda: ctx.from_dict({"b":1}), TypeError) + assert raises(lambda: ctx.from_dict({(1,2,3):1}), TypeError) + assert raises(lambda: ctx.from_dict({(1,"a"):1}), TypeError) + ctx = getctx(2, "lex", 'x,y') + p1 = ctx.from_dict({(1,0):4,(0,3):4,(2,4):9}) + for ztype in [int, long, flint.fmpz]: + assert p1 + ztype(3) == ctx.from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):3}) + assert ztype(3) + p1 == ctx.from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):3}) + assert p1 - ztype(3) == ctx.from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):-3}) + assert ztype(3) - p1 == ctx.from_dict({(1,0):-4,(0,3):-4,(2,4):-9,(0,0):3}) + assert p1 * ztype(3) == ctx.from_dict({(1,0):12,(0,3):12,(2,4):27}) + assert ztype(3) * p1 == ctx.from_dict({(1,0):12,(0,3):12,(2,4):27}) + assert p1 // ztype(3) == ctx.from_dict({(1,0):1,(0.3):1,(2,4):3}) def test_fmpz_series(): From f346904a40ac0f719de604ebaf1afea2a3bbdc50 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Fri, 25 Aug 2023 11:12:37 -0400 Subject: [PATCH 11/21] Added create_fmpz_mpoly to remove blocks of redundant code. --- src/flint/fmpz_mpoly.pyx | 165 +++++++++++++++++++++------------------ src/flint/test/test.py | 30 +++---- 2 files changed, 106 insertions(+), 89 deletions(-) diff --git a/src/flint/fmpz_mpoly.pyx b/src/flint/fmpz_mpoly.pyx index 89fb9514..440bf194 100644 --- a/src/flint/fmpz_mpoly.pyx +++ b/src/flint/fmpz_mpoly.pyx @@ -115,9 +115,28 @@ cdef class fmpz_mpoly_ctx(flint_mpoly_context): fmpz_mpoly_gen(res.val, i, res.ctx.val) return res - def from_dict(self, d): + def constant(self, z): + cdef fmpz_mpoly res + z = any_as_fmpz(z) + if z is NotImplemented: + raise ValueError() + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx = self + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + fmpz_mpoly_set_fmpz(res.val, (z).val, res.ctx.val) + return res + + def fmpz_mpoly_from_dict(self, d): """ Create a fmpz_mpoly from a dictionary. + + The dictionary's keys are tuples of ints (or anything that implicitly converts + to fmpz) representing exponents, and corresponding values of fmpz. + + >>> ctx = get_fmpz_mpoly_context(2,'lex','x,y') + >>> ctx.fmpz_mpoly_from_dict({(1,0):2, (1,1):3, (0,1):1}) + 3*x*y + 2*x + y """ cdef long n cdef fmpz_t coefficient @@ -224,6 +243,19 @@ def coerce_fmpz_mpolys(*args): _fmpz_mpoly_set2(( args2[i]).val, ctx.val, ( args[i]).val, ( args[i]).ctx.val) return ctx, args2 +cdef inline init_fmpz_mpoly(fmpz_mpoly var, fmpz_mpoly_ctx ctx): + var.ctx = ctx + fmpz_mpoly_init(var.val, ctx.val) + var._init = True + +cdef inline create_fmpz_mpoly(fmpz_mpoly_ctx ctx): + cdef fmpz_mpoly var + var = fmpz_mpoly.__new__(fmpz_mpoly) + var.ctx = ctx + fmpz_mpoly_init(var.val, ctx.val) + var._init = True + return var + # todo: store cached context objects externally cdef class fmpz_mpoly(flint_mpoly): @@ -247,9 +279,7 @@ cdef class fmpz_mpoly(flint_mpoly): def __init__(self, val=0, ctx=None): if typecheck(val, fmpz_mpoly): if ctx is None or ctx == (val).ctx: - self.ctx = (val).ctx - fmpz_mpoly_init(self.val, self.ctx.val) - self._init = True + init_fmpz_mpoly(self, (val).ctx) fmpz_mpoly_set(self.val, (val).val, self.ctx.val) else: raise ValueError("Cannot automatically coerce contexts") @@ -261,19 +291,15 @@ cdef class fmpz_mpoly(flint_mpoly): if not isinstance(k, tuple): raise ValueError("Dict should be keyed with tuples of integers") ctx = get_fmpz_mpoly_context(len(k)) - x = ctx.from_dict(val) + x = ctx.fmpz_mpoly_from_dict(val) #XXX this copy is silly, have a ctx function that assigns an fmpz_mpoly_t - self.ctx = ctx - fmpz_mpoly_init(self.val, self.ctx.val) - self._init = True + init_fmpz_mpoly(self, ctx) fmpz_mpoly_set(self.val, (x).val, self.ctx.val) elif isinstance(val, str): if ctx is None: raise ValueError("Cannot parse a polynomial without context") val = bytes(val, 'utf-8') - self.ctx = ctx - fmpz_mpoly_init(self.val, self.ctx.val) - self._init = True + init_fmpz_mpoly(self, ctx) fmpz_mpoly_set_str_pretty(self.val, val, self.ctx.c_names, self.ctx.val) fmpz_mpoly_sort_terms(self.val, self.ctx.val) else: @@ -282,9 +308,7 @@ cdef class fmpz_mpoly(flint_mpoly): raise TypeError("cannot create fmpz_mpoly from type %s" % type(val)) if ctx is None: raise ValueError("Need context to convert fmpz to fmpz_mpoly") - self.ctx = ctx - fmpz_mpoly_init(self.val, self.ctx.val) - self._init = True + init_fmpz_mpoly(self, ctx) fmpz_mpoly_set_fmpz(self.val, (v).val, self.ctx.val) def __nonzero__(self): @@ -362,10 +386,7 @@ cdef class fmpz_mpoly(flint_mpoly): def __neg__(self): cdef fmpz_mpoly res - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_neg(res.val, (self).val, res.ctx.val) return res @@ -374,19 +395,13 @@ cdef class fmpz_mpoly(flint_mpoly): if typecheck(other, fmpz_mpoly): if (self).ctx is not (other).ctx: return NotImplemented - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx =(self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_add(res.val, (self).val, (other).val, res.ctx.val) return res else: other = any_as_fmpz(other) if other is not NotImplemented: - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_add_fmpz(res.val, (self).val, (other).val, res.ctx.val) return res return NotImplemented @@ -395,10 +410,7 @@ cdef class fmpz_mpoly(flint_mpoly): cdef fmpz_mpoly res other = any_as_fmpz(other) if other is not NotImplemented: - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_add_fmpz(res.val, (self).val, (other).val, res.ctx.val) return res return NotImplemented @@ -421,19 +433,13 @@ cdef class fmpz_mpoly(flint_mpoly): if typecheck(other, fmpz_mpoly): if (self).ctx is not (other).ctx: return NotImplemented - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx =(self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_sub(res.val, (self).val, (other).val, res.ctx.val) return res else: other = any_as_fmpz(other) if other is not NotImplemented: - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_sub_fmpz(res.val, (self).val, (other).val, res.ctx.val) return res return NotImplemented @@ -442,10 +448,7 @@ cdef class fmpz_mpoly(flint_mpoly): cdef fmpz_mpoly res other = any_as_fmpz(other) if other is not NotImplemented: - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_sub_fmpz(res.val, (self).val, (other).val, res.ctx.val) return -res return NotImplemented @@ -468,19 +471,13 @@ cdef class fmpz_mpoly(flint_mpoly): if typecheck(other, fmpz_mpoly): if (self).ctx is not (other).ctx: return NotImplemented - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx =(self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_mul(res.val, (self).val, (other).val, res.ctx.val) return res else: other = any_as_fmpz(other) if other is not NotImplemented: - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_scalar_mul_fmpz(res.val, (self).val, (other).val, res.ctx.val) return res return NotImplemented @@ -489,10 +486,7 @@ cdef class fmpz_mpoly(flint_mpoly): cdef fmpz_mpoly res other = any_as_fmpz(other) if other is not NotImplemented: - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_scalar_mul_fmpz(res.val, (self).val, (other).val, res.ctx.val) return res return NotImplemented @@ -519,10 +513,7 @@ cdef class fmpz_mpoly(flint_mpoly): return other if other < 0: raise ValueError("cannot raise fmpz_mpoly to negative power") - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) if fmpz_mpoly_pow_fmpz(res.val, (self).val, (other).val, res.ctx.val) == 0: raise ValueError("unreasonably large polynomial") return res @@ -530,18 +521,31 @@ cdef class fmpz_mpoly(flint_mpoly): def __divmod__(self, other): cdef fmpz_mpoly res, res2 if typecheck(other, fmpz_mpoly): - if (self).ctx is not (other).ctx + if (self).ctx is not (other).ctx: return NotImplemented - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True - res2 = fmpz_mpoly.__new__(fmpz_mpoly) - res2.ctx = (self).ctx - fmpz_mpoly_init(res2.val, res2.ctx.val) - res2._init = True + res = create_fmpz_mpoly(self.ctx) + res2 = create_fmpz_mpoly(self.ctx) fmpz_mpoly_divrem(res.val, res2.val, (self).val, (other).val, res.ctx.val) return (res, res2) + else: + other = any_as_fmpz(other) + if other is not NotImplemented: + other= fmpz_mpoly(other, self.ctx) + res = create_fmpz_mpoly(self.ctx) + res2 = create_fmpz_mpoly(self.ctx) + fmpz_mpoly_divrem(res.val, res2.val, (self).val, (other).val, res.ctx.val) + return (res, res2) + return NotImplemented + + def __rdivmod__(self, other): + cdef fmpz_mpoly res, res2 + other = any_as_fmpz(other) + if other is not NotImplemented: + other = fmpz_mpoly(other, self.ctx) + res = create_fmpz_mpoly(self.ctx) + res2 = create_fmpz_mpoly(self.ctx) + fmpz_mpoly_divrem(res.val, res2.val, (other).val, (self).val, res.ctx.val) + return res return NotImplemented def __floordiv__(self, other): @@ -549,12 +553,26 @@ cdef class fmpz_mpoly(flint_mpoly): if typecheck(other, fmpz_mpoly): if (self).ctx is not (other).ctx: return NotImplemented - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_div(res.val, (self).val, (other).val, res.ctx.val) return res + else: + other = any_as_fmpz(other) + if other is not NotImplemented: + other = fmpz_mpoly(other, self.ctx) + res = create_fmpz_mpoly(self.ctx) + fmpz_mpoly_div(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + + def __rfloordiv__(self,other): + cdef fmpz_mpoly res + other = any_as_fmpz(other) + if other is not NotImplemented: + other = fmpz_mpoly(other, self.ctx) + res = create_fmpz_mpoly(self.ctx) + fmpz_mpoly_div(res.val, (other).val, self.val, res.ctx.val) + return res return NotImplemented def __mod__(self, other): @@ -565,10 +583,7 @@ cdef class fmpz_mpoly(flint_mpoly): assert isinstance(other, fmpz_mpoly) if (self).ctx is not (other).ctx: return NotImplemented - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_gcd(res.val, (self).val, (other).val, res.ctx.val) return res diff --git a/src/flint/test/test.py b/src/flint/test/test.py index 4f3f1da9..6ab31df6 100644 --- a/src/flint/test/test.py +++ b/src/flint/test/test.py @@ -640,22 +640,24 @@ def test_fmpz_mpoly(): p1 = ctx.gen(0) + ctx.gen(1) - ctx.gen(2) * ctx.gen(3) assert p1 == Zp("w + x - y * z", ctx) ctx = getctx(2, "lex", "x,y") - assert ctx.from_dict({(1,0):1, (0,1):2}) == Zp("x + 2*y", ctx) - assert raises(lambda: ctx.from_dict("b"), ValueError) - assert raises(lambda: ctx.from_dict({(1,2):"b"}), TypeError) - assert raises(lambda: ctx.from_dict({"b":1}), TypeError) - assert raises(lambda: ctx.from_dict({(1,2,3):1}), TypeError) - assert raises(lambda: ctx.from_dict({(1,"a"):1}), TypeError) + assert ctx.fmpz_mpoly_from_dict({(1,0):1, (0,1):2}) == Zp("x + 2*y", ctx) + assert raises(lambda: ctx.fmpz_mpoly_from_dict("b"), ValueError) + assert raises(lambda: ctx.fmpz_mpoly_from_dict({(1,2):"b"}), TypeError) + assert raises(lambda: ctx.fmpz_mpoly_from_dict({"b":1}), TypeError) + assert raises(lambda: ctx.fmpz_mpoly_from_dict({(1,2,3):1}), TypeError) + assert raises(lambda: ctx.fmpz_mpoly_from_dict({(1,"a"):1}), TypeError) ctx = getctx(2, "lex", 'x,y') - p1 = ctx.from_dict({(1,0):4,(0,3):4,(2,4):9}) + p1 = ctx.fmpz_mpoly_from_dict({(1,0):4,(0,3):4,(2,4):9}) for ztype in [int, long, flint.fmpz]: - assert p1 + ztype(3) == ctx.from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):3}) - assert ztype(3) + p1 == ctx.from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):3}) - assert p1 - ztype(3) == ctx.from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):-3}) - assert ztype(3) - p1 == ctx.from_dict({(1,0):-4,(0,3):-4,(2,4):-9,(0,0):3}) - assert p1 * ztype(3) == ctx.from_dict({(1,0):12,(0,3):12,(2,4):27}) - assert ztype(3) * p1 == ctx.from_dict({(1,0):12,(0,3):12,(2,4):27}) - assert p1 // ztype(3) == ctx.from_dict({(1,0):1,(0.3):1,(2,4):3}) + assert p1 + ztype(3) == ctx.fmpz_mpoly_from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):3}) + assert ztype(3) + p1 == ctx.fmpz_mpoly_from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):3}) + assert p1 - ztype(3) == ctx.fmpz_mpoly_from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):-3}) + assert ztype(3) - p1 == ctx.fmpz_mpoly_from_dict({(1,0):-4,(0,3):-4,(2,4):-9,(0,0):3}) + assert p1 * ztype(3) == ctx.fmpz_mpoly_from_dict({(1,0):12,(0,3):12,(2,4):27}) + assert ztype(3) * p1 == ctx.fmpz_mpoly_from_dict({(1,0):12,(0,3):12,(2,4):27}) + assert p1 // ztype(3) == ctx.fmpz_mpoly_from_dict({(1,0):1,(0,3):1,(2,4):3}) + assert ztype(3) // p1 == Zp(0,ctx) + assert ctx.constant(7) + ztype(3) == Zp(10, ctx) def test_fmpz_series(): From 3407bce747ad4e9b4ed294618009abee0c4304f6 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Mon, 28 Aug 2023 17:36:16 -0400 Subject: [PATCH 12/21] Initial steps towards fmpz_mpoly. Yes, this does not compile. I need to go off on another branch to experiment with solutions. --- src/flint/_flint.pxd | 157 +++++++++ src/flint/flint_base/flint_base.pyx | 6 + src/flint/fmpq_mpoly.pyx | 511 ++++++++++++++++++++++++++++ src/flint/fmpz_mpoly.pyx | 167 ++++----- src/flint/pyflint.pxd | 6 + src/flint/pyflint.pyx | 1 + src/flint/test/test.py | 34 ++ 7 files changed, 800 insertions(+), 82 deletions(-) create mode 100644 src/flint/fmpq_mpoly.pyx diff --git a/src/flint/_flint.pxd b/src/flint/_flint.pxd index 92cbaa3c..9384813c 100644 --- a/src/flint/_flint.pxd +++ b/src/flint/_flint.pxd @@ -2447,6 +2447,163 @@ cdef extern from "flint/fmpz_mpoly.h": void fmpz_mpoly_term_content(fmpz_mpoly_t M, const fmpz_mpoly_t A, const fmpz_mpoly_ctx_t ctx) int fmpz_mpoly_gcd(fmpz_mpoly_t G, const fmpz_mpoly_t A, const fmpz_mpoly_t B, const fmpz_mpoly_ctx_t ctx) +cdef extern from "flint/fmpq_mpoly.h": + ctypedef struct fmpq_mpoly_ctx_struct: + fmpz_mpoly_ctx_t zctx; + + ctypedef fmpq_mpoly_ctx_struct fmpq_mpoly_ctx_t[1] + + ctypedef struct fmpq_mpoly_struct: + fmpq_t content + fmpz_mpoly_t zpoly + + ctypedef fmpq_mpoly_struct fmpq_mpoly_t[1] + + void fmpq_mpoly_ctx_init(fmpq_mpoly_ctx_t ctx, slong nvars, const ordering_t ord) + slong fmpq_mpoly_ctx_nvars(const fmpq_mpoly_ctx_t ctx) + ordering_t fmpq_mpoly_ctx_ord(const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_ctx_clear(fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_init(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_init2(fmpq_mpoly_t A, slong alloc, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_init3(fmpq_mpoly_t A, slong alloc, flint_bitcnt_t bits, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_fit_length(fmpq_mpoly_t A, slong len, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_fit_bits(fmpq_mpoly_t A, flint_bitcnt_t bits, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_realloc(fmpq_mpoly_t A, slong alloc, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_clear(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + char * fmpq_mpoly_get_str_pretty(const fmpq_mpoly_t A, const char ** x, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_fprint_pretty(FILE * file, const fmpq_mpoly_t A, const char ** x, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_print_pretty(const fmpq_mpoly_t A, const char ** x, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_set_str_pretty(fmpq_mpoly_t A, const char * str, const char ** x, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_gen(fmpq_mpoly_t A, slong var, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_is_gen(const fmpq_mpoly_t A, slong var, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_equal(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_swap(fmpq_mpoly_t A, fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_is_fmpq(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_fmpq(fmpq_t c, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_fmpq(fmpq_mpoly_t A, const fmpq_t c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_fmpz(fmpq_mpoly_t A, const fmpz_t c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_ui(fmpq_mpoly_t A, ulong c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_si(fmpq_mpoly_t A, slong c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_zero(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_one(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_equal_fmpq(const fmpq_mpoly_t A, fmpq_t c, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_equal_fmpz(const fmpq_mpoly_t A, fmpz_t c, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_equal_ui(const fmpq_mpoly_t A, ulong c, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_equal_si(const fmpq_mpoly_t A, slong c, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_is_zero(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_is_one(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_degrees_fit_si(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_degrees_fmpz(fmpz_t ** degs, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_degrees_si(slong * degs, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_degree_fmpz(fmpz_t deg, const fmpq_mpoly_t A, slong var, const fmpq_mpoly_ctx_t ctx) + slong fmpq_mpoly_degree_si(const fmpq_mpoly_t A, slong var, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_total_degree_fits_si(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_total_degree_fmpz(fmpz_t tdeg, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + slong fmpq_mpoly_total_degree_si(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_used_vars(int * used, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_denominator(fmpz_t d, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_coeff_fmpq_monomial(fmpq_t c, const fmpq_mpoly_t A, const fmpq_mpoly_t M, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_coeff_fmpq_monomial(fmpq_mpoly_t A, const fmpq_t c, const fmpq_mpoly_t M, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_get_coeff_fmpq_fmpz(fmpq_t c, const fmpq_mpoly_t A, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_get_coeff_fmpq_ui(fmpq_t c, const fmpq_mpoly_t A, ulong const * exp, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_set_coeff_fmpq_fmpz(fmpq_mpoly_t A, const fmpq_t c, fmpz_t * const * exp, fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_set_coeff_fmpq_ui(fmpq_mpoly_t A, const fmpq_t c, ulong const * exp, fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_get_coeff_vars_ui(fmpq_mpoly_t C, const fmpq_mpoly_t A, const slong * vars, const ulong * exps, slong length, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_cmp(const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + # fmpq * fmpq_mpoly_content_ref(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + # fmpz_mpoly_struct * fmpq_mpoly_zpoly_ref(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + # fmpz_t * fmpq_mpoly_zpoly_term_coeff_ref(fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_is_canonical(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + slong fmpq_mpoly_length(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_resize(fmpq_mpoly_t A, slong new_length, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_term_coeff_fmpq(fmpq_t c, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_term_coeff_fmpq(fmpq_mpoly_t A, slong i, const fmpq_t c, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_term_exp_fits_si(const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_term_exp_fits_ui(const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_term_exp_fmpz(fmpz_struct ** exps, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_get_term_exp_ui(ulong * exps, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_get_term_exp_si(slong * exps, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + # ulong fmpq_mpoly_get_term_var_exp_ui(const fmpq_mpoly_t A, slong i, slong var, const fmpq_mpoly_ctx_t ctx) + # slong fmpq_mpoly_get_term_var_exp_si(const fmpq_mpoly_t A, slong i, slong var, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_set_term_exp_fmpz(fmpq_mpoly_t A, slong i, fmpz_t * const * exps, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_set_term_exp_ui(fmpq_mpoly_t A, slong i, const ulong * exps, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_get_term(fmpq_mpoly_t M, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_get_term_monomial(fmpq_mpoly_t M, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_fmpq_fmpz(fmpq_mpoly_t A, const fmpq_t c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_push_term_fmpz_fmpz(fmpq_mpoly_t A, const fmpz_t c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_push_term_ui_fmpz(fmpq_mpoly_t A, ulong c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_push_term_si_fmpz(fmpq_mpoly_t A, slong c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_push_term_fmpq_ui(fmpq_mpoly_t A, const fmpq_t c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_push_term_fmpz_ui(fmpq_mpoly_t A, const fmpz_t c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_push_term_ui_ui(fmpq_mpoly_t A, ulong c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_push_term_si_ui(fmpq_mpoly_t A, slong c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_reduce(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_sort_terms(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_combine_like_terms(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_reverse(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_randtest_bound(fmpq_mpoly_t A, flint_rand_t state, slong length, mp_limb_t coeff_bits, ulong exp_bound, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_randtest_bounds(fmpq_mpoly_t A, flint_rand_t state, slong length, mp_limb_t coeff_bits, ulong * exp_bounds, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_randtest_bits(fmpq_mpoly_t A, flint_rand_t state, slong length, mp_limb_t coeff_bits, mp_limb_t exp_bits, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_add_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_t c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_add_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_add_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_add_si(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_sub_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_t c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_sub_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_sub_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_sub_si(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_add(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_t C, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_sub(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_t C, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_neg(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_scalar_mul_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_t c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_scalar_mul_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_scalar_mul_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_scalar_mul_si(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_scalar_div_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_t c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_scalar_div_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_scalar_div_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_scalar_div_si(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong c, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_make_monic(fmpq_mpoly_t A, fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_derivative(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_integral(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_evaluate_all_fmpq(fmpq_t ev, const fmpq_mpoly_t A, fmpq * const * vals, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_evaluate_one_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_t val, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_compose_fmpq_poly(fmpq_poly_t A, const fmpq_mpoly_t B, fmpq_poly_struct * const * C, const fmpq_mpoly_ctx_t ctxB) + # int fmpq_mpoly_compose_fmpq_mpoly(fmpq_mpoly_t A, const fmpq_mpoly_t B, fmpq_mpoly_struct * const * C, const fmpq_mpoly_ctx_t ctxB, const fmpq_mpoly_ctx_t ctxAC) + # void fmpq_mpoly_compose_fmpq_mpoly_gen(fmpq_mpoly_t A, const fmpq_mpoly_t B, const slong * c, const fmpq_mpoly_ctx_t ctxB, const fmpq_mpoly_ctx_t ctxAC) + void fmpq_mpoly_mul(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_t C, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_pow_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t k, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_pow_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong k, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_divides(fmpq_mpoly_t Q, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_div(fmpq_mpoly_t Q, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_divrem(fmpq_mpoly_t Q, fmpq_mpoly_t R, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_divrem_ideal(fmpq_mpoly_struct ** Q, fmpq_mpoly_t R, const fmpq_mpoly_t A, fmpq_mpoly_struct * const * B, slong len, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_content(fmpq_t g, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_term_content(fmpq_mpoly_t M, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_content_vars(fmpq_mpoly_t g, const fmpq_mpoly_t A, slong * vars, slong vars_length, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_gcd(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_gcd_cofactors(fmpq_mpoly_t G, fmpq_mpoly_t Abar, fmpq_mpoly_t Bbar, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_gcd_brown(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_gcd_hensel(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_gcd_subresultant(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_gcd_zippel(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_gcd_zippel2(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_resultant(fmpq_mpoly_t R, const fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_discriminant(fmpq_mpoly_t D, const fmpq_mpoly_t A, slong var, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_sqrt(fmpq_mpoly_t Q, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_is_square(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_univar_init(fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_univar_clear(fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_univar_swap(fmpq_mpoly_univar_t A, fmpq_mpoly_univar_t B, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_to_univar(fmpq_mpoly_univar_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_from_univar(fmpq_mpoly_t A, const fmpq_mpoly_univar_t B, slong var, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_univar_degree_fits_si(const fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) + # slong fmpq_mpoly_univar_length(const fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) + # slong fmpq_mpoly_univar_get_term_exp_si(fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_univar_get_term_coeff(fmpq_mpoly_t c, const fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_univar_swap_term_coeff(fmpq_mpoly_t c, fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) + """ cdef extern from "flint/fmpz_mpoly_factor.h": diff --git a/src/flint/flint_base/flint_base.pyx b/src/flint/flint_base/flint_base.pyx index aff5aed8..c8d773df 100644 --- a/src/flint/flint_base/flint_base.pyx +++ b/src/flint/flint_base/flint_base.pyx @@ -118,6 +118,12 @@ cdef class flint_mpoly(flint_elem): s = repr(self) return hash(s) + def to_dict(self): + d = {} + for i in range(len(self)): + d[self.exponent_tuple(i)] = self.coefficient(i) + return d + cdef class flint_series(flint_elem): """ diff --git a/src/flint/fmpq_mpoly.pyx b/src/flint/fmpq_mpoly.pyx new file mode 100644 index 00000000..cd31e179 --- /dev/null +++ b/src/flint/fmpq_mpoly.pyx @@ -0,0 +1,511 @@ +cdef dict _fmpq_mpoly_ctx_cache = {} + +@cython.auto_pickle(False) +cdef class fmpq_mpoly_ctx(flint_mpoly_context): + """ + A class for storing the polynomial context + + :param nvars: The number of variables in the ring + :param ordering: The term order for the ring + :param names: A tuple containing the names of the variables of the ring. + + Do not construct one of these directly, use `get_fmpq_mpoly_context`. + """ + cdef fmpq_mpoly_ctx_t val + + def __init__(self, slong nvars, ordering, names): + if ordering == "lex": + fmpq_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_LEX) + elif ordering == "deglex": + fmpq_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_DEGLEX) + elif ordering == "degrevlex": + fmpq_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_DEGREVLEX) + else: + raise ValueError("Unimplemented term order %s" % ordering) + + super().__init__(nvars, names) + + cpdef slong nvars(self): + """ + Return the number of variables in the context + + >>> ctx = get_fmpq_mpoly_context(4, "lex", 'x') + >>> ctx.nvars() + 4 + """ + return self.val.zctx.minfo.nvars + + cpdef ordering(self): + """ + Return the term order of the context object. + + >>> ctx = get_fmpq_mpoly_context(4, "deglex", 'w') + >>> ctx.ordering() + 'deglex' + """ + if self.val.zctx.minfo.ord == ordering_t.ORD_LEX: + return "lex" + if self.val.zctx.minfo.ord == ordering_t.ORD_DEGLEX: + return "deglex" + if self.val.zctx.minfo.ord == ordering_t.ORD_DEGREVLEX: + return "degrevlex" + + def gen(self, slong i): + """ + Return the `i`th generator of the polynomial ring + + >>> ctx = get_fmpq_mpoly_context(3, 'degrevlex', 'z') + >>> ctx.gen(1) + z1 + """ + cdef fmpq_mpoly res + assert i >= 0 and i < self.val.zctx.minfo.nvars + res = fmpq_mpoly.__new__(fmpq_mpoly) + res.ctx = self + fmpq_mpoly_init(res.val, res.ctx.val) + res._init = True + fmpq_mpoly_gen(res.val, i, res.ctx.val) + return res + + def constant(self, z): + """ + Create a constant polynomial in this context + """ + cdef fmpq_mpoly res + z = any_as_fmpz(z) + if z is NotImplemented: + raise ValueError("A constant fmpq_mpoly is a fmpq") + res = fmpq_mpoly.__new__(fmpq_mpoly) + res.ctx = self + fmpq_mpoly_init(res.val, res.ctx.val) + res._init = True + fmpq_mpoly_set_fmpq(res.val, (z).val, res.ctx.val) + return res + + def fmpq_mpoly_from_dict(self, d): + """ + Create a fmpq_mpoly from a dictionary. + + The dictionary's keys are tuples of ints (or anything that implicitly converts + to fmpz) representing exponents, and corresponding values of fmpq. + + >>> ctx = get_fmpq_mpoly_context(2,'lex','x,y') + >>> ctx.fmpq_mpoly_from_dict({(1,0):2, (1,1):3, (0,1):1}) + 3*x*y + 2*x + y + """ + cdef long n + cdef fmpq_t coefficient + cdef fmpz_struct *exponents + cdef int xtype + cdef int nvars = self.nvars() + cdef int i,j + cdef int count + cdef fmpq_mpoly res + + if not PyDict_Check(d): + raise ValueError("expected a dictionary") + n = PyDict_Size(d) + fmpq_init(coefficient) + exponents = libc.stdlib.calloc(nvars, sizeof(fmpz_struct)) + if exponents == NULL: + raise MemoryError() + for i in range(nvars): + fmpz_init(exponents + i) + fmpq_init(coefficient) + res = fmpq_mpoly.__new__(fmpq_mpoly) + res.ctx = self + fmpq_mpoly_init(res.val, res.ctx.val) + res._init = True + count = 0 + for k,v in d.items(): + coefficient = any_as_fmpq(v) + # xtype = fmpq_set_any_ref(coefficient, v) + # if xtype == FMPZ_UNKNOWN: + # libc.stdlib.free(exponents) + # raise TypeError("invalid coefficient type %s" % type(v)) + if coefficient is NotImplemented: + libc.stdlib.free(exponents) + raise TypeError("invalid coefficient type %s" % type(v)) + if not PyTuple_Check(k): + libc.stdlib.free(exponents) + raise TypeError("Expected tuple of ints as key not %s" % type(k)) + if PyTuple_GET_SIZE(k) != nvars: + libc.stdlib.free(exponents) + raise TypeError("Expected exponent tuple of length %d" % nvars) + for i,tup in enumerate(k): + xtype = fmpz_set_any_ref(exponents + i, tup) + if xtype == FMPZ_UNKNOWN: + libc.stdlib.free(exponents) + raise TypeError("Invalid exponent type %s" % type(tup)) + #Todo lobby for fmpz_mpoly_push_term_fmpz_ffmpz + if not fmpq_is_zero(coefficient): + # fmpq_mpoly_push_term_fmpq_fmpz(res.val, coefficient, exponents, self.val) + _fmpz_mpoly_push_exp_ffmpz(res.val.zpoly, exponents, self.val.zctx) + fmpq_mpoly_set_term_coeff_fmpq(res.val, count, coefficient, self.val) + count += 1 + for i in range(nvars): + fmpz_clear(exponents + i) + fmpq_clear(coefficient) + fmpq_mpoly_sort_terms(res.val, self.val) + return res + + +def get_fmpq_mpoly_context(slong nvars=1, ordering="lex", names='x'): + if nvars <= 0: + nvars = 1 + nametup = tuple(name.strip() for name in names.split(',')) + if len(nametup) != nvars: + if len(nametup) != 1: + raise ValueError("Number of variables does not equal number of names") + nametup = tuple(nametup[0] + str(i) for i in range(nvars)) + key = (nvars, ordering, nametup) + ctx = _fmpq_mpoly_ctx_cache.get(key) + if ctx is None: + ctx = fmpq_mpoly_ctx(nvars, ordering, nametup) + _fmpq_mpoly_ctx_cache[key] = ctx + return ctx + +cdef inline init_fmpq_mpoly(fmpq_mpoly var, fmpq_mpoly_ctx ctx): + var.ctx = ctx + fmpq_mpoly_init(var.val, ctx.val) + var._init = True + +cdef inline create_fmpq_mpoly(fmpq_mpoly_ctx ctx): + cdef fmpq_mpoly var + var = fmpq_mpoly.__new__(fmpq_mpoly) + var.ctx = ctx + fmpq_mpoly_init(var.val, ctx.val) + var._init = True + return var + + + +# todo: store cached context objects externally +cdef class fmpq_mpoly(flint_mpoly): + """ + The *fmpq_poly* type represents sparse multivariate polynomials over + the integers. + """ + + cdef fmpq_mpoly_t val + cdef fmpq_mpoly_ctx ctx + cdef bint _init + + def __cinit__(self): + self._init = False + + def __dealloc__(self): + if self._init: + fmpq_mpoly_clear(self.val, self.ctx.val) + self._init = False + + def __init__(self, val=0, ctx=None): + if typecheck(val, fmpq_mpoly): + if ctx is None or ctx == (val).ctx: + init_fmpq_mpoly(self, (val).ctx) + fmpq_mpoly_set(self.val, (val).val, self.ctx.val) + else: + raise ValueError("Cannot automatically coerce contexts") + elif isinstance(val, dict): + if ctx is None: + if len(val) == 0: + raise ValueError("Need context for zero polynomial") + k = list(val.keys())[0] + if not isinstance(k, tuple): + raise ValueError("Dict should be keyed with tuples of integers") + ctx = get_fmpq_mpoly_context(len(k)) + x = ctx.fmpq_mpoly_from_dict(val) + #XXX this copy is silly, have a ctx function that assigns an fmpq_mpoly_t + init_fmpq_mpoly(self, ctx) + fmpq_mpoly_set(self.val, (x).val, self.ctx.val) + elif isinstance(val, str): + if ctx is None: + raise ValueError("Cannot parse a polynomial without context") + val = bytes(val, 'utf-8') + init_fmpq_mpoly(self, ctx) + fmpq_mpoly_set_str_pretty(self.val, val, self.ctx.c_names, self.ctx.val) + fmpq_mpoly_sort_terms(self.val, self.ctx.val) + else: + v = any_as_fmpq(val) + if v is NotImplemented: + raise TypeError("cannot create fmpq_mpoly from type %s" % type(val)) + if ctx is None: + raise ValueError("Need context to convert fmpq to fmpq_mpoly") + init_fmpq_mpoly(self, ctx) + fmpq_mpoly_set_fmpq(self.val, (v).val, self.ctx.val) + + def __nonzero__(self): + return not fmpq_mpoly_is_zero(self.val, self.ctx.val) + + def __bool__(self): + return not fmpq_mpoly_is_zero(self.val, self.ctx.val) + + def is_one(self): + return fmpq_mpoly_is_one(self.val, self.ctx.val) + + def __richcmp__(self, other, int op): + if op != 2 and op != 3: + return NotImplemented + if typecheck(self, fmpq_mpoly) and typecheck(other, fmpq_mpoly): + if (self).ctx is (other).ctx: + if op == 2: + return bool(fmpq_mpoly_equal((self).val, (other).val, (self).ctx.val)) + else: + return not bool(fmpq_mpoly_equal((self).val, (other).val, (self).ctx.val)) + else: + if op == 2: + return False + else: + return True + if op == 2: + return not bool(self - other) + else: + return bool(self - other) + + def __len__(self): + return fmpq_mpoly_length(self.val, self.ctx.val) + + def coefficient(self, slong i): + cdef fmpq v + if i < 0 or i >= fmpq_mpoly_length(self.val, self.ctx.val): + return fmpq(0) + else: + v = fmpq.__new__(fmpq) + fmpq_mpoly_get_term_coeff_fmpq(v.val, self.val, i, self.ctx.val) + return v + + def exponent_tuple(self, slong i): + cdef slong j, nvars + cdef fmpz_struct ** tmp + if i < 0 or i >= fmpq_mpoly_length(self.val, self.ctx.val): + raise ValueError + nvars = self.ctx.nvars() + res = tuple(fmpz() for j in range(nvars)) + tmp = libc.stdlib.malloc(nvars * sizeof(fmpz_struct *)) + try: + for j in range(nvars): + tmp[j] = &(( (res[j])).val[0]) + fmpq_mpoly_get_term_exp_fmpz(tmp, self.val, i, self.ctx.val) + finally: + libc.stdlib.free(tmp) + return res + + def repr(self): + return self.str() + " (nvars=%s, ordering=%s names=%s)" % (self.ctx.nvars(), self.ctx.ordering(), self.ctx.py_names) + + def str(self): + cdef char * s = fmpq_mpoly_get_str_pretty(self.val, self.ctx.c_names, self.ctx.val) + try: + res = str_from_chars(s) + finally: + libc.stdlib.free(s) + res = res.replace("+", " + ") + res = res.replace("-", " - ") + if res.startswith(" - "): + res = "-" + res[3:] + return res + + return self.repr() + + def __neg__(self): + cdef fmpq_mpoly res + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_neg(res.val, (self).val, res.ctx.val) + return res + + def __add__(self, other): + cdef fmpq_mpoly res + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_add(res.val, (self).val, (other).val, res.ctx.val) + return res + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_add_fmpq(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + + def __radd__(self, other): + cdef fmpq_mpoly res + other = any_as_fmpq(other) + if other is not NotImplemented: + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_add_fmpq(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + + def __iadd__(self, other): + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + fmpq_mpoly_add((self).val, (self).val, (other).val, self.ctx.val) + return self + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + fmpq_mpoly_add_fmpq((self).val, (self).val, (other).val, self.ctx.val) + return self + return NotImplemented + + def __sub__(self, other): + cdef fmpq_mpoly res + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_sub(res.val, (self).val, (other).val, res.ctx.val) + return res + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_sub_fmpq(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + + def __rsub__(self, other): + cdef fmpq_mpoly res + other = any_as_fmpq(other) + if other is not NotImplemented: + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_sub_fmpq(res.val, (self).val, (other).val, res.ctx.val) + return -res + return NotImplemented + + def __isub__(self, other): + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + fmpq_mpoly_sub((self).val, (self).val, (other).val, self.ctx.val) + return self + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + fmpq_mpoly_sub_fmpq((self).val, (self).val, (other).val, self.ctx.val) + return self + return NotImplemented + + def __mul__(self, other): + cdef fmpq_mpoly res + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_mul(res.val, (self).val, (other).val, res.ctx.val) + return res + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_scalar_mul_fmpq(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + + def __rmul__(self, other): + cdef fmpq_mpoly res + other = any_as_fmpq(other) + if other is not NotImplemented: + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_scalar_mul_fmpq(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + + def __imul__(self, other): + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + fmpq_mpoly_mul((self).val, (self).val, (other).val, self.ctx.val) + return self + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + fmpq_mpoly_scalar_mul_fmpq(self.val, (self).val, (other).val, self.ctx.val) + return self + return NotImplemented + + def __pow__(self, other, modulus): + cdef fmpq_mpoly res + if modulus is not None: + raise NotImplementedError + other = any_as_fmpz(other) + if other is NotImplemented: + return other + if other < 0: + raise ValueError("cannot raise fmpq_mpoly to negative power") + res = create_fmpq_mpoly(self.ctx) + if fmpq_mpoly_pow_fmpz(res.val, (self).val, (other).val, res.ctx.val) == 0: + raise ValueError("unreasonably large polynomial") + return res + + def __divmod__(self, other): + cdef fmpq_mpoly res, res2 + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = create_fmpq_mpoly(self.ctx) + res2 = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_divrem(res.val, res2.val, (self).val, (other).val, res.ctx.val) + return (res, res2) + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + other= fmpq_mpoly(other, self.ctx) + res = create_fmpq_mpoly(self.ctx) + res2 = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_divrem(res.val, res2.val, (self).val, (other).val, res.ctx.val) + return (res, res2) + return NotImplemented + + def __rdivmod__(self, other): + cdef fmpq_mpoly res, res2 + other = any_as_fmpq(other) + if other is not NotImplemented: + other = fmpq_mpoly(other, self.ctx) + res = create_fmpq_mpoly(self.ctx) + res2 = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_divrem(res.val, res2.val, (other).val, (self).val, res.ctx.val) + return res + return NotImplemented + + # def __floordiv__(self, other): + # cdef fmpq_mpoly res + # if typecheck(other, fmpq_mpoly): + # if (self).ctx is not (other).ctx: + # return NotImplemented + # res = create_fmpq_mpoly(self.ctx) + # fmpq_mpoly_div(res.val, (self).val, (other).val, res.ctx.val) + # return res + # else: + # other = any_as_fmpq(other) + # if other is not NotImplemented: + # other = fmpq_mpoly(other, self.ctx) + # res = create_fmpq_mpoly(self.ctx) + # fmpq_mpoly_div(res.val, (self).val, (other).val, res.ctx.val) + # return res + # return NotImplemented + + # def __rfloordiv__(self,other): + # cdef fmpq_mpoly res + # other = any_as_fmpq(other) + # if other is not NotImplemented: + # other = fmpq_mpoly(other, self.ctx) + # res = create_fmpq_mpoly(self.ctx) + # fmpq_mpoly_div(res.val, (other).val, self.val, res.ctx.val) + # return res + # return NotImplemented + + def __mod__(self, other): + return divmod(self, other)[1] + + def gcd(self, other): + cdef fmpq_mpoly res + assert isinstance(other, fmpq_mpoly) + if (self).ctx is not (other).ctx: + return NotImplemented + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_gcd(res.val, (self).val, (other).val, res.ctx.val) + return res diff --git a/src/flint/fmpz_mpoly.pyx b/src/flint/fmpz_mpoly.pyx index 440bf194..2fcf8f1a 100644 --- a/src/flint/fmpz_mpoly.pyx +++ b/src/flint/fmpz_mpoly.pyx @@ -116,10 +116,13 @@ cdef class fmpz_mpoly_ctx(flint_mpoly_context): return res def constant(self, z): + """ + Create a constant polynomial in this context + """ cdef fmpz_mpoly res z = any_as_fmpz(z) if z is NotImplemented: - raise ValueError() + raise ValueError("A constant fmpz_mpoly is a fmpz") res = fmpz_mpoly.__new__(fmpz_mpoly) res.ctx = self fmpz_mpoly_init(res.val, res.ctx.val) @@ -205,43 +208,43 @@ def get_fmpz_mpoly_context(slong nvars=1, ordering="lex", names='x'): _fmpz_mpoly_ctx_cache[key] = ctx return ctx -cdef _fmpz_mpoly_set2(fmpz_mpoly_t out, fmpz_mpoly_ctx_t outctx, fmpz_mpoly_t inp, fmpz_mpoly_ctx_t inpctx): - cdef slong * C - cdef slong i - cdef slong inpvars, outvars - if outctx == inpctx: - fmpz_mpoly_set(out, inp, inpctx) - else: - inpvars = inpctx.minfo.nvars - outvars = inpctx.minfo.nvars - C = libc.stdlib.malloc(inpvars * sizeof(slong *)) - for i in range(min(outvars, inpvars)): - C[i] = i - for i in range(outvars, inpvars): - C[i] = -1 - fmpz_mpoly_compose_fmpz_mpoly_gen(out, inp, C, inpctx, outctx) - libc.stdlib.free(C) - -def coerce_fmpz_mpolys(*args): - cdef fmpz_mpoly_ctx ctx - ctx = get_fmpz_mpoly_context() - if not args: - return ctx, [] - args = list(args) - if typecheck(args[0], fmpz_mpoly): - ctx = ( args[0]).ctx - if all(typecheck(args[i], fmpz_mpoly) and ( args[i]).ctx is ctx for i in range(1, len(args))): - return ctx, args - for i in range(len(args)): - if not typecheck(args[i], fmpz_mpoly): - args[i] = fmpz_mpoly(args[i]) - nvars = max((pol).ctx.nvars() for pol in args) - ctx = get_fmpz_mpoly_context(nvars) - args2 = [fmpz_mpoly() for i in range(len(args))] - for i in range(len(args)): - ( args2[i]).ctx = ctx - _fmpz_mpoly_set2(( args2[i]).val, ctx.val, ( args[i]).val, ( args[i]).ctx.val) - return ctx, args2 +# cdef _fmpz_mpoly_set2(fmpz_mpoly_t out, fmpz_mpoly_ctx_t outctx, fmpz_mpoly_t inp, fmpz_mpoly_ctx_t inpctx): +# cdef slong * C +# cdef slong i +# cdef slong inpvars, outvars +# if outctx == inpctx: +# fmpz_mpoly_set(out, inp, inpctx) +# else: +# inpvars = inpctx.minfo.nvars +# outvars = inpctx.minfo.nvars +# C = libc.stdlib.malloc(inpvars * sizeof(slong *)) +# for i in range(min(outvars, inpvars)): +# C[i] = i +# for i in range(outvars, inpvars): +# C[i] = -1 +# fmpz_mpoly_compose_fmpz_mpoly_gen(out, inp, C, inpctx, outctx) +# libc.stdlib.free(C) + +# def coerce_fmpz_mpolys(*args): +# cdef fmpz_mpoly_ctx ctx +# ctx = get_fmpz_mpoly_context() +# if not args: +# return ctx, [] +# args = list(args) +# if typecheck(args[0], fmpz_mpoly): +# ctx = ( args[0]).ctx +# if all(typecheck(args[i], fmpz_mpoly) and ( args[i]).ctx is ctx for i in range(1, len(args))): +# return ctx, args +# for i in range(len(args)): +# if not typecheck(args[i], fmpz_mpoly): +# args[i] = fmpz_mpoly(args[i]) +# nvars = max((pol).ctx.nvars() for pol in args) +# ctx = get_fmpz_mpoly_context(nvars) +# args2 = [fmpz_mpoly() for i in range(len(args))] +# for i in range(len(args)): +# ( args2[i]).ctx = ctx +# _fmpz_mpoly_set2(( args2[i]).val, ctx.val, ( args[i]).val, ( args[i]).ctx.val) +# return ctx, args2 cdef inline init_fmpz_mpoly(fmpz_mpoly var, fmpz_mpoly_ctx ctx): var.ctx = ctx @@ -587,50 +590,50 @@ cdef class fmpz_mpoly(flint_mpoly): fmpz_mpoly_gcd(res.val, (self).val, (other).val, res.ctx.val) return res - def __call__(self, *args): - cdef fmpz_mpoly res - cdef fmpz_mpoly_ctx res_ctx - cdef fmpz_struct ** V - cdef fmpz vres - cdef fmpz_mpoly_struct ** C - cdef slong i, nvars, nargs - other = tuple(args) - nargs = len(args) - nvars = self.ctx.nvars() - # todo: should extend with generators instead? - if nargs < nvars: - args = args + (0,) * (nvars - nargs) - if nargs > nvars: - args = args[:nvars] - args_fmpz = [any_as_fmpz(v) for v in args] - # todo: for combination, compose - # todo: if fewer than number of variables, evaluate partially? - if NotImplemented not in args_fmpz: - V = libc.stdlib.malloc(nvars * sizeof(fmpz_struct *)) - try: - for i in range(nvars): - V[i] = &(( args_fmpz[i]).val[0]) - vres = fmpz.__new__(fmpz) - if fmpz_mpoly_evaluate_all_fmpz(vres.val, self.val, V, self.ctx.val) == 0: - raise ValueError("unreasonably large polynomial") - return vres - finally: - libc.stdlib.free(V) - else: - res_ctx, args = coerce_fmpz_mpolys(*args) - C = libc.stdlib.malloc(nvars * sizeof(fmpz_mpoly_struct *)) - try: - for i in range(nvars): - C[i] = &(( args[i]).val[0]) - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = res_ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True - if fmpz_mpoly_compose_fmpz_mpoly(res.val, self.val, C, self.ctx.val, res_ctx.val) == 0: - raise ValueError("unreasonably large polynomial") - return res - finally: - libc.stdlib.free(C) + # def __call__(self, *args): + # cdef fmpz_mpoly res + # cdef fmpz_mpoly_ctx res_ctx + # cdef fmpz_struct ** V + # cdef fmpz vres + # cdef fmpz_mpoly_struct ** C + # cdef slong i, nvars, nargs + # other = tuple(args) + # nargs = len(args) + # nvars = self.ctx.nvars() + # # todo: should extend with generators instead? + # if nargs < nvars: + # args = args + (0,) * (nvars - nargs) + # if nargs > nvars: + # args = args[:nvars] + # args_fmpz = [any_as_fmpz(v) for v in args] + # # todo: for combination, compose + # # todo: if fewer than number of variables, evaluate partially? + # if NotImplemented not in args_fmpz: + # V = libc.stdlib.malloc(nvars * sizeof(fmpz_struct *)) + # try: + # for i in range(nvars): + # V[i] = &(( args_fmpz[i]).val[0]) + # vres = fmpz.__new__(fmpz) + # if fmpz_mpoly_evaluate_all_fmpz(vres.val, self.val, V, self.ctx.val) == 0: + # raise ValueError("unreasonably large polynomial") + # return vres + # finally: + # libc.stdlib.free(V) + # else: + # res_ctx, args = coerce_fmpz_mpolys(*args) + # C = libc.stdlib.malloc(nvars * sizeof(fmpz_mpoly_struct *)) + # try: + # for i in range(nvars): + # C[i] = &(( args[i]).val[0]) + # res = fmpz_mpoly.__new__(fmpz_mpoly) + # res.ctx = res_ctx + # fmpz_mpoly_init(res.val, res.ctx.val) + # res._init = True + # if fmpz_mpoly_compose_fmpz_mpoly(res.val, self.val, C, self.ctx.val, res_ctx.val) == 0: + # raise ValueError("unreasonably large polynomial") + # return res + # finally: + # libc.stdlib.free(C) ''' def factor(self): diff --git a/src/flint/pyflint.pxd b/src/flint/pyflint.pxd index abfe739f..61682225 100644 --- a/src/flint/pyflint.pxd +++ b/src/flint/pyflint.pxd @@ -81,3 +81,9 @@ cdef class fmpz_mpoly: cdef fmpz_mpoly_t val cdef bint initialized +cdef class fmpq_mpoly_ctx: + cdef fmpq_mpoly_ctx_t val + +cdef class fmpq_mpoly: + cdef fmpq_mpoly_t val + cdef bint initialized diff --git a/src/flint/pyflint.pyx b/src/flint/pyflint.pyx index a9c14ccb..02eb81bb 100644 --- a/src/flint/pyflint.pyx +++ b/src/flint/pyflint.pyx @@ -38,6 +38,7 @@ include "fmpz_series.pyx" include "fmpq.pyx" include "fmpq_poly.pyx" +include "fmpq_mpoly.pyx" include "fmpq_mat.pyx" include "fmpq_series.pyx" diff --git a/src/flint/test/test.py b/src/flint/test/test.py index 6ab31df6..63f71ab3 100644 --- a/src/flint/test/test.py +++ b/src/flint/test/test.py @@ -1138,6 +1138,39 @@ def set_bad(i): assert M3.charpoly() == flint.fmpq_poly([-1,6,-12,8]) / 8 assert M3.minpoly() == flint.fmpq_poly([1,-4,4]) / 4 +def test_fmpq_mpoly(): + Zp = flint.fmpq_mpoly + getctx = flint.get_fmpq_mpoly_context + ctx = getctx(4) + assert ctx.nvars() == 4 + assert ctx.ordering() == "lex" + assert [ctx.name(i) for i in range(4)] == ['x0', 'x1', 'x2', 'x3'] + for order in ['lex', 'deglex', 'degrevlex']: + ctx1 = getctx(4, order) + assert ctx1.ordering() == order + ctx = getctx(4, "lex", 'w,x,y,z') + p1 = ctx.gen(0) + ctx.gen(1) - ctx.gen(2) * ctx.gen(3) + assert p1 == Zp("w + x - y * z", ctx) + ctx = getctx(2, "lex", "x,y") + assert ctx.fmpq_mpoly_from_dict({(1,0):1, (0,1):2}) == Zp("x + 2*y", ctx) + assert raises(lambda: ctx.fmpq_mpoly_from_dict("b"), ValueError) + assert raises(lambda: ctx.fmpq_mpoly_from_dict({(1,2):"b"}), TypeError) + assert raises(lambda: ctx.fmpq_mpoly_from_dict({"b":1}), TypeError) + assert raises(lambda: ctx.fmpq_mpoly_from_dict({(1,2,3):1}), TypeError) + assert raises(lambda: ctx.fmpq_mpoly_from_dict({(1,"a"):1}), TypeError) + ctx = getctx(2, "lex", 'x,y') + p1 = ctx.fmpq_mpoly_from_dict({(1,0):4,(0,3):4,(2,4):9}) + for ztype in [int, long, flint.fmpz]: + assert p1 + ztype(3) == ctx.fmpq_mpoly_from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):3}) + assert ztype(3) + p1 == ctx.fmpq_mpoly_from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):3}) + assert p1 - ztype(3) == ctx.fmpq_mpoly_from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):-3}) + assert ztype(3) - p1 == ctx.fmpq_mpoly_from_dict({(1,0):-4,(0,3):-4,(2,4):-9,(0,0):3}) + assert p1 * ztype(3) == ctx.fmpq_mpoly_from_dict({(1,0):12,(0,3):12,(2,4):27}) + assert ztype(3) * p1 == ctx.fmpq_mpoly_from_dict({(1,0):12,(0,3):12,(2,4):27}) + assert p1 // ztype(3) == ctx.fmpq_mpoly_from_dict({(1,0):1,(0,3):1,(2,4):3}) + assert ztype(3) // p1 == Zp(0,ctx) + assert ctx.constant(7) + ztype(3) == Zp(10, ctx) + def test_fmpq_series(): Qp = flint.fmpq_poly Q = flint.fmpq_series @@ -1607,6 +1640,7 @@ def test_pickling(): test_fmpq, test_fmpq_poly, test_fmpq_mat, + test_fmpq_mpoly, test_fmpq_series, test_nmod, test_nmod_poly, From 0f2fceb6a5273c4336721847ed64b16e2d8b328d Mon Sep 17 00:00:00 2001 From: David Einstein Date: Mon, 11 Sep 2023 21:29:06 -0400 Subject: [PATCH 13/21] Small advances in fmpz_mpoly. Added infrastructure for fmpq_mpoly fixed up new import system --- src/flint/flint_base/flint_context.pyx | 2 +- src/flint/flintlib/fmpq_mpoly.pxd | 162 ++++++++++++------------ src/flint/types/fmpq_mpoly.pxd | 16 +++ src/flint/types/fmpq_mpoly.pyx | 163 +++++++++++++++++++++++++ src/flint/types/fmpz_mpoly.pxd | 1 - src/flint/types/fmpz_poly.pxd | 1 - 6 files changed, 261 insertions(+), 84 deletions(-) create mode 100644 src/flint/types/fmpq_mpoly.pxd create mode 100644 src/flint/types/fmpq_mpoly.pyx diff --git a/src/flint/flint_base/flint_context.pyx b/src/flint/flint_base/flint_context.pyx index c73c83bc..297005f1 100644 --- a/src/flint/flint_base/flint_context.pyx +++ b/src/flint/flint_base/flint_context.pyx @@ -18,7 +18,7 @@ cdef class FlintContext: self.threads = 1 self.cap = 10 - @property + @property def prec(self): return self._prec diff --git a/src/flint/flintlib/fmpq_mpoly.pxd b/src/flint/flintlib/fmpq_mpoly.pxd index 33a42ad9..e37e276d 100644 --- a/src/flint/flintlib/fmpq_mpoly.pxd +++ b/src/flint/flintlib/fmpq_mpoly.pxd @@ -57,104 +57,104 @@ cdef extern from "flint/fmpq_mpoly.h": void fmpq_mpoly_get_denominator(fmpz_t d, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_get_coeff_fmpq_monomial(fmpq_t c, const fmpq_mpoly_t A, const fmpq_mpoly_t M, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_set_coeff_fmpq_monomial(fmpq_mpoly_t A, const fmpq_t c, const fmpq_mpoly_t M, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_get_coeff_fmpq_fmpz(fmpq_t c, const fmpq_mpoly_t A, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_get_coeff_fmpq_ui(fmpq_t c, const fmpq_mpoly_t A, ulong const * exp, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_set_coeff_fmpq_fmpz(fmpq_mpoly_t A, const fmpq_t c, fmpz_t * const * exp, fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_set_coeff_fmpq_ui(fmpq_mpoly_t A, const fmpq_t c, ulong const * exp, fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_get_coeff_vars_ui(fmpq_mpoly_t C, const fmpq_mpoly_t A, const slong * vars, const ulong * exps, slong length, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_cmp(const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - # fmpq * fmpq_mpoly_content_ref(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) - # fmpz_mpoly_struct * fmpq_mpoly_zpoly_ref(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) - # fmpz_t * fmpq_mpoly_zpoly_term_coeff_ref(fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_is_canonical(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_coeff_fmpq_fmpz(fmpq_t c, const fmpq_mpoly_t A, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_coeff_fmpq_ui(fmpq_t c, const fmpq_mpoly_t A, ulong const * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_coeff_fmpq_fmpz(fmpq_mpoly_t A, const fmpq_t c, fmpz_t * const * exp, fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_coeff_fmpq_ui(fmpq_mpoly_t A, const fmpq_t c, ulong const * exp, fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_coeff_vars_ui(fmpq_mpoly_t C, const fmpq_mpoly_t A, const slong * vars, const ulong * exps, slong length, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_cmp(const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + fmpq * fmpq_mpoly_content_ref(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + fmpz_mpoly_struct * fmpq_mpoly_zpoly_ref(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + fmpz_t * fmpq_mpoly_zpoly_term_coeff_ref(fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_is_canonical(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) slong fmpq_mpoly_length(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_resize(fmpq_mpoly_t A, slong new_length, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_resize(fmpq_mpoly_t A, slong new_length, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_get_term_coeff_fmpq(fmpq_t c, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_set_term_coeff_fmpq(fmpq_mpoly_t A, slong i, const fmpq_t c, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_term_exp_fits_si(const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_term_exp_fits_ui(const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_term_exp_fits_si(const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_term_exp_fits_ui(const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_get_term_exp_fmpz(fmpz_struct ** exps, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_get_term_exp_ui(ulong * exps, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_get_term_exp_si(slong * exps, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) - # ulong fmpq_mpoly_get_term_var_exp_ui(const fmpq_mpoly_t A, slong i, slong var, const fmpq_mpoly_ctx_t ctx) - # slong fmpq_mpoly_get_term_var_exp_si(const fmpq_mpoly_t A, slong i, slong var, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_set_term_exp_fmpz(fmpq_mpoly_t A, slong i, fmpz_t * const * exps, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_set_term_exp_ui(fmpq_mpoly_t A, slong i, const ulong * exps, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_get_term(fmpq_mpoly_t M, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_get_term_monomial(fmpq_mpoly_t M, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_term_exp_ui(ulong * exps, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_term_exp_si(slong * exps, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + ulong fmpq_mpoly_get_term_var_exp_ui(const fmpq_mpoly_t A, slong i, slong var, const fmpq_mpoly_ctx_t ctx) + slong fmpq_mpoly_get_term_var_exp_si(const fmpq_mpoly_t A, slong i, slong var, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_term_exp_fmpz(fmpq_mpoly_t A, slong i, fmpz_t * const * exps, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_term_exp_ui(fmpq_mpoly_t A, slong i, const ulong * exps, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_term(fmpq_mpoly_t M, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_term_monomial(fmpq_mpoly_t M, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_push_term_fmpq_fmpz(fmpq_mpoly_t A, const fmpq_t c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_push_term_fmpz_fmpz(fmpq_mpoly_t A, const fmpz_t c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_push_term_ui_fmpz(fmpq_mpoly_t A, ulong c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_push_term_si_fmpz(fmpq_mpoly_t A, slong c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_push_term_fmpq_ui(fmpq_mpoly_t A, const fmpq_t c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_push_term_fmpz_ui(fmpq_mpoly_t A, const fmpz_t c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_push_term_ui_ui(fmpq_mpoly_t A, ulong c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_push_term_si_ui(fmpq_mpoly_t A, slong c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_reduce(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_fmpz_fmpz(fmpq_mpoly_t A, const fmpz_t c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_ui_fmpz(fmpq_mpoly_t A, ulong c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_si_fmpz(fmpq_mpoly_t A, slong c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_fmpq_ui(fmpq_mpoly_t A, const fmpq_t c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_fmpz_ui(fmpq_mpoly_t A, const fmpz_t c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_ui_ui(fmpq_mpoly_t A, ulong c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_si_ui(fmpq_mpoly_t A, slong c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_reduce(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_sort_terms(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_combine_like_terms(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_reverse(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_randtest_bound(fmpq_mpoly_t A, flint_rand_t state, slong length, mp_limb_t coeff_bits, ulong exp_bound, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_randtest_bounds(fmpq_mpoly_t A, flint_rand_t state, slong length, mp_limb_t coeff_bits, ulong * exp_bounds, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_randtest_bits(fmpq_mpoly_t A, flint_rand_t state, slong length, mp_limb_t coeff_bits, mp_limb_t exp_bits, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_combine_like_terms(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_reverse(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_randtest_bound(fmpq_mpoly_t A, flint_rand_t state, slong length, mp_limb_t coeff_bits, ulong exp_bound, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_randtest_bounds(fmpq_mpoly_t A, flint_rand_t state, slong length, mp_limb_t coeff_bits, ulong * exp_bounds, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_randtest_bits(fmpq_mpoly_t A, flint_rand_t state, slong length, mp_limb_t coeff_bits, mp_limb_t exp_bits, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_add_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_t c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_add_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_add_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_add_si(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_add_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_add_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_add_si(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong c, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_sub_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_t c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_sub_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_sub_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_sub_si(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_sub_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_sub_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_sub_si(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong c, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_add(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_t C, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_sub(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_t C, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_neg(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_scalar_mul_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_t c, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_scalar_mul_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_scalar_mul_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_scalar_mul_si(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_scalar_div_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_t c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_scalar_div_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_scalar_div_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_scalar_div_si(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong c, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_make_monic(fmpq_mpoly_t A, fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_derivative(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_integral(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_evaluate_all_fmpq(fmpq_t ev, const fmpq_mpoly_t A, fmpq * const * vals, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_evaluate_one_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_t val, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_compose_fmpq_poly(fmpq_poly_t A, const fmpq_mpoly_t B, fmpq_poly_struct * const * C, const fmpq_mpoly_ctx_t ctxB) - # int fmpq_mpoly_compose_fmpq_mpoly(fmpq_mpoly_t A, const fmpq_mpoly_t B, fmpq_mpoly_struct * const * C, const fmpq_mpoly_ctx_t ctxB, const fmpq_mpoly_ctx_t ctxAC) - # void fmpq_mpoly_compose_fmpq_mpoly_gen(fmpq_mpoly_t A, const fmpq_mpoly_t B, const slong * c, const fmpq_mpoly_ctx_t ctxB, const fmpq_mpoly_ctx_t ctxAC) + void fmpq_mpoly_scalar_mul_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_scalar_mul_si(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_scalar_div_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_t c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_scalar_div_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_scalar_div_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_scalar_div_si(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong c, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_make_monic(fmpq_mpoly_t A, fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_derivative(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_integral(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_evaluate_all_fmpq(fmpq_t ev, const fmpq_mpoly_t A, fmpq * const * vals, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_evaluate_one_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_t val, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_compose_fmpq_poly(fmpq_poly_t A, const fmpq_mpoly_t B, fmpq_poly_struct * const * C, const fmpq_mpoly_ctx_t ctxB) + int fmpq_mpoly_compose_fmpq_mpoly(fmpq_mpoly_t A, const fmpq_mpoly_t B, fmpq_mpoly_struct * const * C, const fmpq_mpoly_ctx_t ctxB, const fmpq_mpoly_ctx_t ctxAC) + void fmpq_mpoly_compose_fmpq_mpoly_gen(fmpq_mpoly_t A, const fmpq_mpoly_t B, const slong * c, const fmpq_mpoly_ctx_t ctxB, const fmpq_mpoly_ctx_t ctxAC) void fmpq_mpoly_mul(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_t C, const fmpq_mpoly_ctx_t ctx) int fmpq_mpoly_pow_fmpz(fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpz_t k, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_pow_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong k, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_divides(fmpq_mpoly_t Q, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_div(fmpq_mpoly_t Q, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_pow_ui(fmpq_mpoly_t A, const fmpq_mpoly_t B, ulong k, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_divides(fmpq_mpoly_t Q, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_div(fmpq_mpoly_t Q, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_divrem(fmpq_mpoly_t Q, fmpq_mpoly_t R, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_divrem_ideal(fmpq_mpoly_struct ** Q, fmpq_mpoly_t R, const fmpq_mpoly_t A, fmpq_mpoly_struct * const * B, slong len, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_content(fmpq_t g, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_term_content(fmpq_mpoly_t M, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_content_vars(fmpq_mpoly_t g, const fmpq_mpoly_t A, slong * vars, slong vars_length, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_divrem_ideal(fmpq_mpoly_struct ** Q, fmpq_mpoly_t R, const fmpq_mpoly_t A, fmpq_mpoly_struct * const * B, slong len, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_content(fmpq_t g, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_term_content(fmpq_mpoly_t M, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_content_vars(fmpq_mpoly_t g, const fmpq_mpoly_t A, slong * vars, slong vars_length, const fmpq_mpoly_ctx_t ctx) int fmpq_mpoly_gcd(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_gcd_cofactors(fmpq_mpoly_t G, fmpq_mpoly_t Abar, fmpq_mpoly_t Bbar, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_gcd_brown(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_gcd_hensel(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_gcd_subresultant(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_gcd_zippel(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_gcd_zippel2(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_resultant(fmpq_mpoly_t R, const fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_discriminant(fmpq_mpoly_t D, const fmpq_mpoly_t A, slong var, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_sqrt(fmpq_mpoly_t Q, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_is_square(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_univar_init(fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_univar_clear(fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_univar_swap(fmpq_mpoly_univar_t A, fmpq_mpoly_univar_t B, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_to_univar(fmpq_mpoly_univar_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_from_univar(fmpq_mpoly_t A, const fmpq_mpoly_univar_t B, slong var, const fmpq_mpoly_ctx_t ctx) - # int fmpq_mpoly_univar_degree_fits_si(const fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) - # slong fmpq_mpoly_univar_length(const fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) - # slong fmpq_mpoly_univar_get_term_exp_si(fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_univar_get_term_coeff(fmpq_mpoly_t c, const fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) - # void fmpq_mpoly_univar_swap_term_coeff(fmpq_mpoly_t c, fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_gcd_cofactors(fmpq_mpoly_t G, fmpq_mpoly_t Abar, fmpq_mpoly_t Bbar, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_gcd_brown(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_gcd_hensel(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_gcd_subresultant(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_gcd_zippel(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_gcd_zippel2(fmpq_mpoly_t G, const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_resultant(fmpq_mpoly_t R, const fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_discriminant(fmpq_mpoly_t D, const fmpq_mpoly_t A, slong var, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_sqrt(fmpq_mpoly_t Q, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_is_square(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_univar_init(fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_univar_clear(fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_univar_swap(fmpq_mpoly_univar_t A, fmpq_mpoly_univar_t B, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_to_univar(fmpq_mpoly_univar_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_from_univar(fmpq_mpoly_t A, const fmpq_mpoly_univar_t B, slong var, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_univar_degree_fits_si(const fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) + slong fmpq_mpoly_univar_length(const fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) + slong fmpq_mpoly_univar_get_term_exp_si(fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_univar_get_term_coeff(fmpq_mpoly_t c, const fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_univar_swap_term_coeff(fmpq_mpoly_t c, fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) """ cdef extern from "flint/fmpz_mpoly_factor.h": diff --git a/src/flint/types/fmpq_mpoly.pxd b/src/flint/types/fmpq_mpoly.pxd new file mode 100644 index 00000000..04a4cdb7 --- /dev/null +++ b/src/flint/types/fmpq_mpoly.pxd @@ -0,0 +1,16 @@ +from flint.flint_base.flint_base cimport flint_mpoly +from flint.flint_base.flint_base cimport flint_mpoly_context + +from flint.flintlib.fmpq_mpoly cimport fmpq_mpoly_ctx_t +from flint.flintlib.fmpq_mpoly cimport fmpq_mpoly_t +from flint.flintlib.flint cimport slong + +cdef class fmpq_mpoly_ctx(flint_mpoly_context): + cdef fmpq_mpoly_ctx_t val + cpdef slong nvars(self) + cpdef ordering(self) + +cdef class fmpq_mpoly(flint_mpoly): + cdef fmpq_mpoly_t val + cdef fmpq_mpoly_ctx ctx + cdef bint _init diff --git a/src/flint/types/fmpq_mpoly.pyx b/src/flint/types/fmpq_mpoly.pyx new file mode 100644 index 00000000..11922e15 --- /dev/null +++ b/src/flint/types/fmpq_mpoly.pyx @@ -0,0 +1,163 @@ + + +cdef dict _fmpq_mpoly_ctx_cache = {} + +@cython.auto_pickle(False) +cdef class fmpq_mpoly_ctx(flint_mpoly_context): + """ + A class for storing the polynomial context + + :param nvars: The number of variables in the ring + :param ordering: The term order for the ring + :param names: A tuple containing the names of the variables of the ring. + + Do not construct one of these directly, use `get_fmpz_mpoly_context`. + """ +# cdef fmpz_mpoly_ctx_t val + + def __init__(self, slong nvars, ordering, names): + if ordering == "lex": + fmpq_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_LEX) + elif ordering == "deglex": + fmpq_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_DEGLEX) + elif ordering == "degrevlex": + fmpq_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_DEGREVLEX) + else: + raise ValueError("Unimplemented term order %s" % ordering) + + super().__init__(nvars, names) + + cpdef slong nvars(self): + """ + Return the number of variables in the context + + >>> ctx = get_fmpz_mpoly_context(4, "lex", 'x') + >>> ctx.nvars() + 4 + """ + return self.val.zctx.minfo.nvars + + cpdef ordering(self): + """ + Return the term order of the context object. + + >>> ctx = get_fmpz_mpoly_context(4, "deglex", 'w') + >>> ctx.ordering() + 'deglex' + """ + if self.val.zctx.minfo.ord == ordering_t.ORD_LEX: + return "lex" + if self.val.zctx.minfo.ord == ordering_t.ORD_DEGLEX: + return "deglex" + if self.val.zctx.minfo.ord == ordering_t.ORD_DEGREVLEX: + return "degrevlex" + + def gen(self, slong i): + """ + Return the `i`th generator of the polynomial ring + + >>> ctx = get_fmpz_mpoly_context(3, 'degrevlex', 'z') + >>> ctx.gen(1) + z1 + """ + cdef fmpq_mpoly res + assert i >= 0 and i < self.val.zctx.minfo.nvars + res = fmpq_mpoly.__new__(fmpz_mpoly) + res.ctx = self + fmpq_mpoly_init(res.val, res.ctx.val) + res._init = True + fmpq_mpoly_gen(res.val, i, res.ctx.val) + return res + + def constant(self, z): + """ + Create a constant polynomial in this context + """ + cdef fmpq_mpoly res + z = any_as_fmpq(z) + if z is NotImplemented: + raise ValueError("A constant fmpq_mpoly is a fmpq") + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx = self + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + fmpz_mpoly_set_fmpz(res.val, (z).val, res.ctx.val) + return res + + def fmpz_mpoly_from_dict(self, d): + """ + Create a fmpz_mpoly from a dictionary. + + The dictionary's keys are tuples of ints (or anything that implicitly converts + to fmpz) representing exponents, and corresponding values of fmpz. + + >>> ctx = get_fmpz_mpoly_context(2,'lex','x,y') + >>> ctx.fmpz_mpoly_from_dict({(1,0):2, (1,1):3, (0,1):1}) + 3*x*y + 2*x + y + """ + cdef long n + cdef fmpz_t coefficient + cdef fmpz_struct *exponents + cdef int xtype + cdef int nvars = self.nvars() + cdef int i,j + cdef int count + cdef fmpz_mpoly res + + if not PyDict_Check(d): + raise ValueError("expected a dictionary") + n = PyDict_Size(d) + fmpz_init(coefficient) + exponents = libc.stdlib.calloc(nvars, sizeof(fmpz_struct)) + if exponents == NULL: + raise MemoryError() + for i in range(nvars): + fmpz_init(exponents + i) + fmpz_init(coefficient) + res = fmpz_mpoly.__new__(fmpz_mpoly) + res.ctx = self + fmpz_mpoly_init(res.val, res.ctx.val) + res._init = True + count = 0 + for k,v in d.items(): + xtype = fmpz_set_any_ref(coefficient, v) + if xtype == FMPZ_UNKNOWN: + libc.stdlib.free(exponents) + raise TypeError("invalid coefficient type %s" % type(v)) + if not PyTuple_Check(k): + libc.stdlib.free(exponents) + raise TypeError("Expected tuple of ints as key not %s" % type(k)) + if PyTuple_GET_SIZE(k) != nvars: + libc.stdlib.free(exponents) + raise TypeError("Expected exponent tuple of length %d" % nvars) + for i,tup in enumerate(k): + xtype = fmpz_set_any_ref(exponents + i, tup) + if xtype == FMPZ_UNKNOWN: + libc.stdlib.free(exponents) + raise TypeError("Invalid exponent type %s" % type(tup)) + #Todo lobby for fmpz_mpoly_push_term_fmpz_ffmpz + if not fmpz_is_zero(coefficient): + _fmpz_mpoly_push_exp_ffmpz(res.val, exponents, self.val) + fmpz_mpoly_set_term_coeff_fmpz(res.val, count, coefficient, self.val) + count += 1 + for i in range(nvars): + fmpz_clear(exponents + i) + fmpz_clear(coefficient) + fmpz_mpoly_sort_terms(res.val, self.val) + return res + + +def get_fmpz_mpoly_context(slong nvars=1, ordering="lex", names='x'): + if nvars <= 0: + nvars = 1 + nametup = tuple(name.strip() for name in names.split(',')) + if len(nametup) != nvars: + if len(nametup) != 1: + raise ValueError("Number of variables does not equal number of names") + nametup = tuple(nametup[0] + str(i) for i in range(nvars)) + key = (nvars, ordering, nametup) + ctx = _fmpz_mpoly_ctx_cache.get(key) + if ctx is None: + ctx = fmpz_mpoly_ctx(nvars, ordering, nametup) + _fmpz_mpoly_ctx_cache[key] = ctx + return ctx diff --git a/src/flint/types/fmpz_mpoly.pxd b/src/flint/types/fmpz_mpoly.pxd index f978f45b..a33d6f00 100644 --- a/src/flint/types/fmpz_mpoly.pxd +++ b/src/flint/types/fmpz_mpoly.pxd @@ -8,7 +8,6 @@ from flint.flintlib.flint cimport slong cdef class fmpz_mpoly_ctx(flint_mpoly_context): cdef fmpz_mpoly_ctx_t val cpdef slong nvars(self) - cpdef ordering(self) cdef class fmpz_mpoly(flint_mpoly): diff --git a/src/flint/types/fmpz_poly.pxd b/src/flint/types/fmpz_poly.pxd index 61bc109d..a91ad265 100644 --- a/src/flint/types/fmpz_poly.pxd +++ b/src/flint/types/fmpz_poly.pxd @@ -1,4 +1,3 @@ - from flint.flint_base.flint_base cimport flint_poly from flint.flintlib.fmpz_poly cimport fmpz_poly_t From fbe31b7d503e7238f259b00e01b1e36db2614eac Mon Sep 17 00:00:00 2001 From: David Einstein Date: Fri, 22 Sep 2023 11:50:51 -0400 Subject: [PATCH 14/21] Added fmpz_mpoly_factor and fmpq_mpoly. --- src/flint/__init__.py | 1 + src/flint/flintlib/fmpq.pxd | 1 + src/flint/flintlib/fmpq_mpoly.pxd | 79 ++--- src/flint/flintlib/fmpz_mpoly_factor.pxd | 32 ++ src/flint/test/test.py | 6 +- src/flint/types/fmpq.pxd | 1 + src/flint/types/fmpq.pyx | 4 +- src/flint/types/fmpq_mpoly.pyx | 425 +++++++++++++++++++++-- src/flint/types/fmpz_mpoly.pyx | 56 ++- 9 files changed, 527 insertions(+), 78 deletions(-) create mode 100644 src/flint/flintlib/fmpz_mpoly_factor.pxd diff --git a/src/flint/__init__.py b/src/flint/__init__.py index 74b306a0..a63a969c 100644 --- a/src/flint/__init__.py +++ b/src/flint/__init__.py @@ -21,6 +21,7 @@ from .types.acb_mat import * from .types.acb_series import * from .types.fmpz_mpoly import * +from .types.fmpq_mpoly import * from .functions.showgood import showgood __version__ = '0.4.4' diff --git a/src/flint/flintlib/fmpq.pxd b/src/flint/flintlib/fmpq.pxd index 12a5d400..e03ddb1d 100644 --- a/src/flint/flintlib/fmpq.pxd +++ b/src/flint/flintlib/fmpq.pxd @@ -5,6 +5,7 @@ cdef extern from "flint/fmpq.h": ctypedef struct fmpq_struct: fmpz_struct num fmpz_struct den + ctypedef fmpq_struct fmpq_t[1] fmpz_struct * fmpq_numref(fmpq_t x) fmpz_struct * fmpq_denref(fmpq_t x) diff --git a/src/flint/flintlib/fmpq_mpoly.pxd b/src/flint/flintlib/fmpq_mpoly.pxd index e37e276d..766794de 100644 --- a/src/flint/flintlib/fmpq_mpoly.pxd +++ b/src/flint/flintlib/fmpq_mpoly.pxd @@ -1,3 +1,12 @@ +from flint.flintlib.flint cimport flint_rand_t, ulong, slong, mp_limb_t, flint_bitcnt_t, fmpz_struct +from flint.flintlib.fmpq_poly cimport fmpq_poly_struct, fmpq_poly_t +from flint.flintlib.fmpz cimport fmpz_t +from flint.flintlib.fmpq cimport fmpq_t, fmpq_struct +from flint.flintlib.mpoly cimport ordering_t +from flint.flintlib.fmpz_mpoly cimport fmpz_mpoly_ctx_t, fmpz_mpoly_t, fmpz_mpoly_struct + + +# unimported types {'fmpq_mpoly_univar_t'} cdef extern from "flint/fmpq_mpoly.h": ctypedef struct fmpq_mpoly_ctx_struct: @@ -46,7 +55,7 @@ cdef extern from "flint/fmpq_mpoly.h": int fmpq_mpoly_is_zero(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) int fmpq_mpoly_is_one(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) int fmpq_mpoly_degrees_fit_si(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_degrees_fmpz(fmpz_t ** degs, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_degrees_fmpz(fmpz_struct ** degs, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_degrees_si(slong * degs, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_degree_fmpz(fmpz_t deg, const fmpq_mpoly_t A, slong var, const fmpq_mpoly_ctx_t ctx) slong fmpq_mpoly_degree_si(const fmpq_mpoly_t A, slong var, const fmpq_mpoly_ctx_t ctx) @@ -57,15 +66,15 @@ cdef extern from "flint/fmpq_mpoly.h": void fmpq_mpoly_get_denominator(fmpz_t d, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_get_coeff_fmpq_monomial(fmpq_t c, const fmpq_mpoly_t A, const fmpq_mpoly_t M, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_set_coeff_fmpq_monomial(fmpq_mpoly_t A, const fmpq_t c, const fmpq_mpoly_t M, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_get_coeff_fmpq_fmpz(fmpq_t c, const fmpq_mpoly_t A, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_get_coeff_fmpq_ui(fmpq_t c, const fmpq_mpoly_t A, ulong const * exp, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_set_coeff_fmpq_fmpz(fmpq_mpoly_t A, const fmpq_t c, fmpz_t * const * exp, fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_set_coeff_fmpq_ui(fmpq_mpoly_t A, const fmpq_t c, ulong const * exp, fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_coeff_fmpq_fmpz(fmpq_t c, const fmpq_mpoly_t A, fmpz_struct * const * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_get_coeff_fmpq_ui(fmpq_t c, const fmpq_mpoly_t A, ulong * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_coeff_fmpq_fmpz(fmpq_mpoly_t A, const fmpq_t c, fmpz_struct * const * exp, fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_coeff_fmpq_ui(fmpq_mpoly_t A, const fmpq_t c, ulong * exp, fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_get_coeff_vars_ui(fmpq_mpoly_t C, const fmpq_mpoly_t A, const slong * vars, const ulong * exps, slong length, const fmpq_mpoly_ctx_t ctx) int fmpq_mpoly_cmp(const fmpq_mpoly_t A, const fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) - fmpq * fmpq_mpoly_content_ref(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + fmpq_struct * fmpq_mpoly_content_ref(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) fmpz_mpoly_struct * fmpq_mpoly_zpoly_ref(fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) - fmpz_t * fmpq_mpoly_zpoly_term_coeff_ref(fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) + fmpz_struct * fmpq_mpoly_zpoly_term_coeff_ref(fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) int fmpq_mpoly_is_canonical(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) slong fmpq_mpoly_length(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_resize(fmpq_mpoly_t A, slong new_length, const fmpq_mpoly_ctx_t ctx) @@ -78,14 +87,18 @@ cdef extern from "flint/fmpq_mpoly.h": void fmpq_mpoly_get_term_exp_si(slong * exps, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) ulong fmpq_mpoly_get_term_var_exp_ui(const fmpq_mpoly_t A, slong i, slong var, const fmpq_mpoly_ctx_t ctx) slong fmpq_mpoly_get_term_var_exp_si(const fmpq_mpoly_t A, slong i, slong var, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_set_term_exp_fmpz(fmpq_mpoly_t A, slong i, fmpz_t * const * exps, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_set_term_exp_fmpz(fmpq_mpoly_t A, slong i, fmpz_struct * const * exps, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_set_term_exp_ui(fmpq_mpoly_t A, slong i, const ulong * exps, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_get_term(fmpq_mpoly_t M, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_get_term_monomial(fmpq_mpoly_t M, const fmpq_mpoly_t A, slong i, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_push_term_fmpq_fmpz(fmpq_mpoly_t A, const fmpq_t c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_push_term_fmpz_fmpz(fmpq_mpoly_t A, const fmpz_t c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_push_term_ui_fmpz(fmpq_mpoly_t A, ulong c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_push_term_si_fmpz(fmpq_mpoly_t A, slong c, fmpz_t * const * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_fmpq_fmpz(fmpq_mpoly_t A, const fmpq_t c, fmpz_struct * const * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_fmpq_ffmpz(fmpq_mpoly_t A, const fmpq_t c, const fmpz_struct * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_fmpz_fmpz(fmpq_mpoly_t A, const fmpz_t c, fmpz_struct * const * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_fmpz_ffmpz(fmpq_mpoly_t A, const fmpz_t c, const fmpz_struct * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_ui_fmpz(fmpq_mpoly_t A, ulong c, fmpz_struct * const * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_ui_ffmpz(fmpq_mpoly_t A, ulong c, const fmpz_struct * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_si_fmpz(fmpq_mpoly_t A, slong c, fmpz_struct * const * exp, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_push_term_si_ffmpz(fmpq_mpoly_t A, slong c, const fmpz_struct * exp, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_push_term_fmpq_ui(fmpq_mpoly_t A, const fmpq_t c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_push_term_fmpz_ui(fmpq_mpoly_t A, const fmpz_t c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_push_term_ui_ui(fmpq_mpoly_t A, ulong c, const ulong * exp, const fmpq_mpoly_ctx_t ctx) @@ -119,7 +132,7 @@ cdef extern from "flint/fmpq_mpoly.h": void fmpq_mpoly_make_monic(fmpq_mpoly_t A, fmpq_mpoly_t B, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_derivative(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) void fmpq_mpoly_integral(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) - int fmpq_mpoly_evaluate_all_fmpq(fmpq_t ev, const fmpq_mpoly_t A, fmpq * const * vals, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_evaluate_all_fmpq(fmpq_t ev, const fmpq_mpoly_t A, fmpq_struct * const * vals, const fmpq_mpoly_ctx_t ctx) int fmpq_mpoly_evaluate_one_fmpq(fmpq_mpoly_t A, const fmpq_mpoly_t B, slong var, const fmpq_t val, const fmpq_mpoly_ctx_t ctx) int fmpq_mpoly_compose_fmpq_poly(fmpq_poly_t A, const fmpq_mpoly_t B, fmpq_poly_struct * const * C, const fmpq_mpoly_ctx_t ctxB) int fmpq_mpoly_compose_fmpq_mpoly(fmpq_mpoly_t A, const fmpq_mpoly_t B, fmpq_mpoly_struct * const * C, const fmpq_mpoly_ctx_t ctxB, const fmpq_mpoly_ctx_t ctxAC) @@ -145,33 +158,13 @@ cdef extern from "flint/fmpq_mpoly.h": int fmpq_mpoly_discriminant(fmpq_mpoly_t D, const fmpq_mpoly_t A, slong var, const fmpq_mpoly_ctx_t ctx) int fmpq_mpoly_sqrt(fmpq_mpoly_t Q, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) int fmpq_mpoly_is_square(const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_univar_init(fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_univar_clear(fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_univar_swap(fmpq_mpoly_univar_t A, fmpq_mpoly_univar_t B, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_to_univar(fmpq_mpoly_univar_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_from_univar(fmpq_mpoly_t A, const fmpq_mpoly_univar_t B, slong var, const fmpq_mpoly_ctx_t ctx) - int fmpq_mpoly_univar_degree_fits_si(const fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) - slong fmpq_mpoly_univar_length(const fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) - slong fmpq_mpoly_univar_get_term_exp_si(fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_univar_get_term_coeff(fmpq_mpoly_t c, const fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) - void fmpq_mpoly_univar_swap_term_coeff(fmpq_mpoly_t c, fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) - -""" -cdef extern from "flint/fmpz_mpoly_factor.h": - - ctypedef struct fmpz_mpoly_factor_struct: - fmpz_t content - fmpz_mpoly_struct * poly - fmpz_struct * exp - slong length - slong alloc - - ctypedef fmpz_mpoly_factor_struct fmpz_mpoly_factor_t[1] - - - void fmpz_mpoly_factor_init(fmpz_mpoly_factor_t fac, const fmpz_mpoly_ctx_t ctx) - - void fmpz_mpoly_factor_clear(fmpz_mpoly_factor_t fac, const fmpz_mpoly_ctx_t ctx) - - int fmpz_mpoly_factor(fmpz_mpoly_factor_t fac, const fmpz_mpoly_t A, int full, const fmpz_mpoly_ctx_t ctx) -""" + # void fmpq_mpoly_univar_init(fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_univar_clear(fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_univar_swap(fmpq_mpoly_univar_t A, fmpq_mpoly_univar_t B, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_to_univar(fmpq_mpoly_univar_t A, const fmpq_mpoly_t B, slong var, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_from_univar(fmpq_mpoly_t A, const fmpq_mpoly_univar_t B, slong var, const fmpq_mpoly_ctx_t ctx) + # int fmpq_mpoly_univar_degree_fits_si(const fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) + # slong fmpq_mpoly_univar_length(const fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx) + # slong fmpq_mpoly_univar_get_term_exp_si(fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_univar_get_term_coeff(fmpq_mpoly_t c, const fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) + # void fmpq_mpoly_univar_swap_term_coeff(fmpq_mpoly_t c, fmpq_mpoly_univar_t A, slong i, const fmpq_mpoly_ctx_t ctx) diff --git a/src/flint/flintlib/fmpz_mpoly_factor.pxd b/src/flint/flintlib/fmpz_mpoly_factor.pxd new file mode 100644 index 00000000..bba20a9b --- /dev/null +++ b/src/flint/flintlib/fmpz_mpoly_factor.pxd @@ -0,0 +1,32 @@ +from flint.flintlib.fmpz_mpoly cimport fmpz_mpoly_t, fmpz_mpoly_ctx_t, fmpz_mpoly_struct +from flint.flintlib.fmpz cimport fmpz_t +from flint.flintlib.flint cimport slong, fmpz_struct +from flint.flintlib.fmpq cimport fmpq_t + + +# unimported types set() + +cdef extern from "flint/fmpz_mpoly_factor.h": + + ctypedef struct fmpz_mpoly_factor_struct: + fmpz_t constant + fmpz_t constant_den + fmpz_mpoly_struct * poly + fmpz_struct * exp + slong num + slong alloc + + ctypedef fmpz_mpoly_factor_struct fmpz_mpoly_factor_t[1]; + + void fmpz_mpoly_factor_init(fmpz_mpoly_factor_t f, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_factor_clear(fmpz_mpoly_factor_t f, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_factor_swap(fmpz_mpoly_factor_t f, fmpz_mpoly_factor_t g, const fmpz_mpoly_ctx_t ctx) + slong fmpz_mpoly_factor_length(const fmpz_mpoly_factor_t f, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_factor_get_constant_fmpz(fmpz_t c, const fmpz_mpoly_factor_t f, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_factor_get_constant_fmpq(fmpq_t c, const fmpz_mpoly_factor_t f, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_factor_get_base(fmpz_mpoly_t B, const fmpz_mpoly_factor_t f, slong i, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_factor_swap_base(fmpz_mpoly_t B, fmpz_mpoly_factor_t f, slong i, const fmpz_mpoly_ctx_t ctx) + slong fmpz_mpoly_factor_get_exp_si(fmpz_mpoly_factor_t f, slong i, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_factor_sort(fmpz_mpoly_factor_t f, const fmpz_mpoly_ctx_t ctx) + int fmpz_mpoly_factor_squarefree(fmpz_mpoly_factor_t f, const fmpz_mpoly_t A, const fmpz_mpoly_ctx_t ctx) + int fmpz_mpoly_factor(fmpz_mpoly_factor_t f, const fmpz_mpoly_t A, const fmpz_mpoly_ctx_t ctx) diff --git a/src/flint/test/test.py b/src/flint/test/test.py index e14bd8aa..5b1e3287 100644 --- a/src/flint/test/test.py +++ b/src/flint/test/test.py @@ -1175,8 +1175,8 @@ def test_fmpq_mpoly(): assert ztype(3) - p1 == ctx.fmpq_mpoly_from_dict({(1,0):-4,(0,3):-4,(2,4):-9,(0,0):3}) assert p1 * ztype(3) == ctx.fmpq_mpoly_from_dict({(1,0):12,(0,3):12,(2,4):27}) assert ztype(3) * p1 == ctx.fmpq_mpoly_from_dict({(1,0):12,(0,3):12,(2,4):27}) - assert p1 // ztype(3) == ctx.fmpq_mpoly_from_dict({(1,0):1,(0,3):1,(2,4):3}) - assert ztype(3) // p1 == Zp(0,ctx) + # assert p1 // ztype(3) == ctx.fmpq_mpoly_from_dict({(1,0):1,(0,3):1,(2,4):3}) + # assert ztype(3) // p1 == Zp(0,ctx) assert ctx.constant(7) + ztype(3) == Zp(10, ctx) def test_fmpq_series(): @@ -1666,7 +1666,7 @@ def test_pickling(): test_fmpq, test_fmpq_poly, test_fmpq_mat, - # test_fmpq_mpoly, + test_fmpq_mpoly, test_fmpq_series, test_nmod, test_nmod_poly, diff --git a/src/flint/types/fmpq.pxd b/src/flint/types/fmpq.pxd index 3ef00f3c..efe0931f 100644 --- a/src/flint/types/fmpq.pxd +++ b/src/flint/types/fmpq.pxd @@ -3,6 +3,7 @@ from flint.flint_base.flint_base cimport flint_scalar from flint.flintlib.fmpq cimport fmpq_t cdef any_as_fmpq(obj) + cdef class fmpq(flint_scalar): cdef fmpq_t val diff --git a/src/flint/types/fmpq.pyx b/src/flint/types/fmpq.pyx index 83c9c4b5..05dfd71e 100644 --- a/src/flint/types/fmpq.pyx +++ b/src/flint/types/fmpq.pyx @@ -4,8 +4,8 @@ from flint.types.fmpz cimport fmpz_set_any_ref from flint.types.fmpz cimport fmpz from flint.types.fmpz cimport any_as_fmpz -from flint.flintlib.flint cimport FMPZ_UNKNOWN, FMPZ_TMP -from flint.flintlib.fmpz cimport fmpz_set, fmpz_one +from flint.flintlib.flint cimport FMPZ_UNKNOWN, FMPZ_TMP, FMPZ_REF +from flint.flintlib.fmpz cimport fmpz_set, fmpz_one, fmpz_t from flint.flintlib.fmpz cimport fmpz_is_zero, fmpz_sgn from flint.flintlib.fmpz cimport fmpz_fdiv_q, fmpz_bits from flint.flintlib.fmpz cimport fmpz_cdiv_q diff --git a/src/flint/types/fmpq_mpoly.pyx b/src/flint/types/fmpq_mpoly.pyx index 11922e15..d769b61b 100644 --- a/src/flint/types/fmpq_mpoly.pyx +++ b/src/flint/types/fmpq_mpoly.pyx @@ -1,4 +1,19 @@ +from cpython.dict cimport PyDict_Size, PyDict_Check, PyDict_Next +from cpython.tuple cimport PyTuple_Check, PyTuple_GET_SIZE +from flint.types.fmpq cimport any_as_fmpq, fmpq +from flint.types.fmpz cimport fmpz, fmpz_set_any_ref, any_as_fmpz +from flint.utils.typecheck cimport typecheck +from flint.utils.conversion cimport str_from_chars + +from flint.flintlib.flint cimport * +from flint.flintlib.fmpq cimport fmpq_init, fmpq_clear, fmpq_is_zero +from flint.flintlib.fmpz cimport fmpz_clear, fmpz_init +from flint.flintlib.fmpq_mpoly cimport * + + +cimport cython +cimport libc.stdlib cdef dict _fmpq_mpoly_ctx_cache = {} @@ -62,7 +77,7 @@ cdef class fmpq_mpoly_ctx(flint_mpoly_context): """ cdef fmpq_mpoly res assert i >= 0 and i < self.val.zctx.minfo.nvars - res = fmpq_mpoly.__new__(fmpz_mpoly) + res = fmpq_mpoly.__new__(fmpq_mpoly) res.ctx = self fmpq_mpoly_init(res.val, res.ctx.val) res._init = True @@ -77,77 +92,92 @@ cdef class fmpq_mpoly_ctx(flint_mpoly_context): z = any_as_fmpq(z) if z is NotImplemented: raise ValueError("A constant fmpq_mpoly is a fmpq") - res = fmpz_mpoly.__new__(fmpz_mpoly) + res = fmpq_mpoly.__new__(fmpq_mpoly) res.ctx = self - fmpz_mpoly_init(res.val, res.ctx.val) + fmpq_mpoly_init(res.val, res.ctx.val) res._init = True - fmpz_mpoly_set_fmpz(res.val, (z).val, res.ctx.val) + fmpq_mpoly_set_fmpq(res.val, (z).val, res.ctx.val) return res - def fmpz_mpoly_from_dict(self, d): + def fmpq_mpoly_from_dict(self, d): """ Create a fmpz_mpoly from a dictionary. The dictionary's keys are tuples of ints (or anything that implicitly converts - to fmpz) representing exponents, and corresponding values of fmpz. + to fmpz) representing exponents, and corresponding coefficient values of fmpq. >>> ctx = get_fmpz_mpoly_context(2,'lex','x,y') - >>> ctx.fmpz_mpoly_from_dict({(1,0):2, (1,1):3, (0,1):1}) + >>> ctx.fmpq_mpoly_from_dict({(1,0):2, (1,1):3, (0,1):1}) 3*x*y + 2*x + y """ cdef long n - cdef fmpz_t coefficient + cdef fmpq coefficient cdef fmpz_struct *exponents + cdef fmpz_struct **exp_ptr cdef int xtype cdef int nvars = self.nvars() cdef int i,j cdef int count - cdef fmpz_mpoly res + cdef fmpq_mpoly res if not PyDict_Check(d): raise ValueError("expected a dictionary") n = PyDict_Size(d) - fmpz_init(coefficient) exponents = libc.stdlib.calloc(nvars, sizeof(fmpz_struct)) if exponents == NULL: raise MemoryError() + exp_ptr = libc.stdlib.calloc(nvars, sizeof(fmpz_struct *)) + if exp_ptr == NULL: + libc.stdlib.free(exponents) + raise MemoryError() for i in range(nvars): fmpz_init(exponents + i) - fmpz_init(coefficient) - res = fmpz_mpoly.__new__(fmpz_mpoly) + exp_ptr[i] = exponents + i + # fmpq_init(coefficient) + res = fmpq_mpoly.__new__(fmpq_mpoly) res.ctx = self - fmpz_mpoly_init(res.val, res.ctx.val) + fmpq_mpoly_init(res.val, res.ctx.val) res._init = True count = 0 for k,v in d.items(): - xtype = fmpz_set_any_ref(coefficient, v) - if xtype == FMPZ_UNKNOWN: + coefficient = any_as_fmpq(v) + if coefficient == NotImplemented: + for i in range(nvars): + fmpz_clear(exponents + i) libc.stdlib.free(exponents) + libc.stdlib.free(exp_ptr) raise TypeError("invalid coefficient type %s" % type(v)) if not PyTuple_Check(k): + for i in range(nvars): + fmpz_clear(exponents + i) libc.stdlib.free(exponents) raise TypeError("Expected tuple of ints as key not %s" % type(k)) if PyTuple_GET_SIZE(k) != nvars: + for i in range(nvars): + fmpz_clear(exponents + i) libc.stdlib.free(exponents) raise TypeError("Expected exponent tuple of length %d" % nvars) for i,tup in enumerate(k): xtype = fmpz_set_any_ref(exponents + i, tup) if xtype == FMPZ_UNKNOWN: + for i in range(nvars): + fmpz_clear(exponents + i) libc.stdlib.free(exponents) raise TypeError("Invalid exponent type %s" % type(tup)) #Todo lobby for fmpz_mpoly_push_term_fmpz_ffmpz - if not fmpz_is_zero(coefficient): - _fmpz_mpoly_push_exp_ffmpz(res.val, exponents, self.val) - fmpz_mpoly_set_term_coeff_fmpz(res.val, count, coefficient, self.val) + if not fmpq_is_zero(coefficient.val): + fmpq_mpoly_push_term_fmpq_fmpz(res.val, coefficient.val, exp_ptr, self.val) + # _fmpq_mpoly_push_exp_ffmpz(res.val, exponents, self.val) + # fmpq_mpoly_set_term_coeff_fmpz(res.val, count, coefficient, self.val) count += 1 for i in range(nvars): fmpz_clear(exponents + i) - fmpz_clear(coefficient) - fmpz_mpoly_sort_terms(res.val, self.val) + fmpq_mpoly_sort_terms(res.val, self.val) + fmpq_mpoly_reduce(res.val, self.val) return res -def get_fmpz_mpoly_context(slong nvars=1, ordering="lex", names='x'): +def get_fmpq_mpoly_context(slong nvars=1, ordering="lex", names='x'): if nvars <= 0: nvars = 1 nametup = tuple(name.strip() for name in names.split(',')) @@ -156,8 +186,355 @@ def get_fmpz_mpoly_context(slong nvars=1, ordering="lex", names='x'): raise ValueError("Number of variables does not equal number of names") nametup = tuple(nametup[0] + str(i) for i in range(nvars)) key = (nvars, ordering, nametup) - ctx = _fmpz_mpoly_ctx_cache.get(key) + ctx = _fmpq_mpoly_ctx_cache.get(key) if ctx is None: - ctx = fmpz_mpoly_ctx(nvars, ordering, nametup) - _fmpz_mpoly_ctx_cache[key] = ctx + ctx = fmpq_mpoly_ctx(nvars, ordering, nametup) + _fmpq_mpoly_ctx_cache[key] = ctx return ctx + +cdef inline init_fmpq_mpoly(fmpq_mpoly var, fmpq_mpoly_ctx ctx): + var.ctx = ctx + fmpq_mpoly_init(var.val, ctx.val) + var._init = True + +cdef inline create_fmpq_mpoly(fmpq_mpoly_ctx ctx): + cdef fmpq_mpoly var + var = fmpq_mpoly.__new__(fmpq_mpoly) + var.ctx = ctx + fmpq_mpoly_init(var.val, ctx.val) + var._init = True + return var + + + + +cdef class fmpq_mpoly(flint_mpoly): + """ + The *fmpz_poly* type represents sparse multivariate polynomials over + the integers. + """ + + # cdef fmpz_mpoly_t val + # cdef fmpz_mpoly_ctx ctx + # cdef bint _init + + def __cinit__(self): + self._init = False + + def __dealloc__(self): + if self._init: + fmpq_mpoly_clear(self.val, self.ctx.val) + self._init = False + + def __init__(self, val=0, ctx=None): + if typecheck(val, fmpq_mpoly): + if ctx is None or ctx == (val).ctx: + init_fmpq_mpoly(self, (val).ctx) + fmpq_mpoly_set(self.val, (val).val, self.ctx.val) + else: + raise ValueError("Cannot automatically coerce contexts") + elif isinstance(val, dict): + if ctx is None: + if len(val) == 0: + raise ValueError("Need context for zero polynomial") + k = list(val.keys())[0] + if not isinstance(k, tuple): + raise ValueError("Dict should be keyed with tuples of integers") + ctx = get_fmpq_mpoly_context(len(k)) + x = ctx.fmpq_mpoly_from_dict(val) + #XXX this copy is silly, have a ctx function that assigns an fmpz_mpoly_t + init_fmpq_mpoly(self, ctx) + fmpq_mpoly_set(self.val, (x).val, self.ctx.val) + elif isinstance(val, str): + if ctx is None: + raise ValueError("Cannot parse a polynomial without context") + val = bytes(val, 'utf-8') + init_fmpq_mpoly(self, ctx) + fmpq_mpoly_set_str_pretty(self.val, val, self.ctx.c_names, self.ctx.val) + fmpq_mpoly_sort_terms(self.val, self.ctx.val) + else: + v = any_as_fmpz(val) + if v is NotImplemented: + raise TypeError("cannot create fmpz_mpoly from type %s" % type(val)) + if ctx is None: + raise ValueError("Need context to convert fmpz to fmpq_mpoly") + init_fmpq_mpoly(self, ctx) + fmpq_mpoly_set_fmpz(self.val, (v).val, self.ctx.val) + + def __nonzero__(self): + return not fmpq_mpoly_is_zero(self.val, self.ctx.val) + + def __bool__(self): + return not fmpq_mpoly_is_zero(self.val, self.ctx.val) + + def is_one(self): + return fmpq_mpoly_is_one(self.val, self.ctx.val) + + def __richcmp__(self, other, int op): + if op != 2 and op != 3: + return NotImplemented + if typecheck(self, fmpq_mpoly) and typecheck(other, fmpq_mpoly): + if (self).ctx is (other).ctx: + if op == 2: + return bool(fmpq_mpoly_equal((self).val, (other).val, (self).ctx.val)) + else: + return not bool(fmpq_mpoly_equal((self).val, (other).val, (self).ctx.val)) + else: + if op == 2: + return False + else: + return True + if op == 2: + return not bool(self - other) + else: + return bool(self - other) + + def __len__(self): + return fmpq_mpoly_length(self.val, self.ctx.val) + + def coefficient(self, slong i): + cdef fmpq v + if i < 0 or i >= fmpq_mpoly_length(self.val, self.ctx.val): + return fmpq(0) + else: + v = fmpq.__new__(fmpz) + fmpq_mpoly_get_term_coeff_fmpq(v.val, self.val, i, self.ctx.val) + return v + + def exponent_tuple(self, slong i): + cdef slong j, nvars + cdef fmpz_struct ** tmp + if i < 0 or i >= fmpq_mpoly_length(self.val, self.ctx.val): + raise ValueError + nvars = self.ctx.nvars() + res = tuple(fmpz() for j in range(nvars)) + tmp = libc.stdlib.malloc(nvars * sizeof(fmpz_struct **)) + try: + for j in range(nvars): + tmp[j] = &(( (res[j])).val[0]) + fmpq_mpoly_get_term_exp_fmpz(tmp, self.val, i, self.ctx.val) + finally: + libc.stdlib.free(tmp) + return res + + def repr(self): + return self.str() + " (nvars=%s, ordering=%s names=%s)" % (self.ctx.nvars(), self.ctx.ordering(), self.ctx.py_names) + + def str(self): + cdef char * s = fmpq_mpoly_get_str_pretty(self.val, self.ctx.c_names, self.ctx.val) + try: + res = str_from_chars(s) + finally: + libc.stdlib.free(s) + res = res.replace("+", " + ") + res = res.replace("-", " - ") + if res.startswith(" - "): + res = "-" + res[3:] + return res + + def __neg__(self): + cdef fmpq_mpoly res + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_neg(res.val, (self).val, res.ctx.val) + return res + + def __add__(self, other): + cdef fmpq_mpoly res + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_add(res.val, (self).val, (other).val, res.ctx.val) + return res + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_add_fmpq(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + + def __radd__(self, other): + cdef fmpq_mpoly res + other = any_as_fmpq(other) + if other is not NotImplemented: + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_add_fmpq(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + + def __iadd__(self, other): + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + fmpq_mpoly_add((self).val, (self).val, (other).val, self.ctx.val) + return self + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + fmpq_mpoly_add_fmpq((self).val, (self).val, (other).val, self.ctx.val) + return self + return NotImplemented + + def __sub__(self, other): + cdef fmpq_mpoly res + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_sub(res.val, (self).val, (other).val, res.ctx.val) + return res + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_sub_fmpq(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + + def __rsub__(self, other): + cdef fmpq_mpoly res + other = any_as_fmpq(other) + if other is not NotImplemented: + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_sub_fmpq(res.val, (self).val, (other).val, res.ctx.val) + return -res + return NotImplemented + + def __isub__(self, other): + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + fmpq_mpoly_sub((self).val, (self).val, (other).val, self.ctx.val) + return self + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + fmpq_mpoly_sub_fmpq((self).val, (self).val, (other).val, self.ctx.val) + return self + return NotImplemented + + def __mul__(self, other): + cdef fmpq_mpoly res + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_mul(res.val, (self).val, (other).val, res.ctx.val) + return res + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_scalar_mul_fmpq(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + + def __rmul__(self, other): + cdef fmpq_mpoly res + other = any_as_fmpq(other) + if other is not NotImplemented: + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_scalar_mul_fmpq(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + + def __imul__(self, other): + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + fmpq_mpoly_mul((self).val, (self).val, (other).val, self.ctx.val) + return self + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + fmpq_mpoly_scalar_mul_fmpq(self.val, (self).val, (other).val, self.ctx.val) + return self + return NotImplemented + + def __pow__(self, other, modulus): + cdef fmpq_mpoly res + if modulus is not None: + raise NotImplementedError + other = any_as_fmpz(other) + if other is NotImplemented: + return other + if other < 0: + raise ValueError("cannot raise fmpz_mpoly to negative power") + res = create_fmpq_mpoly(self.ctx) + if fmpq_mpoly_pow_fmpz(res.val, (self).val, (other).val, res.ctx.val) == 0: + raise ValueError("unreasonably large polynomial") + return res + + def __divmod__(self, other): + cdef fmpq_mpoly res, res2 + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = create_fmpq_mpoly(self.ctx) + res2 = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_divrem(res.val, res2.val, (self).val, (other).val, res.ctx.val) + return (res, res2) + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + other= fmpq_mpoly(other, self.ctx) + res = create_fmpq_mpoly(self.ctx) + res2 = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_divrem(res.val, res2.val, (self).val, (other).val, res.ctx.val) + return (res, res2) + return NotImplemented + + def __rdivmod__(self, other): + cdef fmpq_mpoly res, res2 + other = any_as_fmpq(other) + if other is not NotImplemented: + other = fmpq_mpoly(other, self.ctx) + res = create_fmpq_mpoly(self.ctx) + res2 = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_divrem(res.val, res2.val, (other).val, (self).val, res.ctx.val) + return res + return NotImplemented + + def __floordiv__(self, other): + cdef fmpq_mpoly res + if typecheck(other, fmpq_mpoly): + if (self).ctx is not (other).ctx: + return NotImplemented + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_div(res.val, (self).val, (other).val, res.ctx.val) + return res + else: + other = any_as_fmpq(other) + if other is not NotImplemented: + other = fmpq_mpoly(other, self.ctx) + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_div(res.val, (self).val, (other).val, res.ctx.val) + return res + return NotImplemented + + def __rfloordiv__(self,other): + cdef fmpq_mpoly res + other = any_as_fmpq(other) + if other is not NotImplemented: + other = fmpq_mpoly(other, self.ctx) + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_div(res.val, (other).val, self.val, res.ctx.val) + return res + return NotImplemented + + + def __mod__(self, other): + return divmod(self, other)[1] + + def gcd(self, other): + cdef fmpq_mpoly res + assert isinstance(other, fmpq_mpoly) + if (self).ctx is not (other).ctx: + return NotImplemented + res = create_fmpq_mpoly(self.ctx) + fmpq_mpoly_gcd(res.val, (self).val, (other).val, res.ctx.val) + return res + + + diff --git a/src/flint/types/fmpz_mpoly.pyx b/src/flint/types/fmpz_mpoly.pyx index 7958f584..04084543 100644 --- a/src/flint/types/fmpz_mpoly.pyx +++ b/src/flint/types/fmpz_mpoly.pyx @@ -14,7 +14,9 @@ from flint.types.fmpz cimport fmpz, fmpz_set_any_ref cimport cython cimport libc.stdlib +from flint.flintlib.fmpz cimport fmpz_set from flint.flintlib.fmpz_mpoly cimport * +from flint.flintlib.fmpz_mpoly_factor cimport * cdef any_as_fmpz_mpoly(x): cdef fmpz_mpoly res @@ -642,22 +644,30 @@ cdef class fmpz_mpoly(flint_mpoly): # finally: # libc.stdlib.free(C) - ''' def factor(self): """ Factors self into irreducible factors, returning a tuple (c, factors) where c is the content of the coefficients and factors is a list of (poly, exp) pairs. + >>> Zm = fmpz_mpoly + >>> ctx = get_fmpz_mpoly_context(3, 'lex', 'x,y,z') + >>> p1 = Zm("2*x + 4", ctx) + >>> p2 = Zm("3*x*z + + 3*x + 3*z + 3", ctx) + >>> (p1 * p2).factor() + (6, [(z + 1, 1), (x + 2, 1), (x + 1, 1)]) + >>> (p2 * p1 * p2).factor() + (18, [(z + 1, 2), (x + 2, 1), (x + 1, 2)]) + (18, [(x + 1, 1), (x*y + z + 1, 2)]) """ cdef fmpz_mpoly_factor_t fac cdef int i cdef fmpz c cdef fmpz_mpoly u fmpz_mpoly_factor_init(fac, self.ctx.val) - fmpz_mpoly_factor(fac, self.val, 1, self.ctx.val) - res = [0] * fac.length - for 0 <= i < fac.length: + fmpz_mpoly_factor(fac, self.val, self.ctx.val) + res = [0] * fac.num + for 0 <= i < fac.num: u = fmpz_mpoly.__new__(fmpz_mpoly) u.ctx = self.ctx fmpz_mpoly_init(u.val, u.ctx.val) @@ -667,8 +677,42 @@ cdef class fmpz_mpoly(flint_mpoly): fmpz_set((c).val, &fac.exp[i]) res[i] = (u, c) c = fmpz.__new__(fmpz) - fmpz_set((c).val, fac.content) # should be & with ... + fmpz_set((c).val, fac.constant) fmpz_mpoly_factor_clear(fac, self.ctx.val) return c, res - ''' + def factor_squarefree(self): + """ + Factors self into irreducible factors, returning a tuple + (c, factors) where c is the content of the coefficients and + factors is a list of (poly, exp) pairs. + + >>> Zm = fmpz_mpoly + >>> ctx = get_fmpz_mpoly_context(3, 'lex', 'x,y,z') + >>> p1 = Zm("2*x + 4", ctx) + >>> p2 = Zm("3*x*y + 3*x + 3*y + 3", ctx) + >>> (p1 * p2).factor_squarefree() + (6, [(x + 2, 1), (x*y + x + y + 1, 1)]) + >>> (p1 * p2 * p1).factor_squarefree() + (18, [(x + 2, 2), (x*y + x + y + 1, 1)]) + """ + cdef fmpz_mpoly_factor_t fac + cdef int i + cdef fmpz c + cdef fmpz_mpoly u + fmpz_mpoly_factor_init(fac, self.ctx.val) + fmpz_mpoly_factor_squarefree(fac, self.val, self.ctx.val) + res = [0] * fac.num + for 0 <= i < fac.num: + u = fmpz_mpoly.__new__(fmpz_mpoly) + u.ctx = self.ctx + fmpz_mpoly_init(u.val, u.ctx.val) + u._init = True + fmpz_mpoly_set((u).val, &fac.poly[i], self.ctx.val) + c = fmpz.__new__(fmpz) + fmpz_set((c).val, &fac.exp[i]) + res[i] = (u, c) + c = fmpz.__new__(fmpz) + fmpz_set((c).val, fac.constant) + fmpz_mpoly_factor_clear(fac, self.ctx.val) + return c, res From 7f9c1932634a756f82efb366a79299a075d3e836 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Fri, 22 Sep 2023 11:53:11 -0400 Subject: [PATCH 15/21] Added fmpq_mpoly to setup.py Forgot to add it to last commit --- setup.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index d8b1c043..b94b4d94 100644 --- a/setup.py +++ b/setup.py @@ -94,6 +94,7 @@ ("flint.types.acb_mat", ["src/flint/types/acb_mat.pyx"]), ("flint.types.acb_series", ["src/flint/types/acb_series.pyx"]), ("flint.types.fmpz_mpoly", ["src/flint/types/fmpz_mpoly.pyx"]), + ("flint.types.fmpq_mpoly", ["src/flint/types/fmpq_mpoly.pyx"]), ("flint.types.dirichlet", ["src/flint/types/dirichlet.pyx"]), ("flint.flint_base.flint_base", ["src/flint/flint_base/flint_base.pyx"]), ("flint.flint_base.flint_context", ["src/flint/flint_base/flint_context.pyx"]), @@ -104,8 +105,8 @@ ext_options = { "libraries" : libraries, - "library_dirs" : default_lib_dirs + ["/Users/davideinstein/opt/flint2.9/lib", "/Users/davideinstein/opt/arb/lib"], - "include_dirs" : default_include_dirs + ["/Users/davideinstein/opt/flint2.9/include", "/Users/davideinstein/opt/arb/include"], + "library_dirs" : default_lib_dirs, + "include_dirs" : default_include_dirs, "define_macros" : define_macros, } From ab7e1144c91e3a29cf5b31b4862250d65c863460 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Sat, 23 Sep 2023 22:19:49 -0400 Subject: [PATCH 16/21] Added factoring to fmpq_mpoly Also respliced fmpz_mpoly and fmpq_mpoly back into doctests. --- src/flint/flintlib/fmpq_mpoly_factor.pxd | 27 ++++++ src/flint/test/__main__.py | 2 + src/flint/types/fmpq_mpoly.pyx | 108 ++++++++++++++++++++--- src/flint/types/fmpz_mpoly.pyx | 5 +- 4 files changed, 125 insertions(+), 17 deletions(-) create mode 100644 src/flint/flintlib/fmpq_mpoly_factor.pxd diff --git a/src/flint/flintlib/fmpq_mpoly_factor.pxd b/src/flint/flintlib/fmpq_mpoly_factor.pxd new file mode 100644 index 00000000..3336acf6 --- /dev/null +++ b/src/flint/flintlib/fmpq_mpoly_factor.pxd @@ -0,0 +1,27 @@ +from flint.flintlib.fmpq cimport fmpq_t +from flint.flintlib.fmpz cimport fmpz_t +from flint.flintlib.fmpq_mpoly cimport fmpq_mpoly_ctx_t, fmpq_mpoly_t, fmpq_mpoly_struct +from flint.flintlib.flint cimport slong, fmpz_struct + +cdef extern from "flint/fmpq_mpoly_factor.h": + ctypedef struct fmpq_mpoly_factor_struct: + fmpq_t constant + fmpq_mpoly_struct * poly + fmpz_struct * exp + slong num + slong alloc + ctypedef fmpq_mpoly_factor_struct fmpq_mpoly_factor_t[1] + + void fmpq_mpoly_factor_init(fmpq_mpoly_factor_t f, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_factor_clear(fmpq_mpoly_factor_t f, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_factor_swap(fmpq_mpoly_factor_t f, fmpq_mpoly_factor_t g, const fmpq_mpoly_ctx_t ctx) + slong fmpq_mpoly_factor_length(const fmpq_mpoly_factor_t f, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_factor_get_constant_fmpq(fmpq_t c, const fmpq_mpoly_factor_t f, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_factor_get_base(fmpq_mpoly_t B, const fmpq_mpoly_factor_t f, slong i, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_factor_swap_base(fmpq_mpoly_t B, fmpq_mpoly_factor_t f, slong i, const fmpq_mpoly_ctx_t ctx) + slong fmpq_mpoly_factor_get_exp_si(fmpq_mpoly_factor_t f, slong i, const fmpq_mpoly_ctx_t ctx) + void fmpq_mpoly_factor_sort(fmpq_mpoly_factor_t f, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_factor_make_monic(fmpq_mpoly_factor_t f, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_factor_make_integral(fmpq_mpoly_factor_t f, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_factor_squarefree(fmpq_mpoly_factor_t f, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) + int fmpq_mpoly_factor(fmpq_mpoly_factor_t f, const fmpq_mpoly_t A, const fmpq_mpoly_ctx_t ctx) diff --git a/src/flint/test/__main__.py b/src/flint/test/__main__.py index 542d6739..c1466e1f 100644 --- a/src/flint/test/__main__.py +++ b/src/flint/test/__main__.py @@ -55,10 +55,12 @@ def run_doctests(verbose=None): flint.types.fmpz, flint.types.fmpz_poly, flint.types.fmpz_mat, + flint.types.fmpz_mpoly, flint.types.fmpz_series, flint.types.fmpq, flint.types.fmpq_poly, flint.types.fmpq_mat, + flint.types.fmpq_mpoly, flint.types.fmpq_series, flint.types.nmod, flint.types.nmod_poly, diff --git a/src/flint/types/fmpq_mpoly.pyx b/src/flint/types/fmpq_mpoly.pyx index d769b61b..712346a3 100644 --- a/src/flint/types/fmpq_mpoly.pyx +++ b/src/flint/types/fmpq_mpoly.pyx @@ -1,15 +1,22 @@ from cpython.dict cimport PyDict_Size, PyDict_Check, PyDict_Next from cpython.tuple cimport PyTuple_Check, PyTuple_GET_SIZE -from flint.types.fmpq cimport any_as_fmpq, fmpq +from flint.types.fmpq cimport any_as_fmpq, fmpq, fmpq_set_any_ref from flint.types.fmpz cimport fmpz, fmpz_set_any_ref, any_as_fmpz from flint.utils.typecheck cimport typecheck from flint.utils.conversion cimport str_from_chars from flint.flintlib.flint cimport * -from flint.flintlib.fmpq cimport fmpq_init, fmpq_clear, fmpq_is_zero -from flint.flintlib.fmpz cimport fmpz_clear, fmpz_init +from flint.flintlib.fmpq cimport fmpq_init, fmpq_clear, fmpq_is_zero, fmpq_set +from flint.flintlib.fmpz cimport fmpz_clear, fmpz_init, fmpz_set from flint.flintlib.fmpq_mpoly cimport * +from flint.flintlib.fmpq_mpoly_factor cimport * + +cdef extern from *: + """ + /* An ugly hack to get around the ugly hack of renaming fmpq to avoid a c/python name collision */ + typedef fmpq fmpq_struct; + """ cimport cython @@ -46,7 +53,7 @@ cdef class fmpq_mpoly_ctx(flint_mpoly_context): """ Return the number of variables in the context - >>> ctx = get_fmpz_mpoly_context(4, "lex", 'x') + >>> ctx = get_fmpq_mpoly_context(4, "lex", 'x') >>> ctx.nvars() 4 """ @@ -56,7 +63,7 @@ cdef class fmpq_mpoly_ctx(flint_mpoly_context): """ Return the term order of the context object. - >>> ctx = get_fmpz_mpoly_context(4, "deglex", 'w') + >>> ctx = get_fmpq_mpoly_context(4, "deglex", 'w') >>> ctx.ordering() 'deglex' """ @@ -71,7 +78,7 @@ cdef class fmpq_mpoly_ctx(flint_mpoly_context): """ Return the `i`th generator of the polynomial ring - >>> ctx = get_fmpz_mpoly_context(3, 'degrevlex', 'z') + >>> ctx = get_fmpq_mpoly_context(3, 'degrevlex', 'z') >>> ctx.gen(1) z1 """ @@ -106,15 +113,15 @@ cdef class fmpq_mpoly_ctx(flint_mpoly_context): The dictionary's keys are tuples of ints (or anything that implicitly converts to fmpz) representing exponents, and corresponding coefficient values of fmpq. - >>> ctx = get_fmpz_mpoly_context(2,'lex','x,y') + >>> ctx = get_fmpq_mpoly_context(2,'lex','x,y') >>> ctx.fmpq_mpoly_from_dict({(1,0):2, (1,1):3, (0,1):1}) - 3*x*y + 2*x + y + 3*x*y + 2*x + y """ cdef long n - cdef fmpq coefficient + cdef fmpq_t coefficient + cdef int xtype cdef fmpz_struct *exponents cdef fmpz_struct **exp_ptr - cdef int xtype cdef int nvars = self.nvars() cdef int i,j cdef int count @@ -140,8 +147,8 @@ cdef class fmpq_mpoly_ctx(flint_mpoly_context): res._init = True count = 0 for k,v in d.items(): - coefficient = any_as_fmpq(v) - if coefficient == NotImplemented: + xtype = fmpq_set_any_ref(coefficient, v) + if xtype == FMPZ_UNKNOWN: for i in range(nvars): fmpz_clear(exponents + i) libc.stdlib.free(exponents) @@ -165,8 +172,8 @@ cdef class fmpq_mpoly_ctx(flint_mpoly_context): libc.stdlib.free(exponents) raise TypeError("Invalid exponent type %s" % type(tup)) #Todo lobby for fmpz_mpoly_push_term_fmpz_ffmpz - if not fmpq_is_zero(coefficient.val): - fmpq_mpoly_push_term_fmpq_fmpz(res.val, coefficient.val, exp_ptr, self.val) + if not fmpq_is_zero(coefficient): + fmpq_mpoly_push_term_fmpq_fmpz(res.val, coefficient, exp_ptr, self.val) # _fmpq_mpoly_push_exp_ffmpz(res.val, exponents, self.val) # fmpq_mpoly_set_term_coeff_fmpz(res.val, count, coefficient, self.val) count += 1 @@ -538,3 +545,76 @@ cdef class fmpq_mpoly(flint_mpoly): + def factor(self): + """ + Factors self into irreducible factors, returning a tuple + (c, factors) where c is the content of the coefficients and + factors is a list of (poly, exp) pairs. + + >>> Zm = fmpq_mpoly + >>> ctx = get_fmpq_mpoly_context(3, 'lex', 'x,y,z') + >>> p1 = Zm("2*x + 4", ctx) + >>> p2 = Zm("3*x*z + + 3*x + 3*z + 3", ctx) + >>> (p1 * p2).factor() + (6, [(z + 1, 1), (x + 2, 1), (x + 1, 1)]) + >>> (p2 * p1 * p2).factor() + (18, [(z + 1, 2), (x + 2, 1), (x + 1, 2)]) + """ + cdef fmpq_mpoly_factor_t fac + cdef int i + cdef fmpq c + cdef fmpz exp + cdef fmpq_mpoly u + fmpq_mpoly_factor_init(fac, self.ctx.val) + fmpq_mpoly_factor(fac, self.val, self.ctx.val) + res = [0] * fac.num + for i in range(fac.num): + u = fmpq_mpoly.__new__(fmpq_mpoly) + u.ctx = self.ctx + fmpq_mpoly_init(u.val, u.ctx.val) + u._init = True + fmpq_mpoly_set((u).val, &fac.poly[i], self.ctx.val) + exp = fmpz.__new__(fmpz) + fmpz_set((exp).val, fac.exp + i) + res[i] = (u, exp) + c = fmpq.__new__(fmpq) + fmpq_set((c).val, fac.constant) + fmpq_mpoly_factor_clear(fac, self.ctx.val) + return c, res + + def factor_squarefree(self): + """ + Factors self into irreducible factors, returning a tuple + (c, factors) where c is the content of the coefficients and + factors is a list of (poly, exp) pairs. + + >>> Zm = fmpq_mpoly + >>> ctx = get_fmpq_mpoly_context(3, 'lex', 'x,y,z') + >>> p1 = Zm("2*x + 4", ctx) + >>> p2 = Zm("3*x*y + 3*x + 3*y + 3", ctx) + >>> (p1 * p2).factor_squarefree() + (6, [(y + 1, 1), (x^2 + 3*x + 2, 1)]) + >>> (p1 * p2 * p1).factor_squarefree() + (12, [(y + 1, 1), (x + 1, 1), (x + 2, 2)]) + """ + cdef fmpq_mpoly_factor_t fac + cdef int i + cdef fmpq c + cdef fmpz exp + cdef fmpq_mpoly u + fmpq_mpoly_factor_init(fac, self.ctx.val) + fmpq_mpoly_factor_squarefree(fac, self.val, self.ctx.val) + res = [0] * fac.num + for 0 <= i < fac.num: + u = fmpq_mpoly.__new__(fmpq_mpoly) + u.ctx = self.ctx + fmpq_mpoly_init(u.val, u.ctx.val) + u._init = True + fmpq_mpoly_set((u).val, &fac.poly[i], self.ctx.val) + exp = fmpz.__new__(fmpz) + fmpz_set((exp).val, fac.exp + i) + res[i] = (u, exp) + c = fmpq.__new__(fmpq) + fmpq_set((c).val, fac.constant) + fmpq_mpoly_factor_clear(fac, self.ctx.val) + return c, res diff --git a/src/flint/types/fmpz_mpoly.pyx b/src/flint/types/fmpz_mpoly.pyx index 04084543..682b2428 100644 --- a/src/flint/types/fmpz_mpoly.pyx +++ b/src/flint/types/fmpz_mpoly.pyx @@ -658,7 +658,6 @@ cdef class fmpz_mpoly(flint_mpoly): (6, [(z + 1, 1), (x + 2, 1), (x + 1, 1)]) >>> (p2 * p1 * p2).factor() (18, [(z + 1, 2), (x + 2, 1), (x + 1, 2)]) - (18, [(x + 1, 1), (x*y + z + 1, 2)]) """ cdef fmpz_mpoly_factor_t fac cdef int i @@ -692,9 +691,9 @@ cdef class fmpz_mpoly(flint_mpoly): >>> p1 = Zm("2*x + 4", ctx) >>> p2 = Zm("3*x*y + 3*x + 3*y + 3", ctx) >>> (p1 * p2).factor_squarefree() - (6, [(x + 2, 1), (x*y + x + y + 1, 1)]) + (6, [(y + 1, 1), (x^2 + 3*x + 2, 1)]) >>> (p1 * p2 * p1).factor_squarefree() - (18, [(x + 2, 2), (x*y + x + y + 1, 1)]) + (12, [(y + 1, 1), (x + 1, 1), (x + 2, 2)]) """ cdef fmpz_mpoly_factor_t fac cdef int i From 2ebf15d18853d0f8e3c26f449553847263fcfa3e Mon Sep 17 00:00:00 2001 From: David Einstein Date: Sun, 24 Sep 2023 10:54:51 -0400 Subject: [PATCH 17/21] Framing of fmpz_mpoly_q laid out. Added submodule to setup Added rational function class to flint_base Added interface to flintlib Added skeleton fmpz_mpoly_q to types --- setup.py | 1 + src/flint/flint_base/flint_base.pxd | 3 ++ src/flint/flint_base/flint_base.pyx | 4 +++ src/flint/flintlib/fmpz_mpoly_q.pxd | 53 +++++++++++++++++++++++++++++ src/flint/types/fmpz_mpoly_q.pxd | 9 +++++ src/flint/types/fmpz_mpoly_q.pyx | 35 +++++++++++++++++++ 6 files changed, 105 insertions(+) create mode 100644 src/flint/flintlib/fmpz_mpoly_q.pxd create mode 100644 src/flint/types/fmpz_mpoly_q.pxd create mode 100644 src/flint/types/fmpz_mpoly_q.pyx diff --git a/setup.py b/setup.py index f84964c9..97ea040c 100644 --- a/setup.py +++ b/setup.py @@ -95,6 +95,7 @@ ("flint.types.acb_series", ["src/flint/types/acb_series.pyx"]), ("flint.types.fmpz_mpoly", ["src/flint/types/fmpz_mpoly.pyx"]), ("flint.types.fmpq_mpoly", ["src/flint/types/fmpq_mpoly.pyx"]), + ("flint.types.fmpz_mpoly_q", ["src/flint/types/fmpz_mpoly_q.pyx"]), ("flint.types.fmpz_mod", ["src/flint/types/fmpz_mod.pyx"]), ("flint.types.dirichlet", ["src/flint/types/dirichlet.pyx"]), ("flint.flint_base.flint_base", ["src/flint/flint_base/flint_base.pyx"]), diff --git a/src/flint/flint_base/flint_base.pxd b/src/flint/flint_base/flint_base.pxd index f6b0f7e8..6cbb465b 100644 --- a/src/flint/flint_base/flint_base.pxd +++ b/src/flint/flint_base/flint_base.pxd @@ -20,3 +20,6 @@ cdef class flint_mat(flint_elem): cdef class flint_series(flint_elem): pass + +cdef class flint_rational_function(flint_elem): + pass diff --git a/src/flint/flint_base/flint_base.pyx b/src/flint/flint_base/flint_base.pyx index 29096292..7fb47a12 100644 --- a/src/flint/flint_base/flint_base.pyx +++ b/src/flint/flint_base/flint_base.pyx @@ -218,3 +218,7 @@ cdef class flint_mat(flint_elem): # supports mpmath conversions tolist = table + + +cdef class flint_rational_function(flint_elem): + pass diff --git a/src/flint/flintlib/fmpz_mpoly_q.pxd b/src/flint/flintlib/fmpz_mpoly_q.pxd new file mode 100644 index 00000000..87605c52 --- /dev/null +++ b/src/flint/flintlib/fmpz_mpoly_q.pxd @@ -0,0 +1,53 @@ +from flint.flintlib.flint cimport mp_limb_t, flint_rand_t, slong +from flint.flintlib.fmpq cimport fmpq_t +from flint.flintlib.fmpz cimport fmpz_t +from flint.flintlib.fmpz_mpoly cimport fmpz_mpoly_ctx_t, fmpz_mpoly_t, fmpz_mpoly_struct + +cdef extern from "flint/fmpz_mpoly_q.h": + ctypedef struct fmpz_mpoly_q_struct: + fmpz_mpoly_struct num + fmpz_mpoly_struct num + ctypedef fmpz_mpoly_q_struct fmpz_mpoly_q_t[1] + + fmpz_mpoly_struct * fmpz_mpoly_q_numref(fmpz_mpoly_q_t x) + fmpz_mpoly_struct * fmpz_mpoly_q_denref(fmpz_mpoly_q_t x) + void fmpz_mpoly_q_init(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_clear(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_swap(fmpz_mpoly_q_t x, fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_set(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_set_fmpq(fmpz_mpoly_q_t res, const fmpq_t x, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_set_fmpz(fmpz_mpoly_q_t res, const fmpz_t x, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_set_si(fmpz_mpoly_q_t res, slong x, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_canonicalise(fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) + int fmpz_mpoly_q_is_canonical(const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) + int fmpz_mpoly_q_is_zero(const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) + int fmpz_mpoly_q_is_one(const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_used_vars(int * used, const fmpz_mpoly_q_t f, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_used_vars_num(int * used, const fmpz_mpoly_q_t f, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_used_vars_den(int * used, const fmpz_mpoly_q_t f, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_zero(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_one(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_gen(fmpz_mpoly_q_t res, slong i, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_print_pretty(const fmpz_mpoly_q_t f, const char ** x, fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_randtest(fmpz_mpoly_q_t res, flint_rand_t state, slong length, mp_limb_t coeff_bits, slong exp_bound, const fmpz_mpoly_ctx_t ctx) + int fmpz_mpoly_q_equal(const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_neg(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_add(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_add_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_add_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_add_si(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, slong y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_sub(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_sub_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_sub_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_sub_si(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, slong y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_mul(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_mul_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_mul_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_mul_si(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, slong y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_div(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_div_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_div_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_div_si(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, slong y, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_inv(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) + void _fmpz_mpoly_q_content(fmpz_t num, fmpz_t den, const fmpz_mpoly_t xnum, const fmpz_mpoly_t xden, const fmpz_mpoly_ctx_t ctx) + void fmpz_mpoly_q_content(fmpq_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) diff --git a/src/flint/types/fmpz_mpoly_q.pxd b/src/flint/types/fmpz_mpoly_q.pxd new file mode 100644 index 00000000..c80a7fde --- /dev/null +++ b/src/flint/types/fmpz_mpoly_q.pxd @@ -0,0 +1,9 @@ +from flint.flint_base.flint_base cimport flint_rational_function +from flint.flintlib.fmpz_mpoly_q cimport fmpz_mpoly_q_t + +from flint.types.fmpz_mpoly cimport fmpz_mpoly, fmpz_mpoly_ctx + +cdef class fmpz_mpoly_q(flint_rational_function): + cdef fmpz_mpoly_q_t fraction + cdef fmpz_mpoly_ctx ctx + cdef bint _init diff --git a/src/flint/types/fmpz_mpoly_q.pyx b/src/flint/types/fmpz_mpoly_q.pyx new file mode 100644 index 00000000..768d59ca --- /dev/null +++ b/src/flint/types/fmpz_mpoly_q.pyx @@ -0,0 +1,35 @@ +from flint.flint_base.flint_base cimport flint_rational_function +from flint.utils.typecheck cimport typecheck +from flint.flintlib.fmpz_mpoly cimport fmpz_mpoly_set +from flint.flintlib.fmpz_mpoly_q cimport * +from flint.types.fmpz_mpoly cimport fmpz_mpoly, fmpz_mpoly_ctx + + + +cdef class fmpz_mpoly_q(flint_rational_function): + """ + The `fmpz_mpoly_q` represents multivariate rational functions + over the integers + """ + def __cinit__(self): + self._init = False + + def __dealloc__(self): + if self._init: + fmpz_mpoly_q_clear(self.fraction, self.ctx.val) + self._init = False + + def __init__(self, num, den): + if typecheck(num, fmpz_mpoly) and typecheck(den, fmpz_mpoly): + if (num).ctx == (den).ctx: + self.ctx = (num).ctx + fmpz_mpoly_q_init(self.fraction, self.ctx.val) + fmpz_mpoly_set(fmpz_mpoly_q_numref(self.fraction), + (num).val, self.ctx.val) + fmpz_mpoly_set(fmpz_mpoly_q_denref(self.fraction), + (den).val, self.ctx.val) + self._init = True + else: + raise ValueError("numerator and denominator must have identical contexts") + else: + raise TypeError("fmpz_mpoly_q is a fraction of two fmpz_mpolys fs") From ca4391d355f806b7c63ff7a56674183f3fc5aa32 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Sun, 24 Sep 2023 12:18:05 -0400 Subject: [PATCH 18/21] Fixed small bugs in fmpz_mpoly and fmpq_mpoly Added missing fmpz_clear for exponents in creating fmpz_mpoly from dictionary Fixed spacing in converting fmpq_mpoly to string --- src/flint/types/fmpq_mpoly.pyx | 12 +++++------- src/flint/types/fmpz_mpoly.pyx | 12 ++++++++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/flint/types/fmpq_mpoly.pyx b/src/flint/types/fmpq_mpoly.pyx index 712346a3..48937526 100644 --- a/src/flint/types/fmpq_mpoly.pyx +++ b/src/flint/types/fmpq_mpoly.pyx @@ -115,7 +115,7 @@ cdef class fmpq_mpoly_ctx(flint_mpoly_context): >>> ctx = get_fmpq_mpoly_context(2,'lex','x,y') >>> ctx.fmpq_mpoly_from_dict({(1,0):2, (1,1):3, (0,1):1}) - 3*x*y + 2*x + y + 3*x*y + 2*x + y """ cdef long n cdef fmpq_t coefficient @@ -333,8 +333,6 @@ cdef class fmpq_mpoly(flint_mpoly): res = str_from_chars(s) finally: libc.stdlib.free(s) - res = res.replace("+", " + ") - res = res.replace("-", " - ") if res.startswith(" - "): res = "-" + res[3:] return res @@ -556,9 +554,9 @@ cdef class fmpq_mpoly(flint_mpoly): >>> p1 = Zm("2*x + 4", ctx) >>> p2 = Zm("3*x*z + + 3*x + 3*z + 3", ctx) >>> (p1 * p2).factor() - (6, [(z + 1, 1), (x + 2, 1), (x + 1, 1)]) + (6, [(z + 1, 1), (x + 2, 1), (x + 1, 1)]) >>> (p2 * p1 * p2).factor() - (18, [(z + 1, 2), (x + 2, 1), (x + 1, 2)]) + (18, [(z + 1, 2), (x + 2, 1), (x + 1, 2)]) """ cdef fmpq_mpoly_factor_t fac cdef int i @@ -593,9 +591,9 @@ cdef class fmpq_mpoly(flint_mpoly): >>> p1 = Zm("2*x + 4", ctx) >>> p2 = Zm("3*x*y + 3*x + 3*y + 3", ctx) >>> (p1 * p2).factor_squarefree() - (6, [(y + 1, 1), (x^2 + 3*x + 2, 1)]) + (6, [(y + 1, 1), (x^2 + 3*x + 2, 1)]) >>> (p1 * p2 * p1).factor_squarefree() - (12, [(y + 1, 1), (x + 1, 1), (x + 2, 2)]) + (12, [(y + 1, 1), (x + 1, 1), (x + 2, 2)]) """ cdef fmpq_mpoly_factor_t fac cdef int i diff --git a/src/flint/types/fmpz_mpoly.pyx b/src/flint/types/fmpz_mpoly.pyx index 682b2428..088792c9 100644 --- a/src/flint/types/fmpz_mpoly.pyx +++ b/src/flint/types/fmpz_mpoly.pyx @@ -70,8 +70,6 @@ cdef class fmpz_mpoly_ctx(flint_mpoly_context): Do not construct one of these directly, use `get_fmpz_mpoly_context`. """ -# cdef fmpz_mpoly_ctx_t val - def __init__(self, slong nvars, ordering, names): if ordering == "lex": fmpz_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_LEX) @@ -81,7 +79,6 @@ cdef class fmpz_mpoly_ctx(flint_mpoly_context): fmpz_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_DEGREVLEX) else: raise ValueError("Unimplemented term order %s" % ordering) - super().__init__(nvars, names) cpdef slong nvars(self): @@ -179,17 +176,25 @@ cdef class fmpz_mpoly_ctx(flint_mpoly_context): for k,v in d.items(): xtype = fmpz_set_any_ref(coefficient, v) if xtype == FMPZ_UNKNOWN: + for i in range(nvars): + fmpz_clear(exponents + i) libc.stdlib.free(exponents) raise TypeError("invalid coefficient type %s" % type(v)) if not PyTuple_Check(k): + for i in range(nvars): + fmpz_clear(exponents + i) libc.stdlib.free(exponents) raise TypeError("Expected tuple of ints as key not %s" % type(k)) if PyTuple_GET_SIZE(k) != nvars: + for i in range(nvars): + fmpz_clear(exponents + i) libc.stdlib.free(exponents) raise TypeError("Expected exponent tuple of length %d" % nvars) for i,tup in enumerate(k): xtype = fmpz_set_any_ref(exponents + i, tup) if xtype == FMPZ_UNKNOWN: + for i in range(nvars): + fmpz_clear(exponents + i) libc.stdlib.free(exponents) raise TypeError("Invalid exponent type %s" % type(tup)) #Todo lobby for fmpz_mpoly_push_term_fmpz_ffmpz @@ -270,7 +275,6 @@ cdef inline create_fmpz_mpoly(fmpz_mpoly_ctx ctx): var._init = True return var - # todo: store cached context objects externally cdef class fmpz_mpoly(flint_mpoly): """ From 13136376b69297c75f10b347f9692d2eee0f61b6 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Sat, 30 Sep 2023 11:21:07 -0400 Subject: [PATCH 19/21] Added printing of fmpz_mpoly_q --- src/flint/__init__.py | 1 + src/flint/flintlib/fmpz_mpoly_q.pxd | 2 +- src/flint/types/fmpz_mpoly.pyx | 1 + src/flint/types/fmpz_mpoly_q.pyx | 59 ++++++++++++++++++++++++++++- 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/flint/__init__.py b/src/flint/__init__.py index 89d21e4c..b5c90387 100644 --- a/src/flint/__init__.py +++ b/src/flint/__init__.py @@ -23,6 +23,7 @@ from .types.fmpz_mpoly import * from .types.fmpq_mpoly import * from .types.fmpz_mod import * +from .types.fmpz_mpoly_q import * from .types.dirichlet import * from .functions.showgood import showgood diff --git a/src/flint/flintlib/fmpz_mpoly_q.pxd b/src/flint/flintlib/fmpz_mpoly_q.pxd index 87605c52..682e4263 100644 --- a/src/flint/flintlib/fmpz_mpoly_q.pxd +++ b/src/flint/flintlib/fmpz_mpoly_q.pxd @@ -6,7 +6,7 @@ from flint.flintlib.fmpz_mpoly cimport fmpz_mpoly_ctx_t, fmpz_mpoly_t, fmpz_mpol cdef extern from "flint/fmpz_mpoly_q.h": ctypedef struct fmpz_mpoly_q_struct: fmpz_mpoly_struct num - fmpz_mpoly_struct num + fmpz_mpoly_struct den ctypedef fmpz_mpoly_q_struct fmpz_mpoly_q_t[1] fmpz_mpoly_struct * fmpz_mpoly_q_numref(fmpz_mpoly_q_t x) diff --git a/src/flint/types/fmpz_mpoly.pyx b/src/flint/types/fmpz_mpoly.pyx index 088792c9..beb12175 100644 --- a/src/flint/types/fmpz_mpoly.pyx +++ b/src/flint/types/fmpz_mpoly.pyx @@ -275,6 +275,7 @@ cdef inline create_fmpz_mpoly(fmpz_mpoly_ctx ctx): var._init = True return var + # todo: store cached context objects externally cdef class fmpz_mpoly(flint_mpoly): """ diff --git a/src/flint/types/fmpz_mpoly_q.pyx b/src/flint/types/fmpz_mpoly_q.pyx index 768d59ca..939c3ebc 100644 --- a/src/flint/types/fmpz_mpoly_q.pyx +++ b/src/flint/types/fmpz_mpoly_q.pyx @@ -1,9 +1,21 @@ from flint.flint_base.flint_base cimport flint_rational_function from flint.utils.typecheck cimport typecheck -from flint.flintlib.fmpz_mpoly cimport fmpz_mpoly_set +from flint.flintlib.fmpz_mpoly cimport fmpz_mpoly_set, fmpz_mpoly_get_str_pretty from flint.flintlib.fmpz_mpoly_q cimport * from flint.types.fmpz_mpoly cimport fmpz_mpoly, fmpz_mpoly_ctx +cdef inline init_fmpz_mpoly_q(fmpz_mpoly_q var, fmpz_mpoly_ctx ctx): + var.ctx = ctx + fmpz_mpoly_q_init(var.fraction, ctx.val) + var._init = True + +cdef inline create_fmpz_mpoly_q(fmpz_mpoly_ctx ctx): + cdef fmpz_mpoly_q var + var = fmpz_mpoly_q.__new__(fmpz_mpoly_q) + var.ctx = ctx + fmpz_mpoly_q_init(var.fraction, ctx.val) + var._init = True + return var cdef class fmpz_mpoly_q(flint_rational_function): @@ -33,3 +45,48 @@ cdef class fmpz_mpoly_q(flint_rational_function): raise ValueError("numerator and denominator must have identical contexts") else: raise TypeError("fmpz_mpoly_q is a fraction of two fmpz_mpolys fs") + + + def __nonzero__(self): + return not fmpz_mpoly_q_is_zero(self.fraction, self.ctx.val) + + def __bool__(self): + return not fmpz_mpoly_q_is_zero(self.fraction, self.ctx.val) + + def is_one(self): + return fmpz_mpoly_q_is_one(self.fraction, self.ctx.val) + + def __richcmp__(self, other, int op): + if op != 2 and op != 3: + return NotImplemented + if typecheck(self, fmpz_mpoly_q) and typecheck(other, fmpz_mpoly_q): + if ( self).ctx is ( other).ctx: + if op == 2: + return bool(fmpz_mpoly_q_equal((self).fraction, (other).fraction, self.ctx.val)) + else: + return not bool(fmpz_mpoly_q_equal((self).fraction, (other).fraction, self.ctx.val)) + else: + if op == 2: + return False + else: + return True + if op == 2: + return not bool(self - other) + else: + return bool(self - other) + + def repr(self): + return self.str() + " (nvars=%s, ordering=%s names=%s)" % (self.ctx.nvars(), self.ctx.ordering(), self.ctx.py_names) + + def str(self): + cdef bytes numerator = fmpz_mpoly_get_str_pretty(&(self.fraction.num), self.ctx.c_names, self.ctx.val) + cdef bytes denominator = fmpz_mpoly_get_str_pretty(&(self.fraction.den), self.ctx.c_names, self.ctx.val) + res = str(b"(" + numerator + b")/(" + denominator + b")", encoding='utf-8') + res = res.replace("+", " + ") + res = res.replace("-", " - ") + return res + + def __neg__(self): + cdef fmpz_mpoly_q res + res = create_fmpz_mpoly_q(self.ctx) + fmpz_mpoly_q_neg(res.fraction, self.fraction, res.ctx.val) From 80b132535638218e1494313095e5664643ba3b0f Mon Sep 17 00:00:00 2001 From: David Einstein Date: Sun, 8 Oct 2023 21:58:29 -0400 Subject: [PATCH 20/21] Added operations on fmpz_mpoly that return fmpq_mpoly of fmpz_mpoly_q also basic ops on fmpz_mpoly_q --- src/flint/types/fmpq_mpoly.pxd | 20 +++++- src/flint/types/fmpq_mpoly.pyx | 57 ++++++++++----- src/flint/types/fmpz_mpoly.pxd | 15 +++- src/flint/types/fmpz_mpoly.pyx | 119 +++++++++++++++++++++++-------- src/flint/types/fmpz_mpoly_q.pyx | 48 ++++++++++++- 5 files changed, 208 insertions(+), 51 deletions(-) diff --git a/src/flint/types/fmpq_mpoly.pxd b/src/flint/types/fmpq_mpoly.pxd index 04a4cdb7..8240e736 100644 --- a/src/flint/types/fmpq_mpoly.pxd +++ b/src/flint/types/fmpq_mpoly.pxd @@ -1,10 +1,26 @@ from flint.flint_base.flint_base cimport flint_mpoly from flint.flint_base.flint_base cimport flint_mpoly_context -from flint.flintlib.fmpq_mpoly cimport fmpq_mpoly_ctx_t -from flint.flintlib.fmpq_mpoly cimport fmpq_mpoly_t +from flint.flintlib.fmpq_mpoly cimport * from flint.flintlib.flint cimport slong +from flint.types.fmpz_mpoly cimport fmpz_mpoly_ctx + +cdef inline init_fmpq_mpoly(fmpq_mpoly var, fmpq_mpoly_ctx ctx): + var.ctx = ctx + fmpq_mpoly_init(var.val, ctx.val) + var._init = True + +cdef inline create_fmpq_mpoly(fmpq_mpoly_ctx ctx): + cdef fmpq_mpoly var + var = fmpq_mpoly.__new__(fmpq_mpoly) + var.ctx = ctx + fmpq_mpoly_init(var.val, ctx.val) + var._init = True + return var + +cdef fmpq_mpoly_ctx create_fmpq_mpoly_ctx_from_fmpz_mpoly_ctx(fmpz_mpoly_ctx ctx) + cdef class fmpq_mpoly_ctx(flint_mpoly_context): cdef fmpq_mpoly_ctx_t val cpdef slong nvars(self) diff --git a/src/flint/types/fmpq_mpoly.pyx b/src/flint/types/fmpq_mpoly.pyx index 48937526..f2064cdf 100644 --- a/src/flint/types/fmpq_mpoly.pyx +++ b/src/flint/types/fmpq_mpoly.pyx @@ -7,11 +7,14 @@ from flint.utils.typecheck cimport typecheck from flint.utils.conversion cimport str_from_chars from flint.flintlib.flint cimport * -from flint.flintlib.fmpq cimport fmpq_init, fmpq_clear, fmpq_is_zero, fmpq_set +from flint.flintlib.fmpq cimport fmpq_init, fmpq_clear, fmpq_is_zero, fmpq_set, fmpq_one from flint.flintlib.fmpz cimport fmpz_clear, fmpz_init, fmpz_set +from flint.flintlib.fmpz_mpoly cimport fmpz_mpoly_set from flint.flintlib.fmpq_mpoly cimport * from flint.flintlib.fmpq_mpoly_factor cimport * +from flint.types.fmpz_mpoly cimport fmpz_mpoly, fmpz_mpoly_ctx + cdef extern from *: """ /* An ugly hack to get around the ugly hack of renaming fmpq to avoid a c/python name collision */ @@ -184,14 +187,18 @@ cdef class fmpq_mpoly_ctx(flint_mpoly_context): return res -def get_fmpq_mpoly_context(slong nvars=1, ordering="lex", names='x'): +def get_fmpq_mpoly_context(slong nvars=1, ordering="lex", names='x', nametup=None): if nvars <= 0: nvars = 1 - nametup = tuple(name.strip() for name in names.split(',')) - if len(nametup) != nvars: - if len(nametup) != 1: + if nametup is None: + nametup = tuple(name.strip() for name in names.split(',')) + if len(nametup) != nvars: + if len(nametup) != 1: + raise ValueError("Number of variables does not equal number of names") + nametup = tuple(nametup[0] + str(i) for i in range(nvars)) + else: + if len(nametup) != nvars: raise ValueError("Number of variables does not equal number of names") - nametup = tuple(nametup[0] + str(i) for i in range(nvars)) key = (nvars, ordering, nametup) ctx = _fmpq_mpoly_ctx_cache.get(key) if ctx is None: @@ -199,18 +206,25 @@ def get_fmpq_mpoly_context(slong nvars=1, ordering="lex", names='x'): _fmpq_mpoly_ctx_cache[key] = ctx return ctx -cdef inline init_fmpq_mpoly(fmpq_mpoly var, fmpq_mpoly_ctx ctx): - var.ctx = ctx - fmpq_mpoly_init(var.val, ctx.val) - var._init = True +cdef fmpq_mpoly_ctx create_fmpq_mpoly_ctx_from_fmpz_mpoly_ctx(fmpz_mpoly_ctx ctx): + return get_fmpq_mpoly_context(nvars=ctx.nvars(), ordering=ctx.ordering(), names=None, + nametup=tuple(str(s, 'utf-8') for s in ctx.py_names)) + + + -cdef inline create_fmpq_mpoly(fmpq_mpoly_ctx ctx): - cdef fmpq_mpoly var - var = fmpq_mpoly.__new__(fmpq_mpoly) - var.ctx = ctx - fmpq_mpoly_init(var.val, ctx.val) - var._init = True - return var +# cdef inline init_fmpq_mpoly(fmpq_mpoly var, fmpq_mpoly_ctx ctx): +# var.ctx = ctx +# fmpq_mpoly_init(var.val, ctx.val) +# var._init = True + +# cdef inline create_fmpq_mpoly(fmpq_mpoly_ctx ctx): +# cdef fmpq_mpoly var +# var = fmpq_mpoly.__new__(fmpq_mpoly) +# var.ctx = ctx +# fmpq_mpoly_init(var.val, ctx.val) +# var._init = True +# return var @@ -240,6 +254,15 @@ cdef class fmpq_mpoly(flint_mpoly): fmpq_mpoly_set(self.val, (val).val, self.ctx.val) else: raise ValueError("Cannot automatically coerce contexts") + if typecheck(val, fmpz_mpoly): + if ctx is None: + ctx = create_fmpq_mpoly_ctx_from_fmpz_mpoly_ctx((val).ctx) + elif ctx != create_fmpq_mpoly_ctx_from_fmpz_mpoly_ctx((val).ctx): + raise ValueError("Cannot automatically coerce contexts") + init_fmpq_mpoly(self, ctx) + fmpz_mpoly_set(self.val.zpoly, (val).val, ( val).ctx.val) + fmpq_one(self.val.content) + fmpq_mpoly_reduce(self.val, self.ctx.val) elif isinstance(val, dict): if ctx is None: if len(val) == 0: diff --git a/src/flint/types/fmpz_mpoly.pxd b/src/flint/types/fmpz_mpoly.pxd index a33d6f00..c3e47a23 100644 --- a/src/flint/types/fmpz_mpoly.pxd +++ b/src/flint/types/fmpz_mpoly.pxd @@ -2,9 +2,22 @@ from flint.flint_base.flint_base cimport flint_mpoly from flint.flint_base.flint_base cimport flint_mpoly_context from flint.flintlib.fmpz_mpoly cimport fmpz_mpoly_ctx_t -from flint.flintlib.fmpz_mpoly cimport fmpz_mpoly_t +from flint.flintlib.fmpz_mpoly cimport fmpz_mpoly_t, fmpz_mpoly_init from flint.flintlib.flint cimport slong +cdef inline init_fmpz_mpoly(fmpz_mpoly var, fmpz_mpoly_ctx ctx): + var.ctx = ctx + fmpz_mpoly_init(var.val, ctx.val) + var._init = True + +cdef inline create_fmpz_mpoly(fmpz_mpoly_ctx ctx): + cdef fmpz_mpoly var + var = fmpz_mpoly.__new__(fmpz_mpoly) + var.ctx = ctx + fmpz_mpoly_init(var.val, ctx.val) + var._init = True + return var + cdef class fmpz_mpoly_ctx(flint_mpoly_context): cdef fmpz_mpoly_ctx_t val cpdef slong nvars(self) diff --git a/src/flint/types/fmpz_mpoly.pyx b/src/flint/types/fmpz_mpoly.pyx index beb12175..b4ea3938 100644 --- a/src/flint/types/fmpz_mpoly.pyx +++ b/src/flint/types/fmpz_mpoly.pyx @@ -2,6 +2,7 @@ from cpython.version cimport PY_MAJOR_VERSION from cpython.dict cimport PyDict_Size, PyDict_Check, PyDict_Next from cpython.tuple cimport PyTuple_Check, PyTuple_GET_SIZE from flint.flintlib.fmpz cimport fmpz_init, fmpz_clear, fmpz_is_zero +from flint.flintlib.fmpq_mpoly cimport fmpq_mpoly_t, fmpq_mpoly_add_fmpq, fmpq_mpoly_sub_fmpq, fmpq_mpoly_scalar_mul_fmpq from flint.flintlib.flint cimport * from flint.utils.conversion cimport str_from_chars @@ -10,6 +11,9 @@ from flint.flint_base.flint_base cimport flint_mpoly from flint.flint_base.flint_base cimport flint_mpoly_context from flint.types.fmpz cimport any_as_fmpz from flint.types.fmpz cimport fmpz, fmpz_set_any_ref +from flint.types.fmpq cimport any_as_fmpq, fmpq_set_any_ref +from flint.types.fmpq_mpoly cimport fmpq_mpoly +from flint.types.fmpz_mpoly_q cimport fmpz_mpoly_q cimport cython @@ -18,6 +22,13 @@ from flint.flintlib.fmpz cimport fmpz_set from flint.flintlib.fmpz_mpoly cimport * from flint.flintlib.fmpz_mpoly_factor cimport * +cdef extern from *: + """ + /* An ugly hack to get around the ugly hack of renaming fmpq to avoid a c/python name collision */ + typedef fmpq fmpq_struct; + """ + + cdef any_as_fmpz_mpoly(x): cdef fmpz_mpoly res """ @@ -262,18 +273,6 @@ def get_fmpz_mpoly_context(slong nvars=1, ordering="lex", names='x'): # _fmpz_mpoly_set2(( args2[i]).val, ctx.val, ( args[i]).val, ( args[i]).ctx.val) # return ctx, args2 -cdef inline init_fmpz_mpoly(fmpz_mpoly var, fmpz_mpoly_ctx ctx): - var.ctx = ctx - fmpz_mpoly_init(var.val, ctx.val) - var._init = True - -cdef inline create_fmpz_mpoly(fmpz_mpoly_ctx ctx): - cdef fmpz_mpoly var - var = fmpz_mpoly.__new__(fmpz_mpoly) - var.ctx = ctx - fmpz_mpoly_init(var.val, ctx.val) - var._init = True - return var # todo: store cached context objects externally @@ -409,6 +408,10 @@ cdef class fmpz_mpoly(flint_mpoly): def __add__(self, other): cdef fmpz_mpoly res + cdef fmpq_mpoly qres + cdef fmpz_t z_other + cdef fmpq_t q_other + cdef int xtype if typecheck(other, fmpz_mpoly): if (self).ctx is not (other).ctx: return NotImplemented @@ -416,20 +419,35 @@ cdef class fmpz_mpoly(flint_mpoly): fmpz_mpoly_add(res.val, (self).val, (other).val, res.ctx.val) return res else: - other = any_as_fmpz(other) - if other is not NotImplemented: + xtype = fmpz_set_any_ref(z_other, other) + if xtype != FMPZ_UNKNOWN: res = create_fmpz_mpoly(self.ctx) - fmpz_mpoly_add_fmpz(res.val, (self).val, (other).val, res.ctx.val) + fmpz_mpoly_add_fmpz(res.val, (self).val, z_other, res.ctx.val) return res + xtype = fmpq_set_any_ref(q_other, other) + if xtype != FMPZ_UNKNOWN: + qres = fmpq_mpoly(self) + fmpq_mpoly_add_fmpq(qres.val, qres.val, q_other, qres.ctx.val) + return qres return NotImplemented def __radd__(self, other): cdef fmpz_mpoly res - other = any_as_fmpz(other) - if other is not NotImplemented: + cdef fmpq_mpoly qres + cdef fmpz_t z_other + cdef fmpq_t q_other + cdef int xtype + + xtype = fmpz_set_any_ref(z_other, other) + if xtype != FMPZ_UNKNOWN: res = create_fmpz_mpoly(self.ctx) - fmpz_mpoly_add_fmpz(res.val, (self).val, (other).val, res.ctx.val) + fmpz_mpoly_add_fmpz(res.val, (self).val, z_other, res.ctx.val) return res + xtype = fmpq_set_any_ref(q_other, other) + if xtype != FMPZ_UNKNOWN: + qres = fmpq_mpoly(self) + fmpq_mpoly_add_fmpq(qres.val, qres.val, q_other, qres.ctx.val) + return qres return NotImplemented def __iadd__(self, other): @@ -439,14 +457,18 @@ cdef class fmpz_mpoly(flint_mpoly): fmpz_mpoly_add((self).val, (self).val, (other).val, self.ctx.val) return self else: - other = any_as_fmpz(other) - if other is not NotImplemented: - fmpz_mpoly_add_fmpz((self).val, (self).val, (other).val, self.ctx.val) + zval = any_as_fmpz(other) + if zval is not NotImplemented: + fmpz_mpoly_add_fmpz((self).val, (self).val, (zval).val, self.ctx.val) return self return NotImplemented def __sub__(self, other): cdef fmpz_mpoly res + cdef fmpq_mpoly qres + cdef fmpz_t z_other + cdef fmpq_t q_other + cdef int xtype if typecheck(other, fmpz_mpoly): if (self).ctx is not (other).ctx: return NotImplemented @@ -454,20 +476,35 @@ cdef class fmpz_mpoly(flint_mpoly): fmpz_mpoly_sub(res.val, (self).val, (other).val, res.ctx.val) return res else: - other = any_as_fmpz(other) - if other is not NotImplemented: + xtype = fmpz_set_any_ref(z_other, other) + if xtype != FMPZ_UNKNOWN: res = create_fmpz_mpoly(self.ctx) - fmpz_mpoly_sub_fmpz(res.val, (self).val, (other).val, res.ctx.val) + fmpz_mpoly_sub_fmpz(res.val, (self).val, z_other, res.ctx.val) return res + xtype = fmpq_set_any_ref(q_other, other) + if xtype != FMPZ_UNKNOWN: + qres = fmpq_mpoly(self) + fmpq_mpoly_sub_fmpq(qres.val, qres.val, q_other, qres.ctx.val) + return qres return NotImplemented def __rsub__(self, other): cdef fmpz_mpoly res - other = any_as_fmpz(other) - if other is not NotImplemented: + cdef fmpq_mpoly qres + cdef fmpz_t z_other + cdef fmpq_t q_other + cdef int xtype + + xtype = fmpz_set_any_ref(z_other, other) + if xtype != FMPZ_UNKNOWN: res = create_fmpz_mpoly(self.ctx) - fmpz_mpoly_sub_fmpz(res.val, (self).val, (other).val, res.ctx.val) + fmpz_mpoly_sub_fmpz(res.val, (self).val, z_other, res.ctx.val) return -res + xtype = fmpq_set_any_ref(q_other, other) + if xtype != FMPZ_UNKNOWN: + qres = fmpq_mpoly(self) + fmpq_mpoly_sub_fmpq(qres.val, qres.val, q_other, qres.ctx.val) + return -qres return NotImplemented def __isub__(self, other): @@ -485,6 +522,11 @@ cdef class fmpz_mpoly(flint_mpoly): def __mul__(self, other): cdef fmpz_mpoly res + cdef fmpq_mpoly qres + cdef fmpz_t z_other + cdef fmpq_t q_other + cdef int xtype + if typecheck(other, fmpz_mpoly): if (self).ctx is not (other).ctx: return NotImplemented @@ -492,11 +534,15 @@ cdef class fmpz_mpoly(flint_mpoly): fmpz_mpoly_mul(res.val, (self).val, (other).val, res.ctx.val) return res else: - other = any_as_fmpz(other) - if other is not NotImplemented: + xtype = fmpz_set_any_ref(z_other, other) + if xtype != FMPZ_UNKNOWN: res = create_fmpz_mpoly(self.ctx) - fmpz_mpoly_scalar_mul_fmpz(res.val, (self).val, (other).val, res.ctx.val) + fmpz_mpoly_scalar_mul_fmpz(res.val, (self).val, z_other, res.ctx.val) return res + xtype = fmpq_set_any_ref(q_other, other) + if xtype != FMPZ_UNKNOWN: + qres = fmpq_mpoly(self) + fmpq_mpoly_scalar_mul_fmpq(qres.val, qres.val, q_other, qres.ctx.val) return NotImplemented def __rmul__(self, other): @@ -506,6 +552,9 @@ cdef class fmpz_mpoly(flint_mpoly): res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_scalar_mul_fmpz(res.val, (self).val, (other).val, res.ctx.val) return res + other = any_as_fmpq(other) + if other is not NotImplemented: + return fmpq_mpoly(self) * other return NotImplemented def __imul__(self, other): @@ -519,6 +568,9 @@ cdef class fmpz_mpoly(flint_mpoly): if other is not NotImplemented: fmpz_mpoly_scalar_mul_fmpz(self.val, (self).val, (other).val, self.ctx.val) return self + other = any_as_fmpq(other) + if other is not NotImplemented: + return fmpq_mpoly(self) * other return NotImplemented def __pow__(self, other, modulus): @@ -592,6 +644,13 @@ cdef class fmpz_mpoly(flint_mpoly): return res return NotImplemented + def __truediv__(self, other): + # TODO division by fmpq + if typecheck(other, fmpz_mpoly): + if self.ctx is not ( other).ctx: + return NotImplemented + return fmpz_mpoly_q(self, other) + def __mod__(self, other): return divmod(self, other)[1] diff --git a/src/flint/types/fmpz_mpoly_q.pyx b/src/flint/types/fmpz_mpoly_q.pyx index 939c3ebc..640d9029 100644 --- a/src/flint/types/fmpz_mpoly_q.pyx +++ b/src/flint/types/fmpz_mpoly_q.pyx @@ -2,7 +2,8 @@ from flint.flint_base.flint_base cimport flint_rational_function from flint.utils.typecheck cimport typecheck from flint.flintlib.fmpz_mpoly cimport fmpz_mpoly_set, fmpz_mpoly_get_str_pretty from flint.flintlib.fmpz_mpoly_q cimport * -from flint.types.fmpz_mpoly cimport fmpz_mpoly, fmpz_mpoly_ctx +from flint.types.fmpz_mpoly cimport fmpz_mpoly, fmpz_mpoly_ctx, create_fmpz_mpoly + cdef inline init_fmpz_mpoly_q(fmpz_mpoly_q var, fmpz_mpoly_ctx ctx): var.ctx = ctx @@ -86,7 +87,52 @@ cdef class fmpz_mpoly_q(flint_rational_function): res = res.replace("-", " - ") return res + def numer(self): + """ + Returns the numerator of *self* as an *fmpz_mpoly* + """ + cdef fmpz_mpoly num = create_fmpz_mpoly(self.ctx) + fmpz_mpoly_set(num.val, &(self.fraction.num), self.ctx.val) + return num + + def denom(self): + """ + Returns the denominator of *self* as an *fmpz_mpoly*. + """ + cdef fmpz_mpoly num = create_fmpz_mpoly(self.ctx) + fmpz_mpoly_set(num.val, &(self.fraction.den), self.ctx.val) + return num + def __neg__(self): cdef fmpz_mpoly_q res res = create_fmpz_mpoly_q(self.ctx) fmpz_mpoly_q_neg(res.fraction, self.fraction, res.ctx.val) + return res + + def __add__(s, t): + cdef fmpz_mpoly_q res + if typecheck(t, fmpz_mpoly_q) and typecheck(s, fmpz_mpoly_q): + if (s).ctx is (t).ctx: + res = create_fmpz_mpoly_q(s.ctx) + fmpz_mpoly_q_add(res.fraction, (s).fraction, (t).fraction, ( s).ctx.val) + return res + return NotImplemented + + def __sub__(s,t): + cdef fmpz_mpoly_q res + if typecheck(t, fmpz_mpoly_q) and typecheck(s, fmpz_mpoly_q): + if (s).ctx is (t).ctx: + res = create_fmpz_mpoly_q(s.ctx) + fmpz_mpoly_q_sub(res.fraction, (s).fraction, (t).fraction, ( s).ctx.val) + return res + return NotImplemented + + def __mul__(s,t): + cdef fmpz_mpoly_q res + if typecheck(t, fmpz_mpoly_q) and typecheck(s, fmpz_mpoly_q): + if (s).ctx is (t).ctx: + res = create_fmpz_mpoly_q(s.ctx) + fmpz_mpoly_q_mul(res.fraction, (s).fraction, (t).fraction, ( s).ctx.val) + return res + return NotImplemented + From e3c81d8ec9df882ab46cfe519c05ee07d9003fb0 Mon Sep 17 00:00:00 2001 From: David Einstein Date: Mon, 9 Oct 2023 22:35:05 -0400 Subject: [PATCH 21/21] Added tests, checks for division by zero to fmpz_mpoly Also added method to get context from a fmpq_mpoly so the tests could check that it was correct. --- src/flint/test/__main__.py | 1 + src/flint/test/test.py | 23 ++++++++++ src/flint/types/fmpq_mpoly.pyx | 7 ++- src/flint/types/fmpz_mpoly.pyx | 80 +++++++++++++++++++++++++++++++--- 4 files changed, 102 insertions(+), 9 deletions(-) diff --git a/src/flint/test/__main__.py b/src/flint/test/__main__.py index c1466e1f..be1e2692 100644 --- a/src/flint/test/__main__.py +++ b/src/flint/test/__main__.py @@ -56,6 +56,7 @@ def run_doctests(verbose=None): flint.types.fmpz_poly, flint.types.fmpz_mat, flint.types.fmpz_mpoly, + flint.types.fmpz_mpoly_q, flint.types.fmpz_series, flint.types.fmpq, flint.types.fmpq_poly, diff --git a/src/flint/test/test.py b/src/flint/test/test.py index d164ce97..1429f7f3 100644 --- a/src/flint/test/test.py +++ b/src/flint/test/test.py @@ -665,6 +665,29 @@ def test_fmpz_mpoly(): assert p1 // ztype(3) == ctx.fmpz_mpoly_from_dict({(1,0):1,(0,3):1,(2,4):3}) assert ztype(3) // p1 == Zp(0,ctx) assert ctx.constant(7) + ztype(3) == Zp(10, ctx) + q1 = flint.fmpq_mpoly(p1) + qctx = q1.context() + assert qctx.nvars() == 2 + assert qctx.ordering() == 'lex' + QQ = flint.fmpq + assert p1 + QQ(1,2) == qctx.fmpq_mpoly_from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):QQ(1,2)}) + assert QQ(1,2) + p1 == qctx.fmpq_mpoly_from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):QQ(1,2)}) + assert p1 - QQ(1,2) == qctx.fmpq_mpoly_from_dict({(1,0):4,(0,3):4,(2,4):9,(0,0):QQ(-1,2)}) + assert QQ(1,2) - p1 == qctx.fmpq_mpoly_from_dict({(1,0):-4,(0,3):-4,(2,4):-9,(0,0):QQ(1,2)}) + assert QQ(1,2) * p1 == qctx.fmpq_mpoly_from_dict({(1,0):2,(0,3):2,(2,4):QQ(9,2)}) + assert p1 * QQ(1,2) == qctx.fmpq_mpoly_from_dict({(1,0):2,(0,3):2,(2,4):QQ(9,2)}) + assert p1 / 2 == qctx.fmpq_mpoly_from_dict({(1,0):2,(0,3):2,(2,4):QQ(9,2)}) + assert p1 / QQ(1,2) == flint.fmpq_mpoly(p1 * 2) + p0 = Zp(0, ctx) + assert raises(lambda: p1 // p0 , ZeroDivisionError) + assert raises(lambda: p1 // 0 , ZeroDivisionError) + assert raises(lambda: p1 // QQ(1,1) , TypeError) + assert raises(lambda: p1 % p0 , ZeroDivisionError) + assert raises(lambda: p1 % 0 , ZeroDivisionError) + assert raises(lambda: p1 % QQ(1,1) , TypeError) + assert raises(lambda: p1 / p0 , ZeroDivisionError) + assert raises(lambda: p1 / 0 , ZeroDivisionError) + assert raises(lambda: p1 / QQ(0,1) , ZeroDivisionError) def test_fmpz_series(): diff --git a/src/flint/types/fmpq_mpoly.pyx b/src/flint/types/fmpq_mpoly.pyx index f2064cdf..473054d0 100644 --- a/src/flint/types/fmpq_mpoly.pyx +++ b/src/flint/types/fmpq_mpoly.pyx @@ -283,13 +283,13 @@ cdef class fmpq_mpoly(flint_mpoly): fmpq_mpoly_set_str_pretty(self.val, val, self.ctx.c_names, self.ctx.val) fmpq_mpoly_sort_terms(self.val, self.ctx.val) else: - v = any_as_fmpz(val) + v = any_as_fmpq(val) if v is NotImplemented: raise TypeError("cannot create fmpz_mpoly from type %s" % type(val)) if ctx is None: raise ValueError("Need context to convert fmpz to fmpq_mpoly") init_fmpq_mpoly(self, ctx) - fmpq_mpoly_set_fmpz(self.val, (v).val, self.ctx.val) + fmpq_mpoly_set_fmpq(self.val, (v).val, self.ctx.val) def __nonzero__(self): return not fmpq_mpoly_is_zero(self.val, self.ctx.val) @@ -319,6 +319,9 @@ cdef class fmpq_mpoly(flint_mpoly): else: return bool(self - other) + def context(self): + return self.ctx + def __len__(self): return fmpq_mpoly_length(self.val, self.ctx.val) diff --git a/src/flint/types/fmpz_mpoly.pyx b/src/flint/types/fmpz_mpoly.pyx index b4ea3938..4cd1c39e 100644 --- a/src/flint/types/fmpz_mpoly.pyx +++ b/src/flint/types/fmpz_mpoly.pyx @@ -3,7 +3,10 @@ from cpython.dict cimport PyDict_Size, PyDict_Check, PyDict_Next from cpython.tuple cimport PyTuple_Check, PyTuple_GET_SIZE from flint.flintlib.fmpz cimport fmpz_init, fmpz_clear, fmpz_is_zero from flint.flintlib.fmpq_mpoly cimport fmpq_mpoly_t, fmpq_mpoly_add_fmpq, fmpq_mpoly_sub_fmpq, fmpq_mpoly_scalar_mul_fmpq +from flint.flintlib.fmpq_mpoly cimport fmpq_mpoly_scalar_div_fmpq from flint.flintlib.flint cimport * +from flint.flintlib.fmpq cimport fmpq_numref, fmpq_denref +from flint.flintlib.fmpz_mpoly_q cimport fmpz_mpoly_q_div_fmpz from flint.utils.conversion cimport str_from_chars from flint.utils.typecheck cimport typecheck @@ -329,6 +332,9 @@ cdef class fmpz_mpoly(flint_mpoly): init_fmpz_mpoly(self, ctx) fmpz_mpoly_set_fmpz(self.val, (v).val, self.ctx.val) + def context(self): + return self.ctx + def __nonzero__(self): return not fmpz_mpoly_is_zero(self.val, self.ctx.val) @@ -543,18 +549,26 @@ cdef class fmpz_mpoly(flint_mpoly): if xtype != FMPZ_UNKNOWN: qres = fmpq_mpoly(self) fmpq_mpoly_scalar_mul_fmpq(qres.val, qres.val, q_other, qres.ctx.val) + return qres return NotImplemented def __rmul__(self, other): cdef fmpz_mpoly res - other = any_as_fmpz(other) - if other is not NotImplemented: + cdef fmpq_mpoly qres + cdef fmpz_t z_other + cdef fmpq_t q_other + cdef int xtype + + xtype = fmpz_set_any_ref(z_other, other) + if xtype != FMPZ_UNKNOWN: res = create_fmpz_mpoly(self.ctx) - fmpz_mpoly_scalar_mul_fmpz(res.val, (self).val, (other).val, res.ctx.val) + fmpz_mpoly_scalar_mul_fmpz(res.val, (self).val, z_other, res.ctx.val) return res - other = any_as_fmpq(other) - if other is not NotImplemented: - return fmpq_mpoly(self) * other + xtype = fmpq_set_any_ref(q_other, other) + if xtype != FMPZ_UNKNOWN: + qres = fmpq_mpoly(self) + fmpq_mpoly_scalar_mul_fmpq(qres.val, qres.val, q_other, qres.ctx.val) + return qres return NotImplemented def __imul__(self, other): @@ -590,6 +604,8 @@ cdef class fmpz_mpoly(flint_mpoly): def __divmod__(self, other): cdef fmpz_mpoly res, res2 if typecheck(other, fmpz_mpoly): + if not other: + raise ZeroDivisionError("fmpz_mpoly_divison by zero") if (self).ctx is not (other).ctx: return NotImplemented res = create_fmpz_mpoly(self.ctx) @@ -600,6 +616,8 @@ cdef class fmpz_mpoly(flint_mpoly): other = any_as_fmpz(other) if other is not NotImplemented: other= fmpz_mpoly(other, self.ctx) + if not other: + raise ZeroDivisionError("fmpz_mpoly divison by zero") res = create_fmpz_mpoly(self.ctx) res2 = create_fmpz_mpoly(self.ctx) fmpz_mpoly_divrem(res.val, res2.val, (self).val, (other).val, res.ctx.val) @@ -608,6 +626,8 @@ cdef class fmpz_mpoly(flint_mpoly): def __rdivmod__(self, other): cdef fmpz_mpoly res, res2 + if not self: + raise ZeroDivisionError("fmpz_mpoly divison by zero") other = any_as_fmpz(other) if other is not NotImplemented: other = fmpz_mpoly(other, self.ctx) @@ -620,6 +640,8 @@ cdef class fmpz_mpoly(flint_mpoly): def __floordiv__(self, other): cdef fmpz_mpoly res if typecheck(other, fmpz_mpoly): + if not other: + raise ZeroDivisionError("fmpz_mpoly division by zero") if (self).ctx is not (other).ctx: return NotImplemented res = create_fmpz_mpoly(self.ctx) @@ -628,6 +650,8 @@ cdef class fmpz_mpoly(flint_mpoly): else: other = any_as_fmpz(other) if other is not NotImplemented: + if not other: + raise ZeroDivisionError("fmpz_mpoly division by zero") other = fmpz_mpoly(other, self.ctx) res = create_fmpz_mpoly(self.ctx) fmpz_mpoly_div(res.val, (self).val, (other).val, res.ctx.val) @@ -636,6 +660,8 @@ cdef class fmpz_mpoly(flint_mpoly): def __rfloordiv__(self,other): cdef fmpz_mpoly res + if not self: + raise ZeroDivisionError("fmpz_mpoly division by zero") other = any_as_fmpz(other) if other is not NotImplemented: other = fmpz_mpoly(other, self.ctx) @@ -645,11 +671,51 @@ cdef class fmpz_mpoly(flint_mpoly): return NotImplemented def __truediv__(self, other): - # TODO division by fmpq + cdef fmpq_mpoly qres + cdef fmpq_t q_other + cdef int xtype + if typecheck(other, fmpz_mpoly): + if not other: + raise ZeroDivisionError("fmpz_mpoly division by zero") if self.ctx is not ( other).ctx: return NotImplemented return fmpz_mpoly_q(self, other) + xtype = fmpq_set_any_ref(q_other, other) + if xtype != FMPZ_UNKNOWN: + if not other: + raise ZeroDivisionError("fmpz_mpoly division by zero") + qres = fmpq_mpoly(self) + fmpq_mpoly_scalar_div_fmpq(qres.val, qres.val, q_other, qres.ctx.val) + return qres + + def __rtruediv__(self, other): + cdef fmpz_mpoly num + cdef fmpz_mpoly_q ret + cdef fmpz_t z_other + cdef fmpq_t q_other + cdef int xtype + + if not self: + raise ZeroDivisionError("fmpz_mpoly division by zero") + if typecheck(other, fmpz_mpoly): + if self.ctx is not ( other).ctx: + return NotImplemented + return fmpz_mpoly_q(other, self) + xtype = fmpz_set_any_ref(z_other, other) + if xtype != FMPZ_UNKNOWN: + num = create_fmpz_mpoly(self.ctx) + fmpz_mpoly_set_fmpz(num.val, z_other, self.ctx.val) + return fmpz_mpoly_q(num, self) + xtype = fmpq_set_any_ref(q_other, other) + if xtype != FMPZ_UNKNOWN: + num = create_fmpz_mpoly(self.ctx) + fmpz_mpoly_set_fmpz(num.val, fmpq_numref(q_other),self.ctx.val) + ret = fmpz_mpoly_q(num, self) + fmpz_mpoly_q_div_fmpz(ret.fraction, ret.fraction, fmpq_denref(q_other), self.ctx.val) + return ret + return NotImplemented + def __mod__(self, other): return divmod(self, other)[1]