1

我想创建一个名为 的数组result,它有维度(14,12,10)和值random[0 2],但每行(维度 2)中不应包含0超过三个连续时间,并且每行中所有值的总和必须为<= 11.

这是我目前的做法:

jum_kel = 14;
jum_bag = 12;
uk_pop = 10;

for ii = 1:uk_pop,
  libur(:,:,ii) = randint(jum_kel,jum_bag,[0 2]); %#initialis
  sum_libur(1,:,ii) = sum(libur(:,:,ii),2); %#sum each row
end

for jj = 1:jum_kel
  while sum_libur(1,jj,ii) > 11, %# first constraint : sum each row should be <=11,
    libur(jj,:,ii) = randint(1,jum_bag,[0 2])
    sum_libur(1,:,ii)=  sum(libur(:,:,ii),2);
    for kk = 1:jum_bag
      if kk>2
        o = libur(jj,kk,ii)+libur(jj,kk-1,ii)+libur(jj,kk-2)
        while kk>2 && o==0 %# constraint 2: to make matrix will not contain consecutive triplets (0-0-0) in any row.
          libur(jj,:,ii) = randint(1,jum_bag,[0 2]); 
          sum_libur(1,:,ii)=  sum(libur(:,:,ii),2);
        end
      end
    end
  end
end

但这非常慢......有人看到更快的方法吗?

4

3 回答 3

2

(旁注:矩阵没有 3 维:那将是一个张量,在这种情况下,“行”的概念没有明确定义。)

最简单的方法是使用拒绝采样。通常这可能会很慢,即使您没有提及它,我也会担心此代码可能会出现在程序的性能关键部分中。尽管如此,一切都很好,因为包含子字符串 0-0-0 的行中出现 14 次 3 面硬币翻转的机会相当小。即使这是一个问题,由于矩阵(假设)是均匀分布的,它的元素也必须是独立分布的,因此您可以分别对每一行进行采样拒绝并重新创建一行中包含 0-0-0 或总和的任何行<= 11

于 2012-08-17T05:58:14.847 回答
0

正如@ninjagecko 所指出的,拒绝和重新创建是最明显(如果不是唯一)的方式。有鉴于此,我认为这会做得很好:

R = 14;
C = 12;
T = 10;

result = zeros(C,R*T);

for ii = 1:(R*T)
    done = false;
    while ~done
        newRow = randi([0 2],C,1);
        done = ...
            (sum(newRow)<12) && ...
            (~any(diff([0;find(newRow);C+1])>3));
    end
    result(:,ii) = newRow;
end

result = permute(reshape(result,C,R,T), [2 1 3]);

请注意,<12equals<=11用于整数数学(和>3equals >=4),但需要少检查一次,因此速度更快。该变量newRow被创建为列向量,因为这些东西在内存中组织得更好并且可以更快地检查。分配 3D 数组的速度通常比 2D 矩阵慢,因此在所有操作完成之前,一切都保持 2D。计算强度最高的检查 ( ~any(diff(find(newRow))>3))最后完成,因此短路 ( &&) 可能使其评估变得不必要。两个循环都很小,满足所有条件,由 Matlab 的 JIT 编译为机器代码。

所以这非常接近优化,并且会非常快。除非有人为此提出完全不同的算法,否则我相信这非常接近 Matlab 中的理论最大速度。如果您需要更快,则必须切换到 C(这将允许优化约束检查)。

于 2012-08-17T07:16:56.413 回答
0

为了简单地在数组中查找一系列数字,您可以(ab)使用strfind。索引到多维数组时,您还可以将子索引和线性索引组合到其余维度(在 assignment 中使用result(:,ii) = newRow):

result = NaN(12,14,10);
for ii = 1:14*10
    while 1
        newRow = randi([0 2],12,1);
        if isempty(strfind(newRow',[0 0 0])) && sum(newRow)<=11
            result(:,ii) = newRow; 
            break;
        end
    end
end
result = permute(result, [2 1 3]);
于 2012-08-17T09:19:55.703 回答