在 Matlab 中将矩阵分成 5 组

Partitioning a matrix in 5 sets in Matlab

我有一个矩阵

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

假设矩阵 sV 表示一个集合,其元素是上面列出的 1x2 行向量。

我们可以通过多种方式将集合 sV 划分为 5 个非空集合(here 中的 140 个)。

例如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;

为了找到分区的位置我们可以使用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