Рассмотрим двоичную строку S
длины n
. Индексируя с 1
, мы можем вычислить расстояния Хэмминга между S[1..i+1]
и S[n-i..n]
для всех i
в порядке от 0
до n-1
. Расстояние Хэмминга между двумя строками одинаковой длины - это количество позиций, в которых соответствующие символы различны. Например,
S = 01010
дает
[0, 2, 0, 4, 0].
Это потому , что 0
совпадения имеют расстояние Хэмминга от двух до , совпадения , расстояние Хэмминга от четырех до и, наконец, совпадают.0
01
10
010
010
0101
1010
01010
Однако нас интересуют только результаты, в которых расстояние Хэмминга не более 1. Таким образом, в этой задаче мы сообщим, Y
если расстояние Хэмминга не больше одного, а в N
противном случае. Таким образом, в нашем примере выше мы получили бы
[Y, N, Y, N, Y]
Определите f(n)
количество различных массивов Y
s и N
s, получаемых при переборе всех 2^n
возможных битовых строк S
длины n
.
задача
Для увеличения, n
начиная с 1
, ваш код должен выводить f(n)
.
Пример ответов
Для n = 1..24
, правильные ответы:
1, 1, 2, 4, 6, 8, 14, 18, 27, 36, 52, 65, 93, 113, 150, 188, 241, 279, 377, 427, 540, 632, 768, 870
счет
Ваш код должен повторяться от n = 1
предоставления ответа для каждого n
по очереди. Я рассчитываю весь пробег, убив его через две минуты.
Ваш результат - самый высокий n
за это время.
В случае ничьей победит первый ответ.
Где будет проверяться мой код?
Я буду запускать ваш код на моем (немного старом) ноутбуке с Windows 7 под Cygwin. В результате, пожалуйста, предоставьте любую возможную помощь, чтобы облегчить это.
Мой ноутбук имеет 8 ГБ оперативной памяти и процессор Intel i7 5600U @ 2,6 ГГц (Broadwell) с 2 ядрами и 4 потоками. Набор команд включает SSE4.2, AVX, AVX2, FMA3 и TSX.
Ведущие записи по языку
- n = 40 в Rust с использованием CryptoMiniSat, автор Anders Kaseorg. (В гостевой виртуальной машине Lubuntu под Vbox.)
- n = 35 в C ++ с использованием библиотеки BuDDy, автор Christian Seviers. (В гостевой виртуальной машине Lubuntu под Vbox.)
- n = 34 в клинго Андерс Касорг. (В гостевой виртуальной машине Lubuntu под Vbox.)
- n = 31 в Rust от Anders Kaseorg.
- n = 29 в Clojure от NikoNyrh.
- n = 29 в С по Bartavelle.
- n = 27 в Хаскеле по Бартавелле
- n = 24 в пари / гп по алефале.
- n = 22 в Python 2 + pypy мной.
- n = 21 в Mathematica от alephalpha. (Self сообщается)
Будущие награды
Теперь я дам 200 баллов за каждый ответ, который за две минуты достигнет n = 80 на моей машине.
Ответы:
Rust + CryptoMiniSat , n ≈ 41
src/main.rs
Cargo.toml
Как это устроено
Это делает рекурсивный поиск по дереву всех частичных назначений префиксов массива Y / N, используя решатель SAT, чтобы на каждом шаге проверять, является ли текущее частичное назначение последовательным, и сокращать поиск, если нет. CryptoMiniSat является подходящим решателем SAT для этой работы благодаря специальной оптимизации для предложений XOR.
Три семейства ограничений
S i ⊕ S k + i ⊕ D ki , для 1 ≤ k ≤ n - 2, 0 ≤ i ≤ n - k ;
D ki 1 ∨ D ki 2 ∨ ¬ A k , для 1 ≤ k ≤ n - 2, 0 ≤ i 1 < i 2 ≤ n - k ;
¬ Д ки 1 ∨ ⋯ ∨ ¬ Д ки п - к - 1∨ к , для 1 ≤ K ≤ N - 2, 0 ≤ я 1 <⋯ < я п - к - 1 ≤ п - к ;
за исключением того, что в качестве оптимизации S 0 принудительно устанавливается в false, так что D k 0 просто равно S k .
источник
cargo build
получу--- stderr CMake Error: Could not create named generator Visual Studio 14 2015 Win64
Ржавчина, n ≈
30 или31 или 32На моем ноутбуке (два ядра i5-6200U) это происходит через n = 1,…, 31 за 53 секунды, используя около 2,5 ГБ памяти или через n = 1,…, 32 за 105 секунд, используя около 5 ГиБ памяти. Скомпилируйте
cargo build --release
и запуститеtarget/release/correlations
.src/main.rs
Cargo.toml
Попробуйте онлайн!
У меня также есть немного более медленный вариант, использующий намного меньше памяти.
источник
C ++ с использованием библиотеки BuDDy
Другой подход: иметь двоичную формулу (в виде двоичной диаграммы принятия решений ), которая принимает биты в
S
качестве входных данных и является истинной, если она дает некоторые фиксированные значенияY
илиN
в определенных выбранных положениях Если эта формула не является константой false, выберите свободную позицию и выполните рекурсивный тест, пытаясь одновременноY
иN
. Если свободной позиции нет, мы нашли возможное выходное значение. Если формула является константой false, вернитесь назад.Это работает относительно разумно, потому что существует так мало возможных значений, что мы можем часто возвращаться назад. Я попробовал аналогичную идею с SAT Solver, но это оказалось менее успешным.
Чтобы скомпилировать с Debian 8 (Джесси), установите
libbdd-dev
и сделайтеg++ -std=c++11 -O3 -o hb hb.cpp -lbdd
. Может быть полезно увеличить первый аргументbdd_init
еще больше.источник
Клинго, n ≈
30 или 3134Я был немного удивлен, увидев, что пять строк кода Clingo обогнали моё решение Rust методом «грубой силы» и подошли очень близко к решению Кристиана BuDDy - похоже, оно тоже побеждает с более высоким ограничением по времени.
corr.lp
corr.sh
источник
bdd_init
может помочь более высокое первое значение , или позволяющее увеличить таблицу узлов, вызвавbdd_setmaxincrease
значение, значительно превышающее значение по умолчанию 50000. - Используете ли вы измененную версию моей программы?--configuration=crafty
(jumpy
иtrendy
дайте аналогичные результаты).Пари / ГП , 23
По умолчанию Par / GP ограничивает размер стека до 8 МБ. Первая строка кода
default(parisize, "4g")
устанавливает это ограничение в 4 ГБ. Если он все еще дает стек переполнения, вы можете установить его на 8 ГБ.источник
Clojure, 29 в
7538 секунд, 30 в 80 и 31 в 165Время работы от Intel i7 6700K , использование памяти менее 200 МБ.
project.clj (использует многопоточность com.climate / claypoole ):
Исходный код:
Решение грубой силы, каждый поток проходит через подмножество диапазона (2 ^ 12 элементов) и создает набор целочисленных значений, которые указывают на обнаруженные шаблоны. Затем они «объединяются» вместе и, таким образом, рассчитывается различное количество. Я надеюсь, что код не слишком сложен, чтобы следовать даже при использовании макросы многопоточности . Я
main
запускаю тест несколько раз, чтобы разогреть JVM.Обновление: перебирает только половину целых чисел, получает тот же результат из-за симметрии. Также пропускаются числа с большим количеством битов в нижней половине числа, поскольку они также создают дубликаты.
Готовый Uberjar ( v1 ) (3,7 МБ):
Результаты на разных аппаратных средствах, ожидаемое время выполнения
O(n * 2^n)
?Вы можете легко сделать это однопоточным и избежать зависимости от третьих сторон, используя стандарт для:
Хорошо, встроенный pmap также существует, но у claypoole больше возможностей и настраиваемость.
источник
Mathematica, n = 19
нажмите alt +. прервать и результат будет напечатан
источник
Математика, 21
Для сравнения ответ Jenny_mathy дает
n = 19
на моем компьютере.Самая медленная часть
Tr@IntegerDigits[#, 2] &
. Жаль, что Mathematica не имеет встроенного веса Хэмминга.Если вы хотите проверить мой код, вы можете загрузить бесплатную пробную версию Mathematica .
источник
AC версия, используя встроенный popcount
Работает лучше
clang -O3
, но также работает, если у вас естьgcc
.источник
Haskell, (неофициальное n = 20)
Это просто наивный подход - пока без каких-либо оптимизаций. Я задавался вопросом, насколько хорошо это будет против других языков.
Как это использовать (если у вас есть платформа haskell ):
approx_corr.hs
(или любое другое имя, соответственно измените следующие шаги)ghc approx_corr.hs
approx_corr.exe
n
Код:
источник
main = putStrLn "Hello World!"
?Data.Bits
Модуль может быть полезным. Для вашего основного цикла вы можете использовать что-то вродеmain = do maxn <- getmax; t0 <- gettime; loop 1
гдеloop n|n==maxn = return ()
иloop n = do printresult n (f n); t <- gettime; printtime (t-t0); loop (n+1)
.getmax
Например,getArgs
можно использовать аргументы программы.Решение Haskell, использующее popCount и управляемый вручную параллелизм
Обобщение:
ghc -rtsopts -threaded -O2 -fllvm -Wall foo.hs
(бросьте
-llvm
если это не работает)Бегать :
./foo +RTS -N
источник
-O3
, и может быть быстрее с-O3 -fllvm
...Python 2 + pypy, n = 22
Вот действительно простое решение Python в качестве своего рода базового теста.
источник