我正在尝试在python中实现射击方法,并且遇到有关奇异矩阵的错误消息。我想用边界条件xy''' = -y'y+x^2-1
解决y(1)=1, y(2)=1, y'(2)=4
。我将其转换为一阶方程M(x, y ) y '= f(x, y ),其中:
M = [1 0 0]
[0 1 0]
[0 0 x]
**y** = [ y ]
[ y']
[y'']
f = [ y' ]
[ y'' ]
[-y'y+x^2-1]
我已经按照数字食谱18.1中所述实施了射击方法。常规步骤是:
如果我假设M是可逆的,那么这相对容易解决并且可以按预期工作。但是,我遇到了两个问题,希望能为您解决这些问题提供一些帮助。
A previous answer建议,在第二种奇异情况下,更好地猜测初始条件可能会有所帮助,但是我不确定如何在没有大量蛮力的情况下改善猜测。
这是我的代码:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
### Solving the differential equation xy''' = -y'y+x^2-1
### if x range doesn't include 0, then M is invertible, so equations become:
def fn(y,x):
return np.array([y[1],y[2],(-y[0]*y[1]+x**2-1)/x])
### Boundary values of y(1)=1, y(2)=1, y'(2)=4
x = np.linspace(1.,2.,101)
y0 = np.array([1., 1., 2.]) ### Only the first of these is fixed. The others are variable
sol = np.array([1.,4.]) ### Specify y(2)=1 y'(2)=4
Delta=1
max_itrs = 100
eps = 1e-3
def shoot(y0, Delta, fn, x, sol, eps, max_itrs):
### Throughtout this function, the indexing only works with our specific boundary conditions
### But can be easily modified or generalized to accommodate other cases
for i in range(max_itrs):
F = odeint(fn, y0, x)[-1][:2]-sol ### Define the F "discrepancy" vector at x = 2
if np.linalg.norm(F)>eps:
y0_yp_mod = y0.copy()
y0_yp_mod[1] += Delta ### Augment y'(1) by Delta
F_yp_mod = odeint(fn, y0_yp_mod, x)[-1][:2]-sol
y0_ypp_mod = y0.copy()
y0_ypp_mod[2] += Delta ### Augment y''(1) by Delta
F_ypp_mod = odeint(fn, y0_ypp_mod, x)[-1][:2]-sol
### Compute the Jacobian
j11 = (F_yp_mod[0]-F[0])/Delta
j12 = (F_yp_mod[1]-F[1])/Delta
j21 = (F_ypp_mod[0]-F[0])/Delta
j22 = (F_ypp_mod[1]-F[1])/Delta
jac = np.array([[j11,j12],[j21,j22]])
### Solve for delta V:
d_V = np.linalg.solve(jac,-F)
### Augment our initial conditions by delta V
y0 = np.array([y0[0],y0[1]+d_V[0],y0[2]+d_V[1]])
else:
return y0
print("Failed to achieve convergence after "+str(max_itrs)+" iterations.")
return y0
y0 = shoot(y0, Delta, fn, x, sol, eps, max_itrs)
Y = odeint(fn, y0, x)
plt.plot(x,Y[:,0],c="r",label="y")
plt.plot(x,Y[:,1],c="g",label="y'")
plt.plot(x,Y[:,2],c="b",label="y''")
plt.scatter([x[0]],y0[0],marker="x",c="r")
plt.scatter([x[-1]],sol[0],marker="x",c="r")
plt.scatter([x[-1]],sol[1],marker="x",c="g")
plt.legend()
Here是输出,其行为符合预期