在更大的矩阵中删除相同的子矩阵。 MATLAB

时间:2016-09-21 18:34:59

标签: matlab matrix

我想在更大的矩阵中分析2x2块,如果其中两个块相同,则删除它们。我试图为自己编写的代码看起来有点像这样(C是一个包含2个列的大矩阵):

n=size(C,1);

for k=1:2:(n-3)
    for l=(k+2):2:(n-1)

        if C(k:k+1,1:2)==C(l:l+1,1:2);

        C([l,l+1],:)=[];

        else
        end
    end
end

我遇到的问题是,matlab没有"注意"当它删除行中的C时,C的大小正在缩小。这意味着最终代码会遇到问题,因为它要求维度中的相等检查太高。我怎么能避免呢?有没有更好的方法呢?

我试图绕着"独特的"命令也是。但这只适用于行。我需要2x2段(从奇数行开始)。

此处填写(原始)代码:

A=[1,0;0,1i];
B=1/sqrt(2)*[1,1;1,-1];

C=[0,0;0,0];

C(1:2,1:2)=A(1:2,1:2);
C(3:4,1:2)=B(1:2,1:2);


for m=1:20

d=size(C,1)

C_A=C*A;
C_B=C*B;

s_a=size(C_A);
s_a=s_a(1,1);
s_b=size(C_B);
s_b=s_b(1,1);

C((d+1):(d+s_a),1:2)=C_A(1:s_a,1:2);
C((d+s_a+1):(d+s_a+s_b),1:2)=C_B(1:s_b,1:2);

n=size(C,1);

for k=1:2:(n-3)
    for l=(k+2):2:(n-1)

        if C(k:k+1,1:2)==C(l:l+1,1:2);

        C([l,l+1],:)=[];

        else
        end
    end
end

new_n=size(C,1)

if d==new_n
    error('Done')
else
end 
end

2 个答案:

答案 0 :(得分:1)

要使代码按原样运行,请首先反转l循环的方向:

    for l = (size(C,1)-1):-2:(k+2)

这样你就可以从最后删除并在每次增加k时重新计算最大索引。但是你仍然会遇到k循环的麻烦,所以只需将其更改为while循环即可。此外,使用==比较2x2矩阵将为您提供4个值,可能不是您想要的值。如果两个矩阵具有完全相同的值,则使用isequal将为您提供单个布尔值。

k = 1;
while (k < size(C,1))
    for l = (size(C,1)-1):-2:(k+2)
        if isequal(C(k:k+1,1:2), C(l:l+1,1:2))
            C([l,l+1],:) = [];
        end
    end
    k = k + 2;
end

或者,您可以通过将每个2x2子矩阵重新排列为一行来使用unique

D = reshape(C.', 4, []).';
U = unique(D, 'rows');
C = reshape(U.', 2, []).';

如果您正在处理浮点值,那么比较它们的平等性绝不是一个好主意;浮点值的精度有限总会给您带来麻烦。为了解决这个问题,您可以创建一个函数来比较容差内的相等性。

isequalTol=@(a,b,tol) all(abs(a-b) < tol);

此功能适用于标量,向量或矩阵。现在,您可以定义容差并将isequal替换为isequalTol

tol = eps(1);
k = 1;
while (k < size(C,1))
    for l = (size(C,1)-1):-2:(k+2)
        if isequalTol(C(k:k+1,1:2), C(l:l+1,1:2), tol)   % equal within tolerance
            C([l,l+1],:) = [];
        end
    end
    k = k + 2;
end

答案 1 :(得分:0)

与烧杯略有不同的方法,使用遮蔽来防止while循环。如果您希望稍后对重复值执行任何操作,则此方法更为可取。

CMask = ones(size(C)); %Create mask; anything with a 1 will be part of final answer, zeros will be left out
for ii = 1:2:size(C,1)
    for jj = ii+2:2:size(C,1)
        CMask(jj:jj+1,:) = CMask(jj,1) && ~isequal(C(ii:ii+1,:),C(jj:jj+1,:))) %If the two sections are equal, make CMask zeros in the lower section. && is required so that we don't overwrite 0s with 1s
    end
end
COut = reshape(C(CMask),[],2);