在scipy minimize中添加多个约束条件,是否可以自动生成约束条件字典列表?

10
有没有办法在scipy.minimize中自动生成多个约束条件的字典列表?当我使用以下代码时(其中约束条件列表是相同环上的sage多元多项式列表)
cons = [{'type': 'eq', 'fun': lambda s: ((constraint[0])(*s))},
        {'type': 'eq', 'fun': lambda s: ((constraint[1])(*s))},
        {'type': 'eq', 'fun': lambda s: ((constraint[2])(*s))},
        {'type': 'eq', 'fun': lambda s: ((constraint[3])(*s))}]

y0 = [.5 for xx in x]
bnds = tuple([(0.0, 1.0) for xx in x])
ssoln = scipy.optimize.minimize(HH, y0, jac=dHH, method='SLSQP', bounds=bnds, constraints=cons)
print ssoln

我的输出是

status: 0
 success: True
    njev: 14
    nfev: 22
     fun: -2.2669026273652237
       x: array([ 0.034829615490635,  0.933405952554424,  0.93340765416238 ,
        0.093323548109654,  0.335713397575351,  0.413107862378296])
 message: 'Optimization terminated successfully.'
     jac: array([-3.321836605297572,  2.640225014918886,  2.640252390205999,
       -2.273713195767229, -0.682455873949375, -0.351132324172705,  0.               ])
     nit: 14

然而,如果我尝试通过

cons=[]
for ii in range(len(constraint)):
    cons.append({'type': 'eq', 'fun': lambda s:  ((constraint[ii])(*s))})

最小化失败与

status: 6
 success: False
    njev: 1
    nfev: 1
     fun: -4.1588830833596715
       x: array([ 0.5,  0.5,  0.5,  0.5,  0.5,  0.5])
 message: 'Singular matrix C in LSQ subproblem'
     jac: array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.])
     nit: 1
我的聪明多项式列表可能会因问题而异,长度和多项式数量都可能改变。我不想为每个问题都硬编码给定上面的 cons 字典列表。有没有一种自动化的方法?
以下代码可以工作,但是我理解 eval 函数不是最佳实践。
str1='{\'type\': \'eq\', \'fun\': lambda s: ((constraint['
str2='])(*s))},'
mystr='['
for ii in range(len(constraint)):
    mystr=mystr+str1+str(ii)+str2
mystr=mystr+']'
cons = eval(mystr)

1
我最近也遇到了这个问题。你有没有找到不涉及字符串评估的解决方案? - Ryan
2个回答

5
问题出在你的循环中。lambda运算符执行所谓的惰性求值。在你的循环结束时,lambda表达式对最后一个ii的值进行了函数处理,而不是对每个索引进行处理。
要执行严格的评估,可以使用来自Python functools模块(在Python 2Python 3)的partial对象。
举个例子,在使用lambda时:
constraint = (lambda x: x, lambda x: x**2, lambda x: x**3, lambda x: x**4)

cons=[]
for ii in range(len(constraint)):
    # lambda s will evaluate the last value of ii
    cons.append({'type': 'eq', 'fun': lambda s: ((constraint[ii])(s))})

print([i['fun'](2) for i in cons])
# The value of ii is 3, so it will always call lambda x: x**4
>> [16, 16, 16, 16]

from functools import partial

def f_constraint(s, index):
    return constraint[index](s)

cons=[]
for ii in range(len(constraint)):
    # the value of ii is set in each loop
    cons.append({'type': 'eq', 'fun': partial(f_constraint, index=ii)})

print([i['fun'](2) for i in cons])
>> [2, 4, 8, 16]

根据您的定义,将s替换为*s:

from functools import partial

def f_constraint(s, index):
    return constraint[index](*s)

cons=[]
for ii in range(len(constraint)):
    cons.append({'type': 'eq', 'fun': partial(f_constraint, index=ii)})

希望能帮到你!

0
def wrapper(f, *add_args):
  def inner(*args):
    lt_args=list(args)
    lt_args.extend(add_args)#this arguments will be thus added after so see the positional argument of the parent function to 
    
    return f(*lt_args)
  return inner



def constraint(M,i):
  global bb
  return M - bb[i] 

lt_fn=[]
# const=wrapper(const,)
lt_fn=[wrapper(constraint,i) for i in range(len(bb))]


[f(100) for f in lt_fn]

这将执行像inner(100) inner(100) inner(100) inner(100) inner(100)__> constraint(100,0),constraint(100,1),constraint(100,2),constraint(100,3)constraint(100,4)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接