Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Directly initialize fmpz from a python int. #64

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/flint/flintlib/flint.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ cdef extern from "gmp.h":
ctypedef mp_limb_t* mp_ptr
ctypedef mp_limb_t* mp_srcptr
ctypedef unsigned long mp_bitcnt_t
ctypedef struct __mpz_struct:
pass
ctypedef __mpz_struct mpz_t[1]
void mpz_init(mpz_t)
void mpz_import(mpz_t val, size_t count, int order, size_t size, int endian, size_t nails, const void * op)
void mpz_clear(mpz_t val)
void mpz_neg(mpz_t rop, mpz_t op)
size_t mpz_sizeinbase (const mpz_t op, int base)
void * mpz_export (void *rop, size_t *countp, int order, size_t size, int endian, size_t nails, const mpz_t op)

cdef extern from "flint/fmpz.h":
ctypedef long slong
Expand Down
12 changes: 6 additions & 6 deletions src/flint/flintlib/fmpz.pxd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from flint.flintlib.flint cimport fmpz_struct, ulong, mp_limb_t, mp_ptr
from flint.flintlib.flint cimport fmpz_struct, ulong, mp_limb_t, mp_ptr, __mpz_struct
from flint.flintlib.flint cimport mp_size_t, mp_bitcnt_t, slong, flint_rand_t, flint_bitcnt_t

cdef extern from "flint/fmpz.h":
Expand All @@ -11,15 +11,15 @@ cdef extern from "flint/fmpz.h":
ctypedef fmpz_preinvn_struct fmpz_preinvn_t[1]

# from here on is parsed
# fmpz_struct PTR_TO_COEFF(__mpz_struct * ptr)
# __mpz_struct * COEFF_TO_PTR(fmpz_struct f)
fmpz_struct PTR_TO_COEFF(__mpz_struct * ptr)
__mpz_struct * COEFF_TO_PTR(fmpz_struct f)
int COEFF_IS_MPZ(fmpz_struct f)
# __mpz_struct * _fmpz_new_mpz(void)
__mpz_struct * _fmpz_new_mpz()
void _fmpz_clear_mpz(fmpz_struct f)
void _fmpz_cleanup_mpz_content()
void _fmpz_cleanup()
# __mpz_struct * _fmpz_promote(fmpz_t f)
# __mpz_struct * _fmpz_promote_val(fmpz_t f)
__mpz_struct * _fmpz_promote(fmpz_t f)
__mpz_struct * _fmpz_promote_val(fmpz_t f)
void _fmpz_demote(fmpz_t f)
void _fmpz_demote_val(fmpz_t f)
void fmpz_init(fmpz_t f)
Expand Down
22 changes: 4 additions & 18 deletions src/flint/types/fmpz.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,10 @@ from cpython.version cimport PY_MAJOR_VERSION
cdef int fmpz_set_any_ref(fmpz_t x, obj)
cdef fmpz_get_intlong(fmpz_t x)

cdef inline int fmpz_set_pylong(fmpz_t x, obj):
cdef int overflow
cdef slong longval
longval = pylong_as_slong(<PyObject*>obj, &overflow)
if overflow:
s = "%x" % obj
fmpz_set_str(x, chars_from_str(s), 16)
else:
fmpz_set_si(x, longval)

cdef inline int fmpz_set_python(fmpz_t x, obj):
if PY_MAJOR_VERSION < 3 and PyInt_Check(obj):
fmpz_set_si(x, PyInt_AS_LONG(obj))
return 1
if PyLong_Check(obj):
fmpz_set_pylong(x, obj)
return 1
return 0
cdef int fmpz_set_pylong(fmpz_t x, obj)

cdef int fmpz_set_python(fmpz_t x, obj)

cdef any_as_fmpz(obj)

cdef class fmpz(flint_scalar):
Expand Down
67 changes: 63 additions & 4 deletions src/flint/types/fmpz.pyx
Original file line number Diff line number Diff line change
@@ -1,26 +1,85 @@
from cpython.version cimport PY_MAJOR_VERSION


from flint.flint_base.flint_base cimport flint_scalar
from flint.utils.typecheck cimport typecheck
from flint.utils.conversion cimport chars_from_str
from flint.utils.conversion cimport str_from_chars, _str_trunc
cimport libc.stdlib

from cpython.object cimport Py_SIZE
from cpython.int cimport PyInt_FromLong
from cpython.long cimport PyLong_FromLong
from cpython.longintrepr cimport _PyLong_New, py_long, digit, PyLong_SHIFT

from flint.flintlib.flint cimport FMPZ_REF, FMPZ_TMP, FMPZ_UNKNOWN
from flint.flintlib.flint cimport __mpz_struct, mpz_import, mpz_neg
from flint.flintlib.flint cimport mpz_sizeinbase, mpz_export
from flint.flintlib.fmpz cimport *
from flint.flintlib.fmpz_factor cimport *
from flint.flintlib.arith cimport *
from flint.flintlib.partitions cimport *

cdef extern from *:
"""
/* Compatibility for python 3.8, can be removed later */
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE)
static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
{ ob->ob_size = size; }
#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size)
#endif
"""
void Py_SET_SIZE(object, Py_ssize_t)

# Unused bits in every PyLong digit
cdef size_t PyLong_nails = 8*sizeof(digit) - PyLong_SHIFT
cdef inline int fmpz_set_pylong(fmpz_t x, obj):
cdef Py_ssize_t length
cdef __mpz_struct* mpz_val
cdef bint negative
cdef int overflow
cdef slong longval
longval = pylong_as_slong(<PyObject*>obj, &overflow)
if overflow:
length = Py_SIZE(obj)
mpz_val = _fmpz_promote(x)
negative = False
if length < 0:
negative = True
length = -length
mpz_import(mpz_val, length, -1, sizeof(digit),0,
PyLong_nails, (<py_long>obj).ob_digit)
if negative:
mpz_neg(mpz_val, mpz_val)
_fmpz_demote_val(x)
else:
fmpz_set_si(x, longval)

cdef inline int fmpz_set_python(fmpz_t x, obj):
if PY_MAJOR_VERSION < 3 and PyInt_Check(obj):
fmpz_set_si(x, PyInt_AS_LONG(obj))
return 1
if PyLong_Check(obj):
fmpz_set_pylong(x, obj)
return 1
return 0

cdef fmpz_get_intlong(fmpz_t x):
"""
Convert fmpz_t to a Python int or long.
"""
cdef char * s
cdef size_t nbits
cdef size_t pylong_size
cdef __mpz_struct * z
if COEFF_IS_MPZ(x[0]):
s = fmpz_get_str(NULL, 16, x)
v = int(str_from_chars(s), 16)
libc.stdlib.free(s)
z = _fmpz_promote_val(x)
nbits = mpz_sizeinbase(z, 2)
pylong_size = (nbits + PyLong_SHIFT -1) // PyLong_SHIFT
v = _PyLong_New(pylong_size)
mpz_export(v.ob_digit, NULL, -1, sizeof(digit), 0, PyLong_nails, z)
_fmpz_demote_val(x)
if fmpz_sgn(x) < 0:
Py_SET_SIZE(v, -pylong_size)
return v
else:
return <slong>x[0]
Expand Down
Loading