请帮助我改进以下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
一些一般建议:
- 用英文命名变量。如果不是很清楚,请给出简短的解释,它们缩进表示什么。例如,什么是
jum_bag
?对我来说uk_pop
是一种音乐风格 - 用英语写评论,即使您只为自己开发源代码。如果你必须与外国人分享你的代码,你会花很多时间解释或重新翻译。例如,我想知道CCD_ 7表示。也许,你在这里描述这只是一个快速黑客,但有人真的应该再次检查,然后再投入生产
特定于您的代码:
- 很容易将
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
优点是可以用另一个循环重写比较。这也有助于以后计算
gabh1
、gabb1
和tot
如果您进一步引入像
highestNumberToCompare
这样的变量,您只需要当你确实发现检查很重要时,如果元素也等于5和6。 -
在每个命令的末尾添加一个分号。输出过多很烦人也很慢。
-
numel(find(gabb1 ~= 2 & gabb1 ~= 0))
最好表示为sum(gabb1(:) ~= 2 & gabb1(:) ~= 0)
。不需要find
,因为你不在乎关于索引,但仅关于索引的数量,该数量等于该数量CCD_ 21的。 -
当然:这个代码
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
是CCD_ 27的输出至多为2D)。也许,您可以跳过这个循环,转而使用一个简单的
sum(krom==1, 3)
。然而,在任何情况下,你都应该真正意识到你的后果
受Rody Oldenhuis启发编辑:
正如Rody所指出的,您的代码的"问题"在于它极不可能(尽管并非不可能)创建一个矩阵,该矩阵通过分配这些数字是随机的。下面的代码创建了一个具有以下特性的矩阵temp
:
- 数字
1 .. maxNumber
要么每列出现两次,要么根本不出现 - 所有行都是数字
1 .. B
的随机排列,其中B
等于行的长度(即列的数量)
最后,使用temp
矩阵来填充称为result
的3D阵列。我希望你能根据自己的需要进行调整。
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
好的,下面的代码将显著改善计时。它还不完美,可以进一步优化。
但是,在我这么做之前:我认为你想要的根本不可能。
所以你想要
- 所有行都包含数字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