zoukankan      html  css  js  c++  java
  • 数学优化工具对比及封装scipy.linprog

    用python的话

    • gurobi,不开源,有讲解,性能最好,建模最方便。
    • ortools,建模变量设置方式灵活,但貌似只支持simplex。另外专门有一些特殊问题的包,如最大流问题,最小花费流问题。
    • lpsolve貌似只支持simplex
    • scipy.linprog 支持simplex(更准确)和interior point(本质上是近似),但建模固定矩阵式,不能灵活设置变量。
    • cvxpy,建模变量更灵活些。
      • CVXPY relies on the open source solvers ECOS, OSQP, and SCS
    • cvxopt 也是固定矩阵式建模。
    • pulp

    scipy.linprog

    https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.linprog.html

    min_{x_0,x_1} -x_0 + 4 x_1
    
    s.b. -3x_0 + x_1 leq 6 \
         -x_0 - 2x_1 geq -4 \
         x_1 geq -3
    
    
    

    以下两种写法等价,说明bounds不用也行。

    from scipy.optimize import linprog
    c = [-1, 4]
    A = [[-3, 1], [1, 2], [0,-1]]
    b = [6, 4, 3]
    x0_bounds = (None, None)
    x1_bounds = (None, None)
    res = linprog(c, A_ub=A, b_ub=b, bounds=[x0_bounds, x1_bounds])
    print(res)
    
    from scipy.optimize import linprog
    c = [-1, 4]
    A = [[-3, 1], [1, 2]]
    b = [6, 4]
    x0_bounds = (None, None)
    x1_bounds = (-3, None)
    res = linprog(c, A_ub=A, b_ub=b, bounds=[x0_bounds, x1_bounds])
    print(res)
    

    封装scipy.linprog

    封装的作用是,更方便动态添加变量,应对变量数量庞大的情况。

    '''
    min_{x_0,x_1} -x_0 + 4 x_1
    
    s.b. -3x_0 + x_1 leq 6 \
         -x_0 - 2x_1 geq -4 \
         x_1 geq -3
    
    from scipy.optimize import linprog
    c = [-1, 4]
    A = [[-3, 1], [1, 2]]
    b = [6, 4]
    x0_bounds = (None, None)
    x1_bounds = (-3, None)
    res = linprog(c, A_ub=A, b_ub=b, bounds=[x0_bounds, x1_bounds])
    print(res)
    '''
    
    from scipy.optimize import linprog
    
    class LinearProgramming():
        """
        Desc:
        """
        def __init__(self):
            self._var_dict = {}
            self._var_num = 0
            self._c = []
            self._A_ub = []
            self._b_ub = []
            self._A_eq = []
            self._b_eq = []
            self._bounds_list = []
    
    
        def add_var(self, name : str, lb = None, ub = None):
            self._var_dict[name] = self._var_num
            self._var_num += 1
            self._bounds_list.append((lb, ub))
    
    
        def add_constraint(self, handwritten_str):
            """
            Desc: 为方便解析,规定 handwritten_str 必须用 + 分割,+不可省略
                  且系数必须写出来如 -3*x0 (无须考虑*和-的优先级)
                  且含变量项全放左边
                  如: -3*x0+1*x1<=6
                      -1*x0 + -2*x1 >= -4
                      有无空格均可
            """
            handwritten_str = handwritten_str.replace(' ', '')
            if '<=' in handwritten_str:
                left, right = handwritten_str.split('<=')
                
                self._b_ub.append(float(right))
    
                # 找到所有含变量的项,并将系数 list 添加到 A_ub
                # 位置对应关系通过 _bounds_list 查询
                items = left.split('+')
                tmp_A_ub = [0 for _ in range(self._var_num)]
                for it in items:
                    coe, var_name = it.split('*')
                    index = self._var_dict[var_name]
                    tmp_A_ub[index] = float(coe)
                self._A_ub.append(tmp_A_ub)
            elif '>=' in handwritten_str:
                left, right = handwritten_str.split('>=')
                self._b_ub.append(-float(right))  # 系数需取反
                items = left.split('+')
                tmp_A_ub = [0 for _ in range(self._var_num)]
                for it in items:
                    coe, var_name = it.split('*')
                    index = self._var_dict[var_name]
                    tmp_A_ub[index] = -float(coe)  # 系数需取反
                self._A_ub.append(tmp_A_ub)
            elif '==' in handwritten_str:
                left, right = handwritten_str.split('==')
                self._b_eq.append(float(right))
                items = left.split('+')
                tmp_A_eq = [0 for _ in range(self._var_num)]
                for it in items:
                    coe, var_name = it.split('*')
                    index = self._var_dict[var_name]
                    tmp_A_eq[index] = float(coe)
                self._A_eq.append(tmp_A_eq)
            else:
                print('handwritten_str error')
                exit()
    
    
        def add_objective(self, handwritten_str):
            """
            Desc: minimize objective
                  为方便解析,规定 handwritten_str 必须用 + 分割,+不可省略
                  且系数必须写出来如 -3*x0 (无须考虑*和-的优先级)
            """
            handwritten_str = handwritten_str.replace(' ', '')
            items = handwritten_str.split('+')
            tmp_c = [0 for _ in range(self._var_num)] 
            for it in items:
                coe, var_name = it.split('*')
                index = self._var_dict[var_name]
                tmp_c[index] = float(coe)
            self._c = tmp_c
    
    
        def solve(self, method='interior-point', callback=None,
                  options=None, x0=None):
            """
            Desc: If you need greater accuracy, try method = 'revised simplex'.
            """
            self._A_ub = None if self._A_ub == [] else self._A_ub
            self._b_ub = None if self._b_ub == [] else self._b_ub
            self._A_eq = None if self._A_eq == [] else self._A_eq
            self._b_eq = None if self._b_eq == [] else self._b_eq
            res = linprog(
                c = self._c, A_ub = self._A_ub, b_ub = self._b_ub,
                A_eq = self._A_eq, b_eq = self._b_eq,
                bounds = self._bounds_list,
                method = method, callback = callback,
                options = options, x0 = x0
            )
            return res
    
    
    if __name__ == "__main__":
        lp = LinearProgramming()
        lp.add_var('x0', None, None)
        lp.add_var('x1', -3, None)
        # print(lp._var_dict)
        # print(lp._var_num)
        lp.add_constraint('-1*x0 + -2*x1 >= -4')
        lp.add_constraint('-3*x0+1*x1<=6')
        # print(lp._A_ub)
        lp.add_objective('4*x1 + -1*x0')
        res = lp.solve()
        print(res)
    
    

    pulp

    https://www.cnblogs.com/shizhenqiang/p/8274806.html

    from pulp import *
    
    
    def get_re():
        pass
    
    def getresult(c, con):
    
    # 设置对象
        prob = LpProblem('myPro', LpMinimize)
    # 设置三个变量,并设置变量最小取值
    
        x11 = LpVariable("x11", lowBound=0)
        x12 = LpVariable("x12", lowBound=0)
        x13 = LpVariable("x13", lowBound=0)
        x14 = LpVariable("x14", lowBound=0)
        x21 = LpVariable("x21", lowBound=0)
        x22 = LpVariable("x22", lowBound=0)
        x23 = LpVariable("x23", lowBound=0)
        x24 = LpVariable("x24", lowBound=0)
        x31 = LpVariable("x31", lowBound=0)
        x32 = LpVariable("x32", lowBound=0)
        x33 = LpVariable("x33", lowBound=0)
    
        X = [x11, x12, x13, x14, x21, x22, x23, x24, x31, x32, x33]
    
        #c = [160, 130, 220, 170, 140, 130, 190, 150, 190, 200, 230]
    
    
    # 目标函数
        z = 0
        for i in range(len(X)):
            z += X[i]*c[i]
        #print(z)
        prob += z
    
    # 载入约束变量
        prob += x11+x12+x13+x14 == con[0]# 约束条件1
        prob += x21+x22+x23+x24 == con[1]
        prob += x31+x32+x33 == con[2]
    
        prob += x11+x21+x31 <= con[3]
        prob += x11+x21+x31 >= con[4]
    
        prob += x12 + x22 + x32 <= con[5]
        prob += x12 + x22 + x32 >= con[6]
    
        prob += x13 + x23 + x33 <= con[7]
        prob += x13 + x23 + x33 >= con[8]
        prob += x14 + x24 <= con[9]
        prob += x14 + x24 >= con[10]
    
    # 求解
    
        status = prob.solve()
    
        print(status)
        print(LpStatus[status])
        print(value(prob.objective))  # 计算结果
    
    # 显示结果
    #     for i in prob.variables():
    #         print(i.name + "=" + str(i.varValue))
        for i in prob.variables():
            print(i.varValue)
    
    
    if __name__ == '__main__':
        c = [160, 130, 220, 170, 140, 130, 190, 150, 190, 200, 230]
        con = [50, 60, 50, 80, 30, 140, 70, 30,10, 50, 10]
        getresult(c, con)
    
  • 相关阅读:
    Office 2007在安装过程中出错-解决办法
    Sql日期时间格式转换
    大型网站架构演变和知识体系
    作为一个web开发人员,哪些技术细节是在发布站点前你需要考虑到的
    Java 入门基础
    技术类面试、笔试题汇总
    怎样玩转千万级别的数据
    数据库性能优化:SQL索引
    最后一公里极速配送
    编辑-滴滴算法大赛算法解决过程
  • 原文地址:https://www.cnblogs.com/xrszff/p/12929427.html
Copyright © 2011-2022 走看看