在 Gurobi 中,quicksum()
和 addTerms()
函数都用于构建线性表达式,但它们的使用场景略有不同。下面我将解释它们的作用及用法,并提供示例说明。
1. quicksum()
函数:
- 作用:用于快速构建对多个变量的求和的线性表达式。
- 用法:
quicksum(expr_list)
,其中expr_list
是一个变量和系数的列表或生成器表达式。 - 示例:
import gurobipy as gp
from gurobipy import GRB
# 创建一个新的模型
model = gp.Model()
# 添加变量
x = model.addVars(5, vtype=GRB.CONTINUOUS, name="x")
# 构建线性表达式:x[0] + x[1] + x[2] + x[3] + x[4]
expr = gp.quicksum(x[i] for i in range(5))
# 输出线性表达式
print(expr)
2. addTerms()
函数:
- 作用:用于向线性表达式中添加一个或多个项。
- 用法:
addTerms(coefficients, variables, constant=None)
,其中coefficients
是项的系数,variables
是对应的变量,constant
是常数项。 - 示例:
import gurobipy as gp
from gurobipy import GRB
# 创建一个新的模型
model = gp.Model()
# 添加变量
x = model.addVars(5, vtype=GRB.CONTINUOUS, name="x")
# 创建一个空的线性表达式
expr = gp.LinExpr()
# 向线性表达式中添加项:2*x[0] + 3*x[1] + 4*x[2] + 5*x[3] + 6*x[4]
expr.addTerms([2, 3, 4, 5, 6], x)
# 输出线性表达式
print(expr)
总的来说,quicksum()
函数适用于快速构建对多个变量的求和的线性表达式,而 addTerms()
函数则适用于向线性表达式中逐项添加项。根据具体的情况,你可以选择使用其中的一个函数来构建线性表达式。
代码示例:
# 约束
for i in range(1, data.nodeNum - 1):
expr = LinExpr(0)
for j in range(data.nodeNum):
if i != j:
for k in range(data.vehicleNum):
if i != 0 and i != data.nodeNum - 1:
expr.addTerms(1, X[i][j][k])
model.addConstr(expr == 1)
这段代码是在使用Python的优化建模库来创建约束条件。具体来说,它是在使用线性表达式(Linear Expression)来设置一个约束条件,确保对于每个节点 i(排除起点和终点),有且仅有一个车辆从该节点出发。
下面是代码的逐行解释:
-
for i in range(1, data.nodeNum - 1):
:遍历节点编号,从第二个节点到倒数第二个节点(排除起点和终点)。 -
expr = LinExpr(0)
:创建一个新的线性表达式,初始值为0。这个表达式将用来表示约束条件。 -
for j in range(data.nodeNum):
:遍历所有节点,包括起点和终点。 -
if i != j:
:确保节点 i 和 j 不相等,即不考虑从节点 i 到节点 i 的情况。 -
for k in range(data.vehicleNum):
:遍历所有车辆编号。 -
if i != 0 and i != data.nodeNum - 1:
:检查节点 i 是否为起点或终点之一,如果不是则执行以下操作。 -
expr.addTerms(1, X[i][j][k])
:将变量 X[i][j][k](表示车辆 k 从节点 i 出发到节点 j 的路径是否被选择)的系数设置为1,并添加到线性表达式 expr 中。 -
model.addConstr(expr == 1)
:将刚刚创建的线性表达式 expr 加入到优化模型中作为一个约束条件,要求该表达式的结果等于1,即确保对于节点 i,有且仅有一个车辆从该节点出发。
这段代码的作用是确保每个节点(除了起点和终点)只有一个车辆从该节点出发,从而满足路径规划问题的约束条件。
在这段代码中,expr = LinExpr(0)
是在第一层循环下面而不是在循环之前初始化的原因是因为每次循环需要创建一个新的线性表达式,以确保每个约束条件都是独立的。如果将 expr = LinExpr(0)
放在循环之前,那么在每次迭代时,都会在同一个线性表达式对象上累加系数,而不是创建新的表达式,这将导致约束条件叠加在一起,而不是独立地添加到模型中。
通过在每次循环迭代中创建一个新的线性表达式对象,可以确保每个约束条件都是独立的,不会互相影响。因此,将 expr = LinExpr(0)
放在第一层循环内部是为了确保每个节点 i 对应的约束条件都有自己独立的线性表达式对象。
以下是使用quicksum
函数重写的代码:
for i in range(1, data.nodeNum - 1):
expr = quicksum(X[i][j][k] for j in range(data.nodeNum) if i != j for k in range(data.vehicleNum) if i != 0 and i != data.nodeNum - 1)
model.addConstr(expr == 1)
这段代码与之前的代码实现相同的功能,但使用了quicksum
函数来计算表达式中的求和部分。quicksum
函数是优化库中的一个函数,用于快速求解迭代求和。