1

result次元(14,12,10)と値を持つという配列を作成したいのですが、各行 (次元 2) に連続して 3 回以上random[0 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が、必要なチェックが 1 つ少なくなるため、高速になります。変数newRowは列ベクトルとして作成されます。これは、そのようなものがメモリ内でより適切に整理され、より高速にチェックできるためです。一般に、3D 配列は 2D 行列よりも割り当てが遅いため、すべての操作が終わるまですべてが 2D のままになります。最も計算量の多いチェック ( ~any(diff(find(newRow))>3)) は最後に行われるため、短絡 ( &&) によってその評価が不要になる可能性があります。どちらのループも小さく、Matlab の JIT によってマシン コードにコンパイルされるすべての条件を満たしています。

したがって、これは最適化にかなり近く、かなり高速になります。誰かがこれに対してまったく異なるアルゴリズムを考え出さない限り、これは Matlab の理論上の最大速度にかなり近いと思います。より高速にする必要がある場合は、C に切り替える必要があります (これにより、制約チェックの最適化が可能になります)。

于 2012-08-17T07:16:56.413 に答える
0

配列内の一連の数値を単純に見つけるには、strfindを (ab) 使用できます。多次元配列にインデックスを付ける場合、サブインデックスと線形インデックスを残りの次元に結合することもできます (割り当て で使用されます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 に答える