数学优化工具对比及封装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)
原文地址:https://www.cnblogs.com/xrszff/p/12929427.html