我想选择方形矩阵的方形固定大小子集,以便最小化子集矩阵的总和。一些代码:
import nump as np
import pulp
def subset_matrix(data, inds):
return data[np.ix_(inds, inds)]
A = np.random.random((10, 10))
indices = list(range(len(A)))
prob = pulp.LpProblem("Minimum subset", pulp.LpMaximize)
x = pulp.LpVariable.dicts('elem', indices, lowBound=0, upBound=1, cat=pulp.LpInteger)
prob += pulp.lpSum(subset_matrix(A, [x[i] for i in indices]))
prob.solve()
这失败了,因为numpy索引不喜欢inds
是LpVariables
的列表。有没有解决的办法?如何使纸浆约束包含一个numpy数组查找?
答案 0 :(得分:2)
我认为这不是一个PuLP问题,而是一个如何将数学问题正确地形成为混合整数线性程序的问题。
在您要优化的一组索引中,您似乎试图将您的目标表达为系数之和(“子集矩阵的总和”)。 (顺便说一下,我没有看到子矩阵上的大小约束写在哪里。)但MILP要求目标是决策变量向量与成本系数向量的点积,超过预定的索引集。因此,在自然公式中,决策向量将使用二进制值表示您选择的完整索引集中的哪些索引位于子矩阵中。
如果我明白你要做什么,这似乎是一个很好的问题。我相信你试图选择一个固定大小的索引子集I \ subset {0,1,...,N-1},这样总和{A(i,j):i,j都在I}最大化。假设例如大矩阵是10x10,你想要一个6x6子矩阵。所以我是{0,...,9}的六个元素。
然后我将在{0,...,9}中为i,j定义变量x(i,j),对于为子矩阵选择的大矩阵的每个元素等于1(否则为零)和{0,...,9}中的变量y(i),i,用于所选的索引。然后我会尝试将这些约束表示为线性,并使y变量二进制表示每个索引都在或不在。
以下是我认为你的意思的表述:
import pulp as pp
import numpy as np
import itertools
#####################
# Problem Data: #
#####################
full_matrix_size = 10
submatrix_size = 6
A = np.random.random((full_matrix_size, full_matrix_size)).round(2)
inds = range(full_matrix_size)
product_inds = list(itertools.product(inds,inds))
#####################
# Variables: #
#####################
# x[(i,j)] = 1 if the (i,j)th element of the data matrix is in the submatrix, 0 otherwise.
x = pp.LpVariable.dicts('x', product_inds, cat='Continuous', lowBound=0, upBound=1)
# y[i] = 1 if i is in the selected index set, 0 otherwise.
y = pp.LpVariable.dicts('y', inds, cat='Binary')
prob = pp.LpProblem("submatrix_problem", pp.LpMaximize)
#####################
# Constraints: #
#####################
# The following constraints express the required submatrix shape:
for (i,j) in product_inds:
# x[(i,j)] must be 1 if y[i] and y[j] are both in the selected index set.
prob += pp.LpConstraint(e=x[(i,j)] - y[i] - y[j], sense=1, rhs=-1,
name="true_if_both_%s_%s" % (i,j))
# x[(i,j)] must be 0 if y[i] is not in the selected index set.
prob += pp.LpConstraint(e=x[(i,j)] - y[i], sense=-1, rhs=0,
name="false_if_not_row_%s_%s" % (i,j))
# x[(i,j)] must be 0 if y[j] is not in the selected index set.
prob += pp.LpConstraint(e=x[(i,j)] - y[j], sense=-1, rhs=0,
name="false_if_not_col_%s_%s" % (i,j))
# The number of selected indices must be what we require:
prob += pp.LpConstraint(e=pp.LpAffineExpression([(y[i],1) for i in inds]), sense=0,
rhs=submatrix_size, name="submatrix_size")
#####################
# Objective: #
#####################
prob += pp.LpAffineExpression([(x[pair], A[pair]) for pair in product_inds])
print(prob)
########################
# Create the problem: #
########################
prob.writeLP("max_sum_submatrix.lp")
prob.solve()
##########################
# Display the solution: #
##########################
print("The following indices were selected:")
print([v.name for v in prob.variables() if v.name[0]=='y' and v.varValue==1])
print("Objective value is " + str(pp.value(prob.objective)))
我猜这是一个带回家的考试问题....至少学期已经结束了。