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
|
|
|
|
|
|
|
|
|
def ind(m,g):
|
|
|
|
|
''' mod m ,primary root g -> {n:indg n}'''
|
|
|
|
|
return {j:i for i in range(m-1) \
|
|
|
|
|
for j in range(m) if (g**i-j)%m==0}
|
|
|
|
|
|
|
|
|
|
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]
|
|
|
|
|
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]
|
2018-10-02 21:24:06 +08:00
|
|
|
|
i=2
|
|
|
|
|
while 1:
|
2018-12-16 17:09:54 +08:00
|
|
|
|
if all((i**n-1)%m !=0 for n in checkLst):return i
|
2018-10-02 21:24:06 +08:00
|
|
|
|
i+=1
|
|
|
|
|
|
|
|
|
|
class solve:
|
|
|
|
|
def __init__(self,equ=None):
|
|
|
|
|
self.linearPat= re.compile(r'\s*(\d+)\s*--\s*(\d+)[\s\(]*mod\s*(\d+)')
|
|
|
|
|
self.sol = []
|
|
|
|
|
#self.m = m
|
|
|
|
|
#self.ind_mp = ind(m,minG(m))
|
|
|
|
|
def noSol(self):
|
|
|
|
|
print('equation {equ} has no solution'.format(equ=self.equ))
|
|
|
|
|
def error(self):
|
|
|
|
|
print("Error! The divisor m must be postive integer")
|
|
|
|
|
def solveLinear(self,a,b,m):
|
|
|
|
|
'''ax--b(mod m): solve linear equation with one unknown
|
|
|
|
|
return ([x1,x2,...],m)
|
|
|
|
|
'''
|
|
|
|
|
a,b,m = self.check(a,b,m)
|
|
|
|
|
g,x,y=xgcd(a,m)
|
|
|
|
|
if a*b%g!=0:
|
|
|
|
|
self.noSol()
|
|
|
|
|
return None
|
|
|
|
|
sol=x*b//g
|
|
|
|
|
m0 = m//g
|
2018-12-16 17:09:54 +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)
|
2018-10-02 21:24:06 +08:00
|
|
|
|
def check(self,a,b,m):
|
|
|
|
|
if m<=0:
|
|
|
|
|
self.error()
|
|
|
|
|
return None
|
|
|
|
|
if a<0:a,b=-a,-b ## important
|
|
|
|
|
if b<0:b+= -b//m * m
|
|
|
|
|
return a,b,m
|
|
|
|
|
|
|
|
|
|
def solveHigh(self,a,n,b,m):
|
|
|
|
|
''' ax^n -- b (mod m) ind_mp is a dict of m's {n: indg n}'''
|
|
|
|
|
ind_mp = ind(m,minG(m))
|
|
|
|
|
tmp = ind_mp[b] - ind_mp[a]
|
|
|
|
|
if tmp < 0:tmp+=m
|
2018-12-16 17:09:54 +08:00
|
|
|
|
sol = self.solveLinear(n,tmp,phi(m))
|
2018-10-02 21:24:06 +08:00
|
|
|
|
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]]
|
|
|
|
|
print('{}x^{}--{}(mod {}), solution: {} mod {}'.format(a,n,b,m,sols,m))
|
|
|
|
|
return sols,m
|
2018-10-02 21:24:06 +08:00
|
|
|
|
|
2018-12-16 17:09:54 +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: ')
|
2018-10-02 21:24:06 +08:00
|
|
|
|
for a,b,m in tups:
|
2018-12-16 17:09:54 +08:00
|
|
|
|
print('{}x--{}(mod {})'.format(a,b,m))
|
2018-10-02 21:24:06 +08:00
|
|
|
|
if m in mp:
|
|
|
|
|
if mp[m][0]*b!=mp[m][1]*a:
|
|
|
|
|
self.noSol()
|
|
|
|
|
return
|
|
|
|
|
else:mp[m] = (a,b)
|
2018-12-16 17:09:54 +08:00
|
|
|
|
product = 1
|
|
|
|
|
for i in mp.keys():
|
|
|
|
|
product *=i
|
|
|
|
|
sol = [0]
|
2018-10-02 21:24:06 +08:00
|
|
|
|
for i in mp:
|
2018-12-16 17:09:54 +08:00
|
|
|
|
xs,m = self.solveLinear(product//i*mp[i][0],1,i)
|
|
|
|
|
new = []
|
|
|
|
|
for x in xs:
|
|
|
|
|
cur = x*product//i*mp[i][1]
|
|
|
|
|
for old in sol:
|
|
|
|
|
new.append(old+cur)
|
|
|
|
|
sol = new
|
|
|
|
|
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):
|
|
|
|
|
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]
|
|
|
|
|
print(self.solveLinear(li[0]))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
solver = solve()
|
|
|
|
|
res = solver.solveLinear(3,6,9)
|
2018-12-16 17:09:54 +08:00
|
|
|
|
print()
|
|
|
|
|
res = solver.solveHigh(1,8,3,11)
|
|
|
|
|
print()
|
|
|
|
|
res = solver.solveGroup([(5,11,2),(3,8,5),(4,1,7)])
|