-
Notifications
You must be signed in to change notification settings - Fork 310
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
Template for modulo operations #40
base: master
Are you sure you want to change the base?
Changes from all commits
eef3b7e
54ea14c
ccb5210
4766516
0a990ea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
""" | ||
A template for usefull stuff involving prime modulo. It contains: | ||
1. Fast calculation of (a * b + c) % MOD (Especially usefull for PyPy users on windows). | ||
2. Calculation of factorial, inverse factorial and modular inverse | ||
for all integers < maxN in O(maxN) time. | ||
3. Calculate n choose k in O(1) time using precalculated fac. and inv. fac. | ||
4. Multiply matrices mod MOD. | ||
""" | ||
MOD = 10 ** 9 + 7 # needs to be prime! | ||
maxN = 10 ** 6 # needs to be <= MOD | ||
|
||
|
||
def fast_modder(MOD): | ||
""" Returns a function modmul(a,b,c=0) that quickly calculates (a * b + c) % MOD, assuming 0 <= a,b < MOD """ | ||
import sys, platform | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm tempted to move this up, to the top of the file, even though this is specific. |
||
impl = platform.python_implementation() | ||
maxs = sys.maxsize | ||
if 'PyPy' in impl and MOD <= maxs and MOD ** 2 > maxs: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can actually check |
||
import __pypy__ | ||
intsub = __pypy__.intop.int_sub | ||
intmul = __pypy__.intop.int_mul | ||
intmulmod = __pypy__.intop.int_mulmod | ||
if MOD < 2**30 - 1000: | ||
MODINV = 1.0 / MOD | ||
def modmul(a, b, c=0): | ||
return (intsub(intmul(a,b), intmul(MOD, int(MODINV * a * b))) + c) % MOD | ||
else: | ||
def modmul(a, b, c=0): | ||
return (intmulmod(a, b, MOD) + c) % MOD | ||
else: | ||
def modmul(a, b, c=0): | ||
return (a * b + c) % MOD | ||
return modmul | ||
|
||
modmul = fast_modder(MOD) | ||
|
||
|
||
""" Precalculate factorial, inverse factorial and modular inverse """ | ||
|
||
def mod_precalc(n): | ||
""" Calculates fac, inv_fac and (modular) inv for i < n in O(n) time """ | ||
assert n <= MOD | ||
|
||
fac = [1] * n | ||
for i in range(2, n): | ||
fac[i] = modmul(fac[i - 1], i) | ||
|
||
inv_fac = [pow(fac[-1], MOD - 2, MOD)] * n | ||
for i in reversed(range(1, n)): | ||
inv_fac[i - 1] = modmul(inv_fac[i], i) | ||
|
||
inv = [modmul(inv_fac[i], fac[i - 1]) for i in range(n)] | ||
|
||
return fac, inv_fac, inv | ||
|
||
fac, inv_fac, inv = mod_precalc(maxN) | ||
|
||
|
||
""" Useful functions involving modulo """ | ||
|
||
def choose(n, k): | ||
""" Calculate n choose k in O(1) time """ | ||
if k < 0 or k > n: | ||
return 0 | ||
return modmul(modmul(fac[n], fac_inv[k]), fac_inv[n - k]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
def matrix_modmul(A, B): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have something for this elsewhere, so let's remove that too. |
||
""" Multiplies matrices A and B, assuming 0 <= A[i][j], B[i][j] < MOD """ | ||
assert len(A[0]) == len(B) | ||
C = [] | ||
for Ai in A: | ||
tmp = [0] * len(B[0]) | ||
for k in range(len(B)): | ||
Aik = Ai[k] | ||
Bk = B[k] | ||
for j in range(len(Bk)): | ||
tmp[j] = modmul(Aik, Bk[j], tmp[j]) | ||
C.append(tmp) | ||
return C |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps call this
make_modmul
?