问题描述
我需要优化不同底物与不同产品的混合。每种底物的量应加在一起以达到产品的 C、P、N、Si 组分的最佳比例。 从 4 种基质中,我需要找到 2 种产品的完美比例。 我可以单独优化功能,但我希望将所有功能都集中在一个目标功能中。
我尝试返回不同的优化问题,但收到错误“目标函数必须返回标量”
希望有人能帮助我。
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from scipy.optimize import fsolve
class substrat_1:
C = 0.93
N = 0.005
P = 0.031
Si = 0.034
class substrat_2:
C = 0.523
N = 0.3
P = 0.123
Si = 0.054
class substrat_3:
C = 0.257
N = 0.176
P = 0.461
Si = 0.106
class substrat_4:
C = 0.694
N = 0.005
P = 0.003
Si = 0.298
class sort_1:
C = 0.7
N = 0.15
P = 0.05
Si = 0.1
class sort_2:
C = 0.8
N = 0.03
P = 0.1
Si = 0.07
y[0] substrat_1 -> sort_1
y[1] substrat_2 -> sort_1
y[2] substrat_3 -> sort_1
y[3] substrat_4 -> sort_1
y[4] substrat_1 -> sort_2
y[5] substrat_2 -> sort_2
y[6] substrat_3 -> sort_2
y[7] substrat_4 -> sort_2
def targetFun1(y):
amount_sort1_C = substrat_1.C*y[0] + substrat_2.C*y[1] + substrat_3.C*y[2] + substrat_4.C*y[3]
amount_sort1_N = substrat_1.N*y[0] + substrat_2.N*y[1] + substrat_3.N*y[2] + substrat_4.N*y[3]
amount_sort1_P = substrat_1.P*y[0] + substrat_2.P*y[1] + substrat_3.P*y[2] + substrat_4.P*y[3]
amount_sort1_Si = substrat_1.Si*y[0] + substrat_2.Si*y[1] + substrat_3.Si*y[2] + substrat_4.Si*y[3]
return (np.abs(amount_sort1_C-sort_1.C)+np.abs(amount_sort1_N-sort_1.N)+np.abs(amount_sort1_P-sort_1.P)+np.abs(amount_sort1_Si-sort_1.Si))
bnds=((0,1),(0,1))
y0 = np.zeros((8,))
res = minimize(targetFun1,x0 = y0,method='SLSQP',bounds=bnds)
y = res.x
print(y)
def targetFun2(y):
amount_sort2_C = substrat_1.C*y[4] + substrat_2.C*y[5] + substrat_3.C*y[6] + substrat_4.C*y[7]
amount_sort2_N = substrat_1.N*y[4] + substrat_2.N*y[5] + substrat_3.N*y[6] + substrat_4.N*y[7]
amount_sort2_P = substrat_1.P*y[4] + substrat_2.P*y[5] + substrat_3.P*y[6] + substrat_4.P*y[7]
amount_sort2_Si = substrat_1.Si*y[4] + substrat_2.Si*y[5] + substrat_3.Si*y[6] + substrat_4.Si*y[7]
return (np.abs(amount_sort2_C-sort_2.C)+np.abs(amount_sort2_N-sort_2.N)+np.abs(amount_sort2_P-sort_2.P)+np.abs(amount_sort2_Si-sort_2.Si))
res = minimize(targetFun2,bounds=bnds)
y = res.x
print(y)
解决方法
我强烈建议使用 np.ndarray
而不是类来存储您的数据:
substrat = np.array([
[0.93,0.005,0.031,0.034],# substrat_1
[0.523,0.3,0.123,0.054],# substrat_2
[0.257,0.176,0.461,0.106],# substrat_3
[0.694,0.003,0.298],# substrat_4
])
sort = np.array([
[0.7,0.15,0.05,0.1],# sort_1
[0.8,0.03,0.1,0.07] # sort_2
])
那么,你的目标函数可以写成
def targetFun1(y):
return np.sum(np.abs(substrat.T @ y[:4] - sort[0]))
def targetFun2(y):
return np.sum(np.abs(substrat.T @ y[4:] - sort[1]))
此处,.T
表示矩阵/ np.ndarray substrat
的转置,@
表示矩阵乘法运算符。
由于 0 是两个函数的下限,同时最小化两个函数的一种方法是最小化两个函数的总和:
res = minimize(lambda y: targetFun1(y) + targetFun2(y),x0 = y0,method='SLSQP',bounds=bnds)
# Finally,we only need to reshape the solution `res.x`:
solution = res.x.reshape(4,2)
或者,您可以将其编写为一个目标函数:
# Create BlockDiagonalmatrix:
# ( substrat.T. 0 )
# ( 0 substrat.T )
#
DiagSubstrat = np.kron(np.eye(2),substrat.T)
def targetFun(y):
return np.sum(np.abs(DiagSubstrat @ y - sort.flatten()))