繁体   English   中英

Scipy.optimize.minimize目标函数ValueError

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM