【问题标题】:Finding groups of k disjoint rows in a matrix在矩阵中查找由 k 个不相交行组成的组
【发布时间】:2014-08-27 19:05:05
【问题描述】:

问题说明: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|(要分区的集合的大小)和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,:) 之后的行的索引列,这些行也与之不相交。然后我通过将M(j,:) 与每一行组合来创建2 x n 矩阵。之后,我想用所有这些新的2 x n 矩阵重复ismember()routine,并继续重复直到我得到k x nmatrices。这可能一切都很好而且很花哨,但这也是我绊倒的地方,因为一方面,for-routines 的数量取决于k

问题:

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

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

【问题讨论】:

  • M 是否有典型的列数。即nS 总是有唯一的整数集吗?
  • n 不应该超过 8 或 9,如果我没记错的话。对于S,可以假设S = unique(M),即S 的所有元素都已经包含在M 的某处。 S 的所有元素都是不同的,它们的顺序无关紧要。希望我正确理解了您的第二个问题。
  • @July:在您的大部分问题中,M 是您输入矩阵的名称,但在示例中,M 是一种可能的解决方案,请在此处重命名。至少我们知道您的解决方案的大小是numel(S),这允许尝试近似值并在达到此大小时停止。你能提供一个示例数据集吗?
  • @Daniel:哎呀,抱歉,已修复。当然,我可以提供一个数据集,如果你告诉我在哪里上传它以及你希望它有多大。
  • 对于第二季度——我建议你不要优化,首先让一些方法起作用。 “过早的优化是万恶之源”。

标签: algorithm matlab matrix combinatorics


【解决方案1】:

这个问题是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 检测与其他集合的交集。

【讨论】:

  • 逻辑稀疏矩阵可能是实现它的替代方案。
  • @Daniel 如果按照我期望的方式实现,那么交叉的运行时间将从二次下降到线性,但不会利用单词并行性。无论如何,我希望这里的关键改进是使用具有良好列顺序的算法 X。
  • 感谢您向我介绍 Knuth 的算法 X,它至少在理论上解决了我的问题。
【解决方案2】:

这是你想要的吗? 我假设 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    相关资源
    最近更新 更多