''' mbinary ######################################################################### # File : modulo_equation.py # Author: mbinary # Mail: zhuheqin1@gmail.com # Blog: https://mbinary.xyz # Github: https://github.com/mbinary # Created Time: 2018-3-4 21:14 # Description: `--` represents modulo symbol ######################################################################### ''' import re from gcd import xgcd from euler import phi from isPrime import isPrime from factor import factor 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''' 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)] def minG(m): p = phi(m) mp = factor(p) checkLst = [p//i for i in mp] i=2 while 1: if all((i**n-1)%m !=0 for n in checkLst):return i 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 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: 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 sol = self.solveLinear(n,tmp,phi(m)) re_mp = {j:i for i ,j in ind_mp.items()} sols = [re_mp[i] for i in sol[0]] print('{}x^{}--{}(mod {}), solution: {} mod {}'.format(a,n,b,m,sols,m)) return sols,m def solveGroup(self,tups): '''tups is a list of tongyu equation groups, like [(a1,b1,m1),(a2,b2,m2)...] and, m1,m2... are all primes ''' mp = {} print('solving group of equations: ') for a,b,m in tups: print('{}x--{}(mod {})'.format(a,b,m)) if m in mp: if mp[m][0]*b!=mp[m][1]*a: self.noSol() return else:mp[m] = (a,b) product = 1 for i in mp.keys(): product *=i sol = [0] for i in mp: 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 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) print() res = solver.solveHigh(1,8,3,11) print() res = solver.solveGroup([(5,11,2),(3,8,5),(4,1,7)])