Perguntas sobre análise amortizada

7

Como preparação para um exame sobre algoritmos e complexidade, atualmente estou resolvendo exercícios antigos. Um conceito com o qual eu já estava lutando quando o encontrei pela primeira vez é o conceito de análise amortizada. O que é análise amortizada e como fazê-lo? Em nossas notas de aula, afirma-se que "a análise amortizada fornece limites para o" tempo médio "necessário para determinada operação e também pode fornecer um limite para o pior caso". Isso parece realmente útil, mas quando se trata de exemplos, não tenho idéia do que devo fazer e, mesmo depois de ler a solução de amostra, não tenho idéia do que eles estão fazendo.

Vamos somar 1 na base 2, ou seja, 0, 1, 10, 11, 100, 101, 110, 111, 1000, ... Usando a análise amortizada, mostre que em cada etapa somente amortizada constantemente, muitos bits precisam ser alterados.

(o exercício é originalmente em alemão, peço desculpas pela minha tradução talvez não seja perfeitamente precisa)

Agora a solução padrão primeiro define para alguma constante . Eu acho que isso é chamado de função potencial que, de alguma forma, corresponde às unidades excessivas de tempo (mas não tenho idéia do porquê de apresentar essa definição específica). Supondo que tenhamos que mudar bits na ésima etapa. Esse passo é sempre da formaϕ(i):=c#{1-bits in the binary representation}c>0mi

011m100m.

Esta afirmação é compreensível para mim, mas, novamente, não vejo a motivação por trás disso. Então, do nada, eles criam o que chamam de "estimativa"

a(i)=m+c(ϕ(i)ϕ(i1))=m+c(m+2)

e afirmam que para , obtemos que é o que tivemos que mostrar.c=1a(i)=2

O que acabou de acontecer? O que é ? Por que podemos escolher ? Em geral, se eu tiver que mostrar que em cada etapa apenas amortizadas constantemente muitas "unidades de tempo" são necessárias, isso significa que eu tenho que mostrar que é constante?a(i)c=1a(i)

Existem alguns outros exercícios relacionados à análise amortizada e também não os compreendo. Eu pensei que se alguém pudesse me ajudar com este, eu poderia dar outra chance aos outros exercícios e talvez isso me ajude a entender o conceito.

Agradecemos antecipadamente por qualquer ajuda.

Huy
fonte
Você já olhou em um livro de texto? Este é o exemplo padrão e deve ser desmontado e explicado em qualquer bom livro.
Raphael
@Raphael, IIRC, isso é do capítulo 17 do CLRS.
Kaveh

Respostas:

5

Vamos ser os custos amortizados de operação , ser os custos reais de operação , e a estrutura de dados após a operação . Os custos amortizados de uma operação são definidos como Você geralmente assume o seguinteaiiciiDii

ai:=ci+Φ(Di)Φ(Di1).
  1. O potencial é sempre positivo, ou seja, ,:iΦ(Di)0
  2. No início, o potencial é 0, ou seja, .Φ(D0)=0

Essas duas suposições nem sempre são necessárias, mas são comumente usadas e facilitam a vida. Agora você pode considerar o potencial a custos que já foram pagos por operações anteriores.

Para justificar essa definição, considere os custos acumulados de todas as operações. Obtemos a seguinte soma telescópica Portanto, você vê que a soma dos custos amortizados excede o total dos custos reais. Portanto, os custos amortizados dão um limite superior.

i=1nai=i=1n(ci+Φ(Di)Φ(Di1))=Φ(Dn)Φ(D0)+i=1ncii=1nci.

Eu não vi o uso do na sua fórmula. Mas pode ser simplesmente adicionado à função potencial . Portanto, pense no como um fator que pesa o potencial e redefina a função para se livrar dele.ccΦcΦ

Então, para responder suas perguntas concretas. indica os custos amortizados para o th operação, isto é, os custos reais em uma sequência de operação para operação carregada . O é algum fator positivo que você pode escolher. E os s não são constantes em geral (eles estão no seu exemplo) - você não precisa mostrar nada para os custos a , os valores são o resultado de sua análise.a(i)iica(i)a(i)a(i)

Como você parece falar alemão, também pode dar uma olhada nas minhas anotações de aula de alemão para a função em potencial.

A.Schulz
fonte
4

O método da função potencial é complicado, seu exemplo é simples. O número de bits alterados é 1 aproximadamente metade do tempo, 2 aproximadamente um quarto das vezes, 3 aproximadamente um oitavo das vezes e assim por diante. Isso ocorre porque o número de bits alterados, começando em 0, é 1,2,1,3,1,2,1,4 e assim por diante (você obtém o padrão). Portanto, o número médio de bits alterados é

k=1k2k=k=1l=k12l=k=112k1=2.
Yuval Filmus
fonte
11
Não concordo que o método da função potencial seja complicado. Conceitualmente, é muito simples. No entanto, encontrar a função potencial certa para um determinado problema pode ser complicado.
precisa saber é o seguinte
11
Concordo que esta é a melhor maneira de vê-lo, mas é melhor se você pegar um número da forma e ver que o primeiro bit muda a cada vez, o segundo bit a cada outro, o terceiro muda a cada quarto, etc.2n
Pål GD
3

A análise amortizada lida com o custo de tempo de execução de uma operação como uma média em uma sequência de operações. Isso é semelhante ao conceito financeiro de amortização - uma quantia única, como um empréstimo, é amortizada por um período de tempo. Isso corrige um pagamento mensal, por exemplo, mesmo que o saldo do principal esteja diminuindo.

Dessa forma, um tempo de execução amortizado é um tipo de média, embora não seja o mesmo que um tempo de execução de caso médio que envolve análise probabilística em uma distribuição de entradas.

Existem três técnicas padrão para executar a análise amortizada: (1) o método agregado, (2) o método contábil e (3) o método potencial. Este último é o que você está vendo em suas anotações de aula e o que A. Schulz está usando em sua resposta. Também é um pouco mais complicado.

Apontaria as excelentes notas de aula de JeffE, que incluem uma explicação das três técnicas, começando com o exemplo frequentemente citado (e o que você encontrou) de incrementar um contador binário. Mostra que o custo amortizado de uma operação de incremento é quando a média é calculada sobre uma sequência dessas operações, mesmo que o pior tempo de execução seja .O(1)O(logn)

Outro recurso seria o capítulo 17 do [CLRS01] , que começa com outro exemplo comum, uma pilha com uma operação "multi-pop".

David
fonte
2

Eu acho que a declaração do problema é mais clara quando você pensa nisso como um contador que começa em 0 e tem uma operação que incrementa o valor em um. Toda vez que o contador do seu problema é incrementado, exatamente um bit é ativado e zero ou mais bits são desativados . A função potencial do problema de exemplo não é tão inesperada quanto você imagina. A chave para o problema é que apenas um pouco que foi ativado anteriormente pode ser desligado. Assim, toda vez que fizermos uma operação de incremento e ligarmos um pouco, armazenaremos uma unidade de tempo em nossa "conta poupança" (a função potencial) que podemos usar para desativar esse bit posteriormente.

Isso ocorre porque ao incrementar o contador, você primeiro olha o bit mais à direita. Se estiver desativado, você o liga. Se estiver ligado, desligue-o e olhe para a posição do bit uma à esquerda. Se estiver desligado, ligue-o e pare. Se estiver ativado, desligue-o e olhe para o bit à esquerda dele. Portanto, o número de bits que você inverte em uma operação é igual à posição do primeiro 0-bit da direita.

Inicialmente, tanto a função de contador quanto a potencial são 0. Após realizar uma operação de incremento, o contador é 1 e a função potencial também é 1. Se incrementarmos novamente, o contador se tornará 10. A função potencial permanecerá 1. Após outra etapa, o contador será 11 e a função potencial 2. Se formos incrementar o contador novamente, precisaremos inverter 3 bits para passar de 011 para 100. Para isso, temos que usar parte do potencial e acabamos com um novo potencial de 1. O truque é que o número total de bits realmente virou até agora, mais a função potencial é sempre igual a duas vezes o número de bits. operações de incremento. Como a função potencial nunca é negativa, o número total de bitflips após operações de incremento é no máximon2n, então cada operação leva bitflips amortizados .2

Outro exemplo muito bom é a lista de matrizes. Aqui temos uma lista (suportando a iteração sobre todos os elementos e adicionando um novo elemento) que é implementada armazenando os elementos em uma matriz. A matriz começa inicialmente muito pequena (digamos 2 lugares). Quando adicionamos um elemento, ele é armazenado na matriz. Quando estamos prestes a adicionar o terceiro elemento, não há mais espaço na matriz. Para combater isso, criamos uma nova matriz com o dobro do tamanho e copiamos todos os elementos da matriz original. Isso pode levar muito tempo (linear no número de elementos), mas a análise amortizada mostra que cada operação de adição leva apenas tempo constante. A lista de matrizes tem um desempenho muito bom no mundo real (muito melhor que a lista vinculada). Cada operação pode ser feita em tempo constante, com a ressalva de que ocasionalmente uma operação levará muito mais tempo.

Tom van der Zanden
fonte