试图找到所有有序对(x,y),使得f(x,y)= 0并且g(x,y)= 0;即,我试图找到多变量函数的根

时间:2015-10-28 16:51:47

标签: python numpy scipy mathematical-optimization

注意:我最初使用chi = 1但是我已将其更改为chi = 0(这是更简单的情况)。

我的方程式f(x,y)和g(x,y)来自以下代码:

import numpy as np
from pylab import *

def stress(X,Y):
    chi = 0
    F = 1
    a = 1
    c = (1.0*a)/(np.sqrt(np.power(X,2)+np.power(Y,2))*1.0)
    A = 0.5*(1 - c**2. + (1 - 4*c**2 + 3*c**4.)*np.cos(2*np.arctan(Y/X)))
    B = 0.5*(1 - c**2. - (1 - 4*c**2 + 3*c**4.)*np.cos(2*np.arctan(Y/X)))
    C = 0.5*(1 + c**2. - (1 + 3*c**4.)*np.cos(2*np.arctan(Y/X)))
    D = 0.5*(1 + c**2. + (1 + 3*c**4.)*np.cos(2*np.arctan(Y/X)))
    E = 0.5*((1 + 2*c**2. - 3*c**4.)*np.sin(2*np.arctan(Y/X)))

    f = 1.0*F*c**2 + (A-1.0*chi*B) # Radial stress
    g = -1.*F*c**2 + (C - 1.0*chi*D) # Tangential stress
    return f,g

def f(X,Y):
    return stress(X,Y)[0]
def g(X,Y):
    return stress(X,Y)[1]

def find_points(X_max,Y_max,X_steps,Y_steps):
    Xs = np.linspace(-X_max,X_max,X_steps)
    Ys = np.linspace(-Y_max,Y_max,Y_steps)

    radials = f(Xs,Ys)
    tangentials = g(Xs,Ys)

    return radials, tangentials

find_points(10,10,100,100)

这将返回f和g的值数组。

我想找到所有(X,Y)有序对,其中f(X,Y)= 0和g(X,Y)= 0.我看着不同的scipy包,我不能&#39 ;找到任何似乎适用于这样的多变量函数的东西。另外,我现在的答案是以数组形式返回的,所以我可以使用像np.where()这样的东西吗?这个问题是因为我存储了确切的值,所以我不一定会看到f(x,y)或g(x,y)明确等于零。我的最终目标是绘制这些点。此外,到目前为止,我所做的事情是否有理由将X和Y作为这些范围内的空间?

谢谢

更新:我回过头使用我在类似问题上找到的指南编写了一个小脚本,请参阅This link。我使用了scipy.optimize。

from scipy import optimize

def equations(p):
    X, Y = p
    a = 1
    F = 1
    chi = 0
    c = (1.0*a)/(np.sqrt(np.power(X,2)+np.power(Y,2))*1.0)
    A = 0.5*(1 - c**2. + (1 - 4*c**2 + 3*c**4.)*np.cos(2*np.arctan(Y/X)))
    B = 0.5*(1 - c**2. - (1 - 4*c**2 + 3*c**4.)*np.cos(2*np.arctan(Y/X)))
    C = 0.5*(1 + c**2. - (1 + 3*c**4.)*np.cos(2*np.arctan(Y/X)))
    D = 0.5*(1 + c**2. + (1 + 3*c**4.)*np.cos(2*np.arctan(Y/X)))

    f = 1.0*F*c**2 + (A-1.0*chi*B) # Radial stress
    g = -1.*F*c**2 + (C - 1.0*chi*D) # Tangential stress
    return (f,g)

X, Y =  optimize.fsolve(equations, (1, 1))

print equations((X, Y))

这要求我进行不同的初步猜测以获得不同的(X,Y)根。如果能以某种方式解决所有解决方案,那将是非常棒的。而且,我得到的答案似乎有点不对劲。 再次感谢。

注意: 在将它们转换为笛卡尔坐标之前,原始方程式如下:

def stress(R,theta):
    chi = 0
    F = 1
    a = 1
    c = (1.0*a)/(R*1.0)
    A = 0.5*(1 - c**2. + (1 - 4*c**2 + 3*c**4.)*np.cos(2*theta))
    B = 0.5*(1 - c**2. - (1 - 4*c**2 + 3*c**4.)*np.cos(2*theta))
    C = 0.5*(1 + c**2. - (1 + 3*c**4.)*np.cos(2*theta))
    D = 0.5*(1 + c**2. + (1 + 3*c**4.)*np.cos(2*theta))
    E = 0.5*((1 + 2*c**2. - 3*c**4.)*np.sin(2*theta))

    f = 1.0*F*c**2. + (A-1.0*chi*B) # Radial stress
    g = -1.0*F*c**2. + (C-1.0*chi*D) # Tangential stress
    return f,g

也许这有助于解决与方程式的arctan(Y / X)方面的一些混淆。

1 个答案:

答案 0 :(得分:1)

正如@Azad已在评论中指出,您可能需要scipy.optimize才能完成大部分工作。具体而言,scipy.optimize.fsolvescipy.optimize.root。由于后者似乎更为笼统,我将证明这一点。由于它可以使用多种方法,请查看帮助。

这两个函数都能够找到从R ^ n映射到R ^ m的函数的根,即多元向量值函数。如果你考虑你的stress函数,那就是你拥有的函数:它从R ^ 2映射到R ^ 2。为清楚起见,您甚至可以将其定义为

def stress2(Rvec):
    X,Y=Rvec
    chi = 1
    F = 1
    a = 1
    c = (1.0*a)/(np.sqrt(np.power(X,2)+np.power(Y,2))*1.0)
    A = 0.5*(1 - c**2. + (1 - 4*c**2 + 3*c**4.)*np.cos(2*np.arctan(Y/X)))
    B = 0.5*(1 - c**2. - (1 - 4*c**2 + 3*c**4.)*np.cos(2*np.arctan(Y/X)))
    C = 0.5*(1 + c**2. - (1 + 3*c**4.)*np.cos(2*np.arctan(Y/X)))
    D = 0.5*(1 + c**2. + (1 + 3*c**4.)*np.cos(2*np.arctan(Y/X)))
    E = 0.5*((1 + 2*c**2. - 3*c**4.)*np.sin(2*np.arctan(Y/X)))
    f = 1.0*F*c**2 + (A-1.0*chi*B) # Radial stress
    g = -1.*F*c**2 + (C - 1.0*chi*D) # Tangential stress
    return f,g

现在,通过此定义,您只需调用

即可
import scipy.optimize as opt
sol=opt.root(stress2,[0.5,0.5])

将尝试从[0.5,0.5]开始寻找零。请注意,向量值函数的根恰好是两个组件都为零的位置,这就是你所追求的。

返回OptimizeResult如下所示:

In [224]: sol
Out[224]: 
  status: 1
 success: True
     qtf: array([  2.94481987e-09,   4.76366933e-25])
    nfev: 47
       r: array([ -7.62669534e-06,   7.62669532e-06,   2.16965211e-21])
     fun: array([  2.25125258e-10,  -2.25125258e-10])
       x: array([ 167337.87789902,  167337.87786433])
 message: 'The solution converged.'
    fjac: array([[-0.70710678,  0.70710678],
       [ 0.70710678,  0.70710678]])

它有很多信息。首先,sol.status会告诉您它是否成功融合。这是最重要的输出:你的根和发现非常敏感的可能性取决于你的出发点。如果您在示例中尝试使用X=0Y=0的起点,则会发现找到根目录时遇到困难。

如果您有根,sol.x会告诉您坐标,sol.fun会告诉您函数的值(如果sol.status==1,则接近0 })。

现在,正如您也注意到的,每个电话会告诉您最多一个根。要找到多个根,您无法避免搜索它们。您可以通过选择X,Y网格,从那里开始root/fsolve并检查搜索是否成功来执行此操作。如果是的话:存储后处理的值。

不幸的是,找到非线性多变量函数的零点并不容易,所以你迟早要弄清楚。

更新

你遇到了麻烦。考虑:

v=np.linspace(-10,10,100)
X,Y=np.meshgrid(v,v)

fig = plt.figure()
hc=plt.contourf(X,Y,stress2([X,Y])[0].clip(-1,1),levels=np.linspace(-1,1,20))
plt.contour(X,Y,stress2([X,Y])[0].clip(-1,1),levels=[0],color=(1,0,0))
plt.colorbar(hc)

和其他功能相同。以下是函数的xy组件的外观:

x component y component

它们都有一些类似双曲线的曲线。 似乎相同。这个数字强烈表明你的函数为零的点有:两个组件。这与数值根寻找算法一样糟糕,因为没有明确的(孤立的)零。

我建议在X==Y的情况下在纸上查看你的功能,你可能确实看到你的功能在那里消失了,至少是渐近的。

UPDATE2

您添加了函数的原始极坐标形式。虽然我看不到你出错的地方(除了使用np.arctan而不是np.arctan2,但这似乎无法解决问题),我尝试绘制你的极地函数:

def stress_polar(Rvec):
    R,theta=Rvec
    chi = 0
    F = 1
    a = 1
    c = (1.0*a)/(R*1.0)                                   
    A = 0.5*(1 - c**2. + (1 - 4*c**2 + 3*c**4.)*np.cos(2*theta))
    B = 0.5*(1 - c**2. - (1 - 4*c**2 + 3*c**4.)*np.cos(2*theta))
    C = 0.5*(1 + c**2. - (1 + 3*c**4.)*np.cos(2*theta))
    D = 0.5*(1 + c**2. + (1 + 3*c**4.)*np.cos(2*theta))
    E = 0.5*((1 + 2*c**2. - 3*c**4.)*np.sin(2*theta))
    f = 1.0*F*c**2. + (A-1.0*chi*B)
    g = -1.0*F*c**2. + (C-1.0*chi*D)
    return f,g

v1=np.linspace(0.01,10,100)
v2=np.linspace(-np.pi,np.pi,100)
R,theta=np.meshgrid(v1,v2)

fig = plt.figure()
ax=plt.subplot(111, polar=True)
hc=plt.contourf(theta,R,stress_polar([R,theta])[0].clip(-1,1),levels=np.linspace(-1,1,20))
plt.contour(theta,R,stress_polar([R,theta])[0].clip(-1,1),levels=[0],color=(1,0,0))
plt.colorbar(hc)

和切向分量相同。请注意,极坐标图需要先theta,然后R。结果:

radial component tangential component

这显示了一幅截然不同的图片,对径向分量的零点有一定的支持。现在,我之前从未在matplotlib中使用极坐标图,因此在绘图过程中我也可能搞砸了。但是可能值得查看由极坐标和笛卡尔函数计算的A,B,C,D参数,以确保它们计算相同的东西。