lógica simples de desfragmentação que minimiza as alterações?


8

editar:

tão claramente que não expliquei isso muito bem, então deixe-me tentar novamente com exemplos. Eu tenho um 'pipe' de um determinado tamanho com sinais roteados através dele em determinadas compensações. O tubo pode se fragmentar com sinais em diferentes compensações, impossibilitando o ajuste de um novo sinal. Eu quero um algoritmo que me diga como organizar os sinais para desfragmentar o tubo; mas com um número mínimo de sinais realmente sendo movidos! Então, por exemplo ..

Digamos que eu tenho um tubo de tamanho 16. Ele tem os seguintes sinais com os tamanhos e compensações descritos.

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

Nesse caso, tenho 1 slot aberto nas compensações 4 e 7 e dois na compensação 12-13. Agora, digamos que eu queira adicionar um sinal de tamanho 4 a este tubo. Não há espaço contínuo para ele agora, mas sei que tenho espaço suficiente para desfragmentar. A solução "óbvia" é agrupar todos os sinais no topo, assim:

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____

isso deixa os slots 12 a 15 gratuitos para o meu novo sinal. No entanto, para fazer isso, reposicionei 3 sinais (BD). Para cada sinal que mudei, tenho que enviar comandos para o hardware e aguardar uma quantidade não trivial de tempo.

Se eu fosse mais esperto, poderia perceber que há outra abordagem. Eu poderia reposicionar assim:

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

Agora posso ajustar meu novo sinal nas compensações 4-7; E eu só tive que reposicionar um sinal (B). Economizando assim em chamadas de hardware.

Eu estou querendo saber se existe um bom algoritmo para detectar situações como esta; onde posso 'encaixar' um sinal em um tubo com o número mínimo de sinais movidos. O mês de abril que vem à mente é um N! algoritmo; que basicamente significa "gerar todas as distribuições possíveis, calcular em quantos movimentos resultou". Estou procurando uma abordagem mais rápida.

A abordagem não precisa ser 100% perfeita. Estou procurando principalmente minimizar o caso médio, desde que o pior caso não seja muito horrendo. Eu sei que nunca terei mais que 255 sinais em um determinado tubo; para que eu possa 'fugir' com o N! Tão ruim quanto isso soa. Eu também sei que o tamanho de cada sinal é uma potência de 2, assim como o tamanho do tubo.

Além disso, existem algoritmos brilhantes para a colocação de sinais que minimizem a fragmentação?


Pergunta respondida; ver abaixo.

Eu queria explicar um pouco a resposta para melhor explicar como a desfragmentação ocorreria para qualquer um que estivesse lendo; O amigo explica que eu queria apontar uma abordagem mais simples para conceituar e explicar a parte da difração em mais detalhes, já que essa era a pergunta original.

Estou explicando minha abordagem, que é uma abordagem ligeiramente diferente / mais simples, mas mantém efetivamente o conceito de "amigo". Não estou pré-computando blocos ou rotulando-os, é um esforço demais para implementar e manter. Para mim, o custo da CPU de calcular para onde o sinal irá é bastante trivial em comparação com a real colocação / exclusão de sinais; para que eu possa perder uma quantidade minúscula e linear de CPU, sem pré-computação para simplificar minha lógica. Então o processo é:

para inserção:

Todos os sinais são mantidos em limites de sinal iguais ao tamanho do sinal; portanto, um sinal começará no deslocamento, onde% de sinalização fora do tamanho = 0. Para o deslocamento atual, percorremos e descobrimos intervalos que mantêm esse limite. Portanto, se meu sinal for do tamanho 4 em um tubo de 16, examinarei os intervalos 0-4, 5-7, 8-11, 12-15.

Para cada intervalo, verifique se todo o espaço nesse intervalo está livre. No caso simples, temos um intervalo sem sinais e apenas colocamos o sinal nesse intervalo. Importante, observamos os intervalos em ordem e colocamos nosso sinal no primeiro intervalo livre , para garantir que quebremos o menor 'bloco' possível (usando termos de amizade) quando adicionamos nosso sinal. Isso deve ser equivalente ao método descrito por im3l96; exceto sem pré-computação de blocos.

se nenhum intervalo for completamente livre, temos que desfragmentar. Para isso, encontramos o sinal com os slots mais não utilizados. Se intervalos múltiplos tiverem o mesmo número de slots não utilizados, selecione o primeiro intervalo. Em seguida, encontramos o maior sinal nesse intervalo e chamamos recursivamente o mesmo algoritmo de inserção para o sinal menor (exceto marque o intervalo que selecionamos para inserir nosso primeiro sinal como indisponível de alguma forma). Isso move o sinal para outro lugar em que ele se encaixa. Em seguida, encontramos o próximo sinal menor no intervalo selecionado e fazemos o mesmo até mover todos os sinais. O pior caso de 2 ^ n-1 sinais foi movido; onde N é o número de tamanhos de sinal em potencial <= nosso sinal (assumindo que os sinais sejam múltiplos de 2, em seguida, N = log2 (tamanho do sinal)).

Aqui está um exemplo. * significa um slot marcado como indisponível quando chamamos recursivamente esse método (ou seja, o intervalo em que o método de chamada queria colocar seu sinal e, portanto, não quer que a chamada recursiva tente colocar um sinal)

Aqui está um caso mais simples e simples que eu poderia sugerir que ainda demonstra total complexidade. Nota: a estrutura a seguir seria difícil de criar, mas poderia resultar da abordagem do amigo se alguém tentasse muito.

FFFFFFFF__AA_B__EEEE_HGGCC_DII_J

Alguém passa em um sinal Z de tamanho 8

nós selecionamos o deslocamento 8:

defragInsert (z, tamanho 8)

effective structure: FFFFFFFF__AA_B__EEEE_HGGCC_DII_J

placing signal in interval: __AA_B__

defragInput (A, tamanho 2)

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

defragInput (H, tamanho1)

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

retornar defragInput (H, tamanho1)

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

return defragInput (A, tamanho 2)

estrutura efetiva: FFFFFFFF_ _ _B__EEEEAAGGCCHDII_J move B now ...

defragInput (B, tamanho1)

estrutura efetiva: FFFFFFFF * ** * EEEEAAGGCCHDII_J coloque B entre I e J

retornar defragInput (B, tamanho1)

estrutura eficaz: FFFFFFFF_ __ _EEEEAAGGCCHDIIBJ add B

return defragInsert (z, tamanho 8)

fianl structure: FFFFFFFFzzzzzzzzEEEEAAGGCCHDIIBJ

É difícil entender o que esse processo está fazendo. Você poderia nos dar um exemplo de entrada (talvez com um tubo com digamos 8 ou 16 sinais em vez de 255) e um exemplo de saída ruim e boa saída?
Neil

2
No segundo Neil, é realmente difícil entender o que você está perguntando especificamente. Mas parece que você pode estar tentando fazer algo semelhante à alocação dinâmica de memória. No mundo incorporado, para ajudar a evitar a fragmentação, a memória dinâmica é pré-alocada em conjuntos de tamanhos variados. ie 10.000 blocos de unidades de 256 bytes. 1.000 blocos de 1K unidades, 200 blocos de 1M unidades, etc. novos são substituídos. Em seguida, quando a memória dinâmica é solicitada, ela é recuperada do pool com os blocos de menor tamanho disponíveis. Isso é fácil de gerenciar, rápido e evita a fragmentação. Pode funcionar para você.
Dunk

Editado para adicionar uma ilustração visual dos tubos. Aceite a edição se você achar que isso ajuda.
Bobson

Quando é / o que determina a adição / remoção de sinais?
Paddy3118

1
I 2nd @ Dunker, o problema é semelhante à alocação de memória. Parte do problema no seu exemplo é que ele está alocando slots de uma maneira que o tornou muito fragmentado (sem usar pools / chunk). Uma solução simples que eu sei é usar en.wikipedia.org/wiki/Buddy_memory_allocation . Usando camarada, em vez de AAAA_CC_BBBB__DD, você receberá AAAACCDDBBBB____ (restam 4 espaços vazios). Sem reposicionamento, é alocado dessa maneira.
Imel96 20/05

Respostas:


4

O problema é semelhante à alocação de memória, então minha solução proposta é usar http://en.wikipedia.org/wiki/Buddy_memory_allocation . O uso do alocador de amigos minimiza a fragmentação, escolhendo o menor espaço livre contíguo no canal para um sinal.

Usando o exemplo, veja como o espaço será alocado para o tamanho 8 pipe:

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 ----

Liberar espaço é uma questão de verificar o "amigo" do espaço que está sendo liberado; se o amigo também estiver livre, eles poderão ser mesclados para formar um espaço contíguo maior. Portanto, se o espaço estiver sendo liberado na ordem em que os sinais chegarem, ficará assim:

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: ----------------

Também é bastante simples e rápido, porque há apenas uma pequena fragmentação, principalmente porque o tamanho dos sinais é a potência de 2.

Se for realmente necessário, a desfragmentação / compactação também pode ser feita facilmente, é apenas uma questão de encontrar blocos alocados do mesmo tamanho com amigos livres e mesclá-los (mover um bloco alocado criará um bloco livre maior).


2

Bem, antes de procurar uma resposta, você deve primeiro definir claramente o que deseja minimizar, ou seja, que tipo de reposicionamento de sinal é permitido.

  • tirar um (e apenas um) sinal do tubo e adicioná-lo em outro local sem sobreposições (e repetir esse passo n vezes)?

  • ou pegar n sinais simultaneamente do seu tubo e reinseri-los depois sem sobreposições (contados como n movimentos)?

Obviamente, essa primeira alternativa é muito mais restrita, oferecendo um espaço de pesquisa muito menor. Por exemplo, para passar de AAAA_CC_BBBB__DDpara AAAA_CC___DDBBBB, serão necessários pelo menos 4 movimentos, se nenhum reposicionamento simultâneo for permitido, e 2 movimentos, se forem permitidos.

Suponho que você tenha o primeiro problema em mente (confirme isso), então aqui está minha sugestão para isso:

  • faça deste um problema de pesquisa gráfica. Para um canal de distribuição, cada configuração de sinal define os vértices do seu gráfico, e as arestas entre esses vértices são os possíveis reposicionamentos.

  • atribuir a cada vértice um valor: o comprimento da sequência de slots contínua mais longa

Agora deve ser fácil usar uma técnica de pesquisa de gráfico padrão, como a primeira pesquisa de largura ou a pesquisa A *, para encontrar o menor número de etapas até chegar a uma configuração de canal que tenha espaço suficiente para o novo sinal que você deseja adicionar.


Posso mover quantos sinais quiser e adicionar quantos sinais quiser em um determinado canal. Então, enquanto o resultado final não está sobrepondo cada movimento não tem que gaurentee nenhuma sobreposição
dsollen

@dsollen: esta não é uma resposta para minha pergunta - não perguntei se n é limitado. Eu estava perguntando se seus movimentos devem ser executados um após o outro, sem sobreposições após cada etapa, ou se você pode mover dois sinais simultaneamente. Por exemplo, para trocar de posições dos dois sinais, as primeiras necessidades de caso, pelo menos, 3 movimentos, enquanto a segunda é preciso apenas 2.
Doc Brown

@dsollen: veja minha edição
Doc Brown

0

Você precisa coletar uma amostra representativa dos seus dados reais e simular diferentes algoritmos de reembalagem. No momento, não tenho informações suficientes para simular o sistema, portanto não pude verificar como funcionava qualquer algoritmo.


Sim, eu concordo, mas também não tenho dados sobre como serão usados ​​até que sejam liberados e estejam fora do meu alcance. No entanto, o algoritmo não precisa ser perfeitamente otimizado para um caso de uso específico. Um algoritmo genérico que funciona muito bem para qualquer ordenação potencialmente aleatória de sinais seria bom. Esse conceito provavelmente terá o pior caso de N ^ 2, e isso é realmente factível quando N é tão pequeno ... Ainda assim, posso obter o pior caso de N ^ 2, mas o caso médio decente é ainda melhor.
dsollen

Oi @dsollen, nesse caso, eu colocaria isso o mais rápido possível e diria aos clientes que as otimizações são possíveis assim que você receber algum feedback. Se fosse uma classificação, é o equivalente a dar a classificação por bolhas ou a classificação por mesclagem, pois você não tem informações suficientes para recomendar o Timsort.
Paddy3118

Obrigado pelo feedback. Isso foi essencialmente o que eu fiz, demorou muito tempo para chegar a algo bom, então eu fiz o mais rápido para implementar uma abordagem estúpida para este lançamento. No entanto, tenho certeza de que usarei uma versão preguiçosa do filho bastardo da abordagem de alocação de amigos sugerida por imel96 quando eu fizer o melhor lançamento. Seria difícil coletar o uso, pois muitos sites terão diferentes casos de uso médio. E no final a O (n) approch que minimiza a necessidade de executá-lo em tudo é tão rápido qualquer outra otimização não seria percepable aos usuários em todos os :)
dsollen

@dsollen: Boa sorte :-)
Paddy3118
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.