矢量化搜索包含给定subpermutations(重复)的排列(重复)

时间:2014-09-10 08:13:56

标签: algorithm matlab sequence permutation vectorization

这个问题可以从here看待我的上一个问题的继续/延伸/概括。

一些定义:我有一组整数S = {1,2,...,s},比如s = 20,以及两个矩阵NM,其行是有限的来自S的数字序列(即可能重复的排列),分别为nm1 <= n <= m。让我们将N视为来自M的序列的候选子序列的集合。

示例:[2 3 4 3][1 2 2 3 5 4 1 3]的子序列,以多样性 2出现(=以多少种不同的方式找到子序列。 main seq。),而[3 2 2 3]不是它的子序列。特别是,根据定义,有效的子序列必须保留索引的顺序。

问题陈述:

(P1)对于M的每一行,获取N中作为行出现的多重性且无多重性的子序列数(如果N)中没有包含它,则它可以为零;

(P2)对于N的每一行,找出具有多重性且没有多重性的次数,它包含在M中作为子序列(再次,这个数字可以是零);

示例:允许N = [1 2 2; 2 3 4]M = [1 1 2 2 3; 1 2 2 3 4; 1 2 3 5 6]。然后(P1)为&#39;返回[2; 3; 0]多重性&#39;和[1; 2; 0]没有多重性&#39;。 (P2)为&#39;返回[3; 2]多重性&#39;和[2; 1]没有多重性。

数量级: M通常最多可包含30-40列和几千行,但我目前只有M只有几百行~10列。 N可能接近其大小 M或者也可能更小。

到目前为止我所拥有的:说实话,并不多。我相信我可以从我之前的问题稍微修改我的非常好的矢量化解决方案来解决重复的排列问题,但我仍然在考虑这个并且一旦我有工作就会更新。但鉴于我迄今为止(缺乏)经验,很可能非常不理想:(

谢谢!

2 个答案:

答案 0 :(得分:1)

此方法仅在M(P1)或N(P2)的行上使用一个循环。该代码使用linear indexing和非常强大的bsxfun函数。请注意,如果列数很大,您可能会因nchoosek而遇到问题。

[mr mc] = size(M);
[nr nc] = size(N);

%// P1
combs = nchoosek(1:mc, nc)-1;
P1mu = NaN(mr,1);
P1nm = NaN(mr,1);
for r = 1:mr
    aux = M(r+mr*combs);
    P1mu(r) = sum(ismember(aux, N, 'rows'));
    P1nm(r) = sum(ismember(unique(aux, 'rows'), N, 'rows'));
end

%// P2. Multiplicity defined to span across different rows
rr = reshape(repmat(1:mr, size(combs,1), 1),[],1);
P2mu = NaN(nr,1);
P2nm = NaN(nr,1);
for r = 1:nr
    aux = M(bsxfun(@plus, rr, mr*repmat(combs, mr, 1)));
    P2mu(r) = sum(all(bsxfun(@eq, N(r,:), aux), 2));
    P2nm(r) = sum(all(bsxfun(@eq, N(r,:), unique(aux, 'rows')), 2));
end

%// P2. Multiplicity defined restricted to within one row
rr = reshape(repmat(1:mr, size(combs,1), 1),[],1);
P2mur = NaN(nr,1);
P2nmr = NaN(nr,1);
for r = 1:nr
    aux = M(bsxfun(@plus, rr, mr*repmat(combs, mr, 1)));
    P2mur(r) = sum(all(bsxfun(@eq, N(r,:), aux), 2));
    aux2 = unique([aux rr], 'rows'); %// concat rr to differentiate rows...
    aux2 = aux2(:,1:end-1); %// ...and now remove it
    P2nmr(r) = sum(all(bsxfun(@eq, N(r,:), aux2), 2));
end

示例数据的结果:

P1mu =
     2
     3
     0
P1nm =
     1
     2
     0
P2mu =
     3
     2
P2nm =
     1
     1
P2mur =
     3
     2
P2nmr =
     2
     1

可以对代码进行一些优化。不确定他们是否值得付出努力:

  • repmat替换为另一个bsxfun(使用第三维)。这可能会节省一些内存
  • 转置原始矩阵并减少colunmns,而不是沿着行。这可能会更快。

答案 1 :(得分:1)

简介:由于每行输入数据的重复,组合查找过程中没有"uniqueness"之类的元素,这些元素在之前的问题中被利用了因此这里使用了循环。另请注意,without multiplicity代码不使用nchoosek,因此我觉得对性能更加乐观。

符号:

p1wim -> P1 with multiplicity
p2wim -> P2 with multiplicity
p1wom -> P1 without multiplicity
p2wom -> P2 without multiplicity

代码:

予。 P1的代码,2具有多重性

permN = permute(N,[3 2 1]);

p1wim(size(M,1),1)=0;
p2wim(size(N,1),1)=0;

for k1 = 1:size(M,1)
    d1 = nchoosek(M(k1,:),3);
    t1 = all(bsxfun(@eq,d1,permN),2);
    p1wim(k1) = sum(t1(:));
    p2wim = p2wim + squeeze(sum(t1,1));
end

II。 P1的代码,2没有多重性

eqmat = bsxfun(@eq,M,permute(N,[3 4 2 1])); %// equality matrix

[m,n,p,q] = size(eqmat); %// get sizes
inds = zeros(size(M,1),p,q); %// pre-allocate for indices array

vec1 = [1:m]'; %//' setup constants to loop
vec2 = [0:q-1]*m*n*p;
vec3 = permute([0:p-1]*m*n,[1 3 2]);

for iter = 1:p
    [~,ind1] = max(eqmat(:,:,iter,:),[],2);
    inds(:,iter,:) = reshape(ind1,m,1,q);
    ind2 = squeeze(ind1);
    ind3 = bsxfun(@plus,vec1,(ind2-1)*m); %//' setup forward moving equalities
    ind4 = bsxfun(@plus,ind3,vec2);
    ind5 = bsxfun(@plus,ind4,vec3);
    eqmat(ind5(:)) = 0;
end

p1wom = sum(all(diff(inds,[],2)>0,2),3);
p2wom = squeeze(sum(all(diff(inds,[],2)>0,2),1));

像往常一样,我建议您使用gpuArrays和您最喜欢的parfor