在矩阵中查找k个不相交行的组

时间:2014-08-27 19:05:05

标签: algorithm matlab matrix combinatorics

问题陈述:S成为一组整数,例如S = {1,2,...,12}M是一个整数矩阵,其行可以被视为S的子集,其长度除以S的元素数,特别是M的每一行只包含不同的元/整数。我正在尝试生成Matlab代码,该代码可以识别M的所有不相交行组,其集合理论联合给出S(即具有固定大小的子集中的S分区)和将每个这样的组作为矩阵返回。

示例: A = [1 2 5 6; 3 4 11 12; 9 10 7 8]S的分区,而B = [1 2 3 4; 5 6 7 8; 9 10 11 12; 1 5 9 12]不是S的分区(因为最后一行不是与之前的3)脱节。

数量级:通常情况下,M会有~500 000行,而S最多会有100个元素。

到目前为止

方法:m = size(M,1)n = size(M,2)(分区子集的大小),s = |S|(要分区的集合的大小)和{ {1}}(形成分区所需的不相交行数 - 您可以假设k = s/n,因此问题定义明确)。请注意,为了建立这样的分区,只需要检查行的不相交性,并且确实有s = 0 mod n个行。

对于k,我观察j = 1:(m-k+1),它给出了ind = (sum(ismember(M((j+1):m,:),M(j,:)),2)==0)之后也与之不相交的行的索引列。然后,我通过将M(j,:)与每个行组合来创建2 x n矩阵。在那之后,我想用所有这些新的M(j,:)矩阵重复ismember()例程并继续重复,直到我得到2 x n矩阵。这可能都是好事和花花公子,但它也是我绊倒的地方,因为,对于一个,k x n - 例程的数量取决于for

问题:

(Q1)如何完成我的方法代码?

(Q2)是否有更好的方法解决这个问题(即更快,矢量化/更少k循环,GPU辅助),如果是,它们是什么?

2 个答案:

答案 0 :(得分:2)

这个问题是exact cover的一个非常特殊的情况。如果你在C中工作,我会建议使用Knuth's Algorithm X而不是bit arrays来实施dancing links,因为您关心的实例的密度明显。我希望MATLAB几乎可以容纳你。

作为整数,集合{1,2,5,6}可以表示为2 ** 1 + 2 ** 2 + 2 ** 5 + 2 ** 6。然后两个集合的交集表示为它们的表示的bitwise and,并且两个集合的并集是按位或。空集为0.不幸的是,对于S = 100,您需要使用两个或更多个整数,这会使生命复杂化。拍摄集合后,您可以通过矢量化bitand检测与其他集合的交叉点。

答案 1 :(得分:0)

这是你想要的吗? 我假设M中的行的顺序很重要(即,置换2行是另一个有效的M)。 此示例为您提供了包含2列和3行的所有矩阵,其中元素都是不同的,并且在{1,2,3,4,5,6}中。但是,行是{1,2,3,4,5,6}的子集,其中顺序无关紧要。不确定这是不是你的意思。如果订单很重要,我们可以添加perms以获取nchoosek返回的每一行的所有可能排列。

我不得不使用递归函数,所以你必须把它放在一个文件中:

function test()
    s = 1:6;
    n = 2;

    M_all = ProcessOneRow(s, n, {}, {});

    disp('All possilbe M:')
    M_all
end

function M_all = ProcessOneRow(s, n, cRows, M_all)

    %// find all possible rows for this level
    possibleRows = nchoosek(1:length(s), n);

    for t=1:size(possibleRows, 1)
        %// keep track of all rows so far
        cRows(end+1) = s(possibleRows(t,:));

        %// get elements remaining (remove this row)
        s_sub = s;
        s_sub(possibleRows(t,:)) = [];

        if isempty(s_sub)
            %// We found a new complete matrix M
            M = [];
            for p = 1:numel(cRows)
                M(p,:) = cRows{p};
            end
            M_all{end+1} = M;
        else
            %// Still not a complete M, so we process the rest
            M_all = ProcessOneRow(s_sub, n, cRows, M_all);
        end
        cRows(end) = [];
    end
end