以下のプログラムは、方程式を関数f(x)=0で与えたときに、指定した範囲内で解を全て求めることを意図したものである。
基本は、範囲をdivの数で分割し、それぞれの領域でScipyのbrentqを適用し、解を集めている。
しかし、関数f(x)が解の前後で符号を変えないケースがあり、このような場合の解を求めるためにNewton法も用いている。
f1d_solve_range.py
import numpy as np
def f1d_solve_range(f,range,div=1000,args=(),newtontirigger=1.E-4):
"""
Solve f(x)=0 to otain all solutions between range
range is devided by div to find solution in each subrange
When |f(x)| < 1.E-4, Newton Method is also used
because brentq can not find solution if f(x) does not change sign at a solution.
"""
from scipy.optimize import brentq,newton
x=np.linspace(range[0],range[1],div)
dx=x[1]-x[0]
#solution 1 by bysection
solution1=[]
for x0 in x[:-1]:
try:
a=brentq(f,x0,x0+dx,args=args)
solution1.append(a)
except:
continue
solution1=np.unique(solution1)
# solution2 by Netwon method just in case f(a) f(b) has same sign
solution2=[]
for x0 in x:
if np.abs(f(x0,*args))<newtontirigger:
b=newton(f,x0,args=args)
solution2.append(b)
solution2=np.unique(solution2)
solution2.clip(range[0],range[1]) # remove out of range
# final solution
solution=solution1
for s2 in solution2:
if np.alltrue(np.abs(solution-s2)>dx):
print "New solution added by Newtonian!:",s2
solution=np.append(solution,s2)
return np.sort(solution)
例1
#example 1
def f(x):
return x**3
print "ex1=",f1d_solve_range(f,(-10.,10))
結果:
ex1= [ 0.]
例2
#example 2
def f(x):
return x**3-x
print "ex2=",f1d_solve_range(f,(-10.,10))
結果:ex2= [-1. 0. 1.]
例3
#example 3
def f(x):
return x**3-x**2
print "ex3=",f1d_solve_range(f,(-10.,10))
x=np.linspace(-2,2,100)
結果:ex3= New solution added by Newtonian!: 1.92717530048e-08
[ 1.92717530e-08 1.00000000e+00]
解の前後で符号を変えないケースでNewton法で解が求まっている。
のグラフを参照
例4
#example 4
def f(x):
return x**2+1
print "ex4=",f1d_solve_range(f,(-10.,10))
結果:
ex4= []
解なし。例5
#example 5
def f(x,a,b,c):
return a*x**2 + b*x +c
print "ex5=",f1d_solve_range(f,(-10.,10),args=(1,2,1))
結果:
ex5= New solution added by Newtonian!: -0.999999982865
[-0.99999998]

0 件のコメント:
コメントを投稿