Considérons une chaîne binaire S
de longueur n
. En indexant à partir de 1
, nous pouvons calculer les distances de Hamming entre S[1..i+1]
et S[n-i..n]
pour tous i
dans l'ordre de 0
à n-1
. La distance de Hamming entre deux chaînes de longueur égale est le nombre de positions auxquelles les symboles correspondants sont différents. Par exemple,
S = 01010
donne
[0, 2, 0, 4, 0].
En effet , les 0
matchs 0
, 01
a une distance de Hamming deux à 10
, 010
matchs 010
, 0101
a une distance de Hamming quatre à 1010
et enfin 01010
lui - même correspond.
Cependant, nous ne sommes intéressés que par les sorties où la distance de Hamming est au plus 1. Donc, dans cette tâche, nous signalerons un Y
si la distance de Hamming est au plus un et un N
autre. Donc, dans notre exemple ci-dessus, nous aurions
[Y, N, Y, N, Y]
Définissez f(n)
le nombre de tableaux distincts de Y
s et N
s que l'on obtient lors de l'itération sur toutes les 2^n
différentes chaînes S
de bits possibles de longueur n
.
Tâche
Pour augmenter à n
partir de 1
, votre code devrait sortir f(n)
.
Exemples de réponses
Pour n = 1..24
, les bonnes réponses sont:
1, 1, 2, 4, 6, 8, 14, 18, 27, 36, 52, 65, 93, 113, 150, 188, 241, 279, 377, 427, 540, 632, 768, 870
Notation
Votre code doit répéter n = 1
la réponse de chacun n
à son tour. Je chronométrerai toute la course, le tuant après deux minutes.
Votre score est le plus élevé que n
vous ayez atteint pendant cette période.
En cas d'égalité, la première réponse l'emporte.
Où mon code sera-t-il testé?
Je vais exécuter votre code sur mon (légèrement vieux) ordinateur portable Windows 7 sous cygwin. Par conséquent, veuillez fournir toute l'aide que vous pouvez pour faciliter la tâche.
Mon ordinateur portable a 8 Go de RAM et un processeur Intel i7 5600U@2,6 GHz (Broadwell) avec 2 cœurs et 4 threads. Le jeu d'instructions comprend SSE4.2, AVX, AVX2, FMA3 et TSX.
Entrées principales par langue
- n = 40 dans Rust en utilisant CryptoMiniSat, par Anders Kaseorg. (Dans la VM invitée Lubuntu sous Vbox.)
- n = 35 en C ++ en utilisant la bibliothèque BuDDy, par Christian Seviers. (Dans la VM invitée Lubuntu sous Vbox.)
- n = 34 dans Clingo par Anders Kaseorg. (Dans la VM invitée Lubuntu sous Vbox.)
- n = 31 en rouille par Anders Kaseorg.
- n = 29 dans Clojure par NikoNyrh.
- n = 29 en C par Bartavelle.
- n = 27 à Haskell par Bartavelle
- n = 24 en Pari / gp par alephalpha.
- n = 22 en Python 2 + pypy par moi.
- n = 21 dans Mathematica par alephalpha. (Auto-déclaré)
Futures primes
Je vais maintenant donner une prime de 200 points pour toute réponse atteignant n = 80 sur ma machine en deux minutes.
Réponses:
Rust + CryptoMiniSat , n ≈ 41
src/main.rs
Cargo.toml
Comment ça fonctionne
Cela effectue une recherche récursive dans l'arborescence de toutes les affectations partielles aux préfixes du tableau Y / N, à l'aide d'un solveur SAT pour vérifier à chaque étape si l'affectation partielle actuelle est cohérente et élaguer la recherche dans le cas contraire. CryptoMiniSat est le bon solveur SAT pour ce travail en raison de ses optimisations spéciales pour les clauses XOR.
Les trois familles de contraintes sont
S i ⊕ S k + i ⊕ D ki , pour 1 ≤ k ≤ n - 2, 0 ≤ i ≤ n - k ;
D ki 1 ∨ D ki 2 ∨ ¬ A k , pour 1 ≤ k ≤ n - 2, 0 ≤ i 1 < i 2 ≤ n - k ;
¬ D ki 1 ∨ ⋯ ∨ ¬ D ki n - k - 1∨ A k , pour 1 ≤ k ≤ n - 2, 0 ≤ i 1 <⋯ < i n - k - 1 ≤ n - k ;
sauf que, comme optimisation, S 0 est forcé à faux, de sorte que D k 0 est simplement égal à S k .
la source
cargo build
je reçois--- stderr CMake Error: Could not create named generator Visual Studio 14 2015 Win64
Rouille, n ≈
30 ou31 ou 32Sur mon ordinateur portable (deux cœurs, i5-6200U), cela passe par n = 1,…, 31 en 53 secondes, en utilisant environ 2,5 Gio de mémoire, ou par n = 1,…, 32 en 105 secondes, en utilisant environ 5 Gio de la mémoire. Compilez avec
cargo build --release
et exécuteztarget/release/correlations
.src/main.rs
Cargo.toml
Essayez-le en ligne!
J'ai également une variante légèrement plus lente utilisant beaucoup moins de mémoire.
la source
C ++ à l'aide de la bibliothèque BuDDy
Une approche différente: avoir une formule binaire (sous forme de diagramme de décision binaire ) qui prend les bits de
S
comme entrée et est vraie ssi qui donne des valeurs fixes deY
ouN
à certaines positions sélectionnées. Si cette formule n'est pas constamment fausse, sélectionnez une position libre et répétez, en essayant les deuxY
etN
. S'il n'y a pas de position libre, nous avons trouvé une valeur de sortie possible. Si la formule est constamment fausse, revenez en arrière.Cela fonctionne relativement raisonnable car il y a si peu de valeurs possibles que nous pouvons souvent revenir en arrière tôt. J'ai essayé une idée similaire avec un solveur SAT, mais cela a été moins réussi.
Pour compiler avec debian 8 (jessie), installez
libbdd-dev
et faitesg++ -std=c++11 -O3 -o hb hb.cpp -lbdd
. Il pourrait être utile d'augmenterbdd_init
encore plus le premier argument .la source
Clingo, n ≈
30 ou 3134J'ai été un peu surpris de voir cinq lignes de code Clingo dépasser ma solution Rust à force brute et se rapprocher vraiment de la solution BuDDy de Christian - il semblerait que cela battrait cela aussi avec un délai plus long.
corr.lp
corr.sh
la source
bdd_init
pourrait aider, ou permettre d'augmenter davantage la table des nœuds en appelantbdd_setmaxincrease
avec une valeur bien supérieure à la valeur par défaut de 50000. - Utilisez-vous la version modifiée de mon programme?--configuration=crafty
(jumpy
ettrendy
donnez des résultats similaires).Pari / GP , 23
Par défaut, Pari / GP limite sa taille de pile à 8 Mo. La première ligne du code
default(parisize, "4g")
, définit cette limite à 4 Go. S'il donne toujours un stackoverflow, vous pouvez le régler sur 8 Go.la source
Clojure, 29 en
7538 secondes, 30 en 80 et 31 en 165Runtimes d' Intel i7 6700K , l'utilisation de la mémoire est inférieure à 200 Mo.
project.clj (utilise com.climate / claypoole pour le multithreading):
Code source:
Une solution de force brute, chaque thread parcourt un sous-ensemble de la plage (2 ^ 12 éléments) et construit un ensemble de valeurs entières qui indiquent les modèles détectés. Ceux-ci sont ensuite «réunis» ensemble et donc le décompte distinct est calculé. J'espère que le code n'est pas trop difficile à suivre même s'il utilise beaucoup les macros de threading . Mon
main
exécute le test plusieurs fois pour réchauffer la JVM.Mise à jour: l'itération sur seulement la moitié des entiers obtient le même résultat en raison de la symétrie. Ignorer également les nombres avec un nombre de bits plus élevé sur la moitié inférieure du nombre car ils produisent également des doublons.
Uberjar pré-construit ( v1 ) (3,7 Mo):
Résultats sur différents matériels, la durée d'exécution prévue est
O(n * 2^n)
?Vous pouvez facilement créer ce thread unique et éviter cette dépendance tierce en utilisant la norme pour:
Eh bien, le pmap intégré existe également, mais claypoole a plus de fonctionnalités et de réglage.
la source
Mathematica, n = 19
appuyez sur alt +. pour abandonner et le résultat sera imprimé
la source
Mathematica, 21
A titre de comparaison, la réponse de Jenny_mathy donne
n = 19
sur mon ordinateur.La partie la plus lente est
Tr@IntegerDigits[#, 2] &
. Il est dommage que Mathematica n'ait pas de fonction intégrée pour le poids de Hamming.Si vous souhaitez tester mon code, vous pouvez télécharger un essai gratuit de Mathematica .
la source
Version AC, utilisant popcount intégré
Fonctionne mieux avec
clang -O3
, mais fonctionne également si vous ne l'avez quegcc
.la source
Haskell, (n officieux = 20)
Ceci est juste l'approche naïve - jusqu'à présent sans aucune optimisation. Je me demandais à quel point cela se comporterait bien avec d'autres langues.
Comment l'utiliser (en supposant que la plateforme haskell soit installée):
approx_corr.hs
(ou tout autre nom, modifiez les étapes suivantes en conséquence)ghc approx_corr.hs
approx_corr.exe
n
Code:
la source
main = putStrLn "Hello World!"
?Data.Bits
module pourrait être utile. Pour votre boucle principale, vous pouvez utiliser quelque chose commemain = do maxn <- getmax; t0 <- gettime; loop 1
oùloop n|n==maxn = return ()
etloop n = do printresult n (f n); t <- gettime; printtime (t-t0); loop (n+1)
.getmax
pourrait par exemple utilisergetArgs
pour utiliser les arguments du programme.Une solution Haskell, utilisant popCount et le parallélisme géré manuellement
Compiler:
ghc -rtsopts -threaded -O2 -fllvm -Wall foo.hs
(laissez tomber
-llvm
si ça ne marche pas)Courir :
./foo +RTS -N
la source
-O3
, et pourrait être plus rapide avec-O3 -fllvm
...Python 2 + pypy, n = 22
Voici une solution Python vraiment simple comme une sorte de référence de référence.
la source