2

実行時間を改善するために、次の Matlab コードを改善するのを手伝ってください。

実際には、ランダムな行列 (サイズ ) を作成し、すべての行でと[8,12,10]の間の整数値のみを持ちたいと考えています。ランダム行列に、列ごとに値 (1,2,3,4) を持つ要素の合計が等しいようにしたい。1122

次のコードは物事をより明確にしますが、非常に遅いです。誰か私に提案をしてもらえますか??

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例えば、どういう意味か知りたいです 。おそらく、これは簡単なハックにすぎないが、本番環境に入る前に誰かがこれをもう一度確認する必要があることをここで説明します。

コードに固有:

  • gab1またはと混同するのは本当に簡単gabh1です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に等しいかどうかを確認することが重要であることが確実にわかったときに、1つの変更を加えるだけで済みます。

  • すべてのコマンドの最後にセミコロンを追加します。出力が多すぎると、煩わしく、また遅くなります。

  • は、numel(find(gabb1 ~= 2 & gabb1 ~= 0))としてより適切に表現され sum(gabb1(:) ~= 2 & gabb1(:) ~= 0)ます。findインデックスは気にせず、インデックスの数だけを気にするので、Aは必要ありません。これは、の数と同じtrueです。

  • そしてもちろん:このコード

    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
    

    おそらく、のサイズと形状も再考する必要がありますgab1sum()すでに1次元が縮小されているため、ここでは3D配列が必要だとは思いません( krom3Dの場合、の出力はsum()最大で2Dです)。

    おそらく、ループをまったくスキップして、sum(krom==1, 3)代わりに単純なものを使用することができます。ただし、いずれの場合も、結果のサイズと形状に注意する必要があります。

Rody Oldenhuisに触発された編集:

Rodyが指摘したように、コードの「問題」は、数値をランダムに割り当てることによって制約を満たす行列を作成する可能性が非常に低いことです(不可能ではありませんが)。temp以下のコードは、次の特性を持つマトリックスを作成します。

  • 数値1 .. maxNumberは、列ごとに2回表示されるか、まったく表示されません。
  • すべての行は、数値のランダム順列です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

OK、以下のコードはタイミングを大幅に改善します。まだ完璧ではありませんが、すべてをさらに最適化することができます。

しかし、そうする前に、あなたが望むことは根本的に不可能だと思います。

あなたが望んでいるのは

  • すべての行には、ランダム順列で1から12までの数字が含まれています
  • 1から4までの値は、どの列にも2回存在するか、まったく存在しない必要があります。

私にはこれが不可能であるという予感があります(それがあなたのコードが決して完成しない理由です)が、これについてもう少し考えさせてください。

とにかく、私の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 に答える