Python有多个开源的运筹优化库,本文介绍使用多种求解器来求解线性规划问题。

线性规划(Linear Programming, LP)是一种在一组线性约束条件下最大化或最小化一个线性目标函数的问题。在实际应用中,如资源分配、生产调度等问题都会用到线性规划方法。
目标是最大化利润,其中x1和x2为正整数。
目标函数:5*x1+12*x2
约束1:x1+2*x2<600
约束2:x1+3*x2<=200
接下来,我们将使用8种不同的Python开源库来求解这个问题。以下是各个库的代码示例:
1 scipy
import numpy as np
import scipy
from scipy.optimize import linprog
# declare coefficients of the objective function. profit maximization is converted into minimization problem as per SciPy requirement
c = -np.array([5,12])
lhs_constraints=([3,2], # machining time constraint
[1,3]) # weight constraint
rhs_constraints=([160, # machining time constraint
200]) # weight constraint
bounds = [(0, scipy.inf), (0, scipy.inf)] # Bounds of the decision variables
results = linprog(c=c, A_ub=lhs_constraints, b_ub=rhs_constraints, bounds=bounds, method='highs-ds')
# print the results
print('LP Solution:')
print(f'Profit: = {-round(results.fun,2)} $')
print(f'Make {round(results.x[0],0)} small sets, and make {round(results.x[1],0)} large sets')
2 pulp
from pulp import LpMaximize, LpProblem, LpVariable, lpSum, LpStatus
# Define the model
model = LpProblem(name='ChessSet', sense=LpMaximize)
# Define the decision variables
# x = {i: LpVariable(name=f"x{i}", lowBound=0, upBound = None, cat='Integer') for i in range(1, 3)}
x1 = LpVariable('SmallSet', lowBound = 0, upBound = None, cat='Integer')
x2 = LpVariable('LargeSet', lowBound = 0, upBound = None, cat='Integer')
# Add constraints
model += (3*x1 + 2*x2 <=160, 'Machining time constraint')
model += ( x1 + 3*x2 <= 200, 'Weight constraint')
# Set the profit as the objective function
profit= 5*x1 + 12*x2
model.setObjective(profit)
# Solve the optimization problem
model.solve()
# print the results
print('LP Solution:')
print(f'Profit: = {model.objective.value()} $')
print(f'Make {x1.value()} small sets, and make {x2.value()} large sets')
3 ortools
from ortools.linear_solver import pywraplp
solver = pywraplp.Solver.CreateSolver('GLOP')
# Define the decision variables
x1 = solver.NumVar(0, solver.infinity(), 'x1')
x2 = solver.NumVar(0, solver.infinity(), 'x2')
# Add constraints
ct = solver.Constraint(0, 160, 'ct')
ct.SetCoefficient(x1, 3)
ct.SetCoefficient(x2, 2)
ct = solver.Constraint(0, 200, 'ct')
ct.SetCoefficient(x1, 1)
ct.SetCoefficient(x2, 3)
# Set the profit as the objective function
objective = solver.Objective()
objective.SetCoefficient(x1, 5)
objective.SetCoefficient(x2, 12)
objective.SetMaximization()
# Solve the optimization problem
solver.Solve()
# print the results
print('LP Solution:')
print('Profit =', round(objective.Value(),2),'$')
print('Make', '%.1f'%round(x1.solution_value()),'small sets, and', '%.1f'%round(x2.solution_value()), 'large sets')
4 gurobi
from gurobipy import *
# Define the model
m = Model()
# Define the decision variables
x1 = m.addVar(name='x1')
x2 = m.addVar(name='x2')
# Set the profit as the objective function
m.setObjective(5*x1+12*x2, GRB.MAXIMIZE)
# Add constraints
m.addConstr(x1 >= 0)
m.addConstr(x2 >= 0)
m.addConstr(3*x1 + 2*x2 <= 160)
m.addConstr(x1 + 3*x2 <= 200)
# Solve the optimization problem
m.optimize()
# print the results
print('LP Solution:', round(m.objVal, 2))
result = []
for v in m.getVars():
result.append('%.1f'%round(v.x))
print('Make', result[0],'small sets, and', result[1], 'large sets')
5 python-mip
from mip import *
m = Model(sense=MAXIMIZE, solver_name=CBC)
x1 = m.add_var(name='x1')
x2 = m.add_var(name='x2')
m += 3*x1 + 2*x2 <= 160
m += x1 + 3*x2 <= 200
m += x1 >= 0
m += x2 >= 0
m.objective = 5*x1+12*x2
status = m.optimize()
print('LP Solution:',m.objective_value,'$')
result = []
for v in m.vars:
result.append('%.1f'%round(v.x))
print('Make', result[0],'small sets, and', result[1], 'large sets')
6 pyomo
from pyomo.environ import *
model = ConcreteModel()
model.x1 = Var(domain=Integers, name = 'x1')
model.x2 = Var(domain=Integers, name = 'x2')
model.profit = Objective(expr = 5*model.x1 + 12*model.x2, sense=maximize)
model.noNeg1 = Constraint(expr = model.x1 >= 0)
model.noNeg2 = Constraint(expr = model.x2 >= 0)
model.machiningTime = Constraint(expr = 3*model.x1 + 2*model.x2 <= 160)
model.weight = Constraint(expr = model.x1 + 3*model.x2 <= 200)
results = SolverFactory('gurobi').solve(model)
results.write()
if results.solver.status:
model.pprint()
print('\nProfit = ', model.profit())
print('\nDecision Variables')
print('x1 = ', model.x1())
print('x2 = ', model.x2())
7 gekko
from gekko import GEKKO
m = GEKKO()
x1 = m.Var(integer=True)
x2 = m.Var(integer=True)
m.Equation(x1 >= 0)
m.Equation(x2 >= 0)
m.Equation(3*x1 + 2*x2 <= 160)
m.Equation(x1 + 3*x2 <= 200)
m.Maximize(5*x1 + 12*x2)
m.options.SOLVER = 1 # 使用APOPT求解器
re = m.solve()
print('Make', x1.value,'small sets, and', x2.value, 'large sets')
print(type(x1.value))
8 pymprog
from pymprog import *
begin('model')
x1 = var('x1')
x1.kind = int#设置成整数变量
x2 = var('x2')
x2.kind = int#设置成整数变量
maximize(5*x1 + 12*x2, 'profit')
x1 >= 0
x2 >= 0
3*x1 + 2*x2 <= 160
x1 + 3*x2 <= 200
solve()
print('LP Solution:')
print('Profit =', round(vobj(),2),'$')
print('x1 =', x1.primal)
print('x2 =', x2.primal)
sensitivity()
以上几种库求解线性规划问题,各有优势,感兴趣的朋友可以进一步研究。
如何选择合适的开源库
在比较这些不同的Python开源库时,我们可以考虑以下几个方面:
易用性
考虑如何定义变量、目标函数和约束条件。一些库(如pulp、ortools和pyomo)提供了较为直观的接口,使得建模更加简单。
求解器支持
不同的库支持不同的求解器。例如,scipy通常使用内建求解器,而pulp、ortools等则允许用户选择不同的求解器。Gurobi是商业求解器,提供更高的性能,但需要许可证。
性能
对于大型的线性规划问题,性能变得尤为重要。商业求解器如Gurobi通常在性能上优于开源求解器,但这也取决于问题的具体情况。
灵活性
一些库(如pyomo和gekko)允许更多的自定义选项,包括不同类型的算法和求解器。
文档和社区支持
一个活跃的开发社区和详细的文档可以帮助解决使用过程中的问题,对于新手尤其重要。
成本
大多数库是开源的,可免费使用。但像Gurobi这样的商业求解器则需要购买许可证。
总的来说,选择合适的线性规划库需要考虑问题的具体需求、预算、以及用户的技术背景。