线性规划不可行性 - 创建误差范围并不能改善不可行性

问题描述 投票:0回答:1

我正在使用 PuLP 库。我尝试通过引入一系列值来放松约束,但仍然表明不可行。我是 LP 新手,所以我认为我不明白我在做什么。

项目概况:

获取原材料的 JSON 及其 FDA 营养成分,并使用目标食品的营养成分构建一系列线性方程,以求解食品中每种成分的含量。

例如Trader Joes鸡肉沙拉有:
“鸡胸肉”, “蛋黄酱”, “芹菜”, “甜蔓越莓干”, “蜂蜜”, “胡桃”, “苹果醋”, “糖”, “罂粟种子”, “盐”, “黄原胶”, “白胡椒”

因此,请根据营养标签和成分顺序找出每 100 克鸡肉沙拉中每种成分的用量。

这是我使用 PuLP 库的代码:

margin_of_error = .05

prob = LpProblem("BlendingProblem", LpMinimize)

ingredient_vars = LpVariable.dicts("Ingredient", sorted_filtered_data.keys(), lowBound=0, cat="Continuous")

#objective - no need, just constraints


prob += lpSum([ingredient_vars[i] for i in sorted_filtered_data.keys()]), "Objective"

#constaints

prob += lpSum([ingredient_vars[i] for i in sorted_filtered_data.keys()]) <= 100 * (1 + margin_of_error), "con1"
prob += lpSum([ingredient_vars[i] for i in sorted_filtered_data.keys()]) >= 100 * (1 - margin_of_error), "con1_floor"

for ingredient, next_ingredient in zip(sorted_filtered_data, list(sorted_filtered_data.keys())[1:]):
    prob += ingredient_vars[ingredient] >= 1, f"non_zero_{ingredient}"
    prob += ingredient_vars[next_ingredient] >= 1, f"non_zero_1:{ingredient}"
    prob += ingredient_vars[ingredient] >= ingredient_vars[next_ingredient] + .01, f"Order_constraint_{ingredient}"

for nutrient in target_nutrients:
    nutrient_contributions = []
    for ingredient in ingredient_vars:
        if (
            ingredient in sorted_filtered_data
            and "amount_per_serving" in sorted_filtered_data[ingredient]
            and nutrient in sorted_filtered_data[ingredient]["amount_per_serving"]
            and "value" in sorted_filtered_data[ingredient]["amount_per_serving"][nutrient]
        ):
            nutrient_value = sorted_filtered_data[ingredient]["amount_per_serving"][nutrient]["value"]
            nutrient_contributions.append((nutrient_value / 100) * ingredient_vars[ingredient])
    prob += lpSum(nutrient_contributions) <= target_values[nutrient] * (1 + margin_of_error), f"{nutrient}_constraint"
    prob += lpSum(nutrient_contributions) >= target_values[nutrient] * (1 - margin_of_error), f"{nutrient}_constraint_FLOOR!!"

print(prob)

这是我的日志

BlendingProblem:
MINIMIZE
1*Ingredient_apple_cider_vinegar + 1*Ingredient_celery + 1*Ingredient_chicken_breast + 1*Ingredient_honey + 1*Ingredient_mayonnaise + 1*Ingredient_pecans + 1*Ingredient_poppy_seeds + 1*Ingredient_salt + 1*Ingredient_sugar + 1*Ingredient_sweetened_dried_cranberries + 1*Ingredient_white_pepper + 1*Ingredient_xanthan_gum + 0
SUBJECT TO
con1: Ingredient_apple_cider_vinegar + Ingredient_celery
 + Ingredient_chicken_breast + Ingredient_honey + Ingredient_mayonnaise
 + Ingredient_pecans + Ingredient_poppy_seeds + Ingredient_salt
 + Ingredient_sugar + Ingredient_sweetened_dried_cranberries
 + Ingredient_white_pepper + Ingredient_xanthan_gum <= 105

con1_floor: Ingredient_apple_cider_vinegar + Ingredient_celery
 + Ingredient_chicken_breast + Ingredient_honey + Ingredient_mayonnaise
 + Ingredient_pecans + Ingredient_poppy_seeds + Ingredient_salt
 + Ingredient_sugar + Ingredient_sweetened_dried_cranberries
 + Ingredient_white_pepper + Ingredient_xanthan_gum >= 95

non_zero_chicken_breast: Ingredient_chicken_breast >= 1

non_zero_1:chicken_breast: Ingredient_mayonnaise >= 1

Order_constraint_chicken_breast: Ingredient_chicken_breast
 - Ingredient_mayonnaise >= 0.01

non_zero_mayonnaise: Ingredient_mayonnaise >= 1

non_zero_1:mayonnaise: Ingredient_celery >= 1

Order_constraint_mayonnaise: - Ingredient_celery + Ingredient_mayonnaise
 >= 0.01

non_zero_celery: Ingredient_celery >= 1

non_zero_1:celery: Ingredient_sweetened_dried_cranberries >= 1

Order_constraint_celery: Ingredient_celery
 - Ingredient_sweetened_dried_cranberries >= 0.01

non_zero_sweetened_dried_cranberries: Ingredient_sweetened_dried_cranberries
 >= 1

non_zero_1:sweetened_dried_cranberries: Ingredient_honey >= 1

Order_constraint_sweetened_dried_cranberries: - Ingredient_honey
 + Ingredient_sweetened_dried_cranberries >= 0.01

non_zero_honey: Ingredient_honey >= 1

non_zero_1:honey: Ingredient_pecans >= 1

Order_constraint_honey: Ingredient_honey - Ingredient_pecans >= 0.01

non_zero_pecans: Ingredient_pecans >= 1

non_zero_1:pecans: Ingredient_apple_cider_vinegar >= 1

Order_constraint_pecans: - Ingredient_apple_cider_vinegar + Ingredient_pecans
 >= 0.01

non_zero_apple_cider_vinegar: Ingredient_apple_cider_vinegar >= 1

non_zero_1:apple_cider_vinegar: Ingredient_sugar >= 1

Order_constraint_apple_cider_vinegar: Ingredient_apple_cider_vinegar
 - Ingredient_sugar >= 0.01

non_zero_sugar: Ingredient_sugar >= 1

non_zero_1:sugar: Ingredient_poppy_seeds >= 1

Order_constraint_sugar: - Ingredient_poppy_seeds + Ingredient_sugar >= 0.01

non_zero_poppy_seeds: Ingredient_poppy_seeds >= 1

non_zero_1:poppy_seeds: Ingredient_salt >= 1

Order_constraint_poppy_seeds: Ingredient_poppy_seeds - Ingredient_salt >= 0.01

non_zero_salt: Ingredient_salt >= 1

non_zero_1:salt: Ingredient_xanthan_gum >= 1

Order_constraint_salt: Ingredient_salt - Ingredient_xanthan_gum >= 0.01

non_zero_xanthan_gum: Ingredient_xanthan_gum >= 1

non_zero_1:xanthan_gum: Ingredient_white_pepper >= 1

Order_constraint_xanthan_gum: - Ingredient_white_pepper
 + Ingredient_xanthan_gum >= 0.01

calories_constraint: 0.6666666667 Ingredient_apple_cider_vinegar
 + 0.1386138614 Ingredient_celery + 1.97 Ingredient_chicken_breast
 + 2.8571428571 Ingredient_honey + Ingredient_mayonnaise + 7 Ingredient_pecans
 + 5.3571428571 Ingredient_poppy_seeds + 3.75 Ingredient_sugar
 + 3.5 Ingredient_sweetened_dried_cranberries + 2.96 Ingredient_white_pepper
 + 3.33 Ingredient_xanthan_gum <= 325.221238933

calories_constraint_FLOOR!!: 0.6666666667 Ingredient_apple_cider_vinegar
 + 0.1386138614 Ingredient_celery + 1.97 Ingredient_chicken_breast
 + 2.8571428571 Ingredient_honey + Ingredient_mayonnaise + 7 Ingredient_pecans
 + 5.3571428571 Ingredient_poppy_seeds + 3.75 Ingredient_sugar
 + 3.5 Ingredient_sweetened_dried_cranberries + 2.96 Ingredient_white_pepper
 + 3.33 Ingredient_xanthan_gum >= 294.247787606

total_fat_constraint: 0.09 Ingredient_chicken_breast
 + 0.11 Ingredient_mayonnaise + 0.7285714286 Ingredient_pecans
 + 0.4285714286 Ingredient_poppy_seeds + 0.021 Ingredient_white_pepper
 <= 25.0884955755

total_fat_constraint_FLOOR!!: 0.09 Ingredient_chicken_breast
 + 0.11 Ingredient_mayonnaise + 0.7285714286 Ingredient_pecans
 + 0.4285714286 Ingredient_poppy_seeds + 0.021 Ingredient_white_pepper
 >= 22.6991150445

saturated_fat_constraint: 0.034 Ingredient_chicken_breast
 + 0.02 Ingredient_mayonnaise + 0.0642857143 Ingredient_pecans
 + 0.0357142857 Ingredient_poppy_seeds + 0.006 Ingredient_white_pepper
 <= 1.858407075

saturated_fat_constraint_FLOOR!!: 0.034 Ingredient_chicken_breast
 + 0.02 Ingredient_mayonnaise + 0.0642857143 Ingredient_pecans
 + 0.0357142857 Ingredient_poppy_seeds + 0.006 Ingredient_white_pepper
 >= 1.681415925

cholesterol_constraint: 0.05 Ingredient_mayonnaise <= 46.4601769905

cholesterol_constraint_FLOOR!!: 0.05 Ingredient_mayonnaise >= 42.0353982295

sodium_constraint: 0.8 Ingredient_celery + 0.17 Ingredient_chicken_breast
 + 0.8 Ingredient_mayonnaise + 0.25 Ingredient_poppy_seeds
 + 387.555555556 Ingredient_salt + 0.05 Ingredient_white_pepper
 + 28.89 Ingredient_xanthan_gum <= 399.557522123

sodium_constraint_FLOOR!!: 0.8 Ingredient_celery
 + 0.17 Ingredient_chicken_breast + 0.8 Ingredient_mayonnaise
 + 0.25 Ingredient_poppy_seeds + 387.555555556 Ingredient_salt
 + 0.05 Ingredient_white_pepper + 28.89 Ingredient_xanthan_gum
 >= 361.504424777

potassium_constraint: 0.6666666667 Ingredient_apple_cider_vinegar
 + 2.6 Ingredient_celery + 4.1571428571 Ingredient_pecans
 + 7.1428571429 Ingredient_poppy_seeds + 0.0555555556 Ingredient_salt
 + 0.5 Ingredient_sweetened_dried_cranberries + 0.73 Ingredient_white_pepper
 <= 130.088495576

potassium_constraint_FLOOR!!: 0.6666666667 Ingredient_apple_cider_vinegar
 + 2.6 Ingredient_celery + 4.1571428571 Ingredient_pecans
 + 7.1428571429 Ingredient_poppy_seeds + 0.0555555556 Ingredient_salt
 + 0.5 Ingredient_sweetened_dried_cranberries + 0.73 Ingredient_white_pepper
 >= 117.699115045

total_carbohydrate_constraint: 0.0666666667 Ingredient_apple_cider_vinegar
 + 0.007 Ingredient_chicken_breast + 0.8095238095 Ingredient_honey
 + 0.1392857143 Ingredient_pecans + 0.2857142857 Ingredient_poppy_seeds
 + Ingredient_sugar + 0.875 Ingredient_sweetened_dried_cranberries
 + 0.69 Ingredient_white_pepper <= 14.867256642

total_carbohydrate_constraint_FLOOR!!:
 0.0666666667 Ingredient_apple_cider_vinegar + 0.007 Ingredient_chicken_breast
 + 0.8095238095 Ingredient_honey + 0.1392857143 Ingredient_pecans
 + 0.2857142857 Ingredient_poppy_seeds + Ingredient_sugar
 + 0.875 Ingredient_sweetened_dried_cranberries + 0.69 Ingredient_white_pepper
 >= 13.451327438

dietary_fiber_constraint: 0.0964285714 Ingredient_pecans
 + 0.2142857143 Ingredient_poppy_seeds
 + 0.05 Ingredient_sweetened_dried_cranberries + 0.26 Ingredient_white_pepper
 <= 0.9292035375

dietary_fiber_constraint_FLOOR!!: 0.0964285714 Ingredient_pecans
 + 0.2142857143 Ingredient_poppy_seeds
 + 0.05 Ingredient_sweetened_dried_cranberries + 0.26 Ingredient_white_pepper
 >= 0.8407079625

sugars_constraint: 0.0133663366 Ingredient_celery <= 13.0088495565

sugars_constraint_FLOOR!!: 0.0133663366 Ingredient_celery >= 11.7699115035

protein_constraint: 0.0069306931 Ingredient_celery
 + 0.28 Ingredient_chicken_breast + 0.0928571429 Ingredient_pecans
 + 0.1785714286 Ingredient_poppy_seeds + 0.1 Ingredient_white_pepper
 <= 10.2212389335

protein_constraint_FLOOR!!: 0.0069306931 Ingredient_celery
 + 0.28 Ingredient_chicken_breast + 0.0928571429 Ingredient_pecans
 + 0.1785714286 Ingredient_poppy_seeds + 0.1 Ingredient_white_pepper
 >= 9.2477876065

calcium_constraint: 0.4 Ingredient_celery + 0.09 Ingredient_chicken_breast
 + 0.7107142857 Ingredient_pecans + 14.2857142857 Ingredient_poppy_seeds
 + 2.65 Ingredient_white_pepper <= 18.584070792

calcium_constraint_FLOOR!!: 0.4 Ingredient_celery
 + 0.09 Ingredient_chicken_breast + 0.7107142857 Ingredient_pecans
 + 14.2857142857 Ingredient_poppy_seeds + 2.65 Ingredient_white_pepper
 >= 16.814159288

iron_constraint: 0.001980198 Ingredient_celery
 + 0.014 Ingredient_chicken_breast + 0.0257142857 Ingredient_pecans
 + 0.1071428571 Ingredient_poppy_seeds
 + 0.0025 Ingredient_sweetened_dried_cranberries
 + 0.14 Ingredient_white_pepper <= 0.669026547

iron_constraint_FLOOR!!: 0.001980198 Ingredient_celery
 + 0.014 Ingredient_chicken_breast + 0.0257142857 Ingredient_pecans
 + 0.1071428571 Ingredient_poppy_seeds
 + 0.0025 Ingredient_sweetened_dried_cranberries
 + 0.14 Ingredient_white_pepper >= 0.605309733

VARIABLES
Ingredient_apple_cider_vinegar Continuous
Ingredient_celery Continuous
Ingredient_chicken_breast Continuous
Ingredient_honey Continuous
Ingredient_mayonnaise Continuous
Ingredient_pecans Continuous
Ingredient_poppy_seeds Continuous
Ingredient_salt Continuous
Ingredient_sugar Continuous
Ingredient_sweetened_dried_cranberries Continuous
Ingredient_white_pepper Continuous
Ingredient_xanthan_gum Continuous

Welcome to the CBC MILP Solver 
Version: 2.10.3 
Build Date: Dec 15 2019 

command line - /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/pulp/solverdir/cbc/osx/64/cbc /var/folders/rf/12mmc82n05jd8dcnt91lch500000gn/T/cebd29ecc3224354afa1eeeb07e3b2b7-pulp.mps timeMode elapsed branch printingOptions all solution /var/folders/rf/12mmc82n05jd8dcnt91lch500000gn/T/cebd29ecc3224354afa1eeeb07e3b2b7-pulp.sol (default strategy 1)
At line 2 NAME          MODEL
At line 3 ROWS
At line 64 COLUMNS
At line 275 RHS
At line 335 BOUNDS
At line 336 ENDATA
Problem MODEL has 59 rows, 12 columns and 198 elements
Coin0008I MODEL read with 0 errors
Option for timeMode changed from cpu to elapsed
Presolve determined that the problem was infeasible with tolerance of 1e-08
Analysis indicates model infeasible or unbounded
Perturbing problem by 0.001% of 23.764773 - largest nonzero change 8.7550223e-05 ( 0.0097252709%) - largest zero change 0
0  Obj 0 Primal inf 2092.9285 (46)
Primal infeasible - objective value 880.57246
PrimalInfeasible objective 880.5724605 - 1 iterations time 0.002

Result - Linear relaxation infeasible

Enumerated nodes:           0
Total iterations:           0
Time (CPU seconds):         0.00
Time (Wallclock Seconds):   0.01

Option for printingOptions changed from normal to all
Total time (CPU seconds):       0.00   (Wallclock seconds):       0.02

我尝试创建误差幅度,以提高问题的可行性,但仍然出现错误。

python-3.x optimization linear-programming pulp
1个回答
0
投票

您走在正确的道路上。您缺少的主要内容是,对于每种营养素,您需要对所有成分的贡献进行求和以达到目标。

这是您的原始代码和一些模组。这还没有完成……这听起来像是硬件作业,所以剩下的就交给你了。目前的目标只是尽量减少原料的数量。您可以弹出约束将总数放在一个范围内或执行类似的操作。要点是,从小事做起,让它发挥作用(像这样),然后逐步扩大。

代码:

from pulp import *

margin_of_error = .05

prob = LpProblem("BlendingProblem", LpMinimize)

ingredients = {
                'bubble gum':   {'cal': 20, 'salt': 2},
                'cheese':       {'cal': 10, 'salt': 5},
                'grass':        {'cal': 30, 'salt': 10}
                }

target_values = {'cal': 65, 'salt': 14}


ingredient_vars = LpVariable.dicts("Ingredient", ingredients.keys(), lowBound=0, cat="Continuous")

#objective - no need, just constraints


prob += lpSum([ingredient_vars[i] for i in ingredients]), "Objective"

#constaints

# probably don't need these if we make the targets...
# prob += lpSum([ingredient_vars[i] for i in ingredients.keys()]) <= 100 * (1 + margin_of_error), "con1"
# prob += lpSum([ingredient_vars[i] for i in ingredients.keys()]) >= 100 * (1 - margin_of_error), "con1_floor"

for ingredient, next_ingredient in zip(ingredients, list(ingredients.keys())[1:]):

    # these don't seem needed.  Maybe xantham gum is like 0.02
    # prob += ingredient_vars[ingredient] >= 1, f"non_zero_{ingredient}"
    # prob += ingredient_vars[next_ingredient] >= 1, f"non_zero_1:{ingredient}"
    prob += ingredient_vars[ingredient] >= ingredient_vars[next_ingredient] + .01, f"Order_constraint_{ingredient}"

for nutrient in target_values:
    # let's just try to make the minimum requirement, which means we need to SUM OVER THE INGREDIENTS, not handle them individually...
    prob += sum(ingredients[ingredient][nutrient] * ingredient_vars[ingredient] 
        for ingredient in ingredients.keys() ) >= target_values[nutrient] * (1-margin_of_error)
    prob += sum(ingredients[ingredient][nutrient] * ingredient_vars[ingredient] 
        for ingredient in ingredients.keys() ) <= target_values[nutrient] * (1+margin_of_error)



    # nutrient_contributions = []
    # for ingredient in ingredient_vars:
    #     if (
    #         ingredient in ingredients
    #         and "amount_per_serving" in ingredients[ingredient]
    #         and nutrient in ingredients[ingredient]["amount_per_serving"]
    #         and "value" in ingredients[ingredient]["amount_per_serving"][nutrient]
    #     ):
    #         nutrient_value = ingredients[ingredient]["amount_per_serving"][nutrient]["value"]
    #         nutrient_contributions.append((nutrient_value / 100) * ingredient_vars[ingredient])
    # prob += lpSum(nutrient_contributions) <= target_values[nutrient] * (1 + margin_of_error), f"{nutrient}_constraint"
    # prob += lpSum(nutrient_contributions) >= target_values[nutrient] * (1 - margin_of_error), f"{nutrient}_constraint_FLOOR!!"

print(prob)
prob.solve()

for ingredient in ingredients:
    print(f'quantity of {ingredient}: {ingredient_vars[ingredient].varValue:0.2f}')
for nutrient in target_values:
    t = sum(ingredient_vars[i].varValue * ingredients[i][nutrient] for i in ingredients)
    print(f'total of nutrient {nutrient}: {t:0.2f}')

输出(截断):

Optimal - objective value 3.0925
Optimal objective 3.0925 - 3 iterations time 0.002
Option for printingOptions changed from normal to all
Total time (CPU seconds):       0.00   (Wallclock seconds):       0.00

quantity of bubble gum: 1.54
quantity of cheese: 0.78
quantity of grass: 0.77
total of nutrient cal: 61.75
total of nutrient salt: 14.70
© www.soinside.com 2019 - 2024. All rights reserved.