不是迭代所有 2^p 组合,您可以生成此类二进制矩阵的一种方法是根据您拥有的给定约束执行重复的行和列操作。例如,我将发布一些代码,这些代码将根据您上面列出的三个约束生成一个矩阵:
- 每列最少零个数
- 每行的最小总和
- 每列的最小连续长度
初始化:
首先初始化几个参数:
nRows = 10; % Row size of matrix
nColumns = 10; % Column size of matrix
minZeroes = 5; % Constraint 1 (for columns)
minRowSum = 5; % Constraint 2 (for rows)
minLengthOnes = 3; % Constraint 3 (for columns)
辅助函数:
接下来,创建几个函数来生成与上面的约束 1 和 3 匹配的列向量:
function vector = make_column
vector = [false(minZeroes,1); true(nRows-minZeroes,1)]; % Create vector
[vector,maxLength] = randomize_column(vector); % Randomize order
while maxLength < minLengthOnes, % Loop while constraint 3 is not met
[vector,maxLength] = randomize_column(vector); % Randomize order
end
end
function [vector,maxLength] = randomize_column(vector)
vector = vector(randperm(nRows)); % Randomize order
edges = diff([false; vector; false]); % Find rising and falling edges
maxLength = max(find(edges == -1)-find(edges == 1)); % Find longest
% sequence of ones
end
make_column 函数将首先创建一个逻辑列向量,其中元素最少为 0,其余元素设置为 1(使用函数 TRUE 和 FALSE)。该向量将对其元素进行随机重新排序,直到它包含大于或等于所需最小长度的一序列。这是使用 randomize_column 函数完成的。使用RANDPERM 函数对向量进行随机重新排序,以生成随机索引顺序。使用DIFF 函数检测序列在 0 和 1 之间切换的边沿。然后使用边缘的索引来查找最长序列的长度(使用FIND 和MAX)。
生成矩阵列:
通过以上两个函数,我们现在可以生成一个至少满足约束 1 和 3 的初始二进制矩阵:
binMat = false(nRows,nColumns); % Initialize matrix
for iColumn = 1:nColumns,
binMat(:,iColumn) = make_column; % Create each column
end
满足行和约束:
当然,现在我们必须确保满足约束 2。我们可以使用SUM 函数对每一行求和:
rowSum = sum(binMat,2);
如果 rowSum 的任何元素小于我们想要的最小行总和,我们将不得不调整一些列值来补偿。您可以通过多种不同的方式来修改列值。我这里举一个例子:
while any(rowSum < minRowSum), % Loop while constraint 2 is not met
[minValue,rowIndex] = min(rowSum); % Find row with lowest sum
zeroIndex = find(~binMat(rowIndex,:)); % Find zeroes in that row
randIndex = round(1+rand.*(numel(zeroIndex)-1));
columnIndex = zeroIndex(randIndex); % Choose a zero at random
column = binMat(:,columnIndex);
while ~column(rowIndex), % Loop until zero changes to one
column = make_column; % Make new column vector
end
binMat(:,columnIndex) = column; % Update binary matrix
rowSum = sum(binMat,2); % Update row sum vector
end
此代码将循环直到所有行总和大于或等于我们想要的最小总和。首先,使用MIN 找到总和最小的行的索引 (rowIndex)。接下来,找到该行中零的索引,并随机选择其中一个作为要修改的列的索引(columnIndex)。使用 make_column,不断生成新的列向量,直到给定行中的 0 变为 1。然后更新二进制矩阵中的该列并计算新的行和。
总结:
对于一个相对较小的 10×10 二进制矩阵和给定的约束,上述代码通常在几秒钟内完成。有了更多的约束,事情当然会变得更加复杂。根据您选择约束的方式,可能没有可能的解决方案(例如,将 minRowSum 设置为 6 将导致上述代码从不收敛到一个解决方案)。
希望这将为您提供一个起点,开始使用矢量化操作生成您想要的各种矩阵。