2

请帮助我改进以下 Matlab 代码以缩短执行时间。

实际上我想制作一个随机矩阵(大小[8,12,10]),并且在每一行上,只有 和 之间的整1数值12。我希望随机矩阵具有每列具有值 (1,2,3,4) 的元素的总和等于2

下面的代码会让事情变得更清楚,但速度很慢。谁能给我一个建议??

clc
clear all
jum_kel=8
jum_bag=12
uk_pop=10

for ii=1:uk_pop;    
    for a=1:jum_kel
        krom(a,:,ii)=randperm(jum_bag); %batasan tidak boleh satu kelompok melakukan lebih dari satu aktivitas dalam satu waktu
    end
end

for ii=1:uk_pop;  
gab1(:,:,ii) = sum(krom(:,:,ii)==1)
gab2(:,:,ii) = sum(krom(:,:,ii)==2)
gab3(:,:,ii) = sum(krom(:,:,ii)==3)
gab4(:,:,ii) = sum(krom(:,:,ii)==4)
end

for jj=1:uk_pop;
     gabh1(:,:,jj)=numel(find(gab1(:,:,jj)~=2& gab1(:,:,jj)~=0))
     gabh2(:,:,jj)=numel(find(gab2(:,:,jj)~=2& gab2(:,:,jj)~=0))
     gabh3(:,:,jj)=numel(find(gab3(:,:,jj)~=2& gab3(:,:,jj)~=0))
     gabh4(:,:,jj)=numel(find(gab4(:,:,jj)~=2& gab4(:,:,jj)~=0))
end

for ii=1:uk_pop;
    tot(:,:,ii)=gabh1(:,:,ii)+gabh2(:,:,ii)+gabh3(:,:,ii)+gabh4(:,:,ii)
end

for ii=1:uk_pop;
    while tot(:,:,ii)~=0;
          for a=1:jum_kel
              krom(a,:,ii)=randperm(jum_bag); %batasan tidak boleh satu kelompok melakukan lebih dari satu aktivitas dalam satu waktu
          end
          gabb1 = sum(krom(:,:,ii)==1)
          gabb2 = sum(krom(:,:,ii)==2)
          gabb3 = sum(krom(:,:,ii)==3)
          gabb4 = sum(krom(:,:,ii)==4)

          gabbh1=numel(find(gabb1~=2& gabb1~=0));
          gabbh2=numel(find(gabb2~=2& gabb2~=0));
          gabbh3=numel(find(gabb3~=2& gabb3~=0));
          gabbh4=numel(find(gabb4~=2& gabb4~=0));

          tot(:,:,ii)=gabbh1+gabbh2+gabbh3+gabbh4;
    end
end
4

2 回答 2

5

一些一般性建议:

  • 用英文命名变量。如果不是很清楚,请给出简短的解释,它们是为了什么而缩进的。jum_bag例如什么?对我来说uk_pop是音乐风格。
  • 用英文写评论,即使你只是为自己开发源代码。如果您不得不与外国人分享您的代码,您将花费大量时间解释或重新翻译。例如,我想知道是什么 %batasan tidak boleh意思。可能,您在这里描述这只是一个快速破解,但在投入生产之前,应该有人真的再次检查一下。

特定于您的代码:

  • 它很容易gab1gabh1or混淆gabb1
  • 对我来说,krom太类似于内置函数了kron。事实上,我首先认为您正在计算大量张量积。
  • gab1 .. gab4可能最好组合成一个数组或一个单元格,例如你可以使用

    gab = cell(1, 4);
    for ii = ...
        gab{1}(:,:,ii) = sum(krom(:,:,ii)==1);
        gab{2}(:,:,ii) = sum(krom(:,:,ii)==2);
        gab{3}(:,:,ii) = sum(krom(:,:,ii)==3);
        gab{4}(:,:,ii) = sum(krom(:,:,ii)==4);
    end
    

    优点是您可以用另一个循环重新编写比较。它在计算gabh1gabb1tot以后也有帮助。

    如果您进一步引入一个变量,例如highestNumberToCompare,您只需进行一次更改,当您肯定发现检查元素是否也等于 5 和 6 很重要时。

  • 在每个命令的末尾添加一个分号。输出过多很烦人,而且速度也很慢。

  • 更好地numel(find(gabb1 ~= 2 & gabb1 ~= 0))表示为 sum(gabb1(:) ~= 2 & gabb1(:) ~= 0)。Afind不是必需的,因为您不关心索引,而只关心索引的数量,它等于true's 的数量。

  • 当然还有:这段代码

    for ii=1:uk_pop
        gab1(:,:,ii) = sum(krom(:,:,ii)==1)
    end
    

    真的,真的很慢。在每次迭代中,您都会增加gab1 数组的大小,这意味着您必须 i) 分配更多内存,ii) 复制旧矩阵和 iii) 写入新行。如果 在循环前面设置数组的大小,这会快得多:gab1

    gab1 = zeros(... final size ...);
    for ii=1:uk_pop
        gab1(:,:,ii) = sum(krom(:,:,ii)==1)
    end
    

    或许,您还应该重新考虑gab1. 我不认为,您在这里需要一个 3D 数组,因为sum()已经减少了一维(如果krom是 3D,则输出sum()最多为 2D)。

    可能,您可以完全跳过循环并使用简单的sum(krom==1, 3)代替。但是,在每种情况下,您都应该真正了解结果的大小和形状。

编辑灵感来自罗迪奥尔登惠斯

正如罗迪指出的那样,您的代码的“问题”在于,您创建一个通过随机分配数字来满足您的约束的矩阵极不可能(尽管并非不可能)。下面的代码创建了一个temp具有以下特征的矩阵:

  • 这些数字1 .. maxNumber要么每列出现两次,要么根本不出现。
  • 所有行都是数字的随机排列1 .. B,其中B等于行的长度(即列数)。

最后,该temp矩阵用于填充一个名为 的 3D 数组result。我希望,您可以根据自己的需要进行调整。

clear all;
A = 8; B = 12; C = 10;
% The numbers [1 .. maxNumber] have to appear exactly twice in a
% column or not at all.
maxNumber = 4;
result = zeros(A, B, C);
for ii = 1 : C
    temp = zeros(A, B);
    for number = 1 : maxNumber
        forbiddenRows = zeros(1, A);
        forbiddenColumns = zeros(1, A/2);
        for count = 1 : A/2
            illegalIndices = true;
            while illegalIndices
                illegalIndices = false;
                % Draw a column which has not been used for this number.
                randomColumn = randi(B);
                while any(ismember(forbiddenColumns, randomColumn))
                    randomColumn = randi(B);
                end
                % Draw two rows which have not been used for this number.
                randomRows = randi(A, 1, 2);
                while randomRows(1) == randomRows(2)  ...
                      || any(ismember(forbiddenRows, randomRows))
                  randomRows = randi(A, 1, 2);
                end
                % Make sure not to overwrite previous non-zeros.
                if any(temp(randomRows, randomColumn))
                    illegalIndices = true;
                    continue;
                end
            end
            % Mark the rows and column as forbidden for this number.
            forbiddenColumns(count) = randomColumn;
            forbiddenRows((count - 1) * 2 + (1:2)) = randomRows;
            temp(randomRows, randomColumn) = number;
        end
    end

    % Now every row contains the numbers [1 .. maxNumber] by 
    % construction. Fill the zeros with a permutation of the
    % interval [maxNumber + 1 .. B].
    for count = 1 : A
        mask = temp(count, :) == 0;
        temp(count, mask) = maxNumber + randperm(B - maxNumber);
    end

    % Store this page.
    result(:,:,ii) = temp;
end
于 2012-08-28T09:44:57.613 回答
2

好的,下面的代码将显着改善时序。它还不完美,都可以进一步优化。

但是,在我这样做之前:我认为你想要的基本上是不可能的。

所以你要

  • 所有行都包含数字 1 到 12,随机排列
  • 1 到 4 之间的任何值必须在任何列中出现两次或根本不出现

我有一种预感,这是不可能的(这就是你的代码永远不会完成的原因),但让我再考虑一下。

无论如何,我的 5 分钟显而易见的改进版本:

clc
clear all

jum_kel  =  8;
jum_bag  =  12;
uk_pop   =  10;

A = jum_kel; % renamed to make language independent 
B = jum_bag; % and a lot shorter for readability
C = uk_pop;

krom = zeros(A, B, C);
for ii = 1:C;
    for a = 1:A
        krom(a,:,ii) = randperm(B);
    end
end

gab1  = sum(krom == 1);
gab2  = sum(krom == 2);
gab3  = sum(krom == 3);
gab4  = sum(krom == 4);

gabh1 = sum( gab1 ~= 2 & gab1 ~= 0 );
gabh2 = sum( gab2 ~= 2 & gab2 ~= 0 );
gabh3 = sum( gab3 ~= 2 & gab3 ~= 0 );
gabh4 = sum( gab4 ~= 2 & gab4 ~= 0 );

tot   = gabh1+gabh2+gabh3+gabh4;


for ii = 1:C
    ii
    while tot(:,:,ii) ~= 0

        for a = 1:A
            krom(a,:,ii) = randperm(B);
        end

        gabb1  =  sum(krom(:,:,ii) == 1);
        gabb2  =  sum(krom(:,:,ii) == 2);
        gabb3  =  sum(krom(:,:,ii) == 3);
        gabb4  =  sum(krom(:,:,ii) == 4);

        gabbh1 = sum(gabb1 ~= 2 & gabb1 ~= 0)
        gabbh2 = sum(gabb2 ~= 2 & gabb2 ~= 0);
        gabbh3 = sum(gabb3 ~= 2 & gabb3 ~= 0);
        gabbh4 = sum(gabb4 ~= 2 & gabb4 ~= 0);

        tot(:,:,ii) = gabbh1+gabbh2+gabbh3+gabbh4;

    end
end
于 2012-08-28T10:09:22.660 回答