Я использую cvxpy
в python
для решения определенного типа задачи назначения. Я хотел бы назначить M людей на N групп таким образом, чтобы минимизировать затраты со следующими ограничениями для групп:
- В группах не может быть более J участников
- Если группа заполнена, она должна содержать не менее K членов, в противном случае группа может иметь ноль членов.
Конечно, J <= K. Я могу решить проблему, игнорируя # 2 выше. В приведенном ниже примере M = 6, N = 3 и J = 3. В идеале я хотел бы установить K = 2. Я генерирую предпочтения так, что все предпочитают группу 1 (столбец 1 в функции стоимости), тогда большинство людей предпочитают группу 2, но один человек предпочитает группу 3 группе 2: </p>
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, я получу три группы по 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.
Есть ли способ включить это нестандартное ограничение? Кроме того, если я смогу использовать вышеуказанные ограничения, я смогу решить мою проблему, но я смогу решить свою проблему еще проще, если вы скажете мне, как включить ограничение, как показано ниже:
- Размеры группы должны быть кратны нулю, J или K.