2018-10-02 21:24:06 +08:00
|
|
|
|
''' mbinary
|
|
|
|
|
#########################################################################
|
2018-12-16 17:09:54 +08:00
|
|
|
|
# File : modulo_equation.py
|
2018-10-02 21:24:06 +08:00
|
|
|
|
# Author: mbinary
|
|
|
|
|
# Mail: zhuheqin1@gmail.com
|
2019-01-31 12:09:46 +08:00
|
|
|
|
# Blog: https://mbinary.xyz
|
2018-10-02 21:24:06 +08:00
|
|
|
|
# Github: https://github.com/mbinary
|
2018-12-16 17:09:54 +08:00
|
|
|
|
# Created Time: 2018-3-4 21:14
|
2018-10-02 21:24:06 +08:00
|
|
|
|
# Description:
|
2018-12-16 17:09:54 +08:00
|
|
|
|
`--` represents modulo symbol
|
2018-10-02 21:24:06 +08:00
|
|
|
|
#########################################################################
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
|
2018-12-16 17:09:54 +08:00
|
|
|
|
from gcd import xgcd
|
|
|
|
|
from euler import phi
|
|
|
|
|
from isPrime import isPrime
|
|
|
|
|
from factor import factor
|
2018-10-02 21:24:06 +08:00
|
|
|
|
|
2020-04-15 12:28:20 +08:00
|
|
|
|
|
|
|
|
|
def ind(m, g):
|
2018-10-02 21:24:06 +08:00
|
|
|
|
''' mod m ,primary root g -> {n:indg n}'''
|
2020-04-15 12:28:20 +08:00
|
|
|
|
return {j: i for i in range(m-1)
|
|
|
|
|
for j in range(m) if (g**i-j) % m == 0}
|
|
|
|
|
|
2018-10-02 21:24:06 +08:00
|
|
|
|
|
2020-04-15 12:28:20 +08:00
|
|
|
|
def gs(m, num=100):
|
|
|
|
|
'''return list of m's primary roots below num'''
|
2018-12-16 17:09:54 +08:00
|
|
|
|
p = phi(m)
|
|
|
|
|
mp = factor(p)
|
|
|
|
|
checkLst = [p//i for i in mp]
|
2020-04-15 12:28:20 +08:00
|
|
|
|
return [i for i in range(2, num) if all((i**n-1) % m != 0 for n in checkLst)]
|
|
|
|
|
|
2018-10-02 21:24:06 +08:00
|
|
|
|
|
|
|
|
|
def minG(m):
|
2018-12-16 17:09:54 +08:00
|
|
|
|
p = phi(m)
|
|
|
|
|
mp = factor(p)
|
|
|
|
|
checkLst = [p//i for i in mp]
|
2020-04-15 12:28:20 +08:00
|
|
|
|
i = 2
|
|
|
|
|
while 1:
|
|
|
|
|
if all((i**n-1) % m != 0 for n in checkLst):
|
|
|
|
|
return i
|
|
|
|
|
i += 1
|
|
|
|
|
|
2018-10-02 21:24:06 +08:00
|
|
|
|
|
|
|
|
|
class solve:
|
2020-04-15 12:28:20 +08:00
|
|
|
|
def __init__(self, equ=None):
|
|
|
|
|
self.linearPat = re.compile(r'\s*(\d+)\s*--\s*(\d+)[\s\(]*mod\s*(\d+)')
|
|
|
|
|
self.sol = []
|
2018-10-02 21:24:06 +08:00
|
|
|
|
#self.m = m
|
|
|
|
|
#self.ind_mp = ind(m,minG(m))
|
2020-04-15 12:28:20 +08:00
|
|
|
|
|
2018-10-02 21:24:06 +08:00
|
|
|
|
def noSol(self):
|
|
|
|
|
print('equation {equ} has no solution'.format(equ=self.equ))
|
2020-04-15 12:28:20 +08:00
|
|
|
|
|
2018-10-02 21:24:06 +08:00
|
|
|
|
def error(self):
|
|
|
|
|
print("Error! The divisor m must be postive integer")
|
2020-04-15 12:28:20 +08:00
|
|
|
|
|
|
|
|
|
def solveLinear(self, a, b, m):
|
2018-10-02 21:24:06 +08:00
|
|
|
|
'''ax--b(mod m): solve linear equation with one unknown
|
|
|
|
|
return ([x1,x2,...],m)
|
|
|
|
|
'''
|
2020-04-15 12:28:20 +08:00
|
|
|
|
a, b, m = self.check(a, b, m)
|
|
|
|
|
g, x, y = xgcd(a, m)
|
|
|
|
|
if a*b % g != 0:
|
2018-10-02 21:24:06 +08:00
|
|
|
|
self.noSol()
|
|
|
|
|
return None
|
2020-04-15 12:28:20 +08:00
|
|
|
|
sol = x*b//g
|
2018-10-02 21:24:06 +08:00
|
|
|
|
m0 = m//g
|
2020-04-15 12:28:20 +08:00
|
|
|
|
sols = [(sol+i*m0) % m for i in range(g)]
|
|
|
|
|
print('{}x--{}(mod {}), solution: {} mod {}'.format(a, b, m, sols, m))
|
|
|
|
|
return (sols, m)
|
|
|
|
|
|
|
|
|
|
def check(self, a, b, m):
|
|
|
|
|
if m <= 0:
|
2018-10-02 21:24:06 +08:00
|
|
|
|
self.error()
|
|
|
|
|
return None
|
2020-04-15 12:28:20 +08:00
|
|
|
|
if a < 0:
|
|
|
|
|
a, b = -a, -b # important
|
|
|
|
|
if b < 0:
|
|
|
|
|
b += -b//m * m
|
|
|
|
|
return a, b, m
|
2018-10-02 21:24:06 +08:00
|
|
|
|
|
2020-04-15 12:28:20 +08:00
|
|
|
|
def solveHigh(self, a, n, b, m):
|
2018-10-02 21:24:06 +08:00
|
|
|
|
''' ax^n -- b (mod m) ind_mp is a dict of m's {n: indg n}'''
|
2020-04-15 12:28:20 +08:00
|
|
|
|
ind_mp = ind(m, minG(m))
|
2018-10-02 21:24:06 +08:00
|
|
|
|
tmp = ind_mp[b] - ind_mp[a]
|
2020-04-15 12:28:20 +08:00
|
|
|
|
if tmp < 0:
|
|
|
|
|
tmp += m
|
|
|
|
|
sol = self.solveLinear(n, tmp, phi(m))
|
|
|
|
|
re_mp = {j: i for i, j in ind_mp.items()}
|
2018-12-16 17:09:54 +08:00
|
|
|
|
sols = [re_mp[i] for i in sol[0]]
|
2020-04-15 12:28:20 +08:00
|
|
|
|
print('{}x^{}--{}(mod {}), solution: {} mod {}'.format(a, n, b, m, sols, m))
|
|
|
|
|
return sols, m
|
2018-10-02 21:24:06 +08:00
|
|
|
|
|
2020-04-15 12:28:20 +08:00
|
|
|
|
def solveGroup(self, tups):
|
2018-10-02 21:24:06 +08:00
|
|
|
|
'''tups is a list of tongyu equation groups, like
|
|
|
|
|
[(a1,b1,m1),(a2,b2,m2)...]
|
|
|
|
|
and, m1,m2... are all primes
|
|
|
|
|
'''
|
|
|
|
|
mp = {}
|
2018-12-16 17:09:54 +08:00
|
|
|
|
print('solving group of equations: ')
|
2020-04-15 12:28:20 +08:00
|
|
|
|
for a, b, m in tups:
|
|
|
|
|
print('{}x--{}(mod {})'.format(a, b, m))
|
2018-10-02 21:24:06 +08:00
|
|
|
|
if m in mp:
|
2020-04-15 12:28:20 +08:00
|
|
|
|
if mp[m][0]*b != mp[m][1]*a:
|
2018-10-02 21:24:06 +08:00
|
|
|
|
self.noSol()
|
|
|
|
|
return
|
2020-04-15 12:28:20 +08:00
|
|
|
|
else:
|
|
|
|
|
mp[m] = (a, b)
|
2018-12-16 17:09:54 +08:00
|
|
|
|
product = 1
|
|
|
|
|
for i in mp.keys():
|
2020-04-15 12:28:20 +08:00
|
|
|
|
product *= i
|
2018-12-16 17:09:54 +08:00
|
|
|
|
sol = [0]
|
2018-10-02 21:24:06 +08:00
|
|
|
|
for i in mp:
|
2020-04-15 12:28:20 +08:00
|
|
|
|
xs, m = self.solveLinear(product//i*mp[i][0], 1, i)
|
2018-12-16 17:09:54 +08:00
|
|
|
|
new = []
|
|
|
|
|
for x in xs:
|
|
|
|
|
cur = x*product//i*mp[i][1]
|
|
|
|
|
for old in sol:
|
|
|
|
|
new.append(old+cur)
|
|
|
|
|
sol = new
|
2020-04-15 12:28:20 +08:00
|
|
|
|
sol = [i % product for i in sol]
|
|
|
|
|
print('final solution: {} mod {}'.format(sol, product))
|
|
|
|
|
return sol, product
|
|
|
|
|
|
2018-10-02 21:24:06 +08:00
|
|
|
|
def __call__(self):
|
2020-04-15 12:28:20 +08:00
|
|
|
|
s = input('输入同余方程,用--代表同于号,形如3--5(mod 7)代表3x模7同余于5')
|
|
|
|
|
li = self.linearPat.findall(s)
|
|
|
|
|
li = [(int(a), int(b), int(m)) for a, b, m in li]
|
2018-10-02 21:24:06 +08:00
|
|
|
|
print(self.solveLinear(li[0]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2020-04-15 12:28:20 +08:00
|
|
|
|
solver = solve()
|
|
|
|
|
res = solver.solveLinear(3, 6, 9)
|
2018-12-16 17:09:54 +08:00
|
|
|
|
print()
|
2020-04-15 12:28:20 +08:00
|
|
|
|
res = solver.solveHigh(1, 8, 3, 11)
|
2018-12-16 17:09:54 +08:00
|
|
|
|
print()
|
2020-04-15 12:28:20 +08:00
|
|
|
|
res = solver.solveGroup([(5, 11, 2), (3, 8, 5), (4, 1, 7)])
|