■4.1 非線形方程式の種類 表4-1 グラフ描画のための関数(graph.pyとして保存) from tkinter import * import math def initTk(Title):#Tkモジュール起動 root=Tk();root.title(Title); return root def initCanvas(root,W,H):#キャンパスの定義 canvas=Canvas(root,width=W,height=H) canvas.pack(); return canvas #■目盛り表示 def drawScale(canvas,X0,Y0,X1,Y1,Xsc,Ysc,Xmin,Ymin,dx,dy,xb,yb, xl,yl,nx,ny,format="%.1f",yformat="%.1f"): # canvas : canvasオブジェクト # X0, Y0 : 描画グラフの左上隅座標 # X1   : 左側からのY目盛ラベル表示相対位置 # Y1   : 最下端からのX目盛ラベル表示相対位置 # Xsc  : X目盛の描画間隔 # Ysc  : Y目盛の描画間隔 # Xmin : Xの最小値 # Ymin : Yの最小値 # dx, dy : X, Y の刻み幅 # xb, yb : 太線にする間隔(本数) # xl, yl : ラベル表示する間隔(本数) # nx, ny : 目盛りの本数 # xformat: Xラベルの表示書式 # yformat: Yラベルの表示書式 CL3="#000000"; V=Ymin+ny*dy; Xmax=X0+Xsc*nx; Ymax=Y0+Ysc*ny for i in range(ny+1):#縦方向目盛り表示 Y=i*Ysc+Y0; CL="#777777" if i % yb: CL="#CCCCCC" canvas.create_line(X0,Y,Xmax,Y,width=1,fill=CL) if i % yl==0: canvas.create_text(X0-X1,Y,text=(yformat % (V+1E-7)), font=('Times',8),fill=CL3) V-=dy V=Xmin for i in range(nx+1):#横方向目盛り表示 X=i*Xsc+X0; CL="#777777" if i % xb: CL="#CCCCCC" canvas.create_line(X,Y0,X,Ymax,width=1,fill=CL) if i % xl==0: canvas.create_text(X,Ymax+Y1,text=(xformat % V), font=('Times',8),fill=CL3) V+=dx canvas.create_rectangle(X0,Y0,Xmax,Ymax, width=1,fill="",outline="black") #■値の描画 def drawV(canvas,X1,Y1,X2,Y2,CL,width=3, X0=30,Y0=120,Xscale=100, Yscale=100): XX1=X1*Xscale+X0;YY1=Y0-Y1*Yscale XX2=X2*Xscale+X0;YY2=Y0-Y2*Yscale canvas.create_line(XX1,YY1,XX2,YY2,width=width,fill=CL) ■4.2 実根の求め方 表4-2 f (x) = x2−4x + 1のグラフ化 from graph import * root=initTk("Numerical Analysis") canvas=initCanvas(root,440,240) canvas.pack() drawScale(canvas, 30,20, 15, 10, 20, 20, 0, -4, 0.5, 1, 2, 2, 2,1, 8, 6,"%d","%.1f") def fn(X):return X*X-4*X+1 X2=0; Y2=fn(X2); DX=0.1 for i in range(40): X1=X2; Y1=Y2; X2+=DX; Y2=fn(X2) drawV(canvas, X1,Y1,X2,Y2,"red", X0=30,Y0=60,Xscale=40,Yscale=20) 表4-3 繰返し法による実根 from graph import * root=initTk("Numerical Analysis") canvas=initCanvas(root,440,240) canvas.pack() drawScale(canvas, 30,20, 15, 10, 20, 10, 0, 0, 1, 0.02, 5, 5, 1, 5, 10, 15,"%d","%.2f") #以下繰り返し法 def fn(X):return (X*X + 1)/4 #この部分に漸化式を書く def IterativeMethod(iterMax): X1 = 0; R=[]; R.append(X1) for i in range(iterMax): X2 = fn(X1);R.append(X2); X1 = X2 return R #以下グラフ化 R=IterativeMethod(10);TV=2-math.sqrt(3)#TV:厳密解 for i in range(1, len(R)): drawV(canvas, i-1,TV,i,TV,"blue",width=1, X0=30,Y0=170,Xscale=20,Yscale=500) drawV(canvas, i-1,R[i-1],i,R[i],"red", X0=30,Y0=170,Xscale=20,Yscale=500) 表4-4 繰返し法による実根 from graph import * root=initTk("Numerical Analysis") canvas=initCanvas(root,440,240) canvas.pack() drawScale(canvas, 30,20, 15, 10, 20, 20, 0, -1, 1, 0.5, 5, 5, 1, 1, 10, 5,"%d","%.1f") #■以下繰り返し法 def fn(X):return (-2*X*X-1)/5 #この部分に漸化式を書く def IterativeMethod(iterMax): X1 = 1; R=[]; R.append(X1) for i in range(iterMax): X2 = fn(X1);R.append(X2); X1 = X2 return R def fn2(X): return 1/(2*(X+1)) #■以下グラフ化 R=IterativeMethod(10);TV=2-math.sqrt(3)#TV:厳密解 print(R) TV=(1+math.sqrt(17))/8 for i in range(1, len(R)): drawV(canvas, i-1,TV,i,TV,"#770077",width=1, X0=30,Y0=80,Xscale=20,Yscale=40) drawV(canvas, i-1,R[i-1],i,R[i],"red", X0=30,Y0=80,Xscale=20,Yscale=40) drawV(canvas, i-1,fn2(R[i-1]),i,fn2(R[i]),"blue", X0=30,Y0=80,Xscale=20,Yscale=40) 表4-5 区間縮小法 from graph import * root=initTk("Numerical Analysis") canvas=initCanvas(root,440,240) canvas.pack() drawScale(canvas, 30,20, 15, 10, 20, 20, 0, -1, 1, 1, 5, 5, 1, 1, 10, 6,"%d","%.f") #■以下区分縮小法 def fn(X):return X*X - X - 2 # ここに解くべき関数を書く def DiminishingInterval(iterMax,minX, maxM,EPS): X1 = minX; X2 = maxM; R=[] for i in range(iterMax): X = (X1+X2)/2; Y = fn(X) R.append([X1,X2,X,Y])#Xが求めるべき値 print(X,X1,X2,Y) if abs(Y) < EPS: return R elif Y > 0 : X2 = X else : X1 = X E = abs(X2 - X1) if E= Max : Max = ab; IR = i if Max < ESP : print("解を求めることができません") return [] if IR != k : D=A[k]; A[k]=A[IR]; A[IR]=D #---ピボット入れ替えここまで for i in range(k + 1,N): ALFA = A[i][k] / A[k][k] for j in range(k + 1,N1):A[i][j]-=ALFA*A[k][j] B=array(N,1) for i in range(N-1, -1, -1):# 後退代入 T = A[i][N] for j in range(i + 1,N):T -=A[i][j] * A[j][N] A[i][N] = T / A[i][i]; B[i][0]=A[i][N] return B #■以下連立非線形方程式 def setJACOBI(A): JA=array(2,3) #ヤコビアン設定 JA[0][0] = 2*A[0]+A[1]; JA[0][1] = A[0]+2* A[1] JA[1][0] = 1 ; JA[1][1] = -1 JA[0][2] = -(A[0]*A[0] + A[0]*A[1] + A[1]*A[1] - 1)# - f(X) JA[1][2] = -(A[0] - A[1]) return JA def nonLinearEq(MAT, iterMax,EPS): N=len(MAT);A=array(N) for i in range(N): A[i]=MAT[i] R=[]; R.append([A[0],-0.4]) #h1初期値=-0.4は適当な値 for i in range(iterMax): JACOBI=setJACOBI(A); B=GaussianELMPivot(JACOBI) if B==[]: return R E = 0 #補正値の加算,収束判定 for i in range(N): E += B[i][0]*B[i][0]; A[i] = A[i]+B[i][0] R.append([A[0],B[i][0]]) if E0 : S= form % RE + " +" + (form % IM)+" i" else: S= form % RE + " -" + (form % abs(IM))+" i" print(S) #■以下, ニュートン法による複数の解 def fn(X):return X*X*X + 2*X*X + 2*X+ 1 # ここに解くべき関数を書く def dfn(X):return 3*X*X +4*X+2 # ここに微分式を書く def cabs(X): return math.sqrt(X.real*X.real+X.imag*X.imag) def updDiff(DF,F,X,k,Z): if k >= 2 : DFD = complex(0, 0) # F'-F*Σ(1/(X-Zi)) (i=1〜N-1)の計算 for i in range(k-1): DFD +=1/(X-Z[i]) DF-=F*DFD return DF def multiComplexNewton(N): Z=array(N) EPS = 0.00001; iterMax = 500 for k in range(N): X = complex(1, 1) for Iter in range(iterMax): F = fn(X); E = cabs(F) if E0 : S= form % RE + " +" + (form % IM)+" i" else: S= form % RE + " -" + (form % abs(IM))+" i" print(S) #----------------------以下、DKA法---------------------------- def cabs(X): return math.sqrt(X.real*X.real+X.imag*X.imag) def initFactor(A, N):# 係数の正規化 for j in range(1,N+1):A[j] /= A[0] return A def initRad(A, N): #初期値用半径の計算 R0 = 0 for j in range(2,N+1): Rn = N * math.pow(abs(A[j]),1.0/j) if Rn > R0: R0 = Rn return R0 def compInit(R0, N): #初期値計算 X=array(N); Pi=math.pi for j in range(N): Th = 2.0*Pi*j/N + 0.5*Pi/N X[j] = R0*complex(math.cos(Th),math.sin(Th)) return X def DKA(A, delta,iterMax):#DKA法 N=len(A)-1; A=initFactor(A,N);X=compInit(initRad(A, N), N) for i in range(iterMax): maxFx = 0 for j in range(N): Fx = 1; Xkj = 1; beforX= X[j] for k in range(N): Fx = Fx* beforX+ A[k + 1] if k != j: Xkj *= (beforX- X[k]) Adj = Fx/Xkj; X[j] = beforX-Adj; E = cabs(Fx) if E > maxFx: maxFx = E if maxFx=0: V=math.sqrt(D) if P<0:r1=(-P+V)/2 #減算による桁落ち対策 else: r1=(-P-V)/2 r2 = Q / r1 return [complex(r1,0),complex(r2,0)] else: V=math.sqrt(-D) #虚数項 return [complex(-P/2,V/2),complex(-P/2,-V/2)] def bairstow(a,n):#■ベアストウ法によるPQ計算 B=array(n+1); C=array(n+1);EPS=0.000001 P=1; Q=1; DP=1; DQ=1 #最初の差は大きな値とする while abs(DP)>EPS or abs(DQ)>EPS:#収れんの判定 B[0] = A[0]; B[1] = A[1] - P*B[0] for k in range(2,n+1): B[k] = A[k] - P*B[k-1] - Q*B[k-2] C[0] = B[0]; C[1] = B[1] - P*C[0] for k in range(2,n+1): C[k] = B[k] - P*C[k-1] - Q*C[k-2] e =C[n-2 ]*C[n-2] - C[n-3]*(C[n-1]-B[n-1]) DP=(B[n-1]*C[n-2] - B[n ]*C[n-3])/e DQ=(B[n ]*C[n-2] - B[n-1]*(C[n-1]-B[n-1]))/e P+=DP; Q+=DQ return [P,Q,B] def solEq(A,n):#■N次方程式の解 A=copy.copy(A); n=len(A)-1; r=[] while n>0: if n==1: r.append(complex(-A[1]/A[0],0))#一次式 if n==2: #二次式 rr=root(A[1],A[2]) r.append(rr[0]); r.append(rr[1]) else: #N次式 rr=bairstow(A,n); A=rr[2] rr=root(rr[0],rr[1]) r.append(rr[0]); r.append(rr[1]) n-=2 return r def printCL(A, form="%8.5f"): for i in range(len(A)): if A[i].imag==0: S= form % A[i].real elif A[i].imag>0 : S= form % A[i].real+" +"+form % A[i].imag+"i" else: S=form % A[i].real+" -"+form % abs(A[i].imag)+"i" print(S) A=[1,-8,-6,-32,40] printCL(solEq(A,4))