我正在cvxpy
中使用python
解决特定类型的分配问题。我想以最小化成本的方式将M个人分配给N个组,但对组有以下限制:
当然,J <=K。我可以解决上述#2的问题。在下面的示例中,M = 6,N = 3,J =3。理想情况下,我想设置K =2。我生成首选项,以便每个人都喜欢组1(成本函数中的第1列),然后大多数人更喜欢第2组,但有人更喜欢第3组而不是第2组:
import numpy as np import cvxpy as cp
preference = np.array([[1,2,3],
[1,2,3],
[1,2,3],
[1,2,3],
[1,2,3],
[1,3,2]])
groupmax = np.array([3,3,3])
selection = cp.Variable(shape=preference.shape,boolean=True)
group_constraint_1 = cp.sum(selection,axis=0) <= groupmax
assignment_constraint = cp.sum(selection,axis=1) == 1
cost = cp.sum(cp.multiply(preference,selection))
constraints = [group_constraint_1,assignment_constraint]
assign_prob = cp.Problem(cp.Minimize(cost),constraints)
assign_prob.solve(solver=cp.GLPK_MI)
print(selection.value)
解决方案/分配是:
[[1. 0. 0.]
[1. 0. 0.]
[1. 0. 0.]
[0. 1. 0.]
[0. 1. 0.]
[0. 0. 1.]]
也就是说,我有一个最大尺寸为3的组,另一个最大尺寸为2的组和一个最大尺寸为1的组。在理想的设置中,一个1的组(第3组)太小了,那个人会分配给第2组。请注意,如果我仅将最小组大小设为2,则改为获得3组,每组2个:
import numpy as np import cvxpy as cp
preference = np.array([[1,2,3],
[1,2,3],
[1,2,3],
[1,2,3],
[1,2,3],
[1,3,2]])
groupmax = np.array([3,3,3])
groupmin = np.array([2,2,2])
selection = cp.Variable(shape=preference.shape,boolean=True)
group_constraint_1 = cp.sum(selection,axis=0) <= groupmax
group_constraint_2 = cp.sum(selection,axis=0) => groupmin
assignment_constraint = cp.sum(selection,axis=1) == 1
cost = cp.sum(cp.multiply(preference,selection))
constraints = [group_constraint_1,group_constraint_2,assignment_constraint]
assign_prob = cp.Problem(cp.Minimize(cost),constraints)
assign_prob.solve(solver=cp.GLPK_MI)
print(selection.value)
现在的解决方案是:
[[1. 0. 0.]
[1. 0. 0.]
[0. 1. 0.]
[0. 1. 0.]
[0. 0. 1.]
[0. 0. 1.]]
我尝试了以下解决方法,但是下面的第三个约束被cvxpy
拒绝,因为问题不再是DCP。我认为问题在于我要在约束中将一个变量乘以另一个变量。我想不出另一种方法来使一个组中的总人数大于2或正好为零:
import numpy as np
import cvxpy as cp
preference = np.array([[1,2,3],
[1,2,3],
[1,2,3],
[1,2,3],
[1,2,3],
[1,3,2]])
groupmax = np.array([3,3,3])
selection = cp.Variable(shape=preference.shape,boolean=True)
switch_1 = cp.Variable(shape=preference.shape[1],boolean=True)
switch_2 = cp.Variable(shape=preference.shape[1],boolean=True)
group_constraint_1 = cp.sum(selection,axis=0) <= groupmax
group_constraint_2 = cp.sum(selection,axis=0) - 2 * switch_1 >= 0
group_constraint_3 = cp.sum(selection,axis=0) * switch_2 == 0
switch_constraint = switch_1 + switch_2 == 1
assignment_constraint = cp.sum(selection,axis=1) == 1
cost = cp.sum(cp.multiply(preference,selection))
constraints = [group_constraint_1,group_constraint_2,group_constraint_3,
switch_constraint,assignment_constraint]
assign_prob = cp.Problem(cp.Minimize(cost),
constraints)
assign_prob.solve(solver=cp.GLPK_MI)
print(selection.value)
我现在收到以下错误:DCPError: Problem does not follow DCP rules.
有没有办法纳入这种非标准约束?另外,如果我可以使用上述约束,则可以解决问题,但是如果您可以告诉我如何合并如下约束,则可以更轻松地解决问题:
答案 0 :(得分:0)
经过四处搜寻,我找到了解决自己问题的方法。以下解决了该问题:
import numpy as np
import cvxpy as cp
preference = np.array([[1,2,3],
[1,2,3],
[1,2,3],
[1,2,3],
[1,2,3],
[1,3,2]])
groupmax = np.array([3,3,3])
selection = cp.Variable(shape=preference.shape,boolean=True)
bind_2 = cp.Variable(shape=preference.shape[1],boolean=True)
bind_3 = cp.Variable(shape=preference.shape[1],boolean=True)
group_constraint_1 = cp.sum(selection,axis=0) <= groupmax
group_constraint_2 = (1 - bind_2) * 2 >= 2 - cp.sum(selection,axis=0)
group_constraint_3 = (1 - bind_3) * 4 >= cp.sum(selection,axis=0)
bind_constraint = bind_2 + bind_3 == 1
assignment_constraint = cp.sum(selection,axis=1) == 1
cost = cp.sum(cp.multiply(preference,selection))
constraints = [group_constraint_1,group_constraint_2,group_constraint_3,
bind_constraint,assignment_constraint]
assign_prob = cp.Problem(cp.Minimize(cost),constraints)
assign_prob.solve(solver=cp.GLPK_MI)
print(selection.value)
现在,我得到以下解决方案:
[[1. 0. 0.]
[0. 1. 0.]
[1. 0. 0.]
[0. 1. 0.]
[0. 1. 0.]
[1. 0. 0.]]
说明:
bind
变量是二进制变量,表示约束2和3是否绑定bind
变量之一限制为等于1。因此,每个组的总数可以大于2或正好为零。到目前为止,我无法扩展到组大小需要为零,J或K的倍数的情况。原因是我无法在cvxpy中使用mod
函数。
解决方案的想法来自here