使用多进程在Python中构建Gurobi表达式
首先,我正在使用jupyter笔记本,python版本3.5,Gurobi 7.0.2及其python接口,所有这些都在Red Hat上 这就是我问题的背景:我想解决一个二次问题,它有大量的变量。建立目标函数需要1-2个多小时 我曾考虑过使用NumPy GPU加速,但表达式有点复杂,因此,这不是一个解决方案 因此,我尝试使用几个线程来构建目标函数。然而,我得到了一个错误,我不知道如何处理它 我简化了我的代码,因此它更具可读性(错误仍然相同)使用多进程在Python中构建Gurobi表达式,python,multithreading,python-3.x,gurobi,Python,Multithreading,Python 3.x,Gurobi,首先,我正在使用jupyter笔记本,python版本3.5,Gurobi 7.0.2及其python接口,所有这些都在Red Hat上 这就是我问题的背景:我想解决一个二次问题,它有大量的变量。建立目标函数需要1-2个多小时 我曾考虑过使用NumPy GPU加速,但表达式有点复杂,因此,这不是一个解决方案 因此,我尝试使用几个线程来构建目标函数。然而,我得到了一个错误,我不知道如何处理它 我简化了我的代码,因此它更具可读性(错误仍然相同) 首先,Gurobi优化器不支持多线程进行模型构建。即使
首先,Gurobi优化器不支持多线程进行模型构建。即使我们这样做了,在正确编写的应用程序中,模型构建几乎从来都不是瓶颈 在本例中,有许多表达式看起来像x+x+x。虽然正确,但这是非常低效的——写3*x要好得多。下面是惩罚函数的快速重写:
# var is an array of GRB.BINARY
# D=edge_costs
def penalty_function(var,obj,D):
num_nodes = len(var)
for i,fil in enumerate(D):
for j,val in enumerate(fil):
# -x*D*x
if val!=0:
obj+=var[i]*var[j]*val
# -x(i)x(j)*min(Ds)
if(j>i):
minval = sum(min(D[j][k],D[i][k]) for k in range(num_nodes))
if minval != 0:
obj += var[i]*var[j]*minval
return obj
对于埃尔文·卡维拉根提出的问题,一个快速的解决办法是
编辑:通过组合两个var[i]*var[j]术语,我们可以使惩罚函数稍微更有效:
def penalty_function(var,obj,D):
num_nodes = len(var)
for i,fil in enumerate(D):
for j,val in enumerate(fil):
# -x(i)x(j)*min(Ds)
if(j>i):
val += sum(min(D[j][k],D[i][k]) for k in range(num_nodes))
# -x*D*x
if val!=0:
obj += var[i]*var[j]*val
return obj
在添加GregGlockner改进后,我意识到我可以以不同的方式使用numpy和多线程。我把它加在这里,以防有人对它感兴趣
def parallel_function(D,num_nodes,start,end):
minD=[]
if(end>num_nodes-1):
end=num_nodes
for i in range(start,end,1):
# fill with 0 (triangular matrix)
minval=[0]*(i+1)
for j,val in enumerate(D[i]):
if(j>i):
minval.append(sum(min(D[j][k],D[i][k]) for k in range(num_nodes)))
minD.append(minval)
return minD
def penalty_function(var,obj,D,num_nodes):
num_process=8
inc=math.ceil(num_nodes/num_process)
if __name__ == '__main__':
pool = mp.Pool(processes=num_process) # start 8 worker processes
minval=pool.starmap(parallel_function, [(D,num_nodes,u*inc,u*inc+inc) for u in range(8)])
pool.close()
minD=[]
for x in minval:
minD=minD+x
obj+=np.array(var).dot((np.array(minD)+np.array(D))).dot(var)
return obj
更多信息会有所帮助。有多少个变量?对于目标函数,线性项中有多少个非零,二次项中有多少个非零?计算机上的内存和处理器是什么?是的,我使用的是Intel(R)Core(TM)i7 CPU 870@2.93GHz和16GB内存。一个简化的问题是:优化一个有1行、414列和414个非零的模型模型有4257个二次目标项变量类型:0个连续变量、414个整数(414个二进制变量),顺便说一句,我不是在寻找最优解。我想这个问题很难解决。到目前为止,我已经设置了一个超时,我对古洛比给我的结果感到满意。我的问题是在优化之前,当我在构建目标函数时。但是,我将添加更多关于目标函数的信息。请注意,两个二进制变量的乘法可以很容易地线性化。这里不需要使用二次项。我如何建模?可能是这样的?:x*y等于z,有两个约束z≤x和z≤设置PreQLinearize参数非常有效。由于你回答的第一部分,我将把这个问题设置为已解决。非常感谢你!
# var is an array of GRB.BINARY
# D=edge_costs
def penalty_function(var,obj,D):
num_nodes = len(var)
for i,fil in enumerate(D):
for j,val in enumerate(fil):
# -x*D*x
if val!=0:
obj+=var[i]*var[j]*val
# -x(i)x(j)*min(Ds)
if(j>i):
minval = sum(min(D[j][k],D[i][k]) for k in range(num_nodes))
if minval != 0:
obj += var[i]*var[j]*minval
return obj
def penalty_function(var,obj,D):
num_nodes = len(var)
for i,fil in enumerate(D):
for j,val in enumerate(fil):
# -x(i)x(j)*min(Ds)
if(j>i):
val += sum(min(D[j][k],D[i][k]) for k in range(num_nodes))
# -x*D*x
if val!=0:
obj += var[i]*var[j]*val
return obj
def parallel_function(D,num_nodes,start,end):
minD=[]
if(end>num_nodes-1):
end=num_nodes
for i in range(start,end,1):
# fill with 0 (triangular matrix)
minval=[0]*(i+1)
for j,val in enumerate(D[i]):
if(j>i):
minval.append(sum(min(D[j][k],D[i][k]) for k in range(num_nodes)))
minD.append(minval)
return minD
def penalty_function(var,obj,D,num_nodes):
num_process=8
inc=math.ceil(num_nodes/num_process)
if __name__ == '__main__':
pool = mp.Pool(processes=num_process) # start 8 worker processes
minval=pool.starmap(parallel_function, [(D,num_nodes,u*inc,u*inc+inc) for u in range(8)])
pool.close()
minD=[]
for x in minval:
minD=minD+x
obj+=np.array(var).dot((np.array(minD)+np.array(D))).dot(var)
return obj