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

fix(nmod): Add nmod_ctx to store is_prime #179

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
293ec24
fix(nmod): Add nmod_ctx to store is_prime
oscarbenjamin Aug 6, 2024
27e5e4c
Add nmod_poly_ctx
oscarbenjamin Aug 22, 2024
a88f881
Use nmod contexts for nmod_mat
oscarbenjamin Aug 22, 2024
ba9c1fd
Inline ctx.any_as_nmod for faster nmod.__mul__
oscarbenjamin Aug 22, 2024
8c2221b
Use nmod_ctx consistently in nmod_poly and nmod_mat
oscarbenjamin Aug 24, 2024
affe462
Use cython.no_gc to speed up nmod
oscarbenjamin Aug 24, 2024
6f04cdd
fix: check for non-prime modulus in nmod_poly
oscarbenjamin Aug 26, 2024
23389a5
test: Add nmod_poly with modulus=9 test case
oscarbenjamin Aug 26, 2024
f47188c
Use any_as_nmod rather than ctx.any_as_nmod
oscarbenjamin Aug 26, 2024
154b035
perf: use @cython.final for nmod_ctx.any_as_nmod
oscarbenjamin Aug 26, 2024
82af09e
Add nmod_ctx.new_nmod function
oscarbenjamin Aug 27, 2024
8d69a4e
Add nmod_poly_ctx and nmod_mat_ctx
oscarbenjamin Aug 27, 2024
c454681
Use no_gc for nmod
oscarbenjamin Aug 27, 2024
9062d32
Use setdefault for ctx caches
oscarbenjamin Aug 27, 2024
0fa5d42
pin cython commit for the coverage job
oscarbenjamin Aug 27, 2024
3abe283
Use an earlier Cython commit...
oscarbenjamin Aug 27, 2024
f7d27a5
Use Oscar's cython branch for coverage again
oscarbenjamin Aug 27, 2024
5b16c20
test: add tests for fmpz and fmpz_mat
oscarbenjamin Aug 28, 2024
9b3d7c4
test: add polys tests for div/sqrt
oscarbenjamin Aug 28, 2024
e7c1418
test: handle excluded lines in coverage plugin
oscarbenjamin Aug 28, 2024
0fa1dbf
fmpq: use fmpq_cmp for <,<=,>,>=
oscarbenjamin Aug 28, 2024
b605f97
Full coverage of nmod_poly and various fixes.
oscarbenjamin Aug 28, 2024
ff21556
Test nmod_mat_ctx
oscarbenjamin Aug 28, 2024
c06bc86
Use int(characteristic) for PyPy
oscarbenjamin Aug 28, 2024
3d39267
Use int for PyPy
oscarbenjamin Aug 28, 2024
58f3887
Use Cython master branch again after:
oscarbenjamin Aug 29, 2024
e837d99
Add @cython.no_gc to nmod_poly and nmod_mat
oscarbenjamin Aug 29, 2024
6d14958
Various lint fixes
oscarbenjamin Sep 1, 2024
a9215d0
Lint fixes
oscarbenjamin Sep 2, 2024
b1d5239
refactor: move nmod_ctx cdef methods to .pxd files
oscarbenjamin Sep 3, 2024
f84aad8
Merge remote-tracking branch 'upstream/main' into pr_nmod_ctx
oscarbenjamin Sep 5, 2024
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
Prev Previous commit
Next Next commit
refactor: move nmod_ctx cdef methods to .pxd files
oscarbenjamin committed Sep 3, 2024
commit b1d523994b0cb035fa1923b45d3a1e164657ba4b
75 changes: 69 additions & 6 deletions src/flint/types/nmod.pxd
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
cimport cython

from flint.flint_base.flint_base cimport flint_scalar
from flint.utils.typecheck cimport typecheck

from flint.flintlib.flint cimport mp_limb_t, ulong
from flint.flintlib.nmod cimport nmod_t
from flint.flintlib.nmod cimport nmod_t, nmod_init
from flint.flintlib.ulong_extras cimport n_is_prime

from flint.flintlib.fmpz cimport fmpz_t
from flint.flintlib.fmpq cimport fmpq_mod_fmpz

from flint.flintlib.fmpz cimport (
fmpz_t,
fmpz_fdiv_ui,
fmpz_init,
fmpz_clear,
fmpz_set_ui,
fmpz_get_ui,
)

from flint.types.fmpz cimport fmpz, any_as_fmpz
from flint.types.fmpq cimport fmpq, any_as_fmpq


cdef dict _nmod_ctx_cache


@cython.no_gc
@@ -11,19 +32,61 @@ cdef class nmod_ctx:
cdef bint _is_prime

@staticmethod
cdef nmod_ctx any_as_nmod_ctx(obj)
cdef inline nmod_ctx any_as_nmod_ctx(obj):
"""Convert an ``nmod_ctx`` or ``int`` to an ``nmod_ctx``."""
if typecheck(obj, nmod_ctx):
return obj
if typecheck(obj, int):
return nmod_ctx._get_ctx(obj)
raise TypeError("Invalid context/modulus for nmod: %s" % obj)

@staticmethod
cdef nmod_ctx _get_ctx(int mod)
cdef inline nmod_ctx _get_ctx(int mod):
"""Retrieve an nmod context from the cache or create a new one."""
ctx = _nmod_ctx_cache.get(mod)
if ctx is None:
ctx = _nmod_ctx_cache.setdefault(mod, nmod_ctx._new_ctx(mod))
return ctx

@staticmethod
cdef nmod_ctx _new_ctx(ulong mod)
cdef inline nmod_ctx _new_ctx(ulong mod):
"""Create a new nmod context."""
cdef nmod_ctx ctx = nmod_ctx.__new__(nmod_ctx)
nmod_init(&ctx.mod, mod)
ctx._is_prime = n_is_prime(mod)
return ctx

@cython.final
cdef int any_as_nmod(self, mp_limb_t * val, obj) except -1
cdef inline int any_as_nmod(nmod_ctx ctx, mp_limb_t * val, obj) except -1:
"""Convert an object to an nmod element."""
cdef int success
cdef fmpz_t t
if typecheck(obj, nmod):
if (<nmod>obj).ctx.mod.n != ctx.mod.n:
raise ValueError("cannot coerce integers mod n with different n")
val[0] = (<nmod>obj).val
return 1
z = any_as_fmpz(obj)
if z is not NotImplemented:
val[0] = fmpz_fdiv_ui((<fmpz>z).val, ctx.mod.n)
return 1
q = any_as_fmpq(obj)
if q is not NotImplemented:
fmpz_init(t)
fmpz_set_ui(t, ctx.mod.n)
success = fmpq_mod_fmpz(t, (<fmpq>q).val, t)
val[0] = fmpz_get_ui(t)
fmpz_clear(t)
if not success:
raise ZeroDivisionError("%s does not exist mod %i!" % (q, ctx.mod.n))
return 1
return 0

@cython.final
cdef nmod new_nmod(self)
cdef inline nmod new_nmod(self):
cdef nmod r = nmod.__new__(nmod)
r.ctx = self
return r


@cython.no_gc
67 changes: 2 additions & 65 deletions src/flint/types/nmod.pyx
Original file line number Diff line number Diff line change
@@ -2,24 +2,18 @@ cimport cython

from flint.flint_base.flint_base cimport flint_scalar
from flint.utils.typecheck cimport typecheck
from flint.types.fmpq cimport any_as_fmpq
from flint.types.fmpz cimport any_as_fmpz
from flint.types.fmpz cimport fmpz
from flint.types.fmpq cimport fmpq

from flint.flintlib.flint cimport ulong
from flint.flintlib.fmpz cimport fmpz_t
from flint.flintlib.nmod cimport nmod_pow_fmpz
from flint.flintlib.nmod_vec cimport *
from flint.flintlib.fmpz cimport fmpz_fdiv_ui, fmpz_init, fmpz_clear
from flint.flintlib.fmpz cimport fmpz_set_ui, fmpz_get_ui
from flint.flintlib.fmpq cimport fmpq_mod_fmpz
from flint.flintlib.ulong_extras cimport n_gcdinv, n_is_prime, n_sqrtmod
from flint.flintlib.ulong_extras cimport n_gcdinv, n_sqrtmod

from flint.utils.flint_exceptions import DomainError


cdef dict _nmod_ctx_cache = {}
_nmod_ctx_cache = {}


@cython.no_gc
@@ -48,63 +42,6 @@ cdef class nmod_ctx:
"""Get an nmod context with modulus ``mod``."""
return nmod_ctx.any_as_nmod_ctx(mod)

@staticmethod
cdef nmod_ctx any_as_nmod_ctx(obj):
"""Convert an ``nmod_ctx`` or ``int`` to an ``nmod_ctx``."""
if typecheck(obj, nmod_ctx):
return obj
if typecheck(obj, int):
return nmod_ctx._get_ctx(obj)
raise TypeError("Invalid context/modulus for nmod: %s" % obj)

@staticmethod
cdef nmod_ctx _get_ctx(int mod):
"""Retrieve an nmod context from the cache or create a new one."""
ctx = _nmod_ctx_cache.get(mod)
if ctx is None:
ctx = _nmod_ctx_cache.setdefault(mod, nmod_ctx._new_ctx(mod))
return ctx

@staticmethod
cdef nmod_ctx _new_ctx(ulong mod):
"""Create a new nmod context."""
cdef nmod_ctx ctx = nmod_ctx.__new__(nmod_ctx)
nmod_init(&ctx.mod, mod)
ctx._is_prime = n_is_prime(mod)
return ctx

@cython.final
cdef int any_as_nmod(nmod_ctx ctx, mp_limb_t * val, obj) except -1:
"""Convert an object to an nmod element."""
cdef int success
cdef fmpz_t t
if typecheck(obj, nmod):
if (<nmod>obj).ctx.mod.n != ctx.mod.n:
raise ValueError("cannot coerce integers mod n with different n")
val[0] = (<nmod>obj).val
return 1
z = any_as_fmpz(obj)
if z is not NotImplemented:
val[0] = fmpz_fdiv_ui((<fmpz>z).val, ctx.mod.n)
return 1
q = any_as_fmpq(obj)
if q is not NotImplemented:
fmpz_init(t)
fmpz_set_ui(t, ctx.mod.n)
success = fmpq_mod_fmpz(t, (<fmpq>q).val, t)
val[0] = fmpz_get_ui(t)
fmpz_clear(t)
if not success:
raise ZeroDivisionError("%s does not exist mod %i!" % (q, ctx.mod.n))
return 1
return 0

@cython.final
cdef nmod new_nmod(self):
cdef nmod r = nmod.__new__(nmod)
r.ctx = self
return r

def modulus(self):
"""Get the modulus of the context.

94 changes: 82 additions & 12 deletions src/flint/types/nmod_mat.pxd
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
cimport cython

from flint.utils.typecheck cimport typecheck
from flint.flint_base.flint_base cimport flint_mat

from flint.flintlib.nmod cimport nmod_t
from flint.flintlib.nmod_mat cimport nmod_mat_t
from flint.flintlib.flint cimport mp_limb_t, ulong

from flint.flintlib.fmpz_mat cimport (
fmpz_mat_nrows,
fmpz_mat_ncols,
fmpz_mat_get_nmod_mat,
)
from flint.flintlib.nmod cimport nmod_t
from flint.flintlib.nmod_mat cimport (
nmod_mat_t,
nmod_mat_init,
nmod_mat_init_set,
)

from flint.types.fmpz cimport fmpz
from flint.types.fmpz_mat cimport fmpz_mat, any_as_fmpz_mat
from flint.types.nmod cimport nmod_ctx, nmod
from flint.types.nmod_poly cimport nmod_poly_ctx, nmod_poly


cdef dict _nmod_mat_ctx_cache


@cython.no_gc
cdef class nmod_mat_ctx:
cdef nmod_t mod
@@ -18,31 +33,86 @@ cdef class nmod_mat_ctx:
cdef nmod_poly_ctx poly_ctx

@staticmethod
cdef nmod_mat_ctx any_as_nmod_mat_ctx(obj)
cdef inline nmod_mat_ctx any_as_nmod_mat_ctx(obj):
"""Convert an ``nmod_mat_ctx`` or ``int`` to an ``nmod_mat_ctx``."""
if typecheck(obj, nmod_mat_ctx):
return obj
if typecheck(obj, int):
return nmod_mat_ctx._get_ctx(obj)
elif typecheck(obj, fmpz):
return nmod_mat_ctx._get_ctx(int(obj))
raise TypeError("nmod_mat: expected last argument to be an nmod_mat_ctx or an integer")

@staticmethod
cdef nmod_mat_ctx _get_ctx(int mod)
cdef inline nmod_mat_ctx _get_ctx(int mod):
"""Retrieve an nmod_mat context from the cache or create a new one."""
ctx = _nmod_mat_ctx_cache.get(mod)
if ctx is None:
ctx = _nmod_mat_ctx_cache.setdefault(mod, nmod_mat_ctx._new_ctx(mod))
return ctx

@staticmethod
cdef nmod_mat_ctx _new_ctx(ulong mod)
cdef inline nmod_mat_ctx _new_ctx(ulong mod):
"""Create a new nmod_mat context."""
cdef nmod_ctx scalar_ctx
cdef nmod_poly_ctx poly_ctx
cdef nmod_mat_ctx ctx

poly_ctx = nmod_poly_ctx.new(mod)
scalar_ctx = poly_ctx.scalar_ctx

ctx = nmod_mat_ctx.__new__(nmod_mat_ctx)
ctx.mod = scalar_ctx.mod
ctx._is_prime = scalar_ctx._is_prime
ctx.scalar_ctx = scalar_ctx
ctx.poly_ctx = poly_ctx

return ctx

@cython.final
cdef int any_as_nmod(self, mp_limb_t * val, obj) except -1
cdef inline int any_as_nmod(self, mp_limb_t * val, obj) except -1:
return self.scalar_ctx.any_as_nmod(val, obj)

@cython.final
cdef any_as_nmod_mat(self, obj)
cdef inline any_as_nmod_mat(self, obj):
"""Convert obj to nmod_mat or return NotImplemented."""
cdef nmod_mat r

if typecheck(obj, nmod_mat):
return obj

x = any_as_fmpz_mat(obj)
if x is not NotImplemented:
r = self.new_nmod_mat(fmpz_mat_nrows((<fmpz_mat>x).val),
fmpz_mat_ncols((<fmpz_mat>x).val))
fmpz_mat_get_nmod_mat(r.val, (<fmpz_mat>x).val)
return r

return NotImplemented

@cython.final
cdef nmod new_nmod(self)
cdef inline nmod new_nmod(self):
return self.scalar_ctx.new_nmod()

@cython.final
cdef nmod_poly new_nmod_poly(self)
cdef inline nmod_poly new_nmod_poly(self):
return self.poly_ctx.new_nmod_poly()

@cython.final
cdef nmod_mat new_nmod_mat(self, ulong m, ulong n)
cdef inline nmod_mat new_nmod_mat(self, ulong m, ulong n):
"""New initialized nmod_mat of size m x n with context ctx."""
cdef nmod_mat r = nmod_mat.__new__(nmod_mat)
nmod_mat_init(r.val, m, n, self.mod.n)
r.ctx = self
return r

@cython.final
cdef nmod_mat new_nmod_mat_copy(self, nmod_mat other)
cdef inline nmod_mat new_nmod_mat_copy(self, nmod_mat other):
"""New copy of nmod_mat other."""
cdef nmod_mat r = nmod_mat.__new__(nmod_mat)
nmod_mat_init_set(r.val, other.val)
r.ctx = other.ctx
return r


@cython.no_gc
Loading