Вот текстовый файл ASCII объемом 1,2 Мб, содержащий текст « Моби-Дика» Германа Мелвилла ; или Кит . Ваша задача состоит в том, чтобы написать программу или функцию (или класс и т. Д. - см. Ниже), которым будет присваиваться этот файл по одному символу за раз, и на каждом шаге должен угадываться следующий символ.
Это вызов кода . Ваша оценка будет
2*L + E
где L
- размер вашего представления в байтах, и E
это количество символов, которое он угадывает неправильно. Самый низкий балл побеждает.
Дальнейшие подробности
Ваша заявка будет программой или функцией (и т. Д.), Которая будет вызываться или вызываться или отправлять данные несколько раз. (1215235 раз, чтобы быть точным.) Когда он вызывается в n- й раз, ему присваивается n- й символ whale.txt
или, whale2.txt
и он должен вывести свое предположение для ( n + 1 ) -го символа. E
Компонент его счет будет общее количество символов , которые он не угадает.
В большинстве представлений необходимо сохранять некоторое состояние между вызовами, чтобы они могли отслеживать, сколько раз они были вызваны и каковы были предыдущие входные данные. Вы можете сделать это, записав во внешний файл, используя static
или глобальные переменные, передав класс, а не функцию, используя монаду состояния или что-либо еще, что работает для вашего языка. Ваша заявка должна включать любой код, необходимый для инициализации его состояния перед первым вызовом.
Ваша программа должна выполняться детерминистически, так что она всегда делает одни и те же предположения при одинаковых входных данных (и, следовательно, всегда получает один и тот же результат).
Ваш ответ должен включать не только ваше представление, но и код, который вы использовали для расчета E
части его оценки. Это не обязательно должно быть написано на том же языке, что и ваше представление, и не будет учитываться при подсчете байтов. Вам предлагается сделать его читабельным.
Что касается интерфейса между вашей отправкой и этой программой для подсчета очков, все в порядке, если ваша программа всегда выдает один байт вывода до получения следующего байта ввода. (Так, например, вы не можете просто передать ему строку, содержащую все входные данные, и получить строку обратно, содержащую весь выходной.)
Вы должны запустить свою тестовую программу и рассчитать / проверить свой счет перед отправкой заявки. Если ваша заявка идет слишком медленно, чтобы вы могли проверить ее оценку, тогда она не может участвовать в соревнованиях, даже если вы знаете, какой будет ее оценка в принципе.
L
Компонент вашего счета будет рассчитываться в соответствии с обычными правилами для вызовов кода для гольфа. Если ваша заявка будет содержать несколько файлов, обратите внимание на правила оценки и структуру каталогов в этом случае. Любые данные, которые использует ваш код, должны быть включены в ваш L
счет.
Вы можете импортировать существующие библиотеки, но не можете загружать любые другие внешние файлы, и ваш код может не получить доступ к whale.txt
илиwhale2.txt
Файл любым способом, кроме описанного выше. Вы не можете загружать предварительно обученные нейронные сети или другие источники статистических данных. (Можно использовать нейронные сети, но вы должны включить данные о весе в свое представление и сосчитать их в счетчике байтов.) Если по какой-то причине в вашем языке или библиотеках есть функция, предоставляющая весь или весь текст Moby Dick Вы не можете использовать эту функцию. Кроме того, вы можете использовать любые другие встроенные или библиотечные функции, которые вам нравятся, в том числе связанные с обработкой текста, предсказанием или сжатием, если они являются частью вашего языка или его стандартных библиотек. Для более экзотических, специализированных подпрограмм, которые включают источники статистических данных, вы должны будете реализовать их самостоятельно и включить в свой счетчик байтов.
Вполне вероятно, что некоторые материалы будут включать компоненты, которые сами генерируются кодом. Если это так, пожалуйста, включите в свой ответ код, который использовался для их создания, и объясните, как это работает . (Пока этот код не нужен для запуска вашего представления, он не будет включен в ваш счетчик байтов.)
По историческим причинам существует две версии файла, и вы можете использовать любую из них в ответе. В whale2.txt
(ссылка выше) текст не переносится, поэтому новые строки появляются только в конце абзацев. В оригинале whale.txt
текст оборачивается на ширину в 74 символа, поэтому вы должны прогнозировать конец каждой строки, а также прогнозировать текст. Это делает задачу более трудной, поэтому whale2.txt
рекомендуется для новых ответов. Оба файла имеют одинаковый размер, 1215236 байт.
Подводя итог, все ответы должны включать в себя следующее:
- Ваша подача сама. (Код плюс любые файлы данных, которые он использует - это могут быть ссылки, если они большие.)
- Объяснение того, как работает ваш код. Пожалуйста, объясните метод ввода / вывода, а также как он предсказывает следующий символ. Объяснение вашего алгоритма важно, и хорошие объяснения принесут мне награду.
- Код, который вы использовали для оценки вашего счета. (Если это совпадает с предыдущим ответом, вы можете просто дать ссылку на него.)
- Любой код, который вы использовали для создания вашего представления, вместе с объяснением этого кода. Это включает в себя код, который вы использовали для оптимизации параметров, создания файлов данных и т. Д. (Это не учитывается при подсчете байтов, но должно быть включено в ваш ответ).
Leaderboard
щедроты
Время от времени я буду предлагать награды, чтобы поощрять различные подходы.
Первый, 50 баллов, был присужден А. Рексу за лучший результат на тот момент.
Второе, 100 баллов, было также присуждено А. Рексу за тот же ответ, потому что они добавили очень хорошее объяснение к своему существующему ответу.
Следующая награда, 200 баллов , будет присуждена
- Конкурентный ответ, который использует новую технику. (Это будет основано на моем субъективном суждении, поскольку в награду входит мой представитель, но вы можете доверять мне, чтобы быть справедливым. Обратите внимание, что ваш ответ должен содержать достаточно объяснений, чтобы я мог понять, как это работает!) Такой ответ не нужен Не берите наивысший балл, это просто необходимо сделать достаточно хорошо по сравнению с существующими ответами. Я особенно заинтересован в том, чтобы увидеть решения, основанные на рекуррентных нейронных сетях, но я буду награждать награду всем, что кажется достаточно отличным от марковских моделей, которые доминируют в текущих высших оценках.
Или же:
- Любой, кто бьет лучший результат А. Рекса (в настоящее время 444444), используя любой метод.
После получения награды в 200 баллов я, скорее всего, предложу 400 баллов, соответственно обновив требования.
источник
Ответы:
/// , 2 * 1 + 1020874 = 1020876
Печатает пробел.
источник
Node.js, 2 * 224 + 524279 = 524727
Пожалуйста, обратитесь к журналу изменений в конце этого поста для обновления результатов.
Функция, принимающая и возвращающая байт.
Он состоит из простой модели PPM, которая просматривает последние 8 символов, чтобы предсказать следующий.
Мы доверяем шаблону длины L, когда встречаемся с ним по крайней мере T [L] раз, где T - массив произвольных порогов: [1,1,2,1,2,3,5,2] . Кроме того, мы всегда доверяем шаблону, чей первый символ совпадает
[A-Z '"(]
.Мы выбираем самый длинный доверенный шаблон и возвращаем прогноз с наивысшей оценкой, связанной с этим шаблоном во время вызова.
Примечания
Это, очевидно, не оптимизировано для скорости, но на моем ноутбуке оно работает примерно за 15 секунд.
Если бы нам было позволено повторить процесс несколько раз подряд без сброса модели, число ошибок сравнялось бы с ~ 268000 после 5 итераций.
Текущий показатель успеха функции прогнозирования составляет ~ 56,8%. Как заметил @immibis в комментариях, если плохие и правильные догадки смешиваются вместе, результат даже едва читаем.
Например, этот фрагмент в конце книги:
будет выглядеть так:
Заменив неверные догадки на подчеркивания, мы лучше понимаем, что получилось с этой функцией:
Примечание : приведенный выше пример был создан с предыдущей версией кода, работающей с первой версией входного файла.
Тестовый код
Журнал изменений
источник
sidg tlanses,oeth to, shuld hottut tild aoersors Ch, th! Sa, yr! Sheu arinning whales aut ihe e sl he traaty of rrsf tg homn Bho dla tiasot a shab sor ty, af etoors tnd hocket sh bts ait mtubb tiddin tis aeewnrs, dnhost maundy cnd sner aiwt d boelh cheugh -aaieiyns aasiyns taaeiins! th, tla
. Иногда удается получить несколько полных слов. Какwhales
.Perl, 2 · 70525 + 326508 = 467558
предсказатель
Чтобы запустить эту программу, вам нужен этот файл , который должен быть назван
B
. (Вы можете изменить это имя файла во втором экземпляре символаB
выше.) Ниже описано, как создать этот файл.Программа использует комбинацию моделей Маркова в основном как в этом ответе пользователя 2699 , но с несколькими небольшими модификациями. Это создает распределение для следующего символа. Мы используем теорию информации, чтобы решить, принимать ли ошибку или тратить биты памяти на
B
подсказки кодирования (и если да, то как). Мы используем арифметическое кодирование для оптимального хранения дробных битов из модели.Длина программы составляет 582 байта (включая ненужный заключительный
B
символ новой строки), а длина двоичного файла составляет 69942 байта, поэтому по правилам оценки нескольких файлов мы получаемL
582 + 69942 + 1 = 70525.Программа почти наверняка требует 64-битной (little-endian?) Архитектуры. Для запуска
m5.large
экземпляра на Amazon EC2 требуется примерно 2,5 минуты .Тестовый код
Тестовый жгут предполагает, что отправка находится в файле
submission.pl
, но это можно легко изменить во второй строке.Сравнение текста
Этот образец (выбранный в другом ответе ) встречается довольно поздно в тексте, поэтому модель достаточно развита к этому моменту. Помните, что модель дополнена 70 килобайтами «подсказок», которые напрямую помогают ей угадывать символы; он не управляется просто коротким фрагментом кода выше.
Генерация подсказок
Следующая программа принимает точный код отправки выше (при стандартном вводе) и генерирует точный
B
файл выше (при стандартном выводе):Это занимает примерно столько же времени, сколько и представление, поскольку выполняет аналогичные вычисления.
объяснение
В этом разделе мы попытаемся описать, что делает это решение достаточно подробно, чтобы вы могли «попробовать его дома» самостоятельно. Основной метод, который отличает этот ответ от других, - это несколько разделов, называемых механизмом «перемотки», но прежде чем мы доберемся до этого, нам нужно настроить основы.
модель
Основным компонентом решения является языковая модель. Для наших целей модель - это то, что занимает некоторое количество английского текста и возвращает распределение вероятностей для следующего символа. Когда мы используем модель, текст на английском языке будет иметь некоторый (правильный) префикс Moby Dick. Обратите внимание, что желаемым результатом является распределение , а не просто предположение для наиболее вероятного символа.
В нашем случае мы по существу используем модель в этом ответе пользователя 2699 . Мы не использовали модель из ответа с наивысшим баллом (кроме нашего) Андерса Касеорга именно потому, что нам не удалось извлечь распределение, а не единственное лучшее предположение. Теоретически, этот ответ вычисляет средневзвешенное геометрическое значение, но мы получили несколько плохие результаты, когда интерпретировали это слишком буквально. Мы «украли» модель из другого ответа, потому что наш «секретный соус» - не модель, а общий подход. Если у кого-то есть «лучшая» модель, тогда он сможет добиться лучших результатов, используя остальные наши методы.
Как примечание, большинство методов сжатия, таких как Lempel-Ziv, можно рассматривать как «модель языка», хотя, возможно, придется немного щуриться. (Это особенно сложно для того, что выполняет преобразование Берроуза-Уилера!) Также обратите внимание, что модель user2699 является модификацией модели Маркова; по сути, ничто иное не является конкурентоспособным для этой задачи или, возможно, даже для моделирования текста в целом.
Общая архитектура
В целях понимания полезно разбить общую архитектуру на несколько частей. С точки зрения самого высокого уровня, должен быть небольшой код управления состоянием. Это не особенно интересно, но для полноты картины мы хотим подчеркнуть, что в каждой точке программы запрашивается следующая догадка, в ней есть правильный префикс Moby Dick. Мы никоим образом не используем наши прошлые неверные догадки. Ради эффективности, языковая модель, вероятно, может повторно использовать свое состояние из первых N символов для вычисления своего состояния для первых (N + 1) символов, но в принципе она может пересчитывать вещи с нуля каждый раз, когда она вызывается.
Давайте отложим этот основной «драйвер» программы и заглянем внутрь части, которая угадывает следующий символ. Концептуально это помогает разделить три части: языковую модель (обсуждаемую выше), файл «подсказок» и «интерпретатор». На каждом шаге переводчик будет запрашивать у языковой модели распределение следующего символа и, возможно, считывать некоторую информацию из файла подсказок. Тогда он объединит эти части в догадку. Точно какая информация содержится в файле подсказок, а также как она используется, будет объяснено позже, но пока она помогает мысленно разделить эти части. Обратите внимание, что в плане реализации файл подсказок является буквально отдельным (двоичным) файлом, но он мог быть строкой или чем-то другим, хранящимся внутри программы. В качестве приближения
Если используется стандартный метод сжатия, такой как bzip2, как в этом ответе , файл «подсказок» соответствует сжатому файлу. «Интерпретатор» соответствует декомпрессору, в то время как «языковая модель» немного неявна (как упомянуто выше).
Зачем использовать файл подсказки?
Давайте выберем простой пример для дальнейшего анализа. Предположим, что текст состоит из
N
длинных символов и хорошо аппроксимируется моделью, в которой каждый символ (независимо) представляет собой буквуE
с вероятностью чуть меньше половины,T
аналогично с вероятностью чуть меньше половины иA
с вероятностью 1/1000 = 0,1%. Давайте предположим, что другие символы невозможны; в любом случае,A
это очень похоже на случай ранее невидимого символа на ровном месте.Если мы работаем в режиме L 0 (как большинство, но не все другие ответы на этот вопрос), нет лучшей стратегии для переводчика, чем выбрать один из
E
иT
. В среднем примерно половина символов будет правильной. Так что E ≈ N / 2 и оценка ≈ N / 2 тоже. Однако, если мы используем стратегию сжатия, мы можем сжать до чуть более одного бита на символ. Поскольку L считается в байтах, мы получаем L ≈ N / 8 и, таким образом, получаем значение ≈ N / 4, что вдвое больше, чем в предыдущей стратегии.Достижение этой скорости чуть более одного бита на символ для этой модели немного нетривиально, но одним из методов является арифметическое кодирование.
Арифметическое кодирование
Как известно, кодирование - это способ представления некоторых данных с использованием битов / байтов. Например, ASCII - это 7-битная / символьная кодировка английского текста и связанных с ним символов, и это кодировка исходного файла Moby Dick, который мы рассматриваем. Если некоторые буквы встречаются чаще, чем другие, то кодирование с фиксированной шириной, например ASCII, не является оптимальным. В такой ситуации многие люди тянутся к кодированию Хаффмана . Это оптимально, если вам нужен фиксированный (без префикса) код с целым числом битов на символ.
Однако арифметическое кодирование еще лучше. Грубо говоря, он может использовать «дробные» биты для кодирования информации. В Интернете доступно множество руководств по арифметическому кодированию. Здесь мы пропустим детали (особенно практической реализации, которая может быть немного хитрой с точки зрения программирования) из-за других ресурсов, доступных онлайн, но если кто-то пожалуется, возможно, этот раздел может быть расширен более подробно.
Если у вас есть текст, фактически сгенерированный известной языковой моделью, то арифметическое кодирование обеспечивает по существу оптимальное кодирование текста из этой модели. В некотором смысле это «решает» проблему сжатия для этой модели. (Таким образом, на практике основная проблема заключается в том, что модель неизвестна, и некоторые модели лучше, чем другие, моделируют человеческий текст.) Если в этом конкурсе не было допущено ошибок, то на языке предыдущего раздела Одним из способов решения этой проблемы было бы использование арифметического кодера для генерации файла «подсказок» из языковой модели, а затем использование арифметического декодера в качестве «интерпретатора».
В этом по существу оптимальном кодировании мы в конечном итоге тратим -log_2 (p) битов на символ с вероятностью p, а общая скорость кодирования - энтропия Шеннона . Это означает, что для символа с вероятностью, близкой к 1/2, требуется около одного бита для кодирования, а для символа с вероятностью 1/1000 - около 10 битов (поскольку 2 ^ 10 составляет примерно 1000).
Но показатель выигрыша для этой задачи был выбран правильно, чтобы избежать сжатия в качестве оптимальной стратегии. Мы должны найти способ сделать несколько ошибок в качестве компромисса для получения более короткого файла подсказок. Например, одна стратегия, которую можно попробовать, - это простая стратегия ветвления: мы обычно пытаемся использовать арифметическое кодирование, когда можем, но если распределение вероятностей из модели «плохое», мы просто угадываем наиболее вероятный символ и не не пытайтесь его кодировать.
Зачем делать ошибки?
Давайте проанализируем предыдущий пример, чтобы мотивировать, почему мы можем захотеть делать ошибки «намеренно». Если мы используем арифметическое кодирование для кодирования правильного символа, мы потратим примерно один бит в случае с
E
илиT
, но около десяти бит в случае сA
.В целом, это довольно хорошая кодировка, тратящая чуть больше на символ, хотя есть три возможности; в принципе,
A
это маловероятно, и мы не заканчиваем тратить соответствующие десять бит слишком часто. Однако разве не было бы неплохо, если бы мы могли просто сделать ошибку вместо случаяA
? В конце концов, метрика для проблемы считает, что 1 байт = 8 бит длины эквивалентен 2 ошибкам; таким образом, кажется, что следует предпочесть ошибку, а не тратить более 8/2 = 4 бита на символ. Тратить больше байта на сохранение одной ошибки определенно звучит неоптимально!Механизм «перемотки»
В этом разделе описывается основной умный аспект этого решения, который позволяет обрабатывать неправильные догадки без затрат на длину.
Для простого примера, который мы анализировали, механизм перемотки особенно прост. Интерпретатор читает один бит из файла подсказок. Если это 0, он угадывает
E
. Если это 1, он угадаетT
. В следующий раз, когда он вызывается, он видит правильный символ. Если файл подсказки настроен правильно, мы можем убедиться, что в случаеE
илиT
интерпретатор правильно угадывает. Но как насчетA
? Идея механизма перемотки заключается в том, чтобы просто не кодироватьA
вообще . Точнее, если интерпретатор позже узнает, что правильный символ былA
, он метафорически « перематывает ленту»: он возвращает бит, который он прочитал ранее. Бит, который он читает, намеревается закодироватьE
илиT
, но не сейчас; это будет использовано позже. В этом простом примере это в основном означает, что он продолжает угадывать один и тот же символ (E
илиT
) до тех пор, пока не получит его правильно; затем он читает еще один бит и продолжает идти.Кодировка для этого файла подсказок очень проста: превратить все
E
s в 0 бит иT
s в 1 бит, полностью игнорируяA
s. В результате анализа в конце предыдущего раздела эта схема допускает некоторые ошибки, но снижает общий балл, не кодируя ни одну изA
s. В меньшем эффекте, он на самом деле экономит на длину намеков файла , а также, потому что мы в конечном итоге , используя ровно один бит для каждогоE
иT
, вместо того , чтобы немного больше , чем немного.Маленькая теорема
Как мы решаем, когда сделать ошибку? Предположим, что наша модель дает нам распределение вероятности P для следующего символа. Мы разделим возможные символы на два класса: кодированные и не кодированные . Если правильный символ не закодирован, то мы в конечном итоге будем использовать механизм «перемотки», чтобы принять ошибку бесплатно. Если правильный символ закодирован, то мы будем использовать какой-то другой дистрибутив Q для его кодирования с использованием арифметического кодирования.
Но какое распределение Q мы должны выбрать? Нетрудно понять, что все кодированные символы должны иметь более высокую вероятность (в P), чем не кодированные символы. Также в дистрибутив Q должны входить только кодированные символы; в конце концов, мы не кодируем другие, поэтому мы не должны «тратить» на них энтропию. Немного сложнее увидеть, что распределение вероятностей Q должно быть пропорционально P на кодированных символах. Объединение этих наблюдений означает, что мы должны кодировать наиболее вероятные символы, но, возможно, не менее вероятные символы, и что Q - это просто P, масштабируемый на кодированных символах.
Более того, оказывается, что есть классная теорема о том, какой «обрез» нужно выбрать для кодирующих символов: вы должны кодировать символ, если он по меньшей мере равен 1 / 5,393 с той же вероятностью, что и другие кодированные символы вместе взятые. Это «объясняет» появление, казалось бы, случайной константы
5.393
ближе к концу указанной выше программы. Число 1 / 5,393 ≈ 0,18542 является решением уравнения -p log (16) - p log p + (1 + p) log (1 + p) = 0 .Возможно, разумно написать эту процедуру в коде. Этот фрагмент находится в C ++:
Собираем все вместе
Предыдущий раздел, к сожалению, немного технический, но если мы соберем вместе все остальные части, структура будет следующей. Всякий раз, когда программу просят предсказать следующий символ после заданного правильного символа:
Кодировка файла подсказок работает аналогично. В этом случае программа знает, какой правильный следующий символ. Если это символ, который должен быть закодирован, тогда, конечно, следует использовать арифметический кодер на нем; но если это не кодированный символ, он просто не обновляет состояние арифметического кодировщика.
Если вы понимаете теоретико-информационный фон, такой как распределение вероятностей, энтропия, сжатие и арифметическое кодирование, но пытались и не смогли понять этот пост (за исключением того, почему теорема верна), дайте нам знать, и мы можем попытаться прояснить ситуацию. Спасибо за чтение!
источник
B
файла? Если да, то можете ли вы включить это в свой ответ?Python 3, 2 · 267 + 510193 = 510727
предсказатель
При этом используется взвешенная байесовская комбинация моделей Маркова порядка 0,…, 16 с весами [1, 6, 12, 30, 65, 99, 87, 117, 118, 89, 95, 118, 96, 184, 126, 219, 126].
Результат не очень чувствителен к выбору этих весов, но я оптимизировал их, потому что я мог, используя тот же алгоритм подъема на поздние этапы приема, который я использовал в своем ответе на вопрос «Собрать большинство в Сенате» , где каждая кандидатская мутация только увеличение ± 1 до одного веса.
Тестовый код
источник
b"\0\3\6\r\34'&-20'\22!P\n[\26"
это ascii представление весов, где небольшие непечатаемые значения экранируются в восьмеричном виде.Python 3 ,
2 * 279 + 592920 = 5934782 * 250 + 592467 = 5929672 * 271 + 592084 = 5926262 * 278 + 592059 = 5926152 * 285 + 586660 = 5872302 * 320 + 585161 = 5858012 * 339 + 585050 = 585728Попробуйте онлайн!
Функция, использующая глобальные переменные. Изучая, как это происходит, выстраивая модель на уровне слова: учитывая то, что он видел в этом слове , какой персонаж чаще всего встречается? По мере того, как вводится больше информации, он довольно хорошо изучает обычные слова из текста, а также изучает наиболее распространенный символ для начала следующего слова.
Например:
В начале это не очень хорошо, но к концу появляются большие части реальных слов. Резервный вариант - это пробел, а после единственного пробела это «а», если предыдущей буквой не было «nedtfo», цифры, дефиса или апострофа. Он также агрессивно предсказывает разрывы строк после 71 символа, или если после 66 ожидался пробел. Оба из них были только настроены на данные («t» гораздо чаще встречается после пробела, но чаще уже предсказывалось, поэтому » «это лучшее предположение за пределами этих шести особых случаев).
Изучение того, какие пары слов были вместе, и предпосевное отображение оказались бесполезными.
В итоге получается такой текст:
что соответствует этой части ввода:
Вы можете видеть, где, в частности, правильные существительные получаются довольно хорошо, но концы слов в основном правильные. Когда он видит «доу», он ожидает «сомнения», но как только появляется «я», он получает «дублон».
Если вы запускаете его второй раз с той же моделью, которую он только что построил, он сразу же получает правильные 92 КБ (51,7% -> 59,3%), но это всегда чуть меньше 60% от второй итерации.
Код измерения находится в ссылке TIO, или вот немного лучшая версия:
guess.txt
имеет угаданный вывод в конце.источник
C ++, оценка: 2 * 132 + 865821 = 866085
Спасибо @Quentin за сохранение 217 байтов!
Очень простое решение, которое, учитывая символ, просто выводит символ, который чаще всего появляется после вводимого символа.
Проверьте счет с:
Изменить: Использование
whale2.txt
дает лучший результат.источник
L
чтобы сохранить группу символов :)Python, 2 * 516 + 521122 = 522154
Алгоритм:
В еще одном представлении Python этот алгоритм вычисляет наиболее вероятную следующую букву, просматривая последовательности длиной 1, ..., l. Используется сумма вероятностей, и есть несколько приемов, чтобы получить лучшие результаты.
Результаты:
В основном тарабарщина, хотя вы можете заметить, что она появляется на случайной фразе, такой как «Отец Мэппл».
Тестовый код:
Довольно просто, выводит несколько примеров текста в разных точках. Использует whale2.txt, так как это позволяет избежать дополнительной логики для вычисления новых строк.
источник
С (gcc) ,
6797876528928476 байт,679619652740 неверных догадокПопробуйте онлайн!
Обновление: ~ 27000 очков с обновленным файлом, 16 очков (8 байт) с улучшенной функцией игры в гольф.
объяснение
Это работает так: когда код проходит по тексту, он запоминает последний символ, завершивший любую заданную 4-символьную последовательность, и возвращает это значение. В некоторой степени аналогично подходу Арно, описанному выше, но полагается на присущую ему вероятность двух заданных последовательностей из 4 символов, заканчивающихся одинаково.
Де-golfed:
источник
sh + bzip2, 2 * 364106 = 728212
2 * 381249 + 0 = 762498сопровождаемый сжатым bzip2 whale2.txt с пропущенным первым байтом
Игнорирует его ввод; выводит правильный ответ. Это обеспечивает базовую линию на одном конце; Даниеро обеспечивает базовую линию на другом конце.
Скрипт строителя:
Испытательный жгут I / O (tcc; отрезать первую строку для gcc). Этот тестовый комплект может быть использован любым пользователем на подходящей платформе, которая представляет полную программу, которая ожидает ввода / вывода для чтения / записи. Он использует байтовый ввод-вывод, чтобы избежать мошенничества. Дочерняя программа должна сбрасывать вывод после каждого байта, чтобы избежать блокировки.
источник
but may not load any other external files, and your code may not access the whale.txt file in any way other than described above.
пункт?nth
времени, ей будет присвоен n-й символwhale.txt
или,whale2.txt
и она должна вывести свое предположение для(n+1)th
характер." - Как выполняется это требование? Код отображает весь текстwhale.txt
каждый раз, когда он выполняется.Python 3 , 879766
Попробуйте онлайн!
...
///
Ответ, который печатает пробел, получает 10 голосов, в то время как мой код может получить только 3 ...Объяснение:
Для каждого персонажа программа:
frequency[prev][char]
frequency[char]
которые имеют общий балл
Поскольку нет никакого способа загрузить большой файл в TIO (кроме как спросить Денниса), пример запуска по ссылке TIO запускает программу только для небольшой части текста.
По сравнению со старым ответом, на этот раз на 362 больше неправильных символов, но код короче на 255 байт. Множитель заставляет мое представление иметь более низкий балл.
источник
C #, 378 * 2 + 569279 = 570035
Этот подход использует справочную таблицу, чтобы узнать наиболее распространенный символ, который следует за данной строкой. Клавиши справочной таблицы имеют максимум 4 символа, поэтому функция сначала обновляет справочную таблицу текущим символом, а затем просто проверяет, какой символ наиболее вероятен после 4 предыдущих, включая текущий. , Если эти 4 символа не найдены в справочной таблице, она печатает пробел.
Эта версия использует
whale2.txt
файл, так как это значительно улучшает количество удачных догадок.Ниже приведен код, используемый для проверки класса:
Код выполняется всего за 2 секунды. Для справки: вот что я получаю, когда меняю размер ключей таблицы соответствия (включая результаты второго запуска без сброса модели):
Было бы интересно узнать, почему размер ключа в 4 символа является лучшим выбором в этом алгоритме.
Сравнение текста
Оригинал:
Воссоздал:
Догадки:
Журнал изменений
whale2.txt
и, следовательно, удален оптимизация.источник
Java 7, 1995 символов, (1995 * 2 + 525158) 529148
Java - отстой для небольших программ. Во всяком случае, я попробовал несколько чрезвычайно сложных и хитрых подходов, которые дали удивительно дерьмовые результаты. Впоследствии я вернулся и просто применил простой подход, который привел к уменьшению размера программы и лучшим результатам.
Этот подход на самом деле очень прост. Он вслепую подает предыдущие символы x (в дополнение ко всем подстрокам этих символов) в хеш-таблицу, сопоставленную с текущим символом. Затем он отслеживает, какие шаблоны наиболее точно предсказывают текущий символ. Если шаблоны, которые предшествуют определенным символам, встречаются несколько раз, они преуспевают в предсказании символа. Он дает приоритет более длинным строкам и приоритет тому, какой символ чаще всего следует за данной строкой. Этот алгоритм ничего не знает о типе документа или английском языке.
Я остановился на использовании 9 символов и попытался сопоставить целые слова в этих предыдущих 9 символах, когда это возможно. Если вы не пытаетесь сопоставлять слова в строках, оптимальная длина составляет 6 символов, что приводит к еще нескольким тысячам неправильных предсказаний.
Одним интересным наблюдением было то, что использование 20 символов в первый раз приводило к ошибочным прогнозам, но при последующих проходах точность составляла 99,9%. Алгоритм был в основном способен запоминать книгу в перекрывающихся 20-байтовых кусках, и это было достаточно отчетливо, чтобы позволить ему вспомнить всю книгу за символ за раз.
источник
Python 3,
2 × 497 + 619608 = 6206022 × 496 + 619608 = 620600Я попытался сделать это самостоятельно, но в итоге получился худший вариант ответа Майкла Гомера. Я надеюсь, что это не сделает мой ответ полностью устаревшим.
Со временем создается словарь слов (грубо определяется как строки, оканчивающиеся на
или
\n
с учетом регистра и включая знаки препинания). Затем он ищет в этом словаре слова, начинающиеся с того, что ему до сих пор известно о текущем слове, сортирует результирующий список по частоте встречаемости (медленно) и догадывается, что следующий символ - следующий символ в наиболее распространенном совпадающем слове. Если у нас уже есть наиболее распространенное совпадающее слово или более не совпадающее слово существует, оно возвращается.
Это также создает отвратительно неэффективный словарь пар слов. При достижении границы слова он предполагает, что следующим символом является первая буква второго слова в наиболее часто встречающейся паре слов или
t
если совпадения нет. Это не очень умно, хотя. ПослеMoby
этого программа правильно угадывает, что следующий символ - это следующийD
, но затем она забывает все о контексте и обычно заканчивает тем, что называет кита «Moby Duck» (потому что слово «голландский», кажется, встречается чаще в первой половине текста ). Это было бы легко исправить, расставив приоритеты между парами слов над отдельными словами, но я ожидаю, что выигрыш будет незначительным (поскольку обычно он корректен с третьего символа, а пары слов не очень полезны в первую очередь).Я мог бы настроить это, чтобы лучше соответствовать предоставленному тексту, но я не думаю, что ручная настройка алгоритма, основанная на предварительных знаниях ввода, действительно соответствует духу игры, за исключением выбора t в качестве запасного символа после пробела ( и я, вероятно, не должен был этого делать), я избежал этого. Я проигнорировал известную длину строки входного файла и вместо этого вставил
\n
после каждых 13 пробелов - это почти наверняка очень плохое совпадение, главное намерение было сохранить разумную длину строки, а не совпадать с вводом.Код не очень быстрый (~ 2 часа на моем компьютере), но в целом получается примерно половина правильных символов (49%). Я ожидаю, что счет будет немного лучше, если продолжать
whale2.txt
, но я этого не сделал.Начало вывода выглядит так:
но в конце это выглядит немного больше как ... что-то. Мой любимый отрывок из ближе к концу книги,
выходит как
Это сделало бы Гнев Хана намного более запутанным. И «одинокий» → «покалывание» является особенно удовлетворительной заменой.
Изменить: один байт сохранен путем удаления постороннего пространства
счет
Это запускает программу для текста Moby Dick и выводит «прогнозируемый» текст на стандартный вывод, а также злоупотребляет stderr для записи счета. Я бы порекомендовал перенаправить вывод в файл.
источник
lambda i:i[1]
будет дешевле, чем иметь дело сoperator
?С ++, 2 · 62829 + 318786 = 444444
Чтобы запустить эту программу, вам нужен этот файл , который должен быть назван
C
.В программе используется та же комбинация марковских моделей, что и в нашем предыдущем ответе . Как и прежде, эта комбинация по сути является моделью из этого ответа пользователя 2699 , но с небольшими изменениями.
Видя, как в этом ответе используется та же самая модель, что и раньше, улучшение является лучшим теоретико-информационным механизмом, чем механизм «перемотки», описанный ранее. Это позволяет делать меньше ошибок, а также иметь меньшую общую длину. Сама программа не очень удачна, потому что она не является основным источником оценки.
Длина программы составляет 2167 байт (включая все вкладки для отступа и множество других ненужных символов, но перед тестовым кодом), а
C
длина двоичного файла составляет 60661 байт, поэтому по правилам оценки нескольких файлов мыL
оцениваем как 2167 + 60661 + 1 = 62829.Программа занимает приблизительно 8 минут для запуска на
m5.4xlarge
экземпляре в Amazon EC2 и использует чуть более 16 ГБ памяти. (Это чрезмерное использование памяти не является необходимым - мы просто не оптимизировали это либо.)источник
Python 3, 526640
274 байта, 526092 ошибки (при использовании
whale2.txt
). Это определенно способно к дальнейшему совершенствованию, но оно достигло стадии «достаточно хорошо, чтобы опубликовать».Идея состоит в том, чтобы хранить частоты всех серий 2, 3, 4, ..., 10 символов. Для каждой из этих длин L мы проверяем, соответствуют ли последние символы L-1 сохраненному шаблону; если это так, наше предположение g L является наиболее частым следующим символом, следующим за этим шаблоном. Таким образом, мы собираем до девяти догадок. Чтобы решить, какое предположение использовать, мы взвешиваем частоту каждого паттерна по длине до 8-й степени. Выбирается предположение с наибольшей суммой взвешенных частот. Если нет подходящих шаблонов, мы предполагаем пространство.
(Максимальная длина шаблона и весовой показатель были выбраны методом проб и ошибок, чтобы дать наименьшее количество неверных догадок.)
Вот моя неутешительная версия в процессе разработки:
И испытательный жгут:
Вот пример выходных данных в начале текста. Уже сейчас мы начинаем видеть возможность закончить общие слова после просмотра их первого письма (
in
,to
,and
,by
, а также, по- видимому,school
).Ближе к концу, все еще есть много ошибок, но также есть много очень хороших последовательностей (
shmage seashawks
например).Интересно взглянуть на некоторые ошибки и угадать, какое слово «ожидал» алгоритм. Например, после того
sail
, как программа оба раза предсказываетo
- дляsailor
, я полагаю. Или, опять же, после, a
того , как он ожидает -n
возможно, из-за обычного возникновения, and
.Changelog:
источник
Python 2, оценка: 2 * (407 + 56574) + 562262 = 676224
Выполняет поиск слов, соответствующих предыдущим символам, из списка
всехнаиболее используемых в тексте слов, отсортированных по количеству их вхождений.Код:
Данные: https://www.dropbox.com/s/etmzi6i26lso8xj/d?dl=0
Тестирование:
Изменить: Использование
whale2.txt
дает лучший результат.источник
С ++ (GCC), 725 × 2 + 527076 = 528526
Еще одна префиксная частота представления. Беги дальше
whale2.txt
и получай схожий (чуть хуже) счет, чем другие.Эта жадно находит самую длинную строку, которая начинается с суффикса истории, и, если есть несколько кандидатов, разрыв связи с более короткими строками.
Например: Если последние 7 символы
abcdefgh
, а строкаabcdefghi
иabcdefghj
появляется с наибольшей частотой во всех строках формыabcdefgh*
, на выходе будет либоi
илиj
, тай - брейке с более короткими суффиксами (bcdefgh
,cdefgh
, ...).По неизвестным причинам, больше чем 7, и мой компьютер не имеет достаточно оперативной памяти для его запуска. Даже с 7 мне нужно закрыть все веб-браузеры, чтобы запустить его.
Тестовый код:
Ungolfed:
Пример вывода:
Этот в конце текста. Большинство длинных слов предсказаны довольно точно (
intervals
,pivot-hole
,distance
)Прописные буквы не кажутся хорошими.
источник
Python 2, 756837
Использует что-то, что может быть цепями Маркова?
источник
zlib.decompress('...')
значение{'G?':' ', 'G;':' ','G"':' ',.......}
, иa
представляет собой словарь , который отображает от 2 символа 1 символ. В основном двухсимвольный вариант ответа Steadybox .xxd
,hexdump
,uuencode
, Или аналогичныеHaskell, (1904 + 1621 + 208548 + 25646) * 2 + 371705 = 847143
Пример:
Использует три предварительно вычисленных вспомогательных файла:
seqwords
содержит 236 наиболее распространенных слов.wordsseq
содержит сжатую LZMA последовательность этих слов, и для всех слов, не входящих в 236 наиболее распространенных, длину.dicttries
содержит для каждой длины слова дерево решений, которое содержит все оставшиеся слова. Из этих попыток записи выбираются по мере продвижения.Таким образом, мы достигаем значительно более низкого уровня ошибок, чем все другие схемы с потерями; к сожалению,
wordsseq
файл все еще слишком большой, чтобы быть конкурентоспособным.Вот законченная версия, которая создает файлы и выполняет анализ:
источник
С ++ (WIP), 1923 * 2 + 1017344 = 1021190
В существующем виде это решение является WIP и, следовательно, не вежливым. Кроме того, учитывая, что фактический размер кода едва влияет на оценку, я подумал, что сначала опубликую свой ответ, прежде чем начать микрооптимизацию.
(Полный код доступен здесь: https://github.com/BrainStone/MobyDickRNG - включает в себя полный поиск программы и семян)
Это решение основано на ГСЧ. Сначала я анализирую текст. Я создаю карту, которая подсчитывает вхождения двух последовательных символов. Затем я создаю карту распространения. Все это делается статически, поэтому должно соответствовать правилам.
Затем, пытаясь напечатать текст, я делаю поиск и вытаскиваю случайный символ из возможных. Хотя обычно это приводит к худшим результатам, чем просто вывод наиболее распространенного следующего письма, вполне возможно, что божьи семена будут давать лучшие результаты. Вот почему семя жестко закодировано. В настоящее время я ищу лучшее семя. И я обновлю этот ответ, как только найду лучшие семена. Так что оставайтесь в курсе!
Если кто-то хочет найти семена самостоятельно или использовать разные ГСЧ, не стесняйтесь раскошелиться на репо.
Метод, используемый для подсчета очков: https://github.com/BrainStone/MobyDickRNG/blob/master/src/search.cpp#L15
Обратите внимание, что хотя общая оценка на данный момент является наихудшей, она превосходит количество ошибок только при выводе пробелов. И велики шансы, что счет упадет, если проверить больше семян.
Изменения
Проверено семян: 0-50000. Счет: 2305 * 2 + 1017754 = 1022364
Проверено семян: 0-80000. Счет: 1920 * 2 + 1017754 = 1021594 (-770).
отправку ) Проверенные семена: 0-32000000. Счет: 1923 * 2 + 1017344 = 1021190 (-404)
источник
Рубин, 1164418 (ай)
Я просто хотел посмотреть, насколько хорошо я могу сделать, не проверяя другие ответы.
Я не уверен, разрешено ли это, потому что он включает в себя литерал, который я сгенерировал, анализируя файл, но даже если это не так, это не значит, что он может кого-то избить.
Как я сгенерировал
x
Сначала я сгенерировал
a.txt
следующее:Затем я сгенерировал
a.csv
:Затем я проанализировал его
x
с помощью следующего скрипта Ruby:Как я забил
источник
Python 3 , (146 * 2 + 879757) 880049 байт
Попробуйте онлайн!
Довольно простая таблица частот. Каждая позиция в строке соответствует текущему символу ascii (минус 10 = 0x0a = '\ n', самый низкий символ в файле), и символ в каждом индексе является наиболее частым следующим символом. Предполагая, что я рассчитал частоты правильно ...
Протестировано с кодом из теста user202729
источник
def f(c):return(" ">c)*c or"t ... e"[ord(c)-32]
?[Python 3] (644449 * 2 + 0) 1288898 баллов
Совершенная точность всего в 644449 байт
Полный код не может вписаться в ответ, поэтому я поместил его здесь и заменил большой двоичный строковый литерал на b '###' в тексте ответа.
Это генерируется с помощью следующего кода, где «updated.py» - это сгенерированный файл, а «cheatsheet.txt» - файл whale2.txt, начинающийся со второго символа.
Код можно выполнить, добавив следующее в конец файла «ified.py ». «whale2.txt» должен находиться в том же каталоге, что и «ified.py », а вывод будет записан в« out.txt ».
Этот ответ не имеет прямого доступа ни к whale.txt, ни к whale2.txt. Он использует существующие стандартные библиотеки сжатия, как явно разрешено в правилах.
источник