在行和列总和的约束下找到NxN矩阵的元素 - Mathematica或Matlab

时间:2015-12-18 15:14:43

标签: matlab matrix constraints wolfram-mathematica linear-algebra

我正在尝试找到NxN矩阵的元素,以便满足给定的行和列总和。唯一的另一个约束是矩阵的元素被限制为整数0和1.

这可能是Matlab或Mathematica中的一些简单的界限(我在这里找到并在R中发现了一些相关的问题),但我的相关编码经验只是在有限的优化中 - 我在这里丢失了最小化的目标函数。

我的第一个想法是设置一个线性代数问题,Ax = b,但这不起作用,因为A'A是单数。 (我将在下面的评论中提供详细信息,以防它有所帮助。)

我的下一个想法是试图通过赋予它“约束Ax = b和整数约束”的“虚拟”目标函数来“欺骗”Mathematica中的NMinimize求解器:

    x = Map[Subscript[x, #] &, Range[1, Ngrid^2]];
    x = Map[Subscript[x, #] &, Range[1, Ngrid^2]];
    NMinimize[{x.x\[Transpose], A.x == b && Apply[And,Thread[GreaterEqual[x, 0]]] && 
    Apply[And, Thread[LessEqual[x, 1]]] && Element[x,Integers]}, x, 
    Method -> "DifferentialEvolution", MaxIterations -> 2000];

但它遇到了相同的“递归”错误。

我感觉这不是解决问题的方法。是否有一些命令允许我根据约束填充矩阵的元素?如果它没有生成唯一的解决方案,有没有办法查看解决方案集?

谢谢, 丹

编辑:这是我对线性代数解决方案的想法,Ax = b:

A是0s和1s的2N×N ^ 2矩形矩阵。每列对应于解向量x中的N ^ 2个元素之一(我们之后的重构的NxN矩阵)。 (编辑:前N行对应于受每个行约束影响的x元素,后N行对应于受每个列约束影响的x元素。)

x是0和1的N ^ 2 x 1向量(重构的NxN解矩阵)。

b是行和列总和的2N x 1向量(约束)。

示例:

如果N = 3并且我们想找到x(ETA:下面的“x”是我们所追求的解决方案;我们不提前知道它):

    1   0   0
    1   0   1
    0   1   0

我们可以写A =

    1   1   1   0   0   0   0   0   0
    0   0   0   1   1   1   0   0   0
    0   0   0   0   0   0   1   1   1
    1   0   0   1   0   0   1   0   0
    0   1   0   0   1   0   0   1   0
    0   0   1   0   0   1   0   0   1

并且z =

    1
    2
    1
    2
    1
    1

求解并不像x = inv(A'A)* A'z那么简单,因为A'A没有逆。

提前感谢您提供的任何帮助!

2 个答案:

答案 0 :(得分:6)

这是一种天真的做法。这取决于你需要如何扩大规模:

n = 3;
sumsrows = {2, 1, 1};
sumscols = {1, 2, 1};
X = Array[x, {n, n}];

fi = FindInstance[
   And @@ Thread[(Tr /@ X) == sumsrows] && 
   And @@ Thread[(Tr /@ Transpose@X) == sumscols] && 
   And @@ Thread[0 <= Flatten@X <= 1], Flatten@X, Integers]

Partition[fi[[1, All, 2]], n] // MatrixForm

Mathematica graphics

答案 1 :(得分:0)

另一种非常幼稚的方法是生成随机的“二进制”矩阵,并在其中一个满足您的条件时停止。这是MATLAB代码:

n = 3;
row_sums = [2; 1; 1];
col_sums = [1, 2, 1];
solution_found = false;

while ~solution_found
    X = randi([0, 1], n);
    if isequal(sum(X, 2), row_sums) && isequal(sum(X, 1), col_sums)
        solution_found = true;
    end
end