Considere uma cadeia S
de comprimento binária n
. Indexando de 1
, podemos calcular as distâncias de Hamming entre S[1..i+1]
e S[n-i..n]
para todos i
na ordem de 0
para n-1
. A distância de Hamming entre duas cordas de igual comprimento é o número de posições nas quais os símbolos correspondentes são diferentes. Por exemplo,
S = 01010
dá
[0, 2, 0, 4, 0].
Isso ocorre porque 0
combinações 0
, 01
tem distância de Hamming 2 a 10
, 010
combina 010
, 0101
tem distância de Hamming 4 a 1010
e, finalmente, 01010
combina-se.
No entanto, estamos interessados apenas em saídas onde a distância de Hamming é no máximo 1. Portanto, nesta tarefa, reportaremos a Y
se a distância de Hamming é no máximo uma e N
outra. Então, no nosso exemplo acima, teríamos
[Y, N, Y, N, Y]
Define f(n)
-se o número de matrizes distintas de Y
s e N
s que se tem quando iteração sobre todas as 2^n
sequências de bits diferentes possíveis S
de comprimento n
.
Tarefa
Para aumentar a n
partir de 1
, seu código deve ser exibido f(n)
.
Respostas de exemplo
Pois n = 1..24
, as respostas corretas são:
1, 1, 2, 4, 6, 8, 14, 18, 27, 36, 52, 65, 93, 113, 150, 188, 241, 279, 377, 427, 540, 632, 768, 870
Pontuação
Seu código deve repetir n = 1
a resposta de cada um n
. Eu cronometrarei a corrida inteira, matando-a depois de dois minutos.
Sua pontuação é a mais alta que n
você obtém nesse período.
Em caso de empate, a primeira resposta vence.
Onde meu código será testado?
Vou executar seu código no meu laptop Windows 7 (um pouco antigo) sob o cygwin. Como resultado, forneça qualquer assistência possível para facilitar isso.
Meu laptop possui 8 GB de RAM e uma CPU Intel i7 [email protected] GHz (Broadwell) com 2 núcleos e 4 threads. O conjunto de instruções inclui SSE4.2, AVX, AVX2, FMA3 e TSX.
Entradas principais por idioma
- n = 40 em Rust usando CryptoMiniSat, de Anders Kaseorg. (Na VM convidada do Lubuntu, no Vbox.)
- n = 35 em C ++ usando a biblioteca BuDDy, de Christian Seviers. (Na VM convidada do Lubuntu, no Vbox.)
- n = 34 em Clingo por Anders Kaseorg. (Na VM convidada do Lubuntu, no Vbox.)
- n = 31 em Rust por Anders Kaseorg.
- n = 29 in Clojure por NikoNyrh.
- n = 29 in C por bartavelle.
- n = 27 in Haskell por bartavelle
- n = 24 in Pari / gp por alefalpha.
- n = 22 em Python 2 + pypy por mim.
- n = 21 no Mathematica por alefalpha. (Auto-relatado)
Recompensas futuras
Agora, darei uma recompensa de 200 pontos por qualquer resposta que chegue a n = 80 na minha máquina em dois minutos.
Respostas:
Rust + CryptoMiniSat , nº 41
src/main.rs
Cargo.toml
Como funciona
Isso faz uma pesquisa recursiva na árvore de todas as atribuições parciais aos prefixos da matriz Y / N, usando um solucionador SAT para verificar a cada passo se a atribuição parcial atual é consistente e poda a pesquisa, se não. O CryptoMiniSat é o solucionador SAT certo para este trabalho devido às suas otimizações especiais para cláusulas XOR.
As três famílias de restrições são
S i ⊕ S k + i ⊕ D ki , para 1 ≤ k ≤ n - 2, 0 ≤ i ≤ n - k ;
D ki 1 ∨ D ki 2 ¬ A k , para 1 ≤ k ≤ n - 2, 0 ≤ i 1 < i 2 ≤ n - k ; ¬ D ki 1 ¬ ⋯ ∨ D ki n - kA k , para 1 ≤ k
- 1∨ ≤ n - 2, 0 ≤ i 1 <⋯ < i n - k - 1 ≤ n - k ;
exceto que, como uma otimização, S 0 é forçado a falso, de modo que D k 0 é simplesmente igual a S k .
fonte
cargo build
recebo--- stderr CMake Error: Could not create named generator Visual Studio 14 2015 Win64
Ferrugem, n ≈
30 ou31 ou 32No meu laptop (dois núcleos, i5-6200U), isso passa por n = 1,…, 31 em 53 segundos, usando cerca de 2,5 GiB de memória, ou por n = 1,…, 32 em 105 segundos, usando cerca de 5 GiB de memória. Compile
cargo build --release
e executetarget/release/correlations
.src/main.rs
Cargo.toml
Experimente online!
Eu também tenho uma variante um pouco mais lenta, usando muito menos memória.
fonte
C ++ usando a biblioteca BuDDy
Uma abordagem diferente: tenha uma fórmula binária (como diagrama de decisão binário ) que aceite os bits
S
como entrada e seja verdadeira se der alguns valores fixos deY
ouN
em determinadas posições selecionadas. Se essa fórmula não for constante false, selecione uma posição livre e recorra, tentando ambasY
eN
. Se não houver posição livre, encontramos um possível valor de saída. Se a fórmula for constante false, retorne.Isso funciona relativamente razoável, porque há tão poucos valores possíveis, para que possamos voltar sempre cedo. Tentei uma idéia semelhante com um solucionador SAT, mas isso foi menos bem-sucedido.
Para compilar com o debian 8 (jessie), instale
libbdd-dev
e façag++ -std=c++11 -O3 -o hb hb.cpp -lbdd
. Pode ser útil aumentarbdd_init
ainda mais o primeiro argumento .fonte
Clingo, n.
30 ou 3134Fiquei um pouco surpreso ao ver cinco linhas de código Clingo ultrapassando minha solução Rust de força bruta e chegando muito perto da solução BuDDy de Christian - parece que isso também seria melhor com um limite de tempo mais alto.
corr.lp
corr.sh
fonte
bdd_init
pode ajudar, ou permitir aumentar mais a tabela de nós chamandobdd_setmaxincrease
com um valor muito acima do padrão de 50000. - Você está usando a versão alterada do meu programa?--configuration=crafty
(jumpy
etrendy
fornece resultados semelhantes).Pari / GP , 23
Por padrão, o Pari / GP limita o tamanho da pilha a 8 MB. A primeira linha do código
default(parisize, "4g")
,, define esse limite para 4 GB. Se ele ainda der um fluxo de pilha, você poderá configurá-lo para 8 GB.fonte
Clojure, 29 em
7538 segundos, 30 em 80 e 31 em 165Duração de tempos de execução Intel i7 6700K , o uso de memória é inferior a 200 MB.
project.clj (usa com.climate / claypoole para multithreading):
Código fonte:
Uma solução de força bruta, cada encadeamento passa por um subconjunto do intervalo (2 ^ 12 itens) e cria um conjunto de valores inteiros que indicam padrões detectados. Estes são então "unidos" juntos e, portanto, a contagem distinta é calculada. Espero que o código não seja muito complicado de seguir, apesar de usar muito as macros de encadeamento . Minhas
main
executa o teste algumas vezes para aquecer a JVM.Atualização: Iterando apenas a metade dos números inteiros, obtém o mesmo resultado devido à simetria. Também pular números com maior contagem de bits na metade inferior do número, pois eles também produzem duplicatas.
Uberjar pré-construído ( v1 ) (3,7 MB):
Resultados em diferentes hardwares, o tempo de execução esperado é
O(n * 2^n)
?Você pode facilmente fazer isso com thread único e evitar essa dependência de terceiros usando o padrão para:
Bem, o pmap embutido também existe, mas o claypoole tem mais recursos e capacidade de ajuste.
fonte
Mathematica, n = 19
pressione alt +. abortar e o resultado será impresso
fonte
Mathematica, 21
Para comparação, a resposta de Jenny_mathy dá
n = 19
no meu computador.A parte mais lenta é
Tr@IntegerDigits[#, 2] &
. É uma pena que o Mathematica não tenha um peso embutido para Hamming.Se você quiser testar meu código, pode fazer o download de uma avaliação gratuita do Mathematica .
fonte
Versão CA, usando popcount embutido
Funciona melhor com
clang -O3
, mas também funciona se você tivergcc
.fonte
Haskell, (não oficial n = 20)
Essa é apenas a abordagem ingênua - até agora sem otimizações. Eu me perguntava o quão bem isso se sairia contra outras línguas.
Como usá-lo (supondo que você tenha a plataforma haskell instalada):
approx_corr.hs
(ou qualquer outro nome, modifique as etapas a seguir)ghc approx_corr.hs
approx_corr.exe
n
Código:
fonte
main = putStrLn "Hello World!"
?Data.Bits
módulo pode ser útil. Para o loop principal, você pode usar algo comomain = do maxn <- getmax; t0 <- gettime; loop 1
ondeloop n|n==maxn = return ()
eloop n = do printresult n (f n); t <- gettime; printtime (t-t0); loop (n+1)
.getmax
poderia, por exemplo,getArgs
usar os argumentos do programa.Uma solução Haskell, usando popCount e paralelismo gerenciado manualmente
Compilar:
ghc -rtsopts -threaded -O2 -fllvm -Wall foo.hs
(largue o
-llvm
se não funcionar)Corre :
./foo +RTS -N
fonte
-O3
, e pode ser mais rápido com-O3 -fllvm
...Python 2 + pypy, n = 22
Aqui está uma solução Python realmente simples como uma espécie de referência de linha de base.
fonte