Em formação

Tratamentos modernos das redes neurais do tipo B de Alan Turing

Tratamentos modernos das redes neurais do tipo B de Alan Turing

Nas ciências cognitivas, Alan Turing é mais conhecido por lançar IA com seu Maquinário de computação e inteligência (1950). No entanto, esta não foi sua primeira contribuição para as ciências cognitivas, em seu relatório técnico não publicado de 1948 Maquinário de Inteligência ele previu o conexionismo com suas redes neurais do tipo B.

O modelo é uma rede neural recorrente conectada aleatoriamente e sincronizada por um relógio global. Os neurônios são duas entradas $ mathrm {NAND} $-gates. As conexões têm um de dois estados: ou encaminham seu sinal perfeitamente ($ 0 mapsto 0 $ e $ 1 mapsto 1 $) ou substitua por $1$ ($ 0 mapsto 1 $ e $ 1 mapsto 1 $) O algoritmo de aprendizagem ajusta os estados das conexões.

Infelizmente, o diretor do Laboratório Nacional de Física rejeitou o trabalho de Turing e ele só foi publicado significativamente após a morte de Turing. O manuscrito original, embora seja anterior ao aprendizado de Hebbian (1949) e aos perceptrons de Rosenblatt (1957; e eles não eram tão sofisticados, apenas realizando feedforward em vez de recorrentes).

As redes neurais do tipo B de Turing foram os primeiros modelos de computação semelhantes aos neurais, capazes de aprender?

Embora pelo padrão moderno, a abordagem de Turing seja datada e foi suplantada por tratamentos mais realistas e gerais (por exemplo, aqueles que incorporam atualização Hebbian dinâmica em conexões ponderadas sem a necessidade de sincronização de relógio central). Quando o estado de conexionismo ultrapassou pela primeira vez as redes neurais do tipo B de Turing? Existem tratamentos modernos para as redes neurais do tipo B e suas habilidades de aprendizagem?


Notas

Estou interessado nisso principalmente do ponto de vista histórico, e não em quão preciso era o modelo de Turing sob as interpretações atuais. Embora o conhecimento atual ajudasse a responder quando outros modelos ultrapassaram o de Turing.


Que eu saiba, no que diz respeito ao contexto da questão, o primeiro modelo neural de computação capaz de aprender - ou, nesse caso, modelo computacional de processamento neural e aprendizagem - foi apresentado em McCulloch / Pitts (1943), como também é reconhecido em alguns dos textos sobre as máquinas desorganizadas de Turing (›Redes neurais do tipo A- / B‹) Turing não se refere a este artigo em seu relatório de 1948, no entanto, constituindo uma referência central para os perceptrons de Rosenblatt, o artigo de McCulloch / Pitts também é regularmente ignorado em relatos históricos do conexionismo.

As máquinas desorganizadas originais de Turing são geralmente reconhecidas como tendo algumas limitações no que diz respeito a certas operações lógicas, como XOR (cf. por exemplo, Teuscher / Sanchez 2001). Nesse aspecto (que por brevidade pode ser chamado apenas de narrativa histórica), eles são semelhantes ao perceptron. Assim, parece seguro assumir que pelo menos o conexionismo ultrapassou as máquinas desorganizadas do tipo B quando foi mostrado como implementar tais funções (por exemplo, no infame Minsky / Papert 1969 - lembre-se de que isso não implica necessariamente uma deficiência lógica geral dos modelos originais).

Os relativamente poucos artigos que abordaram o tema nos últimos 20 anos de fato, expressaram a observação de que as máquinas desorganizadas de Turings foram amplamente negligenciadas e, portanto, constituem um tópico interessante para uma análise mais detalhada - mas veja Teuscher (2002) para uma monografia sobre o assunto.


• Boccato, L., Soares, E. S., Fernandes, M. M. L. P., Soriano, D. C., & Attux, R. (2011). Máquinas desorganizadas: das ideias de Turing às abordagens conexionistas modernas. International Journal of Natural Computing Research, 2(4).

• Copeland, B. J., & Proudfoot, D. (1996). Sobre a antecipação do conexionismo por Alan Turing. Synthese, 108 (3), 361-377. doi: 10.1007 / BF00413694

• Copeland, B. J., & Proudfoot, D. (1999). Ideias esquecidas de Alan Turing na ciência da computação. Americano científico(280), 99-103.

• McCulloch, W. S., & Pitts, W. (1943). Um cálculo lógico das idéias imanentes na atividade nervosa. Boletim de Biofísica Matemática, 5, 115-133.

• Minsky, M., & Papert, S. (1969). Perceptrons. Uma introdução à geometria computacional. Cambridge, Mass .: MIT Press.

• Teuscher, C. (2002). Conexionismo de Turing. Uma investigação de arquiteturas de rede neural. Londres: Springer-Verlag.

• Teuscher, C., & Sanchez, E. (2001). Um renascimento das idéias esquecidas de conexão de Turing: explorando máquinas desorganizadas. Em R. M. French & J. P. Sougné (Eds.), Modelos conexionistas de aprendizagem, desenvolvimento e evolução (pp. 153-162): Springer London.

• Webster, C. S. (2012). As máquinas desorganizadas e as redes neurais artificiais de Alan Turing: seu notável trabalho inicial e possibilidades futuras. Inteligência Evolucionária, 5 (1), 35-43. doi: 10.1007 / s12065-011-0060-5


Nada vago do ponto de vista & # 8220sem semântica & # 8221

Sou um defensor da & # 8220no semântica & # 8221 e tentarei convencê-lo de que não há nada de vago nisso.

Considere qualquer formalismo. A qualquer termo construído a partir deste formalismo existe uma árvore sintática associada. Agora, olhe para a árvore sintática e esqueça o formalismo. Por ser uma árvore, isso significa que não importa como você decida decorar suas folhas, você pode progredir das folhas até a raiz decorando cada borda. Em cada nó da árvore, você segue uma regra de decoração que diz: pegue as decorações das bordas de entrada e use-as para decorar as bordas de saída. Se você supõe que o formalismo é aquele que usa operações de aridade limitada, então você pode dizer o seguinte: estritamente seguindo as regras de decoração que são locais (você precisa saber apenas no máximo N decorações de aresta para decorar outra aresta) você pode chegar para decorar toda a árvore. Al o gráfico! E o significado do gráfico tem algo a ver com essa decoração. Na verdade, o formalismo não se trata de gráficos (árvores), mas de decorações estáticas que aparecem na raiz da árvore sintática.
Mas, você vê, essas decorações estáticas são efeitos globais das regras locais de decoração. Aqui entra a polícia semântica. Tu aceitarás apenas árvores cujas raízes aceitem decorações de um determinado idioma. Seguem-se problemas difíceis, que são fortemente carregados de semântica.
Agora, vamos & # 8217s passar das árvores para outros gráficos.
O mesmo fenômeno (há uma decoração global estática emergida das regras locais de decoração) para qualquer DAG (grafo acíclico direcionado). É revelador que as pessoas AMAM DAGs, tanto que vão ao extremo de excluir de seu pensamento outros gráficos. São eles que colocam tudo em uma estrutura funcional.
Não há nada de errado nisso!
Os gráficos decorados têm uma longa tradição em matemática, pense, por exemplo, na teoria dos nós.
Na teoria do nó, o diagrama do nó é um gráfico (com nós 4-valentes) que certamente não é acíclico! No entanto, um dos objetos fundamentais associados a um nó é o objeto algébrico denominado & # 8220quandle & # 8221, que é gerado a partir das arestas do gráfico, com certas relações vindas das arestas. Obviamente, é um problema muito difícil, totalmente carregado semanticamente, tentar identificar o nó do nó associado.
A diferença das árvores sintáticas é que o grafo não admite decoração global estática, genericamente. É por isso que o objeto algébrico associado, o quandle, é gerado (e não igual a) o conjunto de arestas.

Existem belos problemas relacionados aos objetos globais gerados por regras locais. Eles também são difíceis, por causa do aspecto global. Talvez seja tão difícil encontrar um algoritmo que construa um isomorfismo entre dois grafos que possuem a mesma família de decorações associadas, quanto encontrar um algoritmo descentralizado para redução de grafos de uma árvore sintática distribuída.

Mas esse tipo de problema não cobre todos os problemas interessantes.

E se esse ponto de vista semântico global tornar as coisas mais difíceis do que realmente são?

Suponha que você seja um gênio que encontrou esse algoritmo, por meio de incríveis insights matemáticos que dobram a mente.

Seu algoritmo brilhante, por ser um algoritmo, pode ser executado por uma Máquina de Turing.

Ou as máquinas de Turing são puramente locais. O cabeçote da máquina tem apenas acesso local à fita, a qualquer momento (esqueça a indireção, voltarei a isso em instantes). O número de estados das máquinas é finito e o número de regras é finito.

Isso significa que o trabalho brilhante serviu para separar o global do problema!

Se você não está satisfeito com TM, por causa de indireção, então não procure além de chemlambda (se desejar combinado com TM, como em
http://chorasimilarity.github.io/chemlambda-gui/dynamic/turingchem.html, se você adora TM), que é definitivamente local e Turing universal. Funciona pelo algoritmo brilhante: faça todas as reescritas que você puder fazer, nunca se importando com o significado global delas.

Oh, espere, que tal uma célula viva, ela tem uma maneira de gerenciar a semântica das redes de reações químicas globais corretas que SÃO a célula?

Que tal um cérebro, feito de muitas células neurais, células da glia e outros enfeites? Pela falácia do homúnculo, ele não pode ter funções e termos estáticos, externos e globalmente selecionados (também conhecidos como semânticos).

Por outro lado, é claro que o pesquisador que estuda a célula, ou o cérebro, ou o matemático que encontra o algoritmo brilhante, todos estão usando um maquinário semântico pesado.

Não que a célula ou o cérebro precisem da história para viver.

No gif animado existe uma molécula chemlambda chamada 28 quine, que satisfaz a definição de vida no sentido de que ela reabastece aleatoriamente seus átomos, mantendo aproximadamente sua forma global (portanto, tem um metabolismo). Ele faz isso de acordo com o algoritmo: faça todas as reescritas que puder, mas só poderá reescrever se um lançamento de moeda aleatório aceitar.


A maioria dos átomos da molécula está relacionada a operações (aplicação e abstração) do cálculo lambda.

Modifiquei um pouco um script (desculpe, não no repo este aqui) para que sempre que possível as arestas deste gráfico que PODEM fazer parte de uma árvore sintática de um termo lambda se transformem em OURO enquanto as outras ficam em cinza escuro.

Eles não significam nada, não há semântica, porque pela primeira vez os gráficos dourados não são DAGs e porque o cálculo consiste em reescrever gráficos que não preservam bem as decorações & # 8220corretas & # 8221 antes da reescrita.

Não há semântica, mas ainda há algumas questões interessantes a explorar, sendo a principal: como funciona a vida?


Computer_science_theory & lt- StackExchange principais 100

Para demonstrar a importância dos algoritmos (por exemplo, para alunos e professores que não fazem teoria ou até mesmo de áreas totalmente diferentes), às vezes é útil ter em mãos uma lista de exemplos onde algoritmos centrais foram implantados em áreas comerciais, governamentais, ou software / hardware amplamente utilizado.

Estou procurando exemplos que satisfaçam os seguintes critérios:

O software / hardware que usa o algoritmo deve ser amplamente utilizado agora.

O exemplo deve ser específico. Por favor, dê uma referência a um sistema específico e um algoritmo específico.
Por exemplo, em “o algoritmo X é útil para processamento de imagem”, o termo “processamento de imagem” não é específico o suficiente. Em “A pesquisa do Google usa algoritmos de gráfico”, o termo “algoritmos de gráfico” não é específico o suficiente.

O algoritmo deve ser ensinado em cursos de graduação ou doutorado típicos. classes em algoritmos ou estruturas de dados. Idealmente, o algoritmo é abordado em livros didáticos de algoritmos típicos. Por exemplo, “sistema X bem conhecido usa algoritmo Y pouco conhecido” não é bom.

Atualizar:

Obrigado novamente pelas ótimas respostas e links! Algumas pessoas comentam que é difícil satisfazer os critérios porque os algoritmos principais são tão difundidos que é difícil apontar para um uso específico. Eu vejo a dificuldade. Mas acho que vale a pena citar exemplos específicos porque, em minha experiência, digo às pessoas: “Veja, algoritmos são importantes porque são quase em todo lugar! ” não funciona.

Resposta aceita (pontuação 473)

Os algoritmos que são o principal condutor de um sistema são, na minha opinião, mais fáceis de encontrar em cursos sem algoritmos pela mesma razão que os teoremas com aplicações imediatas são mais fáceis de encontrar em matemática aplicada do que em cursos de matemática pura. É raro que um problema prático tenha a estrutura exata do problema abstrato em uma aula. Para ser argumentativo, não vejo razão para que o material do curso de algoritmos da moda, como a multiplicação de Strassen, o teste de primalidade AKS ou o algoritmo Moser-Tardos seja relevante para problemas práticos de baixo nível de implementação de um banco de dados de vídeo, um compilador de otimização, um sistema operacional , um sistema de controle de congestionamento de rede ou qualquer outro sistema. O valor desses cursos é aprender que existem maneiras intrincadas de explorar a estrutura de um problema para encontrar soluções eficientes. Algoritmos avançados também é onde encontramos algoritmos simples, cuja análise não é trivial. Por esse motivo, eu não descartaria algoritmos aleatórios simples ou PageRank.

Acho que você pode escolher qualquer software grande e encontrar algoritmos básicos e avançados implementados nele. Como um estudo de caso, fiz isso para o kernel Linux e mostrei alguns exemplos do Chromium.

Estruturas de dados e algoritmos básicos no kernel Linux

Árvores B + com comentários dizendo o que você não consegue encontrar nos livros didáticos.

Uma implementação B + Tree relativamente simples. Eu o escrevi como um exercício de aprendizado para entender como as árvores B + funcionam. Acabou sendo útil também.

Foi usado um truque que não é comumente encontrado em livros didáticos. Os valores mais baixos estão à direita, não à esquerda. Todos os slots usados ​​em um nó estão à esquerda, todos os slots não usados ​​contêm valores NUL. A maioria das operações simplesmente executa um loop em todos os slots e termina no primeiro NUL.

As árvores Radix são usadas para gerenciamento de memória, pesquisas relacionadas a NFS e funcionalidade relacionada à rede.

Heap de prioridade, que é literalmente uma implementação de livro didático, usada no sistema de grupo de controle.

Funções de hash, com referência a Knuth e a um artigo.

Knuth recomenda números primos em aproximadamente a proporção áurea para o número inteiro máximo representável por uma palavra de máquina para hash multiplicativo. Chuck Lever verificou a eficácia desta técnica:

http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf

Esses primos são escolhidos para serem esparsos em bits, ou seja, as operações neles podem usar deslocamentos e adições em vez de multiplicações para máquinas onde as multiplicações são lentas.

Algumas partes do código, como este driver, implementam sua própria função hash.

função hash usando um algoritmo de Hash rotativo

Knuth, D. The Art of Computer Programming, Volume 3: Sorting and Searching, Capítulo 6.4. Addison Wesley, 1973

Matrizes de bits, que são usadas para lidar com sinalizadores, interrupções, etc. e são apresentadas em Knuth Vol. 4

Executa uma caminhada de profundidade modificada da árvore do namespace, começando (e terminando) no nó especificado por start_handle. A função de retorno de chamada é chamada sempre que um nó que corresponde ao parâmetro de tipo é encontrado. Se a função de retorno de chamada retornar um valor diferente de zero, a pesquisa será encerrada imediatamente e esse valor será retornado ao chamador.

A primeira pesquisa de amplitude é usada para verificar a exatidão do bloqueio em tempo de execução.

O Bubble Sort também é incrivelmente implementado em uma biblioteca de drivers.

Implementa um algoritmo de correspondência de strings de tempo linear devido a Knuth, Morris e Pratt [1]. Seu algoritmo evita o cálculo explícito da função de transição DELTA completamente. Seu tempo de correspondência é O (n), para n ser comprimento (texto), usando apenas uma função auxiliar PI [1..m], para m ser comprimento (padrão), pré-calculado do padrão no tempo O (m). O array PI permite que a função de transição DELTA seja calculada de forma eficiente “em tempo real” conforme necessário. Grosso modo, para qualquer estado “q” = 0,1,…, me qualquer caractere “a” no SIGMA, o valor PI [“q”] contém a informação que é independente de “a” e é necessária para calcular DELTA (“Q”, “a”) 2. Como o array PI tem apenas m entradas, enquanto DELTA tem O (m | SIGMA |) entradas, salvamos um fator de | SIGMA | no tempo de pré-processamento, computando PI em vez de DELTA.

[1] Cormen, Leiserson, Rivest, Stein Introdcution to Algorithms, 2ª edição, MIT Press

[2] Veja a teoria de automação finita

Correspondência de padrões de Boyer-Moore com referências e recomendações para quando preferir a alternativa.

Implementa o algoritmo de correspondência de strings de Boyer-Moore:

[1] A Fast String Searching Algorithm, R.S. Boyer e Moore. Communications of the Association for Computing Machinery, 20 (10), 1977, pp. 762-772. http://www.cs.utexas.edu/users/moore/publications/fstrpos.pdf

[2] Handbook of Exact String Matching Algorithms, Thierry Lecroq, 2004 http://www-igm.univ-mlv.fr/

lecroq / string / string.pdf

Observação: como Boyer-Moore (BM) realiza pesquisas de correspondências da direita para a esquerda, ainda é possível que uma correspondência possa ser espalhada por vários blocos, nesse caso, esse algoritmo não encontrará nenhuma coincidência.

Se você deseja garantir que isso nunca aconteça, use a implementação Knuth-Pratt-Morris (KMP). Em conclusão, escolha o algoritmo de pesquisa de string adequado, dependendo de sua configuração.

Digamos que você esteja usando a infraestrutura de pesquisa de texto para filtragem, NIDS ou
qualquer finalidade semelhante com foco na segurança, vá para KMP. Caso contrário, se você realmente se preocupa com o desempenho, digamos que você está classificando pacotes para aplicar políticas de qualidade de serviço (QoS) e não se importa com possíveis correspondências espalhadas por vários fragmentos, então vá BM.

Estruturas de dados e algoritmos no navegador da Web Chromium

Os links são para o código-fonte no código do Google. Vou apenas listar alguns. Eu sugeriria usar o recurso de pesquisa para pesquisar seu algoritmo ou estrutura de dados favorita.

Bibliotecas de linguagem de programação

Acho que vale a pena considerá-los. Os designers das linguagens de programação acharam que valeu a pena o tempo e o esforço de alguns engenheiros para implementar essas estruturas de dados e algoritmos para que outros não precisassem fazer isso.A existência de bibliotecas é parte do motivo pelo qual podemos encontrar estruturas de dados básicas reimplementadas em software escrito em C, mas nem tanto para aplicativos Java.

  1. O C ++ STL inclui listas, pilhas, filas, mapas, vetores e algoritmos para classificação, pesquisa e manipulação de heap.
  2. A API Java é muito extensa e cobre muito mais.
  3. A biblioteca Boost C ++ inclui algoritmos como algoritmos de correspondência de string de Boyer-Moore e Knuth-Morris-Pratt.
Algoritmos de alocação e programação

Acho isso interessante porque, embora sejam chamados de heurísticas, a política que você usa dita o tipo de algoritmo e estrutura de dados que são necessários, portanto, é necessário saber sobre pilhas e filas.

  1. Menos usado recentemente pode ser implementado de várias maneiras. Uma implementação baseada em lista no kernel Linux.
  2. Outras possibilidades são Primeiro a entrar, primeiro a sair, Menos usado com frequência e Round Robin.
  3. Uma variante do FIFO foi usada pelo sistema VAX / VMS.
  4. O algoritmo Clock de Richard Carr é usado para substituição de quadro de página no Linux.
  5. O processador Intel i860 usou uma política de substituição aleatória.
  6. O Adaptive Replacement Cache é usado em alguns controladores de armazenamento IBM e no PostgreSQL, embora apenas brevemente devido a questões de patentes.
  7. O algoritmo de alocação de memória Buddy, que é discutido por Knuth em TAOCP Vol. 1 é usado no kernel Linux e o alocador simultâneo jemalloc usado pelo FreeBSD e no Facebook.
Principais utilitários em sistemas * nix
  1. grep e awk ambos implementam a construção Thompson-McNaughton-Yamada de NFAs a partir de expressões regulares, o que aparentemente supera a implementação Perl.
  2. Tsort implementa classificação topológica.
  3. fgrep implementa o algoritmo de correspondência de strings Aho-Corasick.
  4. GNU grep, implementa o algoritmo Boyer-Moore de acordo com o autor Mike Haertel.
  5. crypt (1) no Unix implementou uma variante do algoritmo de criptografia na máquina Enigma.
  6. Dif Unix implementado por Doug McIllroy, baseado em um protótipo co-escrito com James Hunt, tem um desempenho melhor do que o algoritmo de programação dinâmica padrão usado para calcular distâncias de Levenshtein. A versão Linux calcula a distância de edição mais curta.
Algoritmos criptográficos

Esta pode ser uma lista muito longa. Algoritmos criptográficos são implementados em todos os softwares que podem realizar comunicações ou transações seguras.

  1. Árvores Merkle, especificamente a variante Tiger Tree Hash, foram usadas em aplicativos ponto a ponto, como GTK Gnutella e LimeWire.
  2. MD5 é usado para fornecer uma soma de verificação para pacotes de software e é usado para verificações de integridade em sistemas * nix (implementação de Linux) e também é compatível com Windows e OS X.
  3. OpenSSL implementa muitos algoritmos criptográficos, incluindo AES, Blowfish, DES, SHA-1, SHA-2, RSA, DES, etc.
Compiladores
  1. A análise LALR é implementada por yacc e bison.
  2. Os algoritmos do Dominator são usados ​​na maioria dos compiladores de otimização baseados no formulário SSA.
  3. Lex e flex compilar expressões regulares em NFAs.
Compressão e processamento de imagem
  1. Os algoritmos Lempel-Ziv para o formato de imagem GIF são implementados em programas de manipulação de imagens, a partir do utilitário * nix converter a programas complexos.
  2. A codificação de comprimento de execução é usada para gerar arquivos PCX (usados ​​pelo programa Paintbrush original), arquivos BMP compactados e arquivos TIFF.
  3. A compactação wavelet é a base do JPEG 2000, portanto, todas as câmeras digitais que produzem arquivos JPEG 2000 implementarão esse algoritmo.
  4. A correção de erros Reed-Solomon é implementada no kernel Linux, unidades de CD, leitores de código de barras e foi combinada com convolução para transmissão de imagem do Voyager.
Aprendizagem de cláusulas orientadas por conflito

Desde o ano 2000, o tempo de execução dos solucionadores SAT em benchmarks industriais (geralmente da indústria de hardware, embora outras fontes também sejam usadas) diminuiu quase exponencialmente a cada ano. Uma parte muito importante deste desenvolvimento é o Aprendizagem de cláusulas orientadas por conflito algoritmo que combina o Propagação de restrição booleana algoritmo no artigo original de Davis Logemann e Loveland com a técnica de aprendizagem de cláusula que se originou na programação de restrição e na pesquisa de inteligência artificial. Para modelagem industrial específica, o SAT é considerado um problema fácil (veja esta discussão). Para mim, esta é uma das maiores histórias de sucesso dos últimos tempos, porque combina avanços algorítmicos espalhados por vários anos, ideias de engenharia inteligentes, avaliação experimental e um esforço conjunto conjunto para resolver o problema. O artigo CACM de Malik e Zhang é uma boa leitura. Este algoritmo é ensinado em muitas universidades (participei de quatro onde era o caso), mas normalmente em uma aula de lógica ou métodos formais.

As aplicações dos solucionadores SAT são numerosas. IBM, Intel e muitas outras empresas têm suas próprias implementações de solucionador SAT. O gerenciador de pacotes no OpenSUSE também usa um solucionador SAT.

Resposta 2 (pontuação 40)

O PageRank é um dos algoritmos mais conhecidos. Desenvolvido pelo cofundador do Google Larry Page e co-autores, ele formou a base do mecanismo de pesquisa original do Google e é amplamente reconhecido por ajudá-los a obter melhores resultados de pesquisa do que seus concorrentes na época.

Imaginamos um “surfista aleatório” começando em alguma página da web e clicando repetidamente em um link aleatório para levá-lo a uma nova página. A pergunta é: “Qual fração de tempo o surfista gastará em cada página?” Quanto mais tempo o surfista passa em uma página, mais importante a página é considerada.

Mais formalmente, vemos a internet como um gráfico onde as páginas são nós e os links são arestas direcionadas. Podemos então modelar a ação do surfista como um passeio aleatório em um gráfico ou equivalentemente como uma Cadeia de Markov com matriz de transição (M ). Depois de lidar com alguns problemas para garantir que a Cadeia de Markov seja ergódica (para onde vai o surfista se uma página não tem links de saída?), Calculamos a quantidade de tempo que o surfista gasta em cada página como a distribuição de estado estacionário da Cadeia de Markov .

O algoritmo em si é, em certo sentido, trivial - nós apenas calculamos (M ^ k pi_0 ) para grande (k ) e distribuição inicial arbitrária ( pi_0 ). Isso equivale apenas a uma multiplicação repetida de matriz-matriz ou matriz-vetor. O conteúdo dos algoritmos está principalmente na configuração (garantindo a ergodicidade, provando que uma Cadeia de Markov ergódica tem uma distribuição de estado estacionário única) e na análise de convergência (dependência do gap espectral de (M )).

Resposta 3 (pontuação 33)

Eu mencionaria a implementação do software CPLEX (ou similar) amplamente utilizado do método / algoritmo Simplex para resolver problemas de programação linear. É o (?) Algoritmo mais utilizado em pesquisa econômica e operacional.

“Se alguém pegasse estatísticas sobre qual problema matemático está usando a maior parte do tempo do computador no mundo, então (sem contar os problemas de manuseio de banco de dados como classificação e busca) a resposta provavelmente seria programação linear.”(L. Lovász, Um novo algoritmo de programação linear - melhor ou pior do que o método simplex? Math. Intelligencer 2 (3) (1979/80) 141-146.)

O algoritmo Simplex também tem grande influência na teoria, ver, por exemplo, a conjectura de Hirsch (polinomial).

Eu acho que um típico estudante de graduação ou Ph.D. classe em algoritmos lida com o algoritmo Simplex (incluindo algoritmos básicos de álgebra linear como Método de Eliminação de Gauss).

(Outros algoritmos de sucesso, incluindo Quicksort para classificação, estão listados em Algoritmos do Livro.)

2: Quais jornais todos deveriam ler? (pontuação 161084 em 2017)

Pergunta

Esta pergunta é (inspirada por) / (vergonhosamente roubada de) uma pergunta semelhante no MathOverflow, mas espero que as respostas aqui sejam bem diferentes.

Todos nós temos artigos favoritos em nossas respectivas áreas de teoria. De vez em quando, encontramos um artigo tão surpreendente (por exemplo, importante, atraente, aparentemente simples, etc.) que queremos compartilhá-lo com todos. Então, liste esses papéis aqui! Eles não tenho ser da ciência da computação teórica - qualquer coisa que você ache que possa agradar à comunidade é uma boa resposta.

Você pode dar quantas respostas quiser por favor coloque um papel por resposta! Além disso, observe que este é um wiki da comunidade, então vote em tudo o que quiser!

(Observe que houve uma pergunta anterior sobre artigos em complexidade teórica de recursão, mas ela é bastante especializada.)

Resposta 2 (pontuação 164)

“Uma teoria matemática da comunicação” de Claude Shannon, clássicos da teoria da informação. Muito legível.

Resposta 3 (pontuação 145)

O artigo de 1936 que possivelmente deu início à própria ciência da computação:

  • Alan Turing, "On Computable Numbers, with an Application to the Entscheidungsproblem", Proceedings of the London Mathematical Society s2-42, 230–265, 1937. doi: 10.1112 / plms / s2-42.1.230

Em apenas 36 páginas, Turing formula (mas não nomeia) a Máquina de Turing, reformula o famoso Primeiro Teorema da Incompletude de Gödel em termos de computação, descreve o conceito de universalidade e no apêndice mostra que a computabilidade por máquinas de Turing é equivalente à computabilidade por ( lambda ) -funções definíveis (conforme estudado por Church e Kleene).

3: A prova de Norbert Blum de 2017 de que (P ne NP ) correto? (pontuação 115991 em 2017)

Pergunta

Norbert Blum postou recentemente uma prova de 38 páginas que (P ne NP ). Está correto?

Também no tópico: onde mais (na internet) sua correção está sendo discutida?

Observação: o foco deste texto da pergunta mudou ao longo do tempo. Veja os comentários das perguntas para detalhes.

Resposta aceita (pontuação 98)

Como observado aqui antes, o exemplo de Tardos refuta claramente a prova que dá uma função monótona, que concorda com CLIQUE em T0 e T1, mas que está em P. Isso não seria possível se a prova fosse correta, uma vez que a prova se aplica a este caso também. No entanto, podemos identificar o erro? Aqui está, a partir de uma postagem no blog do Lipton, o que parece ser o lugar onde a prova falha:

O único erro é um ponto sutil na prova do Teorema 6, a saber, na Etapa 1, na página 31 (e também 33, onde o caso dual é discutido) - uma afirmação aparentemente óbvia de que (C & # 39_g ) contém todas as cláusulas correspondentes contidas em (CNF & # 39 (g) ) etc, parece errado.

Para explicar isso com mais detalhes, precisamos entrar no método de prova e aproximação de Berg e Ulfberg, que reafirma a prova original de Razborov da complexidade monótona exponencial para CLIQUE em termos de switches DNF / CNF. É assim que eu vejo:

Para cada nó / porta (g ) de um circuito lógico ( beta ) (contendo apenas portas OR / AND binárias), uma forma normal conjuntiva (CNF (g) ), uma forma normal disjuntiva (DNF (g) ), e aproximadores (C ^ k_g ) e (D ^ r_g ) são anexados. (CNF ) e (DNF ) são simplesmente as formas normais disjuntivas e conjuntivas correspondentes da saída da porta. (D ^ r_g ) e (C ^ k_g ) também são formas disjuntivas e conjuntivas, mas de algumas outras funções, “aproximando-se” da saída da porta. No entanto, eles devem ter um número limitado de variáveis ​​em cada monômio para (D ^ r_g ) (menos que uma constante r) e em cada cláusula para (C ^ k_g ) (menos que uma constante k).

Há noção de um “erro” introduzida com esta aproximação. Como esse erro é calculado? Estamos interessados ​​apenas em algum conjunto T0 de entradas em que nossa função total assume valor 0, e T1 de entradas em que nossa função total assume valor 1 (uma “promessa”). Agora, em cada porta, olhamos apenas para as entradas de T0 e T1, que são calculadas corretamente (por ambos (DNF (g) ) e (CNF (g) ), que representam a mesma função - saída da porta (g ) em ( beta )) na saída do portão, e veja quantos erros / erros são para (C ^ k_g ) e (D ^ r_g ), em comparação com isso. Se a porta for uma conjunção, então a saída da porta pode computar mais entradas de T0 corretamente (mas as entradas corretamente computadas de T1 são possivelmente diminuídas). Para (C ^ k_g ), que é definido como uma conjunção simples, não há novos erros, entretanto, em todas essas entradas. Agora, (D ^ r_g ) é definido como uma opção CNF / DNF de (C ^ k_g ), portanto, pode haver uma série de novos erros em T0, vindos dessa opção. Também em T1, não há novos erros em (C ^ k_g ) - cada erro deve estar presente em qualquer uma das entradas de porta e, da mesma forma, em (D ^ r_g ), o switch não introduz novos erros em T1. A análise da porta OR é dupla.

Portanto, o número de erros para os aproximadores finais é limitado pelo número de portas em ( beta ), vezes o número máximo possível de erros introduzidos por uma chave CNF / DNF (para T0), ou por uma chave DNF / CNF ( para T1). Mas o número total de erros tem que ser "grande" em pelo menos um caso (T0 ou T1), uma vez que esta é uma propriedade das formas normais conjuntivas positivas com cláusulas delimitadas por (k ), que foi o principal insight de Razborov prova original (Lema 5 no artigo de Blum).

Então, o que Blum fez para lidar com negações (que são empurradas para o nível de entradas, de modo que o circuito ( beta ) ainda contém apenas portas binárias OR / AND)?

Sua ideia é realizar chaves CNF / DNF e DNF / CNF de forma restrita, apenas quando todas as variáveis ​​são positivas. Então os interruptores funcionariam EXATAMENTE como no caso de Berg e Ulfberg, introduzindo a mesma quantidade de erros. Acontece que este é o único caso que precisa ser considerado.

Portanto, ele segue as linhas de Berg e Ulfberg, com algumas distinções. Em vez de anexar (CNF (g) ), (DNF (g) ), (C ^ k_g ) e (D ^ r_g ) a cada porta (g ) do circuito ( beta ), ele anexa suas modificações, (CNF & # 39 (g) ), (DNF & # 39 (g) ), (^ k_g ) e (^ r_g ), ou seja, as formas normais disjuntivas e conjuntivas "reduzidas", que ele definiu como diferindo de (CNF (g) ) e (DNF (g) ) pela "regra de absorção", removendo variáveis ​​negadas de todos monômios / orações mistos (ele também usa para este propósito a operação denotada por R, removendo alguns monômios / orações inteiramente como discutimos antes, sua definição um tanto informal de R não é realmente o problema, R pode ser tornado preciso para que seja aplicado a cada porta, mas o que é removido depende não apenas das duas entradas anteriores, mas de todo o circuito que conduz a essa porta), e seus aproximadores (^ r_g ) e (^ r_g ), que ele também apresentou.

Ele conclui, no Teorema 5, que para uma função monótona, reduzida (CNF & # 39 ) e (DNF & # 39 ) irá realmente calcular 1 e 0 nos conjuntos T1 e T0, no nó raiz (g_0 ) ( cuja saída é a saída de toda a função em ( beta )). Este teorema está, acredito, correto.

Agora vem a contagem de erros. Eu acredito que os erros em cada nó devem ser calculados comparando reduzido (CNF & # 39 (g) ) e (DNF & # 39 (g) ) (que agora são possivelmente duas funções diferentes), para (^ r_g ) e (^ k_g ) como ele os definiu. As definições dos aproximadores reproduzem as definições de (CNF & # 39 ) e (DNF & # 39 ) (Etapa 1) ao misturar variáveis ​​com as negadas, mas quando ele lida com variáveis ​​positivas, ele usa a chave como no caso de Berg e Ulfberg (Etapa 2). E, de fato, na Etapa 2, ele introduzirá o mesmo número de erros possíveis de antes (é a mesma chave, e todas as variáveis ​​envolvidas são positivas).

Mas a prova está errada no Passo 1. Acho que Blum está confundindo ( gamma_1 ), ( gamma_2 ), o que realmente vem, como ele os definiu, de aproximadores anteriores (para portas (h_1 ), (h_2 )), com partes positivas de (CNF & # 39_ beta (h_1) ) e (CNF & # 39_ beta (h_2) ). Há uma diferença e, portanto, a declaração “ (C_g & # 39 ) ainda contém todas as cláusulas contidas em (CNF & # 39_ beta (g) ) antes da aproximação da porta g que usa uma cláusula em ( gamma_1 & # 39 ) ou ( gamma_2 & # 39 ) ”parece estar errado em geral.

Resposta 2 (pontuação 95)

Estou familiarizado com Alexander Razborov, cujo trabalho anterior é extremamente crucial e serve como base para a prova de Blum. Tive a sorte de conhecê-lo hoje e não perdi tempo em pedir sua opinião sobre todo este assunto, se ele tinha visto a prova ou não e o que pensa disso se viu.

Para minha surpresa, ele respondeu que realmente estava ciente do artigo de Blum, mas não se importou em lê-lo inicialmente. Mas à medida que mais fama era dada a ele, ele teve a chance de lê-lo e detectou uma falha imediatamente: a saber, que os raciocínios dados por Berg e Ulfberg são perfeitamente válidos para a função de Tardos e, uma vez que é assim, a prova de Blum é necessariamente incorreta, pois contradiz o núcleo do Teorema 6 em seu artigo.

Resposta 3 (pontuação 41)

Esta é uma resposta da comunidade postada porque (a) não são minhas próprias palavras, mas uma citação de Luca Trevisan em uma plataforma de mídia social ou de outras pessoas sem conta CSTheory.SE e (b) qualquer pessoa deve se sentir à vontade para atualizar , informação relevante.

Citando Luca Trevisan em uma postagem pública no Facebook (14/08/2017), respondendo a uma pergunta sobre este artigo feita por Shachar Lovett:

Na verdade, este não é necessariamente um ponto em que a prova falha Luca então respondeu o seguinte (15/08/2017), após uma pergunta relacionada ao comentário de Andrew abaixo:

Karl Wimmer comentou sobre o ponto levantado por Gustav Nordh (reproduzido com a permissão de Karl):

Para adicionar a isso, não vejo porque, a partir dos dois primeiros parágrafos da prova do Teorema 5, podemos concluir que ( mathrm(g_0) ) calcula (f ). Eu vejo apenas algum tipo de unilateralidade que ( mathrm(g_0) ) calcula uma função tal que (f = 1 ) implica que esta função também é 1.

O terceiro parágrafo também não me ajuda: com certeza ( mathrm(g_0) ) e sua chave DNF / CNF computam a mesma função, mas não segue imediatamente que a chave DNF / CNF calcula (f ) (porque ( mathrm(g_0) ) pode não), então não podemos tirar conclusões sobre (f ) -cláusulas.

(À parte: essa unilateralidade é consistente com o exemplo de Gustav acima.)

De um ponto de vista diferente, certamente uma rede padrão computando uma função monótona poderia computar funções não monótonas em nós internos. O Teorema 5 não se aplica a funções não monótonas, então ( mathrm(g) ) pode não computar corretamente a subfunção na rede cujo nó de saída é (g ) (o que acontecerá para muitas funções não monótonas). Por causa disso, não estou convencido de que esta construção indutiva de ( mathrm(g_0) ) será necessariamente correto no final.

Se eu estiver totalmente enganado aqui, por favor, me avise!

De um usuário anônimo, em reação ao ponto de Karl:

E a resposta de Karl (que reproduzo novamente aqui):

Eu vejo o que anon está dizendo (obrigado!) Meu comentário não resolveu adequadamente minha confusão. Se (f ) é monótono e calculado em (g_0 ), é bom tomar ( mathrm(g_0) ), aplique absorção e o operador (R ), e o resultado ( mathrm(g_0) ) representa (f ). Usando esta construção "one-shot", o Teorema 5 está bem - no Teorema 6. Eu encostei esta definição de ( mathrm(g_0) )

O que eu não consigo ver é por que a construção de aplicação de absorção e (R ) à medida que você avança, portão por portão, de ( mathrm(g_0) ) nas páginas 27-28 faz a mesma coisa. Isso parece necessário para que a análise porta a porta do Teorema 6 funcione, a menos que o erro dessa construção seja considerado. Quer dizer, nem toda função pode ser representada por um DNF com termos apenas com literais não negados ou negados, mas para cada nó (g ), ( mathrm(g) ) parece sempre ter esta forma. E se houver um nó (g ) na minha rede tal que ( mathrm(g) ) não tem tal representação?

(Outro pequeno (?) Ponto: não vejo o que (R ) faz na construção porta a porta conforme você avança em 1.-4., Parece que ( alpha ) é já a construção DNF padrão, mas com absorção e (R ) aplicada.)

(resposta de anon) Concordo que a imprecisão na definição de R pode ser um problema na seção 6. R não é explicitamente definido e a menos que sua ação dependa de alguma forma de todo o DNF (e não dos valores de DNF 'nos portões indutivamente) , pode haver um problema. A prova de Deolalikar teve problema semelhante - duas definições diferentes foram confundidas. Aqui, pelo menos sabemos o que significa DNF ', e se esta é a origem do problema na seção 6, pode ser fácil de rastrear. Eu não entrei na seção 6 ainda, ela requer a compreensão da prova por aproximadores de Berg e Ulfberg descritos na seção 4, em última análise relacionados à construção de Razborov de 1985, o que não é fácil.

Quando R é aplicado em alguma etapa, ele apenas cancela os termos que, NESSE PASSO, conteriam literais opostos (podemos precisar rastrear literais negativos). Por exemplo, vamos avaliar [(x lor y) land ( lnot x lor y) land (x lor lnot y) ] como [((x lor y) land ( lnot x lor y)) land (x lor lnot y) ] primeiro, para calcular DNF 'no primeiro nó AND, obtemos [(x lor y) lor ((x land y) lor (y land y)) ] antes de aplicar R, mas depois de aplicar R perdemos o primeiro (x ) do primeiro colchete e obtemos [(y) lor (x land y) lor (y ), ] (onde o primeiro (y ) pode ter NOT (x ) virtual se o estivéssemos rastreando). Em seguida, aplique o segundo AND para obter [((y) lor (x land y) lor (y)) lor ((x land y) lor (x land y) lor (x land y)), ] mas então R remove todo o primeiro colchete porque tem NÃO y virtual presente (neste caso, não precisamos acompanhar as etapas anteriores, mas talvez precisemos em geral), deixando [ ((x land y) lor (x land y) lor (x land y)) ] ou simplesmente [(x land y) ]

4: O que há de novo em estruturas de dados puramente funcionais desde Okasaki? (pontuação 115419 pol.)

Pergunta

Desde o livro de 1998 de Chris Okasaki "Estruturas de dados puramente funcionais", eu não vi muitas novas estruturas de dados puramente funcionais interessantes aparecerem, posso citar apenas algumas:

  • IntMap (também inventado por Okasaki em 1998, mas não presente naquele livro)
  • Árvores de dedos (e sua generalização sobre os monoides)

Existem também algumas maneiras interessantes de implementar estruturas de dados já conhecidas, como o uso de “tipos aninhados” ou “tipos de dados algébricos generalizados” para garantir invariantes de árvore.

Que outras novas ideias surgiram desde 1998 nesta área?

Resposta aceita (pontuação 553)

Novas estruturas de dados puramente funcionais publicadas desde 1998:

2001: Ideal Hash Trees e seu predecessor de 2000, Fast And Space Efficient Trie Searches, de Phil Bagwell: Aparentemente usado como um bloco de construção fundamental na biblioteca padrão de Clojure.

2001: Uma técnica de implementação simples para filas de pesquisa prioritária, por Ralf Hinze: uma técnica realmente simples e bonita para implementar esta importante estrutura de dados (útil, digamos, no algoritmo de Dijkstra). A implementação é particularmente bonita e legível devido ao uso intenso de “padrões de visualização”.

2002: Inicializando matrizes flexíveis unilaterais, por Ralf Hinze: Semelhante às listas de acesso aleatório de Okasaki, mas elas podem ser ajustadas para alterar a troca de tempo entre contras e indexação.

2003: Novos deques catenáveis ​​e não catenáveis, de Radu Mihaescu e Robert Tarjan: Uma nova abordagem sobre alguns trabalhos mais antigos (por Kaplan e Tarjan) que Okasaki cita (a versão mais recente do trabalho de Kaplan e Tarjan foi publicada em 2000). Esta versão é mais simples em alguns aspectos.

2005: Montes maxifóbicos (papel e código), por Chris Okasaki: Apresentado não como uma estrutura nova e mais eficiente, mas como uma forma de ensinar filas prioritárias.

2006: Listas Classificadas Catenáveis ​​de Tempo Constante Puramente Funcional do Pior Caso, por Gerth Stølting Brodal, Christos Makris e Kostas Tsichlas: Responde a uma questão pendente de Kaplan e Tarjan demonstrando uma estrutura com O (lg n) inserir, pesquisar e excluir e O (1) concat.

2008: Confluently Persistent Tries for Efficient Version Control, de Erik D. Demaine, Stefan Langerman e Eric Price: Apresenta várias estruturas de dados para tentativas que possuem navegação e modificação eficientes perto das folhas. Alguns são puramente funcionais. Outros, na verdade, melhoram uma estrutura de dados de longa data de Dietz et al. para matrizes totalmente persistentes (mas não confluentemente persistentes ou puramente funcionais). Este artigo também apresenta árvores de corte de link puramente funcionais, às vezes chamadas de “árvores dinâmicas”.

2010: Um novo algoritmo de exclusão puramente funcional para árvores vermelhas e pretas, de Matt Might: Como o algoritmo de inserção de árvore vermelho-preto de Okasaki, esta não é uma nova estrutura de dados ou uma nova operação em uma estrutura de dados, mas uma maneira nova e mais simples de escrever uma operação conhecida.

2012: RRB-Trees: Efficient Immutable Vectors, de Phil Bagwell e Tiark Rompf: Uma extensão para Hash Array Mapped Tries, suportando concatenação de vetor imutável, inserção em e divisão em tempo O (lg n), enquanto mantém o índice, atualização e velocidades de inserção do vetor imutável original.

Conhecido em 1997, mas não discutido no livro de Okasaki:

Muitos outros estilos de árvore de pesquisa equilibrada. AVL, brother, rank-balance, bounded-balance e muitas outras árvores de busca balanceadas podem ser (e têm sido) implementadas de forma puramente funcional por cópia de caminhos. Talvez merecedores de menção especial são:

  • Árvores de pesquisa tendenciosas, de Samuel W. Bent, Daniel D. Sleator e Robert E. Tarjan: Um elemento chave no artigo de 2006 de Brodal et al. E no artigo de 2008 de Demaine et al.

Conjuntos infinitos que admitem uma busca rápida e exaustiva, de Martín Escardó: Talvez não seja uma estrutura de dados per se.

Três algoritmos em árvores Braun, por Chris Okasaki: As árvores Braun oferecem muitas operações de pilha no pior caso O (lg n). Este limite é ultrapassado por muitas outras estruturas de dados, mas as árvores Braun têm uma operação contrária preguiçosa em seu segundo argumento e, portanto, podem ser usadas como pilhas infinitas de algumas maneiras que outras estruturas não podem.

O heap mínimo-máximo relaxado: uma fila de prioridade dupla finalizável e o heap KD: uma fila de prioridade multidimensional eficiente, de Yuzheng Ding e Mark Allen Weiss: Acontece que são puramente funcionais, embora isso não seja discutido nos documentos. Não acho que os limites de tempo alcançados sejam melhores do que aqueles que podem ser alcançados usando árvores de dedo (de Hinze & amp Paterson ou Kaplan & amp Tarjan) como filas de prioridade k-dimensional, mas acho que as estruturas de Ding & amp Weiss usam menos espaço .

O Zíper, de Gérard Huet: Usado em muitas outras estruturas de dados (como árvores de dedo de Hinze & amp Paterson), esta é uma maneira de transformar uma estrutura de dados do avesso.

Listas de diferenças são O (1) listas catenáveis ​​com uma transformação O (n) em listas contras usuais. Aparentemente, eles são conhecidos desde a antiguidade na comunidade Prolog, onde têm uma transformação O (1) em listas cons usuais. A transformação O (1) parece ser impossível na programação funcional tradicional, mas a abstração de buraco de Minamide, do POPL '98, discute uma maneira de permitir o acréscimo de O (1) e a transformação de O (1) dentro da programação funcional pura. Ao contrário das implementações de programação funcional usuais de listas de diferenças, que são baseadas em fechamentos de funções, as abstrações de buraco são essencialmente as mesmas (tanto em seu uso quanto em sua implementação) que as listas de diferenças Prolog. No entanto, parece que por anos a única pessoa que percebeu isso foi um dos revisores do Minamide.

Dicionários representados exclusivamente suporta inserção, atualização e pesquisa com a restrição de que duas estruturas contendo os mesmos elementos não podem ter formas distintas. Para dar um exemplo, as listas classificadas com links simples são representadas de forma única, mas as árvores AVL tradicionais não. As tentativas também são representadas de forma única. Tarjan e Sundar, em “Representações de árvore de pesquisa binária única e teste de igualdade de conjuntos e sequências”, mostraram um dicionário representado de forma única e puramente funcional que suporta pesquisas em tempo logarítmico e atualizações em (O ( sqrt)) Tempo. No entanto, ele usa espaço ( Theta (n lg n) ). Existe uma representação simples usando árvores Braun que usa apenas espaço linear mas tem tempo de atualização de ( Theta ( sqrt) ) e tempo de pesquisa de ( Theta ( lg ^ 2 n) )

Principalmente estruturas de dados funcionais, antes, durante e depois do livro de Okasaki:

Muitos procedimentos para tornar as estruturas de dados persistentes, totalmente persistentes ou confluentemente persistentes: Haim Kaplan escreveu uma excelente pesquisa sobre o assunto. Veja também acima o trabalho de Demaine et al., Que demonstra uma matriz totalmente persistente no espaço (O (m) ) (onde (m ) é o número de operações já realizadas na matriz) e (O ( lg lg n) ) tempo de acesso esperado.

1989: Árvores de busca aleatória por Cecilia R. Aragon e Raimund Seidel: Estes foram discutidos em um ambiente puramente funcional por Guy E. Blelloch e Margaret Reid-Miller em Fast Set Operations Using Treaps e por Dan Blandford e Guy Blelloch em Functional Set Operations with Treaps (código). Eles fornecem todas as operações de árvores de dedo puramente funcionais e árvores de pesquisa tendenciosas, mas exigem uma fonte de aleatoriedade, o que as torna não puramente funcionais. Isso também pode invalidar a complexidade do tempo das operações em treaps, assumindo um adversário que pode cronometrar as operações e repetir as longas. (Esta é a mesma razão pela qual os argumentos de amortização imperativa não são válidos em uma configuração persistente, mas requer um adversário com um cronômetro)

1997: Skip-trees, uma estrutura de dados alternativa para Skip-lists em uma abordagem simultânea, de Xavier Messeguer e Exploring the Duality Between Skip Lists e Binary Search Trees, de Brian C. Dean e Zachary H. Jones: Listas de salto não são puramente funcionais, mas podem ser implementadas funcionalmente como árvores. Como treaps, eles exigem uma fonte de bits aleatórios. (É possível ignorar listas determinísticas, mas, depois de traduzi-las para uma árvore, acho que são apenas outra maneira de ver 2 a 3 árvores.)

1998: Todas as estruturas amortizadas no livro de Okasaki! Okasaki inventou esse novo método para misturar amortização e estruturas de dados funcionais, que antes eram consideradas incompatíveis. Depende da memoização, que, como Kaplan e Tarjan mencionaram algumas vezes, é na verdade um efeito colateral. Em alguns casos (como PFDS em SSDs por motivos de desempenho), isso pode ser inadequado.

1998: Simple Confluently Persistent Catenable Lists, de Haim Kaplan, Chris Okasaki e Robert E. Tarjan: Usa modificação sob o capô para fornecer deques catenáveis ​​O (1) amortizados, apresentando a mesma interface de uma versão anterior (puramente funcional, mas com memoização) que aparece no livro de Okasaki. Kaplan e Tarjan haviam criado anteriormente uma estrutura de pior caso O (1) puramente funcional, mas é substancialmente mais complicada.

2007: Como mencionado em outra resposta nesta página, estruturas de dados semi-persistentes e união persistente-find de Sylvain Conchon e Jean-Christophe Filliâtre

Técnicas para verificar estruturas de dados funcionais, antes, durante e depois do livro de Okasaki:

Tipos fantasmas são um método antigo para criar uma API que não permite certas operações malformadas. Um uso sofisticado deles pode ser encontrado nos recursos estáticos leves de Oleg Kiselyov e Chung-chieh Shan.

Tipos aninhados na verdade, não são mais recentes do que 1998 - Okasaki até os usa em seu livro. Existem muitos outros exemplos que não estão no livro de Okasaki, alguns são novos e alguns são antigos. Eles incluem:

  • Árvores vermelho-pretas de Stefan Kahrs com tipos (código)
  • Árvores AVL de Ross Paterson (espelho)
  • Da exponenciação rápida às matrizes quadradas de Chris Okasaki: uma aventura em tipos
  • A notação de Bruijn de Richard S. Bird e Ross Peterson como um tipo de dados aninhado
  • Representações numéricas de Ralf Hinze como tipos de dados aninhados de ordem superior.

GADTs não são tão novos assim. Eles são uma adição recente a Haskell e alguns MLs, mas eles estão presentes, eu acho, em vários cálculos lambda digitados desde os anos 1970.

2004-2010: Coq e Isabelle pela correção. Várias pessoas usaram provadores de teoremas para verificar a exatidão de estruturas de dados puramente funcionais. Coq pode extrair essas verificações para o código de trabalho em Haskell, OCaml e Scheme Isabelle pode extrair para Haskell, ML e OCaml.

  • Tobias Nipkow e Cornelia Pusch formalizaram árvores AVL.
  • Viktor Kuncak formalizou árvores de busca binárias não balanceadas.
  • Peter Lammich publicou o framework Isabelle Collections, que inclui formalizações de estruturas de dados puramente funcionais eficientes como árvores vermelhas e pretas e tentativas, bem como estruturas de dados que são menos eficientes quando usadas persistentemente, como duas pilhas de filas (sem o truque da preguiça de Okasaki ) e tabelas de hash.
  • Peter Lammich também publicou formalizações de autômatos de árvore, árvores de dedo de Hinze & amp Patterson (com Benedikt Nordhoff e Stefan Körner) e filas de prioridade puramente funcionais de Brodal e Okasaki (com Rene Meis e Finn Nielsen).
  • René Neumann formalizou filas de prioridade binomial.

2007: Refined Typechecking with Stardust, de Joshua Dunfield: Este artigo usa tipos de refinamento para ML para encontrar erros na função de exclusão de árvore vermelho-preto do SMLNJ.

2008: Análise de complexidade de tempo semiformal leve para estruturas de dados puramente funcionais por Nils Anders Danielsson: Usa Agda com anotação manual para provar limites de tempo para alguns PFDS.

Estruturas de dados imperativas ou análises não discutidas no livro de Okasaki, mas relacionadas a estruturas de dados puramente funcionais:

The Soft Heap: Uma fila de prioridade aproximada com taxa de erro ideal, por Bernard Chazelle: Esta estrutura de dados não usa matrizes e, portanto, tentou primeiro o canal de IRC #haskell e depois os usuários do Stack Overflow, mas inclui exclusão em o (lg n), o que geralmente não é possível em um ambiente funcional, e análise amortizada imperativa , o que não é válido em um ambiente puramente funcional.

Árvores de pesquisa binárias balanceadas com atualizações O (1) dedo. Em Tornando as Estruturas de Dados Persistentes, James R Driscoll, Neil Sarnak, Daniel D. Sleator e Robert E. Tarjan apresentam um método para agrupar os nós em uma árvore vermelha e preta de forma que atualizações persistentes requeiram apenas espaço O (1). Os deques e árvores de dedo puramente funcionais projetados por Tarjan, Kaplan e Mihaescu usam uma técnica de agrupamento muito semelhante para permitir atualizações O (1) em ambas as extremidades. Árvores AVL para pesquisa localizada por Athanasios K. Tsakalidis funcionam de forma semelhante.

Montes de emparelhamento mais rápidos ou melhores limites para montes de emparelhamento: Desde que o livro de Okasaki foi publicado, várias novas análises de heaps de emparelhamento imperativo apareceram, incluindo heaps de emparelhamento com custo de redução de O (log log n) por Amr Elmasry e Rumo a uma análise final de heaps de emparelhamento por Seth Pettie. Pode ser possível aplicar parte desse trabalho aos lotes preguiçosos de emparelhamento de Okasaki.

Árvores de dedo enviesadas determinísticas: Em Listas de ignorar enviesadas, de Amitabha Bagchi, Adam L. Buchsbaum e Michael T. Goodrich, um projeto é apresentado para listas de ignorar enviesadas determinísticas. Por meio da transformação de lista / árvore de ignorar mencionada acima, pode ser possível fazer árvores de pesquisa enviesadas determinísticas. As listas de omissão tendenciosa descritas por John Iacono e Özgür Özkan em Dicionários intercaláveis ​​podem então ser possíveis em árvores de omissão tendenciosa. Uma árvore de dedo tendenciosa é sugerida por Demaine et al. em seu artigo sobre tentativas puramente funcionais (veja acima) como uma forma de reduzir os limites de tempo e espaço na atualização do dedo nas tentativas.

The String B-Tree: Uma Nova Estrutura de Dados para Pesquisa de String em Memória Externa e suas Aplicações por Paolo Ferragina e Roberto Grossi é uma estrutura de dados bem estudada combinando os benefícios de try e B-trees.

Resposta 2 (pontuação 63)

Às excelentes notas já feitas, acrescentarei Zíperes.

Huet, Gerard. “Functional Pearl: The Zipper” Journal of Functional Programming 7 (5): 549-554, setembro de 1997.


O micróbio numérico e o castor ocupado

Este é outro post com um nome estranho, mas contente depois deste. Durante uma tentativa de me lançar em explicações em vídeo, fiz um post sobre o micróbio numérico.

O micróbio numérico é a versão chemlambda de uma multiplicação de dois números de Igreja, neste caso 5X5 = 25. Chamei a criatura que evolui no vídeo de & # 8220 micróbio numérico & # 8221 porque ela realmente consome cópias do número 5, metaboliza-as e acaba produzindo 25. De uma forma muito cuidadosa, no entanto, o que me inspirou a seguinte descrição (mas você tem para ver o vídeo dessa postagem):

& # 8220O micróbio numérico adora os números da Igreja. Sua estratégia é esta: nunca um sem o outro. Quando ele encontra um número da Igreja, ele procura o segundo. Então ele acorrenta o primeiro ao segundo e só depois começa a mastigar lentamente a cabeça do primeiro. Enquanto isso, o segundo número da Igreja observa o infeliz primeiro número da Igreja entrando, átomo por átomo, na boca numérica.

Apenas o último número da Igreja sobreviveu, na forma da cauda do numerador. & # 8221

O arquivo mol usado é times_only.mol. Sim, tudo bem, é a versão mol do AST de um termo lambda.

Você pode ver o número-phile também nesta animação, junto com uma máquina de Turing de castor ocupada (a versão chemlambda explicada aqui):

Na primeira metade da animação, você vê o & # 8220numberphile & # 8221 à esquerda e o castor ocupado como um loop avermelhado à direita.

O que acontece é que o termo lambda como 5X5 reduz para 25, enquanto ao mesmo tempo a máquina de castores ocupada também funciona. Ao mesmo tempo, a Igreja número 25 em formação já faz com que o pequeno laço se replique e cresça cada vez mais, eventualmente 25 vezes maior.

Isso explica o título.

O arquivo mol usado é times_only_bb.mol. Abra-o e veja como é diferente do primeiro.

Você pode ver uma simulação (js) do número da Igreja aplicada a um castor ocupado aqui.

E o mais importante é: durante a realização deste curta-metragem, nenhum diretor humano esteve presente para encenar o ato.


Um algoritmo de aprendizagem para máquinas Boltzmann *

A pesquisa relatada aqui foi apoiada por doações da System Development Foundation. Agradecemos a Peter Brown, Francis Crick, Mark Derthick, Scott Fahlman, Jerry Feldman, Stuart Geman, Gail Gong, John Hopfield, Jay McClelland, Barak Pearlmutter, Harry Printz, Dave Rumelhart, Timubra Shallice, Paul Smolensky, Rick Szeliski e Venkataraman Venkatasmanian para discussões úteis.

Resumo

O poder computacional de redes massivamente paralelas de elementos de processamento simples reside na largura de banda de comunicação fornecida pelas conexões de hardware entre os elementos. Essas conexões podem permitir que uma fração significativa do conhecimento do sistema seja aplicada a uma instância de um problema em um tempo muito curto. Um tipo de cálculo para o qual redes massivamente paralelas parecem ser bem adequadas são as pesquisas de satisfação de grandes restrições, mas para usar as conexões de forma eficiente duas condições devem ser atendidas: primeiro, uma técnica de pesquisa que seja adequada para redes paralelas deve ser encontrada. Em segundo lugar, deve haver alguma maneira de escolher representações internas que permitam que as conexões de hardware preexistentes sejam usadas de forma eficiente para codificar as restrições no domínio que está sendo pesquisado. Descrevemos um método geral de busca paralela, baseado em mecânica estatística, e mostramos como ele conduz a uma regra geral de aprendizado para modificar as forças de conexão de forma a incorporar o conhecimento sobre um domínio de tarefa de forma eficiente. Descrevemos alguns exemplos simples nos quais o algoritmo de aprendizagem cria representações internas que são comprovadamente a maneira mais eficiente de usar a estrutura de conectividade preexistente.


ArXiv é 3 vezes maior do que todos os megajournals juntos

Para ter uma comparação clara, vou olhar para a janela 2010-2014.

Antes de mostrar os números, há algumas coisas a acrescentar.

1. Eu vi o artigo [1] através da postagem de + Mike Taylor

Convido você a lê-lo, é interessante como sempre.

Essas discussões me fizeram perceber que o modelo arXiv é cuidadosamente retirado da realidade pelos criadores e principais apoiadores do OA verde e OA dourado.

De [1], o número total de artigos por ano para & # 8220megajournals & # 8221 é

2010: 6,913
2011: 14,521
2012: 25,923
2013: 37,525
2014: 37,794
2015: 33,872

(para 2015, o número representa & # 8220 os artigos publicados no primeiro trimestre do ano multiplicados por quatro & # 8221 [1])

ArXiv: (com base na contagem dos envios mensais listados em [2])

2010: 70,131
2011: 76,578
2012: 84,603
2013: 92,641
2014: 97,517
2015: 100.628 (pelo mesmo procedimento de [1])

Isto mostra que arXiv é 3 vezes maior do que todos os megajournals de uma vez, Apesar disso:
& # 8211 não é um editor
& # 8211 não pede APC
& # 8211 cobre campos muito menos atraentes e prolíficos do que os megajournals.

E isso porque:
& # 8211 arxiv atende a uma demanda real dos pesquisadores, de comunicar de forma rápida e confiável seu trabalho aos seus companheiros, de forma que respeite sua autoria
& # 8211 também uma reação de apoio ao que a maioria deles pensa ser & # 8220green OA & # 8221, ou seja, colocar seu trabalho ali onde está longe das fechaduras dos editores.


Computer_science_theory & lt- StackExchange principais 100

Para demonstrar a importância dos algoritmos (por exemplo, para alunos e professores que não fazem teoria ou até mesmo de áreas totalmente diferentes), às vezes é útil ter em mãos uma lista de exemplos onde algoritmos centrais foram implantados em áreas comerciais, governamentais, ou software / hardware amplamente utilizado.

Estou procurando exemplos que satisfaçam os seguintes critérios:

O software / hardware que usa o algoritmo deve ser amplamente utilizado agora.

O exemplo deve ser específico. Por favor, dê uma referência a um sistema específico e um algoritmo específico.
Por exemplo, em “o algoritmo X é útil para processamento de imagem”, o termo “processamento de imagem” não é específico o suficiente. Em “A pesquisa do Google usa algoritmos de gráfico”, o termo “algoritmos de gráfico” não é específico o suficiente.

O algoritmo deve ser ensinado em cursos de graduação ou doutorado típicos. classes em algoritmos ou estruturas de dados. Idealmente, o algoritmo é abordado em livros didáticos de algoritmos típicos. Por exemplo, “sistema X bem conhecido usa algoritmo Y pouco conhecido” não é bom.

Atualizar:

Obrigado novamente pelas ótimas respostas e links! Algumas pessoas comentam que é difícil satisfazer os critérios porque os algoritmos principais são tão difundidos que é difícil apontar para um uso específico. Eu vejo a dificuldade. Mas acho que vale a pena citar exemplos específicos porque, em minha experiência, digo às pessoas: “Veja, algoritmos são importantes porque são quase em todo lugar! ” não funciona.

Resposta aceita (pontuação 473)

Os algoritmos que são o principal condutor de um sistema são, na minha opinião, mais fáceis de encontrar em cursos sem algoritmos pela mesma razão que os teoremas com aplicações imediatas são mais fáceis de encontrar em matemática aplicada do que em cursos de matemática pura. É raro que um problema prático tenha a estrutura exata do problema abstrato em uma aula. Para ser argumentativo, não vejo razão para que o material do curso de algoritmos da moda, como a multiplicação de Strassen, o teste de primalidade AKS ou o algoritmo Moser-Tardos seja relevante para problemas práticos de baixo nível de implementação de um banco de dados de vídeo, um compilador de otimização, um sistema operacional , um sistema de controle de congestionamento de rede ou qualquer outro sistema. O valor desses cursos é aprender que existem maneiras intrincadas de explorar a estrutura de um problema para encontrar soluções eficientes. Algoritmos avançados também é onde encontramos algoritmos simples, cuja análise não é trivial. Por esse motivo, eu não descartaria algoritmos aleatórios simples ou PageRank.

Acho que você pode escolher qualquer software grande e encontrar algoritmos básicos e avançados implementados nele. Como um estudo de caso, fiz isso para o kernel Linux e mostrei alguns exemplos do Chromium.

Estruturas de dados e algoritmos básicos no kernel Linux

Árvores B + com comentários dizendo o que você não consegue encontrar nos livros didáticos.

Uma implementação B + Tree relativamente simples. Eu o escrevi como um exercício de aprendizado para entender como as árvores B + funcionam. Acabou sendo útil também.

Foi usado um truque que não é comumente encontrado em livros didáticos. Os valores mais baixos estão à direita, não à esquerda. Todos os slots usados ​​em um nó estão à esquerda, todos os slots não usados ​​contêm valores NUL. A maioria das operações simplesmente executa um loop em todos os slots e termina no primeiro NUL.

As árvores Radix são usadas para gerenciamento de memória, pesquisas relacionadas a NFS e funcionalidade relacionada à rede.

Heap de prioridade, que é literalmente uma implementação de livro didático, usada no sistema de grupo de controle.

Funções de hash, com referência a Knuth e a um artigo.

Knuth recomenda números primos em aproximadamente a proporção áurea para o número inteiro máximo representável por uma palavra de máquina para hash multiplicativo. Chuck Lever verificou a eficácia desta técnica:

http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf

Esses primos são escolhidos para serem esparsos em bits, ou seja, as operações neles podem usar deslocamentos e adições em vez de multiplicações para máquinas onde as multiplicações são lentas.

Algumas partes do código, como este driver, implementam sua própria função hash.

função hash usando um algoritmo de Hash rotativo

Knuth, D. The Art of Computer Programming, Volume 3: Sorting and Searching, Capítulo 6.4. Addison Wesley, 1973

Matrizes de bits, que são usadas para lidar com sinalizadores, interrupções, etc. e são apresentadas em Knuth Vol. 4

Executa uma caminhada de profundidade modificada da árvore do namespace, começando (e terminando) no nó especificado por start_handle. A função de retorno de chamada é chamada sempre que um nó que corresponde ao parâmetro de tipo é encontrado. Se a função de retorno de chamada retornar um valor diferente de zero, a pesquisa será encerrada imediatamente e esse valor será retornado ao chamador.

A primeira pesquisa de amplitude é usada para verificar a exatidão do bloqueio em tempo de execução.

O Bubble Sort também é incrivelmente implementado em uma biblioteca de drivers.

Implementa um algoritmo de correspondência de strings de tempo linear devido a Knuth, Morris e Pratt [1]. Seu algoritmo evita o cálculo explícito da função de transição DELTA completamente. Seu tempo de correspondência é O (n), para n ser comprimento (texto), usando apenas uma função auxiliar PI [1..m], para m ser comprimento (padrão), pré-calculado do padrão no tempo O (m). O array PI permite que a função de transição DELTA seja calculada de forma eficiente “em tempo real” conforme necessário. Grosso modo, para qualquer estado “q” = 0,1,…, me qualquer caractere “a” no SIGMA, o valor PI [“q”] contém a informação que é independente de “a” e é necessária para calcular DELTA (“Q”, “a”) 2. Como o array PI tem apenas m entradas, enquanto DELTA tem O (m | SIGMA |) entradas, salvamos um fator de | SIGMA | no tempo de pré-processamento, computando PI em vez de DELTA.

[1] Cormen, Leiserson, Rivest, Stein Introdcution to Algorithms, 2ª edição, MIT Press

[2] Veja a teoria de automação finita

Correspondência de padrões de Boyer-Moore com referências e recomendações para quando preferir a alternativa.

Implementa o algoritmo de correspondência de strings de Boyer-Moore:

[1] A Fast String Searching Algorithm, R.S. Boyer e Moore. Communications of the Association for Computing Machinery, 20 (10), 1977, pp. 762-772. http://www.cs.utexas.edu/users/moore/publications/fstrpos.pdf

[2] Handbook of Exact String Matching Algorithms, Thierry Lecroq, 2004 http://www-igm.univ-mlv.fr/

lecroq / string / string.pdf

Observação: como Boyer-Moore (BM) realiza pesquisas de correspondências da direita para a esquerda, ainda é possível que uma correspondência possa ser espalhada por vários blocos, nesse caso, esse algoritmo não encontrará nenhuma coincidência.

Se você deseja garantir que isso nunca aconteça, use a implementação Knuth-Pratt-Morris (KMP). Em conclusão, escolha o algoritmo de pesquisa de string adequado, dependendo de sua configuração.

Digamos que você esteja usando a infraestrutura de pesquisa de texto para filtragem, NIDS ou
qualquer finalidade semelhante com foco na segurança, vá para KMP. Caso contrário, se você realmente se preocupa com o desempenho, digamos que você está classificando pacotes para aplicar políticas de qualidade de serviço (QoS) e não se importa com possíveis correspondências espalhadas por vários fragmentos, então vá BM.

Estruturas de dados e algoritmos no navegador da Web Chromium

Os links são para o código-fonte no código do Google. Vou apenas listar alguns. Eu sugeriria usar o recurso de pesquisa para pesquisar seu algoritmo ou estrutura de dados favorita.

Bibliotecas de linguagem de programação

Acho que vale a pena considerá-los. Os designers das linguagens de programação acharam que valeu a pena o tempo e o esforço de alguns engenheiros para implementar essas estruturas de dados e algoritmos para que outros não precisassem fazer isso. A existência de bibliotecas é parte do motivo pelo qual podemos encontrar estruturas de dados básicas reimplementadas em software escrito em C, mas nem tanto para aplicativos Java.

  1. O C ++ STL inclui listas, pilhas, filas, mapas, vetores e algoritmos para classificação, pesquisa e manipulação de heap.
  2. A API Java é muito extensa e cobre muito mais.
  3. A biblioteca Boost C ++ inclui algoritmos como algoritmos de correspondência de string de Boyer-Moore e Knuth-Morris-Pratt.
Algoritmos de alocação e programação

Acho isso interessante porque, embora sejam chamados de heurísticas, a política que você usa dita o tipo de algoritmo e estrutura de dados que são necessários, portanto, é necessário saber sobre pilhas e filas.

  1. Menos usado recentemente pode ser implementado de várias maneiras. Uma implementação baseada em lista no kernel Linux.
  2. Outras possibilidades são Primeiro a entrar, primeiro a sair, Menos usado com frequência e Round Robin.
  3. Uma variante do FIFO foi usada pelo sistema VAX / VMS.
  4. O algoritmo Clock de Richard Carr é usado para substituição de quadro de página no Linux.
  5. O processador Intel i860 usou uma política de substituição aleatória.
  6. O Adaptive Replacement Cache é usado em alguns controladores de armazenamento IBM e no PostgreSQL, embora apenas brevemente devido a questões de patentes.
  7. O algoritmo de alocação de memória Buddy, que é discutido por Knuth em TAOCP Vol. 1 é usado no kernel Linux e o alocador simultâneo jemalloc usado pelo FreeBSD e no Facebook.
Principais utilitários em sistemas * nix
  1. grep e awk ambos implementam a construção Thompson-McNaughton-Yamada de NFAs a partir de expressões regulares, o que aparentemente supera a implementação Perl.
  2. Tsort implementa classificação topológica.
  3. fgrep implementa o algoritmo de correspondência de strings Aho-Corasick.
  4. GNU grep, implementa o algoritmo Boyer-Moore de acordo com o autor Mike Haertel.
  5. crypt (1) no Unix implementou uma variante do algoritmo de criptografia na máquina Enigma.
  6. Dif Unix implementado por Doug McIllroy, baseado em um protótipo co-escrito com James Hunt, tem um desempenho melhor do que o algoritmo de programação dinâmica padrão usado para calcular distâncias de Levenshtein. A versão Linux calcula a distância de edição mais curta.
Algoritmos criptográficos

Esta pode ser uma lista muito longa. Algoritmos criptográficos são implementados em todos os softwares que podem realizar comunicações ou transações seguras.

  1. Árvores Merkle, especificamente a variante Tiger Tree Hash, foram usadas em aplicativos ponto a ponto, como GTK Gnutella e LimeWire.
  2. MD5 é usado para fornecer uma soma de verificação para pacotes de software e é usado para verificações de integridade em sistemas * nix (implementação de Linux) e também é compatível com Windows e OS X.
  3. OpenSSL implementa muitos algoritmos criptográficos, incluindo AES, Blowfish, DES, SHA-1, SHA-2, RSA, DES, etc.
Compiladores
  1. A análise LALR é implementada por yacc e bison.
  2. Os algoritmos do Dominator são usados ​​na maioria dos compiladores de otimização baseados no formulário SSA.
  3. Lex e flex compilar expressões regulares em NFAs.
Compressão e processamento de imagem
  1. Os algoritmos Lempel-Ziv para o formato de imagem GIF são implementados em programas de manipulação de imagens, a partir do utilitário * nix converter a programas complexos.
  2. A codificação de comprimento de execução é usada para gerar arquivos PCX (usados ​​pelo programa Paintbrush original), arquivos BMP compactados e arquivos TIFF.
  3. A compactação wavelet é a base do JPEG 2000, portanto, todas as câmeras digitais que produzem arquivos JPEG 2000 implementarão esse algoritmo.
  4. A correção de erros Reed-Solomon é implementada no kernel Linux, unidades de CD, leitores de código de barras e foi combinada com convolução para transmissão de imagem do Voyager.
Aprendizagem de cláusulas orientadas por conflito

Desde o ano 2000, o tempo de execução dos solucionadores SAT em benchmarks industriais (geralmente da indústria de hardware, embora outras fontes também sejam usadas) diminuiu quase exponencialmente a cada ano. Uma parte muito importante deste desenvolvimento é o Aprendizagem de cláusulas orientadas por conflito algoritmo que combina o Propagação de restrição booleana algoritmo no artigo original de Davis Logemann e Loveland com a técnica de aprendizagem de cláusula que se originou na programação de restrição e na pesquisa de inteligência artificial. Para modelagem industrial específica, o SAT é considerado um problema fácil (veja esta discussão). Para mim, esta é uma das maiores histórias de sucesso dos últimos tempos, porque combina avanços algorítmicos espalhados por vários anos, ideias de engenharia inteligentes, avaliação experimental e um esforço conjunto conjunto para resolver o problema. O artigo CACM de Malik e Zhang é uma boa leitura. Este algoritmo é ensinado em muitas universidades (participei de quatro onde era o caso), mas normalmente em uma aula de lógica ou métodos formais.

As aplicações dos solucionadores SAT são numerosas. IBM, Intel e muitas outras empresas têm suas próprias implementações de solucionador SAT. O gerenciador de pacotes no OpenSUSE também usa um solucionador SAT.

Resposta 2 (pontuação 40)

O PageRank é um dos algoritmos mais conhecidos. Desenvolvido pelo cofundador do Google Larry Page e co-autores, ele formou a base do mecanismo de pesquisa original do Google e é amplamente reconhecido por ajudá-los a obter melhores resultados de pesquisa do que seus concorrentes na época.

Imaginamos um “surfista aleatório” começando em alguma página da web e clicando repetidamente em um link aleatório para levá-lo a uma nova página. A pergunta é: “Qual fração de tempo o surfista gastará em cada página?” Quanto mais tempo o surfista passa em uma página, mais importante a página é considerada.

Mais formalmente, vemos a internet como um gráfico onde as páginas são nós e os links são arestas direcionadas. Podemos então modelar a ação do surfista como um passeio aleatório em um gráfico ou equivalentemente como uma Cadeia de Markov com matriz de transição (M ). Depois de lidar com alguns problemas para garantir que a Cadeia de Markov seja ergódica (para onde vai o surfista se uma página não tem links de saída?), Calculamos a quantidade de tempo que o surfista gasta em cada página como a distribuição de estado estacionário da Cadeia de Markov .

O algoritmo em si é, em certo sentido, trivial - nós apenas calculamos (M ^ k pi_0 ) para grande (k ) e distribuição inicial arbitrária ( pi_0 ). Isso equivale apenas a uma multiplicação repetida de matriz-matriz ou matriz-vetor. O conteúdo dos algoritmos está principalmente na configuração (garantindo a ergodicidade, provando que uma Cadeia de Markov ergódica tem uma distribuição de estado estacionário única) e na análise de convergência (dependência do gap espectral de (M )).

Resposta 3 (pontuação 33)

Eu mencionaria a implementação do software CPLEX (ou similar) amplamente utilizado do método / algoritmo Simplex para resolver problemas de programação linear. É o (?) Algoritmo mais utilizado em pesquisa econômica e operacional.

“Se alguém pegasse estatísticas sobre qual problema matemático está usando a maior parte do tempo do computador no mundo, então (sem contar os problemas de manuseio de banco de dados como classificação e busca) a resposta provavelmente seria programação linear.”(L. Lovász, Um novo algoritmo de programação linear - melhor ou pior do que o método simplex? Math. Intelligencer 2 (3) (1979/80) 141-146.)

O algoritmo Simplex também tem grande influência na teoria, ver, por exemplo, a conjectura de Hirsch (polinomial).

Eu acho que um típico estudante de graduação ou Ph.D. classe em algoritmos lida com o algoritmo Simplex (incluindo algoritmos básicos de álgebra linear como Método de Eliminação de Gauss).

(Outros algoritmos de sucesso, incluindo Quicksort para classificação, estão listados em Algoritmos do Livro.)

2: Quais jornais todos deveriam ler? (pontuação 161084 em 2017)

Pergunta

Esta pergunta é (inspirada por) / (vergonhosamente roubada de) uma pergunta semelhante no MathOverflow, mas espero que as respostas aqui sejam bem diferentes.

Todos nós temos artigos favoritos em nossas respectivas áreas de teoria.De vez em quando, encontramos um artigo tão surpreendente (por exemplo, importante, atraente, aparentemente simples, etc.) que queremos compartilhá-lo com todos. Então, liste esses papéis aqui! Eles não tenho ser da ciência da computação teórica - qualquer coisa que você ache que possa agradar à comunidade é uma boa resposta.

Você pode dar quantas respostas quiser por favor coloque um papel por resposta! Além disso, observe que este é um wiki da comunidade, então vote em tudo o que quiser!

(Observe que houve uma pergunta anterior sobre artigos em complexidade teórica de recursão, mas ela é bastante especializada.)

Resposta 2 (pontuação 164)

“Uma teoria matemática da comunicação” de Claude Shannon, clássicos da teoria da informação. Muito legível.

Resposta 3 (pontuação 145)

O artigo de 1936 que possivelmente deu início à própria ciência da computação:

  • Alan Turing, "On Computable Numbers, with an Application to the Entscheidungsproblem", Proceedings of the London Mathematical Society s2-42, 230–265, 1937. doi: 10.1112 / plms / s2-42.1.230

Em apenas 36 páginas, Turing formula (mas não nomeia) a Máquina de Turing, reformula o famoso Primeiro Teorema da Incompletude de Gödel em termos de computação, descreve o conceito de universalidade e no apêndice mostra que a computabilidade por máquinas de Turing é equivalente à computabilidade por ( lambda ) -funções definíveis (conforme estudado por Church e Kleene).

3: A prova de Norbert Blum de 2017 de que (P ne NP ) correto? (pontuação 115991 em 2017)

Pergunta

Norbert Blum postou recentemente uma prova de 38 páginas que (P ne NP ). Está correto?

Também no tópico: onde mais (na internet) sua correção está sendo discutida?

Observação: o foco deste texto da pergunta mudou ao longo do tempo. Veja os comentários das perguntas para detalhes.

Resposta aceita (pontuação 98)

Como observado aqui antes, o exemplo de Tardos refuta claramente a prova que dá uma função monótona, que concorda com CLIQUE em T0 e T1, mas que está em P. Isso não seria possível se a prova fosse correta, uma vez que a prova se aplica a este caso também. No entanto, podemos identificar o erro? Aqui está, a partir de uma postagem no blog do Lipton, o que parece ser o lugar onde a prova falha:

O único erro é um ponto sutil na prova do Teorema 6, a saber, na Etapa 1, na página 31 (e também 33, onde o caso dual é discutido) - uma afirmação aparentemente óbvia de que (C & # 39_g ) contém todas as cláusulas correspondentes contidas em (CNF & # 39 (g) ) etc, parece errado.

Para explicar isso com mais detalhes, precisamos entrar no método de prova e aproximação de Berg e Ulfberg, que reafirma a prova original de Razborov da complexidade monótona exponencial para CLIQUE em termos de switches DNF / CNF. É assim que eu vejo:

Para cada nó / porta (g ) de um circuito lógico ( beta ) (contendo apenas portas OR / AND binárias), uma forma normal conjuntiva (CNF (g) ), uma forma normal disjuntiva (DNF (g) ), e aproximadores (C ^ k_g ) e (D ^ r_g ) são anexados. (CNF ) e (DNF ) são simplesmente as formas normais disjuntivas e conjuntivas correspondentes da saída da porta. (D ^ r_g ) e (C ^ k_g ) também são formas disjuntivas e conjuntivas, mas de algumas outras funções, “aproximando-se” da saída da porta. No entanto, eles devem ter um número limitado de variáveis ​​em cada monômio para (D ^ r_g ) (menos que uma constante r) e em cada cláusula para (C ^ k_g ) (menos que uma constante k).

Há noção de um “erro” introduzida com esta aproximação. Como esse erro é calculado? Estamos interessados ​​apenas em algum conjunto T0 de entradas em que nossa função total assume valor 0, e T1 de entradas em que nossa função total assume valor 1 (uma “promessa”). Agora, em cada porta, olhamos apenas para as entradas de T0 e T1, que são calculadas corretamente (por ambos (DNF (g) ) e (CNF (g) ), que representam a mesma função - saída da porta (g ) em ( beta )) na saída do portão, e veja quantos erros / erros são para (C ^ k_g ) e (D ^ r_g ), em comparação com isso. Se a porta for uma conjunção, então a saída da porta pode computar mais entradas de T0 corretamente (mas as entradas corretamente computadas de T1 são possivelmente diminuídas). Para (C ^ k_g ), que é definido como uma conjunção simples, não há novos erros, entretanto, em todas essas entradas. Agora, (D ^ r_g ) é definido como uma opção CNF / DNF de (C ^ k_g ), portanto, pode haver uma série de novos erros em T0, vindos dessa opção. Também em T1, não há novos erros em (C ^ k_g ) - cada erro deve estar presente em qualquer uma das entradas de porta e, da mesma forma, em (D ^ r_g ), o switch não introduz novos erros em T1. A análise da porta OR é dupla.

Portanto, o número de erros para os aproximadores finais é limitado pelo número de portas em ( beta ), vezes o número máximo possível de erros introduzidos por uma chave CNF / DNF (para T0), ou por uma chave DNF / CNF ( para T1). Mas o número total de erros tem que ser "grande" em pelo menos um caso (T0 ou T1), uma vez que esta é uma propriedade das formas normais conjuntivas positivas com cláusulas delimitadas por (k ), que foi o principal insight de Razborov prova original (Lema 5 no artigo de Blum).

Então, o que Blum fez para lidar com negações (que são empurradas para o nível de entradas, de modo que o circuito ( beta ) ainda contém apenas portas binárias OR / AND)?

Sua ideia é realizar chaves CNF / DNF e DNF / CNF de forma restrita, apenas quando todas as variáveis ​​são positivas. Então os interruptores funcionariam EXATAMENTE como no caso de Berg e Ulfberg, introduzindo a mesma quantidade de erros. Acontece que este é o único caso que precisa ser considerado.

Portanto, ele segue as linhas de Berg e Ulfberg, com algumas distinções. Em vez de anexar (CNF (g) ), (DNF (g) ), (C ^ k_g ) e (D ^ r_g ) a cada porta (g ) do circuito ( beta ), ele anexa suas modificações, (CNF & # 39 (g) ), (DNF & # 39 (g) ), (^ k_g ) e (^ r_g ), ou seja, as formas normais disjuntivas e conjuntivas "reduzidas", que ele definiu como diferindo de (CNF (g) ) e (DNF (g) ) pela "regra de absorção", removendo variáveis ​​negadas de todos monômios / orações mistos (ele também usa para este propósito a operação denotada por R, removendo alguns monômios / orações inteiramente como discutimos antes, sua definição um tanto informal de R não é realmente o problema, R pode ser tornado preciso para que seja aplicado a cada porta, mas o que é removido depende não apenas das duas entradas anteriores, mas de todo o circuito que conduz a essa porta), e seus aproximadores (^ r_g ) e (^ r_g ), que ele também apresentou.

Ele conclui, no Teorema 5, que para uma função monótona, reduzida (CNF & # 39 ) e (DNF & # 39 ) irá realmente calcular 1 e 0 nos conjuntos T1 e T0, no nó raiz (g_0 ) ( cuja saída é a saída de toda a função em ( beta )). Este teorema está, acredito, correto.

Agora vem a contagem de erros. Eu acredito que os erros em cada nó devem ser calculados comparando reduzido (CNF & # 39 (g) ) e (DNF & # 39 (g) ) (que agora são possivelmente duas funções diferentes), para (^ r_g ) e (^ k_g ) como ele os definiu. As definições dos aproximadores reproduzem as definições de (CNF & # 39 ) e (DNF & # 39 ) (Etapa 1) ao misturar variáveis ​​com as negadas, mas quando ele lida com variáveis ​​positivas, ele usa a chave como no caso de Berg e Ulfberg (Etapa 2). E, de fato, na Etapa 2, ele introduzirá o mesmo número de erros possíveis de antes (é a mesma chave, e todas as variáveis ​​envolvidas são positivas).

Mas a prova está errada no Passo 1. Acho que Blum está confundindo ( gamma_1 ), ( gamma_2 ), o que realmente vem, como ele os definiu, de aproximadores anteriores (para portas (h_1 ), (h_2 )), com partes positivas de (CNF & # 39_ beta (h_1) ) e (CNF & # 39_ beta (h_2) ). Há uma diferença e, portanto, a declaração “ (C_g & # 39 ) ainda contém todas as cláusulas contidas em (CNF & # 39_ beta (g) ) antes da aproximação da porta g que usa uma cláusula em ( gamma_1 & # 39 ) ou ( gamma_2 & # 39 ) ”parece estar errado em geral.

Resposta 2 (pontuação 95)

Estou familiarizado com Alexander Razborov, cujo trabalho anterior é extremamente crucial e serve como base para a prova de Blum. Tive a sorte de conhecê-lo hoje e não perdi tempo em pedir sua opinião sobre todo este assunto, se ele tinha visto a prova ou não e o que pensa disso se viu.

Para minha surpresa, ele respondeu que realmente estava ciente do artigo de Blum, mas não se importou em lê-lo inicialmente. Mas à medida que mais fama era dada a ele, ele teve a chance de lê-lo e detectou uma falha imediatamente: a saber, que os raciocínios dados por Berg e Ulfberg são perfeitamente válidos para a função de Tardos e, uma vez que é assim, a prova de Blum é necessariamente incorreta, pois contradiz o núcleo do Teorema 6 em seu artigo.

Resposta 3 (pontuação 41)

Esta é uma resposta da comunidade postada porque (a) não são minhas próprias palavras, mas uma citação de Luca Trevisan em uma plataforma de mídia social ou de outras pessoas sem conta CSTheory.SE e (b) qualquer pessoa deve se sentir à vontade para atualizar , informação relevante.

Citando Luca Trevisan em uma postagem pública no Facebook (14/08/2017), respondendo a uma pergunta sobre este artigo feita por Shachar Lovett:

Na verdade, este não é necessariamente um ponto em que a prova falha Luca então respondeu o seguinte (15/08/2017), após uma pergunta relacionada ao comentário de Andrew abaixo:

Karl Wimmer comentou sobre o ponto levantado por Gustav Nordh (reproduzido com a permissão de Karl):

Para adicionar a isso, não vejo porque, a partir dos dois primeiros parágrafos da prova do Teorema 5, podemos concluir que ( mathrm(g_0) ) calcula (f ). Eu vejo apenas algum tipo de unilateralidade que ( mathrm(g_0) ) calcula uma função tal que (f = 1 ) implica que esta função também é 1.

O terceiro parágrafo também não me ajuda: com certeza ( mathrm(g_0) ) e sua chave DNF / CNF computam a mesma função, mas não segue imediatamente que a chave DNF / CNF calcula (f ) (porque ( mathrm(g_0) ) pode não), então não podemos tirar conclusões sobre (f ) -cláusulas.

(À parte: essa unilateralidade é consistente com o exemplo de Gustav acima.)

De um ponto de vista diferente, certamente uma rede padrão computando uma função monótona poderia computar funções não monótonas em nós internos. O Teorema 5 não se aplica a funções não monótonas, então ( mathrm(g) ) pode não computar corretamente a subfunção na rede cujo nó de saída é (g ) (o que acontecerá para muitas funções não monótonas). Por causa disso, não estou convencido de que esta construção indutiva de ( mathrm(g_0) ) será necessariamente correto no final.

Se eu estiver totalmente enganado aqui, por favor, me avise!

De um usuário anônimo, em reação ao ponto de Karl:

E a resposta de Karl (que reproduzo novamente aqui):

Eu vejo o que anon está dizendo (obrigado!) Meu comentário não resolveu adequadamente minha confusão. Se (f ) é monótono e calculado em (g_0 ), é bom tomar ( mathrm(g_0) ), aplique absorção e o operador (R ), e o resultado ( mathrm(g_0) ) representa (f ). Usando esta construção "one-shot", o Teorema 5 está bem - no Teorema 6. Eu encostei esta definição de ( mathrm(g_0) )

O que eu não consigo ver é por que a construção de aplicação de absorção e (R ) à medida que você avança, portão por portão, de ( mathrm(g_0) ) nas páginas 27-28 faz a mesma coisa. Isso parece necessário para que a análise porta a porta do Teorema 6 funcione, a menos que o erro dessa construção seja considerado. Quer dizer, nem toda função pode ser representada por um DNF com termos apenas com literais não negados ou negados, mas para cada nó (g ), ( mathrm(g) ) parece sempre ter esta forma. E se houver um nó (g ) na minha rede tal que ( mathrm(g) ) não tem tal representação?

(Outro pequeno (?) Ponto: não vejo o que (R ) faz na construção porta a porta conforme você avança em 1.-4., Parece que ( alpha ) é já a construção DNF padrão, mas com absorção e (R ) aplicada.)

(resposta de anon) Concordo que a imprecisão na definição de R pode ser um problema na seção 6. R não é explicitamente definido e a menos que sua ação dependa de alguma forma de todo o DNF (e não dos valores de DNF 'nos portões indutivamente) , pode haver um problema. A prova de Deolalikar teve problema semelhante - duas definições diferentes foram confundidas. Aqui, pelo menos sabemos o que significa DNF ', e se esta é a origem do problema na seção 6, pode ser fácil de rastrear. Eu não entrei na seção 6 ainda, ela requer a compreensão da prova por aproximadores de Berg e Ulfberg descritos na seção 4, em última análise relacionados à construção de Razborov de 1985, o que não é fácil.

Quando R é aplicado em alguma etapa, ele apenas cancela os termos que, NESSE PASSO, conteriam literais opostos (podemos precisar rastrear literais negativos). Por exemplo, vamos avaliar [(x lor y) land ( lnot x lor y) land (x lor lnot y) ] como [((x lor y) land ( lnot x lor y)) land (x lor lnot y) ] primeiro, para calcular DNF 'no primeiro nó AND, obtemos [(x lor y) lor ((x land y) lor (y land y)) ] antes de aplicar R, mas depois de aplicar R perdemos o primeiro (x ) do primeiro colchete e obtemos [(y) lor (x land y) lor (y ), ] (onde o primeiro (y ) pode ter NOT (x ) virtual se o estivéssemos rastreando). Em seguida, aplique o segundo AND para obter [((y) lor (x land y) lor (y)) lor ((x land y) lor (x land y) lor (x land y)), ] mas então R remove todo o primeiro colchete porque tem NÃO y virtual presente (neste caso, não precisamos acompanhar as etapas anteriores, mas talvez precisemos em geral), deixando [ ((x land y) lor (x land y) lor (x land y)) ] ou simplesmente [(x land y) ]

4: O que há de novo em estruturas de dados puramente funcionais desde Okasaki? (pontuação 115419 pol.)

Pergunta

Desde o livro de 1998 de Chris Okasaki "Estruturas de dados puramente funcionais", eu não vi muitas novas estruturas de dados puramente funcionais interessantes aparecerem, posso citar apenas algumas:

  • IntMap (também inventado por Okasaki em 1998, mas não presente naquele livro)
  • Árvores de dedos (e sua generalização sobre os monoides)

Existem também algumas maneiras interessantes de implementar estruturas de dados já conhecidas, como o uso de “tipos aninhados” ou “tipos de dados algébricos generalizados” para garantir invariantes de árvore.

Que outras novas ideias surgiram desde 1998 nesta área?

Resposta aceita (pontuação 553)

Novas estruturas de dados puramente funcionais publicadas desde 1998:

2001: Ideal Hash Trees e seu predecessor de 2000, Fast And Space Efficient Trie Searches, de Phil Bagwell: Aparentemente usado como um bloco de construção fundamental na biblioteca padrão de Clojure.

2001: Uma técnica de implementação simples para filas de pesquisa prioritária, por Ralf Hinze: uma técnica realmente simples e bonita para implementar esta importante estrutura de dados (útil, digamos, no algoritmo de Dijkstra). A implementação é particularmente bonita e legível devido ao uso intenso de “padrões de visualização”.

2002: Inicializando matrizes flexíveis unilaterais, por Ralf Hinze: Semelhante às listas de acesso aleatório de Okasaki, mas elas podem ser ajustadas para alterar a troca de tempo entre contras e indexação.

2003: Novos deques catenáveis ​​e não catenáveis, de Radu Mihaescu e Robert Tarjan: Uma nova abordagem sobre alguns trabalhos mais antigos (por Kaplan e Tarjan) que Okasaki cita (a versão mais recente do trabalho de Kaplan e Tarjan foi publicada em 2000). Esta versão é mais simples em alguns aspectos.

2005: Montes maxifóbicos (papel e código), por Chris Okasaki: Apresentado não como uma estrutura nova e mais eficiente, mas como uma forma de ensinar filas prioritárias.

2006: Listas Classificadas Catenáveis ​​de Tempo Constante Puramente Funcional do Pior Caso, por Gerth Stølting Brodal, Christos Makris e Kostas Tsichlas: Responde a uma questão pendente de Kaplan e Tarjan demonstrando uma estrutura com O (lg n) inserir, pesquisar e excluir e O (1) concat.

2008: Confluently Persistent Tries for Efficient Version Control, de Erik D. Demaine, Stefan Langerman e Eric Price: Apresenta várias estruturas de dados para tentativas que possuem navegação e modificação eficientes perto das folhas. Alguns são puramente funcionais. Outros, na verdade, melhoram uma estrutura de dados de longa data de Dietz et al. para matrizes totalmente persistentes (mas não confluentemente persistentes ou puramente funcionais). Este artigo também apresenta árvores de corte de link puramente funcionais, às vezes chamadas de “árvores dinâmicas”.

2010: Um novo algoritmo de exclusão puramente funcional para árvores vermelhas e pretas, de Matt Might: Como o algoritmo de inserção de árvore vermelho-preto de Okasaki, esta não é uma nova estrutura de dados ou uma nova operação em uma estrutura de dados, mas uma maneira nova e mais simples de escrever uma operação conhecida.

2012: RRB-Trees: Efficient Immutable Vectors, de Phil Bagwell e Tiark Rompf: Uma extensão para Hash Array Mapped Tries, suportando concatenação de vetor imutável, inserção em e divisão em tempo O (lg n), enquanto mantém o índice, atualização e velocidades de inserção do vetor imutável original.

Conhecido em 1997, mas não discutido no livro de Okasaki:

Muitos outros estilos de árvore de pesquisa equilibrada. AVL, brother, rank-balance, bounded-balance e muitas outras árvores de busca balanceadas podem ser (e têm sido) implementadas de forma puramente funcional por cópia de caminhos. Talvez merecedores de menção especial são:

  • Árvores de pesquisa tendenciosas, de Samuel W. Bent, Daniel D. Sleator e Robert E. Tarjan: Um elemento chave no artigo de 2006 de Brodal et al. E no artigo de 2008 de Demaine et al.

Conjuntos infinitos que admitem uma busca rápida e exaustiva, de Martín Escardó: Talvez não seja uma estrutura de dados per se.

Três algoritmos em árvores Braun, por Chris Okasaki: As árvores Braun oferecem muitas operações de pilha no pior caso O (lg n). Este limite é ultrapassado por muitas outras estruturas de dados, mas as árvores Braun têm uma operação contrária preguiçosa em seu segundo argumento e, portanto, podem ser usadas como pilhas infinitas de algumas maneiras que outras estruturas não podem.

O heap mínimo-máximo relaxado: uma fila de prioridade dupla finalizável e o heap KD: uma fila de prioridade multidimensional eficiente, de Yuzheng Ding e Mark Allen Weiss: Acontece que são puramente funcionais, embora isso não seja discutido nos documentos. Não acho que os limites de tempo alcançados sejam melhores do que aqueles que podem ser alcançados usando árvores de dedo (de Hinze & amp Paterson ou Kaplan & amp Tarjan) como filas de prioridade k-dimensional, mas acho que as estruturas de Ding & amp Weiss usam menos espaço .

O Zíper, de Gérard Huet: Usado em muitas outras estruturas de dados (como árvores de dedo de Hinze & amp Paterson), esta é uma maneira de transformar uma estrutura de dados do avesso.

Listas de diferenças são O (1) listas catenáveis ​​com uma transformação O (n) em listas contras usuais. Aparentemente, eles são conhecidos desde a antiguidade na comunidade Prolog, onde têm uma transformação O (1) em listas cons usuais.A transformação O (1) parece ser impossível na programação funcional tradicional, mas a abstração de buraco de Minamide, do POPL '98, discute uma maneira de permitir o acréscimo de O (1) e a transformação de O (1) dentro da programação funcional pura. Ao contrário das implementações de programação funcional usuais de listas de diferenças, que são baseadas em fechamentos de funções, as abstrações de buraco são essencialmente as mesmas (tanto em seu uso quanto em sua implementação) que as listas de diferenças Prolog. No entanto, parece que por anos a única pessoa que percebeu isso foi um dos revisores do Minamide.

Dicionários representados exclusivamente suporta inserção, atualização e pesquisa com a restrição de que duas estruturas contendo os mesmos elementos não podem ter formas distintas. Para dar um exemplo, as listas classificadas com links simples são representadas de forma única, mas as árvores AVL tradicionais não. As tentativas também são representadas de forma única. Tarjan e Sundar, em “Representações de árvore de pesquisa binária única e teste de igualdade de conjuntos e sequências”, mostraram um dicionário representado de forma única e puramente funcional que suporta pesquisas em tempo logarítmico e atualizações em (O ( sqrt)) Tempo. No entanto, ele usa espaço ( Theta (n lg n) ). Existe uma representação simples usando árvores Braun que usa apenas espaço linear mas tem tempo de atualização de ( Theta ( sqrt) ) e tempo de pesquisa de ( Theta ( lg ^ 2 n) )

Principalmente estruturas de dados funcionais, antes, durante e depois do livro de Okasaki:

Muitos procedimentos para tornar as estruturas de dados persistentes, totalmente persistentes ou confluentemente persistentes: Haim Kaplan escreveu uma excelente pesquisa sobre o assunto. Veja também acima o trabalho de Demaine et al., Que demonstra uma matriz totalmente persistente no espaço (O (m) ) (onde (m ) é o número de operações já realizadas na matriz) e (O ( lg lg n) ) tempo de acesso esperado.

1989: Árvores de busca aleatória por Cecilia R. Aragon e Raimund Seidel: Estes foram discutidos em um ambiente puramente funcional por Guy E. Blelloch e Margaret Reid-Miller em Fast Set Operations Using Treaps e por Dan Blandford e Guy Blelloch em Functional Set Operations with Treaps (código). Eles fornecem todas as operações de árvores de dedo puramente funcionais e árvores de pesquisa tendenciosas, mas exigem uma fonte de aleatoriedade, o que as torna não puramente funcionais. Isso também pode invalidar a complexidade do tempo das operações em treaps, assumindo um adversário que pode cronometrar as operações e repetir as longas. (Esta é a mesma razão pela qual os argumentos de amortização imperativa não são válidos em uma configuração persistente, mas requer um adversário com um cronômetro)

1997: Skip-trees, uma estrutura de dados alternativa para Skip-lists em uma abordagem simultânea, de Xavier Messeguer e Exploring the Duality Between Skip Lists e Binary Search Trees, de Brian C. Dean e Zachary H. Jones: Listas de salto não são puramente funcionais, mas podem ser implementadas funcionalmente como árvores. Como treaps, eles exigem uma fonte de bits aleatórios. (É possível ignorar listas determinísticas, mas, depois de traduzi-las para uma árvore, acho que são apenas outra maneira de ver 2 a 3 árvores.)

1998: Todas as estruturas amortizadas no livro de Okasaki! Okasaki inventou esse novo método para misturar amortização e estruturas de dados funcionais, que antes eram consideradas incompatíveis. Depende da memoização, que, como Kaplan e Tarjan mencionaram algumas vezes, é na verdade um efeito colateral. Em alguns casos (como PFDS em SSDs por motivos de desempenho), isso pode ser inadequado.

1998: Simple Confluently Persistent Catenable Lists, de Haim Kaplan, Chris Okasaki e Robert E. Tarjan: Usa modificação sob o capô para fornecer deques catenáveis ​​O (1) amortizados, apresentando a mesma interface de uma versão anterior (puramente funcional, mas com memoização) que aparece no livro de Okasaki. Kaplan e Tarjan haviam criado anteriormente uma estrutura de pior caso O (1) puramente funcional, mas é substancialmente mais complicada.

2007: Como mencionado em outra resposta nesta página, estruturas de dados semi-persistentes e união persistente-find de Sylvain Conchon e Jean-Christophe Filliâtre

Técnicas para verificar estruturas de dados funcionais, antes, durante e depois do livro de Okasaki:

Tipos fantasmas são um método antigo para criar uma API que não permite certas operações malformadas. Um uso sofisticado deles pode ser encontrado nos recursos estáticos leves de Oleg Kiselyov e Chung-chieh Shan.

Tipos aninhados na verdade, não são mais recentes do que 1998 - Okasaki até os usa em seu livro. Existem muitos outros exemplos que não estão no livro de Okasaki, alguns são novos e alguns são antigos. Eles incluem:

  • Árvores vermelho-pretas de Stefan Kahrs com tipos (código)
  • Árvores AVL de Ross Paterson (espelho)
  • Da exponenciação rápida às matrizes quadradas de Chris Okasaki: uma aventura em tipos
  • A notação de Bruijn de Richard S. Bird e Ross Peterson como um tipo de dados aninhado
  • Representações numéricas de Ralf Hinze como tipos de dados aninhados de ordem superior.

GADTs não são tão novos assim. Eles são uma adição recente a Haskell e alguns MLs, mas eles estão presentes, eu acho, em vários cálculos lambda digitados desde os anos 1970.

2004-2010: Coq e Isabelle pela correção. Várias pessoas usaram provadores de teoremas para verificar a exatidão de estruturas de dados puramente funcionais. Coq pode extrair essas verificações para o código de trabalho em Haskell, OCaml e Scheme Isabelle pode extrair para Haskell, ML e OCaml.

  • Tobias Nipkow e Cornelia Pusch formalizaram árvores AVL.
  • Viktor Kuncak formalizou árvores de busca binárias não balanceadas.
  • Peter Lammich publicou o framework Isabelle Collections, que inclui formalizações de estruturas de dados puramente funcionais eficientes como árvores vermelhas e pretas e tentativas, bem como estruturas de dados que são menos eficientes quando usadas persistentemente, como duas pilhas de filas (sem o truque da preguiça de Okasaki ) e tabelas de hash.
  • Peter Lammich também publicou formalizações de autômatos de árvore, árvores de dedo de Hinze & amp Patterson (com Benedikt Nordhoff e Stefan Körner) e filas de prioridade puramente funcionais de Brodal e Okasaki (com Rene Meis e Finn Nielsen).
  • René Neumann formalizou filas de prioridade binomial.

2007: Refined Typechecking with Stardust, de Joshua Dunfield: Este artigo usa tipos de refinamento para ML para encontrar erros na função de exclusão de árvore vermelho-preto do SMLNJ.

2008: Análise de complexidade de tempo semiformal leve para estruturas de dados puramente funcionais por Nils Anders Danielsson: Usa Agda com anotação manual para provar limites de tempo para alguns PFDS.

Estruturas de dados imperativas ou análises não discutidas no livro de Okasaki, mas relacionadas a estruturas de dados puramente funcionais:

The Soft Heap: Uma fila de prioridade aproximada com taxa de erro ideal, por Bernard Chazelle: Esta estrutura de dados não usa matrizes e, portanto, tentou primeiro o canal de IRC #haskell e depois os usuários do Stack Overflow, mas inclui exclusão em o (lg n), o que geralmente não é possível em um ambiente funcional, e análise amortizada imperativa , o que não é válido em um ambiente puramente funcional.

Árvores de pesquisa binárias balanceadas com atualizações O (1) dedo. Em Tornando as Estruturas de Dados Persistentes, James R Driscoll, Neil Sarnak, Daniel D. Sleator e Robert E. Tarjan apresentam um método para agrupar os nós em uma árvore vermelha e preta de forma que atualizações persistentes requeiram apenas espaço O (1). Os deques e árvores de dedo puramente funcionais projetados por Tarjan, Kaplan e Mihaescu usam uma técnica de agrupamento muito semelhante para permitir atualizações O (1) em ambas as extremidades. Árvores AVL para pesquisa localizada por Athanasios K. Tsakalidis funcionam de forma semelhante.

Montes de emparelhamento mais rápidos ou melhores limites para montes de emparelhamento: Desde que o livro de Okasaki foi publicado, várias novas análises de heaps de emparelhamento imperativo apareceram, incluindo heaps de emparelhamento com custo de redução de O (log log n) por Amr Elmasry e Rumo a uma análise final de heaps de emparelhamento por Seth Pettie. Pode ser possível aplicar parte desse trabalho aos lotes preguiçosos de emparelhamento de Okasaki.

Árvores de dedo enviesadas determinísticas: Em Listas de ignorar enviesadas, de Amitabha Bagchi, Adam L. Buchsbaum e Michael T. Goodrich, um projeto é apresentado para listas de ignorar enviesadas determinísticas. Por meio da transformação de lista / árvore de ignorar mencionada acima, pode ser possível fazer árvores de pesquisa enviesadas determinísticas. As listas de omissão tendenciosa descritas por John Iacono e Özgür Özkan em Dicionários intercaláveis ​​podem então ser possíveis em árvores de omissão tendenciosa. Uma árvore de dedo tendenciosa é sugerida por Demaine et al. em seu artigo sobre tentativas puramente funcionais (veja acima) como uma forma de reduzir os limites de tempo e espaço na atualização do dedo nas tentativas.

The String B-Tree: Uma Nova Estrutura de Dados para Pesquisa de String em Memória Externa e suas Aplicações por Paolo Ferragina e Roberto Grossi é uma estrutura de dados bem estudada combinando os benefícios de try e B-trees.

Resposta 2 (pontuação 63)

Às excelentes notas já feitas, acrescentarei Zíperes.

Huet, Gerard. “Functional Pearl: The Zipper” Journal of Functional Programming 7 (5): 549-554, setembro de 1997.


ArXiv é 3 vezes maior do que todos os megajournals juntos

Para ter uma comparação clara, vou olhar para a janela 2010-2014.

Antes de mostrar os números, há algumas coisas a acrescentar.

1. Eu vi o artigo [1] através da postagem de + Mike Taylor

Convido você a lê-lo, é interessante como sempre.

Essas discussões me fizeram perceber que o modelo arXiv é cuidadosamente retirado da realidade pelos criadores e principais apoiadores do OA verde e OA dourado.

De [1], o número total de artigos por ano para & # 8220megajournals & # 8221 é

2010: 6,913
2011: 14,521
2012: 25,923
2013: 37,525
2014: 37,794
2015: 33,872

(para 2015, o número representa & # 8220 os artigos publicados no primeiro trimestre do ano multiplicados por quatro & # 8221 [1])

ArXiv: (com base na contagem dos envios mensais listados em [2])

2010: 70,131
2011: 76,578
2012: 84,603
2013: 92,641
2014: 97,517
2015: 100.628 (pelo mesmo procedimento de [1])

Isto mostra que arXiv é 3 vezes maior do que todos os megajournals de uma vez, Apesar disso:
& # 8211 não é um editor
& # 8211 não pede APC
& # 8211 cobre campos muito menos atraentes e prolíficos do que os megajournals.

E isso porque:
& # 8211 arxiv atende a uma demanda real dos pesquisadores, de comunicar de forma rápida e confiável seu trabalho aos seus companheiros, de forma que respeite sua autoria
& # 8211 também uma reação de apoio ao que a maioria deles pensa ser & # 8220green OA & # 8221, ou seja, colocar seu trabalho ali onde está longe das fechaduras dos editores.


Um algoritmo de aprendizagem para máquinas Boltzmann *

A pesquisa relatada aqui foi apoiada por doações da System Development Foundation. Agradecemos a Peter Brown, Francis Crick, Mark Derthick, Scott Fahlman, Jerry Feldman, Stuart Geman, Gail Gong, John Hopfield, Jay McClelland, Barak Pearlmutter, Harry Printz, Dave Rumelhart, Timubra Shallice, Paul Smolensky, Rick Szeliski e Venkataraman Venkatasmanian para discussões úteis.

Resumo

O poder computacional de redes massivamente paralelas de elementos de processamento simples reside na largura de banda de comunicação fornecida pelas conexões de hardware entre os elementos. Essas conexões podem permitir que uma fração significativa do conhecimento do sistema seja aplicada a uma instância de um problema em um tempo muito curto. Um tipo de cálculo para o qual redes massivamente paralelas parecem ser bem adequadas são as pesquisas de satisfação de grandes restrições, mas para usar as conexões de forma eficiente duas condições devem ser atendidas: primeiro, uma técnica de pesquisa que seja adequada para redes paralelas deve ser encontrada. Em segundo lugar, deve haver alguma maneira de escolher representações internas que permitam que as conexões de hardware preexistentes sejam usadas de forma eficiente para codificar as restrições no domínio que está sendo pesquisado. Descrevemos um método geral de busca paralela, baseado em mecânica estatística, e mostramos como ele conduz a uma regra geral de aprendizado para modificar as forças de conexão de forma a incorporar o conhecimento sobre um domínio de tarefa de forma eficiente. Descrevemos alguns exemplos simples nos quais o algoritmo de aprendizagem cria representações internas que são comprovadamente a maneira mais eficiente de usar a estrutura de conectividade preexistente.


Nada vago do ponto de vista & # 8220sem semântica & # 8221

Sou um defensor da & # 8220no semântica & # 8221 e tentarei convencê-lo de que não há nada de vago nisso.

Considere qualquer formalismo. A qualquer termo construído a partir deste formalismo existe uma árvore sintática associada. Agora, olhe para a árvore sintática e esqueça o formalismo. Por ser uma árvore, isso significa que não importa como você decida decorar suas folhas, você pode progredir das folhas até a raiz decorando cada borda. Em cada nó da árvore, você segue uma regra de decoração que diz: pegue as decorações das bordas de entrada e use-as para decorar as bordas de saída. Se você supõe que o formalismo é aquele que usa operações de aridade limitada, então você pode dizer o seguinte: estritamente seguindo as regras de decoração que são locais (você precisa saber apenas no máximo N decorações de aresta para decorar outra aresta) você pode chegar para decorar toda a árvore. Al o gráfico! E o significado do gráfico tem algo a ver com essa decoração. Na verdade, o formalismo não se trata de gráficos (árvores), mas de decorações estáticas que aparecem na raiz da árvore sintática.
Mas, você vê, essas decorações estáticas são efeitos globais das regras locais de decoração. Aqui entra a polícia semântica. Tu aceitarás apenas árvores cujas raízes aceitem decorações de um determinado idioma. Seguem-se problemas difíceis, que são fortemente carregados de semântica.
Agora, vamos & # 8217s passar das árvores para outros gráficos.
O mesmo fenômeno (há uma decoração global estática emergida das regras locais de decoração) para qualquer DAG (grafo acíclico direcionado). É revelador que as pessoas AMAM DAGs, tanto que vão ao extremo de excluir de seu pensamento outros gráficos. São eles que colocam tudo em uma estrutura funcional.
Não há nada de errado nisso!
Os gráficos decorados têm uma longa tradição em matemática, pense, por exemplo, na teoria dos nós.
Na teoria do nó, o diagrama do nó é um gráfico (com nós 4-valentes) que certamente não é acíclico! No entanto, um dos objetos fundamentais associados a um nó é o objeto algébrico denominado & # 8220quandle & # 8221, que é gerado a partir das arestas do gráfico, com certas relações vindas das arestas. Obviamente, é um problema muito difícil, totalmente carregado semanticamente, tentar identificar o nó do nó associado.
A diferença das árvores sintáticas é que o grafo não admite decoração global estática, genericamente. É por isso que o objeto algébrico associado, o quandle, é gerado (e não igual a) o conjunto de arestas.

Existem belos problemas relacionados aos objetos globais gerados por regras locais. Eles também são difíceis, por causa do aspecto global. Talvez seja tão difícil encontrar um algoritmo que construa um isomorfismo entre dois grafos que possuem a mesma família de decorações associadas, quanto encontrar um algoritmo descentralizado para redução de grafos de uma árvore sintática distribuída.

Mas esse tipo de problema não cobre todos os problemas interessantes.

E se esse ponto de vista semântico global tornar as coisas mais difíceis do que realmente são?

Suponha que você seja um gênio que encontrou esse algoritmo, por meio de incríveis insights matemáticos que dobram a mente.

Seu algoritmo brilhante, por ser um algoritmo, pode ser executado por uma Máquina de Turing.

Ou as máquinas de Turing são puramente locais. O cabeçote da máquina tem apenas acesso local à fita, a qualquer momento (esqueça a indireção, voltarei a isso em instantes). O número de estados das máquinas é finito e o número de regras é finito.

Isso significa que o trabalho brilhante serviu para separar o global do problema!

Se você não está satisfeito com TM, por causa de indireção, então não procure além de chemlambda (se desejar combinado com TM, como em
http://chorasimilarity.github.io/chemlambda-gui/dynamic/turingchem.html, se você adora TM), que é definitivamente local e Turing universal. Funciona pelo algoritmo brilhante: faça todas as reescritas que você puder fazer, nunca se importando com o significado global delas.

Oh, espere, que tal uma célula viva, ela tem uma maneira de gerenciar a semântica das redes de reações químicas globais corretas que SÃO a célula?

Que tal um cérebro, feito de muitas células neurais, células da glia e outros enfeites? Pela falácia do homúnculo, ele não pode ter funções e termos estáticos, externos e globalmente selecionados (também conhecidos como semânticos).

Por outro lado, é claro que o pesquisador que estuda a célula, ou o cérebro, ou o matemático que encontra o algoritmo brilhante, todos estão usando um maquinário semântico pesado.

Não que a célula ou o cérebro precisem da história para viver.

No gif animado existe uma molécula chemlambda chamada 28 quine, que satisfaz a definição de vida no sentido de que ela reabastece aleatoriamente seus átomos, mantendo aproximadamente sua forma global (portanto, tem um metabolismo). Ele faz isso de acordo com o algoritmo: faça todas as reescritas que puder, mas só poderá reescrever se um lançamento de moeda aleatório aceitar.


A maioria dos átomos da molécula está relacionada a operações (aplicação e abstração) do cálculo lambda.

Modifiquei um pouco um script (desculpe, não no repo este aqui) para que sempre que possível as arestas deste gráfico que PODEM fazer parte de uma árvore sintática de um termo lambda se transformem em OURO enquanto as outras ficam em cinza escuro.

Eles não significam nada, não há semântica, porque pela primeira vez os gráficos dourados não são DAGs e porque o cálculo consiste em reescrever gráficos que não preservam bem as decorações & # 8220corretas & # 8221 antes da reescrita.

Não há semântica, mas ainda há algumas questões interessantes a explorar, sendo a principal: como funciona a vida?


O micróbio numérico e o castor ocupado

Este é outro post com um nome estranho, mas contente depois deste. Durante uma tentativa de me lançar em explicações em vídeo, fiz um post sobre o micróbio numérico.

O micróbio numérico é a versão chemlambda de uma multiplicação de dois números de Igreja, neste caso 5X5 = 25. Chamei a criatura que evolui no vídeo de & # 8220 micróbio numérico & # 8221 porque ela realmente consome cópias do número 5, metaboliza-as e acaba produzindo 25. De uma forma muito cuidadosa, no entanto, o que me inspirou a seguinte descrição (mas você tem para ver o vídeo dessa postagem):

& # 8220O micróbio numérico adora os números da Igreja. Sua estratégia é esta: nunca um sem o outro. Quando ele encontra um número da Igreja, ele procura o segundo. Então ele acorrenta o primeiro ao segundo e só depois começa a mastigar lentamente a cabeça do primeiro. Enquanto isso, o segundo número da Igreja observa o infeliz primeiro número da Igreja entrando, átomo por átomo, na boca numérica.

Apenas o último número da Igreja sobreviveu, na forma da cauda do numerador. & # 8221

O arquivo mol usado é times_only.mol. Sim, tudo bem, é a versão mol do AST de um termo lambda.

Você pode ver o número-phile também nesta animação, junto com uma máquina de Turing de castor ocupada (a versão chemlambda explicada aqui):

Na primeira metade da animação, você vê o & # 8220numberphile & # 8221 à esquerda e o castor ocupado como um loop avermelhado à direita.

O que acontece é que o termo lambda como 5X5 reduz para 25, enquanto ao mesmo tempo a máquina de castores ocupada também funciona. Ao mesmo tempo, a Igreja número 25 em formação já faz com que o pequeno laço se replique e cresça cada vez mais, eventualmente 25 vezes maior.

Isso explica o título.

O arquivo mol usado é times_only_bb.mol. Abra-o e veja como é diferente do primeiro.

Você pode ver uma simulação (js) do número da Igreja aplicada a um castor ocupado aqui.

E o mais importante é: durante a realização deste curta-metragem, nenhum diretor humano esteve presente para encenar o ato.


Assista o vídeo: ALAN TURING - KHOA HỌC MÁY TÍNH tập 15. Tri thức nhân loại (Janeiro 2022).