有没有办法可以矢量化fsolve?

时间:2012-05-31 06:25:43

标签: numpy scipy

我正在尝试将fsolve应用于数组:

from __future__ import division
from math import fsum
from numpy import *
from scipy.optimize import fsolve
from scipy.constants import pi

nu = 0.05
cn = [0]
cn.extend([pi*n - pi/4 for n in range(1, 5 +1)])
b = linspace(200, 600, 400)
a = fsolve(lambda a: 1/b + fsum([1/(b+cn[i]) for i in range(1, 5 +1)]) - nu*(sqrt(a) - 1)**2, 3)

默认情况下不允许:

TypeError: only length-1 arrays can be converted to Python scalars

有没有办法将fsolve应用于数组?

修改

#!/usr/bin/env python

from __future__ import division
import numpy as np
from scipy.optimize import fsolve

nu = np.float64(0.05)

cn = np.pi * np.arange(6) - np.pi / 4.
cn[0] = 0.

b = np.linspace(200, 600, 400)

cn.shape = (6,1)
cn_grid = np.repeat(cn, b.size, axis=1)
K = np.sum(1/(b + cn_grid), axis=0)

f = lambda a: K - nu*(np.sqrt(a) - 1)**2
a0 = 3. * np.ones(K.shape)
a = fsolve(f, a0)

print a

解决它。

2 个答案:

答案 0 :(得分:3)

fsum适用于python标量,所以你应该看numpy进行矢量化。你的方法可能失败了,因为你试图总结一个包含五个numpy数组的列表,而不是五个数字或一个numpy数组。

首先,我将使用numpy重新计算cn

import numpy as np

cn = np.pi * np.arange(6) - np.pi / 4.
cn[0] = 0.

接下来,我将分别计算前一个fsum结果,因为它是一个常量向量。这是一种方式,尽管可能有更有效的方法:

cn.shape = (6,1)
cn_grid = np.repeat(cn, b.size, axis=1)
K = np.sum(1/(b + cn_grid), axis=0)

根据K重新定义您的功能现在应该有效:

f = lambda a: K - nu*(np.sqrt(a) - 1)**2

要使用fsolve查找解决方案,请为其提供适当的初始向量以进行迭代。这使用零向量:

a0 = np.zeros(K.shape)
a = fsolve(f, a0)

或者您可以使用a0 = 3

a0 = 3. * np.ones(K.shape)
a = fsolve(f, a0)

此功能是可逆的,因此您可以针对两个确切的解决方案检查f(a) = 0

a = (1 - np.sqrt(K/nu))**2

a = (1 + np.sqrt(K/nu))**2

fsolve似乎是从a0 = 0开始的第一个解决方案,而a0 = 3的第二个解决方案。

答案 1 :(得分:1)

你可以定义一个最小化的函数(应该是原始函数的平方)然后使用一个简单的最小化器(你最好定义函数的导数):

funcOrig = lambda a: (K - nu*(np.sqrt(a) - 1)**2)
func2 = lambda a: funcOrig(a)**2
dotfunc2 = lambda a: 2*funcOrig(a)* (-nu * 2 * ( np.sqrt(a)-1) * 1./2./np.sqrt(a))
ret = scipy.optimize.fmin_l_bfgs_b(func2, np.ones(400)+1, fprime=dotfunc2, pgtol=1e-20)