![](/img/trans.png)
[英]Apply constraints to the objective function in scipy.optimize.minimize? Such as 0 <= objective <= 1
[英]Scipy.optimize.minimize objective function ValueError
我正在使用scipy.optimize.minimize來解決帶有9個自由變量的小型優化問題。 我的目標函數基本上是另一個函數的包裝器,如果我評估目標函數,則返回類型為'numpy.float32'...這是標量嗎? 但是,嘗試使用最小化功能時出現以下錯誤:
raise ValueError("Objective function must return a scalar")
ValueError: Objective function must return a scalar
是否可以將目標函數包裝在另一個函數周圍? 其他函數參數是全局聲明的,但是如果這樣做不合適,我可以將它們硬編碼到beam_shear函數中。
相關代碼段:
from numpy import array, shape, newaxis, isnan, arange, zeros, dot, linspace
from numpy import pi, cross, tile, arccos,sin, cos, sum, atleast_2d, asarray, float32, ones
from numpy import sum, reshape
from scipy.optimize import minimize
def normrow(A):
A = atleast_2d(asarray(A, dtype=float32))
return (sum(A ** 2, axis=1) ** 0.5).reshape((-1, 1))
def beam_shear(xyz, pt0, pt1, pt2, x):
# will not work for overlapping nodes...
s = zeros((len(xyz), 3))
xyz_pt0 = xyz[pt0, :]
xyz_pt1 = xyz[pt1, :]
xyz_pt2 = xyz[pt2, :]
e01 = xyz_pt1 - xyz_pt0
e12 = xyz_pt2 - xyz_pt1
e02 = xyz_pt2 - xyz_pt0
trip_norm = cross(e01, e12)
mu = 0.5 * (xyz_pt2 - xyz_pt1)
l01 = normrow(e01)
l12 = normrow(e12)
l02 = normrow(e02)
l_tn = normrow(trip_norm)
l_mu = normrow(mu)
a = arccos((l01**2 + l12**2 - l02**2) / (2 * l01 * l12))
k = 2 * sin(a) / l02 # discrete curvature
ex = trip_norm / tile(l_tn, (1, 3))
ez = mu / tile(l_mu, (1, 3))
ey = cross(ez, ex)
kb = tile(k / l_tn, (1, 3)) * trip_norm
kx = tile(sum(kb * ex, 1)[:, newaxis], (1, 3)) * ex
m = x * kx
cma = cross(m, e01)
cmb = cross(m, e12)
ua = cma / tile(normrow(cma), (1, 3))
ub = cmb / tile(normrow(cmb), (1, 3))
c1 = cross(e01, ua)
c2 = cross(e12, ub)
l_c1 = normrow(c1)
l_c2 = normrow(c2)
ms = sum(m**2, 1)[:, newaxis]
Sa = ua * tile(ms * l_c1 / (l01 * sum(m * c1, 1)[:, newaxis]), (1, 3))
Sb = ub * tile(ms * l_c2 / (l12 * sum(m * c2, 1)[:, newaxis]), (1, 3))
Sa[isnan(Sa)] = 0
Sb[isnan(Sb)] = 0
s[pt0, :] += Sa
s[pt1, :] -= Sa + Sb
s[pt2, :] += Sb
return s
def cross_section_obj(x):
s = beam_shear(xyz, pt0, pt1, pt2, x)
l_s = normrow(s)
val = sum(l_s)
return val
xyz = array([[ 0, 0., 0.],
[ 0.16179067, 0.24172157, 0.],
[ 0.33933063, 0.47210142, 0.],
[ 0.53460629, 0.68761389, 0.],
[ 0.75000537, 0.88293512, 0.],
[ 0.98816469, 1.04956383, 0.],
[ 1.25096091, 1.17319961, 0.],
[ 1.5352774, 1.22977204, 0.],
[ 1.82109752, 1.18695051, 0.],
[ 2.06513705, 1.03245579, 0.],
[ 2.23725517, 0.79943842, 0.]])
pt0 = array([0, 1, 2, 3, 4, 5, 6, 7, 8])
pt1 = array([1, 2, 3, 4, 5, 6, 7, 8, 9])
pt2 = array([2, 3, 4, 5, 6, 7, 8, 9, 10])
EIx = (ones(len(pt1)) * 12.75).reshape(-1, 1)
bounds = []
for i in range(len(EIx)):
bounds.append((EIx[i][0], EIx[i][0] * 100))
print(type(cross_section_obj(EIx)))
res = minimize(cross_section_obj, EIx, method='SLSQP', bounds=bounds)
正如之前所提:
print(type(cross_section_obj(EIx)))
返回:
<type 'numpy.float32'>
EIx是優化的初始值集,它是形狀(9,1)的數組。
您可能要看看利用scipy.optimize.minimize和具有不同形狀的多個變量 。 需要理解的重要一點是,如果要對數組使用最小化,則應傳入展平版本,然后重塑形狀。 因此,我總是將所需形狀作為最小化函數的參數之一。 在您的情況下,我會這樣做:
def cross_section_obj(x, *args):
xyz, pt0, pt1, pt2, shape = args
x = x.reshape(shape)
s = beam_shear(xyz, pt0, pt1, pt2, x)
l_s = normrow(s)
val = sum(l_s)
return val
然后,您的minimize
調用將發生如下變化:
res = minimize(cross_section_obj, EIx.flatten(), method='SLSQP',
bounds=bounds, args=(xyz, pt0, pt1, pt2, EIx.shape))
參數值的數組EIx
是二維的。 它的形狀為(9,1)。 在最小化過程中,此數組在第一次迭代后變為一維。 但是,如果x
為一維,則函數beam_shear
不起作用。
您可以通過將cross_section
更改為以下內容來解決此問題:
def cross_section_obj(x):
x = x.reshape((-1,1))
s = beam_shear(xyz, pt0, pt1, pt2, x)
l_s = normrow(s)
val = sum(l_s)
return val
該代碼隨后運行,但是當然您需要仔細檢查這是否是您真正想要計算的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.