Skip to content

Commit f7bfbe9

Browse files
committed
Move primality testing to constructor, create mod_mpoly_context class
Creates a subclass of flint_mpoly_context to hold mod_mpoly specific methods and abstractions
1 parent e66a07e commit f7bfbe9

File tree

6 files changed

+59
-120
lines changed

6 files changed

+59
-120
lines changed

src/flint/flint_base/flint_base.pxd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ cdef class flint_mpoly_context(flint_elem):
1313
cdef public object py_names
1414
cdef const char ** c_names
1515

16+
cdef class flint_mod_mpoly_context(flint_mpoly_context):
17+
cdef readonly bint __prime_modulus
18+
1619
cdef class flint_mpoly(flint_elem):
1720
cdef _add_scalar_(self, other)
1821
cdef _sub_scalar_(self, other)

src/flint/flint_base/flint_base.pyx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,51 @@ cdef class flint_mpoly_context(flint_elem):
409409
exp_vec = (0,) * self.nvars()
410410
return self.from_dict({tuple(exp_vec): coeff})
411411

412+
cdef class flint_mod_mpoly_context(flint_mpoly_context):
413+
def __init__(self, nvars, names, prime_modulus):
414+
super().__init__(nvars, names)
415+
self.__prime_modulus = <bint>prime_modulus
416+
417+
@classmethod
418+
def create_context_key(
419+
cls,
420+
slong nvars=1,
421+
ordering=Ordering.lex,
422+
modulus = None,
423+
names: Optional[str] = "x",
424+
nametup: Optional[tuple] = None,
425+
):
426+
"""
427+
Create a key for the context cache via the number of variables, the ordering, the modulus, and either a
428+
variable name string, or a tuple of variable names.
429+
"""
430+
# A type hint of ``ordering: Ordering`` results in the error "TypeError: an integer is required" if a Ordering
431+
# object is not provided. This is pretty obtuse so we check its type ourselves
432+
if not isinstance(ordering, Ordering):
433+
raise TypeError(f"'ordering' ('{ordering}') is not an instance of flint.Ordering")
434+
435+
if nametup is not None:
436+
key = nvars, ordering, nametup, modulus
437+
elif nametup is None and names is not None:
438+
key = nvars, ordering, cls.create_variable_names(nvars, names), modulus
439+
else:
440+
raise ValueError("must provide either 'names' or 'nametup'")
441+
return key
442+
443+
def is_prime(self):
444+
"""
445+
Return whether the modulus is prime
446+
447+
>>> from flint import Ordering, fmpz_mod_mpoly_ctx
448+
>>> ctx = fmpz_mod_mpoly_ctx.get_context(4, Ordering.degrevlex, 2**127, 'z')
449+
>>> ctx.is_prime()
450+
False
451+
>>> ctx = fmpz_mod_mpoly_ctx.get_context(4, Ordering.degrevlex, 2**127 - 1, 'z')
452+
>>> ctx.is_prime()
453+
True
454+
"""
455+
return self.__prime_modulus
456+
412457

413458
cdef class flint_mpoly(flint_elem):
414459
"""

src/flint/types/fmpz_mod_mpoly.pxd

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from flint.flint_base.flint_base cimport flint_mpoly, flint_mpoly_context
1+
from flint.flint_base.flint_base cimport flint_mpoly, flint_mod_mpoly_context
22

33
from flint.flintlib.functions.fmpz_mod_mpoly cimport (
44
fmpz_mod_mpoly_ctx_t,
@@ -21,9 +21,8 @@ cdef inline fmpz_mod_mpoly create_fmpz_mod_mpoly(fmpz_mod_mpoly_ctx ctx):
2121
var._init = True
2222
return var
2323

24-
cdef class fmpz_mod_mpoly_ctx(flint_mpoly_context):
24+
cdef class fmpz_mod_mpoly_ctx(flint_mod_mpoly_context):
2525
cdef fmpz_mod_mpoly_ctx_t val
26-
cdef readonly object __prime_modulus
2726

2827
cdef class fmpz_mod_mpoly(flint_mpoly):
2928
cdef fmpz_mod_mpoly_t val

src/flint/types/fmpz_mod_mpoly.pyx

Lines changed: 4 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from flint.flint_base.flint_base cimport (
22
flint_mpoly,
3-
flint_mpoly_context,
3+
flint_mod_mpoly_context,
44
ordering_py_to_c,
55
ordering_c_to_py,
66
)
@@ -76,7 +76,7 @@ cimport libc.stdlib
7676
cdef dict _fmpz_mod_mpoly_ctx_cache = {}
7777

7878

79-
cdef class fmpz_mod_mpoly_ctx(flint_mpoly_context):
79+
cdef class fmpz_mod_mpoly_ctx(flint_mod_mpoly_context):
8080
"""
8181
A class for storing the polynomial context
8282
@@ -97,60 +97,20 @@ cdef class fmpz_mod_mpoly_ctx(flint_mpoly_context):
9797
raise TypeError(f"modulus ({modulus}) is not coercible to fmpz")
9898
else:
9999
m = modulus
100-
fmpz_mod_mpoly_ctx_init(self.val, nvars, ordering_py_to_c(ordering), m.val)
101-
self.__prime_modulus = None
102-
super().__init__(nvars, names)
103-
104-
@classmethod
105-
def create_context_key(
106-
cls,
107-
slong nvars=1,
108-
ordering=Ordering.lex,
109-
modulus = None,
110-
names: Optional[str] = "x",
111-
nametup: Optional[tuple] = None,
112-
):
113-
"""
114-
Create a key for the context cache via the number of variables, the ordering, the modulus, and either a
115-
variable name string, or a tuple of variable names.
116-
"""
117-
# A type hint of ``ordering: Ordering`` results in the error "TypeError: an integer is required" if a Ordering
118-
# object is not provided. This is pretty obtuse so we check its type ourselves
119-
if not isinstance(ordering, Ordering):
120-
raise TypeError(f"'ordering' ('{ordering}') is not an instance of flint.Ordering")
121-
elif not typecheck(modulus, fmpz):
122-
m = any_as_fmpz(modulus)
123-
if m is NotImplemented:
124-
raise TypeError(f"'modulus' ('{modulus}') is not coercible to fmpz")
125-
else:
126-
modulus = m
127100

128-
if nametup is not None:
129-
key = nvars, ordering, nametup, modulus
130-
elif nametup is None and names is not None:
131-
key = nvars, ordering, cls.create_variable_names(nvars, names), modulus
132-
else:
133-
raise ValueError("must provide either 'names' or 'nametup'")
134-
return key
101+
super().__init__(nvars, names, m.is_prime())
102+
fmpz_mod_mpoly_ctx_init(self.val, nvars, ordering_py_to_c(ordering), m.val)
135103

136104
def _any_as_scalar(self, other):
137105
if isinstance(other, int):
138106
return any_as_fmpz(other)
139107
elif typecheck(other, nmod):
140-
if (<nmod>other).modulus() != self.modulus():
141-
raise DomainError(
142-
f"modulus does not match, got {(<nmod>other).modulus()}, expected {self.modulus()}"
143-
)
144108
return any_as_fmpz((<nmod>other).val)
145109
elif typecheck(other, fmpz):
146110
res = fmpz.__new__(fmpz)
147111
fmpz_set((<fmpz>res).val, (<fmpz>other).val)
148112
return res
149113
elif typecheck(other, fmpz_mod):
150-
if (<fmpz_mod>other).ctx.modulus() != self.modulus():
151-
raise DomainError(
152-
f"modulus does not match, got {(<fmpz_mod>other).ctx.modulus()}, expected {self.modulus()}"
153-
)
154114
res = fmpz.__new__(fmpz)
155115
fmpz_set((<fmpz>res).val, (<fmpz_mod>other).val)
156116
return res
@@ -197,22 +157,6 @@ cdef class fmpz_mod_mpoly_ctx(flint_mpoly_context):
197157
fmpz_mod_mpoly_ctx_get_modulus(m.val, self.val)
198158
return m
199159

200-
def is_prime(self):
201-
"""
202-
Return whether the modulus is prime
203-
204-
>>> from flint import Ordering
205-
>>> ctx = fmpz_mod_mpoly_ctx.get_context(4, Ordering.degrevlex, 2**127, 'z')
206-
>>> ctx.is_prime()
207-
False
208-
>>> ctx = fmpz_mod_mpoly_ctx.get_context(4, Ordering.degrevlex, 2**127 - 1, 'z')
209-
>>> ctx.is_prime()
210-
True
211-
"""
212-
if self.__prime_modulus is None:
213-
self.__prime_modulus = <bint>self.modulus().is_prime()
214-
return self.__prime_modulus
215-
216160
def gen(self, slong i):
217161
"""
218162
Return the ``i`` th generator of the polynomial ring

src/flint/types/nmod_mpoly.pxd

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from flint.flint_base.flint_base cimport flint_mpoly, flint_mpoly_context
1+
from flint.flint_base.flint_base cimport flint_mpoly, flint_mod_mpoly_context
22

33
from flint.flintlib.functions.nmod_mpoly cimport (
44
nmod_mpoly_ctx_t,
@@ -21,9 +21,8 @@ cdef inline nmod_mpoly create_nmod_mpoly(nmod_mpoly_ctx ctx):
2121
var._init = True
2222
return var
2323

24-
cdef class nmod_mpoly_ctx(flint_mpoly_context):
24+
cdef class nmod_mpoly_ctx(flint_mod_mpoly_context):
2525
cdef nmod_mpoly_ctx_t val
26-
cdef readonly object __prime_modulus
2726

2827
cdef class nmod_mpoly(flint_mpoly):
2928
cdef nmod_mpoly_t val

src/flint/types/nmod_mpoly.pyx

Lines changed: 3 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from flint.flint_base.flint_base cimport (
22
flint_mpoly,
3-
flint_mpoly_context,
3+
flint_mod_mpoly_context,
44
ordering_py_to_c,
55
ordering_c_to_py,
66
)
@@ -81,7 +81,7 @@ cimport libc.stdlib
8181
cdef dict _nmod_mpoly_ctx_cache = {}
8282

8383

84-
cdef class nmod_mpoly_ctx(flint_mpoly_context):
84+
cdef class nmod_mpoly_ctx(flint_mod_mpoly_context):
8585
"""
8686
A class for storing the polynomial context
8787
@@ -98,35 +98,8 @@ cdef class nmod_mpoly_ctx(flint_mpoly_context):
9898
if modulus <= 0:
9999
raise ValueError("modulus must be positive")
100100

101+
super().__init__(nvars, names, <bint>n_is_prime(modulus))
101102
nmod_mpoly_ctx_init(self.val, nvars, ordering_py_to_c(ordering), modulus)
102-
self.__prime_modulus = None
103-
super().__init__(nvars, names)
104-
105-
@classmethod
106-
def create_context_key(
107-
cls,
108-
slong nvars=1,
109-
ordering=Ordering.lex,
110-
modulus = None,
111-
names: Optional[str] = "x",
112-
nametup: Optional[tuple] = None,
113-
):
114-
"""
115-
Create a key for the context cache via the number of variables, the ordering, the modulus, and either a
116-
variable name string, or a tuple of variable names.
117-
"""
118-
# A type hint of ``ordering: Ordering`` results in the error "TypeError: an integer is required" if a Ordering
119-
# object is not provided. This is pretty obtuse so we check its type ourselves
120-
if not isinstance(ordering, Ordering):
121-
raise TypeError(f"'ordering' ('{ordering}') is not an instance of flint.Ordering")
122-
123-
if nametup is not None:
124-
key = nvars, ordering, nametup, modulus
125-
elif nametup is None and names is not None:
126-
key = nvars, ordering, cls.create_variable_names(nvars, names), modulus
127-
else:
128-
raise ValueError("must provide either 'names' or 'nametup'")
129-
return key
130103

131104
def _any_as_scalar(self, other):
132105
if isinstance(other, int):
@@ -135,18 +108,10 @@ cdef class nmod_mpoly_ctx(flint_mpoly_context):
135108
except OverflowError:
136109
return <ulong>(other % self.modulus())
137110
elif typecheck(other, nmod):
138-
if (<nmod>other).modulus() != self.modulus():
139-
raise DomainError(
140-
f"modulus does not match, got {(<nmod>other).modulus()}, expected {self.modulus()}"
141-
)
142111
return (<nmod>other).val
143112
elif typecheck(other, fmpz):
144113
return fmpz_get_nmod((<fmpz>other).val, self.val.mod)
145114
elif typecheck(other, fmpz_mod):
146-
if (<fmpz_mod>other).ctx.modulus() != self.modulus():
147-
raise DomainError(
148-
f"modulus does not match, got {(<fmpz_mod>other).ctx.modulus()}, expected {self.modulus()}"
149-
)
150115
return fmpz_get_nmod((<fmpz_mod>other).val, self.val.mod)
151116
else:
152117
return NotImplemented
@@ -189,22 +154,6 @@ cdef class nmod_mpoly_ctx(flint_mpoly_context):
189154
"""
190155
return nmod_mpoly_ctx_modulus(self.val)
191156

192-
def is_prime(self):
193-
"""
194-
Return whether the modulus is prime
195-
196-
>>> from flint import Ordering
197-
>>> ctx = nmod_mpoly_ctx.get_context(4, Ordering.degrevlex, 2**32, 'z')
198-
>>> ctx.is_prime()
199-
False
200-
>>> ctx = nmod_mpoly_ctx.get_context(4, Ordering.degrevlex, 2**32 - 17, 'z')
201-
>>> ctx.is_prime()
202-
True
203-
"""
204-
if self.__prime_modulus is None:
205-
self.__prime_modulus = <bint>n_is_prime(self.modulus())
206-
return self.__prime_modulus
207-
208157
def gen(self, slong i):
209158
"""
210159
Return the ``i`` th generator of the polynomial ring

0 commit comments

Comments
 (0)