在Matlab中对5组中的矩阵进行分区

时间:2016-08-16 15:45:46

标签: matlab partitioning

我有一个矩阵

sV:=[0 -1; 
     1  1; 
     1  0;  
     2  1; 
     2  0; 
     3  1; 
     3  0]

想象一下,矩阵sV表示一个元素,其元素是上面列出的1x2行向量。

我们可以通过多种方式在5个非空集(140 here)中对集合sV进行分区。

例如,5分区sV的方式是:

{(0,-1)}
{(1,1)} 
{(1,0)}
{(2,1)}
{(2,0), (3,2), (3,0)}

分区集的可能基数为1,1,1,1,31,1,1,2,2(不考虑订单)。

问题:

你能帮我构建一个1x2单元格V_all,以便

V_all{1,1}是一个mx5单元,列出了对集合sV进行5分区的所有可能方式,以便分区集分别具有基数1,1,1,1,3。具体来说,对于任何j = 1,...,m,V_all{1,1}{j,1}应该是1x2向量,V_all{1,1}{j,2}应该是1x2向量,V_all{1,1}{j,3}应该成为1x2向量,V_all{1,1}{j,4}应为1x2向量,V_all{1,1}{j,5}应为3x2向量。

V_all{1,2}是一个nx5单元,列出了对集合sV进行5分区的所有可能方式,以便分区集分别具有基数1,1,1,2,2。具体来说,对于任何j = 1,...,n,V_all{1,1}{j,1}应该是1x2向量,V_all{1,1}{j,2}应该是1x2向量,V_all{1,1}{j,3}应该成为1x2向量,V_all{1,1}{j,4}应为2x2向量,V_all{1,1}{j,5}应为2x2向量。

请注意m+n=140

这是我的尝试。可能存在错误,因为我获得了超过140个分区。

%3+1+1+1+1
k=3;
M=reshape(sV(nchoosek(1:size(sV,1),k),:),[],k,size(sV,2));
V_1=cell(size(M,1),2); 
for p=1:size(M,1)
    V_1{p,1}=squeeze(M(p,:,:)); 
    left=~ismember(sV, V_1{p,1}, 'rows');
    V_1{p,2}=sV(left,:); 
end
%Rearrange
for j=1:size(V_1,1)
    V_1new{j,1}=V_1{j,1};
    V_1new{j,2}=V_1{j,2}(1,:);
    V_1new{j,3}=V_1{j,2}(2,:);
    V_1new{j,4}=V_1{j,2}(3,:);
    V_1new{j,5}=V_1{j,2}(4,:);
end
V_all{1,1}=V_1new;

%2+2+1+1+1
k=4;
M=reshape(sV(nchoosek(1:size(sV,1),k),:),[],k,size(sV,2));
V_2=cell(size(M,1),2); 
for p=1:size(M,1)
    V_2{p,1}=squeeze(M(p,:,:)); 
    left=~ismember(sV, V_2{p,1}, 'rows');
    V_2{p,2}=sV(left,:); 
end

k=2;
count=0;
for j=1:size(V_2,1)
    M=reshape(V_2{j,1}(nchoosek(1:size(V_2{j,1},1),k),:),[],k,size(V_2{j,1},2));
    V_2_22=cell(size(M,1),2); 
    for p=1:size(M,1)
        V_2_22{p,1}=squeeze(M(p,:,:)); 
        left=~ismember(V_2{j,1}, V_2_22{p,1}, 'rows');
        V_2_22{p,2}=V_2{j,1}(left,:); 
    end
    for l=1:size(V_2_22,1)
        V_2new{count+l,1}=V_2_22{l,1};
        V_2new{count+l,2}=V_2_22{l,2};
        V_2new{count+l,3}=V_2{j,2}(1,:);
        V_2new{count+l,4}=V_2{j,2}(2,:);
        V_2new{count+l,5}=V_2{j,2}(3,:);
    end
    count=size(V_2new,1);
end

V_all{1,2}=V_2new;

1 个答案:

答案 0 :(得分:0)

为了找到分区的位置,我们可以使用powerset 例如,如果powerset的元素是[2 3],则该集合将以这种方式分配:

0 -1; 
1  1; 
-----   <-- 2
1  0;
-----   <-- 3
2  1; 
2  0; 
3  1; 
3  0]

然后我们可以在这种情况下获得每个分区(num_el)中的元素数量:[2,1,4] 这是基数,但因为基数中元素的顺序不是重要的,所以[2,1,4]与[1 4 2]相同,我们可以对它进行排序以获得[1 2 4]

然后我们需要一个关联容器(字典)来将基数映射到一组分区。

matlab中的关联容器可以通过struct实现,所以我们需要将基数表示形式的数字数组更改为字符串,这样就可以用作struct的键,然后得到:'_1_2_4'

V_all是作为结构数组实现的关联容器:

V_all('_ 1_2_4')= {{} ....}

sV=[0 -1; 
     1  1; 
     1  0;  
     2  1; 
     2  0; 
     3  1; 
     3  0]

n = size(sV,1)
p=powerset(1:(n-1));

cardinality =sprintf('_%i',n);
V_all.(cardinality)(end+1)={sV};
for i = 2:numel(p)
    num_el = [p{i} n] - [0 p{i}];
    cardinality = sprintf('_%i',sort(num_el));
    cum = [0 cumsum(num_el)];
    temp = {};
    for j = 2: numel(cum)
        temp(end + 1) = {sV(cum(j-1)+1:cum(j),:)};
    end
    V_all.(cardinality)(end+1)={temp};
end