diff --git a/setup.py b/setup.py index 1972be10..97ea040c 100644 --- a/setup.py +++ b/setup.py @@ -94,6 +94,8 @@ ("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.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/__init__.py b/src/flint/__init__.py index ef3f78e9..b5c90387 100644 --- a/src/flint/__init__.py +++ b/src/flint/__init__.py @@ -21,7 +21,9 @@ from .types.acb_mat import * from .types.acb_series import * 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/flint_base/flint_base.pxd b/src/flint/flint_base/flint_base.pxd index 95f87e9a..6cbb465b 100644 --- a/src/flint/flint_base/flint_base.pxd +++ b/src/flint/flint_base/flint_base.pxd @@ -7,6 +7,11 @@ cdef class flint_scalar(flint_elem): cdef class flint_poly(flint_elem): pass +cdef class flint_mpoly_context(flint_elem): + cdef public object py_names + cdef char ** c_names + cdef bint _init + cdef class flint_mpoly(flint_elem): pass @@ -15,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 4e33ae6e..7fb47a12 100644 --- a/src/flint/flint_base/flint_base.pyx +++ b/src/flint/flint_base/flint_base.pyx @@ -1,4 +1,5 @@ from flint.flint_base.flint_context cimport thectx +cimport libc.stdlib cdef class flint_elem: def __repr__(self): @@ -95,16 +96,60 @@ cdef class flint_poly(flint_elem): v = - fac[0] roots.append((v, m)) return roots - + def complex_roots(self): raise AttributeError("Complex roots are not supported for this polynomial") +cdef class flint_mpoly_context(flint_elem): + """ + Base class for multivariate ring contexts + """ + + def __cinit__(self): + self._init = False + + def __init__(self, long 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 + + def name(self, long 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) + + 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): """ @@ -173,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/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.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 new file mode 100644 index 00000000..766794de --- /dev/null +++ b/src/flint/flintlib/fmpq_mpoly.pxd @@ -0,0 +1,170 @@ +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: + 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_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) + 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_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_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_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) + 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_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_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) + 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_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) + 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) 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/flintlib/fmpz_mpoly.pxd b/src/flint/flintlib/fmpz_mpoly.pxd index d74f2df1..1d9ce207 100644 --- a/src/flint/flintlib/fmpz_mpoly.pxd +++ b/src/flint/flintlib/fmpz_mpoly.pxd @@ -196,3 +196,7 @@ cdef extern from "flint/fmpz_mpoly.h": void fmpz_mpoly_quasidivrem_heap(fmpz_t scale, fmpz_mpoly_t q, fmpz_mpoly_t r, const fmpz_mpoly_t poly2, const fmpz_mpoly_t poly3, const fmpz_mpoly_ctx_t ctx) slong _fmpz_mpoly_divrem_ideal_monagan_pearce(fmpz_mpoly_struct ** polyq, fmpz_struct ** polyr, ulong ** expr, slong * allocr, const fmpz_struct * poly2, const ulong * exp2, slong len2, fmpz_mpoly_struct * const * poly3, ulong * const * exp3, slong len, slong N, slong bits, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_divrem_ideal_monagan_pearce(fmpz_mpoly_struct ** q, fmpz_mpoly_t r, const fmpz_mpoly_t poly2, fmpz_mpoly_struct * const * poly3, slong len, const fmpz_mpoly_ctx_t ctx) +# undocumented functions + void _fmpz_mpoly_push_exp_ffmpz(fmpz_mpoly_t A, const fmpz_struct * exp, const fmpz_mpoly_ctx_t ctx); + void _fmpz_mpoly_push_exp_pfmpz(fmpz_mpoly_t A, fmpz_struct * const * exp, const fmpz_mpoly_ctx_t ctx); + void _fmpz_mpoly_push_exp_ui(fmpz_mpoly_t A, const ulong * exp, const fmpz_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/flintlib/fmpz_mpoly_q.pxd b/src/flint/flintlib/fmpz_mpoly_q.pxd new file mode 100644 index 00000000..682e4263 --- /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 den + 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/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/pyflint.pxd b/src/flint/pyflint.pxd index ec18e14c..19779743 100644 --- a/src/flint/pyflint.pxd +++ b/src/flint/pyflint.pxd @@ -14,3 +14,4 @@ cdef class Context: cdef public bint pretty cdef public long prec cdef arf_rnd_t rnd + diff --git a/src/flint/test/__main__.py b/src/flint/test/__main__.py index 542d6739..be1e2692 100644 --- a/src/flint/test/__main__.py +++ b/src/flint/test/__main__.py @@ -55,10 +55,13 @@ def run_doctests(verbose=None): flint.types.fmpz, 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, flint.types.fmpq_mat, + flint.types.fmpq_mpoly, flint.types.fmpq_series, flint.types.nmod, flint.types.nmod_poly, diff --git a/src/flint/test/test.py b/src/flint/test/test.py index 71bcea10..1429f7f3 100644 --- a/src/flint/test/test.py +++ b/src/flint/test/test.py @@ -633,6 +633,63 @@ 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_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.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.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.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) + 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(): Zp = flint.fmpz_poly Z = flint.fmpz_series @@ -1112,6 +1169,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 @@ -2022,10 +2112,12 @@ def setbad(obj, i, val): test_fmpz_poly_factor, test_fmpz_poly_functions, test_fmpz_mat, + test_fmpz_mpoly, test_fmpz_series, test_fmpq, test_fmpq_poly, test_fmpq_mat, + 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 1fe92bc8..5445fdc3 100644 --- a/src/flint/types/fmpq.pxd +++ b/src/flint/types/fmpq.pxd @@ -3,5 +3,6 @@ from flint.flintlib.fmpq cimport fmpq_t cdef int fmpq_set_any_ref(fmpq_t x, obj) 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 cc25fc7b..103d0a77 100644 --- a/src/flint/types/fmpq.pyx +++ b/src/flint/types/fmpq.pyx @@ -5,7 +5,7 @@ from flint.types.fmpz cimport fmpz from flint.types.fmpz cimport any_as_fmpz from flint.flintlib.flint cimport FMPZ_UNKNOWN, FMPZ_TMP, FMPZ_REF -from flint.flintlib.fmpz cimport fmpz_set, fmpz_one +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.pxd b/src/flint/types/fmpq_mpoly.pxd new file mode 100644 index 00000000..8240e736 --- /dev/null +++ b/src/flint/types/fmpq_mpoly.pxd @@ -0,0 +1,32 @@ +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 * +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) + 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..473054d0 --- /dev/null +++ b/src/flint/types/fmpq_mpoly.pyx @@ -0,0 +1,644 @@ +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, 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, 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 */ + typedef fmpq fmpq_struct; + """ + + +cimport cython +cimport libc.stdlib + +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_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_fmpq(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 fmpz_mpoly from a dictionary. + + 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_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 int xtype + cdef fmpz_struct *exponents + cdef fmpz_struct **exp_ptr + 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) + 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) + exp_ptr[i] = 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(): + xtype = fmpq_set_any_ref(coefficient, v) + if xtype == FMPZ_UNKNOWN: + 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 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 + for i in range(nvars): + fmpz_clear(exponents + i) + fmpq_mpoly_sort_terms(res.val, self.val) + fmpq_mpoly_reduce(res.val, self.val) + return res + + +def get_fmpq_mpoly_context(slong nvars=1, ordering="lex", names='x', nametup=None): + if nvars <= 0: + nvars = 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") + 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 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 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") + 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: + 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_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_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 context(self): + return self.ctx + + 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) + 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 + + + + 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.pxd b/src/flint/types/fmpz_mpoly.pxd index e4470efd..c3e47a23 100644 --- a/src/flint/types/fmpz_mpoly.pxd +++ b/src/flint/types/fmpz_mpoly.pxd @@ -1,13 +1,26 @@ 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 class fmpz_mpoly_ctx: +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) - cpdef ordering(self) cdef class fmpz_mpoly(flint_mpoly): diff --git a/src/flint/types/fmpz_mpoly.pyx b/src/flint/types/fmpz_mpoly.pyx index 1e179c9b..4cd1c39e 100644 --- a/src/flint/types/fmpz_mpoly.pyx +++ b/src/flint/types/fmpz_mpoly.pyx @@ -1,14 +1,36 @@ 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.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 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 +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 cimport libc.stdlib +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 @@ -52,68 +74,208 @@ 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 fmpz_mpoly_ctx_t val +cdef class fmpz_mpoly_ctx(flint_mpoly_context): + """ + A class for storing the polynomial context - def __init__(self, slong nvars, ordering="lex"): - assert nvars >= 1 - fmpz_mpoly_ctx_init(self.val, nvars, ordering_t.ORD_LEX) + :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`. + """ + def __init__(self, slong nvars, ordering, names): + 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) + 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 "lex" + """ + Return the term order of the context object. -cdef get_fmpz_mpoly_context(slong nvars=1, ordering=None): + >>> 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: + return "deglex" + if self.val.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 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 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("A constant fmpz_mpoly is a fmpz") + 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: + 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 + 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 - 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 -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 + # todo: store cached context objects externally @@ -135,30 +297,50 @@ 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: - self.ctx = (val).ctx - fmpz_mpoly_init(self.val, self.ctx.val) - self._init = True + if ctx is None or ctx == (val).ctx: + init_fmpz_mpoly(self, (val).ctx) 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, 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.fmpz_mpoly_from_dict(val) + #XXX this copy is silly, have a ctx function that assigns an fmpz_mpoly_t + 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') + 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: 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) - fmpz_mpoly_init(self.val, self.ctx.val) - self._init = True + if ctx is None: + raise ValueError("Need context to convert fmpz to fmpz_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) + 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) @@ -171,6 +353,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: @@ -179,12 +366,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) - i = s.index("(nvars") - s = s[:i] - return hash(s) - def coefficient(self, slong i): cdef fmpz v if i < 0 or i >= fmpz_mpoly_length(self.val, self.ctx.val): @@ -194,9 +375,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 @@ -213,27 +391,11 @@ 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): - 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: @@ -242,168 +404,319 @@ 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()) - - def str(self): - return self.repr() + return res 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 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 + 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 + res = create_fmpz_mpoly(self.ctx) + 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: - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (other).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) + 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, 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 + 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, 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): + 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: + 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 - 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 + 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 + res = create_fmpz_mpoly(self.ctx) + 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: - 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) + 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, 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 + 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, 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): + 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(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 + 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 + res = create_fmpz_mpoly(self.ctx) + 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: - 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) + 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, 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 qres + return NotImplemented + + def __rmul__(self, other): + cdef fmpz_mpoly res + 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, 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 qres + 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 + other = any_as_fmpq(other) + if other is not NotImplemented: + return fmpq_mpoly(self) * other return NotImplemented def __pow__(self, other, modulus): 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") - 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 - return NotImplemented + 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_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 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 + 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) + 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) + 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) return (res, res2) return NotImplemented + 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) + 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): 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 + 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) + 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: + 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) return res return NotImplemented + 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) + res = create_fmpz_mpoly(self.ctx) + fmpz_mpoly_div(res.val, (other).val, self.val, res.ctx.val) + return res + return NotImplemented + + def __truediv__(self, other): + 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] @@ -411,75 +724,79 @@ 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) - res = fmpz_mpoly.__new__(fmpz_mpoly) - res.ctx = (self).ctx - fmpz_mpoly_init(res.val, res.ctx.val) - res._init = True + return NotImplemented + res = create_fmpz_mpoly(self.ctx) 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): """ 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)]) """ 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) @@ -489,8 +806,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, [(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 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 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..640d9029 --- /dev/null +++ b/src/flint/types/fmpz_mpoly_q.pyx @@ -0,0 +1,138 @@ +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, create_fmpz_mpoly + + +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): + """ + 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") + + + 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 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 + 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