変更を最小限に抑える単純な「デフラグ」ロジック?


8

編集:

はっきりと私はこれをうまく説明しなかったので、例を使ってもう一度試してみましょう。私は与えられたサイズの「パイプ」を持ち、与えられたオフセットで信号がルーティングされます。パイプは、異なるオフセットの信号でフラグメント化される可能性があり、新しい信号を適合させることが不可能になります。パイプをデフラグするための信号の配置方法を教えてくれるアルゴリズムが必要です。しかし、実際には最小限の数の信号が移動しています!だから例のために..

サイズ16のパイプがあるとします。これには、サイズとオフセットが記述された次の信号があります。

offset 0: A (size of 4; fills slots 0-3)
offset 5: C (size of 2, fills slot 5-6)
offset 8: B (size of 4, fills 8-11)
offset 14: D (size 2, fills 14-15)

Pipe: AAAA_CC_BBBB__DD

この場合、オフセット4および7で1つのスロットを開き、オフセット12-13で2つのスロットを開いています。次に、このパイプにサイズ4の信号を追加するとします。現在、そのための連続したスペースはありませんが、デフラグすると、十分なスペースがあることがわかります。「明白な」ソリューションは、次のようにすべての信号を「上部」でグループ化することです。

offset 0:  A (size 4, fills 0-3)
offset 4:  B (size 4, fills 4-7)
offset 8:  C (size 2, fills 8-9)
offset 10: D (size 2, fills 10-11)

Pipe: AAAABBBBCCDD____

これにより、新しい信号用にスロット12〜15が解放されます。ただし、これを行うために3つの信号(BD)を再配置しました。移動した信号ごとに、コマンドをハードウェアに送信し、重要な時間待機する必要があります。

もっと賢くなれば、別のアプローチがあることに気づくことができました。私はこのように再配置できます:

offset 0:  A(size 4, fills 0-3)
offset 8:  B(size 4, fills 8-11)
offset 12: C(size 2, fills 12-13)
offset 14: D(size 2, fills 14-15).

Pipe: AAAA____BBBBCCDD

これで、新しい信号をオフセット4〜7に合わせることができます。そして、私は1つの信号を再配置する必要がありました(B)。したがって、ハードウェアコールを節約できます。

このような状況を検出するための適切なアルゴリズムがあるかどうか疑問に思っています。最小数の信号を移動して、信号をパイプに「フィット」できます。頭に浮かぶ近づきはNです!アルゴリズム; これは基本的には、「可能なすべての分布を生成し、それが何回移動したかを計算する」ことを表しています。私はより速いアプローチを求めています。

最悪のケースがあまり恐ろしくならない限り、このアプローチは100%完全である必要はありませ。私は主に平均的なケースを最小限に抑えることを目指しています。特定のパイプで255を超える信号が発生することはありません。Nで「逃げる」ことができるかもしれません!それが聞こえるほど悪い。また、各信号のサイズはパイプのサイズと同様に2の累乗であることも知っています。

また、断片化を最小限に抑える信号を配置するためのブリリアントアルゴリズムはありますか?


質問への回答。下記参照。

解答を少し詳しく調べて、読んでいる人にとって最適化がどのように行われるかをよりよく説明したいと思いました。buddyは、元の質問だったので、デフラグの部分をより詳細に概念化して説明するためのより簡単な方法を指摘したかったと説明しています。

私のアプローチについて説明します。これは、わずかに異なる/単純なアプローチですが、「バディ」の概念を効果的に維持しています。私はブロックを事前に計算したり、ラベルを付けたりしていません。これは、実装して維持するにはあまりにも多くの労力です。私にとって、信号がどこに行くかを計算するCPUコストは、実際の信号の配置/削除と比較して非常に簡単です。そのため、ロジックを単純化するための事前計算を行わないことで、小さな線形の量のCPUを失う余裕があります。したがって、プロセスは次のとおりです。

挿入用:

すべての信号は、信号サイズと等しい信号境界に保持されるため、信号は、offest%signalsize = 0のオフセットで開始します。実際のオフセットについては、この境界を維持する間隔を調べて把握します。したがって、信号が16サイズのパイプでサイズ4の場合、間隔0〜4、5〜7、8〜11、12〜15を調べます。

各間隔について、その間隔のすべてのスペースが空いているかどうかを確認します。単純なケースでは、信号のない間隔があり、その間隔で信号を配置します。重要なのは、間隔を順番に見て最初の空き間隔に信号を配置することです。これにより、信号を追加するときに(バディ用語を使用して)可能な最小の「ブロック」を確実に破ります。これは、im3l96によって記述されたバディのアプローチと同等でなければなりません。ブロックの事前計算がない場合を除きます。

間隔が完全に空いていない場合は、デフラグする必要があります。このため、最も未使用のスロットを持つ信号を見つけます。複数の間隔に同じ数の未使用のスロットがある場合は、最初の間隔を選択します。次に、この間隔で最大の信号を見つけ、小さい信号に対して同じ挿入アルゴリズムを再帰的に呼び出します(ただし、最初の信号を挿入するために選択した間隔を何らかの理由で使用不可としてマークする場合を除きます)。これにより、信号が適合する別の場所に信号が移動します。次に、選択した間隔で次に小さい信号を見つけ、すべての信号を移動するまで同じことを行います。2 ^ n-1信号の最悪のケースが移動しました。ここで、Nは潜在的な信号サイズ<=私たちの信号の数です(信号が2の倍数であると仮定すると、N = log2(signalSize))。

ここに例があります。*このメソッドを再帰的に呼び出したときに使用不可としてマークされたスロットを表します(つまり、呼び出し側メソッドがシグナルを配置したかったため、再帰呼び出しがシグナルを配置しようとはしません)

これは、私が思いつくことができる、非常に単純な例であり、それでも完全な複雑さを示しています。注:次の構造は作成が困難ですが、誰かが非常に一生懸命に努力した場合のバディのアプローチから生じる可能性があります。

FFFFFFFF__AA_B__EEEE_HGGCC_DII_J

誰かがサイズ8の信号Zを渡します

オフセット8を選択します。

defragInsert(z、サイズ8)

effective structure: FFFFFFFF__AA_B__EEEE_HGGCC_DII_J

placing signal in interval: __AA_B__

defragInput(A、サイズ2)

effective structure: FFFFFFFF********EEEE_HGGCC_DII_J
place signal in interval (offset 20)  _H

defragInput(H、size1)

effective structure: FFFFFFFF********EEEE**GGCC_DII_J
place signal between C & D

defragInput(H、size1)を返します

effective structure: FFFFFFFF********EEEE__GGCCHDII_J
place H at offset 20 now that it's open

defragInput(A、サイズ2)を返す

有効な構造:FFFFFFFF_ _ _B__EEEEAAGGCCHDII_J今すぐBを移動...

defragInput(B、size1)

有効な構造:FFFFFFFF * ** * EEEEAAGGCCHDII_J IとJの間にBを配置

defragInput(B、size1)を返します

有効な構造:FFFFFFFF_ __ _EEEEAAGGCCHDIIBJ追加B

defragInsert(z、サイズ8)を返します

fianl structure: FFFFFFFFzzzzzzzzEEEEAAGGCCHDIIBJ

このプロセスが何をしているのかを理解することは困難です。入力の例(255ではなく8または16信号のパイプを使用している可能性があります)と悪い出力と良い出力の例を教えてください。
Neil

2
私は2番目のニールです。具体的に何を求めているのか理解するのは本当に難しいです。しかし、動的なメモリ割り当てのようなものを実行しようとしているように思えます。組み込みの世界では、断片化を回避するために、動的メモリがさまざまなサイズのプールに事前に割り当てられます。すなわち。256バイト単位の10,000ブロック。1Kユニットの1,000ブロック、1Mユニットの200ブロックなど。新しいものは上書きされます。次に、動的メモリが要求されると、利用可能な最小サイズのブロックを持つプールから取得されます。これは管理が簡単で高速であり、断片化を回避できます。あなたのために働くかもしれません。
ダンク

パイプの視覚的なイラストを追加するために編集されました。役に立ったと思われる場合は、編集を承認してください。
ボブソン

シグナルの追加/削除はいつ/何が決定しますか?
Paddy3118 2013年

1
@Dunkの2番目です。問題はメモリ割り当てと似ています。あなたの例の問題の一部は、それがひどく断片化するような方法でスロットを割り当てていることです(プール/チャンクを使用していない)。私が知っている簡単な解決策の1つは、en.wikipedia.org/wiki/Buddy_memory_allocationを使用することです。AAAA_CC_BBBB__DDの代わりにバディを使用すると、AAAACCDDBBBB ____(4つの空のスロットが残ります)を取得します。再配置は不要で、そのように割り当てられます。
imel96 2013年

回答:


4

問題はメモリ割り当てに似ているので、私の提案する解決策はhttp://en.wikipedia.org/wiki/Buddy_memory_allocationを使用することです。バディアロケーターを使用すると、信号用のパイプ内の最小の隣接する空きスペースを選択することにより、最初からフラグメンテーションが発生するのを最小限に抑えることができます。

例を使用して、サイズ8のパイプにスペースを割り当てる方法を次に示します。

Initial state
Pipe: ----------------

A (size 4), smallest available is 16, so split that into 2x4 and 1x8
Pipe: AAAA ---- --------

C (size of 2), smallest available is 4, split that into 2x2 
Pipe: AAAA CC -- --------

B (size of 4), smallest available is 8, split that into 2x4
Pipe: AAAA CC -- BBBB ----

D (size 2), smallest available is 2
Pipe: AAAA CC DD BBBB ----

スペースの解放は、解放されるスペースの「バディ」を確認することです。バディも無料の場合、それらをマージして、より大きな隣接スペースを形成できます。したがって、スペースが入ってくる信号の順に解放されている場合、それは次のようになります。

Free A (buddy of space being freed is not free)
Pipe: ---- CC DD BBBB ----

Free C (buddy is not free)
Pipe: ---- -- DD BBBB ----

Free B (buddy is free, merge)
Pipe: ---- -- DD --------

Free D (buddy is free, merge)
Pipe: ----------------

特に信号のサイズが2の累乗であるため、断片化がほとんどないため、それも非常にシンプルで高速です。

それが本当に必要な場合は、デフラグ/圧縮も簡単に行うことができます。これは、空きバディと同じサイズの割り当てられたブロックを見つけてマージすることです(割り当てられたブロックを1つ移動すると、大きな空きブロックが作成されます)。


2

さて、答えを探す前に、まず最小化したいもの、つまりどのような信号の再配置を許可するかを明確に定義する必要があります。

  • パイプから1つ(そして1つだけ)の信号を取り出し、これを別の場所にオーバーラップなしで追加します(そのステップをn回繰り返します)。

  • または、パイプからn個の信号を同時に取得して、それらを後で再挿入します(n回の移動としてカウントされます)。

明らかに、この最初の選択肢ははるかに制限されており、検索スペースがはるかに小さくなります。例えば、から行くことAAAA_CC_BBBB__DDAAAA_CC___DDBBBBそれらが許可されている場合は、1にはsimultanous repositioningsが許可されていない場合は、少なくとも4移動し、2移動が必要になります。

私はあなたが最初の問題を念頭に置いていると仮定します(それを確認してください)、これが私の提案です:

  • これをグラフ検索の問題にします。特定のパイプの場合、各信号構成はグラフの頂点を定義し、それらの頂点間のエッジが再配置の可能性があります。

  • 各頂点に値を与える:最長の連続スロットシーケンスの長さ

これで、幅優先検索A *検索などの標準的なグラフ検索手法を使用して、追加する新しい信号に十分なスペースがあるパイプ構成に到達するまで、最小ステップ数を見つけるのは簡単です。


特定のパイプに必要なだけ信号を移動し、必要なだけ信号を追加できます。最終結果がオーバーラップしない限り、各移動はオーバーラップする必要はありません
dsollen

@dsollen:これは私の質問に対する回答ではありません-nが制限されているかどうかは尋ねませんでした。あなたの動きは、各ステップの後に重複することなく、次々に実行する必要があるかどうか、または2つの信号を同時に移動できるかどうかを尋ねていました。例えば、2つの信号の位置を、第一ケースニーズ少なくとも3が移動すると、2つだけ2を必要としながら切り替える
ドクブラウン

@dsollen:私の編集を参照してください
Doc Brown

0

実際のデータの代表的なサンプルを取り、さまざまな再パッキングアルゴリズムをシミュレートする必要があります。現時点では、システムをシミュレーションするための十分な情報がないため、アルゴリズムがどのように機能するかを確認できませんでした。


はい、同意しますが、リリースされて手に入るまでの使用方法に関するデータはありません。ただし、アルゴリズムを特定のユースケースに完全に最適化する必要はありません。信号のランダムな順序の可能性がある場合に非常にうまく機能する一般的なアルゴリズムで問題ありません。そのような概念は恐らくN ^ 2の最悪のケースに対処し、Nが非常に小さい場合にそれは実際に実行可能です...それでも、私はN ^ 2の最悪のケースを得ることができますが、まともな平均ケースの方がましです。
dsollen 2013年

こんにちは、@ dsollen。その場合、私はすぐにそれをドアから取り出し、フィードバックを得るとすぐに最適化が可能であることを顧客に伝えます。並べ替えの場合は、Timsortを推奨するのに十分な情報がないため、バブルソートまたはマージソートを行うのと同じです。
Paddy3118 2013年

フィードバックをお寄せいただきありがとうございます。それは本質的に私がやったことであり、何か良いものを思いつくのに長い時間がかかったので、このリリースに愚かなアプローチを実装するのに最も迅速に行いました。ただし、より良いリリースを行うときは、imel96によって提案されたバディアロケーションアプローチの怠惰なろくでなしバージョンを使用すると確信しています。多くのサイトでは平均的なユースケースが異なるため、使用状況を収集することは困難です。そして結局、それを実行する必要性を最小限に抑えるO(n)アプローチは非常に高速であり、それ以上の最適化はユーザーにはまったく認識されません:)
dsollen

@dsollen:がんばって:-)
Paddy3118 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.