Skip to content

Commit

Permalink
Merge pull request #44 from oscarbenjamin/pr_sympy_integration
Browse files Browse the repository at this point in the history
Add missing operations for fmpz and fmpq
  • Loading branch information
oscarbenjamin authored Aug 8, 2023
2 parents 027dd1f + 2d4cfa9 commit deb4448
Show file tree
Hide file tree
Showing 4 changed files with 465 additions and 58 deletions.
6 changes: 6 additions & 0 deletions src/flint/_flint.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ cdef extern from "flint/fmpz.h":
void fmpz_pow_ui(fmpz_t f, fmpz_t g, ulong exp)
void fmpz_powm_ui(fmpz_t f, fmpz_t g, ulong exp, fmpz_t m)
void fmpz_powm(fmpz_t f, fmpz_t g, fmpz_t e, fmpz_t m)
int fmpz_pow_fmpz(fmpz_t f, const fmpz_t g, const fmpz_t x)
int fmpz_sqrtmod(fmpz_t b, fmpz_t a, fmpz_t p)
void fmpz_sqrt(fmpz_t f, fmpz_t g)
void fmpz_sqrtrem(fmpz_t f, fmpz_t r, fmpz_t g)
Expand Down Expand Up @@ -310,6 +311,10 @@ cdef extern from "flint/fmpz.h":
int fmpz_jacobi(const fmpz_t a, const fmpz_t p)
int fmpz_is_prime(const fmpz_t n)
int fmpz_is_probabprime(const fmpz_t n)
void fmpz_complement(fmpz_t r, const fmpz_t f)
void fmpz_and(fmpz_t r, const fmpz_t a, const fmpz_t b)
void fmpz_or(fmpz_t r, const fmpz_t a, const fmpz_t b)
void fmpz_xor(fmpz_t r, const fmpz_t a, const fmpz_t b)

cdef extern from "flint/fmpz_factor.h":
ctypedef struct fmpz_factor_struct:
Expand Down Expand Up @@ -547,6 +552,7 @@ cdef extern from "flint/fmpq.h":
void fmpq_div(fmpq_t res, fmpq_t op1, fmpq_t op2)
void fmpq_div_fmpz(fmpq_t res, fmpq_t op, fmpz_t x)
int fmpq_mod_fmpz(fmpz_t res, fmpq_t x, fmpz_t mod)
int fmpq_pow_fmpz(fmpq_t a, const fmpq_t b, const fmpz_t e)
int fmpq_reconstruct_fmpz(fmpq_t res, fmpz_t a, fmpz_t m)
int fmpq_reconstruct_fmpz_2(fmpq_t res, fmpz_t a, fmpz_t m, fmpz_t N, fmpz_t D)
mp_bitcnt_t fmpq_height_bits(fmpq_t x)
Expand Down
87 changes: 74 additions & 13 deletions src/flint/fmpq.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ cdef class fmpq(flint_scalar):
p = property(numer)
q = property(denom)

# These are the property names in the numeric tower.
numerator = property(numer)
denominator = property(denom)

def __reduce__(self):
return (fmpq, (int(self.p), int(self.q)))

def repr(self):
if self.q == 1:
return "fmpq(%s)" % self.p
Expand All @@ -122,9 +129,24 @@ cdef class fmpq(flint_scalar):
else:
return "%s/%s" % (self.p.str(**kwargs), self.q.str(**kwargs))

def __int__(self):
return int(self.trunc())

def __floor__(self):
return self.floor()

def __ceil__(self):
return self.ceil()

def __trunc__(self):
return self.trunc()

def __nonzero__(self):
return not fmpq_is_zero(self.val)

def __round__(self, ndigits=None):
return self.round(ndigits)

def __pos__(self):
return self

Expand Down Expand Up @@ -335,6 +357,37 @@ cdef class fmpq(flint_scalar):
fmpz_cdiv_q(r.val, fmpq_numref(self.val), fmpq_denref(self.val))
return r

def trunc(self):
"""
Truncation function.
>>> fmpq(3,2).trunc()
1
>>> fmpq(-3,2).trunc()
-1
"""
cdef fmpz r = fmpz.__new__(fmpz)
fmpz_tdiv_q(r.val, fmpq_numref(self.val), fmpq_denref(self.val))
return r

def round(self, ndigits=None):
"""
Rounding function.
>>> fmpq(3,2).round()
2
>>> fmpq(-3,2).round()
-2
"""
from fractions import Fraction
fself = Fraction(int(self.p), int(self.q))
if ndigits is not None:
fround = round(fself, ndigits)
return fmpq(fround.numerator, fround.denominator)
else:
fround = round(fself)
return fmpz(fround)

def __hash__(self):
from fractions import Fraction
return hash(Fraction(int(self.p), int(self.q), _normalize=False))
Expand All @@ -359,20 +412,28 @@ cdef class fmpq(flint_scalar):
return max(b1, b2)

def __pow__(self, n, z):
cdef fmpz_struct nval[1]
cdef int ntype = FMPZ_UNKNOWN
cdef fmpq v
cdef int success
cdef long e

assert z is None
e = n
if type(self) is fmpq:
v = fmpq.__new__(fmpq)
if e >= 0:
fmpz_pow_ui(fmpq_numref(v.val), fmpq_numref((<fmpq>self).val), e)
fmpz_pow_ui(fmpq_denref(v.val), fmpq_denref((<fmpq>self).val), e)
else:
if fmpq_is_zero((<fmpq>self).val):
raise ZeroDivisionError
fmpz_pow_ui(fmpq_denref(v.val), fmpq_numref((<fmpq>self).val), -e)
fmpz_pow_ui(fmpq_numref(v.val), fmpq_denref((<fmpq>self).val), -e)
return v
return NotImplemented

ntype = fmpz_set_any_ref(nval, n)
if ntype == FMPZ_UNKNOWN:
return NotImplemented

if fmpq_is_zero((<fmpq>self).val) and fmpz_sgn(nval) == -1:
if ntype == FMPZ_TMP: fmpz_clear(nval)
raise ZeroDivisionError

v = fmpq.__new__(fmpq)
success = fmpq_pow_fmpz(v.val, (<fmpq>self).val, nval)

if ntype == FMPZ_TMP: fmpz_clear(nval)

if success:
return v
else:
raise OverflowError("fmpq_pow_fmpz(): exponent too large")
Loading

0 comments on commit deb4448

Please sign in to comment.