From 1bd96ee05ded6d696d6d45ccec79393f3d293095 Mon Sep 17 00:00:00 2001 From: giacomopope Date: Thu, 19 Oct 2023 17:10:01 +0100 Subject: [PATCH 01/36] Add a VERY rough start on adding fq --- src/flint/flintlib/fmpz_mod_mat.pxd | 70 ++++++++++++++ src/flint/flintlib/fq.pxd | 109 +++++++++++++++++++++ src/flint/flintlib/fq_default.pxd | 145 ++++++++++++++++++++++++++++ src/flint/flintlib/fq_nmod.pxd | 109 +++++++++++++++++++++ src/flint/flintlib/fq_zech.pxd | 111 +++++++++++++++++++++ src/flint/types/fq_default.pxd | 11 +++ src/flint/types/fq_default.pyx | 0 7 files changed, 555 insertions(+) create mode 100644 src/flint/flintlib/fmpz_mod_mat.pxd create mode 100644 src/flint/flintlib/fq.pxd create mode 100644 src/flint/flintlib/fq_default.pxd create mode 100644 src/flint/flintlib/fq_nmod.pxd create mode 100644 src/flint/flintlib/fq_zech.pxd create mode 100644 src/flint/types/fq_default.pxd create mode 100644 src/flint/types/fq_default.pyx diff --git a/src/flint/flintlib/fmpz_mod_mat.pxd b/src/flint/flintlib/fmpz_mod_mat.pxd new file mode 100644 index 00000000..ba7bdfe2 --- /dev/null +++ b/src/flint/flintlib/fmpz_mod_mat.pxd @@ -0,0 +1,70 @@ +from flint.flintlib.flint cimport flint_rand_t, fmpz_struct, slong +from flint.flintlib.fmpz_mod_poly cimport fmpz_mod_poly_t +from flint.flintlib.fmpz cimport fmpz_t +from flint.flintlib.fmpz_mod cimport fmpz_mod_ctx_t +from flint.flintlib.fmpz_mat cimport fmpz_mat_t + + +# unimported types {'thread_pool_handle', 'fmpz_mod_mat_t'} + +cdef extern from "flint/fmpz_mod_mat.h": + + ctypedef struct fmpz_mod_mat_struct: + fmpz_mat_t mat + fmpz_t mod + ctypedef fmpz_mod_mat_struct fmpz_mod_mat_t[1] + + fmpz_struct * fmpz_mod_mat_entry(const fmpz_mod_mat_t mat, slong i, slong j) + void fmpz_mod_mat_set_entry(fmpz_mod_mat_t mat, slong i, slong j, const fmpz_t val) + void fmpz_mod_mat_init(fmpz_mod_mat_t mat, slong rows, slong cols, const fmpz_t n) + void fmpz_mod_mat_init_set(fmpz_mod_mat_t mat, const fmpz_mod_mat_t src) + void fmpz_mod_mat_clear(fmpz_mod_mat_t mat) + slong fmpz_mod_mat_nrows(const fmpz_mod_mat_t mat) + slong fmpz_mod_mat_ncols(const fmpz_mod_mat_t mat) + void _fmpz_mod_mat_set_mod(fmpz_mod_mat_t mat, const fmpz_t n) + void fmpz_mod_mat_one(fmpz_mod_mat_t mat) + void fmpz_mod_mat_zero(fmpz_mod_mat_t mat) + void fmpz_mod_mat_swap(fmpz_mod_mat_t mat1, fmpz_mod_mat_t mat2) + void fmpz_mod_mat_swap_entrywise(fmpz_mod_mat_t mat1, fmpz_mod_mat_t mat2) + int fmpz_mod_mat_is_empty(const fmpz_mod_mat_t mat) + int fmpz_mod_mat_is_square(const fmpz_mod_mat_t mat) + void _fmpz_mod_mat_reduce(fmpz_mod_mat_t mat) + void fmpz_mod_mat_randtest(fmpz_mod_mat_t mat, flint_rand_t state) + void fmpz_mod_mat_window_init(fmpz_mod_mat_t window, const fmpz_mod_mat_t mat, slong r1, slong c1, slong r2, slong c2) + void fmpz_mod_mat_window_clear(fmpz_mod_mat_t window) + void fmpz_mod_mat_concat_horizontal(fmpz_mod_mat_t res, const fmpz_mod_mat_t mat1, const fmpz_mod_mat_t mat2) + void fmpz_mod_mat_concat_vertical(fmpz_mod_mat_t res, const fmpz_mod_mat_t mat1, const fmpz_mod_mat_t mat2) + void fmpz_mod_mat_print_pretty(const fmpz_mod_mat_t mat) + int fmpz_mod_mat_is_zero(const fmpz_mod_mat_t mat) + void fmpz_mod_mat_set(fmpz_mod_mat_t B, const fmpz_mod_mat_t A) + void fmpz_mod_mat_transpose(fmpz_mod_mat_t B, const fmpz_mod_mat_t A) + void fmpz_mod_mat_set_fmpz_mat(fmpz_mod_mat_t A, const fmpz_mat_t B) + void fmpz_mod_mat_get_fmpz_mat(fmpz_mat_t A, const fmpz_mod_mat_t B) + void fmpz_mod_mat_add(fmpz_mod_mat_t C, const fmpz_mod_mat_t A, const fmpz_mod_mat_t B) + void fmpz_mod_mat_sub(fmpz_mod_mat_t C, const fmpz_mod_mat_t A, const fmpz_mod_mat_t B) + void fmpz_mod_mat_neg(fmpz_mod_mat_t B, const fmpz_mod_mat_t A) + void fmpz_mod_mat_scalar_mul_si(fmpz_mod_mat_t B, const fmpz_mod_mat_t A, slong c) + void fmpz_mod_mat_scalar_mul_ui(fmpz_mod_mat_t B, const fmpz_mod_mat_t A, slong c) + void fmpz_mod_mat_scalar_mul_fmpz(fmpz_mod_mat_t B, const fmpz_mod_mat_t A, fmpz_t c) + void fmpz_mod_mat_mul(fmpz_mod_mat_t C, const fmpz_mod_mat_t A, const fmpz_mod_mat_t B) + # void _fmpz_mod_mat_mul_classical_threaded_pool_op(fmpz_mod_mat_t D, const fmpz_mod_mat_t C, const fmpz_mod_mat_t A, const fmpz_mod_mat_t B, int op, thread_pool_handle * threads, slong num_threads) + # void _fmpz_mod_mat_mul_classical_threaded_op(fmpz_mod_mat_t D, const fmpz_mod_mat_t C, const fmpz_mod_mat_t A, const fmpz_mod_mat_t B, int op) + void fmpz_mod_mat_mul_classical_threaded(fmpz_mod_mat_t C, const fmpz_mod_mat_t A, const fmpz_mod_mat_t B) + void fmpz_mod_mat_sqr(fmpz_mod_mat_t B, const fmpz_mod_mat_t A) + void fmpz_mod_mat_mul_fmpz_vec(fmpz_struct * c, const fmpz_mod_mat_t A, const fmpz_struct * b, slong blen) + void fmpz_mod_mat_mul_fmpz_vec_ptr(fmpz_struct * const * c, const fmpz_mod_mat_t A, const fmpz_struct * const * b, slong blen) + void fmpz_mod_mat_fmpz_vec_mul(fmpz_struct * c, const fmpz_struct * a, slong alen, const fmpz_mod_mat_t B) + void fmpz_mod_mat_fmpz_vec_mul_ptr(fmpz_struct * const * c, const fmpz_struct * const * a, slong alen, const fmpz_mod_mat_t B) + void fmpz_mod_mat_trace(fmpz_t trace, const fmpz_mod_mat_t mat) + slong fmpz_mod_mat_rref(slong * perm, fmpz_mod_mat_t mat) + void fmpz_mod_mat_strong_echelon_form(fmpz_mod_mat_t mat) + slong fmpz_mod_mat_howell_form(fmpz_mod_mat_t mat) + int fmpz_mod_mat_inv(fmpz_mod_mat_t B, fmpz_mod_mat_t A, fmpz_mod_ctx_t ctx) + slong fmpz_mod_mat_lu(slong * P, fmpz_mod_mat_t A, int rank_check, const fmpz_mod_ctx_t ctx) + void fmpz_mod_mat_solve_tril(fmpz_mod_mat_t X, const fmpz_mod_mat_t L, const fmpz_mod_mat_t B, int unit, const fmpz_mod_ctx_t ctx) + void fmpz_mod_mat_solve_triu(fmpz_mod_mat_t X, const fmpz_mod_mat_t U, const fmpz_mod_mat_t B, int unit, const fmpz_mod_ctx_t ctx) + int fmpz_mod_mat_solve(fmpz_mod_mat_t X, const fmpz_mod_mat_t A, const fmpz_mod_mat_t B, const fmpz_mod_ctx_t ctx) + int fmpz_mod_mat_can_solve(fmpz_mod_mat_t X, fmpz_mod_mat_t A, fmpz_mod_mat_t B, const fmpz_mod_ctx_t ctx) + void fmpz_mod_mat_similarity(fmpz_mod_mat_t M, slong r, fmpz_t d, fmpz_mod_ctx_t ctx) + void fmpz_mod_mat_charpoly(fmpz_mod_poly_t p, const fmpz_mod_mat_t M, const fmpz_mod_ctx_t ctx) + void fmpz_mod_mat_minpoly(fmpz_mod_poly_t p, const fmpz_mod_mat_t M, const fmpz_mod_ctx_t ctx) diff --git a/src/flint/flintlib/fq.pxd b/src/flint/flintlib/fq.pxd new file mode 100644 index 00000000..b98daa44 --- /dev/null +++ b/src/flint/flintlib/fq.pxd @@ -0,0 +1,109 @@ +from flint.flintlib.flint cimport flint_bitcnt_t, fmpz_struct, slong, flint_rand_t, ulong +from flint.flintlib.fmpz cimport fmpz_t, fmpz_struct +from flint.flintlib.fmpz_mod cimport fmpz_mod_ctx_t +from flint.flintlib.fmpz_mod_mat cimport fmpz_mod_mat_t +from flint.flintlib.fmpz_poly cimport fmpz_poly_t, fmpz_poly_struct +from flint.flintlib.fmpz_mod_poly cimport fmpz_mod_poly_t, fmpz_mod_poly_struct + +cdef extern from "flint/fq.h": + + ctypedef fmpz_poly_t fq_t + ctypedef fmpz_poly_struct fq_struct + + ctypedef struct fq_ctx_struct: + fmpz_mod_ctx_t ctxp + + int sparse_modulus + int is_conway # whether field was initialized with the Flint Conway tables (assures primitivity) + + fmpz_struct * a + slong * j + slong len + + fmpz_mod_poly_t modulus + fmpz_mod_poly_t inv + + char * var + + ctypedef fq_ctx_struct fq_ctx_t[1] + + void fq_ctx_init(fq_ctx_t ctx, const fmpz_t p, slong d, const char *var) + int _fq_ctx_init_conway(fq_ctx_t ctx, const fmpz_t p, slong d, const char *var) + void fq_ctx_init_conway(fq_ctx_t ctx, const fmpz_t p, slong d, const char *var) + void fq_ctx_init_modulus(fq_ctx_t ctx, const fmpz_mod_poly_t modulus, const fmpz_mod_ctx_t ctxp, const char *var) + void fq_ctx_clear(fq_ctx_t ctx) + const fmpz_mod_poly_struct* fq_ctx_modulus(const fq_ctx_t ctx) + long fq_ctx_degree(const fq_ctx_t ctx) + fmpz_struct * fq_ctx_prime(const fq_ctx_t ctx) + void fq_ctx_order(fmpz_t f, const fq_ctx_t ctx) + # int fq_ctx_fprint(FILE * file, const fq_ctx_t ctx) + void fq_ctx_print(const fq_ctx_t ctx) + void fq_ctx_randtest(fq_ctx_t ctx) + void fq_ctx_randtest_reducible(fq_ctx_t ctx) + void fq_init(fq_t rop, const fq_ctx_t ctx) + void fq_init2(fq_t rop, const fq_ctx_t ctx) + void fq_clear(fq_t rop, const fq_ctx_t ctx) + void _fq_sparse_reduce(fmpz_struct *R, slong lenR, const fq_ctx_t ctx) + void _fq_dense_reduce(fmpz_struct *R, slong lenR, const fq_ctx_t ctx) + void _fq_reduce(fmpz_struct *r, slong lenR, const fq_ctx_t ctx) + void fq_reduce(fq_t rop, const fq_ctx_t ctx) + void fq_add(fq_t rop, const fq_t op1, const fq_t op2, const fq_ctx_t ctx) + void fq_sub(fq_t rop, const fq_t op1, const fq_t op2, const fq_ctx_t ctx) + void fq_sub_one(fq_t rop, const fq_t op1, const fq_ctx_t ctx) + void fq_neg(fq_t rop, const fq_t op, const fq_ctx_t ctx) + void fq_mul(fq_t rop, const fq_t op1, const fq_t op2, const fq_ctx_t ctx) + void fq_mul_fmpz(fq_t rop, const fq_t op, const fmpz_t x, const fq_ctx_t ctx) + void fq_mul_si(fq_t rop, const fq_t op, slong x, const fq_ctx_t ctx) + void fq_mul_ui(fq_t rop, const fq_t op, ulong x, const fq_ctx_t ctx) + void fq_sqr(fq_t rop, const fq_t op, const fq_ctx_t ctx) + void fq_div(fq_t rop, const fq_t op1, const fq_t op2, const fq_ctx_t ctx) + void _fq_inv(fmpz_struct *rop, const fmpz_struct *op, slong len, const fq_ctx_t ctx) + void fq_inv(fq_t rop, const fq_t op, const fq_ctx_t ctx) + void fq_gcdinv(fq_t f, fq_t inv, const fq_t op, const fq_ctx_t ctx) + void _fq_pow(fmpz_struct *rop, const fmpz_struct *op, slong len, const fmpz_t e, const fq_ctx_t ctx) + void fq_pow(fq_t rop, const fq_t op, const fmpz_t e, const fq_ctx_t ctx) + void fq_pow_ui(fq_t rop, const fq_t op, const ulong e, const fq_ctx_t ctx) + int fq_sqrt(fq_t rop, const fq_t op1, const fq_ctx_t ctx) + void fq_pth_root(fq_t rop, const fq_t op1, const fq_ctx_t ctx) + int fq_is_square(const fq_t op, const fq_ctx_t ctx) + # int fq_fprint_pretty(FILE *file, const fq_t op, const fq_ctx_t ctx) + int fq_print_pretty(const fq_t op, const fq_ctx_t ctx) + # void fq_fprint(FILE * file, const fq_t op, const fq_ctx_t ctx) + void fq_print(const fq_t op, const fq_ctx_t ctx) + char * fq_get_str(const fq_t op, const fq_ctx_t ctx) + char * fq_get_str_pretty(const fq_t op, const fq_ctx_t ctx) + void fq_randtest(fq_t rop, flint_rand_t state, const fq_ctx_t ctx) + void fq_randtest_not_zero(fq_t rop, flint_rand_t state, const fq_ctx_t ctx) + void fq_randtest_dense(fq_t rop, flint_rand_t state, const fq_ctx_t ctx) + void fq_rand(fq_t rop, flint_rand_t state, const fq_ctx_t ctx) + void fq_rand_not_zero(fq_t rop, flint_rand_t state, const fq_ctx_t ctx) + void fq_set(fq_t rop, const fq_t op, const fq_ctx_t ctx) + void fq_set_si(fq_t rop, const slong x, const fq_ctx_t ctx) + void fq_set_ui(fq_t rop, const ulong x, const fq_ctx_t ctx) + void fq_set_fmpz(fq_t rop, const fmpz_t x, const fq_ctx_t ctx) + void fq_swap(fq_t op1, fq_t op2, const fq_ctx_t ctx) + void fq_zero(fq_t rop, const fq_ctx_t ctx) + void fq_one(fq_t rop, const fq_ctx_t ctx) + void fq_gen(fq_t rop, const fq_ctx_t ctx) + int fq_get_fmpz(fmpz_t rop, const fq_t op, const fq_ctx_t ctx) + void fq_get_fmpz_poly(fmpz_poly_t a, const fq_t b, const fq_ctx_t ctx) + void fq_get_fmpz_mod_poly(fmpz_mod_poly_t a, const fq_t b, const fq_ctx_t ctx) + void fq_set_fmpz_poly(fq_t a, const fmpz_poly_t b, const fq_ctx_t ctx) + void fq_set_fmpz_mod_poly(fq_t a, const fmpz_mod_poly_t b, const fq_ctx_t ctx) + void fq_get_fmpz_mod_mat(fmpz_mod_mat_t col, const fq_t a, const fq_ctx_t ctx) + void fq_set_fmpz_mod_mat(fq_t a, const fmpz_mod_mat_t col, const fq_ctx_t ctx) + int fq_is_zero(const fq_t op, const fq_ctx_t ctx) + int fq_is_one(const fq_t op, const fq_ctx_t ctx) + int fq_equal(const fq_t op1, const fq_t op2, const fq_ctx_t ctx) + int fq_is_invertible(const fq_t op, const fq_ctx_t ctx) + int fq_is_invertible_f(fq_t f, const fq_t op, const fq_ctx_t ctx) + void _fq_trace(fmpz_t rop, const fmpz_struct *op, slong len, const fq_ctx_t ctx) + void fq_trace(fmpz_t rop, const fq_t op, const fq_ctx_t ctx) + void _fq_norm(fmpz_t rop, const fmpz_struct *op, slong len, const fq_ctx_t ctx) + void fq_norm(fmpz_t rop, const fq_t op, const fq_ctx_t ctx) + void _fq_frobenius(fmpz_struct *rop, const fmpz_struct *op, slong len, slong e, const fq_ctx_t ctx) + void fq_frobenius(fq_t rop, const fq_t op, slong e, const fq_ctx_t ctx) + int fq_multiplicative_order(fmpz_t ord, const fq_t op, const fq_ctx_t ctx) + int fq_is_primitive(const fq_t op, const fq_ctx_t ctx) + void fq_bit_pack(fmpz_t f, const fq_t op, flint_bitcnt_t bit_size, const fq_ctx_t ctx) + void fq_bit_unpack(fq_t rop, const fmpz_t f, flint_bitcnt_t bit_size, const fq_ctx_t ctx) diff --git a/src/flint/flintlib/fq_default.pxd b/src/flint/flintlib/fq_default.pxd new file mode 100644 index 00000000..289df611 --- /dev/null +++ b/src/flint/flintlib/fq_default.pxd @@ -0,0 +1,145 @@ +from flint.flintlib.fmpz_poly cimport fmpz_poly_t +from flint.flintlib.fmpz cimport fmpz_t +from flint.flintlib.flint cimport slong, flint_rand_t, ulong, mp_limb_t + +from flint.flintlib.nmod cimport nmod_t +from flint.flintlib.nmod_poly cimport nmod_poly_t +from flint.flintlib.fmpz_mod cimport fmpz_mod_ctx_t +from flint.flintlib.fmpz_mod_poly cimport fmpz_mod_poly_t + +from flint.flintlib.fq cimport fq_t, fq_ctx_t +from flint.flintlib.fq_nmod cimport fq_nmod_t, fq_nmod_ctx_t +from flint.flintlib.fq_zech cimport fq_zech_t, fq_zech_ctx_t + +cdef extern from "flint/fq_default.h": + """ + TODO: how best to handle union + https://stackoverflow.com/questions/12452210/cython-nesting-a-union-within-a-struct + + typedef union fq_default_struct + { + fq_t fq; + fq_nmod_t fq_nmod; + fq_zech_t fq_zech; + ulong nmod; + fmpz_t fmpz_mod; + } fq_default_struct; + + typedef fq_default_struct fq_default_t[1]; + """ + ctypedef struct fq_default_struct: + fq_t fq + fq_nmod_t fq_nmod + fq_zech_t fq_zech + ulong nmod + fmpz_t fmpz_mod + ctypedef fq_default_struct fq_default_t[1] + + """ + TODO: how best to handle union + https://stackoverflow.com/questions/12452210/cython-nesting-a-union-within-a-struct + + typedef struct + { + int type; + union ctx + { + fq_ctx_t fq; + fq_nmod_ctx_t fq_nmod; + fq_zech_ctx_t fq_zech; + struct { + nmod_t mod; + mp_limb_t a; /* minpoly is x - a */ + } nmod; + struct { + fmpz_mod_ctx_t mod; + fmpz_t a; /* minpoly is x - a */ + } fmpz_mod; + } ctx; + } fq_default_ctx_struct; + """ + + ctypedef struct fq_default_fmpz_mod_ctx_struct: + fmpz_mod_ctx_t mod + fmpz_t a # minpoly is x - a + + ctypedef struct fq_default_nmod_ctx_struct: + nmod_t mod + mp_limb_t a # minpoly is x - a + + ctypedef struct fq_default_ctx_struct: + fq_ctx_t fq + fq_nmod_ctx_t fq_nmod + fq_zech_ctx_t fq_zech + fq_default_nmod_ctx_struct nmod + fq_default_fmpz_mod_ctx_struct fmpz_mod + ctypedef fq_default_ctx_struct fq_default_ctx_t[1] + + # Parsed from here + void fq_default_ctx_init(fq_default_ctx_t ctx, const fmpz_t p, slong d, const char * var) + void fq_default_ctx_init_type(fq_default_ctx_t ctx, const fmpz_t p, slong d, const char * var, int type) + void fq_default_ctx_init_modulus(fq_default_ctx_t ctx, const fmpz_mod_poly_t modulus, fmpz_mod_ctx_t mod_ctx, const char * var) + void fq_default_ctx_init_modulus_type(fq_default_ctx_t ctx, const fmpz_mod_poly_t modulus, fmpz_mod_ctx_t mod_ctx, const char * var, int type) + void fq_default_ctx_init_modulus_nmod(fq_default_ctx_t ctx, const nmod_poly_t modulus, const char * var) + void fq_default_ctx_init_modulus_nmod_type(fq_default_ctx_t ctx, const nmod_poly_t modulus, const char * var, int type) + void fq_default_ctx_clear(fq_default_ctx_t ctx) + int fq_default_ctx_type(const fq_default_ctx_t ctx) + slong fq_default_ctx_degree(const fq_default_ctx_t ctx) + void fq_default_ctx_prime(fmpz_t prime, const fq_default_ctx_t ctx) + void fq_default_ctx_order(fmpz_t f, const fq_default_ctx_t ctx) + void fq_default_ctx_modulus(fmpz_mod_poly_t p, const fq_default_ctx_t ctx) + # int fq_default_ctx_fprint(FILE * file, const fq_default_ctx_t ctx) + void fq_default_ctx_print(const fq_default_ctx_t ctx) + void fq_default_ctx_randtest(fq_default_ctx_t ctx) + void fq_default_get_coeff_fmpz(fmpz_t c, fq_default_t op, slong n, const fq_default_ctx_t ctx) + void fq_default_init(fq_default_t rop, const fq_default_ctx_t ctx) + void fq_default_init2(fq_default_t rop, const fq_default_ctx_t ctx) + void fq_default_clear(fq_default_t rop, const fq_default_ctx_t ctx) + int fq_default_is_invertible(const fq_default_t op, const fq_default_ctx_t ctx) + void fq_default_add(fq_default_t rop, const fq_default_t op1, const fq_default_t op2, const fq_default_ctx_t ctx) + void fq_default_sub(fq_default_t rop, const fq_default_t op1, const fq_default_t op2, const fq_default_ctx_t ctx) + void fq_default_sub_one(fq_default_t rop, const fq_default_t op1, const fq_default_ctx_t ctx) + void fq_default_neg(fq_default_t rop, const fq_default_t op, const fq_default_ctx_t ctx) + void fq_default_mul(fq_default_t rop, const fq_default_t op1, const fq_default_t op2, const fq_default_ctx_t ctx) + void fq_default_mul_fmpz(fq_default_t rop, const fq_default_t op, const fmpz_t x, const fq_default_ctx_t ctx) + void fq_default_mul_si(fq_default_t rop, const fq_default_t op, slong x, const fq_default_ctx_t ctx) + void fq_default_mul_ui(fq_default_t rop, const fq_default_t op, ulong x, const fq_default_ctx_t ctx) + void fq_default_sqr(fq_default_t rop, const fq_default_t op, const fq_default_ctx_t ctx) + void fq_default_div(fq_default_t rop, const fq_default_t op1, const fq_default_t op2, const fq_default_ctx_t ctx) + void fq_default_inv(fq_default_t rop, const fq_default_t op, const fq_default_ctx_t ctx) + void fq_default_pow(fq_default_t rop, const fq_default_t op, const fmpz_t e, const fq_default_ctx_t ctx) + void fq_default_pow_ui(fq_default_t rop, const fq_default_t op, const ulong e, const fq_default_ctx_t ctx) + int fq_default_sqrt(fq_default_t rop, const fq_default_t op1, const fq_default_ctx_t ctx) + void fq_default_pth_root(fq_default_t rop, const fq_default_t op1, const fq_default_ctx_t ctx) + int fq_default_is_square(const fq_default_t op, const fq_default_ctx_t ctx) + # int fq_default_fprint_pretty(FILE *file, const fq_default_t op, const fq_default_ctx_t ctx) + int fq_default_print_pretty(const fq_default_t op, const fq_default_ctx_t ctx) + # void fq_default_fprint(FILE * file, const fq_default_t op, const fq_default_ctx_t ctx) + void fq_default_print(const fq_default_t op, const fq_default_ctx_t ctx) + char * fq_default_get_str(const fq_default_t op, const fq_default_ctx_t ctx) + char * fq_default_get_str_pretty(const fq_default_t op, const fq_default_ctx_t ctx) + void fq_default_randtest(fq_default_t rop, flint_rand_t state, const fq_default_ctx_t ctx) + void fq_default_randtest_not_zero(fq_default_t rop, flint_rand_t state, const fq_default_ctx_t ctx) + void fq_default_rand(fq_default_t rop, flint_rand_t state, const fq_default_ctx_t ctx) + void fq_default_rand_not_zero(fq_default_t rop, flint_rand_t state, const fq_default_ctx_t ctx) + void fq_default_set(fq_default_t rop, const fq_default_t op, const fq_default_ctx_t ctx) + void fq_default_set_si(fq_default_t rop, const slong x, const fq_default_ctx_t ctx) + void fq_default_set_ui(fq_default_t rop, const ulong x, const fq_default_ctx_t ctx) + void fq_default_set_fmpz(fq_default_t rop, const fmpz_t x, const fq_default_ctx_t ctx) + void fq_default_swap(fq_default_t op1, fq_default_t op2, const fq_default_ctx_t ctx) + void fq_default_zero(fq_default_t rop, const fq_default_ctx_t ctx) + void fq_default_one(fq_default_t rop, const fq_default_ctx_t ctx) + void fq_default_gen(fq_default_t rop, const fq_default_ctx_t ctx) + int fq_default_get_fmpz(fmpz_t rop, const fq_default_t op, const fq_default_ctx_t ctx) + void fq_default_get_nmod_poly(nmod_poly_t poly, const fq_default_t op, const fq_default_ctx_t ctx) + void fq_default_set_nmod_poly(fq_default_t op, const nmod_poly_t poly, const fq_default_ctx_t ctx) + void fq_default_get_fmpz_mod_poly(fmpz_mod_poly_t poly, const fq_default_t op, const fmpz_mod_ctx_t mod_ctx, const fq_default_ctx_t ctx) + void fq_default_set_fmpz_mod_poly(fq_default_t op, const fmpz_mod_poly_t poly, const fmpz_mod_ctx_t mod_ctx, const fq_default_ctx_t ctx) + void fq_default_get_fmpz_poly(fmpz_poly_t a, const fq_default_t b, const fq_default_ctx_t ctx) + void fq_default_set_fmpz_poly(fq_default_struct a, const fmpz_poly_t b, const fq_default_ctx_t ctx) + int fq_default_is_zero(const fq_default_t op, const fq_default_ctx_t ctx) + int fq_default_is_one(const fq_default_t op, const fq_default_ctx_t ctx) + int fq_default_equal(const fq_default_t op1, const fq_default_t op2, const fq_default_ctx_t ctx) + void fq_default_trace(fmpz_t rop, const fq_default_t op, const fq_default_ctx_t ctx) + void fq_default_norm(fmpz_t rop, const fq_default_t op, const fq_default_ctx_t ctx) + void fq_default_frobenius(fq_default_t rop, const fq_default_t op, slong e, const fq_default_ctx_t ctx) diff --git a/src/flint/flintlib/fq_nmod.pxd b/src/flint/flintlib/fq_nmod.pxd new file mode 100644 index 00000000..c273be9d --- /dev/null +++ b/src/flint/flintlib/fq_nmod.pxd @@ -0,0 +1,109 @@ +# unimported types {'fq_nmod_t', 'fq_nmod_ctx_t'} +from flint.flintlib.fmpz cimport fmpz_t, fmpz_struct +from flint.flintlib.nmod_poly cimport nmod_poly_t +from flint.flintlib.flint cimport mp_ptr, mp_limb_t, slong, mp_srcptr, flint_rand_t, flint_bitcnt_t, ulong +from flint.flintlib.nmod cimport nmod_t +from flint.flintlib.nmod_mat cimport nmod_mat_t +from flint.flintlib.nmod_poly cimport nmod_poly_struct, nmod_poly_t + +cdef extern from "flint/fq_nmod.h": + + ctypedef nmod_poly_t fq_nmod_t + ctypedef nmod_poly_struct fq_nmod_struct + + ctypedef struct fq_nmod_ctx_struct: + fmpz_struct p + nmod_t mod + + int sparse_modulus + int is_conway # whether field was generated using Flint Conway table (assures primitivity + + mp_limb_t *a + slong *j + slong len + + nmod_poly_t modulus + nmod_poly_t inv + + char *var + ctypedef fq_nmod_ctx_struct fq_nmod_ctx_t[1] + + + void fq_nmod_ctx_init(fq_nmod_ctx_t ctx, const fmpz_t p, slong d, const char *var) + int _fq_nmod_ctx_init_conway(fq_nmod_ctx_t ctx, const fmpz_t p, slong d, const char *var) + void fq_nmod_ctx_init_conway(fq_nmod_ctx_t ctx, const fmpz_t p, slong d, const char *var) + void fq_nmod_ctx_init_modulus(fq_nmod_ctx_t ctx, nmod_poly_t modulus, const char *var) + void fq_nmod_ctx_clear(fq_nmod_ctx_t ctx) + const nmod_poly_struct* fq_nmod_ctx_modulus(const fq_nmod_ctx_t ctx) + long fq_nmod_ctx_degree(const fq_nmod_ctx_t ctx) + fmpz_struct * fq_nmod_ctx_prime(const fq_nmod_ctx_t ctx) + void fq_nmod_ctx_order(fmpz_t f, const fq_nmod_ctx_t ctx) + # int fq_nmod_ctx_fprint(FILE * file, const fq_nmod_ctx_t ctx) + void fq_nmod_ctx_print(const fq_nmod_ctx_t ctx) + void fq_nmod_ctx_randtest(fq_nmod_ctx_t ctx) + void fq_nmod_ctx_randtest_reducible(fq_nmod_ctx_t ctx) + void fq_nmod_init(fq_nmod_t rop, const fq_nmod_ctx_t ctx) + void fq_nmod_init2(fq_nmod_t rop, const fq_nmod_ctx_t ctx) + void fq_nmod_clear(fq_nmod_t rop, const fq_nmod_ctx_t ctx) + void _fq_nmod_sparse_reduce(mp_ptr R, slong lenR, const fq_nmod_ctx_t ctx) + void _fq_nmod_dense_reduce(mp_ptr R, slong lenR, const fq_nmod_ctx_t ctx) + void _fq_nmod_reduce(mp_ptr r, slong lenR, const fq_nmod_ctx_t ctx) + void fq_nmod_reduce(fq_nmod_t rop, const fq_nmod_ctx_t ctx) + void fq_nmod_add(fq_nmod_t rop, const fq_nmod_t op1, const fq_nmod_t op2, const fq_nmod_ctx_t ctx) + void fq_nmod_sub(fq_nmod_t rop, const fq_nmod_t op1, const fq_nmod_t op2, const fq_nmod_ctx_t ctx) + void fq_nmod_sub_one(fq_nmod_t rop, const fq_nmod_t op1, const fq_nmod_ctx_t ctx) + void fq_nmod_neg(fq_nmod_t rop, const fq_nmod_t op, const fq_nmod_ctx_t ctx) + void fq_nmod_mul(fq_nmod_t rop, const fq_nmod_t op1, const fq_nmod_t op2, const fq_nmod_ctx_t ctx) + void fq_nmod_mul_fmpz(fq_nmod_t rop, const fq_nmod_t op, const fmpz_t x, const fq_nmod_ctx_t ctx) + void fq_nmod_mul_si(fq_nmod_t rop, const fq_nmod_t op, slong x, const fq_nmod_ctx_t ctx) + void fq_nmod_mul_ui(fq_nmod_t rop, const fq_nmod_t op, ulong x, const fq_nmod_ctx_t ctx) + void fq_nmod_sqr(fq_nmod_t rop, const fq_nmod_t op, const fq_nmod_ctx_t ctx) + void _fq_nmod_inv(mp_ptr * rop, mp_srcptr * op, slong len, const fq_nmod_ctx_t ctx) + void fq_nmod_inv(fq_nmod_t rop, const fq_nmod_t op, const fq_nmod_ctx_t ctx) + void fq_nmod_gcdinv(fq_nmod_t f, fq_nmod_t inv, const fq_nmod_t op, const fq_nmod_ctx_t ctx) + void _fq_nmod_pow(mp_ptr * rop, mp_srcptr * op, slong len, const fmpz_t e, const fq_nmod_ctx_t ctx) + void fq_nmod_pow(fq_nmod_t rop, const fq_nmod_t op, const fmpz_t e, const fq_nmod_ctx_t ctx) + void fq_nmod_pow_ui(fq_nmod_t rop, const fq_nmod_t op, const ulong e, const fq_nmod_ctx_t ctx) + void fq_nmod_sqrt(fq_nmod_t rop, const fq_nmod_t op1, const fq_nmod_ctx_t ctx) + void fq_nmod_pth_root(fq_nmod_t rop, const fq_nmod_t op1, const fq_nmod_ctx_t ctx) + int fq_nmod_is_square(const fq_nmod_t op, const fq_nmod_ctx_t ctx) + # int fq_nmod_fprint_pretty(FILE * file, const fq_nmod_t op, const fq_nmod_ctx_t ctx) + int fq_nmod_print_pretty(const fq_nmod_t op, const fq_nmod_ctx_t ctx) + # void fq_nmod_fprint(FILE * file, const fq_nmod_t op, const fq_nmod_ctx_t ctx) + void fq_nmod_print(const fq_nmod_t op, const fq_nmod_ctx_t ctx) + char * fq_nmod_get_str(const fq_nmod_t op, const fq_nmod_ctx_t ctx) + char * fq_nmod_get_str_pretty(const fq_nmod_t op, const fq_nmod_ctx_t ctx) + void fq_nmod_randtest(fq_nmod_t rop, flint_rand_t state, const fq_nmod_ctx_t ctx) + void fq_nmod_randtest_not_zero(fq_nmod_t rop, flint_rand_t state, const fq_nmod_ctx_t ctx) + void fq_nmod_randtest_dense(fq_nmod_t rop, flint_rand_t state, const fq_nmod_ctx_t ctx) + void fq_nmod_rand(fq_nmod_t rop, flint_rand_t state, const fq_nmod_ctx_t ctx) + void fq_nmod_rand_not_zero(fq_nmod_t rop, flint_rand_t state, const fq_nmod_ctx_t ctx) + void fq_nmod_set(fq_nmod_t rop, const fq_nmod_t op, const fq_nmod_ctx_t ctx) + void fq_nmod_set_si(fq_nmod_t rop, const slong x, const fq_nmod_ctx_t ctx) + void fq_nmod_set_ui(fq_nmod_t rop, const ulong x, const fq_nmod_ctx_t ctx) + void fq_nmod_set_fmpz(fq_nmod_t rop, const fmpz_t x, const fq_nmod_ctx_t ctx) + void fq_nmod_swap(fq_nmod_t op1, fq_nmod_t op2, const fq_nmod_ctx_t ctx) + void fq_nmod_zero(fq_nmod_t rop, const fq_nmod_ctx_t ctx) + void fq_nmod_one(fq_nmod_t rop, const fq_nmod_ctx_t ctx) + void fq_nmod_gen(fq_nmod_t rop, const fq_nmod_ctx_t ctx) + int fq_nmod_get_fmpz(fmpz_t rop, const fq_nmod_t op, const fq_nmod_ctx_t ctx) + void fq_nmod_get_nmod_poly(nmod_poly_t a, const fq_nmod_t b, const fq_nmod_ctx_t ctx); + void fq_nmod_set_nmod_poly(fq_nmod_t a, const nmod_poly_t b, const fq_nmod_ctx_t ctx); + void fq_nmod_get_nmod_mat(nmod_mat_t col, const fq_nmod_t a, const fq_nmod_ctx_t ctx) + void fq_nmod_set_nmod_mat(fq_nmod_t a, const nmod_mat_t col, const fq_nmod_ctx_t ctx) + int fq_nmod_is_zero(const fq_nmod_t op, const fq_nmod_ctx_t ctx) + int fq_nmod_is_one(const fq_nmod_t op, const fq_nmod_ctx_t ctx) + int fq_nmod_equal(const fq_nmod_t op1, const fq_nmod_t op2, const fq_nmod_ctx_t ctx) + int fq_nmod_is_invertible(const fq_nmod_t op, const fq_nmod_ctx_t ctx) + int fq_nmod_is_invertible_f(fq_nmod_t f, const fq_nmod_t op, const fq_nmod_ctx_t ctx) + int fq_nmod_cmp(const fq_nmod_t a, const fq_nmod_t b, const fq_nmod_ctx_t ctx) + void _fq_nmod_trace(fmpz_t rop, mp_srcptr * op, slong len, const fq_nmod_ctx_t ctx) + void fq_nmod_trace(fmpz_t rop, const fq_nmod_t op, const fq_nmod_ctx_t ctx) + void _fq_nmod_norm(fmpz_t rop, mp_srcptr * op, slong len, const fq_nmod_ctx_t ctx) + void fq_nmod_norm(fmpz_t rop, const fq_nmod_t op, const fq_nmod_ctx_t ctx) + void _fq_nmod_frobenius(mp_ptr * rop, mp_srcptr * op, slong len, slong e, const fq_nmod_ctx_t ctx) + void fq_nmod_frobenius(fq_nmod_t rop, const fq_nmod_t op, slong e, const fq_nmod_ctx_t ctx) + int fq_nmod_multiplicative_order(fmpz_t ord, const fq_nmod_t op, const fq_nmod_ctx_t ctx) + int fq_nmod_is_primitive(const fq_nmod_t op, const fq_nmod_ctx_t ctx) + void fq_nmod_bit_pack(fmpz_t f, const fq_nmod_t op, flint_bitcnt_t bit_size, const fq_nmod_ctx_t ctx) + void fq_nmod_bit_unpack(fq_nmod_t rop, const fmpz_t f, flint_bitcnt_t bit_size, const fq_nmod_ctx_t ctx) diff --git a/src/flint/flintlib/fq_zech.pxd b/src/flint/flintlib/fq_zech.pxd new file mode 100644 index 00000000..531536ee --- /dev/null +++ b/src/flint/flintlib/fq_zech.pxd @@ -0,0 +1,111 @@ +from flint.flintlib.flint cimport ulong, slong, flint_bitcnt_t, mp_ptr, flint_rand_t, mp_srcptr, mp_limb_t +from flint.flintlib.fmpz cimport fmpz_t, fmpz_struct +from flint.flintlib.nmod_mat cimport nmod_mat_t +from flint.flintlib.nmod_poly cimport nmod_poly_t, nmod_poly_struct +from flint.flintlib.fq_nmod cimport fq_nmod_t, fq_nmod_ctx_t, fq_nmod_ctx_struct + + +cdef extern from "flint/fq_zech.h": + ctypedef struct fq_zech_struct: + mp_limb_t value + ctypedef fq_zech_struct fq_zech_t[1] + + ctypedef struct fq_zech_ctx_struct: + mp_limb_t qm1 # q - 1 + mp_limb_t qm1o2 # (q - 1) / 2 or 1 when p == 2 + mp_limb_t qm1opm1 # (q - 1) / (p - 1) + mp_limb_t p + double ppre + mp_limb_t prime_root # primitive root for prime subfield + mp_limb_t * zech_log_table + mp_limb_t * prime_field_table + mp_limb_t * eval_table + + fq_nmod_ctx_struct * fq_nmod_ctx + int owns_fq_nmod_ctx + int is_conway # whether field was generated using Flint Conway tables (assures primitivity) + ctypedef fq_zech_ctx_struct fq_zech_ctx_t[1] + + # PArsed from here + void fq_zech_ctx_init(fq_zech_ctx_t ctx, const fmpz_t p, slong d, const char *var) + int _fq_zech_ctx_init_conway(fq_zech_ctx_t ctx, const fmpz_t p, slong d, const char *var) + void fq_zech_ctx_init_conway(fq_zech_ctx_t ctx, const fmpz_t p, slong d, const char *var) + void fq_zech_ctx_init_random(fq_zech_ctx_t ctx, const fmpz_t p, slong d, const char *var) + void fq_zech_ctx_init_modulus(fq_zech_ctx_t ctx, nmod_poly_t modulus, const char *var) + int fq_zech_ctx_init_modulus_check(fq_zech_ctx_t ctx, nmod_poly_t modulus, const char *var) + void fq_zech_ctx_init_fq_nmod_ctx(fq_zech_ctx_t ctx, fq_nmod_ctx_t ctxn) + int fq_zech_ctx_init_fq_nmod_ctx_check(fq_zech_ctx_t ctx, fq_nmod_ctx_t ctxn) + void fq_zech_ctx_clear(fq_zech_ctx_t ctx) + const nmod_poly_struct* fq_zech_ctx_modulus(const fq_zech_ctx_t ctx) + long fq_zech_ctx_degree(const fq_zech_ctx_t ctx) + fmpz_struct * fq_zech_ctx_prime(const fq_zech_ctx_t ctx) + void fq_zech_ctx_order(fmpz_t f, const fq_zech_ctx_t ctx) + mp_limb_t fq_zech_ctx_order_ui(const fq_zech_ctx_t ctx) + # int fq_zech_ctx_fprint(FILE * file, const fq_zech_ctx_t ctx) + void fq_zech_ctx_print(const fq_zech_ctx_t ctx) + void fq_zech_ctx_randtest(fq_zech_ctx_t ctx) + void fq_zech_ctx_randtest_reducible(fq_zech_ctx_t ctx) + void fq_zech_init(fq_zech_t rop, const fq_zech_ctx_t ctx) + void fq_zech_init2(fq_zech_t rop, const fq_zech_ctx_t ctx) + void fq_zech_clear(fq_zech_t rop, const fq_zech_ctx_t ctx) + void _fq_zech_sparse_reduce(mp_ptr R, slong lenR, const fq_zech_ctx_t ctx) + void _fq_zech_dense_reduce(mp_ptr R, slong lenR, const fq_zech_ctx_t ctx) + void _fq_zech_reduce(mp_ptr r, slong lenR, const fq_zech_ctx_t ctx) + void fq_zech_reduce(fq_zech_t rop, const fq_zech_ctx_t ctx) + void fq_zech_add(fq_zech_t rop, const fq_zech_t op1, const fq_zech_t op2, const fq_zech_ctx_t ctx) + void fq_zech_sub(fq_zech_t rop, const fq_zech_t op1, const fq_zech_t op2, const fq_zech_ctx_t ctx) + void fq_zech_sub_one(fq_zech_t rop, const fq_zech_t op1, const fq_zech_ctx_t ctx) + void fq_zech_neg(fq_zech_t rop, const fq_zech_t op, const fq_zech_ctx_t ctx) + void fq_zech_mul(fq_zech_t rop, const fq_zech_t op1, const fq_zech_t op2, const fq_zech_ctx_t ctx) + void fq_zech_mul_fmpz(fq_zech_t rop, const fq_zech_t op, const fmpz_t x, const fq_zech_ctx_t ctx) + void fq_zech_mul_si(fq_zech_t rop, const fq_zech_t op, slong x, const fq_zech_ctx_t ctx) + void fq_zech_mul_ui(fq_zech_t rop, const fq_zech_t op, ulong x, const fq_zech_ctx_t ctx) + void fq_zech_sqr(fq_zech_t rop, const fq_zech_t op, const fq_zech_ctx_t ctx) + void fq_zech_div(fq_zech_t rop, const fq_zech_t op1, const fq_zech_t op2, const fq_zech_ctx_t ctx) + void _fq_zech_inv(mp_ptr *rop, mp_srcptr *op, slong len, const fq_zech_ctx_t ctx) + void fq_zech_inv(fq_zech_t rop, const fq_zech_t op, const fq_zech_ctx_t ctx) + void fq_zech_gcdinv(fq_zech_t f, fq_zech_t inv, const fq_zech_t op, const fq_zech_ctx_t ctx) + void _fq_zech_pow(mp_ptr *rop, mp_srcptr *op, slong len, const fmpz_t e, const fq_zech_ctx_t ctx) + void fq_zech_pow(fq_zech_t rop, const fq_zech_t op, const fmpz_t e, const fq_zech_ctx_t ctx) + void fq_zech_pow_ui(fq_zech_t rop, const fq_zech_t op, const ulong e, const fq_zech_ctx_t ctx) + void fq_zech_sqrt(fq_zech_t rop, const fq_zech_t op1, const fq_zech_ctx_t ctx) + void fq_zech_pth_root(fq_zech_t rop, const fq_zech_t op1, const fq_zech_ctx_t ctx) + int fq_zech_is_square(const fq_zech_t op, const fq_zech_ctx_t ctx) + # int fq_zech_fprint_pretty(FILE *file, const fq_zech_t op, const fq_zech_ctx_t ctx) + int fq_zech_print_pretty(const fq_zech_t op, const fq_zech_ctx_t ctx) + # void fq_zech_fprint(FILE * file, const fq_zech_t op, const fq_zech_ctx_t ctx) + void fq_zech_print(const fq_zech_t op, const fq_zech_ctx_t ctx) + char * fq_zech_get_str(const fq_zech_t op, const fq_zech_ctx_t ctx) + char * fq_zech_get_str_pretty(const fq_zech_t op, const fq_zech_ctx_t ctx) + void fq_zech_randtest(fq_zech_t rop, flint_rand_t state, const fq_zech_ctx_t ctx) + void fq_zech_randtest_not_zero(fq_zech_t rop, flint_rand_t state, const fq_zech_ctx_t ctx) + void fq_zech_randtest_dense(fq_zech_t rop, flint_rand_t state, const fq_zech_ctx_t ctx) + void fq_zech_rand(fq_zech_t rop, flint_rand_t state, const fq_zech_ctx_t ctx) + void fq_zech_rand_not_zero(fq_zech_t rop, flint_rand_t state, const fq_zech_ctx_t ctx) + void fq_zech_set(fq_zech_t rop, const fq_zech_t op, const fq_zech_ctx_t ctx) + void fq_zech_set_si(fq_zech_t rop, const slong x, const fq_zech_ctx_t ctx) + void fq_zech_set_ui(fq_zech_t rop, const ulong x, const fq_zech_ctx_t ctx) + void fq_zech_set_fmpz(fq_zech_t rop, const fmpz_t x, const fq_zech_ctx_t ctx) + void fq_zech_swap(fq_zech_t op1, fq_zech_t op2, const fq_zech_ctx_t ctx) + void fq_zech_zero(fq_zech_t rop, const fq_zech_ctx_t ctx) + void fq_zech_one(fq_zech_t rop, const fq_zech_ctx_t ctx) + void fq_zech_gen(fq_zech_t rop, const fq_zech_ctx_t ctx) + int fq_zech_get_fmpz(fmpz_t rop, const fq_zech_t op, const fq_zech_ctx_t ctx) + void fq_zech_get_fq_nmod(fq_nmod_t rop, const fq_zech_t op, const fq_zech_ctx_t ctx) + void fq_zech_set_fq_nmod(fq_zech_t rop, const fq_nmod_t op, const fq_zech_ctx_t ctx) + void fq_zech_get_nmod_poly(nmod_poly_t a, const fq_zech_t b, const fq_zech_ctx_t ctx) + void fq_zech_set_nmod_poly(fq_zech_t a, const nmod_poly_t b, const fq_zech_ctx_t ctx) + void fq_zech_get_nmod_mat(nmod_mat_t col, const fq_zech_t a, const fq_zech_ctx_t ctx) + void fq_zech_set_nmod_mat(fq_zech_t a, const nmod_mat_t col, const fq_zech_ctx_t ctx) + int fq_zech_is_zero(const fq_zech_t op, const fq_zech_ctx_t ctx) + int fq_zech_is_one(const fq_zech_t op, const fq_zech_ctx_t ctx) + int fq_zech_equal(const fq_zech_t op1, const fq_zech_t op2, const fq_zech_ctx_t ctx) + int fq_zech_is_invertible(const fq_zech_t op, const fq_zech_ctx_t ctx) + int fq_zech_is_invertible_f(fq_zech_t f, const fq_zech_t op, const fq_zech_ctx_t ctx) + void fq_zech_trace(fmpz_t rop, const fq_zech_t op, const fq_zech_ctx_t ctx) + void fq_zech_norm(fmpz_t rop, const fq_zech_t op, const fq_zech_ctx_t ctx) + void fq_zech_frobenius(fq_zech_t rop, const fq_zech_t op, slong e, const fq_zech_ctx_t ctx) + int fq_zech_multiplicative_order(fmpz_t ord, const fq_zech_t op, const fq_zech_ctx_t ctx) + int fq_zech_is_primitive(const fq_zech_t op, const fq_zech_ctx_t ctx) + void fq_zech_bit_pack(fmpz_t f, const fq_zech_t op, flint_bitcnt_t bit_size, const fq_zech_ctx_t ctx) + void fq_zech_bit_unpack(fq_zech_t rop, const fmpz_t f, flint_bitcnt_t bit_size, const fq_zech_ctx_t ctx) diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd new file mode 100644 index 00000000..1a333751 --- /dev/null +++ b/src/flint/types/fq_default.pxd @@ -0,0 +1,11 @@ +from flint.flintlib.fq_default cimport * + +from flint.flint_base.flint_base cimport flint_scalar + + +cdef class fq_default_ctx: + pass + + +cdef class fq_default(flint_scalar): + pass diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx new file mode 100644 index 00000000..e69de29b From 3d637f61a7b92518694f48529a2c3c9c194c9a85 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Tue, 6 Aug 2024 09:00:30 +0100 Subject: [PATCH 02/36] further work on fq_default with luca de feo Co-Authored-By: Luca De Feo <1315842+defeo@users.noreply.github.com> --- setup.py | 2 + src/flint/__init__.py | 2 + src/flint/flint_base/flint_base.pyx | 10 +- src/flint/flintlib/fq_default.pxd | 41 +---- src/flint/types/fq_default.pxd | 21 ++- src/flint/types/fq_default.pyx | 265 ++++++++++++++++++++++++++++ 6 files changed, 295 insertions(+), 46 deletions(-) diff --git a/setup.py b/setup.py index d260834e..93e83c9d 100644 --- a/setup.py +++ b/setup.py @@ -105,6 +105,8 @@ ("flint.types.fmpq_mpoly", ["src/flint/types/fmpq_mpoly.pyx"]), ("flint.types.fmpz_mpoly_q", ["src/flint/types/fmpz_mpoly_q.pyx"]), + ("flint.types.fq_default", ["src/flint/types/fq_default.pyx"]), + ("flint.types.arf", ["src/flint/types/arf.pyx"]), ("flint.types.arb", ["src/flint/types/arb.pyx"]), ("flint.types.arb_poly", ["src/flint/types/arb_poly.pyx"]), diff --git a/src/flint/__init__.py b/src/flint/__init__.py index 77656aca..4db5de5f 100644 --- a/src/flint/__init__.py +++ b/src/flint/__init__.py @@ -24,6 +24,8 @@ from .types.fmpq_mpoly import fmpq_mpoly_ctx, fmpq_mpoly, fmpq_mpoly_vec +from .types.fq_default import * + from .types.arf import * from .types.arb import * from .types.arb_poly import * diff --git a/src/flint/flint_base/flint_base.pyx b/src/flint/flint_base/flint_base.pyx index 481cac7f..3704d1d0 100644 --- a/src/flint/flint_base/flint_base.pyx +++ b/src/flint/flint_base/flint_base.pyx @@ -55,7 +55,7 @@ cdef class flint_poly(flint_elem): """ return list(self) - def str(self, bint ascending=False, *args, **kwargs): + def str(self, bint ascending=False, var="x", *args, **kwargs): """ Convert to a human-readable string (generic implementation for all polynomial types). @@ -80,14 +80,14 @@ cdef class flint_poly(flint_elem): s.append("%s" % c) elif i == 1: if c == "1": - s.append("x") + s.append(var) else: - s.append("%s*x" % c) + s.append(f"{c}*{var}") else: if c == "1": - s.append("x^%s" % i) + s.append(f"{var}^{i}") else: - s.append("%s*x^%s" % (c, i)) + s.append(f"{c}*{var}^{i}") return " + ".join(s) def roots(self): diff --git a/src/flint/flintlib/fq_default.pxd b/src/flint/flintlib/fq_default.pxd index 289df611..c8dab74c 100644 --- a/src/flint/flintlib/fq_default.pxd +++ b/src/flint/flintlib/fq_default.pxd @@ -12,21 +12,8 @@ from flint.flintlib.fq_nmod cimport fq_nmod_t, fq_nmod_ctx_t from flint.flintlib.fq_zech cimport fq_zech_t, fq_zech_ctx_t cdef extern from "flint/fq_default.h": - """ - TODO: how best to handle union - https://stackoverflow.com/questions/12452210/cython-nesting-a-union-within-a-struct - - typedef union fq_default_struct - { - fq_t fq; - fq_nmod_t fq_nmod; - fq_zech_t fq_zech; - ulong nmod; - fmpz_t fmpz_mod; - } fq_default_struct; - - typedef fq_default_struct fq_default_t[1]; - """ + # TODO: how best to handle union + # https://stackoverflow.com/questions/12452210/cython-nesting-a-union-within-a-struct ctypedef struct fq_default_struct: fq_t fq fq_nmod_t fq_nmod @@ -35,30 +22,6 @@ cdef extern from "flint/fq_default.h": fmpz_t fmpz_mod ctypedef fq_default_struct fq_default_t[1] - """ - TODO: how best to handle union - https://stackoverflow.com/questions/12452210/cython-nesting-a-union-within-a-struct - - typedef struct - { - int type; - union ctx - { - fq_ctx_t fq; - fq_nmod_ctx_t fq_nmod; - fq_zech_ctx_t fq_zech; - struct { - nmod_t mod; - mp_limb_t a; /* minpoly is x - a */ - } nmod; - struct { - fmpz_mod_ctx_t mod; - fmpz_t a; /* minpoly is x - a */ - } fmpz_mod; - } ctx; - } fq_default_ctx_struct; - """ - ctypedef struct fq_default_fmpz_mod_ctx_struct: fmpz_mod_ctx_t mod fmpz_t a # minpoly is x - a diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index 1a333751..f578249c 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -1,11 +1,28 @@ from flint.flintlib.fq_default cimport * +from flint.types.fmpz cimport fmpz from flint.flint_base.flint_base cimport flint_scalar +cpdef enum fq_default_type: + DEFAULT = 0 + FQ_ZECH = 1 + FQ_NMOD = 2 + FQ = 3 cdef class fq_default_ctx: - pass + cdef fq_default_ctx_t val + cdef readonly char *var + cdef bint initialized + + cdef set_any_as_fq_default(self, fq_default_t val, obj) + cdef any_as_fmpz_mod(self, obj) + + @staticmethod + cdef fq_default_ctx c_from_order(fmpz p, int d, char *var, fq_default_type type=*) + @staticmethod + cdef fq_default_ctx c_from_modulus(modulus, char *var, fq_default_type type=*) cdef class fq_default(flint_scalar): - pass + cdef fq_default_ctx ctx + cdef fq_default_t val diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index e69de29b..01bcade3 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -0,0 +1,265 @@ +from flint.types.fmpz cimport fmpz, any_as_fmpz +from flint.types.fmpz_mod_poly cimport fmpz_mod_poly, fmpz_mod_poly_ctx +from flint.types.nmod_poly cimport nmod_poly +from flint.utils.typecheck cimport typecheck + +cdef class fq_default_ctx: + r""" + Context object for creating :class:`~.fq_default`. + + Finite fields can be initialized in one of two possible ways. The + first is by providing characteristic and degree: + + >>> fq_default_ctx.from_order(fmpz(5), 2, 'y') + fq_default_ctx.from_modulus(x^2 + 4*x + 2, b'y', 1) + + The second is by giving an irreducible polynomial of type + :class:`~.nmod_poly` or :class:`~.fmpz_mod_poly`: + + >>> fq_default_ctx.from_modulus(fmpz_mod_poly([1,0,1], fmpz_mod_poly_ctx(11)), 'x') + fq_default_ctx.from_modulus(x^2 + 1, b'x', 2) + + For more details, see the documentation of :method:`~.from_order` + and :method:`~.from_modulus`. + """ + def __dealloc__(self): + if self.initialized is not None: + fq_default_ctx_clear(self.val) + + def __init__(self): + raise TypeError("This class cannot be instantiated directly. Use .from_order() or .from_modulus().") + + @staticmethod + cdef fq_default_ctx c_from_order(fmpz p, int d, char *var, + fq_default_type type=fq_default_type.DEFAULT): + cdef fq_default_ctx ctx = fq_default_ctx.__new__(fq_default_ctx) + ctx.var = var + fq_default_ctx_init_type(ctx.val, p.val, d, ctx.var, type) + ctx.initialized = True + return ctx + + @staticmethod + def from_order(p, d, var, type=fq_default_type.DEFAULT): + """ + Construct a context for the finite field GF(p^d). + + `var` is a name for the ring generator of this field over GF(p). + + The optional parameter `type` select the implementation. The + possible values are: + + - `fq_default_ctx.DEFAULT`: implementation automatically decided by Flint (default), + - `fq_default_ctx.FQ_ZECH`: Use `fq_zech_t`, + - `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, + - `fq_default_ctx.FQ`: Use `fq_t`. + + >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y') + >>> gf + fq_default_ctx.from_modulus(x^2 + 4*x + 2, b'y', 1) + >>> gf.type + + + >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y', fq_default_type.FQ_NMOD) + >>> gf + fq_default_ctx.from_modulus(x^2 + 4*x + 2, b'y', 2) + >>> gf.type + + + + """ + # c_from_order expects the characteristic to be fmpz type + order = any_as_fmpz(p) + if order is NotImplemented: + raise TypeError(f"cannot coerce {p = } to type fmpz") + + # the degree must be strictly positive + if d < 1: + raise ValueError(f"the degree must be positive, got {d = }") + + # TODO: we should allow var to be None when d == 1 + if isinstance(var, str): + var = var.encode() + + return fq_default_ctx.c_from_order(order, d, var, type) + + @staticmethod + cdef fq_default_ctx c_from_modulus(modulus, char *var, + fq_default_type type=fq_default_type.DEFAULT): + cdef fq_default_ctx ctx = fq_default_ctx.__new__(fq_default_ctx) + + ctx.var = var + if typecheck(modulus, fmpz_mod_poly): + fq_default_ctx_init_modulus_type(ctx.val, (modulus).val, + (modulus).ctx.mod.val, ctx.var, type) + elif typecheck(modulus, nmod_poly): + fq_default_ctx_init_modulus_nmod_type(ctx.val, (modulus).val, + ctx.var, type) + else: + raise TypeError(f"modulus must be fmpz_mod_poly or nmod_poly, got {modulus!r}") + ctx.initialized = True + + return ctx + + @staticmethod + def from_modulus(modulus, var, type=fq_default_type.DEFAULT): + """ + Construct a context for a finite field from an irreducible polynomial. + + `modulus` may be of type :class:`~.fmpz_mod_poly` or :class:`~.nmod_poly`. + + `var` is a name for the ring generator of this field over the prime field. + + The optional parameter `type` select the implementation. The + possible values are: + + - `fq_default_ctx.DEFAULT`: implementation automatically decided by Flint (default), + - `fq_default_ctx.FQ_ZECH`: Use `fq_zech_t`, + - `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, + - `fq_default_ctx.FQ`: Use `fq_t`. + + >>> gf = fq_default_ctx.from_modulus(fmpz_mod_poly([1,0,1], fmpz_mod_poly_ctx(11)), 'x') + >>> gf + fq_default_ctx.from_modulus(x^2 + 1, b'x', 2) + >>> gf.type + + + >>> gf = fq_default_ctx.from_modulus(fmpz_mod_poly([1,0,1], fmpz_mod_poly_ctx(11)), 'x', fq_default_type.FQ) + >>> gf + fq_default_ctx.from_modulus(x^2 + 1, b'x', 2) + >>> gf.type + + + """ + if isinstance(var, str): + var = var.encode() + return fq_default_ctx.c_from_modulus(modulus, var, type) + + @property + def type(self): + """ + Return the implementation of this context. It is one of: + + - `fq_default_ctx.FQ_ZECH`: Using `fq_zech_t`, + - `fq_default_ctx.FQ_NMOD`: Using `fq_nmod_t`, + - `fq_default_ctx.FQ`: Using `fq_t`. + """ + return fq_default_type(fq_default_ctx_type(self.val)) + + def degree(self): + """ + >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y') + >>> gf.degree() + 2 + """ + return fq_default_ctx_degree(self.val) + + def prime(self): + """ + >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y') + >>> gf.prime() + 5 + """ + cdef fmpz p + p = fmpz.__new__(fmpz) + fq_default_ctx_prime(p.val, self.val) + return p + + def order(self): + """ + >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y') + >>> gf.prime() + 25 + """ + cdef fmpz q + q = fmpz.__new__(fmpz) + fq_default_ctx_order(q.val, self.val) + return q + + def modulus(self): + """ + Return the modulus from the context as an fmpz_mod_poly type + + >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y') + >>> gf.modulus() + x^2 + 4*x + 2 + + """ + cdef fmpz_mod_poly_ctx ctx + cdef fmpz_mod_poly pol + ctx = fmpz_mod_poly_ctx(self.prime()) + pol = ctx.new_ctype_poly() + fq_default_ctx_modulus(pol.val, self.val) + return pol + + def zero(self): + """ + Return the zero element + + >>> F = fmpz_mod_ctx(163) + >>> F.zero() + fmpz_mod(0, 163) + """ + pass + + def one(self): + """ + Return the one element + + >>> F = fmpz_mod_ctx(163) + >>> F.one() + fmpz_mod(1, 163) + """ + pass + + def random_element(self): + r""" + Return a random element in :math:`\mathbb{Z}/N\mathbb{Z}` + """ + pass + + cdef set_any_as_fq_default(self, fq_default_t val, obj): + pass + + cdef any_as_fmpz_mod(self, obj): + pass + + def __eq__(self, other): + """ + Two finite field context compare equal if they have same + characteristic, modulus, type and variable + + >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y') + >>> gf2 = fq_default_ctx.from_modulus(fmpz_mod_poly([2,4,1], fmpz_mod_poly_ctx(5)), 'y', 1) + >>> gf2 == gf + True + >>> gf3 = fq_default_ctx.from_modulus(fmpz_mod_poly([2,4,1], fmpz_mod_poly_ctx(5)), 'x', 1) + >>> gf3 == gf + False + + """ + if self is other: + return True + + if typecheck(other, fq_default_ctx): + return (self.type == other.type + and self.var == other.var + and self.prime() == other.prime() + and self.modulus() == other.modulus()) + else: + raise TypeError(f"Cannot compare fq_default_ctx with {type(other)}") + + def __hash__(self): + return hash((self.type, self.var, self.prime(), self.modulus())) + + def __str__(self): + return f"Context for fq_default in GF({self.prime()}^{self.degree()})[{self.var.decode()}]/({self.modulus().str(var=self.var.decode())})" + + def __repr__(self): + return f"fq_default_ctx.from_modulus({self.modulus()!r}, {self.var.encode()}, {self.type})" + + def __call__(self, val): + return fq_default(val, self) + + +cdef class fq_default(flint_scalar): + pass From b728899bafc5004c789d1d46739e075875b7d584 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Tue, 6 Aug 2024 11:58:35 +0100 Subject: [PATCH 03/36] add line to meson build --- src/flint/types/meson.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/flint/types/meson.build b/src/flint/types/meson.build index 4dbfcd35..d256d389 100644 --- a/src/flint/types/meson.build +++ b/src/flint/types/meson.build @@ -26,6 +26,8 @@ exts = [ 'fmpz_mod_poly', 'fmpz_mod_mat', + 'fq_default', + 'arf', 'arb', From c8fe69961f39dace4b56375d963cbc89bfec0f42 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Tue, 6 Aug 2024 17:24:51 +0100 Subject: [PATCH 04/36] more boilerplate code --- src/flint/flint_base/flint_base.pyx | 73 ++++++++++- src/flint/flintlib/fq_default.pxd | 6 +- src/flint/types/fq_default.pxd | 5 +- src/flint/types/fq_default.pyx | 188 +++++++++++++++++++++++++--- 4 files changed, 249 insertions(+), 23 deletions(-) diff --git a/src/flint/flint_base/flint_base.pyx b/src/flint/flint_base/flint_base.pyx index 3704d1d0..e723b648 100644 --- a/src/flint/flint_base/flint_base.pyx +++ b/src/flint/flint_base/flint_base.pyx @@ -30,7 +30,78 @@ cdef class flint_elem: cdef class flint_scalar(flint_elem): - pass + # ================================================= + # These are the functions a new class should define + # assumes that addition and multiplication are + # commutative + # ================================================= + def _neg_(self): + return NotImplemented + + def _add_(self, other): + return NotImplemented + + @staticmethod + def _sub_(left, right): + return NotImplemented + + def _mul_(self, other): + return NotImplemented + + @staticmethod + def _div_(left, right): + return NotImplemented + + @staticmethod + def _floordiv_(left, right): + return NotImplemented + + def _invert_(self): + return NotImplemented + + # ================================================= + # Generic arithmetic using the above functions + # ================================================= + + def __pos__(self): + return self + + def __neg__(self): + return self._neg_() + + def __add__(self, other): + return self._add_(other) + + def __radd__(self, other): + return self._add_(other) + + def __sub__(self, other): + return self._sub_(self, other) + + def __rsub__(self, other): + return self._sub_(other, self) + + def __mul__(self, other): + return self._mul_(other) + + def __rmul__(self, other): + return self._mul_(other) + + def __truediv__(self, other): + return self._div_(self, other) + + def __rtruediv__(self, other): + return self._div_(other, self) + + def __floordiv__(self, other): + return self._floordiv_(self, other) + + def __rfloordiv__(self, other): + return self._floordiv_(other, self) + + def __invert__(self): + return self._invert_() + cdef class flint_poly(flint_elem): diff --git a/src/flint/flintlib/fq_default.pxd b/src/flint/flintlib/fq_default.pxd index c8dab74c..fa49dcd0 100644 --- a/src/flint/flintlib/fq_default.pxd +++ b/src/flint/flintlib/fq_default.pxd @@ -96,8 +96,10 @@ cdef extern from "flint/fq_default.h": int fq_default_get_fmpz(fmpz_t rop, const fq_default_t op, const fq_default_ctx_t ctx) void fq_default_get_nmod_poly(nmod_poly_t poly, const fq_default_t op, const fq_default_ctx_t ctx) void fq_default_set_nmod_poly(fq_default_t op, const nmod_poly_t poly, const fq_default_ctx_t ctx) - void fq_default_get_fmpz_mod_poly(fmpz_mod_poly_t poly, const fq_default_t op, const fmpz_mod_ctx_t mod_ctx, const fq_default_ctx_t ctx) - void fq_default_set_fmpz_mod_poly(fq_default_t op, const fmpz_mod_poly_t poly, const fmpz_mod_ctx_t mod_ctx, const fq_default_ctx_t ctx) + # void fq_default_get_fmpz_mod_poly(fmpz_mod_poly_t poly, const fq_default_t op, const fmpz_mod_ctx_t mod_ctx, const fq_default_ctx_t ctx) + # void fq_default_set_fmpz_mod_poly(fq_default_t op, const fmpz_mod_poly_t poly, const fmpz_mod_ctx_t mod_ctx, const fq_default_ctx_t ctx) + void fq_default_get_fmpz_mod_poly(fmpz_mod_poly_t poly, const fq_default_t op, const fq_default_ctx_t ctx) + void fq_default_set_fmpz_mod_poly(fq_default_t op, const fmpz_mod_poly_t poly, const fq_default_ctx_t ctx) void fq_default_get_fmpz_poly(fmpz_poly_t a, const fq_default_t b, const fq_default_ctx_t ctx) void fq_default_set_fmpz_poly(fq_default_struct a, const fmpz_poly_t b, const fq_default_ctx_t ctx) int fq_default_is_zero(const fq_default_t op, const fq_default_ctx_t ctx) diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index f578249c..ebec1997 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -12,13 +12,14 @@ cpdef enum fq_default_type: cdef class fq_default_ctx: cdef fq_default_ctx_t val cdef readonly char *var - cdef bint initialized + cdef bint _initialized + cdef new_ctype_fq_default(self) cdef set_any_as_fq_default(self, fq_default_t val, obj) - cdef any_as_fmpz_mod(self, obj) @staticmethod cdef fq_default_ctx c_from_order(fmpz p, int d, char *var, fq_default_type type=*) + @staticmethod cdef fq_default_ctx c_from_modulus(modulus, char *var, fq_default_type type=*) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 01bcade3..95800204 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -1,4 +1,6 @@ +from flint.pyflint cimport global_random_state from flint.types.fmpz cimport fmpz, any_as_fmpz +from flint.types.fmpz_poly cimport fmpz_poly from flint.types.fmpz_mod_poly cimport fmpz_mod_poly, fmpz_mod_poly_ctx from flint.types.nmod_poly cimport nmod_poly from flint.utils.typecheck cimport typecheck @@ -22,11 +24,14 @@ cdef class fq_default_ctx: For more details, see the documentation of :method:`~.from_order` and :method:`~.from_modulus`. """ + def __cinit__(self): + pass + def __dealloc__(self): - if self.initialized is not None: + if self._initialized: fq_default_ctx_clear(self.val) - def __init__(self): + def __init__(self, *args, **kwargs): raise TypeError("This class cannot be instantiated directly. Use .from_order() or .from_modulus().") @staticmethod @@ -35,7 +40,7 @@ cdef class fq_default_ctx: cdef fq_default_ctx ctx = fq_default_ctx.__new__(fq_default_ctx) ctx.var = var fq_default_ctx_init_type(ctx.val, p.val, d, ctx.var, type) - ctx.initialized = True + ctx._initialized = True return ctx @staticmethod @@ -64,8 +69,6 @@ cdef class fq_default_ctx: fq_default_ctx.from_modulus(x^2 + 4*x + 2, b'y', 2) >>> gf.type - - """ # c_from_order expects the characteristic to be fmpz type order = any_as_fmpz(p) @@ -163,6 +166,8 @@ cdef class fq_default_ctx: p = fmpz.__new__(fmpz) fq_default_ctx_prime(p.val, self.val) return p + + characteristic = prime def order(self): """ @@ -195,11 +200,15 @@ cdef class fq_default_ctx: """ Return the zero element - >>> F = fmpz_mod_ctx(163) - >>> F.zero() + >>> Fq = fq_default_ctx.from_order(5, 1, "x") + >>> Fq.zero() fmpz_mod(0, 163) """ - pass + cdef fq_default res + res = self.new_ctype_fq_default() + res.ctx = self + fq_default_zero(res.val, self.val) + return res def one(self): """ @@ -209,19 +218,33 @@ cdef class fq_default_ctx: >>> F.one() fmpz_mod(1, 163) """ - pass + cdef fq_default res + res = self.new_ctype_fq_default() + res.ctx = self + fq_default_one(res.val, self.val) + return res - def random_element(self): + def random_element(self, not_zero=False): r""" - Return a random element in :math:`\mathbb{Z}/N\mathbb{Z}` + Return a random element of the finite field """ - pass + cdef fq_default res + res = self.new_ctype_fq_default() + res.ctx = self + if not_zero: + fq_default_rand_not_zero(res.val, global_random_state, self.val) + else: + fq_default_rand(res.val, global_random_state, self.val) + return res - cdef set_any_as_fq_default(self, fq_default_t val, obj): - pass + cdef new_ctype_fq_default(self): + return fq_default.__new__(fq_default, None, self) - cdef any_as_fmpz_mod(self, obj): - pass + cdef set_any_as_fq_default(self, fq_default_t val, obj): + if typecheck(obj, fmpz): + fq_default_set_fmpz(val, (obj).val, self.val) + return 0 + return NotImplemented def __eq__(self, other): """ @@ -255,11 +278,140 @@ cdef class fq_default_ctx: return f"Context for fq_default in GF({self.prime()}^{self.degree()})[{self.var.decode()}]/({self.modulus().str(var=self.var.decode())})" def __repr__(self): - return f"fq_default_ctx.from_modulus({self.modulus()!r}, {self.var.encode()}, {self.type})" + return f"fq_default_ctx.from_modulus({self.modulus()!r}, {self.var.decode()}, {self.type})" def __call__(self, val): return fq_default(val, self) cdef class fq_default(flint_scalar): - pass + def __cinit__(self, val, ctx): + if not typecheck(ctx, fq_default_ctx): + raise TypeError + self.ctx = ctx + fq_default_init(self.val, self.ctx.val) + + def __dealloc__(self): + if self.ctx is not None: + fq_default_clear(self.val, self.ctx.val) + + def __init__(self, val, ctx): + if not typecheck(ctx, fq_default_ctx): + raise TypeError + self.ctx = ctx + + check = self.ctx.set_any_as_fq_default(self.val, val) + if check is NotImplemented: + raise TypeError + + def __int__(self): + """ + Attempts to lift self to an integer of type fmpz in [0, p-1] + """ + cdef fmpz x = fmpz.__new__(fmpz) + res = fq_default_get_fmpz(x.val, self.val, self.ctx.val) + if res == 1: + return int(x) + raise ValueError("fq element has no lift to the integers") + + def polynomial(self): + """ + Returns a representative of ``self`` as a polynomial in `(Z/pZ)[x] / h(x)` + where `h(x)` is the defining polynomial of the finite field. + """ + cdef fmpz_mod_poly_ctx ctx + cdef fmpz_mod_poly pol + + ring_ctx = fmpz_mod_poly_ctx(self.ctx.prime()) + pol = ring_ctx.new_ctype_poly() + fq_default_get_fmpz_mod_poly((pol).val, self.val, self.ctx.val) + + return pol + + def __repr__(self): + return f"fq_default({self.polynomial()}, {self.ctx.__repr__()})" + + def str(self): + return self.polynomial().__str__() + + # ================================================= + # Comparisons + # ================================================= + def is_zero(self): + return 1 == fq_default_is_zero(self.val, self.ctx.val) + + def is_one(self): + return 1 == fq_default_is_zero(self.val, self.ctx.val) + + # ================================================= + # Generic arithmetic required by flint_scalar + # ================================================= + + def _neg_(self): + cdef fq_default res + res = self.ctx.new_ctype_fq_default() + fq_default_neg(res.val, self.val, self.ctx.val) + return res + + def _add_(self, other): + return NotImplemented + + @staticmethod + def _sub_(left, right): + return NotImplemented + + def _mul_(self, other): + return NotImplemented + + @staticmethod + def _div_(left, right): + return NotImplemented + + def _invert_(self): + cdef fq_default res + res = self.ctx.new_ctype_fq_default() + fq_default_inv(res.val, self.val, self.ctx.val) + return res + + # ================================================= + # Additional arithmetic + # ================================================= + + def square(self): + cdef fq_default res + res = self.ctx.new_ctype_fq_default() + fq_default_sqr(res.val, self.val, self.ctx.val) + return res + + def __pow__(self, e): + return NotImplemented + + def sqrt(self): + cdef fq_default res + res = self.ctx.new_ctype_fq_default() + check = fq_default_sqrt(res.val, self.val, self.ctx.val) + if check: + return res + raise ValueError("element is not a square") + + def is_square(self): + return 1 == fq_default_is_square(self.val, self.ctx.val) + + def pth_root(self): + cdef fq_default res + res = self.ctx.new_ctype_fq_default() + fq_default_pth_root(res.val, self.val, self.ctx.val) + return res + + # ================================================= + # Special functions + # ================================================= + + def trace(self): + return NotImplemented + + def norm(self): + return NotImplemented + + def frobenius(self): + return NotImplemented From 130711632e428837f219561ab9ab8516ea43e5f0 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 10:15:51 +0100 Subject: [PATCH 05/36] add fq_default to the doctests --- src/flint/test/__main__.py | 1 + src/flint/types/fq_default.pyx | 74 ++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/flint/test/__main__.py b/src/flint/test/__main__.py index f837f63a..580e90c6 100644 --- a/src/flint/test/__main__.py +++ b/src/flint/test/__main__.py @@ -71,6 +71,7 @@ def run_doctests(verbose=None): flint.types.nmod_poly, flint.types.nmod_mat, flint.types.nmod_series, + flint.types.fq_default, flint.types.arf, flint.types.arb, flint.types.arb_poly, diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 95800204..484d25b6 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -12,14 +12,16 @@ cdef class fq_default_ctx: Finite fields can be initialized in one of two possible ways. The first is by providing characteristic and degree: - >>> fq_default_ctx.from_order(fmpz(5), 2, 'y') - fq_default_ctx.from_modulus(x^2 + 4*x + 2, b'y', 1) + >>> fq_default_ctx.from_order(5, 2, 'y') + fq_default_ctx.from_modulus(x^2 + 4*x + 2, 'y', 1) The second is by giving an irreducible polynomial of type :class:`~.nmod_poly` or :class:`~.fmpz_mod_poly`: - >>> fq_default_ctx.from_modulus(fmpz_mod_poly([1,0,1], fmpz_mod_poly_ctx(11)), 'x') - fq_default_ctx.from_modulus(x^2 + 1, b'x', 2) + >>> from flint import fmpz_mod_poly_ctx + >>> modulus = fmpz_mod_poly_ctx(11)([1,0,1]) + >>> fq_default_ctx.from_modulus(modulus, 'x') + fq_default_ctx.from_modulus(x^2 + 1, 'x', 2) For more details, see the documentation of :method:`~.from_order` and :method:`~.from_modulus`. @@ -58,15 +60,15 @@ cdef class fq_default_ctx: - `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, - `fq_default_ctx.FQ`: Use `fq_t`. - >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y') + >>> gf = fq_default_ctx.from_order(5, 2, 'y') >>> gf - fq_default_ctx.from_modulus(x^2 + 4*x + 2, b'y', 1) + fq_default_ctx.from_modulus(x^2 + 4*x + 2, 'y', 1) >>> gf.type - >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y', fq_default_type.FQ_NMOD) + >>> gf = fq_default_ctx.from_order(5, 2, 'y', fq_default_type.FQ_NMOD) >>> gf - fq_default_ctx.from_modulus(x^2 + 4*x + 2, b'y', 2) + fq_default_ctx.from_modulus(x^2 + 4*x + 2, 'y', 2) >>> gf.type """ @@ -99,7 +101,7 @@ cdef class fq_default_ctx: ctx.var, type) else: raise TypeError(f"modulus must be fmpz_mod_poly or nmod_poly, got {modulus!r}") - ctx.initialized = True + ctx._initialized = True return ctx @@ -120,18 +122,19 @@ cdef class fq_default_ctx: - `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, - `fq_default_ctx.FQ`: Use `fq_t`. - >>> gf = fq_default_ctx.from_modulus(fmpz_mod_poly([1,0,1], fmpz_mod_poly_ctx(11)), 'x') + >>> from flint import fmpz_mod_poly_ctx + >>> modulus = fmpz_mod_poly_ctx(11)([1,0,1]) + >>> gf = fq_default_ctx.from_modulus(modulus, 'x') >>> gf - fq_default_ctx.from_modulus(x^2 + 1, b'x', 2) + fq_default_ctx.from_modulus(x^2 + 1, 'x', 2) >>> gf.type - >>> gf = fq_default_ctx.from_modulus(fmpz_mod_poly([1,0,1], fmpz_mod_poly_ctx(11)), 'x', fq_default_type.FQ) + >>> gf = fq_default_ctx.from_modulus(modulus, 'x', fq_default_type.FQ) >>> gf - fq_default_ctx.from_modulus(x^2 + 1, b'x', 2) + fq_default_ctx.from_modulus(x^2 + 1, 'x', 3) >>> gf.type - """ if isinstance(var, str): var = var.encode() @@ -150,7 +153,7 @@ cdef class fq_default_ctx: def degree(self): """ - >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y') + >>> gf = fq_default_ctx.from_order(5, 2, 'y') >>> gf.degree() 2 """ @@ -158,7 +161,7 @@ cdef class fq_default_ctx: def prime(self): """ - >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y') + >>> gf = fq_default_ctx.from_order(5, 2, 'y') >>> gf.prime() 5 """ @@ -171,8 +174,8 @@ cdef class fq_default_ctx: def order(self): """ - >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y') - >>> gf.prime() + >>> gf = fq_default_ctx.from_order(5, 2, 'y') + >>> gf.order() 25 """ cdef fmpz q @@ -184,7 +187,7 @@ cdef class fq_default_ctx: """ Return the modulus from the context as an fmpz_mod_poly type - >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y') + >>> gf = fq_default_ctx.from_order(5, 2, 'y') >>> gf.modulus() x^2 + 4*x + 2 @@ -200,9 +203,9 @@ cdef class fq_default_ctx: """ Return the zero element - >>> Fq = fq_default_ctx.from_order(5, 1, "x") - >>> Fq.zero() - fmpz_mod(0, 163) + >>> gf = fq_default_ctx.from_order(5, 1, "x") + >>> gf.zero() + 0 """ cdef fq_default res res = self.new_ctype_fq_default() @@ -214,9 +217,9 @@ cdef class fq_default_ctx: """ Return the one element - >>> F = fmpz_mod_ctx(163) - >>> F.one() - fmpz_mod(1, 163) + >>> gf = fq_default_ctx.from_order(5, 1, "x") + >>> gf.one() + 1 """ cdef fq_default res res = self.new_ctype_fq_default() @@ -251,14 +254,16 @@ cdef class fq_default_ctx: Two finite field context compare equal if they have same characteristic, modulus, type and variable - >>> gf = fq_default_ctx.from_order(fmpz(5), 2, 'y') - >>> gf2 = fq_default_ctx.from_modulus(fmpz_mod_poly([2,4,1], fmpz_mod_poly_ctx(5)), 'y', 1) + >>> from flint import fmpz_mod_poly_ctx + >>> R = fmpz_mod_poly_ctx(5) + >>> modulus = R([2,4,1]) + >>> gf = fq_default_ctx.from_order(5, 2, 'y') + >>> gf2 = fq_default_ctx.from_modulus(modulus, 'y', 1) >>> gf2 == gf True - >>> gf3 = fq_default_ctx.from_modulus(fmpz_mod_poly([2,4,1], fmpz_mod_poly_ctx(5)), 'x', 1) + >>> gf3 = fq_default_ctx.from_modulus(modulus, 'x', 1) >>> gf3 == gf False - """ if self is other: return True @@ -278,7 +283,7 @@ cdef class fq_default_ctx: return f"Context for fq_default in GF({self.prime()}^{self.degree()})[{self.var.decode()}]/({self.modulus().str(var=self.var.decode())})" def __repr__(self): - return f"fq_default_ctx.from_modulus({self.modulus()!r}, {self.var.decode()}, {self.type})" + return f"fq_default_ctx.from_modulus({self.modulus()!r}, '{self.var.decode()}', {self.type})" def __call__(self, val): return fq_default(val, self) @@ -328,11 +333,12 @@ cdef class fq_default(flint_scalar): return pol - def __repr__(self): - return f"fq_default({self.polynomial()}, {self.ctx.__repr__()})" - def str(self): - return self.polynomial().__str__() + return self.polynomial().str(var=self.ctx.var) + + def __repr__(self): + # TODO: what do we want here? + return str(self) # ================================================= # Comparisons From 6bf96a7b66ec1e4b3e5548ddcf6533bdd5248f11 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 11:11:07 +0100 Subject: [PATCH 06/36] start on type conversions and comparisons --- src/flint/flintlib/fq_default.pxd | 2 +- src/flint/types/fq_default.pxd | 4 +- src/flint/types/fq_default.pyx | 104 ++++++++++++++++++++++++++++-- 3 files changed, 102 insertions(+), 8 deletions(-) diff --git a/src/flint/flintlib/fq_default.pxd b/src/flint/flintlib/fq_default.pxd index fa49dcd0..ec4c20c5 100644 --- a/src/flint/flintlib/fq_default.pxd +++ b/src/flint/flintlib/fq_default.pxd @@ -101,7 +101,7 @@ cdef extern from "flint/fq_default.h": void fq_default_get_fmpz_mod_poly(fmpz_mod_poly_t poly, const fq_default_t op, const fq_default_ctx_t ctx) void fq_default_set_fmpz_mod_poly(fq_default_t op, const fmpz_mod_poly_t poly, const fq_default_ctx_t ctx) void fq_default_get_fmpz_poly(fmpz_poly_t a, const fq_default_t b, const fq_default_ctx_t ctx) - void fq_default_set_fmpz_poly(fq_default_struct a, const fmpz_poly_t b, const fq_default_ctx_t ctx) + void fq_default_set_fmpz_poly(fq_default_t a, const fmpz_poly_t b, const fq_default_ctx_t ctx) int fq_default_is_zero(const fq_default_t op, const fq_default_ctx_t ctx) int fq_default_is_one(const fq_default_t op, const fq_default_ctx_t ctx) int fq_default_equal(const fq_default_t op1, const fq_default_t op2, const fq_default_ctx_t ctx) diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index ebec1997..a588da1a 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -15,8 +15,10 @@ cdef class fq_default_ctx: cdef bint _initialized cdef new_ctype_fq_default(self) + cdef set_list_as_fq_default(self, fq_default_t val, obj) cdef set_any_as_fq_default(self, fq_default_t val, obj) - + cdef any_as_fq_default(self, obj) + @staticmethod cdef fq_default_ctx c_from_order(fmpz p, int d, char *var, fq_default_type type=*) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 484d25b6..b47548aa 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -1,10 +1,20 @@ from flint.pyflint cimport global_random_state from flint.types.fmpz cimport fmpz, any_as_fmpz -from flint.types.fmpz_poly cimport fmpz_poly +from flint.types.fmpz_poly cimport fmpz_poly, any_as_fmpz_poly, fmpz_poly_set_list from flint.types.fmpz_mod_poly cimport fmpz_mod_poly, fmpz_mod_poly_ctx from flint.types.nmod_poly cimport nmod_poly from flint.utils.typecheck cimport typecheck +""" +TODO: + +- be able to call from __init__ +- allow the variable name to be None if the degree is 1 +- allow the variable name to be as long as we want +- print the context differently for degree = 1 +- decide on __repr__ of elements +""" + cdef class fq_default_ctx: r""" Context object for creating :class:`~.fq_default`. @@ -84,6 +94,10 @@ cdef class fq_default_ctx: # TODO: we should allow var to be None when d == 1 if isinstance(var, str): var = var.encode() + + # TODO: Flint only wants one-character inputs + if len(var) > 1: + raise ValueError return fq_default_ctx.c_from_order(order, d, var, type) @@ -243,11 +257,55 @@ cdef class fq_default_ctx: cdef new_ctype_fq_default(self): return fq_default.__new__(fq_default, None, self) - cdef set_any_as_fq_default(self, fq_default_t val, obj): - if typecheck(obj, fmpz): - fq_default_set_fmpz(val, (obj).val, self.val) + cdef set_list_as_fq_default(self, fq_default_t fq_ele, obj): + cdef fmpz_poly poly + poly = fmpz_poly.__new__(fmpz_poly) + fmpz_poly_set_list(poly.val, obj) + + # Now set the value from the fmpz_poly + fq_default_set_fmpz_poly(fq_ele, poly.val, self.val) + + return 0 + + cdef set_any_as_fq_default(self, fq_default_t fq_ele, obj): + # Converts the list to an fmpz_poly and then sets from this + if typecheck(obj, list): + return self.set_list_as_fq_default(fq_ele, obj) + + # Assumes that the modulus of the polynomial matches + # the context for the fq_default + if typecheck(obj, fmpz_mod_poly): + fq_default_set_fmpz_mod_poly(fq_ele, (obj).val, self.val) return 0 - return NotImplemented + + # Assumes that the modulus of the polynomial matches + # the context for the fq_default + if typecheck(obj, nmod_poly): + fq_default_set_nmod_poly(fq_ele, (obj).val, self.val) + return 0 + + # If the input is not fmpz_mod_poly or nmod_poly or a list, we cast the + # input to an fmpz_poly and then set from this + poly = any_as_fmpz_poly(obj) + if poly is NotImplemented: + return NotImplemented + + fq_default_set_fmpz_poly(fq_ele, (poly).val, self.val) + return 0 + + cdef any_as_fq_default(self, obj): + # convert from fq_default + if typecheck(obj, fq_default): + if self != (obj).ctx: + raise ValueError("contexts dont match") + return obj + + cdef fq_default res + res = self.new_ctype_fq_default() + check = self.set_any_as_fq_default(res.val, obj) + if check is NotImplemented: + return NotImplemented + return res def __eq__(self, other): """ @@ -334,7 +392,7 @@ cdef class fq_default(flint_scalar): return pol def str(self): - return self.polynomial().str(var=self.ctx.var) + return self.polynomial().str(var=self.ctx.var.decode()) def __repr__(self): # TODO: what do we want here? @@ -349,6 +407,24 @@ cdef class fq_default(flint_scalar): def is_one(self): return 1 == fq_default_is_zero(self.val, self.ctx.val) + def __richcmp__(self, other, int op): + cdef bint res + if op != 2 and op != 3: + raise TypeError("fq_default cannot be ordered") + + if not typecheck(other, fq_default): + other = self.ctx.any_as_fq_default(other) + + if typecheck(other, fq_default): + res = (self.ctx == (other).ctx) and \ + fq_default_equal(self.val, (other).val, self.ctx.val) + if op == 2: + return res + else: + return not res + else: + return NotImplemented + # ================================================= # Generic arithmetic required by flint_scalar # ================================================= @@ -374,6 +450,8 @@ cdef class fq_default(flint_scalar): return NotImplemented def _invert_(self): + """ + """ cdef fq_default res res = self.ctx.new_ctype_fq_default() fq_default_inv(res.val, self.val, self.ctx.val) @@ -384,12 +462,16 @@ cdef class fq_default(flint_scalar): # ================================================= def square(self): + """ + """ cdef fq_default res res = self.ctx.new_ctype_fq_default() fq_default_sqr(res.val, self.val, self.ctx.val) return res def __pow__(self, e): + """ + """ return NotImplemented def sqrt(self): @@ -401,9 +483,13 @@ cdef class fq_default(flint_scalar): raise ValueError("element is not a square") def is_square(self): + """ + """ return 1 == fq_default_is_square(self.val, self.ctx.val) def pth_root(self): + """ + """ cdef fq_default res res = self.ctx.new_ctype_fq_default() fq_default_pth_root(res.val, self.val, self.ctx.val) @@ -414,10 +500,16 @@ cdef class fq_default(flint_scalar): # ================================================= def trace(self): + """ + """ return NotImplemented def norm(self): + """ + """ return NotImplemented def frobenius(self): + """ + """ return NotImplemented From 7e68a0cbfce8dd80375a83cb53ce5c5d815d502b Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 12:42:10 +0100 Subject: [PATCH 07/36] untested arithemtic --- src/flint/types/fq_default.pxd | 7 +- src/flint/types/fq_default.pyx | 313 ++++++++++++++++++++++----------- 2 files changed, 216 insertions(+), 104 deletions(-) diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index a588da1a..a155894d 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -19,11 +19,8 @@ cdef class fq_default_ctx: cdef set_any_as_fq_default(self, fq_default_t val, obj) cdef any_as_fq_default(self, obj) - @staticmethod - cdef fq_default_ctx c_from_order(fmpz p, int d, char *var, fq_default_type type=*) - - @staticmethod - cdef fq_default_ctx c_from_modulus(modulus, char *var, fq_default_type type=*) + cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type type=*) + cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type type=*) cdef class fq_default(flint_scalar): diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index b47548aa..35444c38 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -5,16 +5,6 @@ from flint.types.fmpz_mod_poly cimport fmpz_mod_poly, fmpz_mod_poly_ctx from flint.types.nmod_poly cimport nmod_poly from flint.utils.typecheck cimport typecheck -""" -TODO: - -- be able to call from __init__ -- allow the variable name to be None if the degree is 1 -- allow the variable name to be as long as we want -- print the context differently for degree = 1 -- decide on __repr__ of elements -""" - cdef class fq_default_ctx: r""" Context object for creating :class:`~.fq_default`. @@ -22,16 +12,16 @@ cdef class fq_default_ctx: Finite fields can be initialized in one of two possible ways. The first is by providing characteristic and degree: - >>> fq_default_ctx.from_order(5, 2, 'y') - fq_default_ctx.from_modulus(x^2 + 4*x + 2, 'y', 1) + >>> fq_default_ctx(5, 2, 'y') + fq_default_ctx(5, 2, 'y', x^2 + 4*x + 2, 1) The second is by giving an irreducible polynomial of type :class:`~.nmod_poly` or :class:`~.fmpz_mod_poly`: >>> from flint import fmpz_mod_poly_ctx - >>> modulus = fmpz_mod_poly_ctx(11)([1,0,1]) - >>> fq_default_ctx.from_modulus(modulus, 'x') - fq_default_ctx.from_modulus(x^2 + 1, 'x', 2) + >>> mod = fmpz_mod_poly_ctx(11)([1,0,1]) + >>> fq_default_ctx(modulus=mod) + fq_default_ctx(11, 2, 'x', x^2 + 1, 2) For more details, see the documentation of :method:`~.from_order` and :method:`~.from_modulus`. @@ -43,20 +33,33 @@ cdef class fq_default_ctx: if self._initialized: fq_default_ctx_clear(self.val) - def __init__(self, *args, **kwargs): - raise TypeError("This class cannot be instantiated directly. Use .from_order() or .from_modulus().") + def __init__(self, p=None, degree=None, var=None, modulus=None, type=fq_default_type.DEFAULT): + # If no variable is given, use x + if var is None: + var = "x" + + # If a modulus is given, attempt to construct from this + if modulus is not None: + self.set_from_modulus(modulus, var, type) + return + + # If there's no modulus and no prime, we can't continue + if p is None: + raise ValueError("either a prime or modulus must be passed for construction") + + # If we're not given a degree, construct GF(p) + if degree is None: + degree = 1 - @staticmethod - cdef fq_default_ctx c_from_order(fmpz p, int d, char *var, - fq_default_type type=fq_default_type.DEFAULT): - cdef fq_default_ctx ctx = fq_default_ctx.__new__(fq_default_ctx) - ctx.var = var - fq_default_ctx_init_type(ctx.val, p.val, d, ctx.var, type) - ctx._initialized = True - return ctx + # Construct the field from the prime and degree GF(p^d) + self.set_from_order(p, degree, var, type) - @staticmethod - def from_order(p, d, var, type=fq_default_type.DEFAULT): + cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type type=fq_default_type.DEFAULT): + self.var = var + fq_default_ctx_init_type(self.val, p.val, d, self.var, type) + self._initialized = True + + def set_from_order(self, p, d, var, type=fq_default_type.DEFAULT, check_prime=True): """ Construct a context for the finite field GF(p^d). @@ -69,29 +72,19 @@ cdef class fq_default_ctx: - `fq_default_ctx.FQ_ZECH`: Use `fq_zech_t`, - `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, - `fq_default_ctx.FQ`: Use `fq_t`. - - >>> gf = fq_default_ctx.from_order(5, 2, 'y') - >>> gf - fq_default_ctx.from_modulus(x^2 + 4*x + 2, 'y', 1) - >>> gf.type - - - >>> gf = fq_default_ctx.from_order(5, 2, 'y', fq_default_type.FQ_NMOD) - >>> gf - fq_default_ctx.from_modulus(x^2 + 4*x + 2, 'y', 2) - >>> gf.type - """ # c_from_order expects the characteristic to be fmpz type - order = any_as_fmpz(p) - if order is NotImplemented: + prime = any_as_fmpz(p) + if prime is NotImplemented: raise TypeError(f"cannot coerce {p = } to type fmpz") + if check_prime and not prime.is_prime(): + raise ValueError("characteristic is not prime") + # the degree must be strictly positive if d < 1: raise ValueError(f"the degree must be positive, got {d = }") - # TODO: we should allow var to be None when d == 1 if isinstance(var, str): var = var.encode() @@ -99,28 +92,22 @@ cdef class fq_default_ctx: if len(var) > 1: raise ValueError - return fq_default_ctx.c_from_order(order, d, var, type) - - @staticmethod - cdef fq_default_ctx c_from_modulus(modulus, char *var, - fq_default_type type=fq_default_type.DEFAULT): - cdef fq_default_ctx ctx = fq_default_ctx.__new__(fq_default_ctx) + # Cython type conversion and context initalisation + self._c_set_from_order(prime, d, var, type) - ctx.var = var + cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type type=fq_default_type.DEFAULT): + self.var = var if typecheck(modulus, fmpz_mod_poly): - fq_default_ctx_init_modulus_type(ctx.val, (modulus).val, - (modulus).ctx.mod.val, ctx.var, type) + fq_default_ctx_init_modulus_type(self.val, (modulus).val, + (modulus).ctx.mod.val, self.var, type) elif typecheck(modulus, nmod_poly): - fq_default_ctx_init_modulus_nmod_type(ctx.val, (modulus).val, - ctx.var, type) + fq_default_ctx_init_modulus_nmod_type(self.val, (modulus).val, + self.var, type) else: raise TypeError(f"modulus must be fmpz_mod_poly or nmod_poly, got {modulus!r}") - ctx._initialized = True + self._initialized = True - return ctx - - @staticmethod - def from_modulus(modulus, var, type=fq_default_type.DEFAULT): + def set_from_modulus(self, modulus, var, type=fq_default_type.DEFAULT, check_modulus=True): """ Construct a context for a finite field from an irreducible polynomial. @@ -135,24 +122,15 @@ cdef class fq_default_ctx: - `fq_default_ctx.FQ_ZECH`: Use `fq_zech_t`, - `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, - `fq_default_ctx.FQ`: Use `fq_t`. - - >>> from flint import fmpz_mod_poly_ctx - >>> modulus = fmpz_mod_poly_ctx(11)([1,0,1]) - >>> gf = fq_default_ctx.from_modulus(modulus, 'x') - >>> gf - fq_default_ctx.from_modulus(x^2 + 1, 'x', 2) - >>> gf.type - - - >>> gf = fq_default_ctx.from_modulus(modulus, 'x', fq_default_type.FQ) - >>> gf - fq_default_ctx.from_modulus(x^2 + 1, 'x', 3) - >>> gf.type - """ if isinstance(var, str): var = var.encode() - return fq_default_ctx.c_from_modulus(modulus, var, type) + + if check_modulus and not modulus.is_irreducible(): + raise ValueError("modulus must be irreducible") + + # Cython type conversion and context initalisation + self._c_set_from_modulus(modulus, var, type) @property def type(self): @@ -167,16 +145,20 @@ cdef class fq_default_ctx: def degree(self): """ - >>> gf = fq_default_ctx.from_order(5, 2, 'y') + The extension degree of the finite field + + >>> gf = fq_default_ctx(5, 2) >>> gf.degree() 2 """ return fq_default_ctx_degree(self.val) - def prime(self): + def characteristic(self): """ - >>> gf = fq_default_ctx.from_order(5, 2, 'y') - >>> gf.prime() + Return the characteristic of the finite field + + >>> gf = fq_default_ctx(5, 2) + >>> gf.characteristic() 5 """ cdef fmpz p @@ -184,11 +166,13 @@ cdef class fq_default_ctx: fq_default_ctx_prime(p.val, self.val) return p - characteristic = prime + prime = characteristic def order(self): """ - >>> gf = fq_default_ctx.from_order(5, 2, 'y') + Return the order of the finite field + + >>> gf = fq_default_ctx(5, 2) >>> gf.order() 25 """ @@ -197,11 +181,21 @@ cdef class fq_default_ctx: fq_default_ctx_order(q.val, self.val) return q + def multiplicative_order(self): + """" + Return the multiplicative order of the finite field + + >>> gf = fq_default_ctx(5, 2) + >>> gf.multiplicative_order() + 24 + """ + return self.order() - 1 + def modulus(self): """ Return the modulus from the context as an fmpz_mod_poly type - >>> gf = fq_default_ctx.from_order(5, 2, 'y') + >>> gf = fq_default_ctx(5, 2) >>> gf.modulus() x^2 + 4*x + 2 @@ -217,7 +211,7 @@ cdef class fq_default_ctx: """ Return the zero element - >>> gf = fq_default_ctx.from_order(5, 1, "x") + >>> gf = fq_default_ctx(5) >>> gf.zero() 0 """ @@ -231,7 +225,7 @@ cdef class fq_default_ctx: """ Return the one element - >>> gf = fq_default_ctx.from_order(5, 1, "x") + >>> gf = fq_default_ctx(5) >>> gf.one() 1 """ @@ -241,6 +235,20 @@ cdef class fq_default_ctx: fq_default_one(res.val, self.val) return res + def gen(self): + """ + Return the one element + + >>> gf = fq_default_ctx(5, 2, var="w") + >>> gf.gen() + w + """ + cdef fq_default res + res = self.new_ctype_fq_default() + res.ctx = self + fq_default_gen(res.val, self.val) + return res + def random_element(self, not_zero=False): r""" Return a random element of the finite field @@ -272,6 +280,11 @@ cdef class fq_default_ctx: if typecheck(obj, list): return self.set_list_as_fq_default(fq_ele, obj) + # For small integers we can convert directly + if typecheck(obj, int) and obj.bit_length() < 32: + fq_default_set_si(fq_ele, obj, self.val) + return 0 + # Assumes that the modulus of the polynomial matches # the context for the fq_default if typecheck(obj, fmpz_mod_poly): @@ -313,13 +326,12 @@ cdef class fq_default_ctx: characteristic, modulus, type and variable >>> from flint import fmpz_mod_poly_ctx - >>> R = fmpz_mod_poly_ctx(5) - >>> modulus = R([2,4,1]) - >>> gf = fq_default_ctx.from_order(5, 2, 'y') - >>> gf2 = fq_default_ctx.from_modulus(modulus, 'y', 1) + >>> modulus = fmpz_mod_poly_ctx(5)([2,4,1]) + >>> gf = fq_default_ctx(5, 2) + >>> gf2 = fq_default_ctx(modulus=modulus) >>> gf2 == gf True - >>> gf3 = fq_default_ctx.from_modulus(modulus, 'x', 1) + >>> gf3 = fq_default_ctx(modulus=modulus, var="y") >>> gf3 == gf False """ @@ -338,10 +350,14 @@ cdef class fq_default_ctx: return hash((self.type, self.var, self.prime(), self.modulus())) def __str__(self): + if self.degree() == 1: + return f"Context for fq_default in GF({self.prime()})" return f"Context for fq_default in GF({self.prime()}^{self.degree()})[{self.var.decode()}]/({self.modulus().str(var=self.var.decode())})" def __repr__(self): - return f"fq_default_ctx.from_modulus({self.modulus()!r}, '{self.var.decode()}', {self.type})" + if self.degree() == 1: + return f"fq_default_ctx({self.prime()}, var='{self.var.decode()}' type={self.type})" + return f"fq_default_ctx({self.prime()}, {self.degree()}, '{self.var.decode()}', {self.modulus()!r}, {self.type})" def __call__(self, val): return fq_default(val, self) @@ -436,22 +452,76 @@ cdef class fq_default(flint_scalar): return res def _add_(self, other): - return NotImplemented + other = self.ctx.any_as_fq_default(other) + if other is NotImplemented: + return NotImplemented + + cdef fq_default res + res = self.ctx.new_ctype_fq_default() + fq_default_add(res.val, self.val, (other).val, self.ctx.val) + return res @staticmethod def _sub_(left, right): - return NotImplemented + # Case when left and right are already fq_default + if typecheck(left, fq_default) and typecheck(right, fq_default): + if not (left).ctx == (right).ctx: + raise ValueError("moduli must match") + + # Otherwise, exactly one of these values is fq_default, if it's left + # convert the right + elif typecheck(left, fq_default): + right = (left).ctx.any_as_fq_default(right) + if right is NotImplemented: + return NotImplemented + # Otherwise convert the left + else: + left = (right).ctx.any_as_fq_default(left) + if left is NotImplemented: + return NotImplemented + + # Now perform subtraction + cdef fq_default res + res = (left).ctx.new_ctype_fq_default() + fq_default_sub(res.val, (left).val, (right).val, res.ctx.val) + return res def _mul_(self, other): - return NotImplemented + other = self.ctx.any_as_fq_default(other) + if other is NotImplemented: + return NotImplemented + + cdef fq_default res + res = self.ctx.new_ctype_fq_default() + fq_default_mul(res.val, self.val, (other).val, self.ctx.val) + return res @staticmethod def _div_(left, right): - return NotImplemented + # Case when left and right are already fq_default + if typecheck(left, fq_default) and typecheck(right, fq_default): + if not (left).ctx == (right).ctx: + raise ValueError("moduli must match") + + # Otherwise, exactly one of these values is fq_default, if it's left + # convert the right + elif typecheck(left, fq_default): + right = (left).ctx.any_as_fq_default(right) + if right is NotImplemented: + return NotImplemented + # Otherwise convert the left + else: + left = (right).ctx.any_as_fq_default(left) + if left is NotImplemented: + return NotImplemented + + # Now perform division + cdef fq_default res + res = (left).ctx.new_ctype_fq_default() + fq_default_div(res.val, (left).val, (right).val, res.ctx.val) + return res def _invert_(self): - """ - """ cdef fq_default res res = self.ctx.new_ctype_fq_default() fq_default_inv(res.val, self.val, self.ctx.val) @@ -463,6 +533,7 @@ cdef class fq_default(flint_scalar): def square(self): """ + Computes the square of ``self`` """ cdef fq_default res res = self.ctx.new_ctype_fq_default() @@ -472,9 +543,37 @@ cdef class fq_default(flint_scalar): def __pow__(self, e): """ """ - return NotImplemented + cdef fq_default res + res = self.ctx.new_ctype_fq_default() + + # If e is negative, we invert first + if e < 0: + if self.is_zero(): + raise ZeroDivisionError + e = -e + fq_default_inv(res.val, self.val, self.ctx.val) + else: + fq_default_set(res.val, self.val, self.ctx.val) + + # For small e we dont need to make an fmpz + if e.bit_length() < 32: + fq_default_pow_ui(res.val, res.val, e, self.ctx.val) + return res + + # Attempt to cast the exponent to an fmpz type then exponentiate + e_fmpz = any_as_fmpz(e) + if e_fmpz is NotImplemented: + raise TypeError(f"exponent {e = } cannot be cast to fmpz") + + fq_default_pow(res.val, res.val, (e_fmpz).val, self.ctx.val) + + return res def sqrt(self): + """ + Returns the square root of the element, if not square root exists, + throws a ValueError. + """ cdef fq_default res res = self.ctx.new_ctype_fq_default() check = fq_default_sqrt(res.val, self.val, self.ctx.val) @@ -484,11 +583,17 @@ cdef class fq_default(flint_scalar): def is_square(self): """ + Returns if the element is a square in the field """ return 1 == fq_default_is_square(self.val, self.ctx.val) def pth_root(self): """ + Returns the pth root of the element. + + This is computed by raising ``self`` to the `p^(d-1)` power, + `p` is the characteristic of the field and `d` is the degree + of the extension. """ cdef fq_default res res = self.ctx.new_ctype_fq_default() @@ -501,15 +606,25 @@ cdef class fq_default(flint_scalar): def trace(self): """ + Returns the trace of self """ - return NotImplemented + cdef fmpz tr = fmpz.__new__(fmpz) + fq_default_trace(tr.val, self.val, self.ctx.val) + return tr def norm(self): """ + Returns the norm of self """ - return NotImplemented + cdef fmpz nrm = fmpz.__new__(fmpz) + fq_default_norm(nrm.val, self.val, self.ctx.val) + return nrm - def frobenius(self): + def frobenius(self, e): """ + Evaluates the homomorphism `\Sigma^e` on ``self``. """ - return NotImplemented + cdef fq_default res + res = self.ctx.new_ctype_fq_default() + fq_default_frobenius(res.val, self.val, e, self.ctx.val) + return res From 73479246fd7cd430257db1a8f94249efa9d1751a Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 13:12:51 +0100 Subject: [PATCH 08/36] begin adding tests --- src/flint/test/test_all.py | 70 ++++++++++++++++++++++++++++++++++ src/flint/types/fq_default.pyx | 8 +++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index aca7668e..d0cbc25a 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -3585,6 +3585,74 @@ def test_matrices_transpose(): assert M1234.transpose() == M([[1, 4], [2, 5], [3, 6]]) +def test_fq_default(): + # test fq_default context creation + # TODO + + # GF(5) + gf_5 = flint.fq_default_ctx(5) + + # GF(5^2) + gf_5_2 = flint.fq_default_ctx(5, 2) + + # GF((2**127 - 1)^2) + gf_127_2 = flint.fq_default_ctx(2**127 - 1, 2) + + assert gf_5.prime() == gf_5_2.prime() == 5 + assert gf_5_2.order() == 5*5 + assert gf_5_2.multiplicative_order() == 5*5 - 1 + assert gf_127_2.prime() == 2**127 - 1 + + assert gf_5_2(0) == gf_5_2.zero() + assert gf_5_2(1) == gf_5_2.one() + assert gf_5_2.gen() == gf_5_2([0, 1]) + + assert str(gf_5) == "Context for fq_default in GF(5)" + assert str(gf_5_2) == "Context for fq_default in GF(5^2)[x]/(x^2 + 4*x + 2)" + + # test fq_default element arithemtic + + for gf in [gf_5, gf_5_2, gf_127_2]: + + assert gf.zero().is_zero() is True + assert gf.one().is_zero() is False + + assert gf.zero().is_one() is False + assert gf.one().is_one() is True + + a = gf.random_element(not_zero=True) + b = gf.random_element(not_zero=True) + c = gf.random_element(not_zero=True) + + assert a + (-a) == gf.zero() + assert a + a == 2*a + assert a * a == a**2 + assert a * a == a.square() + assert a * a * a == pow(a, 3) + + assert (a + b) + c == a + (b + c) + assert (a - b) - c == a - (b + c) + assert (a * b) * c == a * (b * c) + assert (a / b) / c == a / (b * c) + + assert a + 0 == 0 + a == a + assert a + gf.zero() == a + assert a * 1 == 1 * a == a + assert a * gf.one() == a + assert a * gf.zero() == gf.zero() + assert a / a == gf.one() + + assert raises(lambda: a / 0, ZeroDivisionError) + assert raises(lambda: ~gf.zero(), ZeroDivisionError) + assert raises(lambda: pow(gf.zero(), -1), ZeroDivisionError) + + assert 1/a == pow(a, -1) == ~a + assert gf.one() == pow(a, 0) + assert gf.zero() == pow(gf.zero(), 2**64) + assert a == pow(a, 1) + + assert (a*a).is_square() + def test_all_tests(): test_funcs = {f for name, f in globals().items() if name.startswith("test_")} untested = test_funcs - set(all_tests) @@ -3650,6 +3718,8 @@ def test_all_tests(): test_matrices_rref, test_matrices_solve, + test_fq_default, + test_arb, test_pickling, diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 35444c38..5239d41c 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -421,7 +421,7 @@ cdef class fq_default(flint_scalar): return 1 == fq_default_is_zero(self.val, self.ctx.val) def is_one(self): - return 1 == fq_default_is_zero(self.val, self.ctx.val) + return 1 == fq_default_is_one(self.val, self.ctx.val) def __richcmp__(self, other, int op): cdef bint res @@ -515,6 +515,9 @@ cdef class fq_default(flint_scalar): if left is NotImplemented: return NotImplemented + if right.is_zero(): + raise ZeroDivisionError + # Now perform division cdef fq_default res res = (left).ctx.new_ctype_fq_default() @@ -522,6 +525,9 @@ cdef class fq_default(flint_scalar): return res def _invert_(self): + if self.is_zero(): + raise ZeroDivisionError + cdef fq_default res res = self.ctx.new_ctype_fq_default() fq_default_inv(res.val, self.val, self.ctx.val) From 49b882c8248448915732ad493f929125f4dd358a Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 16:01:21 +0100 Subject: [PATCH 09/36] clean up enum name, maybe a little hacky... --- src/flint/types/fq_default.pxd | 4 +- src/flint/types/fq_default.pyx | 74 ++++++++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index a155894d..fd704cc0 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -19,8 +19,8 @@ cdef class fq_default_ctx: cdef set_any_as_fq_default(self, fq_default_t val, obj) cdef any_as_fq_default(self, obj) - cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type type=*) - cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type type=*) + cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type fq_type=*) + cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type fq_type=*) cdef class fq_default(flint_scalar): diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 5239d41c..fe630db8 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -33,14 +33,38 @@ cdef class fq_default_ctx: if self._initialized: fq_default_ctx_clear(self.val) - def __init__(self, p=None, degree=None, var=None, modulus=None, type=fq_default_type.DEFAULT): + def __init__(self, p=None, degree=None, var=None, modulus=None, fq_type=fq_default_type.DEFAULT): # If no variable is given, use x if var is None: var = "x" + + # Allow the type to be denoted by strings or integers + FQ_TYPES = { + "FQ_ZECH" : 1, + "FQ_NMOD" : 2, + "FQ" : 3, + } + if typecheck(fq_type, str): + fq_type = FQ_TYPES.get(typecheck, None) + if fq_type is None: + raise ValueError("invalid fq_type, must be one of FQ_ZECH, FQ_NMOD or FQ") + if not typecheck(fq_type, int): + raise ValueError(f"{fq_type = } is invalid") # If a modulus is given, attempt to construct from this if modulus is not None: - self.set_from_modulus(modulus, var, type) + # If the polynomial has no known characteristic, we can try and create one + # using the supplied prime + if not typecheck(modulus, [fmpz_mod_poly, nmod_poly]): + if p is None: + raise ValueError("cannot create from modulus if no characteristic is known") + + ring_ctx = fmpz_mod_poly_ctx(p) + modulus = ring_ctx.any_as_fmpz_mod_poly(modulus) + if modulus is NotImplemented: + raise TypeError("modulus cannot be cast to fmpz_mod_poly") + + self.set_from_modulus(modulus, var, fq_type) return # If there's no modulus and no prime, we can't continue @@ -52,14 +76,14 @@ cdef class fq_default_ctx: degree = 1 # Construct the field from the prime and degree GF(p^d) - self.set_from_order(p, degree, var, type) + self.set_from_order(p, degree, var, fq_type) - cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type type=fq_default_type.DEFAULT): + cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type fq_type=fq_default_type.DEFAULT): self.var = var - fq_default_ctx_init_type(self.val, p.val, d, self.var, type) + fq_default_ctx_init_type(self.val, p.val, d, self.var, fq_type) self._initialized = True - def set_from_order(self, p, d, var, type=fq_default_type.DEFAULT, check_prime=True): + def set_from_order(self, p, d, var, fq_type=fq_default_type.DEFAULT, check_prime=True): """ Construct a context for the finite field GF(p^d). @@ -93,21 +117,21 @@ cdef class fq_default_ctx: raise ValueError # Cython type conversion and context initalisation - self._c_set_from_order(prime, d, var, type) + self._c_set_from_order(prime, d, var, fq_type) - cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type type=fq_default_type.DEFAULT): + cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type fq_type=fq_default_type.DEFAULT): self.var = var if typecheck(modulus, fmpz_mod_poly): fq_default_ctx_init_modulus_type(self.val, (modulus).val, - (modulus).ctx.mod.val, self.var, type) + (modulus).ctx.mod.val, self.var, fq_type) elif typecheck(modulus, nmod_poly): fq_default_ctx_init_modulus_nmod_type(self.val, (modulus).val, - self.var, type) + self.var, fq_type) else: raise TypeError(f"modulus must be fmpz_mod_poly or nmod_poly, got {modulus!r}") self._initialized = True - def set_from_modulus(self, modulus, var, type=fq_default_type.DEFAULT, check_modulus=True): + def set_from_modulus(self, modulus, var, fq_type=fq_default_type.DEFAULT, check_modulus=True): """ Construct a context for a finite field from an irreducible polynomial. @@ -130,18 +154,34 @@ cdef class fq_default_ctx: raise ValueError("modulus must be irreducible") # Cython type conversion and context initalisation - self._c_set_from_modulus(modulus, var, type) + self._c_set_from_modulus(modulus, var, fq_type) @property - def type(self): + def fq_type(self): """ Return the implementation of this context. It is one of: + - 1: `fq_default_ctx.FQ_ZECH`: Using `fq_zech_t`, + - 2: `fq_default_ctx.FQ_NMOD`: Using `fq_nmod_t`, + - 3: `fq_default_ctx.FQ`: Using `fq_t`. + """ + return fq_default_type(fq_default_ctx_type(self.val)) + + @property + def fq_type_str(self): + """ + Return the string implementation of this context. It is one of: + - `fq_default_ctx.FQ_ZECH`: Using `fq_zech_t`, - `fq_default_ctx.FQ_NMOD`: Using `fq_nmod_t`, - `fq_default_ctx.FQ`: Using `fq_t`. """ - return fq_default_type(fq_default_ctx_type(self.val)) + FQ_TYPES = { + 1 : "FQ_ZECH", + 2 : "FQ_NMOD", + 3 : "FQ", + } + return FQ_TYPES[self.fq_type] def degree(self): """ @@ -339,7 +379,7 @@ cdef class fq_default_ctx: return True if typecheck(other, fq_default_ctx): - return (self.type == other.type + return (self.fq_type == other.fq_type and self.var == other.var and self.prime() == other.prime() and self.modulus() == other.modulus()) @@ -356,8 +396,8 @@ cdef class fq_default_ctx: def __repr__(self): if self.degree() == 1: - return f"fq_default_ctx({self.prime()}, var='{self.var.decode()}' type={self.type})" - return f"fq_default_ctx({self.prime()}, {self.degree()}, '{self.var.decode()}', {self.modulus()!r}, {self.type})" + return f"fq_default_ctx({self.prime()}, var='{self.var.decode()}' type='{self.fq_type_str}')" + return f"fq_default_ctx({self.prime()}, {self.degree()}, '{self.var.decode()}', {self.modulus()!r}, '{self.fq_type_str}')" def __call__(self, val): return fq_default(val, self) From ad5be0b0d19e14689bc3e3055fe702ecb3018133 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 16:15:36 +0100 Subject: [PATCH 10/36] attempt to fix doctests for all versions --- src/flint/types/fq_default.pyx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index fe630db8..03a69f93 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -12,16 +12,16 @@ cdef class fq_default_ctx: Finite fields can be initialized in one of two possible ways. The first is by providing characteristic and degree: - >>> fq_default_ctx(5, 2, 'y') - fq_default_ctx(5, 2, 'y', x^2 + 4*x + 2, 1) + >>> fq_default_ctx(5, 2, 'y', fq_type=1) + fq_default_ctx(5, 2, 'y', x^2 + 4*x + 2, 'FQ_ZECH') The second is by giving an irreducible polynomial of type :class:`~.nmod_poly` or :class:`~.fmpz_mod_poly`: >>> from flint import fmpz_mod_poly_ctx >>> mod = fmpz_mod_poly_ctx(11)([1,0,1]) - >>> fq_default_ctx(modulus=mod) - fq_default_ctx(11, 2, 'x', x^2 + 1, 2) + >>> fq_default_ctx(modulus=mod, fq_type=2) + fq_default_ctx(11, 2, 'x', x^2 + 1, 'FQ_NMOD') For more details, see the documentation of :method:`~.from_order` and :method:`~.from_modulus`. @@ -55,7 +55,7 @@ cdef class fq_default_ctx: if modulus is not None: # If the polynomial has no known characteristic, we can try and create one # using the supplied prime - if not typecheck(modulus, [fmpz_mod_poly, nmod_poly]): + if not (typecheck(modulus, fmpz_mod_poly) or typecheck(modulus, nmod_poly)): if p is None: raise ValueError("cannot create from modulus if no characteristic is known") @@ -661,12 +661,15 @@ cdef class fq_default(flint_scalar): def norm(self): """ Returns the norm of self + + >>> gf = fq_default_ctx(163, 3) + >>> a = gf([1,2,3]) """ cdef fmpz nrm = fmpz.__new__(fmpz) fq_default_norm(nrm.val, self.val, self.ctx.val) return nrm - def frobenius(self, e): + def frobenius(self, e=1): """ Evaluates the homomorphism `\Sigma^e` on ``self``. """ From ece8c453b8edceb66456e4c1396528368bac13c0 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 16:36:06 +0100 Subject: [PATCH 11/36] add docstrings --- src/flint/types/fq_default.pyx | 114 ++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 03a69f93..b7a389e9 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -263,7 +263,7 @@ cdef class fq_default_ctx: def one(self): """ - Return the one element + Return the unit element >>> gf = fq_default_ctx(5) >>> gf.one() @@ -292,6 +292,14 @@ cdef class fq_default_ctx: def random_element(self, not_zero=False): r""" Return a random element of the finite field + + >>> gf = fq_default_ctx(163, 3) + >>> a = gf.random_element() + >>> type(a) is fq_default + True + >>> a = gf.random_element(not_zero=True) + >>> not a.is_zero() + True """ cdef fq_default res res = self.new_ctype_fq_default() @@ -426,6 +434,11 @@ cdef class fq_default(flint_scalar): def __int__(self): """ Attempts to lift self to an integer of type fmpz in [0, p-1] + + >>> gf = fq_default_ctx(163, 3) + >>> a = gf([1,2,3]) + >>> int(gf(123)) + 123 """ cdef fmpz x = fmpz.__new__(fmpz) res = fq_default_get_fmpz(x.val, self.val, self.ctx.val) @@ -437,6 +450,13 @@ cdef class fq_default(flint_scalar): """ Returns a representative of ``self`` as a polynomial in `(Z/pZ)[x] / h(x)` where `h(x)` is the defining polynomial of the finite field. + + >>> gf = fq_default_ctx(163, 3) + >>> a = gf([1,2,3]) + >>> a.polynomial() + 3*x^2 + 2*x + 1 + >>> gf(123).polynomial() + 123 """ cdef fmpz_mod_poly_ctx ctx cdef fmpz_mod_poly pol @@ -458,9 +478,27 @@ cdef class fq_default(flint_scalar): # Comparisons # ================================================= def is_zero(self): + """ + Returns true is self is zero and false otherwise + + >>> gf = fq_default_ctx(163, 3) + >>> gf(0).is_zero() + True + >>> gf(-1).is_zero() + False + """ return 1 == fq_default_is_zero(self.val, self.ctx.val) def is_one(self): + """ + Returns true is self is one and false otherwise + + >>> gf = fq_default_ctx(163, 3) + >>> gf(-1).is_one() + False + >>> gf(1).is_one() + True + """ return 1 == fq_default_is_one(self.val, self.ctx.val) def __richcmp__(self, other, int op): @@ -573,6 +611,20 @@ cdef class fq_default(flint_scalar): fq_default_inv(res.val, self.val, self.ctx.val) return res + def inverse(self): + """ + Computes the inverse of self + + >>> gf = fq_default_ctx(163, 3) + >>> a = gf([1,2,3]) + >>> b = a.inverse() + >>> b + 68*x^2 + 17*x + 116 + >>> a*b == gf.one() + True + """ + return self._invert_() + # ================================================= # Additional arithmetic # ================================================= @@ -580,6 +632,13 @@ cdef class fq_default(flint_scalar): def square(self): """ Computes the square of ``self`` + + >>> gf = fq_default_ctx(163, 3) + >>> a = gf([1,2,3]) + >>> a.square() == a*a + True + >>> a.square() + 110*x^2 + 101*x + 25 """ cdef fq_default res res = self.ctx.new_ctype_fq_default() @@ -588,6 +647,19 @@ cdef class fq_default(flint_scalar): def __pow__(self, e): """ + Compute `a^e` for `a` equal to ``self``. + + >>> gf = fq_default_ctx(163, 3) + >>> a = gf([1,2,3]) + >>> pow(a, -1) == 1/a + True + >>> pow(a, 2) == a * a + True + >>> pow(a, 2**128) == pow(a, 2**128 % (163**3 - 1)) + True + >>> pow(a, 123) + 46*x^2 + 110*x + 155 + """ cdef fq_default res res = self.ctx.new_ctype_fq_default() @@ -619,6 +691,16 @@ cdef class fq_default(flint_scalar): """ Returns the square root of the element, if not square root exists, throws a ValueError. + + >>> gf = fq_default_ctx(163, 3) + >>> a = gf([3,2,1]) + >>> a.is_square() + True + >>> b = a.sqrt() + >>> b + 95*x^2 + 36*x + 34 + >>> b**2 in [a, -a] + True """ cdef fq_default res res = self.ctx.new_ctype_fq_default() @@ -630,6 +712,13 @@ cdef class fq_default(flint_scalar): def is_square(self): """ Returns if the element is a square in the field + + >>> gf = fq_default_ctx(163, 3) + >>> a = gf([1,2,3]) + >>> a.is_square() + False + >>> (a*a).is_square() + True """ return 1 == fq_default_is_square(self.val, self.ctx.val) @@ -640,6 +729,11 @@ cdef class fq_default(flint_scalar): This is computed by raising ``self`` to the `p^(d-1)` power, `p` is the characteristic of the field and `d` is the degree of the extension. + + >>> gf = fq_default_ctx(163, 3) + >>> a = gf([1,2,3]) + >>> a.pth_root() + 5*x^2 + 152*x + 119 """ cdef fq_default res res = self.ctx.new_ctype_fq_default() @@ -653,6 +747,11 @@ cdef class fq_default(flint_scalar): def trace(self): """ Returns the trace of self + + >>> gf = fq_default_ctx(163, 3) + >>> a = gf([1,2,3]) + >>> a.trace() + 124 """ cdef fmpz tr = fmpz.__new__(fmpz) fq_default_trace(tr.val, self.val, self.ctx.val) @@ -664,6 +763,8 @@ cdef class fq_default(flint_scalar): >>> gf = fq_default_ctx(163, 3) >>> a = gf([1,2,3]) + >>> a.norm() + 116 """ cdef fmpz nrm = fmpz.__new__(fmpz) fq_default_norm(nrm.val, self.val, self.ctx.val) @@ -672,6 +773,17 @@ cdef class fq_default(flint_scalar): def frobenius(self, e=1): """ Evaluates the homomorphism `\Sigma^e` on ``self``. + + >>> gf = fq_default_ctx(163, 3) + >>> a = gf([1,2,3]) + >>> a.frobenius() + 155*x^2 + 9*x + 4 + >>> a.frobenius(2) + 5*x^2 + 152*x + 119 + >>> a == a.frobenius(3) + True + >>> a.frobenius(2) == a.frobenius(-1) + True """ cdef fq_default res res = self.ctx.new_ctype_fq_default() From 273deee3406a64f93979a3afb6554e49763ccfb1 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 16:41:13 +0100 Subject: [PATCH 12/36] remove trailing whitespace --- src/flint/types/fq_default.pyx | 62 +++++++++++++++++----------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index b7a389e9..433e59b9 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -22,13 +22,13 @@ cdef class fq_default_ctx: >>> mod = fmpz_mod_poly_ctx(11)([1,0,1]) >>> fq_default_ctx(modulus=mod, fq_type=2) fq_default_ctx(11, 2, 'x', x^2 + 1, 'FQ_NMOD') - + For more details, see the documentation of :method:`~.from_order` and :method:`~.from_modulus`. """ def __cinit__(self): pass - + def __dealloc__(self): if self._initialized: fq_default_ctx_clear(self.val) @@ -50,7 +50,7 @@ cdef class fq_default_ctx: raise ValueError("invalid fq_type, must be one of FQ_ZECH, FQ_NMOD or FQ") if not typecheck(fq_type, int): raise ValueError(f"{fq_type = } is invalid") - + # If a modulus is given, attempt to construct from this if modulus is not None: # If the polynomial has no known characteristic, we can try and create one @@ -70,7 +70,7 @@ cdef class fq_default_ctx: # If there's no modulus and no prime, we can't continue if p is None: raise ValueError("either a prime or modulus must be passed for construction") - + # If we're not given a degree, construct GF(p) if degree is None: degree = 1 @@ -101,7 +101,7 @@ cdef class fq_default_ctx: prime = any_as_fmpz(p) if prime is NotImplemented: raise TypeError(f"cannot coerce {p = } to type fmpz") - + if check_prime and not prime.is_prime(): raise ValueError("characteristic is not prime") @@ -115,11 +115,11 @@ cdef class fq_default_ctx: # TODO: Flint only wants one-character inputs if len(var) > 1: raise ValueError - + # Cython type conversion and context initalisation self._c_set_from_order(prime, d, var, fq_type) - cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type fq_type=fq_default_type.DEFAULT): + cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type fq_type=fq_default_type.DEFAULT): self.var = var if typecheck(modulus, fmpz_mod_poly): fq_default_ctx_init_modulus_type(self.val, (modulus).val, @@ -136,7 +136,7 @@ cdef class fq_default_ctx: Construct a context for a finite field from an irreducible polynomial. `modulus` may be of type :class:`~.fmpz_mod_poly` or :class:`~.nmod_poly`. - + `var` is a name for the ring generator of this field over the prime field. The optional parameter `type` select the implementation. The @@ -155,12 +155,12 @@ cdef class fq_default_ctx: # Cython type conversion and context initalisation self._c_set_from_modulus(modulus, var, fq_type) - + @property def fq_type(self): """ Return the implementation of this context. It is one of: - + - 1: `fq_default_ctx.FQ_ZECH`: Using `fq_zech_t`, - 2: `fq_default_ctx.FQ_NMOD`: Using `fq_nmod_t`, - 3: `fq_default_ctx.FQ`: Using `fq_t`. @@ -171,7 +171,7 @@ cdef class fq_default_ctx: def fq_type_str(self): """ Return the string implementation of this context. It is one of: - + - `fq_default_ctx.FQ_ZECH`: Using `fq_zech_t`, - `fq_default_ctx.FQ_NMOD`: Using `fq_nmod_t`, - `fq_default_ctx.FQ`: Using `fq_t`. @@ -207,7 +207,7 @@ cdef class fq_default_ctx: return p prime = characteristic - + def order(self): """ Return the order of the finite field @@ -246,7 +246,7 @@ cdef class fq_default_ctx: pol = ctx.new_ctype_poly() fq_default_ctx_modulus(pol.val, self.val) return pol - + def zero(self): """ Return the zero element @@ -260,7 +260,7 @@ cdef class fq_default_ctx: res.ctx = self fq_default_zero(res.val, self.val) return res - + def one(self): """ Return the unit element @@ -317,7 +317,7 @@ cdef class fq_default_ctx: cdef fmpz_poly poly poly = fmpz_poly.__new__(fmpz_poly) fmpz_poly_set_list(poly.val, obj) - + # Now set the value from the fmpz_poly fq_default_set_fmpz_poly(fq_ele, poly.val, self.val) @@ -331,7 +331,7 @@ cdef class fq_default_ctx: # For small integers we can convert directly if typecheck(obj, int) and obj.bit_length() < 32: fq_default_set_si(fq_ele, obj, self.val) - return 0 + return 0 # Assumes that the modulus of the polynomial matches # the context for the fq_default @@ -365,14 +365,14 @@ cdef class fq_default_ctx: res = self.new_ctype_fq_default() check = self.set_any_as_fq_default(res.val, obj) if check is NotImplemented: - return NotImplemented + return NotImplemented return res def __eq__(self, other): """ Two finite field context compare equal if they have same characteristic, modulus, type and variable - + >>> from flint import fmpz_mod_poly_ctx >>> modulus = fmpz_mod_poly_ctx(5)([2,4,1]) >>> gf = fq_default_ctx(5, 2) @@ -385,7 +385,7 @@ cdef class fq_default_ctx: """ if self is other: return True - + if typecheck(other, fq_default_ctx): return (self.fq_type == other.fq_type and self.var == other.var @@ -476,11 +476,11 @@ cdef class fq_default(flint_scalar): # ================================================= # Comparisons - # ================================================= + # ================================================= def is_zero(self): """ Returns true is self is zero and false otherwise - + >>> gf = fq_default_ctx(163, 3) >>> gf(0).is_zero() True @@ -492,7 +492,7 @@ cdef class fq_default(flint_scalar): def is_one(self): """ Returns true is self is one and false otherwise - + >>> gf = fq_default_ctx(163, 3) >>> gf(-1).is_one() False @@ -521,7 +521,7 @@ cdef class fq_default(flint_scalar): # ================================================= # Generic arithmetic required by flint_scalar - # ================================================= + # ================================================= def _neg_(self): cdef fq_default res @@ -627,7 +627,7 @@ cdef class fq_default(flint_scalar): # ================================================= # Additional arithmetic - # ================================================= + # ================================================= def square(self): """ @@ -648,7 +648,7 @@ cdef class fq_default(flint_scalar): def __pow__(self, e): """ Compute `a^e` for `a` equal to ``self``. - + >>> gf = fq_default_ctx(163, 3) >>> a = gf([1,2,3]) >>> pow(a, -1) == 1/a @@ -697,7 +697,7 @@ cdef class fq_default(flint_scalar): >>> a.is_square() True >>> b = a.sqrt() - >>> b + >>> b 95*x^2 + 36*x + 34 >>> b**2 in [a, -a] True @@ -725,9 +725,9 @@ cdef class fq_default(flint_scalar): def pth_root(self): """ Returns the pth root of the element. - - This is computed by raising ``self`` to the `p^(d-1)` power, - `p` is the characteristic of the field and `d` is the degree + + This is computed by raising ``self`` to the `p^(d-1)` power, + `p` is the characteristic of the field and `d` is the degree of the extension. >>> gf = fq_default_ctx(163, 3) @@ -742,12 +742,12 @@ cdef class fq_default(flint_scalar): # ================================================= # Special functions - # ================================================= + # ================================================= def trace(self): """ Returns the trace of self - + >>> gf = fq_default_ctx(163, 3) >>> a = gf([1,2,3]) >>> a.trace() From 78a42dd0e1f1e08f3e9a0a2f804a429bf7833480 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 16:42:57 +0100 Subject: [PATCH 13/36] remove unused var --- src/flint/types/fq_default.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 433e59b9..1431bc06 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -458,7 +458,6 @@ cdef class fq_default(flint_scalar): >>> gf(123).polynomial() 123 """ - cdef fmpz_mod_poly_ctx ctx cdef fmpz_mod_poly pol ring_ctx = fmpz_mod_poly_ctx(self.ctx.prime()) @@ -771,7 +770,7 @@ cdef class fq_default(flint_scalar): return nrm def frobenius(self, e=1): - """ + r""" Evaluates the homomorphism `\Sigma^e` on ``self``. >>> gf = fq_default_ctx(163, 3) From 6e71a59635939246e11ad0154170566abf933763 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 18:02:09 +0100 Subject: [PATCH 14/36] include equality tests --- src/flint/test/test_all.py | 15 +++++++++++++++ src/flint/types/fq_default.pxd | 10 ++++++---- src/flint/types/fq_default.pyx | 8 ++++++-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index d0cbc25a..163c820b 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -3591,6 +3591,7 @@ def test_fq_default(): # GF(5) gf_5 = flint.fq_default_ctx(5) + gf_5_ = flint.fq_default_ctx(5) # GF(5^2) gf_5_2 = flint.fq_default_ctx(5, 2) @@ -3598,6 +3599,11 @@ def test_fq_default(): # GF((2**127 - 1)^2) gf_127_2 = flint.fq_default_ctx(2**127 - 1, 2) + assert (gf_5 == gf_5_) is True + assert (gf_5 != gf_5_) is False + assert (gf_5 == gf_5_2) is False + assert (gf_5 != gf_5_2) is True + assert gf_5.prime() == gf_5_2.prime() == 5 assert gf_5_2.order() == 5*5 assert gf_5_2.multiplicative_order() == 5*5 - 1 @@ -3614,6 +3620,15 @@ def test_fq_default(): for gf in [gf_5, gf_5_2, gf_127_2]: + assert (gf(0) == gf.zero()) is True + assert (gf(0) != gf.zero()) is False + assert (gf(1) == gf.zero()) is False + assert (gf(1) != gf.zero()) is True + assert raises(lambda: gf.zero() > gf.zero(), TypeError) + assert raises(lambda: gf.zero() >= gf.zero(), TypeError) + assert raises(lambda: gf.zero() < gf.zero(), TypeError) + assert raises(lambda: gf.zero() <= gf.zero(), TypeError) + assert gf.zero().is_zero() is True assert gf.one().is_zero() is False diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index fd704cc0..9c94e932 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -4,10 +4,12 @@ from flint.types.fmpz cimport fmpz from flint.flint_base.flint_base cimport flint_scalar cpdef enum fq_default_type: - DEFAULT = 0 - FQ_ZECH = 1 - FQ_NMOD = 2 - FQ = 3 + DEFAULT = 0 + FQ_ZECH = 1 + FQ_NMOD = 2 + FQ = 3 + NMOD = 4 + FMPZ_MOD = 5 cdef class fq_default_ctx: cdef fq_default_ctx_t val diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 1431bc06..23db05fa 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -43,9 +43,11 @@ cdef class fq_default_ctx: "FQ_ZECH" : 1, "FQ_NMOD" : 2, "FQ" : 3, + "NMOD" : 4, + "FMPZ_MOD" : 5 } if typecheck(fq_type, str): - fq_type = FQ_TYPES.get(typecheck, None) + fq_type = FQ_TYPES.get(fq_type, None) if fq_type is None: raise ValueError("invalid fq_type, must be one of FQ_ZECH, FQ_NMOD or FQ") if not typecheck(fq_type, int): @@ -165,7 +167,7 @@ cdef class fq_default_ctx: - 2: `fq_default_ctx.FQ_NMOD`: Using `fq_nmod_t`, - 3: `fq_default_ctx.FQ`: Using `fq_t`. """ - return fq_default_type(fq_default_ctx_type(self.val)) + return fq_default_ctx_type(self.val) @property def fq_type_str(self): @@ -180,6 +182,8 @@ cdef class fq_default_ctx: 1 : "FQ_ZECH", 2 : "FQ_NMOD", 3 : "FQ", + 4 : "NMOD", + 5 : "FMPZ_MOD", } return FQ_TYPES[self.fq_type] From 44c3186ffeb2001b545b4a9437523b8bd5fa7e7b Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 22:07:14 +0100 Subject: [PATCH 15/36] move more boilerplate into the flint_base --- src/flint/flint_base/flint_base.pyx | 75 ++++++++++++++++++++----- src/flint/types/fq_default.pyx | 85 ++++++++++------------------- 2 files changed, 90 insertions(+), 70 deletions(-) diff --git a/src/flint/flint_base/flint_base.pyx b/src/flint/flint_base/flint_base.pyx index e723b648..8fb6d2e8 100644 --- a/src/flint/flint_base/flint_base.pyx +++ b/src/flint/flint_base/flint_base.pyx @@ -35,25 +35,28 @@ cdef class flint_scalar(flint_elem): # assumes that addition and multiplication are # commutative # ================================================= + def is_zero(self): + return False + + def _any_as_self(self): + return NotImplemented + def _neg_(self): return NotImplemented def _add_(self, other): return NotImplemented - @staticmethod - def _sub_(left, right): + def _sub_(self, other, swap=False): return NotImplemented def _mul_(self, other): return NotImplemented - @staticmethod - def _div_(left, right): + def _div_(self, other, swap=False): return NotImplemented - @staticmethod - def _floordiv_(left, right): + def _floordiv_(self, other, swap=False): return NotImplemented def _invert_(self): @@ -61,8 +64,8 @@ cdef class flint_scalar(flint_elem): # ================================================= # Generic arithmetic using the above functions - # ================================================= - + # ================================================= + def __pos__(self): return self @@ -70,36 +73,82 @@ cdef class flint_scalar(flint_elem): return self._neg_() def __add__(self, other): + other = self._any_as_self(other) + if other is NotImplemented: + return NotImplemented return self._add_(other) def __radd__(self, other): + other = self._any_as_self(other) + if other is NotImplemented: + return NotImplemented return self._add_(other) def __sub__(self, other): - return self._sub_(self, other) + other = self._any_as_self(other) + if other is NotImplemented: + return NotImplemented + return self._sub_(other) def __rsub__(self, other): - return self._sub_(other, self) + other = self._any_as_self(other) + if other is NotImplemented: + return NotImplemented + return self._sub_(other, swap=True) def __mul__(self, other): + other = self._any_as_self(other) + if other is NotImplemented: + return NotImplemented return self._mul_(other) def __rmul__(self, other): + other = self._any_as_self(other) + if other is NotImplemented: + return NotImplemented return self._mul_(other) def __truediv__(self, other): + other = self._any_as_self(other) + if other is NotImplemented: + return NotImplemented + + if other.is_zero(): + raise ZeroDivisionError + return self._div_(self, other) def __rtruediv__(self, other): - return self._div_(other, self) + if self.is_zero(): + raise ZeroDivisionError + + other = self._any_as_self(other) + if other is NotImplemented: + return NotImplemented + return self._div_(other, swap=True) def __floordiv__(self, other): + other = self._any_as_self(other) + if other is NotImplemented: + return NotImplemented + + if other.is_zero(): + raise ZeroDivisionError + return self._floordiv_(self, other) def __rfloordiv__(self, other): - return self._floordiv_(other, self) + if self.is_zero(): + raise ZeroDivisionError + + other = self._any_as_self(other) + if other is NotImplemented: + return NotImplemented + return self._floordiv_(other, swap=True) def __invert__(self): + if self.is_zero(): + raise ZeroDivisionError return self._invert_() @@ -164,7 +213,7 @@ cdef class flint_poly(flint_elem): def roots(self): """ Computes all the roots in the base ring of the polynomial. - Returns a list of all pairs (*v*, *m*) where *v* is the + Returns a list of all pairs (*v*, *m*) where *v* is the integer root and *m* is the multiplicity of the root. To compute complex roots of a polynomial, instead use diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 23db05fa..a5aa3403 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -526,6 +526,9 @@ cdef class fq_default(flint_scalar): # Generic arithmetic required by flint_scalar # ================================================= + def _any_as_self(self, other): + return self.ctx.any_as_fq_default(other) + def _neg_(self): cdef fq_default res res = self.ctx.new_ctype_fq_default() @@ -533,82 +536,50 @@ cdef class fq_default(flint_scalar): return res def _add_(self, other): - other = self.ctx.any_as_fq_default(other) - if other is NotImplemented: - return NotImplemented - + """ + Assumes that __add__() has ensured other is of type self + """ cdef fq_default res res = self.ctx.new_ctype_fq_default() fq_default_add(res.val, self.val, (other).val, self.ctx.val) return res - @staticmethod - def _sub_(left, right): - # Case when left and right are already fq_default - if typecheck(left, fq_default) and typecheck(right, fq_default): - if not (left).ctx == (right).ctx: - raise ValueError("moduli must match") - - # Otherwise, exactly one of these values is fq_default, if it's left - # convert the right - elif typecheck(left, fq_default): - right = (left).ctx.any_as_fq_default(right) - if right is NotImplemented: - return NotImplemented - # Otherwise convert the left - else: - left = (right).ctx.any_as_fq_default(left) - if left is NotImplemented: - return NotImplemented - - # Now perform subtraction + def _sub_(self, other, swap=False): + """ + Assumes that __sub__() has ensured other is of type self + """ cdef fq_default res - res = (left).ctx.new_ctype_fq_default() - fq_default_sub(res.val, (left).val, (right).val, res.ctx.val) + res = self.ctx.new_ctype_fq_default() + if swap: + fq_default_sub(res.val, (other).val, self.val, res.ctx.val) + else: + fq_default_sub(res.val, self.val, (other).val, res.ctx.val) return res def _mul_(self, other): - other = self.ctx.any_as_fq_default(other) - if other is NotImplemented: - return NotImplemented + """ + Assumes that __mul__() has ensured other is of type self + TODO: this could be optimised by using mul_si and others + """ cdef fq_default res res = self.ctx.new_ctype_fq_default() fq_default_mul(res.val, self.val, (other).val, self.ctx.val) return res - @staticmethod - def _div_(left, right): - # Case when left and right are already fq_default - if typecheck(left, fq_default) and typecheck(right, fq_default): - if not (left).ctx == (right).ctx: - raise ValueError("moduli must match") - - # Otherwise, exactly one of these values is fq_default, if it's left - # convert the right - elif typecheck(left, fq_default): - right = (left).ctx.any_as_fq_default(right) - if right is NotImplemented: - return NotImplemented - # Otherwise convert the left - else: - left = (right).ctx.any_as_fq_default(left) - if left is NotImplemented: - return NotImplemented - - if right.is_zero(): - raise ZeroDivisionError - - # Now perform division + def _div_(self, other, swap=False): + """ + Assumes that __div__() has ensured other is of type self + """ cdef fq_default res - res = (left).ctx.new_ctype_fq_default() - fq_default_div(res.val, (left).val, (right).val, res.ctx.val) + res = self.ctx.new_ctype_fq_default() + if swap: + fq_default_div(res.val, (other).val, self.val, res.ctx.val) + else: + fq_default_div(res.val, self.val, (other).val, res.ctx.val) return res def _invert_(self): - if self.is_zero(): - raise ZeroDivisionError - cdef fq_default res res = self.ctx.new_ctype_fq_default() fq_default_inv(res.val, self.val, self.ctx.val) From 9da32dafa42d06910dc5021e5ade87763a112b02 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 22:12:48 +0100 Subject: [PATCH 16/36] remove parsing of list to self in any_to... --- src/flint/types/fq_default.pyx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index a5aa3403..12aa667d 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -328,10 +328,6 @@ cdef class fq_default_ctx: return 0 cdef set_any_as_fq_default(self, fq_default_t fq_ele, obj): - # Converts the list to an fmpz_poly and then sets from this - if typecheck(obj, list): - return self.set_list_as_fq_default(fq_ele, obj) - # For small integers we can convert directly if typecheck(obj, int) and obj.bit_length() < 32: fq_default_set_si(fq_ele, obj, self.val) @@ -431,6 +427,12 @@ cdef class fq_default(flint_scalar): raise TypeError self.ctx = ctx + # Converts the list to an fmpz_poly and then sets from this + if typecheck(val, list): + self.ctx.set_list_as_fq_default(self.val, val) + return + + # Otherwise cascades through types to convert check = self.ctx.set_any_as_fq_default(self.val, val) if check is NotImplemented: raise TypeError From 3c93c4578527d9306ba7aa10a171ccbb95b844b8 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 22:25:30 +0100 Subject: [PATCH 17/36] add to_list method and repr function --- src/flint/types/fq_default.pyx | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 12aa667d..e916eeb5 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -472,12 +472,29 @@ cdef class fq_default(flint_scalar): return pol + def to_list(self): + """ + Returns self as a list of fmpz types corresponding to a + list of coefficients + + >>> gf = fq_default_ctx(163, 3) + >>> gf([-1,2,1]).to_list() + [162, 2, 1] + >>> gf.one().to_list() + [1, 0, 0] + """ + coeffs = [None for _ in range(self.ctx.degree())] + for i in range(self.ctx.degree()): + c = fmpz.__new__(fmpz) + fq_default_get_coeff_fmpz((c).val, self.val, i, self.ctx.val) + coeffs[i] = c + return coeffs + def str(self): return self.polynomial().str(var=self.ctx.var.decode()) - def __repr__(self): - # TODO: what do we want here? - return str(self) + def repr(self): + return f"fq_default({self.to_list(), self.ctx.__repr__()})" # ================================================= # Comparisons From 0a9d2768828042c0d3203d569867c3a5f119710a Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Wed, 7 Aug 2024 22:48:26 +0100 Subject: [PATCH 18/36] add tests for fq_default init from context --- src/flint/test/test_all.py | 10 +++++++++- src/flint/types/fq_default.pyx | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index 163c820b..d34799a9 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -3597,6 +3597,7 @@ def test_fq_default(): gf_5_2 = flint.fq_default_ctx(5, 2) # GF((2**127 - 1)^2) + gf_127 = flint.fq_default_ctx(2**127 - 1, 2) gf_127_2 = flint.fq_default_ctx(2**127 - 1, 2) assert (gf_5 == gf_5_) is True @@ -3616,9 +3617,16 @@ def test_fq_default(): assert str(gf_5) == "Context for fq_default in GF(5)" assert str(gf_5_2) == "Context for fq_default in GF(5^2)[x]/(x^2 + 4*x + 2)" + # coercision + assert gf_5(1) == gf_5(flint.fmpz(1)) == gf_5.one() + assert gf_5(-1) == gf_5(flint.fmpz(-1)) == -gf_5.one() + assert gf_5([0, 1]) == gf_5(flint.fmpz_poly([0, 1])) == gf_5.gen() + R = flint.fmpz_mod_poly_ctx(5) + assert gf_5.gen() == gf_5(R.gen()) == gf_5(flint.nmod_poly([0, 1], 5)) + # test fq_default element arithemtic - for gf in [gf_5, gf_5_2, gf_127_2]: + for gf in [gf_5, gf_5_2, gf_127, gf_127_2]: assert (gf(0) == gf.zero()) is True assert (gf(0) != gf.zero()) is False diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index e916eeb5..931819fa 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -330,7 +330,15 @@ cdef class fq_default_ctx: cdef set_any_as_fq_default(self, fq_default_t fq_ele, obj): # For small integers we can convert directly if typecheck(obj, int) and obj.bit_length() < 32: - fq_default_set_si(fq_ele, obj, self.val) + if obj < 0: + fq_default_set_si(fq_ele, obj, self.val) + else: + fq_default_set_ui(fq_ele, obj, self.val) + return 0 + + # For fmpz we can also convert directly + if typecheck(obj, fmpz): + fq_default_set_fmpz(fq_ele, (obj).val, self.val) return 0 # Assumes that the modulus of the polynomial matches From eca0210965f126bc06f4a261bcbed25bbde7b77c Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Thu, 8 Aug 2024 00:04:21 +0100 Subject: [PATCH 19/36] some small clean up across the file --- src/flint/types/fq_default.pyx | 80 ++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 931819fa..b73335f1 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -23,8 +23,8 @@ cdef class fq_default_ctx: >>> fq_default_ctx(modulus=mod, fq_type=2) fq_default_ctx(11, 2, 'x', x^2 + 1, 'FQ_NMOD') - For more details, see the documentation of :method:`~.from_order` - and :method:`~.from_modulus`. + For more details, see the documentation of :method:`~.set_from_order` + and :method:`~.set_from_modulus`. """ def __cinit__(self): pass @@ -33,11 +33,8 @@ cdef class fq_default_ctx: if self._initialized: fq_default_ctx_clear(self.val) - def __init__(self, p=None, degree=None, var=None, modulus=None, fq_type=fq_default_type.DEFAULT): - # If no variable is given, use x - if var is None: - var = "x" - + @staticmethod + def _parse_input_fq_type(fq_type): # Allow the type to be denoted by strings or integers FQ_TYPES = { "FQ_ZECH" : 1, @@ -49,9 +46,40 @@ cdef class fq_default_ctx: if typecheck(fq_type, str): fq_type = FQ_TYPES.get(fq_type, None) if fq_type is None: - raise ValueError("invalid fq_type, must be one of FQ_ZECH, FQ_NMOD or FQ") + raise ValueError("invalid fq_type string") + + # Now fq_type should be an int between 0, 5 if not typecheck(fq_type, int): - raise ValueError(f"{fq_type = } is invalid") + raise TypeError(f"{fq_type = } is invalid") + if fq_type < 0 or fq_type > 5: + raise ValueError(f"{fq_type = } should be between 0 and 5") + + return fq_type + + @staticmethod + def _parse_input_var(var): + # If no variable is given, use x + if var is None: + var = b"x" + + # Encode to bytes for cython to parse + if isinstance(var, str): + var = var.encode() + + # TODO: Flint only wants one-character inputs + if len(var) > 1: + raise ValueError("variable for GF(p^k) generator can only be one character") + + return var + + def __init__(self, p=None, degree=None, var=None, modulus=None, fq_type=fq_default_type.DEFAULT): + # Ensure the var used for the generator of GF(p^d) is a single byte + # TODO: this var is meaningless for GF(p) -- we could handle this somehow? + var = self._parse_input_var(var) + + # Ensure the fq_type is an integer between 0, 5 -- we allow users to + # input a string which is converted as an enum + fq_type = self._parse_input_fq_type(fq_type) # If a modulus is given, attempt to construct from this if modulus is not None: @@ -80,12 +108,14 @@ cdef class fq_default_ctx: # Construct the field from the prime and degree GF(p^d) self.set_from_order(p, degree, var, fq_type) - cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type fq_type=fq_default_type.DEFAULT): + cdef _c_set_from_order(self, fmpz p, int d, char *var, + fq_default_type fq_type=fq_default_type.DEFAULT): self.var = var fq_default_ctx_init_type(self.val, p.val, d, self.var, fq_type) self._initialized = True - def set_from_order(self, p, d, var, fq_type=fq_default_type.DEFAULT, check_prime=True): + def set_from_order(self, p, d, var, + fq_type=fq_default_type.DEFAULT, check_prime=True): """ Construct a context for the finite field GF(p^d). @@ -111,17 +141,11 @@ cdef class fq_default_ctx: if d < 1: raise ValueError(f"the degree must be positive, got {d = }") - if isinstance(var, str): - var = var.encode() - - # TODO: Flint only wants one-character inputs - if len(var) > 1: - raise ValueError - # Cython type conversion and context initalisation self._c_set_from_order(prime, d, var, fq_type) - cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type fq_type=fq_default_type.DEFAULT): + cdef _c_set_from_modulus(self, modulus, char *var, + fq_default_type fq_type=fq_default_type.DEFAULT): self.var = var if typecheck(modulus, fmpz_mod_poly): fq_default_ctx_init_modulus_type(self.val, (modulus).val, @@ -133,7 +157,8 @@ cdef class fq_default_ctx: raise TypeError(f"modulus must be fmpz_mod_poly or nmod_poly, got {modulus!r}") self._initialized = True - def set_from_modulus(self, modulus, var, fq_type=fq_default_type.DEFAULT, check_modulus=True): + def set_from_modulus(self, modulus, var, + fq_type=fq_default_type.DEFAULT, check_modulus=True): """ Construct a context for a finite field from an irreducible polynomial. @@ -149,9 +174,6 @@ cdef class fq_default_ctx: - `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, - `fq_default_ctx.FQ`: Use `fq_t`. """ - if isinstance(var, str): - var = var.encode() - if check_modulus and not modulus.is_irreducible(): raise ValueError("modulus must be irreducible") @@ -242,7 +264,6 @@ cdef class fq_default_ctx: >>> gf = fq_default_ctx(5, 2) >>> gf.modulus() x^2 + 4*x + 2 - """ cdef fmpz_mod_poly_ctx ctx cdef fmpz_mod_poly pol @@ -504,6 +525,9 @@ cdef class fq_default(flint_scalar): def repr(self): return f"fq_default({self.to_list(), self.ctx.__repr__()})" + def __hash__(self): + return hash((self.to_polynomial(), hash(self.ctx))) + # ================================================= # Comparisons # ================================================= @@ -612,6 +636,10 @@ cdef class fq_default(flint_scalar): fq_default_inv(res.val, self.val, self.ctx.val) return res + # ================================================= + # Additional arithmetic + # ================================================= + def inverse(self): """ Computes the inverse of self @@ -626,10 +654,6 @@ cdef class fq_default(flint_scalar): """ return self._invert_() - # ================================================= - # Additional arithmetic - # ================================================= - def square(self): """ Computes the square of ``self`` From f2443f80bd31e9f3390316870452395bee1067d3 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Thu, 8 Aug 2024 15:39:05 +0100 Subject: [PATCH 20/36] refactor equality and coercion --- src/flint/test/test_all.py | 74 ++++++++++++++++++++++++++-- src/flint/types/fq_default.pxd | 1 + src/flint/types/fq_default.pyx | 90 +++++++++++++++++++++++++++++----- 3 files changed, 149 insertions(+), 16 deletions(-) diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index d34799a9..f10ab63c 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -3595,6 +3595,7 @@ def test_fq_default(): # GF(5^2) gf_5_2 = flint.fq_default_ctx(5, 2) + gf_5_2_ = flint.fq_default_ctx(5, 2) # GF((2**127 - 1)^2) gf_127 = flint.fq_default_ctx(2**127 - 1, 2) @@ -3618,11 +3619,76 @@ def test_fq_default(): assert str(gf_5_2) == "Context for fq_default in GF(5^2)[x]/(x^2 + 4*x + 2)" # coercision - assert gf_5(1) == gf_5(flint.fmpz(1)) == gf_5.one() - assert gf_5(-1) == gf_5(flint.fmpz(-1)) == -gf_5.one() - assert gf_5([0, 1]) == gf_5(flint.fmpz_poly([0, 1])) == gf_5.gen() + assert gf_5(1) == gf_5.one() + assert gf_5(flint.fmpz(1)) == gf_5.one() + assert gf_5(-1) == -gf_5.one() + assert gf_5(flint.fmpz(-1)) == -gf_5.one() + R = flint.fmpz_mod_ctx(5) + assert gf_5(R(1)) == gf_5.one() + assert gf_5(R(-1)) == -gf_5.one() + assert gf_5(flint.nmod(1, 5)) == gf_5.one() + assert gf_5(flint.nmod(-1, 5)) == -gf_5.one() + assert gf_5([0, 1]) == gf_5.gen() + assert gf_5(flint.fmpz_poly([0, 1])) == gf_5.gen() R = flint.fmpz_mod_poly_ctx(5) - assert gf_5.gen() == gf_5(R.gen()) == gf_5(flint.nmod_poly([0, 1], 5)) + assert gf_5.gen() == gf_5(R.gen()) + assert gf_5.gen() == gf_5(flint.nmod_poly([0, 1], 5)) + + + # testing various equalties between types + + # integers are the same if charactersitic is the same + # even with extensions + assert gf_5.one() == gf_5_.one() + assert gf_5.one() == gf_5_2.one() + assert gf_5.one() != gf_127.one() + + # the generators for different extensions + assert gf_5_2([0, 1]) != gf_5([0, 1]) + assert gf_5_2([0, 1]) == gf_5_2_([0, 1]) + assert gf_5_2([0, 1]) != gf_127_2([0, 1]) + + # integers are reduced modulo p before comparison + for int_type in [int, flint.fmpz]: + assert gf_5(1) == int_type(1) + assert gf_5(-1) == int_type(-1) + assert gf_5(-1) == int_type(4) + assert gf_5(4) == int_type(4) + assert gf_5(4) == int_type(-1) + + # integers modulo n also can be compared when they match + assert gf_5(1) == flint.nmod(1, 5) + assert gf_5(-1) == flint.nmod(-1, 5) + assert gf_5(-1) == flint.nmod(4, 5) + assert gf_5_2(1) == flint.nmod(1, 5) + assert gf_5_2(-1) == flint.nmod(-1, 5) + assert gf_5_2(-1) == flint.nmod(4, 5) + + # when the moduli dont match, comparison is always false + assert gf_5(1) != flint.nmod(1, 7) + assert gf_5(-1) != flint.nmod(-1, 7) + assert gf_5(-1) != flint.nmod(4, 7) + assert gf_5_2(1) != flint.nmod(1, 7) + assert gf_5_2(-1) != flint.nmod(-1, 7) + assert gf_5_2(-1) != flint.nmod(4, 7) + + # integers modulo n also can be compared when they match + R5 = flint.fmpz_mod_ctx(5) + assert gf_5(1) == R5(1) + assert gf_5(-1) == R5(-1) + assert gf_5(-1) == R5(4) + assert gf_5_2(1) == R5(1) + assert gf_5_2(-1) == R5(-1) + assert gf_5_2(-1) == R5(4) + + # when the moduli dont match, comparison is always false + R7 = flint.fmpz_mod_ctx(7) + assert gf_5(1) != R7(1) + assert gf_5(-1) != R7(-1) + assert gf_5(-1) != R7(4) + assert gf_5_2(1) != R7(1) + assert gf_5_2(-1) != R7(-1) + assert gf_5_2(-1) != R7(4) # test fq_default element arithemtic diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index 9c94e932..c55d8bde 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -18,6 +18,7 @@ cdef class fq_default_ctx: cdef new_ctype_fq_default(self) cdef set_list_as_fq_default(self, fq_default_t val, obj) + cdef set_any_scalar_as_fq_default(self, fq_default_t fq_ele, obj) cdef set_any_as_fq_default(self, fq_default_t val, obj) cdef any_as_fq_default(self, obj) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index b73335f1..fdf758fa 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -1,5 +1,7 @@ from flint.pyflint cimport global_random_state from flint.types.fmpz cimport fmpz, any_as_fmpz +from flint.types.nmod cimport nmod +from flint.types.fmpz_mod cimport fmpz_mod from flint.types.fmpz_poly cimport fmpz_poly, any_as_fmpz_poly, fmpz_poly_set_list from flint.types.fmpz_mod_poly cimport fmpz_mod_poly, fmpz_mod_poly_ctx from flint.types.nmod_poly cimport nmod_poly @@ -348,13 +350,17 @@ cdef class fq_default_ctx: return 0 - cdef set_any_as_fq_default(self, fq_default_t fq_ele, obj): - # For small integers we can convert directly - if typecheck(obj, int) and obj.bit_length() < 32: - if obj < 0: + cdef set_any_scalar_as_fq_default(self, fq_default_t fq_ele, obj): + if typecheck(obj, int): + # For small integers we can convert directly + if obj < 0 and obj.bit_length() < 31: fq_default_set_si(fq_ele, obj, self.val) - else: + elif obj.bit_length() < 32: fq_default_set_ui(fq_ele, obj, self.val) + # For larger integers we first convert to fmpz + else: + obj_fmpz = any_as_fmpz(obj) + fq_default_set_fmpz(fq_ele, (obj_fmpz).val, self.val) return 0 # For fmpz we can also convert directly @@ -362,6 +368,27 @@ cdef class fq_default_ctx: fq_default_set_fmpz(fq_ele, (obj).val, self.val) return 0 + # For nmod we can convert by taking it as an int + # Ignores the modulus of nmod + if typecheck(obj, nmod): + fq_default_set_ui(fq_ele, (obj).val, self.val) + return 0 + + # For fmpz_mod we can also convert directly + # Assumes that the modulus of the ring matches the context + if typecheck(obj, fmpz_mod): + fq_default_set_fmpz(fq_ele, (obj).val, self.val) + return 0 + + # Otherwise the object wasn't a scalar we convert from + return NotImplemented + + cdef set_any_as_fq_default(self, fq_default_t fq_ele, obj): + # First try and convert from scalars + check = self.set_any_scalar_as_fq_default(fq_ele, obj) + if check is not NotImplemented: + return 0 + # Assumes that the modulus of the polynomial matches # the context for the fq_default if typecheck(obj, fmpz_mod_poly): @@ -560,18 +587,57 @@ cdef class fq_default(flint_scalar): if op != 2 and op != 3: raise TypeError("fq_default cannot be ordered") + # If other is not an fq_default element, we attempt to convert to fq_default if not typecheck(other, fq_default): - other = self.ctx.any_as_fq_default(other) + # For nmod and fmpz_mod if the modulus does not match the characteristic + # then we return false. + if typecheck(other, nmod) and self.ctx.characteristic() != (other).modulus(): + res = False - if typecheck(other, fq_default): - res = (self.ctx == (other).ctx) and \ - fq_default_equal(self.val, (other).val, self.ctx.val) + elif typecheck(other, fmpz_mod) and self.ctx.characteristic() != (other).ctx.modulus(): + res = False + + else: + # Convert from int, fmpz, fmpz_mod and nmod to fq_default + cmp = self.ctx.new_ctype_fq_default() + check = self.ctx.set_any_scalar_as_fq_default((cmp).val, other) + + # Conversion failed, element was not a compatible scalar + if check is NotImplemented: + res = False + else: + # We now have an fq_default element with the same context, so compare value only + res = fq_default_equal(self.val, (cmp).val, self.ctx.val) + + # Flip the result of res if we're doing not equals if op == 2: return res - else: - return not res + return not res + + # Otherwise we're in the case where other is also an fq_default but may have a + # different context. + + # If the contexts match exactly, only check values + if self.ctx == (other).ctx: + res = fq_default_equal(self.val, (other).val, self.ctx.val) + + # Otherwise if both contexts have the same characteristic check + # if both fq_default lift to the same integer + elif self.ctx.characteristic() == (other).ctx.characteristic(): + try: + res = int(self) == int(other) + # One or both lifts failed, so values are not equal + except ValueError: + res = False + + # Otherwise, values are considered not equal else: - return NotImplemented + res = False + + # Flip the result of res if we're doing not equals + if op == 2: + return res + return not res # ================================================= # Generic arithmetic required by flint_scalar From 915837e2a4d41534322a12c11144aeb8daad5697 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 10:46:50 +0100 Subject: [PATCH 21/36] attempt to include is_primitive --- src/flint/types/fq_default.pxd | 4 +++- src/flint/types/fq_default.pyx | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index c55d8bde..b236475b 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -1,5 +1,7 @@ from flint.flintlib.fq_default cimport * - +from flint.flintlib.fq_zech cimport fq_zech_is_primitive, fq_zech_multiplicative_order +from flint.flintlib.fq_nmod cimport fq_nmod_is_primitive, fq_nmod_multiplicative_order +from flint.flintlib.fq cimport fq_is_primitive, fq_multiplicative_order from flint.types.fmpz cimport fmpz from flint.flint_base.flint_base cimport flint_scalar diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index fdf758fa..21898751 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -880,3 +880,15 @@ cdef class fq_default(flint_scalar): res = self.ctx.new_ctype_fq_default() fq_default_frobenius(res.val, self.val, e, self.ctx.val) return res + + def is_primitive(self): + """ + """ + if self.ctx.fq_type == 1: + return 1 == fq_zech_is_primitive(self.val, self.ctx.val) + elif self.ctx.fq_type in [2, 4]: + return 1 == fq_nmod_is_primitive(self.val, self.ctx.val) + elif self.ctx.fq_type in [3, 5]: + return 1 == fq_is_primitive(self.val, self.ctx.val) + else: + return NotImplemented From 83f2179324ac337f37229d38e2c59ca80bd87d93 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 11:24:34 +0100 Subject: [PATCH 22/36] use union instead of struct --- src/flint/flintlib/fq_default.pxd | 6 ++---- src/flint/types/fq_default.pyx | 10 +++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/flint/flintlib/fq_default.pxd b/src/flint/flintlib/fq_default.pxd index ec4c20c5..ac298c62 100644 --- a/src/flint/flintlib/fq_default.pxd +++ b/src/flint/flintlib/fq_default.pxd @@ -12,9 +12,7 @@ from flint.flintlib.fq_nmod cimport fq_nmod_t, fq_nmod_ctx_t from flint.flintlib.fq_zech cimport fq_zech_t, fq_zech_ctx_t cdef extern from "flint/fq_default.h": - # TODO: how best to handle union - # https://stackoverflow.com/questions/12452210/cython-nesting-a-union-within-a-struct - ctypedef struct fq_default_struct: + ctypedef union fq_default_struct: fq_t fq fq_nmod_t fq_nmod fq_zech_t fq_zech @@ -30,7 +28,7 @@ cdef extern from "flint/fq_default.h": nmod_t mod mp_limb_t a # minpoly is x - a - ctypedef struct fq_default_ctx_struct: + ctypedef union fq_default_ctx_struct: fq_ctx_t fq fq_nmod_ctx_t fq_nmod fq_zech_ctx_t fq_zech diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 21898751..98078ab2 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -885,10 +885,10 @@ cdef class fq_default(flint_scalar): """ """ if self.ctx.fq_type == 1: - return 1 == fq_zech_is_primitive(self.val, self.ctx.val) - elif self.ctx.fq_type in [2, 4]: - return 1 == fq_nmod_is_primitive(self.val, self.ctx.val) - elif self.ctx.fq_type in [3, 5]: - return 1 == fq_is_primitive(self.val, self.ctx.val) + return 1 == fq_zech_is_primitive((self).val.fq_zech, (self.ctx).val.fq_zech) + elif self.ctx.fq_type == 2: + return 1 == fq_nmod_is_primitive((self).val.fq_nmod, (self.ctx).val.fq_nmod) + elif self.ctx.fq_type == 3: + return 1 == fq_is_primitive((self).val.fq, (self.ctx).val.fq) else: return NotImplemented From 525883fb2ed28de238e6049a8ecc00d19b1784e1 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 11:31:00 +0100 Subject: [PATCH 23/36] comment out broken function --- src/flint/types/fq_default.pyx | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 98078ab2..7917dd92 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -881,14 +881,15 @@ cdef class fq_default(flint_scalar): fq_default_frobenius(res.val, self.val, e, self.ctx.val) return res - def is_primitive(self): - """ - """ - if self.ctx.fq_type == 1: - return 1 == fq_zech_is_primitive((self).val.fq_zech, (self.ctx).val.fq_zech) - elif self.ctx.fq_type == 2: - return 1 == fq_nmod_is_primitive((self).val.fq_nmod, (self.ctx).val.fq_nmod) - elif self.ctx.fq_type == 3: - return 1 == fq_is_primitive((self).val.fq, (self.ctx).val.fq) - else: - return NotImplemented + # TODO: this crashes as the context cannot be found during compile time. + # def is_primitive(self): + # """ + # """ + # if self.ctx.fq_type == 1: + # return 1 == fq_zech_is_primitive((self).val.fq_zech, (self.ctx).val.fq_zech) + # elif self.ctx.fq_type == 2: + # return 1 == fq_nmod_is_primitive((self).val.fq_nmod, (self.ctx).val.fq_nmod) + # elif self.ctx.fq_type == 3: + # return 1 == fq_is_primitive((self).val.fq, (self.ctx).val.fq) + # else: + # return NotImplemented From 812fea4cd4c37a160a73f5339eaa9cf1729e7341 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 12:44:55 +0100 Subject: [PATCH 24/36] make is_primitive work --- src/flint/types/fq_default.pxd | 8 +++++ src/flint/types/fq_default.pyx | 62 +++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index b236475b..da226244 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -5,6 +5,11 @@ from flint.flintlib.fq cimport fq_is_primitive, fq_multiplicative_order from flint.types.fmpz cimport fmpz from flint.flint_base.flint_base cimport flint_scalar +cdef extern from "flint/fq_default.h": + cdef fq_ctx_t FQ_DEFAULT_CTX_FQ(fq_default_ctx_t ctx) + cdef fq_zech_ctx_t FQ_DEFAULT_CTX_FQ_ZECH(fq_default_ctx_t ctx) + cdef fq_nmod_ctx_t FQ_DEFAULT_CTX_FQ_NMOD(fq_default_ctx_t ctx) + cpdef enum fq_default_type: DEFAULT = 0 FQ_ZECH = 1 @@ -27,6 +32,9 @@ cdef class fq_default_ctx: cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type fq_type=*) cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type fq_type=*) + # cdef fq_zech_ctx_t get_fq_zech_ctx_t(self) + # cdef fq_nmod_ctx_t get_fq_nmod_ctx_t(self) + # cdef fq_ctx_t get_fq_ctx_t(self) cdef class fq_default(flint_scalar): cdef fq_default_ctx ctx diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 7917dd92..39d6ad26 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -424,6 +424,30 @@ cdef class fq_default_ctx: return NotImplemented return res + # cdef get_fq_zech_ctx_t(self): + # """ + # Return the fq_zech_ctx_t type from the context + # """ + # cdef fq_default s + # s = self + # return FQ_DEFAULT_CTX_FQ_ZECH(s.ctx.val) + + # cdef get_fq_nmod_ctx_t(self): + # """ + # Return the fq_nmod_ctx_t type from the context + # """ + # cdef fq_default s + # s = self + # return FQ_DEFAULT_CTX_FQ_NMOD(s.ctx.val) + + # cdef fq_ctx_t get_fq_ctx_t(self): + # """ + # Return the fq_ctx_t type from the context + # """ + # cdef fq_default s + # s = self + # return FQ_DEFAULT_CTX_FQ(s.ctx.val) + def __eq__(self, other): """ Two finite field context compare equal if they have same @@ -881,15 +905,29 @@ cdef class fq_default(flint_scalar): fq_default_frobenius(res.val, self.val, e, self.ctx.val) return res - # TODO: this crashes as the context cannot be found during compile time. - # def is_primitive(self): - # """ - # """ - # if self.ctx.fq_type == 1: - # return 1 == fq_zech_is_primitive((self).val.fq_zech, (self.ctx).val.fq_zech) - # elif self.ctx.fq_type == 2: - # return 1 == fq_nmod_is_primitive((self).val.fq_nmod, (self.ctx).val.fq_nmod) - # elif self.ctx.fq_type == 3: - # return 1 == fq_is_primitive((self).val.fq, (self.ctx).val.fq) - # else: - # return NotImplemented + def is_primitive(self): + """ + Returns whether ``self`` is primitive, i.e., whether it is a + generator of the multiplicative group of the finite field. + + >>> gf = fq_default_ctx(163, fq_type=1) + >>> gf(2).is_primitive() + True + >>> gf(5).is_primitive() + False + >>> gf = fq_default_ctx(163, 3, fq_type=2) + >>> gf.gen().is_primitive() + True + >>> gf = fq_default_ctx(2**127 - 1, fq_type=3) + >>> gf(43).is_primitive() + True + """ + cdef fq_default s + s = self + if self.ctx.fq_type == 1: + return 1 == fq_zech_is_primitive(s.val.fq_zech, FQ_DEFAULT_CTX_FQ_ZECH(s.ctx.val)) + elif self.ctx.fq_type == 2: + return 1 == fq_nmod_is_primitive(s.val.fq_nmod, FQ_DEFAULT_CTX_FQ_NMOD(s.ctx.val)) + elif self.ctx.fq_type == 3: + return 1 == fq_is_primitive(s.val.fq, FQ_DEFAULT_CTX_FQ(s.ctx.val)) + raise TypeError("Can only call is_primitive() for elements with context FQ, FQ_ZECH and FQ_NMOD") From ef2136a1f4fc027755c060a9a576770f0c25a320 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 14:09:05 +0100 Subject: [PATCH 25/36] broken refactor; need help --- src/flint/types/fq_default.pxd | 15 ++++++---- src/flint/types/fq_default.pyx | 50 +++++++++++++++++----------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index da226244..50f35013 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -1,4 +1,7 @@ from flint.flintlib.fq_default cimport * +from flint.flintlib.fq cimport fq_ctx_struct +from flint.flintlib.fq_nmod cimport fq_nmod_ctx_struct +from flint.flintlib.fq_zech cimport fq_zech_ctx_struct from flint.flintlib.fq_zech cimport fq_zech_is_primitive, fq_zech_multiplicative_order from flint.flintlib.fq_nmod cimport fq_nmod_is_primitive, fq_nmod_multiplicative_order from flint.flintlib.fq cimport fq_is_primitive, fq_multiplicative_order @@ -6,9 +9,9 @@ from flint.types.fmpz cimport fmpz from flint.flint_base.flint_base cimport flint_scalar cdef extern from "flint/fq_default.h": - cdef fq_ctx_t FQ_DEFAULT_CTX_FQ(fq_default_ctx_t ctx) - cdef fq_zech_ctx_t FQ_DEFAULT_CTX_FQ_ZECH(fq_default_ctx_t ctx) - cdef fq_nmod_ctx_t FQ_DEFAULT_CTX_FQ_NMOD(fq_default_ctx_t ctx) + cdef fq_ctx_struct* FQ_DEFAULT_CTX_FQ(fq_default_ctx_t ctx) + cdef fq_zech_ctx_struct* FQ_DEFAULT_CTX_FQ_ZECH(fq_default_ctx_t ctx) + cdef fq_nmod_ctx_struct* FQ_DEFAULT_CTX_FQ_NMOD(fq_default_ctx_t ctx) cpdef enum fq_default_type: DEFAULT = 0 @@ -32,9 +35,9 @@ cdef class fq_default_ctx: cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type fq_type=*) cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type fq_type=*) - # cdef fq_zech_ctx_t get_fq_zech_ctx_t(self) - # cdef fq_nmod_ctx_t get_fq_nmod_ctx_t(self) - # cdef fq_ctx_t get_fq_ctx_t(self) + cdef inline fq_ctx_struct* get_fq_ctx_t(self) + cdef inline fq_zech_ctx_struct* get_fq_zech_ctx_t(self) + cdef inline fq_nmod_ctx_struct* get_fq_nmod_ctx_t(self) cdef class fq_default(flint_scalar): cdef fq_default_ctx ctx diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 39d6ad26..c3cdaf40 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -424,29 +424,29 @@ cdef class fq_default_ctx: return NotImplemented return res - # cdef get_fq_zech_ctx_t(self): - # """ - # Return the fq_zech_ctx_t type from the context - # """ - # cdef fq_default s - # s = self - # return FQ_DEFAULT_CTX_FQ_ZECH(s.ctx.val) - - # cdef get_fq_nmod_ctx_t(self): - # """ - # Return the fq_nmod_ctx_t type from the context - # """ - # cdef fq_default s - # s = self - # return FQ_DEFAULT_CTX_FQ_NMOD(s.ctx.val) + cdef inline fq_zech_ctx_struct* get_fq_zech_ctx_t(self): + """ + Return the fq_zech_ctx_t type from the context + """ + cdef fq_default s + s = self + return FQ_DEFAULT_CTX_FQ_ZECH(s.ctx.val) + + cdef inline fq_nmod_ctx_struct* get_fq_nmod_ctx_t(self): + """ + Return the fq_nmod_ctx_t type from the context + """ + cdef fq_default s + s = self + return FQ_DEFAULT_CTX_FQ_NMOD(s.ctx.val) - # cdef fq_ctx_t get_fq_ctx_t(self): - # """ - # Return the fq_ctx_t type from the context - # """ - # cdef fq_default s - # s = self - # return FQ_DEFAULT_CTX_FQ(s.ctx.val) + cdef inline fq_ctx_struct* get_fq_ctx_t(self): + """ + Return the fq_ctx_t type from the context + """ + cdef fq_default s + s = self + return FQ_DEFAULT_CTX_FQ(s.ctx.val) def __eq__(self, other): """ @@ -925,9 +925,9 @@ cdef class fq_default(flint_scalar): cdef fq_default s s = self if self.ctx.fq_type == 1: - return 1 == fq_zech_is_primitive(s.val.fq_zech, FQ_DEFAULT_CTX_FQ_ZECH(s.ctx.val)) + return 1 == fq_zech_is_primitive(s.val.fq_zech, s.get_fq_zech_ctx_t()) elif self.ctx.fq_type == 2: - return 1 == fq_nmod_is_primitive(s.val.fq_nmod, FQ_DEFAULT_CTX_FQ_NMOD(s.ctx.val)) + return 1 == fq_nmod_is_primitive(s.val.fq_nmod, s.get_fq_nmod_ctx_t()) elif self.ctx.fq_type == 3: - return 1 == fq_is_primitive(s.val.fq, FQ_DEFAULT_CTX_FQ(s.ctx.val)) + return 1 == fq_is_primitive(s.val.fq, self.get_fq_ctx_t()) raise TypeError("Can only call is_primitive() for elements with context FQ, FQ_ZECH and FQ_NMOD") From 172c9d8482ab6efee22af228395a9dce73dde860 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 14:32:12 +0100 Subject: [PATCH 26/36] remove is_primitive and modify base template --- src/flint/flint_base/flint_base.pyx | 25 ++++++--- src/flint/types/fq_default.pxd | 12 ----- src/flint/types/fq_default.pyx | 83 ++++++++--------------------- 3 files changed, 39 insertions(+), 81 deletions(-) diff --git a/src/flint/flint_base/flint_base.pyx b/src/flint/flint_base/flint_base.pyx index 8fb6d2e8..e6151845 100644 --- a/src/flint/flint_base/flint_base.pyx +++ b/src/flint/flint_base/flint_base.pyx @@ -47,16 +47,25 @@ cdef class flint_scalar(flint_elem): def _add_(self, other): return NotImplemented - def _sub_(self, other, swap=False): + def _sub_(self, other): + return NotImplemented + + def _rsub_(self, other): return NotImplemented def _mul_(self, other): return NotImplemented - def _div_(self, other, swap=False): + def _div_(self, other): + return NotImplemented + + def _rdiv_(self, other): + return NotImplemented + + def _floordiv_(self, other): return NotImplemented - def _floordiv_(self, other, swap=False): + def _rfloordiv_(self, other): return NotImplemented def _invert_(self): @@ -94,7 +103,7 @@ cdef class flint_scalar(flint_elem): other = self._any_as_self(other) if other is NotImplemented: return NotImplemented - return self._sub_(other, swap=True) + return self._rsub_(other) def __mul__(self, other): other = self._any_as_self(other) @@ -116,7 +125,7 @@ cdef class flint_scalar(flint_elem): if other.is_zero(): raise ZeroDivisionError - return self._div_(self, other) + return self._div_(other) def __rtruediv__(self, other): if self.is_zero(): @@ -125,7 +134,7 @@ cdef class flint_scalar(flint_elem): other = self._any_as_self(other) if other is NotImplemented: return NotImplemented - return self._div_(other, swap=True) + return self._rdiv_(other) def __floordiv__(self, other): other = self._any_as_self(other) @@ -135,7 +144,7 @@ cdef class flint_scalar(flint_elem): if other.is_zero(): raise ZeroDivisionError - return self._floordiv_(self, other) + return self._floordiv_(other) def __rfloordiv__(self, other): if self.is_zero(): @@ -144,7 +153,7 @@ cdef class flint_scalar(flint_elem): other = self._any_as_self(other) if other is NotImplemented: return NotImplemented - return self._floordiv_(other, swap=True) + return self._rfloordiv_(other) def __invert__(self): if self.is_zero(): diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index 50f35013..bccdd2ce 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -1,18 +1,10 @@ from flint.flintlib.fq_default cimport * -from flint.flintlib.fq cimport fq_ctx_struct -from flint.flintlib.fq_nmod cimport fq_nmod_ctx_struct -from flint.flintlib.fq_zech cimport fq_zech_ctx_struct from flint.flintlib.fq_zech cimport fq_zech_is_primitive, fq_zech_multiplicative_order from flint.flintlib.fq_nmod cimport fq_nmod_is_primitive, fq_nmod_multiplicative_order from flint.flintlib.fq cimport fq_is_primitive, fq_multiplicative_order from flint.types.fmpz cimport fmpz from flint.flint_base.flint_base cimport flint_scalar -cdef extern from "flint/fq_default.h": - cdef fq_ctx_struct* FQ_DEFAULT_CTX_FQ(fq_default_ctx_t ctx) - cdef fq_zech_ctx_struct* FQ_DEFAULT_CTX_FQ_ZECH(fq_default_ctx_t ctx) - cdef fq_nmod_ctx_struct* FQ_DEFAULT_CTX_FQ_NMOD(fq_default_ctx_t ctx) - cpdef enum fq_default_type: DEFAULT = 0 FQ_ZECH = 1 @@ -35,10 +27,6 @@ cdef class fq_default_ctx: cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type fq_type=*) cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type fq_type=*) - cdef inline fq_ctx_struct* get_fq_ctx_t(self) - cdef inline fq_zech_ctx_struct* get_fq_zech_ctx_t(self) - cdef inline fq_nmod_ctx_struct* get_fq_nmod_ctx_t(self) - cdef class fq_default(flint_scalar): cdef fq_default_ctx ctx cdef fq_default_t val diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index c3cdaf40..df0a6a4a 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -424,30 +424,6 @@ cdef class fq_default_ctx: return NotImplemented return res - cdef inline fq_zech_ctx_struct* get_fq_zech_ctx_t(self): - """ - Return the fq_zech_ctx_t type from the context - """ - cdef fq_default s - s = self - return FQ_DEFAULT_CTX_FQ_ZECH(s.ctx.val) - - cdef inline fq_nmod_ctx_struct* get_fq_nmod_ctx_t(self): - """ - Return the fq_nmod_ctx_t type from the context - """ - cdef fq_default s - s = self - return FQ_DEFAULT_CTX_FQ_NMOD(s.ctx.val) - - cdef inline fq_ctx_struct* get_fq_ctx_t(self): - """ - Return the fq_ctx_t type from the context - """ - cdef fq_default s - s = self - return FQ_DEFAULT_CTX_FQ(s.ctx.val) - def __eq__(self, other): """ Two finite field context compare equal if they have same @@ -685,16 +661,22 @@ cdef class fq_default(flint_scalar): fq_default_add(res.val, self.val, (other).val, self.ctx.val) return res - def _sub_(self, other, swap=False): + def _sub_(self, other): """ Assumes that __sub__() has ensured other is of type self """ cdef fq_default res res = self.ctx.new_ctype_fq_default() - if swap: - fq_default_sub(res.val, (other).val, self.val, res.ctx.val) - else: - fq_default_sub(res.val, self.val, (other).val, res.ctx.val) + fq_default_sub(res.val, self.val, (other).val, res.ctx.val) + return res + + def _rsub_(self, other): + """ + Assumes that __rsub__() has ensured other is of type self + """ + cdef fq_default res + res = self.ctx.new_ctype_fq_default() + fq_default_sub(res.val, (other).val, self.val, res.ctx.val) return res def _mul_(self, other): @@ -708,16 +690,22 @@ cdef class fq_default(flint_scalar): fq_default_mul(res.val, self.val, (other).val, self.ctx.val) return res - def _div_(self, other, swap=False): + def _div_(self, other): """ Assumes that __div__() has ensured other is of type self """ cdef fq_default res res = self.ctx.new_ctype_fq_default() - if swap: - fq_default_div(res.val, (other).val, self.val, res.ctx.val) - else: - fq_default_div(res.val, self.val, (other).val, res.ctx.val) + fq_default_div(res.val, self.val, (other).val, res.ctx.val) + return res + + def _rdiv_(self, other): + """ + Assumes that __div__() has ensured other is of type self + """ + cdef fq_default res + res = self.ctx.new_ctype_fq_default() + fq_default_div(res.val, (other).val, self.val, res.ctx.val) return res def _invert_(self): @@ -904,30 +892,3 @@ cdef class fq_default(flint_scalar): res = self.ctx.new_ctype_fq_default() fq_default_frobenius(res.val, self.val, e, self.ctx.val) return res - - def is_primitive(self): - """ - Returns whether ``self`` is primitive, i.e., whether it is a - generator of the multiplicative group of the finite field. - - >>> gf = fq_default_ctx(163, fq_type=1) - >>> gf(2).is_primitive() - True - >>> gf(5).is_primitive() - False - >>> gf = fq_default_ctx(163, 3, fq_type=2) - >>> gf.gen().is_primitive() - True - >>> gf = fq_default_ctx(2**127 - 1, fq_type=3) - >>> gf(43).is_primitive() - True - """ - cdef fq_default s - s = self - if self.ctx.fq_type == 1: - return 1 == fq_zech_is_primitive(s.val.fq_zech, s.get_fq_zech_ctx_t()) - elif self.ctx.fq_type == 2: - return 1 == fq_nmod_is_primitive(s.val.fq_nmod, s.get_fq_nmod_ctx_t()) - elif self.ctx.fq_type == 3: - return 1 == fq_is_primitive(s.val.fq, self.get_fq_ctx_t()) - raise TypeError("Can only call is_primitive() for elements with context FQ, FQ_ZECH and FQ_NMOD") From ce8cd4d969ebc19708b29a18b8a6fe4b016fcb91 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 14:50:56 +0100 Subject: [PATCH 27/36] modify _arith_ to use cpdef --- src/flint/types/fq_default.pxd | 10 +++++++ src/flint/types/fq_default.pyx | 52 ++++++++++++++-------------------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index bccdd2ce..429b25ed 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -30,3 +30,13 @@ cdef class fq_default_ctx: cdef class fq_default(flint_scalar): cdef fq_default_ctx ctx cdef fq_default_t val + + # Arithmetic for flint_scalar base class + cpdef fq_default _neg_(fq_default self) + cpdef fq_default _add_(fq_default self, fq_default other) + cpdef fq_default _mul_(fq_default self, fq_default other) + cpdef fq_default _sub_(fq_default self, fq_default other) + cpdef fq_default _rsub_(fq_default self, fq_default other) + cpdef fq_default _div_(fq_default self, fq_default other) + cpdef fq_default _rdiv_(fq_default self, fq_default other) + cpdef fq_default _invert_(fq_default self) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index df0a6a4a..92607826 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -646,71 +646,63 @@ cdef class fq_default(flint_scalar): def _any_as_self(self, other): return self.ctx.any_as_fq_default(other) - def _neg_(self): - cdef fq_default res - res = self.ctx.new_ctype_fq_default() + cpdef fq_default _neg_(fq_default self): + cdef fq_default res = self.ctx.new_ctype_fq_default() fq_default_neg(res.val, self.val, self.ctx.val) return res - def _add_(self, other): + cpdef fq_default _add_(fq_default self, fq_default other): """ Assumes that __add__() has ensured other is of type self """ - cdef fq_default res - res = self.ctx.new_ctype_fq_default() - fq_default_add(res.val, self.val, (other).val, self.ctx.val) + cdef fq_default res = self.ctx.new_ctype_fq_default() + fq_default_add(res.val, self.val, other.val, self.ctx.val) return res - def _sub_(self, other): + cpdef fq_default _sub_(fq_default self, fq_default other): """ Assumes that __sub__() has ensured other is of type self """ - cdef fq_default res - res = self.ctx.new_ctype_fq_default() - fq_default_sub(res.val, self.val, (other).val, res.ctx.val) + cdef fq_default res = self.ctx.new_ctype_fq_default() + fq_default_sub(res.val, self.val, other.val, res.ctx.val) return res - def _rsub_(self, other): + cpdef fq_default _rsub_(fq_default self, fq_default other): """ Assumes that __rsub__() has ensured other is of type self """ - cdef fq_default res - res = self.ctx.new_ctype_fq_default() - fq_default_sub(res.val, (other).val, self.val, res.ctx.val) + cdef fq_default res = self.ctx.new_ctype_fq_default() + fq_default_sub(res.val, other.val, self.val, res.ctx.val) return res - def _mul_(self, other): + cpdef fq_default _mul_(fq_default self, fq_default other): """ Assumes that __mul__() has ensured other is of type self TODO: this could be optimised by using mul_si and others """ - cdef fq_default res - res = self.ctx.new_ctype_fq_default() - fq_default_mul(res.val, self.val, (other).val, self.ctx.val) + cdef fq_default res = self.ctx.new_ctype_fq_default() + fq_default_mul(res.val, self.val, other.val, self.ctx.val) return res - def _div_(self, other): + cpdef fq_default _div_(fq_default self, fq_default other): """ Assumes that __div__() has ensured other is of type self """ - cdef fq_default res - res = self.ctx.new_ctype_fq_default() - fq_default_div(res.val, self.val, (other).val, res.ctx.val) + cdef fq_default res = self.ctx.new_ctype_fq_default() + fq_default_div(res.val, self.val, other.val, res.ctx.val) return res - def _rdiv_(self, other): + cpdef fq_default _rdiv_(fq_default self, fq_default other): """ Assumes that __div__() has ensured other is of type self """ - cdef fq_default res - res = self.ctx.new_ctype_fq_default() - fq_default_div(res.val, (other).val, self.val, res.ctx.val) + cdef fq_default res = self.ctx.new_ctype_fq_default() + fq_default_div(res.val, other.val, self.val, res.ctx.val) return res - def _invert_(self): - cdef fq_default res - res = self.ctx.new_ctype_fq_default() + cpdef fq_default _invert_(fq_default self): + cdef fq_default res = self.ctx.new_ctype_fq_default() fq_default_inv(res.val, self.val, self.ctx.val) return res From ee4ae24172708c43941830c7f8fd563b153c5ca5 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 18:21:48 +0100 Subject: [PATCH 28/36] fix some but not all reviewer comments -- need to stop for the day --- src/flint/types/fq_default.pxd | 3 +++ src/flint/types/fq_default.pyx | 44 ++++++++++------------------------ 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index 429b25ed..044005d8 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -24,6 +24,9 @@ cdef class fq_default_ctx: cdef set_any_as_fq_default(self, fq_default_t val, obj) cdef any_as_fq_default(self, obj) + cdef _set_from_order(self, p, d, var, fq_type=*, check_prime=*) + cdef _set_from_modulus(self, modulus, var, fq_type=*, check_modulus=*) + cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type fq_type=*) cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type fq_type=*) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 92607826..2828e395 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -14,7 +14,7 @@ cdef class fq_default_ctx: Finite fields can be initialized in one of two possible ways. The first is by providing characteristic and degree: - >>> fq_default_ctx(5, 2, 'y', fq_type=1) + >>> fq_default_ctx(5, 2, 'y', fq_type='FQ_ZECH') fq_default_ctx(5, 2, 'y', x^2 + 4*x + 2, 'FQ_ZECH') The second is by giving an irreducible polynomial of type @@ -22,7 +22,7 @@ cdef class fq_default_ctx: >>> from flint import fmpz_mod_poly_ctx >>> mod = fmpz_mod_poly_ctx(11)([1,0,1]) - >>> fq_default_ctx(modulus=mod, fq_type=2) + >>> fq_default_ctx(modulus=mod, fq_type='FQ_NMOD') fq_default_ctx(11, 2, 'x', x^2 + 1, 'FQ_NMOD') For more details, see the documentation of :method:`~.set_from_order` @@ -34,6 +34,7 @@ cdef class fq_default_ctx: def __dealloc__(self): if self._initialized: fq_default_ctx_clear(self.val) + self._initialized = False @staticmethod def _parse_input_fq_type(fq_type): @@ -96,7 +97,7 @@ cdef class fq_default_ctx: if modulus is NotImplemented: raise TypeError("modulus cannot be cast to fmpz_mod_poly") - self.set_from_modulus(modulus, var, fq_type) + self._set_from_modulus(modulus, var, fq_type) return # If there's no modulus and no prime, we can't continue @@ -108,7 +109,7 @@ cdef class fq_default_ctx: degree = 1 # Construct the field from the prime and degree GF(p^d) - self.set_from_order(p, degree, var, fq_type) + self._set_from_order(p, degree, var, fq_type) cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type fq_type=fq_default_type.DEFAULT): @@ -116,7 +117,7 @@ cdef class fq_default_ctx: fq_default_ctx_init_type(self.val, p.val, d, self.var, fq_type) self._initialized = True - def set_from_order(self, p, d, var, + cdef _set_from_order(self, p, d, var, fq_type=fq_default_type.DEFAULT, check_prime=True): """ Construct a context for the finite field GF(p^d). @@ -159,7 +160,7 @@ cdef class fq_default_ctx: raise TypeError(f"modulus must be fmpz_mod_poly or nmod_poly, got {modulus!r}") self._initialized = True - def set_from_modulus(self, modulus, var, + cdef _set_from_modulus(self, modulus, var, fq_type=fq_default_type.DEFAULT, check_modulus=True): """ Construct a context for a finite field from an irreducible polynomial. @@ -191,25 +192,7 @@ cdef class fq_default_ctx: - 2: `fq_default_ctx.FQ_NMOD`: Using `fq_nmod_t`, - 3: `fq_default_ctx.FQ`: Using `fq_t`. """ - return fq_default_ctx_type(self.val) - - @property - def fq_type_str(self): - """ - Return the string implementation of this context. It is one of: - - - `fq_default_ctx.FQ_ZECH`: Using `fq_zech_t`, - - `fq_default_ctx.FQ_NMOD`: Using `fq_nmod_t`, - - `fq_default_ctx.FQ`: Using `fq_t`. - """ - FQ_TYPES = { - 1 : "FQ_ZECH", - 2 : "FQ_NMOD", - 3 : "FQ", - 4 : "NMOD", - 5 : "FMPZ_MOD", - } - return FQ_TYPES[self.fq_type] + return fq_default_type(fq_default_ctx_type(self.val)) def degree(self): """ @@ -355,7 +338,7 @@ cdef class fq_default_ctx: # For small integers we can convert directly if obj < 0 and obj.bit_length() < 31: fq_default_set_si(fq_ele, obj, self.val) - elif obj.bit_length() < 32: + elif obj > 0 and obj.bit_length() < 32: fq_default_set_ui(fq_ele, obj, self.val) # For larger integers we first convert to fmpz else: @@ -447,8 +430,7 @@ cdef class fq_default_ctx: and self.var == other.var and self.prime() == other.prime() and self.modulus() == other.modulus()) - else: - raise TypeError(f"Cannot compare fq_default_ctx with {type(other)}") + return False def __hash__(self): return hash((self.type, self.var, self.prime(), self.modulus())) @@ -460,8 +442,8 @@ cdef class fq_default_ctx: def __repr__(self): if self.degree() == 1: - return f"fq_default_ctx({self.prime()}, var='{self.var.decode()}' type='{self.fq_type_str}')" - return f"fq_default_ctx({self.prime()}, {self.degree()}, '{self.var.decode()}', {self.modulus()!r}, '{self.fq_type_str}')" + return f"fq_default_ctx({self.prime()}, var='{self.var.decode()}' type='{self.fq_type._name_}')" + return f"fq_default_ctx({self.prime()}, {self.degree()}, '{self.var.decode()}', {self.modulus()!r}, '{self.fq_type._name_}')" def __call__(self, val): return fq_default(val, self) @@ -553,7 +535,7 @@ cdef class fq_default(flint_scalar): return f"fq_default({self.to_list(), self.ctx.__repr__()})" def __hash__(self): - return hash((self.to_polynomial(), hash(self.ctx))) + return hash((self.polynomial(), hash(self.ctx))) # ================================================= # Comparisons From 38b6ce184a5dc70b0b33b12a793be896272b96a0 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 18:30:30 +0100 Subject: [PATCH 29/36] change docstrings for the type stuff --- src/flint/types/fq_default.pyx | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 2828e395..5995feb2 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -25,8 +25,8 @@ cdef class fq_default_ctx: >>> fq_default_ctx(modulus=mod, fq_type='FQ_NMOD') fq_default_ctx(11, 2, 'x', x^2 + 1, 'FQ_NMOD') - For more details, see the documentation of :method:`~.set_from_order` - and :method:`~.set_from_modulus`. + For more details, see the documentation of :method:`~._set_from_order` + and :method:`~._set_from_modulus`. """ def __cinit__(self): pass @@ -124,13 +124,8 @@ cdef class fq_default_ctx: `var` is a name for the ring generator of this field over GF(p). - The optional parameter `type` select the implementation. The - possible values are: - - - `fq_default_ctx.DEFAULT`: implementation automatically decided by Flint (default), - - `fq_default_ctx.FQ_ZECH`: Use `fq_zech_t`, - - `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, - - `fq_default_ctx.FQ`: Use `fq_t`. + The optional parameter `type` select the implementation. For more + information about the types available, see :method:`~.fq_type`. """ # c_from_order expects the characteristic to be fmpz type prime = any_as_fmpz(p) @@ -169,13 +164,8 @@ cdef class fq_default_ctx: `var` is a name for the ring generator of this field over the prime field. - The optional parameter `type` select the implementation. The - possible values are: - - - `fq_default_ctx.DEFAULT`: implementation automatically decided by Flint (default), - - `fq_default_ctx.FQ_ZECH`: Use `fq_zech_t`, - - `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, - - `fq_default_ctx.FQ`: Use `fq_t`. + The optional parameter `type` select the implementation. For more + information about the types available, see :method:`~.fq_type`. """ if check_modulus and not modulus.is_irreducible(): raise ValueError("modulus must be irreducible") @@ -188,9 +178,14 @@ cdef class fq_default_ctx: """ Return the implementation of this context. It is one of: - - 1: `fq_default_ctx.FQ_ZECH`: Using `fq_zech_t`, - - 2: `fq_default_ctx.FQ_NMOD`: Using `fq_nmod_t`, - - 3: `fq_default_ctx.FQ`: Using `fq_t`. + - 1. `fq_default_ctx.FQ_ZECH`: Use `fq_zech_t`, + - 2. `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, + - 3. `fq_default_ctx.FQ`: Use `fq_t`. + - 4. `fq_default_ctx.NMOD`: Use `nmod` for degree = 1, + - 5. `fq_default_ctx.FMPZ_MOD`: Use `fmpz_mod` for degree = 1. + + These can be manually selected, or type: `fq_default_ctx.DEFAULT` can be used + for the implementation to be automatically decided by Flint (default), """ return fq_default_type(fq_default_ctx_type(self.val)) From 52f884795af290aa2d5f734f678508169683ca96 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 18:34:09 +0100 Subject: [PATCH 30/36] ensure the modulus matches for scalar coercion --- src/flint/types/fq_default.pyx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 5995feb2..556572c4 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -347,14 +347,12 @@ cdef class fq_default_ctx: return 0 # For nmod we can convert by taking it as an int - # Ignores the modulus of nmod - if typecheck(obj, nmod): + if typecheck(obj, nmod) and self.prime() == obj.modulus(): fq_default_set_ui(fq_ele, (obj).val, self.val) return 0 # For fmpz_mod we can also convert directly - # Assumes that the modulus of the ring matches the context - if typecheck(obj, fmpz_mod): + if typecheck(obj, fmpz_mod) and self.prime() == (obj).ctx.modulus(): fq_default_set_fmpz(fq_ele, (obj).val, self.val) return 0 From 66c54f4c1a1d5a377aa22b4943166dbb3faf77d2 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 18:38:35 +0100 Subject: [PATCH 31/36] use try / except for slong conversion --- src/flint/types/fq_default.pyx | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 556572c4..b5f9cdf3 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -124,7 +124,7 @@ cdef class fq_default_ctx: `var` is a name for the ring generator of this field over GF(p). - The optional parameter `type` select the implementation. For more + The optional parameter `type` select the implementation. For more information about the types available, see :method:`~.fq_type`. """ # c_from_order expects the characteristic to be fmpz type @@ -164,7 +164,7 @@ cdef class fq_default_ctx: `var` is a name for the ring generator of this field over the prime field. - The optional parameter `type` select the implementation. For more + The optional parameter `type` select the implementation. For more information about the types available, see :method:`~.fq_type`. """ if check_modulus and not modulus.is_irreducible(): @@ -329,16 +329,19 @@ cdef class fq_default_ctx: return 0 cdef set_any_scalar_as_fq_default(self, fq_default_t fq_ele, obj): + cdef slong i if typecheck(obj, int): # For small integers we can convert directly - if obj < 0 and obj.bit_length() < 31: - fq_default_set_si(fq_ele, obj, self.val) - elif obj > 0 and obj.bit_length() < 32: - fq_default_set_ui(fq_ele, obj, self.val) - # For larger integers we first convert to fmpz - else: - obj_fmpz = any_as_fmpz(obj) - fq_default_set_fmpz(fq_ele, (obj_fmpz).val, self.val) + try: + i = obj + fq_default_set_si(fq_ele, i, self.val) + return 0 + # For larger integers fall through to conversion to fmpz + except OverflowError: + pass + + obj_fmpz = any_as_fmpz(obj) + fq_default_set_fmpz(fq_ele, (obj_fmpz).val, self.val) return 0 # For fmpz we can also convert directly From 163f7cc0f3eede6ad69ff8b038e1bf1a0c41289d Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 18:40:20 +0100 Subject: [PATCH 32/36] move docstring to class --- src/flint/types/fq_default.pxd | 12 ++++++++++++ src/flint/types/fq_default.pyx | 17 +++++------------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index 044005d8..2bf637bb 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -5,6 +5,18 @@ from flint.flintlib.fq cimport fq_is_primitive, fq_multiplicative_order from flint.types.fmpz cimport fmpz from flint.flint_base.flint_base cimport flint_scalar +""" +Enum for the fq_default context types: + +- 1. `fq_default_ctx.FQ_ZECH`: Use `fq_zech_t`, +- 2. `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, +- 3. `fq_default_ctx.FQ`: Use `fq_t`. +- 4. `fq_default_ctx.NMOD`: Use `nmod` for degree = 1, +- 5. `fq_default_ctx.FMPZ_MOD`: Use `fmpz_mod` for degree = 1. + +These can be manually selected, or type: `fq_default_ctx.DEFAULT` can be used +for the implementation to be automatically decided by Flint (default), +""" cpdef enum fq_default_type: DEFAULT = 0 FQ_ZECH = 1 diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index b5f9cdf3..a68f7708 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -125,7 +125,8 @@ cdef class fq_default_ctx: `var` is a name for the ring generator of this field over GF(p). The optional parameter `type` select the implementation. For more - information about the types available, see :method:`~.fq_type`. + information about the types available, see :class:`~.fq_default_type` + for possible types. """ # c_from_order expects the characteristic to be fmpz type prime = any_as_fmpz(p) @@ -165,7 +166,8 @@ cdef class fq_default_ctx: `var` is a name for the ring generator of this field over the prime field. The optional parameter `type` select the implementation. For more - information about the types available, see :method:`~.fq_type`. + information about the types available, see :class:`~.fq_default_type` + for possible types. """ if check_modulus and not modulus.is_irreducible(): raise ValueError("modulus must be irreducible") @@ -176,16 +178,7 @@ cdef class fq_default_ctx: @property def fq_type(self): """ - Return the implementation of this context. It is one of: - - - 1. `fq_default_ctx.FQ_ZECH`: Use `fq_zech_t`, - - 2. `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, - - 3. `fq_default_ctx.FQ`: Use `fq_t`. - - 4. `fq_default_ctx.NMOD`: Use `nmod` for degree = 1, - - 5. `fq_default_ctx.FMPZ_MOD`: Use `fmpz_mod` for degree = 1. - - These can be manually selected, or type: `fq_default_ctx.DEFAULT` can be used - for the implementation to be automatically decided by Flint (default), + Return the implementation of this context """ return fq_default_type(fq_default_ctx_type(self.val)) From e32a6ddd743ea28eddbd63050a0d04621f2735be Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 18:42:24 +0100 Subject: [PATCH 33/36] refactor out where the dict is for types --- src/flint/types/fq_default.pyx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index a68f7708..637cb410 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -7,6 +7,15 @@ from flint.types.fmpz_mod_poly cimport fmpz_mod_poly, fmpz_mod_poly_ctx from flint.types.nmod_poly cimport nmod_poly from flint.utils.typecheck cimport typecheck +# Allow the type to be denoted by strings or integers +FQ_TYPES = { + "FQ_ZECH" : 1, + "FQ_NMOD" : 2, + "FQ" : 3, + "NMOD" : 4, + "FMPZ_MOD" : 5 +} + cdef class fq_default_ctx: r""" Context object for creating :class:`~.fq_default`. @@ -38,14 +47,6 @@ cdef class fq_default_ctx: @staticmethod def _parse_input_fq_type(fq_type): - # Allow the type to be denoted by strings or integers - FQ_TYPES = { - "FQ_ZECH" : 1, - "FQ_NMOD" : 2, - "FQ" : 3, - "NMOD" : 4, - "FMPZ_MOD" : 5 - } if typecheck(fq_type, str): fq_type = FQ_TYPES.get(fq_type, None) if fq_type is None: From 876fd2ae79d3e1e9344f0375e385590e476bbcb8 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 18:52:53 +0100 Subject: [PATCH 34/36] move docstring --- src/flint/types/fq_default.pxd | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/flint/types/fq_default.pxd b/src/flint/types/fq_default.pxd index 2bf637bb..265cd962 100644 --- a/src/flint/types/fq_default.pxd +++ b/src/flint/types/fq_default.pxd @@ -5,19 +5,19 @@ from flint.flintlib.fq cimport fq_is_primitive, fq_multiplicative_order from flint.types.fmpz cimport fmpz from flint.flint_base.flint_base cimport flint_scalar -""" -Enum for the fq_default context types: - -- 1. `fq_default_ctx.FQ_ZECH`: Use `fq_zech_t`, -- 2. `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, -- 3. `fq_default_ctx.FQ`: Use `fq_t`. -- 4. `fq_default_ctx.NMOD`: Use `nmod` for degree = 1, -- 5. `fq_default_ctx.FMPZ_MOD`: Use `fmpz_mod` for degree = 1. - -These can be manually selected, or type: `fq_default_ctx.DEFAULT` can be used -for the implementation to be automatically decided by Flint (default), -""" cpdef enum fq_default_type: + """ + Enum for the fq_default context types: + + - 1. `fq_default_ctx.FQ_ZECH`: Use `fq_zech_t`, + - 2. `fq_default_ctx.FQ_NMOD`: Use `fq_nmod_t`, + - 3. `fq_default_ctx.FQ`: Use `fq_t`. + - 4. `fq_default_ctx.NMOD`: Use `nmod` for degree = 1, + - 5. `fq_default_ctx.FMPZ_MOD`: Use `fmpz_mod` for degree = 1. + + These can be manually selected, or type: `fq_default_ctx.DEFAULT` can be used + for the implementation to be automatically decided by Flint (default), + """ DEFAULT = 0 FQ_ZECH = 1 FQ_NMOD = 2 From e79b3974854ad5c631b309b5a5796a883680779e Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 18:53:57 +0100 Subject: [PATCH 35/36] add docs --- doc/source/fq_default.rst | 8 ++++++++ doc/source/index.rst | 1 + 2 files changed, 9 insertions(+) create mode 100644 doc/source/fq_default.rst diff --git a/doc/source/fq_default.rst b/doc/source/fq_default.rst new file mode 100644 index 00000000..bea090f9 --- /dev/null +++ b/doc/source/fq_default.rst @@ -0,0 +1,8 @@ +**fq_default** -- finite fields +=============================================================================== + +.. autoclass :: flint.fq_default + :members: + :inherited-members: + :undoc-members: + diff --git a/doc/source/index.rst b/doc/source/index.rst index 8e95e722..71e50360 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -45,6 +45,7 @@ Scalar types fmpq.rst fmpz_mod.rst nmod.rst + fq_default.rst arb.rst acb.rst dirichlet.rst From f789f22124c531968f05ef259d7c98f5391c9c07 Mon Sep 17 00:00:00 2001 From: Giacomo Pope Date: Fri, 9 Aug 2024 21:57:50 +0100 Subject: [PATCH 36/36] check modulus for nmod_poly and fmpz_mod_poly --- src/flint/types/fq_default.pyx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/flint/types/fq_default.pyx b/src/flint/types/fq_default.pyx index 637cb410..4b0a128e 100644 --- a/src/flint/types/fq_default.pyx +++ b/src/flint/types/fq_default.pyx @@ -362,15 +362,11 @@ cdef class fq_default_ctx: if check is not NotImplemented: return 0 - # Assumes that the modulus of the polynomial matches - # the context for the fq_default - if typecheck(obj, fmpz_mod_poly): + if typecheck(obj, fmpz_mod_poly) and self.prime() == (obj).ctx.mod.modulus(): fq_default_set_fmpz_mod_poly(fq_ele, (obj).val, self.val) return 0 - # Assumes that the modulus of the polynomial matches - # the context for the fq_default - if typecheck(obj, nmod_poly): + if typecheck(obj, nmod_poly) and self.prime() == obj.modulus(): fq_default_set_nmod_poly(fq_ele, (obj).val, self.val) return 0