但是在我安装的使用报了下面这样一个错误:

ERROR: Could not install packages due to an EnvironmentError: [WinError 5] 拒绝访问。: ‘d:\…\anaconda3\lib\site-packages\_cffi_backend.cp38-win_amd64.pyd’
Consider using the --user option or check the permissions.

如果你遇见了这个错误,可以使用在安装指令中添加 --user 选项,最终命令是:

pip install mip --user

2 基础API的使用

2.1 模型类 Model

这是mip库的主类,通过该类可以完成模型的构建、决策变量的添加、约束的添加、目标函数的设置、模型的求解以及解的状态查询。

在构造Model对象时,可以不传递任何参数,也可以指定相关参数:

# 方式1
mp = Model()
# 方式2:这种方式指定了模型的名称、模型的目标函数类型、求解模型要调用的求解器;这里指定为Gurobi,还可以使用开源的 CBC
mp = Model(name='TSP',sense=MINIMIZE,solver_name='GRB')

2.1.1 向模型中加入约束

添加约束涉及的api:

  • add_constr(expr, name):包含约束表达式和约束的名称两个参数
  • += : 这是mip库特有的添加约束的方式
  • 如果你的约束中包含求和项,则需调用 xsum(expr) 方法,这个方法类似于gurobipy中的 quicksum() 方法
  • add_cut() :向模型中添加有效不等式时,使用该方法
  • add_lazy_constr():当初始模型不完整且发现整数解时,使用该方法添加规避掉当前整数解的约束
# 添加单个约束
model.add_constr(x1 + x2 <= 9, name='约束1')
model += x1 + x2 <= 9, "约束1"
# 添加求和约束
model += xsum(x[i] for i in range(2)) <= 9, '约束1'

2.1.2 向模型中添加变量

添加决策变量涉及的API:

  • add_var(name=‘’, lb=0.0, ub=inf, obj=0.0, var_type=‘C’, column=None):决策变量的名称、下界、上界、目标系数、类型;Column在列生成时使用
  • add_var_tensor(shape, name, **kwargs):一次性添加多个决策变量,shape属性表示决策变量的维度
x = model.add_var(name='x', lb=0.0, ub=10.0, var_type='C') # 创建一个连续型决策变量
x = model.add_var_tensor(name='x',shape=(3,3),var_type='B') # 创建3*3个二进制决策变量
x = [[ model.add_var(name='x',var_type='I') for i in range(0,3)] for j in range(0,3)] # 创建3*3个整数决策变量

2.1.3 模型状态检查

状态说明:

  • ERROR = -1:求解器返回了一个错误
  • OPTIMAL = 0:得到的最优解
  • INFEASIBLE = 1:建立的模型是一个不可行模型
  • UNBOUNDED = 2:目标函数值是无穷的,且存在一个或多个决策变量不受约束条件限制
  • FEASIBLE = 3:在搜索过程中找到了整数解,但在证明他是最优解之前,求解被中断
  • INT_INFEASIBLE = 4:问题的线性松弛存在可行解,但是不存在整数解
  • NO_SOLUTION_FOUND = 5:执行了截断(truncated)搜索,没找到可行解
  • LOADED = 6:问题被加载了,但是还有执行优化过程
  • CUTOFF = 7:在当前cutoff下没有找到可行的解决方案

代码示例:

status = lp.optimize()
if status == OptimizationStatus.OPTIMAL:
    print('模型已求解到最优')

2.1.4 几个高效率的方法

下面介绍几个提升编码效率的有用的方法:

  • xum():该方法用于构造带求和形式的线性表达式
  • minimize():该方法用于构造最小化目标函数
  • maximize():该方法用于构造最大化目标函数
  • start():该方法可以为模型设置初始解
  • model.threads:该属性可以配置求解模型用到的线程数目,默认使用求解器自身的线程配置;设置的线程多了可能会加速但是会增加内存消耗。
  • model.read(filePath):从指定的路径下读取lp或mps模型文件

2.2 有效不等式的使用

2.2.1 生割或添加lazy_cut

要用的类是:ConstrsGenerator,该类的标准定义为:

class myConstrsGen:
	def _nint__():
		# 类的构造函数
	def generate_constrs(model, depth=0, npass=0):
		# 编写你的生割代码
		# 求解器引擎将自动调用该方法,因此这个方法是生割类必须有的方法,不能少

2.2.2 调用coin-or库中的有效不等式

这些有效不等式是定义在 CutType类中的,主要包含以下几种:

  • PROBING = 0:Cuts generated evaluating the impact of fixing bounds for integer variables
  • GOMORY = 1:Gomory Mixed Integer cuts, as implemented by John Forrest.
  • GMI = 2:Gomory Mixed Integer cuts, as implemented by Giacomo Nannicini, focusing on numerically safer cuts.
  • RED_SPLIT = 3:Reduce and split cuts [AGY05], implemented by Francois Margot.
  • RED_SPLIT_G = 4:Reduce and split cuts [AGY05], implemented by Giacomo Nannicini.
  • FLOW_COVER = 5:Lifted Simple Generalized Flow Cover Cut Generator.
  • MIR = 6:Mixed-Integer Rounding cuts
  • TWO_MIR = 7:Two-phase Mixed-integer rounding cuts.
  • LATWO_MIR = 8:Lagrangean relaxation for two-phase Mixed-integer rounding cuts, as in LAGomory
  • LIFT_AND_PROJECT = 9:Lift-and-project cuts [BCC93], implemented by Pierre Bonami.
  • RESIDUAL_CAPACITY = 10:Residual capacity cuts [AtRa02], implemented by Francisco Barahona.
  • ZERO_HALF = 11:Zero/Half cuts
  • CLIQUE=12:Clique cuts
  • ODD_WHEEL = 13:Lifted odd-hole inequalities.
  • KNAPSACK_COVER = 14:Knapsack cover cuts

使用方法是:

 cp = model.generate_cuts([CutType.GOMORY, CutType.MIR, CutType.ZERO_HALF, CutType.KNAPSACK_COVER])

2.2.3 割池 CutPool

CutPool类中仅有一个方法, add();可以使用该方法将构造的一个或多个cut存储起来,最后统一添加到数学模型中。其典型的用法是:

cp = CutPool()
cp.add(x1 + x2 <= 12)
cp.add(x1 + x2 >= 5)
for cut in cp.cuts:
	model += cut

2.3 获取多个可行解

  • num_solutions 属性,记录了可行解的个数
  • objective_values 属性,记录了可行解的目标函数值
  • xi 方法,记录了决策变量的值
for idx in range(multiSol.num_solutions):
    print(f'第{idx}个可行解的目标函数值为{multiSol.objective_values[idx]}')
    print(f"x1={x1.xi(idx)},x2={x2.xi(idx)}")

3 应用示例

3.1 旅行商问题

3.1.1 问题描述与模型定义

给定一组城市坐标,旅行商需要从其中的某一个城市出发,每个城市访问一次,最终返回到他出发的城市。