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

Add fmpz mod #83

Merged
merged 33 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5a84520
Add new type to package
GiacomoPope Sep 14, 2023
9fbe93a
Include additional struct
GiacomoPope Sep 14, 2023
12a87ea
Tidy up
GiacomoPope Sep 14, 2023
b7b3df3
Level 0 functions for fmpz_mod
GiacomoPope Sep 14, 2023
548107a
Start working on context for fmpz_mod
GiacomoPope Sep 14, 2023
7e7dc87
Small progress
GiacomoPope Sep 14, 2023
59cfb05
clean up context
GiacomoPope Sep 14, 2023
0ecf9a0
Got initalisation somewhat working
GiacomoPope Sep 14, 2023
bd09992
Add ability to create type from context
GiacomoPope Sep 14, 2023
06f00d1
Add fmpz_mod tests
GiacomoPope Sep 14, 2023
9f01093
Add comparisons and start arithmetic
GiacomoPope Sep 14, 2023
6f58268
Modify comparison tests following feedback
GiacomoPope Sep 14, 2023
f32fdfa
allow other types in addition
GiacomoPope Sep 14, 2023
79db695
update tests
GiacomoPope Sep 14, 2023
717acf4
add test to ensure correct error for mismatched moduli
GiacomoPope Sep 14, 2023
7a8f7e5
First draft of fmpz_mod
GiacomoPope Sep 15, 2023
514f3b0
Update tests
GiacomoPope Sep 15, 2023
91615a2
Avoid call to modulus
GiacomoPope Sep 15, 2023
356ec25
Include additional tests
GiacomoPope Sep 15, 2023
70a1f57
Modify code based on feedback and attempt to simplify code
GiacomoPope Sep 15, 2023
cd73cf8
increase coverage of fmpz_mod tests
GiacomoPope Sep 15, 2023
3e79dc7
Small changes based off feedback from PR
GiacomoPope Sep 15, 2023
2e433ca
Remove function in favour for import
GiacomoPope Sep 15, 2023
f96f3c3
Get to 99% coverage
GiacomoPope Sep 15, 2023
952159f
Various changes thanks to PR feedback
GiacomoPope Sep 15, 2023
6244dc2
Modify cinit and init
GiacomoPope Sep 15, 2023
42d44ad
Add doctests and rst for fmpz_mod
GiacomoPope Sep 15, 2023
1e7332f
fix doc issues
GiacomoPope Sep 15, 2023
5e09ff1
add sphinx links to docstrings
GiacomoPope Sep 15, 2023
db0c86b
Add missing export
GiacomoPope Sep 15, 2023
b2dfc43
Fix latex in docstring
GiacomoPope Sep 15, 2023
ea30b64
Remove unneeded docstring
GiacomoPope Sep 15, 2023
5dead0c
Make function cdef
GiacomoPope Sep 15, 2023
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
13 changes: 13 additions & 0 deletions doc/source/fmpz_mod.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
**fmpz_mod** -- integers mod n
===============================================================================
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should say fmpz_mod.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!!


.. autoclass :: flint.fmpz_mod_ctx
:members:
:inherited-members:
:undoc-members:

.. autoclass :: flint.fmpz_mod
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fmpz_mod_ctx class also needs to be documented here.

:members:
:inherited-members:
:undoc-members:

2 changes: 0 additions & 2 deletions doc/source/general.rst
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,6 @@ determined from the available data.
The following convenience functions are provided for numerical evaluation
with adaptive working precision.

.. autofunction :: flint.good

.. autofunction :: flint.showgood

Power series
Expand Down
1 change: 1 addition & 0 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Scalar types

fmpz.rst
fmpq.rst
fmpz_mod.rst
nmod.rst
arb.rst
acb.rst
Expand Down
2 changes: 1 addition & 1 deletion doc/source/nmod.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
**nmod** -- integers mod n
**nmod** -- integers mod wordsize n
===============================================================================

.. autoclass :: flint.nmod
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
("flint.types.acb_mat", ["src/flint/types/acb_mat.pyx"]),
("flint.types.acb_series", ["src/flint/types/acb_series.pyx"]),
("flint.types.fmpz_mpoly", ["src/flint/types/fmpz_mpoly.pyx"]),
("flint.types.fmpz_mod", ["src/flint/types/fmpz_mod.pyx"]),
("flint.types.dirichlet", ["src/flint/types/dirichlet.pyx"]),
("flint.flint_base.flint_base", ["src/flint/flint_base/flint_base.pyx"]),
("flint.flint_base.flint_context", ["src/flint/flint_base/flint_context.pyx"]),
Expand Down
2 changes: 2 additions & 0 deletions src/flint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
from .types.acb_mat import *
from .types.acb_series import *
from .types.fmpz_mpoly import *
from .types.fmpz_mod import *
from .types.dirichlet import *
from .functions.showgood import showgood

__version__ = '0.4.4'
9 changes: 6 additions & 3 deletions src/flint/flintlib/fmpz.pxd
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from flint.flintlib.flint cimport fmpz_struct, ulong, mp_limb_t
from flint.flintlib.flint cimport fmpz_struct, ulong, mp_limb_t, mp_ptr
from flint.flintlib.flint cimport mp_size_t, mp_bitcnt_t, slong, flint_rand_t, flint_bitcnt_t
# from flint.flintlib.nmod cimport nmod_t
# from flint.flintlib.fmpz_factor cimport fmpz_factor_t

cdef extern from "flint/fmpz.h":
ctypedef fmpz_struct fmpz_t[1]

ctypedef struct fmpz_preinvn_struct:
mp_ptr dinv
slong n
flint_bitcnt_t norm
ctypedef fmpz_preinvn_struct fmpz_preinvn_t[1]

# from here on is parsed
# fmpz_struct PTR_TO_COEFF(__mpz_struct * ptr)
Expand Down
45 changes: 45 additions & 0 deletions src/flint/flintlib/fmpz_mod.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from flint.flintlib.flint cimport ulong, slong
from flint.flintlib.fmpz cimport fmpz_t, fmpz_preinvn_struct
from flint.flintlib.nmod cimport nmod_t

# unimported types {'fmpz_mod_discrete_log_pohlig_hellman_t'}

cdef extern from "flint/fmpz_mod.h":
ctypedef struct fmpz_mod_ctx_struct:
fmpz_t n
nmod_t mod
ulong n_limbs[3]
ulong ninv_limbs[3]
fmpz_preinvn_struct * ninv_huge
ctypedef fmpz_mod_ctx_struct fmpz_mod_ctx_t[1]

# Parsed from here
void fmpz_mod_ctx_init(fmpz_mod_ctx_t ctx, const fmpz_t n)
void fmpz_mod_ctx_clear(fmpz_mod_ctx_t ctx)
void fmpz_mod_ctx_set_modulus(fmpz_mod_ctx_t ctx, const fmpz_t n)
void fmpz_mod_set_fmpz(fmpz_t a, const fmpz_t b, const fmpz_mod_ctx_t ctx)
int fmpz_mod_is_canonical(const fmpz_t a, const fmpz_mod_ctx_t ctx)
int fmpz_mod_is_one(const fmpz_t a, const fmpz_mod_ctx_t ctx)
void fmpz_mod_add(fmpz_t a, const fmpz_t b, const fmpz_t c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_add_fmpz(fmpz_t a, const fmpz_t b, const fmpz_t c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_add_ui(fmpz_t a, const fmpz_t b, ulong c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_add_si(fmpz_t a, const fmpz_t b, slong c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_sub(fmpz_t a, const fmpz_t b, const fmpz_t c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_sub_fmpz(fmpz_t a, const fmpz_t b, const fmpz_t c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_sub_ui(fmpz_t a, const fmpz_t b, ulong c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_sub_si(fmpz_t a, const fmpz_t b, slong c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_fmpz_sub(fmpz_t a, const fmpz_t b, const fmpz_t c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_ui_sub(fmpz_t a, ulong b, const fmpz_t c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_si_sub(fmpz_t a, slong b, const fmpz_t c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_neg(fmpz_t a, const fmpz_t b, const fmpz_mod_ctx_t ctx)
void fmpz_mod_mul(fmpz_t a, const fmpz_t b, const fmpz_t c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_inv(fmpz_t a, const fmpz_t b, const fmpz_mod_ctx_t ctx)
int fmpz_mod_divides(fmpz_t a, const fmpz_t b, const fmpz_t c, const fmpz_mod_ctx_t ctx)
void fmpz_mod_pow_ui(fmpz_t a, const fmpz_t b, ulong e, const fmpz_mod_ctx_t ctx)
int fmpz_mod_pow_fmpz(fmpz_t a, const fmpz_t b, const fmpz_t e, const fmpz_mod_ctx_t ctx)
# void fmpz_mod_discrete_log_pohlig_hellman_init(fmpz_mod_discrete_log_pohlig_hellman_t L)
# void fmpz_mod_discrete_log_pohlig_hellman_clear(fmpz_mod_discrete_log_pohlig_hellman_t L)
# double fmpz_mod_discrete_log_pohlig_hellman_precompute_prime(fmpz_mod_discrete_log_pohlig_hellman_t L, const fmpz_t p)
# const fmpz_struct * fmpz_mod_discrete_log_pohlig_hellman_primitive_root(const fmpz_mod_discrete_log_pohlig_hellman_t L)
# void fmpz_mod_discrete_log_pohlig_hellman_run(fmpz_t x, const fmpz_mod_discrete_log_pohlig_hellman_t L, const fmpz_t y)
int fmpz_next_smooth_prime(fmpz_t a, const fmpz_t b)
187 changes: 187 additions & 0 deletions src/flint/test/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1584,6 +1584,192 @@ def test_pickling():
obj2 = pickle.loads(s)
assert obj == obj2

def test_fmpz_mod():
from flint import fmpz_mod_ctx, fmpz, fmpz_mod

p_sml = 163
p_med = 2**127 - 1
p_big = 2**255 - 19

F_sml = fmpz_mod_ctx(p_sml)
F_med = fmpz_mod_ctx(p_med)
F_big = fmpz_mod_ctx(p_big)

# Context tests
assert raises(lambda: fmpz_mod_ctx("AAA"), TypeError)
assert raises(lambda: fmpz_mod_ctx(-1), ValueError)
assert F_sml.modulus() == p_sml
assert F_med.modulus() == p_med
assert F_big.modulus() == p_big

F_big_copy = fmpz_mod_ctx(p_big)
assert F_big_copy == F_big
assert F_big != F_sml
assert hash(F_big_copy) == hash(F_big)
assert hash(F_big) != hash(F_sml)
assert F_big_copy != F_sml
assert F_big_copy != "A"

assert repr(F_sml) == "fmpz_mod_ctx(163)"
assert str(F_sml) == "Context for fmpz_mod with modulus: 163"

# Type tests
assert raises(lambda: fmpz_mod(1, "AAA"), TypeError)

# Test for small, medium and large char.
for F_test in [F_sml, F_med, F_big]:
test_mod = int(F_test.modulus())
test_x = (-123) % test_mod # canonical value
test_y = ((-456) % test_mod)**2 # non-canoncial value

F_test_copy = fmpz_mod_ctx(test_mod)
F_other = fmpz_mod_ctx(11)

assert raises(lambda: F_test(test_x) > 0, TypeError)
assert raises(lambda: F_test(test_x) >= 0, TypeError)
assert raises(lambda: F_test(test_x) < 0, TypeError)
assert raises(lambda: F_test(test_x) <= 0, TypeError)

assert (test_x == F_test(test_x)) is True, f"{test_x}, {F_test(test_x)}"
assert (124 != F_test(test_x)) is True
assert (F_test(test_x) == test_x) is True
assert (F_test(test_x) == test_x + test_mod) is True
assert (F_test(test_x) == 1) is False
assert (F_test(test_x) != 1) is True
assert (F_test(test_x) == F_test(test_x)) is True
assert (F_test(test_x) == F_test(test_x + test_mod)) is True
assert (F_test(test_x) == F_test(1)) is False
assert (F_test(test_x) != F_test(1)) is True

assert (hash(F_test(test_x)) == hash(test_x)) is True
assert (hash(F_test(F_test(test_x))) == hash(test_x)) is True
assert (hash(F_test(test_x)) == hash(1)) is False
assert (hash(F_test(test_x)) != hash(1)) is True
assert (hash(F_test(test_x)) == hash(F_test(test_x))) is True
assert (hash(F_test(test_x)) == hash(F_test(test_x + test_mod))) is True
assert (hash(F_test(test_x)) == hash(F_test(1))) is False
assert (hash(F_test(test_x)) != hash(F_test(1))) is True

# Is one, zero
assert (F_test(0) == 0) is True
assert F_test(0).is_zero() is True
assert not F_test(0)
assert not F_test(test_mod)
assert F_test(1).is_one() is True
assert F_test(test_mod + 1).is_one() is True
assert F_test(1).is_one() is True
assert F_test(2).is_one() is False

# int, str, repr
assert str(F_test(11)) == "11"
assert str(F_test(-1)) == str(test_mod - 1)
assert repr(F_test(11)) == f"fmpz_mod(11, {test_mod})"
assert repr(F_test(-1)) == f"fmpz_mod({test_mod - 1}, {test_mod})"

assert +F_test(5) == F_test(5)

# Arithmetic tests

# Negation
assert -F_test(test_x) == F_test(-test_x) == (-test_x % test_mod)
assert -F_test(1) == F_test(-1) == F_test(test_mod - 1)

# Addition
assert F_test(test_x) + F_test(test_y) == F_test(test_x + test_y)
assert F_test(test_x) + F_test_copy(test_y) == F_test(test_x + test_y)
assert F_test(test_x) + F_test(test_y) == F_test_copy(test_x + test_y)
assert raises(lambda: F_test(test_x) + "AAA", TypeError)

assert F_test(test_x) + F_test(test_y) == F_test(test_y) + F_test(test_x)
assert F_test(test_x) + test_y == F_test(test_x + test_y)
assert test_y + F_test(test_x) == F_test(test_x + test_y)
assert F_test(test_x) + fmpz(test_y) == F_test(test_y) + F_test(test_x)
assert raises(lambda: F_test(test_x) + F_other(test_y), ValueError)

# Subtraction

assert F_test(test_x) - F_test(test_y) == F_test(test_x - test_y)
assert F_test(test_x) - test_y == F_test(test_x - test_y)
assert F_test(test_x) - test_y == F_test(test_x) - F_test(test_y)
assert F_test(test_y) - test_x == F_test(test_y) - F_test(test_x)
assert test_x - F_test(test_y) == F_test(test_x) - F_test(test_y)
assert test_y - F_test(test_x) == F_test(test_y) - F_test(test_x)
assert F_test(test_x) - fmpz(test_y) == F_test(test_x) - F_test(test_y)
assert raises(lambda: F_test(test_x) - F_other(test_y), ValueError)
assert raises(lambda: F_test(test_x) - "AAA", TypeError)

# Multiplication

assert F_test(test_x) * F_test(test_y) == (test_x * test_y) % test_mod
assert F_test(test_x) * test_y == (test_x * test_y) % test_mod
assert test_y * F_test(test_x) == (test_x * test_y) % test_mod

assert F_test(1) * F_test(test_x) == F_test(1 * test_x)
assert F_test(2) * F_test(test_x) == F_test(2 * test_x)
assert F_test(3) * F_test(test_x) == F_test(3 * test_x)
assert 1 * F_test(test_x) == F_test(1 * test_x)
assert 2 * F_test(test_x) == F_test(2 * test_x)
assert 3 * F_test(test_x) == F_test(3 * test_x)
assert F_test(test_x) * 1 == F_test(1 * test_x)
assert F_test(test_x) * 2 == F_test(2 * test_x)
assert F_test(test_x) * 3 == F_test(3 * test_x)
assert fmpz(1) * F_test(test_x) == F_test(1 * test_x)
assert fmpz(2) * F_test(test_x) == F_test(2 * test_x)
assert fmpz(3) * F_test(test_x) == F_test(3 * test_x)
assert raises(lambda: F_test(test_x) * "AAA", TypeError)
assert raises(lambda: F_test(test_x) * F_other(test_x), ValueError)

# Exponentiation

assert F_test(0)**0 == pow(0, 0, test_mod)
assert F_test(0)**1 == pow(0, 1, test_mod)
assert F_test(0)**2 == pow(0, 2, test_mod)
assert raises(lambda: F_test(0)**(-1), ZeroDivisionError)
assert raises(lambda: F_test(0)**("AA"), NotImplementedError)

assert F_test(test_x)**fmpz(0) == pow(test_x, 0, test_mod)
assert F_test(test_x)**fmpz(1) == pow(test_x, 1, test_mod)
assert F_test(test_x)**fmpz(2) == pow(test_x, 2, test_mod)
assert F_test(test_x)**fmpz(3) == pow(test_x, 3, test_mod)

assert F_test(test_x)**0 == pow(test_x, 0, test_mod)
assert F_test(test_x)**1 == pow(test_x, 1, test_mod)
assert F_test(test_x)**2 == pow(test_x, 2, test_mod)
assert F_test(test_x)**3 == pow(test_x, 3, test_mod)
assert F_test(test_x)**100 == pow(test_x, 100, test_mod)

assert F_test(test_x)**(-1) == pow(test_x, -1, test_mod)
assert F_test(test_x)**(-2) == pow(test_x, -2, test_mod)
assert F_test(test_x)**(-3) == pow(test_x, -3, test_mod)
assert F_test(test_x)**(-4) == pow(test_x, -4, test_mod)

# Inversion

assert raises(lambda: ~F_test(0), ZeroDivisionError)
assert ~F_test(test_x) == pow(test_x, -1, test_mod)
assert ~F_test(1) == pow(1, -1, test_mod)
assert ~F_test(2) == pow(2, -1, test_mod), f"Broken!! {~F_test(2)}, {pow(2, -1, test_mod)}"

assert F_test(1).inverse(check=False) == pow(1, -1, test_mod)
assert F_test(2).inverse(check=False) == pow(2, -1, test_mod)
assert F_test(test_x).inverse(check=False) == pow(test_x, -1, test_mod)

# Division
assert raises(lambda: F_test(1) / F_test(0), ZeroDivisionError)
assert F_test(test_x) / F_test(test_y) == (test_x * pow(test_y, -1, test_mod)) % test_mod
assert F_test(test_x) / fmpz(test_y) == (test_x * pow(test_y, -1, test_mod)) % test_mod
assert F_test(test_x) / test_y == (test_x * pow(test_y, -1, test_mod)) % test_mod
assert raises(lambda: F_test(test_x) / "AAA", TypeError)
assert raises(lambda: "AAA" / F_test(test_x), TypeError)
assert raises(lambda: F_other(test_x) / F_test(test_x), ValueError)
assert raises(lambda: F_test(test_x) // F_test(test_x), TypeError)
assert 1 / F_test(2) == pow(2, -1, test_mod)
assert 1 / F_test(test_x) == pow(test_x, -1, test_mod)
assert 1 / F_test(test_y) == pow(test_y, -1, test_mod)

assert fmpz(test_y) / F_test(test_x) == (test_y * pow(test_x, -1, test_mod)) % test_mod
assert test_y / F_test(test_x) == (test_y * pow(test_x, -1, test_mod)) % test_mod


all_tests = [
test_pyflint,
Expand All @@ -1603,4 +1789,5 @@ def test_pickling():
test_nmod_poly,
test_nmod_mat,
test_arb,
test_fmpz_mod,
]
1 change: 1 addition & 0 deletions src/flint/types/fmpz.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ from flint.flintlib.fmpz cimport fmpz_t, fmpz_set_str, fmpz_set_si
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
Expand Down
14 changes: 14 additions & 0 deletions src/flint/types/fmpz_mod.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from flint.flint_base.flint_base cimport flint_scalar
from flint.flintlib.fmpz cimport fmpz_t
from flint.flintlib.fmpz_mod cimport fmpz_mod_ctx_t


cdef class fmpz_mod_ctx:
cdef fmpz_mod_ctx_t val

cdef class fmpz_mod(flint_scalar):
cdef fmpz_mod_ctx ctx
cdef fmpz_t val

cdef any_as_fmpz_mod(self, obj)

Loading