如何吃,少花钱又营养丰富?可用MindOpt线性规划求解来决策

简介: 营养调配问题的的目标是利用优化模型来设定每日饮食菜单,在满足各类营养的需求同时更能优化总成本

本篇将介绍使用MindOpt来优化营养调配问题。(本例数据是假设的,决策值不能作为参考,仅为讲解决策算法用。

营养调配问题的的目标是利用优化模型来设定每日饮食菜单,在满足各类营养的需求同时更能优化总成本.营养调配问题是可用线性优化来表达

  • 决策 变量 为:以下食物调配多少量:起司汉堡 (Cheeseburger)、汉堡 (Hamburger)、火腿三明治 (Ham-sandwich)、鱼肉三民治 (Fish-sandwich)、鸡肉三民治 (Chicken-sandwich)、薯条 (Fries)、香肠比司吉 (Sausage biscuit)、低脂牛乳 (Low-fat milk)、和橙汁 (Orange juice);
  • 约束 条件为:卡路里 (Cal.)、碳水化合物 (Carbo.)、蛋白质 (Portien)、维生素A/D (Vit. A/D)、铁 (Iron)和钙质 (Calc.)的每日摄取上/下限制,以及总量 (Volume) 限制;
  • 目标 函数则为:总成本的最小化.
  • image.png

问题定义

问题类型

线性优化问题,我们用先用集合和参数标明后面变量的取值关联信息。

集合


image.png

参数

image.png


然后这个线性规划问题定义如下:

决策变量


image.png


目标函数


image.png


约束条件


image.png


总结下这个模型的数学公式为:


image.png


数据


  • 为简化表达,以下以食物的简称替代.

食物

Cheese burger

Ham sandwich

Ham-burger

Fish sandwich

Chicken sandwich

Fries

Sausage biscuit

Lowfat milk

Orange juice

简称

CB

HS

H

FS

CS

F

SB

LM

OJ


  • 每单位食物的成本价

食物

CB

HS

H

FS

CS

F

SB

LM

OJ

成本

1.84

2.19

1.84

1.44

2.29

0.77

1.29

0.60

0.72


  • 各营养的单日摄取上限和下限

营养

Cal

Carbo

Protein

VitA

VitC

Calc

Iron

Volume

下界

2000

355

55

100

100

100

100

-∞

上界

375

75


  • 各种食物的营养含量与容积量

食物

CB

HS

H

FS

CS

F

SB

LM

OJ

Cal

510

370

500

370

400

220

345

110

80

Carbo

34

55

42

38

42

26

27

12

20

Protein

28

24

25

14

31

3

15

9

1

VitA

15

15

6

2

8

0

4

10

2

VitC

6

10

2

0

15

15

0

4

120

Calc

30

20

25

15

15

0

20

30

2

Iron

20

20

20

10

8

2

15

0

2

Volume

4

7.5

3.5

5

7.3

2.6

4.1

8

12

使用MindOpt求解器的API


直接采用求解器的API,需要查阅API文档来理解API的意思,没有建模语言可读性高。请参阅https://solver.damo.alibaba.com/doc/html/API%20reference/API-python/index.html来查看PythonAPI的使用说明。


关于Python的例子,在达摩院 MindOpt优化中文社区中有Python的示例。这里是个LP的问题,我们可以参考:https://developer.aliyun.com/article/1090860?spm=a2c6h.26396819.creator-center.8.14fb3e182y9iZl


下面我们分三种方式描述在本平台环境中的运行方法:

方法1:cell中直接输入代码运行

示例:进入官网>进入线上平台>创建项目>输入代码

云上平台运行python案例.gif

请运行下面cell中的代码,点击本窗口上面的播放△运行,或者摁shift+enter键运行:

# LP_2_diet.py

"""
/**
 *  example_2_py1.py
 *  Description 
 *  -----------
 *
 *  Linear optimization (diet problem).
 * 
 *  The goal is to select foods that satisfy daily nutritional requirements while minimizing the total cost. 
 *  The constraints in this problem limit the number of calories, the volume of good consumed, and the amount of 
 *  vitamins, protein, carbohydrates, calcium, and iron in the diet.
 *
 *  Note
 *  ----
 * 
 *  The model below will be inputted in a row-wise order.
 *
 *  Formulation
 *  -----------
 *
 * Minimize
 * Obj:        1.840000000 Cheeseburger + 2.190000000 HamSandwich + 1.840000000 Hamburger + 1.440000000 FishSandwich +
 *             2.290000000 ChickenSandwich + 0.770000000 Fries + 1.290000000 SausageBiscuit + 0.600000000 LowfatMilk + 
 *             0.720000000 OrangeJuice
 * Subject To
 * Cal:        510 Cheeseburger + 370 HamSandwich + 500 Hamburger + 370 FishSandwich +
 *             400 ChickenSandwich + 220 Fries + 345 SausageBiscuit + 110 LowfatMilk + 80 OrangeJuice >= 2000
 * Carbo:      34 Cheeseburger + 35 HamSandwich + 42 Hamburger + 38 FishSandwich + 42 ChickenSandwich + 
 *             26 Fries + 27 SausageBiscuit + 12 LowfatMilk + 20 OrangeJuice <= 375
 * Carbo_low:  34 Cheeseburger + 35 HamSandwich + 42 Hamburger + 38 FishSandwich + 42 ChickenSandwich + 
 *             26 Fries + 27 SausageBiscuit + 12 LowfatMilk + 20 OrangeJuice >= 350
 * Protein:    28 Cheeseburger + 24 HamSandwich + 25 Hamburger + 14 FishSandwich + 31 ChickenSandwich + 
 *             3 Fries + 15 SausageBiscuit + 9 LowfatMilk + OrangeJuice >= 55
 * VitA:       15 Cheeseburger + 15 HamSandwich + 6 Hamburger + 2 FishSandwich + 8 ChickenSandwich + 
 *             4 SausageBiscuit + 10 LowfatMilk + 2 OrangeJuice >= 100
 * VitC:       6 Cheeseburger + 10 HamSandwich + 2 Hamburger + 15 ChickenSandwich + 
 *             15 Fries + 4 LowfatMilk + 120 OrangeJuice >= 100
 * Calc:       30 Cheeseburger + 20 HamSandwich + 25 Hamburger + 15 FishSandwich + 
 *             15 ChickenSandwich + 20 SausageBiscuit + 30 LowfatMilk + 2 OrangeJuice >= 100
 * Iron:       20 Cheeseburger + 20 HamSandwich + 20 Hamburger + 10 FishSandwich + 
 *             8 ChickenSandwich + 2 Fries + 15 SausageBiscuit + 2 OrangeJuice >= 100
 * Volume:     4 Cheeseburger + 7.500000000 HamSandwich + 3.500000000 Hamburger + 5 FishSandwich + 
 *             7.300000000 ChickenSandwich + 2.600000000 Fries + 4.100000000 SausageBiscuit + 8 LowfatMilk + 12 OrangeJuice <= 75
 * Bounds
 * End
 */
"""
from mindoptpy import *


if __name__ == "__main__":

    MDO_INFINITY = MdoModel.get_infinity()

    req = \
    {   
        # requirement: ( lower bound,   upper bound)
        "Cal"        : (         2000, MDO_INFINITY), 
        "Carbo"      : (          350,          375),
        "Protein"    : (           55, MDO_INFINITY), 
        "VitA"       : (          100, MDO_INFINITY),
        "VitC"       : (          100, MDO_INFINITY),
        "Calc"       : (          100, MDO_INFINITY), 
        "Iron"       : (          100, MDO_INFINITY), 
        "Volume"     : (-MDO_INFINITY,           75)
    }

    food = \
    {
        # food            : ( lower bound,  upper bound, cost)
        "Cheeseburger"    : (           0, MDO_INFINITY, 1.84),
        "HamSandwich"     : (           0, MDO_INFINITY, 2.19),
        "Hamburger"       : (           0, MDO_INFINITY, 1.84),
        "FishSandwich"    : (           0, MDO_INFINITY, 1.44),
        "ChickenSandwich" : (           0, MDO_INFINITY, 2.29),
        "Fries"           : (           0, MDO_INFINITY, 0.77),
        "SausageBiscuit"  : (           0, MDO_INFINITY, 1.29),
        "LowfatMilk"      : (           0, MDO_INFINITY, 0.60),
        "OrangeJuice"     : (           0, MDO_INFINITY, 0.72)
    }
    
    req_value = \
    {  
        # (requirement, food              ) : value
        ( "Cal",        "Cheeseburger"    ) : 510,
        ( "Cal",        "HamSandwich"     ) : 370,
        ( "Cal",        "Hamburger"       ) : 500,
        ( "Cal",        "FishSandwich"    ) : 370,
        ( "Cal",        "ChickenSandwich" ) : 400,
        ( "Cal",        "Fries"           ) : 220,
        ( "Cal",        "SausageBiscuit"  ) : 345,
        ( "Cal",        "LowfatMilk"      ) : 110,
        ( "Cal",        "OrangeJuice"     ) : 80,

        ( "Carbo",      "Cheeseburger"    ) : 34,
        ( "Carbo",      "HamSandwich"     ) : 35,
        ( "Carbo",      "Hamburger"       ) : 42,
        ( "Carbo",      "FishSandwich"    ) : 38,
        ( "Carbo",      "ChickenSandwich" ) : 42,
        ( "Carbo",      "Fries"           ) : 26,
        ( "Carbo",      "SausageBiscuit"  ) : 27,
        ( "Carbo",      "LowfatMilk"      ) : 12,
        ( "Carbo",      "OrangeJuice"     ) : 20,

        ( "Protein",    "Cheeseburger"    ) : 28,
        ( "Protein",    "HamSandwich"     ) : 24,
        ( "Protein",    "Hamburger"       ) : 25,
        ( "Protein",    "FishSandwich"    ) : 14,
        ( "Protein",    "ChickenSandwich" ) : 31,
        ( "Protein",    "Fries"           ) : 3,
        ( "Protein",    "SausageBiscuit"  ) : 15,
        ( "Protein",    "LowfatMilk"      ) : 9,
        ( "Protein",    "OrangeJuice"     ) : 1,

        ( "VitA",       "Cheeseburger"    ) : 15,
        ( "VitA",       "HamSandwich"     ) : 15,
        ( "VitA",       "Hamburger"       ) : 6,
        ( "VitA",       "FishSandwich"    ) : 2,
        ( "VitA",       "ChickenSandwich" ) : 8,
        ( "VitA",       "Fries"           ) : 0,
        ( "VitA",       "SausageBiscuit"  ) : 4,
        ( "VitA",       "LowfatMilk"      ) : 10,
        ( "VitA",       "OrangeJuice"     ) : 2,

        ( "VitC",       "Cheeseburger"    ) : 6,
        ( "VitC",       "HamSandwich"     ) : 10,
        ( "VitC",       "Hamburger"       ) : 2,
        ( "VitC",       "FishSandwich"    ) : 0,
        ( "VitC",       "ChickenSandwich" ) : 15,
        ( "VitC",       "Fries"           ) : 15,
        ( "VitC",       "SausageBiscuit"  ) : 0,
        ( "VitC",       "OrangeJuice"     ) : 4,
        ( "VitC",       "LowfatMilk"      ) : 120,

        ( "Calc",       "Cheeseburger"    ) : 30,
        ( "Calc",       "HamSandwich"     ) : 20,
        ( "Calc",       "Hamburger"       ) : 25,
        ( "Calc",       "FishSandwich"    ) : 15,
        ( "Calc",       "ChickenSandwich" ) : 15,
        ( "Calc",       "Fries"           ) : 0,
        ( "Calc",       "SausageBiscuit"  ) : 20,
        ( "Calc",       "LowfatMilk"      ) : 30,
        ( "Calc",       "OrangeJuice"     ) : 2,

        ( "Iron",       "Cheeseburger"    ) : 20,
        ( "Iron",       "HamSandwich"     ) : 20,
        ( "Iron",       "Hamburger"       ) : 20,
        ( "Iron",       "FishSandwich"    ) : 10,
        ( "Iron",       "ChickenSandwich" ) : 8,
        ( "Iron",       "Fries"           ) : 2,
        ( "Iron",       "SausageBiscuit"  ) : 15,
        ( "Iron",       "LowfatMilk"      ) : 0,
        ( "Iron",       "OrangeJuice"     ) : 2,

        ( "Volume",     "Cheeseburger"    ) : 4,
        ( "Volume",     "HamSandwich"     ) : 7.5,
        ( "Volume",     "Hamburger"       ) : 3.5,
        ( "Volume",     "FishSandwich"    ) : 5,
        ( "Volume",     "ChickenSandwich" ) : 7.3,
        ( "Volume",     "Fries"           ) : 2.6,
        ( "Volume",     "SausageBiscuit"  ) : 4.1,
        ( "Volume",     "LowfatMilk"      ) : 8,
        ( "Volume",     "OrangeJuice"     ) : 12
    }

    # ----Step 1. Create a model and change the parameters.
    model = MdoModel()

    try:
        # ----Step 2. Input model.
        # Change to minimization problem.
        model.set_int_attr("MinSense", 1)
        
        # Add variables.
        var = {}
        for food_name, food_data in food.items():
            var[food_name] = model.add_var(food_data[0], food_data[1], food_data[2], None, food_name, False)

        # Add constraints.
        cons = {}
        for req_name, req_data in req.items():
            expr = MdoExprLinear()
            for food_name in food.keys():
                expr += req_value[req_name, food_name] * var[food_name]
            cons[req_name] = model.add_cons(req_data[0], req_data[1], expr, req_name)

        # ----Step 3. Solve the problem and populate the result.
        model.solve_prob()
        model.display_results()
        time.sleep(1) #for print
  
        status_code, status_msg = model.get_status()
        if status_msg == "OPTIMAL":
            print("----\n")
            print("The solver terminated with an OPTIMAL status (code {0}).".format(status_code))

            print("目标函数总收益是: {0}".format(model.get_real_attr("PrimalObjVal")))
            
            print("原始解是:")
            for var_name,var_val in var.items():
                primal_soln = var_val.get_real_attr("PrimalSoln")
                print("{0:>20} : {1}".format(var_name,primal_soln))
    
        else:
            print("Optimizer terminated with a(n) {0} status (code {1}).".format(status_msg, status_code))
     
    except MdoError as e:
        print("Received Mindopt exception.")
        print(" - Code          : {}".format(e.code))
        print(" - Reason        : {}".format(e.message))
    except Exception as e:
        print("Received exception.")
        print(" - Reason        : {}".format(e))
    finally:
        # Step 4. Free the model.
        model.free_mdl()

点击运行后,得到的结果如下:

Start license validation (current time : 17-JAN-2023 23:54:14).
License validation terminated. Time : 0.003s

Model summary.
 - Num. variables     : 9
 - Num. constraints   : 8
 - Num. nonzeros      : 67
 - Bound range        : [5.5e+01,2.0e+03]
 - Objective range    : [6.0e-01,2.3e+00]
 - Matrix range       : [1.0e+00,5.1e+02]

Presolver started.
Presolver terminated. Time : 0.000s

Simplex method started.
Model fingerprint: =IGYvFmb5d2dgF2dud3b

    Iteration       Objective       Dual Inf.     Primal Inf.     Time
            0     0.00000e+00      0.0000e+00      4.0937e+01     0.00s    
            3     1.48557e+01      0.0000e+00      0.0000e+00     0.00s    
Postsolver started.
Simplex method terminated. Time : 0.001s

Optimizer summary.
 - Optimizer used     : Simplex method
 - Optimizer status   : OPTIMAL
 - Total time         : 0.002s

Solution summary.       Primal solution
 - Objective          : 1.4855737705e+01 
----

The solver terminated with an OPTIMAL status (code 1).
目标函数总收益是: 14.855737704918033
原始解是:
        Cheeseburger : 4.385245901639344
         HamSandwich : 0.0
           Hamburger : 0.0
        FishSandwich : 0.0
     ChickenSandwich : 0.0
               Fries : 6.147540983606558
      SausageBiscuit : 0.0
          LowfatMilk : 3.422131147540985
         OrangeJuice : 0.0

方法2:命令行直接运行.py文件

上面是直接在cell中运行所有的脚本,我们也可以建立个新文档,将Python代码存在src/python_src文件夹的LP_2_diet.py文件。然后在Launcher中打开Terminal,执行python xx.py文件来运行。


您也可以下载本.py文件,在自己的电脑上安装MindOpt求解器,然后在自己电脑的环境运行。


Luancher可以点击左上角的+打方块打开,Terminal在最下方,如截图示意。打开的窗口可以拖动调整位置。

image.png

然后在Terminal命令行里运行如下指令:

cd src/python_src
python LP_2_diet.py

运行得到的结果同方法1:

image.png

方法3:复制案例广场的例子

这个例子已经在MindOpt的案例广场,可以直接复制:营养调配

直接点击复制项目,会将配置的文件全部复制过来,可以直接运行。(如上图所示)

image.png

求解结果

运行结果里面打印有:

目标函数总收益是: 14.855737704918033
原始解是:
        Cheeseburger : 4.385245901639344
         HamSandwich : 0.0
           Hamburger : 0.0
        FishSandwich : 0.0
     ChickenSandwich : 0.0
               Fries : 6.147540983606558
      SausageBiscuit : 0.0
          LowfatMilk : 3.422131147540985
         OrangeJuice : 0.0


代表求解结果的目标函数(每日饮食餐费)最低解为:$14.86元,包含了4.39份起司汉堡,6.15份薯条,以及3.42份低脂牛乳。

联系我们

钉钉答疑群:32451444

钉钉活动群:18890022111(精彩好礼等你来拿!)

邮箱地址:solver.damo@list.alibaba-inc.com

更多更新通知:https://solver.damo.alibaba.com

相关文章
|
存储 达摩院
「达摩院MindOpt」线性规划用于排程排程问题(02)
排产排程、原料采购、仓储存放等是制造业降本增效的关键问题。
「达摩院MindOpt」线性规划用于排程排程问题(02)
|
存储 达摩院
「达摩院MindOpt」线性规划用于排程排程问题(03)
比上一篇问题02中,我们只考虑了一次性的采购和生产计划,实际中的排产排程问题要更加复杂和精细。例如,我们要考虑未来三个月内采购和排产排程计划。其中,原材料每个月的采买价格均有不同,并且原材料购买后的存储也需要成本开销。在本节中,我们将考虑这样一个相对复杂的排产排程的决策问题。
「达摩院MindOpt」线性规划用于排程排程问题(03)
|
达摩院 调度
使用达摩院MindOpt优化交通调度_最大化通行量—线性规划问题
在数学规划中,网络流问题是指一类基于网络模型的流量分配问题。网络流问题的目标是在网络中分配资源,使得网络的流量满足一定的限制条件,并且使得某些目标函数最小或最大化。网络流问题通常涉及一个有向图,图中每个节点表示一个资源,每条边表示资源之间的关系。边上有一个容量值,表示该边上最多可以流动的资源数量。流量从源节点开始流出,经过一系列中间节点,最终到达汇节点。在这个过程中,需要遵守一定的流量守恒和容量限制条件。
|
存储 达摩院 供应链
混合整数线性规划-仓库选址问题-达摩院MindOpt
仓库选址问题是一个重要的运筹学问题,它涉及到在一个给定的地理区域中选择最佳的仓库位置以最小化总成本或者提高效率。仓库选址问题在现代物流和供应链管理中具有重要的应用,因为仓库的位置直接影响到货物的运输成本、交货时间和库存量等因素。
Python语言如何使用MindOpt建模并求解混合整数线性规划问题
MindOpt是一款高效的优化算法软件包,求解算法实现了线性规划(LP)、混合整数线性规划(MILP)、二次规划(QP),可以支持命令行、c、c++、java和python调用。接下来我们将发布一系列文章,讲述各个语言如何使用 MindOpt 来求解数学规划问题。
Python语言如何使用MindOpt建模并求解混合整数线性规划问题
|
达摩院 API C++
MindOpt--C++语言-对一个简单的混合整数规划问题建模求解
MindOpt是达摩院决策智能实验室研究的一款优化求解器,目前在优化求解线性规划问题这一功能上取得不错的成绩,希望大家能够帮我们多多打磨其他功能(混合整数线性规划、二次规划、半定规划目前都在公测),让我们的MindOpt在优化求解器这板块成为国产之光。
MindOpt--C++语言-对一个简单的混合整数规划问题建模求解
|
达摩院 API C语言
C语言如何使用MindOpt建模并求解线性规划问题
MindOpt是达摩院决策智能实验室研究的一款优化求解器,能帮助做方案设计、生产方案优化、资源合理分配、辅助决策等。可以支持命令行、c、c++、java和python调用,目前求解算法实现了线性规划、混合整数线性规划、二次规划。
C语言如何使用MindOpt建模并求解线性规划问题
|
达摩院 算法 Java
MindOpt也能使用C++ 来建模求解线性规划问题?
MindOpt是达摩院决策智能实验室研究的一款优化求解器,能帮助做方案设计、生产方案优化、资源合理分配、辅助决策等。可以支持命令行、c、c++、java和python调用,目前求解算法实现了线性规划、混合整数线性规划、二次规划。
MindOpt也能使用C++ 来建模求解线性规划问题?
|
达摩院 API C语言
C语言如何使用MindOpt建模并求解混合整数线性规划问题
MindOpt是达摩院决策智能实验室研究的一款优化求解器,能帮助做方案设计、生产方案优化、资源合理分配、辅助决策等。可以支持命令行、c、c++、java和python调用,目前求解算法实现了线性规划、混合整数线性规划、二次规划。
C语言如何使用MindOpt建模并求解混合整数线性规划问题
|
机器学习/深度学习 人工智能 达摩院
达摩院的MindOpt优化求解器又获「线性规划」第一啦?
MindOpt优化求解器又迎来新版本啦~此次发布的 V0.15.0 版本中,MindOpt 升级了单纯形法模块和内点法模块,并新发布了新模块。不仅功能增加,性能依然很强,在单纯形法评测「再夺第一」!并且还在阿里云产品平台上线,可自助下载求解器SDK包和获取授权码!实验室还有其他的成绩公开!
1378 0
达摩院的MindOpt优化求解器又获「线性规划」第一啦?