达摩院的MindOpt求解器如何求解单纯形法求解线性规划问题(Python语言)

简介

MindOpt是一款高效的优化算法软件包,求解算法实现了线性规划(LP)、混合整数线性规划(MILP)、二次规划(QP),可以支持命令行、c、c++、java和python调用。接下来我们将发布一系列文章,讲述各个语言如何使用 MindOpt 来求解数学规划问题。

如何获取MindOpt求解器

求解器安装包的发布渠道。请大家:

  1. 前往 https://www.aliyun.com/product/ai/opt 来下载求解器软件。
  2. 在阿里云上获取免费授权码:
    • 请大家迁移到“云鉴权”自助申请licenseKey,配置fl_client.ini。新的“云鉴权”不需要绑定机器ID,只要阿里云账号并联网就好。
    关于求解器的使用文档,请参考:https://help.aliyun.com/document_detail/298219.htm

线性规划

线性规划的定义,我个人认为是在线性的目标和约束中,找出一个最优解(如最大利润或最低成本)。线性规划可以广泛的应用在我们的生活中,解决资源利用、人力调配、生产安排等问题。

入门算例

一位员工每天要负责处理a任务(生成零部件) 和b任务(组装产品)。其参与a任务的报酬为100元/小时,b任务的报酬为150元/小时。工厂要求该员工每天在每个任务上花费至少 3 个小时。已知该员工每天工作8小时(因此在 6 小时之外,可以自行决定 2 小时如何工作),那么他该如何在两项任务上分配时间以得到尽可能多的报酬?

  • 以上问题可以被称为任务分配问题,也可以被视为一个简单的排产排程问题,由于该员工要决策时间分配,我们引入决策变量 Xa和 Xb用于表示该工人投入在任务和任务中的时长。由问题描述可知,这些变量需要满足Xa+Xb=8 和 Xa>=3,Xb>=3。
  • 此外,该工人的目标是获得尽可能多的报酬。在定义如上三要素后,我们可以建立如下的数学规划问题
  • 决策变量: Xa,Xb
  • 目标函数: maxmize 100Xa + 150Xb
  •  约束:  s.t.  Xa + Xb = 8
    
  •        Xa >= 3 , Xb >= 3
    

在这里插入图片描述

在上文的例子,是一个简单的线性规划问题,只有两个决策变量,而线性规划问题示例中的问题涉及到四个决策变量,人工去求最优解呢,需要先把线性规划问题转换为标准形式,然后制表、入基、出基、换基,最后迭代得出最优解,过程比较复杂,那么我们可以使用商用求解器 MindOpt ,让计算机来帮助我们求解。

  • 线性规划问题可以用以下数学公式来描述:
    在这里插入图片描述

其中
在这里插入图片描述

进阶算例

  • 要找到一个和线性规划问题示例中的问题相匹配的文字列题比较困难,所以我们在这里做一个假设,把它当成是一个人力调配的问题,求解的是一个目标函数的最小值,也就是花费最低成本去解决问题
  • 线性规划问题示例:
    在这里插入图片描述

Python代码示例:


 # 引入python包
from mindoptpy import *

if __name__ == "__main__":
    MDO_INFINITY = MdoModel.get_infinity()

    # Step 1.创建模型并更改参数。
    model = MdoModel()

    try:

        # Step 2. 输入模型。
        #  改为最小化问题。
        model.set_int_attr(MDO_INT_ATTR.MIN_SENSE, 1)

        #  添加变量。
        x = []
        x.append(model.add_var(0.0,         10.0, 1.0, None, "x0", False))
        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, None, "x1", False))
        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, None, "x2", False))
        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, None, "x3", False))

        #  添加约束。
        #  注意这里的非零元素是按行顺序输入的。
        model.add_cons(1.0, MDO_INFINITY, 1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3], "c0")
        model.add_cons(1.0,          1.0, 1.0 * x[0]              - 1.0 * x[2] + 6.0 * x[3], "c1")

        # Step 3. 解决问题并填充结果。
        model.solve_prob()
        model.display_results()

        # 调用 mindoptpy.MdoModel.get_status() 来检查求解器的优化状态,
        # 并通过 mindoptpy.MdoModel.get_real_attr() 和 
        # mindoptpy.MdoVar.get_real_attr() 来获取目标值和最优解。
        status_code, status_msg = model.get_status()
        if status_msg == "OPTIMAL":
            print("Optimizer terminated with an OPTIMAL status (code {0}).".format(status_code))
            print("Primal objective : {0}".format(round(model.get_real_attr(MDO_REAL_ATTR.PRIMAL_OBJ_VAL), 2)))
            for curr_x in x:
                print(" - x[{0}]          : {1}".format(curr_x.get_index(), round(curr_x.get_real_attr(MDO_REAL_ATTR.PRIMAL_SOLN), 2)))
        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. 释放模型。
        # 调用 mindoptpy.MdoModel.free_mdl() 来释放内存
        # (多次运行部分脚本的时候有些变量已经被用,所以调用这个api进行清除)
        model.free_mdl()

详细代码解释如下:

第一步:创建模型

首先,我们必须建立一个空的模型

model = MdoModel()

第二步:LP模型输入

接着我们利用Python API set_int_attr()将目标函数改为最小化

model.set_int_attr(MDO_INT_ATTR.MIN_SENSE, 1)
# 也可以选择这个模型属性model.set_int_attr("MinSense", 1) 数字1代表最小化,0代表最大化

再调用 add_var() 来添加四个优化变量,定义其下界、上界、名称和类型
(0.0是新增变量的下界,10和MDO_INFINITY是上界,1.0为新变量的目标系数,
None是包含非零元素的列对象,默认为None。""中是变量的名字,False代表不可指定是否为整数变量的布尔标志)

 x = []
        x.append(model.add_var(0.0,         10.0, 1.0, None, "x0", False))
        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, None, "x1", False))
        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, None, "x2", False))
        x.append(model.add_var(0.0, MDO_INFINITY, 1.0, None, "x3", False))

然后调用add_cons()来添加约束
(1.0为新约束的左侧值,或临时线性对象。MDO_INFINITY和10为新约束的右侧值,或者一个约束名称的字符串。"c0、c1"为这条约束的名字。)

model.add_cons(1.0, MDO_INFINITY, 1.0 * x[0] + 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[3], "c0")
model.add_cons(1.0,          1.0, 1.0 * x[0]              - 1.0 * x[2] + 6.0 * x[3], "c1")

第三步:求解LP模型

模型输入后,我们接着用solve_prob()来求解问题。
并用display_results()呈现求解结果。

model.solve_prob()
model.display_results()

联系我们

钉钉群号:32451444
邮箱地址:solver.damo@list.alibaba-inc.com
更多更新通知:https://solver.damo.alibaba.com

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值