Skip to content

Commit 49e35dd

Browse files
Extend pow_trunc to arbitrary size exponents
1 parent febe154 commit 49e35dd

File tree

6 files changed

+105
-25
lines changed

6 files changed

+105
-25
lines changed

src/flint/test/test_all.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2969,6 +2969,15 @@ def setbad(obj, i, val):
29692969
assert raises(lambda: P([1, 2, 3]).mul_low(None, 3), TypeError) # type: ignore
29702970
assert raises(lambda: P([1, 2, 3]).mul_low(P([4, 5, 6]), None), TypeError) # type: ignore
29712971

2972+
p = P([1, 2, 3])
2973+
assert p.pow_trunc(1234, 3) == P([1, 2468, 3046746])
2974+
assert raises(lambda: p.pow_trunc(None, 3), TypeError) # type: ignore
2975+
assert raises(lambda: p.pow_trunc(3, "A"), TypeError) # type: ignore
2976+
assert raises(lambda: p.pow_trunc(P([4, 5, 6]), 3), TypeError) # type: ignore
2977+
# Large exponents are allowed
2978+
assert p.pow_trunc(2**100, 2) == P([1, 2**101])
2979+
assert p.pow_trunc(6**60, 3) == p.pow_trunc(2**60, 3).pow_trunc(3**60, 3)
2980+
29722981
# XXX: Not sure what this should do in general:
29732982
p = P([1, 1])
29742983
mod = P([1, 1])

src/flint/types/fmpq_poly.pyx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -526,14 +526,11 @@ cdef class fmpq_poly(flint_poly):
526526
fmpq_poly_mullow(res.val, self.val, (<fmpq_poly>other).val, n)
527527
return res
528528

529-
def pow_trunc(self, slong e, slong n):
529+
def pow_trunc(self, e, slong n):
530530
r"""
531531
Returns ``self`` raised to the power ``e`` modulo `x^n`:
532532
:math:`f^e \mod x^n`/
533533
534-
Note: For exponents larger that 2^63 (which do not fit inside a slong) use the
535-
method :meth:`~.pow_mod` with the explicit modulus `x^n`.
536-
537534
>>> f = fmpq_poly([1, 2, 3])
538535
>>> x = fmpq_poly([0, 1])
539536
>>> f.pow_trunc(2**20, 4)
@@ -544,7 +541,23 @@ cdef class fmpq_poly(flint_poly):
544541
if e < 0:
545542
raise ValueError("Exponent must be non-negative")
546543

547-
cdef fmpq_poly res
544+
cdef slong e_c
545+
cdef fmpq_poly res, tmp
546+
547+
try:
548+
e_c = e
549+
except OverflowError:
550+
# Exponent does not fit slong
551+
res = fmpq_poly.__new__(fmpq_poly)
552+
tmp = fmpq_poly.__new__(fmpq_poly)
553+
ebytes = e.to_bytes((e.bit_length() + 15) // 16 * 2, "big")
554+
fmpq_poly_pow_trunc(res.val, self.val, ebytes[0] * 256 + ebytes[1], n)
555+
for i in range(2, len(ebytes), 2):
556+
fmpq_poly_pow_trunc(res.val, res.val, 1 << 16, n)
557+
fmpq_poly_pow_trunc(tmp.val, self.val, ebytes[i] * 256 + ebytes[i+1], n)
558+
fmpq_poly_mullow(res.val, res.val, tmp.val, n)
559+
return res
560+
548561
res = fmpq_poly.__new__(fmpq_poly)
549562
fmpq_poly_pow_trunc(res.val, self.val, e, n)
550563
return res

src/flint/types/fmpz_mod_poly.pyx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,26 +1668,41 @@ cdef class fmpz_mod_poly(flint_poly):
16681668
)
16691669
return res
16701670

1671-
def pow_trunc(self, slong e, slong n):
1671+
def pow_trunc(self, e, slong n):
16721672
r"""
16731673
Returns ``self`` raised to the power ``e`` modulo `x^n`:
16741674
:math:`f^e \mod x^n`/
16751675
1676-
Note: For exponents larger that 2^31 (which do not fit inside a ulong) use the
1677-
method :meth:`~.pow_mod` with the explicit modulus `x^n`.
1678-
16791676
>>> R = fmpz_mod_poly_ctx(163)
16801677
>>> x = R.gen()
16811678
>>> f = 30*x**6 + 104*x**5 + 76*x**4 + 33*x**3 + 70*x**2 + 44*x + 65
16821679
>>> f.pow_trunc(2**20, 30) == pow(f, 2**20, x**30)
16831680
True
16841681
>>> f.pow_trunc(2**20, 5)
16851682
132*x^4 + 113*x^3 + 36*x^2 + 48*x + 6
1683+
>>> f.pow_trunc(5**25, 5)
1684+
147*x^4 + 98*x^3 + 95*x^2 + 33*x + 126
16861685
"""
16871686
if e < 0:
16881687
raise ValueError("Exponent must be non-negative")
16891688

1690-
cdef fmpz_mod_poly res
1689+
cdef fmpz_mod_poly res, tmp
1690+
cdef slong e_c
1691+
1692+
try:
1693+
e_c = e
1694+
except OverflowError:
1695+
# Exponent does not fit slong
1696+
res = self.ctx.new_ctype_poly()
1697+
tmp = self.ctx.new_ctype_poly()
1698+
ebytes = e.to_bytes((e.bit_length() + 15) // 16 * 2, "big")
1699+
fmpz_mod_poly_pow_trunc(res.val, self.val, ebytes[0] * 256 + ebytes[1], n, res.ctx.mod.val)
1700+
for i in range(2, len(ebytes), 2):
1701+
fmpz_mod_poly_pow_trunc(res.val, res.val, 1 << 16, n, res.ctx.mod.val)
1702+
fmpz_mod_poly_pow_trunc(tmp.val, self.val, ebytes[i] * 256 + ebytes[i+1], n, res.ctx.mod.val)
1703+
fmpz_mod_poly_mullow(res.val, res.val, tmp.val, n, res.ctx.mod.val)
1704+
return res
1705+
16911706
res = self.ctx.new_ctype_poly()
16921707
fmpz_mod_poly_pow_trunc(res.val, self.val, e, n, res.ctx.mod.val)
16931708
return res

src/flint/types/fmpz_poly.pyx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -507,14 +507,11 @@ cdef class fmpz_poly(flint_poly):
507507
fmpz_poly_mullow(res.val, self.val, (<fmpz_poly>other).val, n)
508508
return res
509509

510-
def pow_trunc(self, slong e, slong n):
510+
def pow_trunc(self, e, slong n):
511511
r"""
512512
Returns ``self`` raised to the power ``e`` modulo `x^n`:
513513
:math:`f^e \mod x^n`/
514514
515-
Note: For exponents larger that 2^63 (which do not fit inside a slong) use the
516-
method :meth:`~.pow_mod` with the explicit modulus `x^n`.
517-
518515
>>> f = fmpz_poly([1, 2, 3])
519516
>>> x = fmpz_poly([0, 1])
520517
>>> f.pow_trunc(2**20, 4)
@@ -525,7 +522,23 @@ cdef class fmpz_poly(flint_poly):
525522
if e < 0:
526523
raise ValueError("Exponent must be non-negative")
527524

528-
cdef fmpz_poly res
525+
cdef slong e_c
526+
cdef fmpz_poly res, tmp
527+
528+
try:
529+
e_c = e
530+
except OverflowError:
531+
# Exponent does not fit slong
532+
res = fmpz_poly.__new__(fmpz_poly)
533+
tmp = fmpz_poly.__new__(fmpz_poly)
534+
ebytes = e.to_bytes((e.bit_length() + 15) // 16 * 2, "big")
535+
fmpz_poly_pow_trunc(res.val, self.val, ebytes[0] * 256 + ebytes[1], n)
536+
for i in range(2, len(ebytes), 2):
537+
fmpz_poly_pow_trunc(res.val, res.val, 1 << 16, n)
538+
fmpz_poly_pow_trunc(tmp.val, self.val, ebytes[i] * 256 + ebytes[i+1], n)
539+
fmpz_poly_mullow(res.val, res.val, tmp.val, n)
540+
return res
541+
529542
res = fmpz_poly.__new__(fmpz_poly)
530543
fmpz_poly_pow_trunc(res.val, self.val, e, n)
531544
return res

src/flint/types/fq_default_poly.pyx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,26 +1190,41 @@ cdef class fq_default_poly(flint_poly):
11901190
)
11911191
return res
11921192

1193-
def pow_trunc(self, slong e, slong n):
1193+
def pow_trunc(self, e, slong n):
11941194
r"""
11951195
Returns ``self`` raised to the power ``e`` modulo `x^n`:
11961196
:math:`f^e \mod x^n`/
11971197
1198-
Note: For exponents larger that 2^31 (which do not fit inside a ulong) use the
1199-
method :meth:`~.pow_mod` with the explicit modulus `x^n`.
1200-
12011198
>>> R = fq_default_poly_ctx(163)
12021199
>>> x = R.gen()
12031200
>>> f = 30*x**6 + 104*x**5 + 76*x**4 + 33*x**3 + 70*x**2 + 44*x + 65
12041201
>>> f.pow_trunc(2**20, 30) == pow(f, 2**20, x**30)
12051202
True
12061203
>>> f.pow_trunc(2**20, 5)
12071204
132*x^4 + 113*x^3 + 36*x^2 + 48*x + 6
1205+
>>> f.pow_trunc(5**25, 5)
1206+
147*x^4 + 98*x^3 + 95*x^2 + 33*x + 126
12081207
"""
12091208
if e < 0:
12101209
raise ValueError("Exponent must be non-negative")
12111210

1212-
cdef fq_default_poly res
1211+
cdef slong e_c
1212+
cdef fq_default_poly res, tmp
1213+
1214+
try:
1215+
e_c = e
1216+
except OverflowError:
1217+
# Exponent does not fit slong
1218+
res = self.ctx.new_ctype_poly()
1219+
tmp = self.ctx.new_ctype_poly()
1220+
ebytes = e.to_bytes((e.bit_length() + 15) // 16 * 2, "big")
1221+
fq_default_poly_pow_trunc(res.val, self.val, ebytes[0] * 256 + ebytes[1], n, res.ctx.field.val)
1222+
for i in range(2, len(ebytes), 2):
1223+
fq_default_poly_pow_trunc(res.val, res.val, 1 << 16, n, res.ctx.field.val)
1224+
fq_default_poly_pow_trunc(tmp.val, self.val, ebytes[i] * 256 + ebytes[i+1], n, res.ctx.field.val)
1225+
fq_default_poly_mullow(res.val, res.val, tmp.val, n, res.ctx.field.val)
1226+
return res
1227+
12131228
res = self.ctx.new_ctype_poly()
12141229
fq_default_poly_pow_trunc(res.val, self.val, e, n, res.ctx.field.val)
12151230
return res

src/flint/types/nmod_poly.pyx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -752,14 +752,11 @@ cdef class nmod_poly(flint_poly):
752752
nmod_poly_mullow(res.val, self.val, (<nmod_poly>other).val, n)
753753
return res
754754

755-
def pow_trunc(self, slong e, slong n):
755+
def pow_trunc(self, e, slong n):
756756
r"""
757757
Returns ``self`` raised to the power ``e`` modulo `x^n`:
758758
:math:`f^e \mod x^n`/
759759
760-
Note: For exponents larger that 2^63 (which do not fit inside a slong) use the
761-
method :meth:`~.pow_mod` with the explicit modulus `x^n`.
762-
763760
>>> f = nmod_poly([65, 44, 70, 33, 76, 104, 30], 163)
764761
>>> x = nmod_poly([0, 1], 163)
765762
>>> f.pow_trunc(2**20, 30) == pow(f, 2**20, x**30)
@@ -772,7 +769,25 @@ cdef class nmod_poly(flint_poly):
772769
if e < 0:
773770
raise ValueError("Exponent must be non-negative")
774771

775-
cdef nmod_poly res = nmod_poly.__new__(nmod_poly)
772+
cdef nmod_poly res, tmp
773+
cdef slong e_c
774+
775+
try:
776+
e_c = e
777+
except OverflowError:
778+
# Exponent does not fit slong
779+
res = nmod_poly.__new__(nmod_poly)
780+
tmp = nmod_poly.__new__(nmod_poly)
781+
nmod_poly_init_preinv(res.val, self.val.mod.n, self.val.mod.ninv)
782+
nmod_poly_init_preinv(tmp.val, self.val.mod.n, self.val.mod.ninv)
783+
ebytes = e.to_bytes((e.bit_length() + 15) // 16 * 2, "big")
784+
nmod_poly_pow_trunc(res.val, self.val, ebytes[0] * 256 + ebytes[1], n)
785+
for i in range(2, len(ebytes), 2):
786+
nmod_poly_pow_trunc(res.val, res.val, 1 << 16, n)
787+
nmod_poly_pow_trunc(tmp.val, self.val, ebytes[i] * 256 + ebytes[i+1], n)
788+
nmod_poly_mullow(res.val, res.val, tmp.val, n)
789+
return res
790+
776791
res = nmod_poly.__new__(nmod_poly)
777792
nmod_poly_init_preinv(res.val, self.val.mod.n, self.val.mod.ninv)
778793
nmod_poly_pow_trunc(res.val, self.val, e, n)

0 commit comments

Comments
 (0)