问题描述
我一直在使用一个预先存在的作业工具,该工具用于将本科生分配给项目。我现在很想尝试在python中构建一个赋值工具,这将使我能够添加和调整约束,因为由于COVID面临着空间使用方面的巨大压力。
任务的基础是让尽可能多的学生与他们喜欢的导师一起。我有85名学生,他们提供了1到5个优先级主管的排名,这使我可以调整成本变量。此外,还有40位主管,每位主管的能力水平各不相同;有些可以容纳2名学生,有些可以容纳3名,总容量约为100。
到目前为止,我一直在使用Google OR-Tools和python实现,并尝试使用CP-SAT和MIP进行“任务大小分配”策略。我可以使用CP-SAT为小型虚拟数据集生成解决方案,但是当我使用成本矩阵为85x40的去年数据时,我无法生成分配解决方案。相反,MIP求解器方法产生的分配为“ 0成本”,而没有实际分配。我也已经开始构建最小流量模型,但是到目前为止,我还无法使程序在我的输入数据上运行。
我的一般问题是“对于这样的分配问题,即代理人数多于任务,但任务接受能力大于1个代理的任务,什么是最佳的一般方法?”
很高兴提供有用的代码。 谢谢,戴夫
编辑 下面是我一直在尝试CP-SAT解决方案的代码。最初,我填充一个由学生数量和职员数量定义的大小的np数组,并使用值100填充它。这是我在成本矩阵中无法选择的元素所使用的。我接受了学生的选择(1至5),并进行平方以给出一些区别:
from __future__ import print_function
from ortools.sat.python import cp_model
import time
import pandas as pd
import numpy as np
capacity=pd.read_excel(r'C:\Users\Dave\Documents\assign_2019.xlsx',index_col=0,sheet_name='capacity')
capacity=capacity.reset_index()
choices=pd.read_excel(r'C:\Users\Dave\Documents\assign_2019.xlsx',sheet_name='choices')
choices=choices.reset_index()
array=np.empty((len(choices),len(capacity)))
array.fill(100)
cost = pd.DataFrame(data=array)
cost.index=choices['student']
cost.columns=capacity['staff']
choices=choices.set_index(['student'])
for i in choices.index:
for j in choices.columns:
s=choices.loc[i,j]
cost.loc[i,s]=j**2
cost=cost.to_numpy()
cost=cost.astype(int)
sizes = capacity['capacity']
sizes=sizes.to_numpy()
sizes=sizes.astype(int)
def main():
model = cp_model.CpModel()
start = time.time()
num_workers = len(cost)
num_tasks = len(cost[1])
# Variables
x = []
for i in range(num_workers):
t = []
for j in range(num_tasks):
t.append(model.NewIntvar(0,1,"x[%i,%i]" % (i,j)))
x.append(t)
x_array = [x[i][j] for i in range(num_workers) for j in
range(num_tasks)]
# Constraints
# Each staff is allocated no more than capacity.
[model.Add(sum(x[i][j] for i in range(num_workers)) <= sizes[j])
for j in range(num_tasks)]
# Number of projects allocated to a student is 1.
[model.Add(sum(x[i][j] for j in range(num_tasks)) == 1)
for i in range(num_workers)]
model.Minimize(sum([np.dot(x_row,cost_row) for (x_row,cost_row) in
zip(x,cost)]))
solver = cp_model.cpsolver()
status = solver.solve(model)
if status == cp_model.OPTIMAL:
print('Minimum cost = %i' % solver.ObjectiveValue())
print()
for i in range(num_workers):
for j in range(num_tasks):
if solver.Value(x[i][j]) >= 1:
print('Worker ',i,' assigned to task ',j,' Cost = ',cost[i][j])
print()
end = time.time()
print("Time = ",round(end - start,4),"seconds")
if __name__ == '__main__':
main()
编辑2: 用于MIP求解器的代码(数据输入与上述CP-SAT尝试相同):
def main():
solver = pywraplp.solver('SolveAssignmentProblem',pywraplp.solver.CBC_MIXED_INTEGER_PROGRAMMING)
start = time.time()
num_workers = len(cost)
num_tasks = len(cost[1])
# Variables
x = {}
for i in range(num_workers):
for j in range(num_tasks):
x[i,j] = solver.Intvar(0,'x[%i,%i]' % (i,j))
# Constraints
# Staff can accept students up to capacity.
for i in range(num_workers):
solver.Add(solver.Sum([x[i,j] for j in range(num_tasks)]) <=
sizes[j])
# Student is allocated 1 project.
for j in range(num_tasks):
solver.Add(solver.Sum([x[i,j] for i in range(num_workers)]) == 1)
solver.Minimize(solver.Sum([cost[i][j] * x[i,j] for i in
range(num_workers)
for j in range(num_tasks)]))
print('Minimum cost = ',solver.Objective().Value())
print()
for i in range(num_workers):
for j in range(num_tasks):
if x[i,j].solution_value() > 0:
print('Worker',' assigned to task',cost[i]
[j])
print()
end = time.time()
print("Time = ","seconds")
if __name__ == '__main__':
main()
尝试进行MIP的结果是:
Minimum cost = 0.0
Time = 0.553 seconds
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)