algorithm-in-python/computationalMethod/tongyu_equation.py

164 lines
4.4 KiB
Python
Raw Normal View History

2018-10-02 21:24:06 +08:00
''' mbinary
#########################################################################
# File : tongyu_equation.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.coding.me
# Github: https://github.com/mbinary
# Created Time: 2018-10-02 21:14
# Description:
#########################################################################
'''
# created by mbinary @2018-3-4
# description: solve tongyu equation
# notice that i use -- to repr tongyu symbol
from isPrime import isPrime,primes
from operator import mul, and_
from functools import reduce,partial
import re
def primeFactoize(x):
'''质因数分解 , ret {p:r}'''
if isPrime(x):return {x:1}
mp={}
for i in primes:
if x==1:break
ct=0
while x%i==0:
ct+=1
x//=i
if ct!=0:mp[i]=ct
return mp
def xgcd(a,b):
'''ax+by=gcd(a,b) ,用辗转相除法得到gcd,x,y'''
def _xgcd(a,b):
if b==0:return a,1,0
gcd,x,y=_xgcd(b,a%b)
return gcd,y,x-y*a//b
if a<b:
g,x,y = _xgcd(b,a)
return g,y,x
return _xgcd(a,b)
def gcd(a,b):
return a if b==0 else gcd(b,a%b)
def lcm(a,b):
return a*b//gcd(a,b)
def euler(x):
mp = primeFactoize(x)
fac = [1-1/i for i in mp]
return round(reduce(mul,fac,x))
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'''
phi = euler(m)
mp = primeFactoize(phi)
checkLst = [phi//i for i in mp]
return [i for i in range(2,num) \
if reduce(and_,[(i**n-1)%m !=0 for n in checkLst])]
def minG(m):
phi = euler(m)
mp = primeFactoize(phi)
checkLst = [phi//i for i in mp]
i=2
while 1:
if reduce(and_,[(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
return ([(sol+i*m0)%m for i in range(g)],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 solvePoly(self,m,mp):
''' mod m, mp:{index:coef} is a dict of the polynomials' coefficient and index'''
''' g = minG(m)
ind_mp = ind(m,g)
li = []
for i in mp:
solve
'''
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
print(n,tmp)
sol = self.solveLinear(n,tmp,euler(m))
re_mp = {j:i for i ,j in ind_mp.items()}
print(sol)
return [re_mp[i] for i in sol[0]],m
def solveGroup(tups):
'''tups is a list of tongyu equation groups, like
[(a1,b1,m1),(a2,b2,m2)...]
and, m1,m2... are all primes
'''
mp = {}
for a,b,m in tups:
if m in mp:
if mp[m][0]*b!=mp[m][1]*a:
self.noSol()
return
else:mp[m] = (a,b)
product= reduce(lambda i,j:i*j, mp.keys(), 1)
sol = 0
for i in mp:
x = self.solveLinear(product//i*mp[i][0],1,i)
sol+= x*product//i*mp[i][1]
sol%=m
return ([sol],m)
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)
print(solver.solveHigh(1,8,3,11))