我正在尝试有关烹饪食谱的简单优化。 特殊之处在于,由于尚未实现的常见约束(例如:所有食谱的共同核心),系统将必须同时优化多个食谱。
下面是显示scipy的错误:
fun: 3.467601477010358
jac: array([1.79999998, 2.04999998, 1.79999998, 2.04999998])
message: 'Singular matrix C in LSQ subproblem'
nfev: 6
nit: 1
njev: 1
status: 6
success: False
x: array([0.99425684, 0.3895346 , 0.31931526, 0.14859794])
代码在这里:
import sys
import numpy as np
from scipy.optimize import minimize
ingredient = dict()
ingredient[0] = dict()
ingredient[0]['description'] = 'Corn'
ingredient[0]['price'] = 180
ingredient[1] = dict()
ingredient[1]['description'] = 'Rice'
ingredient[1]['price'] = 205
ingredient_count = len(ingredient)
product = dict()
product[0] = dict()
product[0]['description'] = "Bread 1"
product[0]['ingredient'] = dict()
product[0]['ingredient'][0] = dict()
product[0]["ingredient"][0]['min'] = 0
product[0]["ingredient"][0]['max'] = 36
product[0]["ingredient"][1] = dict()
product[0]["ingredient"][1]['min'] = 0
product[0]["ingredient"][1]['max'] = 100
product[1] = dict()
product[1]["description"] = "Bread 2"
product[1]['ingredient'] = dict()
product[1]['ingredient'][0] = dict()
product[1]["ingredient"][0]['min'] = 0
product[1]["ingredient"][0]['max'] = 36
product[1]["ingredient"][1] = dict()
product[1]["ingredient"][1]['min'] = 0
product[1]["ingredient"][1]['max'] = 100
product_count = len(product)
def function(x):
totals = list()
for product_index in product:
total = 0
for ingredient_index in product[product_index]['ingredient']:
x_index = (ingredient_count * product_index) + ingredient_index
total += (x[x_index] * ingredient[ingredient_index]['price'] / 100)
totals.append(total)
return totals
def function_sum(x):
# p1 + p2 + ... + pn
totals = function(x)
return sum(totals)
def function_diff_sum(x):
# p_min + (p1 - p_min) + (p2 - p_min) + ... + (pn - p_min)
totals = function(x)
min_total = min(totals)
grand_total = min_total
for total in totals:
grand_total += total - min_total
return grand_total
# Constraints
constraints = list()
def populate_constraints():
for product_index in product:
total_of_ingredients(product_index)
for ingredient_index in product[product_index]['ingredient']:
for constraint_type in product[product_index]['ingredient'][ingredient_index]:
if constraint_type == 'min':
min_for_ingredient(product_index, ingredient_index)
elif constraint_type == 'max':
max_for_ingredient(product_index, ingredient_index)
def min_for_ingredient(product_index, ingredient_index):
x_index = (ingredient_count*product_index)+ingredient_index
constraints.append({'type': 'ineq', 'fun': lambda x: x[x_index] - product[product_index]['ingredient'][ingredient_index]['min']})
def max_for_ingredient(product_index, ingredient_index):
x_index = (ingredient_count*product_index) + ingredient_index
constraints.append({'type': 'ineq', 'fun': lambda x: product[product_index]['ingredient'][ingredient_index]['max'] - x[x_index]})
def total_of_ingredients(product_index):
# The total of ingredient for a product have to be 100.
first_x_index = ingredient_count*product_index
constraints.append({'type': 'eq', 'fun': lambda x: (sum(x[i] for i in range(first_x_index, ingredient_count)))-100})
def main():
x0 = np.random.rand(1, product_count*ingredient_count)
# x0 = np.array([36, 64, 36, 64]) # The solution that the optimizer should give
populate_constraints()
# There are 2 type of sum
fun = function_sum
# fun = function_diff_sum
res = minimize(fun, x0, constraints=constraints)
print(res)
if __name__ == '__main__':
sys.exit(main())
答案 0 :(得分:1)
如果我正确阅读了您的问题,那么您正在尝试解决linear programming最小化的问题
1.8*i_11 + 2.05*i_12 + 1.8*i_21 + 2.05*i_22
有约束条件
i_11 + i_12 = 100
i_21 + i_22 = 100
0 <= i_11 <= 36
0 <= i_12 <= 100
0 <= i_21 <= 36
0 <= i_22 <= 100
将变量按(i_11, i_12, i_21, i_22)
排序,并参考its documentation以获得有关符号的详细信息,这对于scipy.optimize.linprog
来说很简单:
c = [1.8, 2.05, 1.8, 2.05]
A_eq = [[1, 1, 0, 0], [0, 0, 1, 1]]
b_eq = [100, 100]
bounds = [(0, 36), (0, 100), (0, 36), (0, 100)]
output = linprog(c=c, A_eq=A_eq, b_eq=b_eq, bounds=bounds)
然后,output
是以下OptimizeResult
:
con: array([3.13126236e-09, 3.13126236e-09])
fun: 391.9999999946266
message: 'Optimization terminated successfully.'
nit: 5
slack: array([], dtype=float64)
status: 0
success: True
x: array([35.99999999, 64.00000001, 35.99999999, 64.00000001])