Encontrando programaticamente a notação Landau (notação Big O ou Theta) de um algoritmo?


11

Estou acostumado a procurar a notação Landau (Big O, Theta ...) dos meus algoritmos manualmente, para garantir que eles sejam o mais otimizados possível, mas quando as funções estão ficando muito grandes e complexas, está acontecendo muito tempo para fazê-lo manualmente. também é propenso a erros humanos.

Passei algum tempo em Codility (exercícios de codificação / algo), e notei que eles fornecerão a notação Landau para sua solução enviada (tanto no uso de tempo quanto de memória).

Fiquei me perguntando como eles fazem isso ... Como você faria isso?

Existe outra maneira além da Análise Lexical ou da análise do código?

Esta questão diz respeito principalmente a PHP e / ou JavaScript, mas estou aberto a qualquer linguagem e teoria.


4
Verifique esta resposta da SO. Parece o que você está procurando.
Deco

2
Se você puder criar um programa que resolva esse problema para todo e qualquer algoritmo, ficará famoso como "o homem que refutou Turing".
User281377

1
Para obter provas de que geralmente é impossível decidir o tempo de execução, veja aqui e aqui - as respostas são muito mais do que você pede, na verdade.
Alex10 Brink #

Respostas:


13

Fiquei me perguntando como eles fazem isso ... Como você faria isso?

Eu imagino que eles estão realmente estimando as medidas do Big O ... executando o programa para diferentes tamanhos de problemas, medindo o uso de tempo e espaço e ajustando curvas aos resultados.

O problema com essa abordagem é que ela pode errar se as funções de custo mudarem de forma à medida que N se torna grande; por exemplo 1000 N + N^1.5.

Existe outra maneira além da Análise Lexical ou da análise do código?

A análise e análise lexical não são suficientes. Você também precisa raciocinar sobre o comportamento do algoritmo. E fazer isso automaticamente para um algoritmo anteriormente desconhecido é difícil.


6
"fazer isso automaticamente para um algoritmo previamente desconhecido é difícil" - Mais precisamente: é equivalente a resolver o problema da parada.
Jörg W Mittag

Ermm ... não exatamente. Resolver o problema de parada seria equivalente a ser capaz de fazê-lo para todos os algoritmos anteriormente desconhecidos.
Stephen C

2
Sim, desculpe. Fazer isso para um algoritmo é equivalente a (ou melhor, implica) provar a terminação.
Jörg W Mittag

1
Os aspectos práticos disso são: 1) é impossível provar ou refutar a terminação para alguns algoritmos, mas 2) a maioria dos algoritmos não possui esse impedimento teórico, mas 3) o estado da arte na prova de teoremas não está suficientemente avançado para seja capaz de fazer isso de qualquer maneira ... exceto em casos relativamente simples. Daí a minha afirmação de que imagino que eles estão fazendo isso de uma maneira diferente. Mas, obviamente, não podemos ter certeza de como eles estão realmente fazendo isso sem olhar para o código.
Stephen C

3

Eles não podem sem analisar o código.

Os exemplos abaixo, com "inflação / deflação" artificial de complexidade, provam que simplesmente medir o tempo de execução do programa não é suficiente para estimar com segurança o Big-O

void lets_trick_runtime(int n) {
   if (n == 10 || n == 25 || n == 118) {
      // unfair speed-up
      do_precalculated_solution_in_constant_time(n);
      return;
   }
   if (n == 11 || n == 26 || n == 119) {
      // unfair slow-down
      do_some_fake_processing_in_n_cube_time(n);
      return;
   }
   // fair solution
   do_general_solution_in_quadratic_time(n);
}

A estimativa de tempo de execução para o acima seria aceitável para fornecer estimativas falsas - tempo constante para valores de nonde existe uma solução pré-calculada e tempo cúbico para valores onde unfair slow-downentra em ação - em vez de tempo quadrático "justo".


No entanto, se eles verificarem os casos "injustos", ainda poderão assumir que o pior caso realmente estima a complexidade do Big-O.
Yam Marcovic

1

Eu acho que isso não é possível.

Se você executar alguns testes com um número fixo de diferentes tamanhos de entrada, poderá calcular facilmente um polinômio, que aproximará os tempos de execução que você mediu muito bem. Então você acaba com um polinômio para todos os programas possíveis, o que significaria P = NP(sim!;)).

Se você tentar fazer isso com manipulação simbólica, você acaba no halting problem. Como você não pode decidir se seu programa será interrompido, você não pode decidir qual complexidade de tempo de execução terá.

No entanto, pode haver casos muito especiais, onde o método posterior é possível. Mas nesses casos, talvez tão pequeno, que é questionável se algum esforço é pago.


1
+1, embora eu ache que o problema da parada possa ser considerado uma raridade.
Yam Marcovic

0

Como eu faria isso? Como resolvo quase qualquer problema, não quero me sentar e resolver . Eu simulo.

Para muitos problemas, pode ser suficiente executar o algoritmo várias vezes usando uma variedade de tamanhos e ajustar uma curva de regressão a esses resultados. Isso identificaria rapidamente alguns custos indiretos "fixos" específicos do seu algoritmo (a interceptação da curva) e como ele é dimensionado à medida que o tamanho do seu problema aumenta.

Serão necessários alguns ajustes para capturar soluções particularmente complicadas, mas especialmente se você estiver apenas procurando uma estimativa de estacionamento, poderá obtê-la dessa maneira e ver como sua estimativa difere dos resultados reais e decidir se é uma aproximação aceitável.

A maior fraqueza em minha mente com esse método é que, se o seu algoritmo for muito ruim, a etapa inicial "execute várias vezes" ficará feia. Mas, francamente, é esse o caso, que por si só deve ser um indicador de que você pode recuar e reconsiderar as coisas.


0

Minha intuição é que uma solução geral para esse problema é impossível; afirmar, como faz, fatos a priori sobre o tempo de execução dos algoritmos sem executá-los (você alude à análise lexical). Dito isso, é possível para algum algoritmo heurístico de uma classe (provavelmente grande) de algoritmos (já que fazemos isso o tempo todo), mas um algoritmo geral para fazer isso seria equivalente a resolver o problema de Entscheidung, que é conhecido por não ser possível (cf. Church, Turing, et al.). Tenho ~ 99,9% de certeza disso agora que penso nisso ...

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.