Pull to refresh

Подбор мнемонических цитат для автомобильных и телефонных номеров

PHPProgramming
Sandbox
Порой бывает сложно запомнить цифровую или цифро-буквенную последовательность, но если при помощи простого правила, строка стихотворения, выученного в детстве может быть преобразована к этому числу — всё станет легче. В этой статье методами Монте-Карло сравниваются результаты подбора таких отрывков при помощи двух различных способов кодирования чисел.

Приведу пример: Если кодировать цифры согласными буквами, то каждое слово или предложение соответствует целому числу. Обычно выбирают следующий способ кодирования 1-р, 2-д, 3-т, 4-ч, 5-п, 6-ш, 7-с, 8-в, 9-м (потому что 9 это “много”). Тогда слова “добрый мой приятель” соответствуют числу 219513. Но это несколько неудобно, поскольку без специальной подготовки не получается быстро выкинуть ненужные буквы, тем не менее, “добрый мой приятель” забыть довольно сложно, что всегда позволит вам находясь в спокойной обстановке вспомнить число 219513. И это весьма заманчиво, поскольку само по себе число это является весьма абстрактным и может запросто перепутаться с другими такими же абстрактными числами.


Существует довольно много информации по мнемотехнике, здесь я старался не изобретать велосипедов, а использовать возможности подбора текста, которые довольно затруднительно использовать без помощи вычислительной системы.
На всякий случай определение из Википедии: Мнемоника (греч. искусство запоминания), мнемотехника — совокупность специальных приёмов и способов, облегчающих запоминание нужной информации и увеличивающих объём памяти путём образования ассоциаций (связей). Замена абстрактных объектов и фактов на понятия и представления, имеющие визуальное, аудиальное или кинестетическое представление, связывание объектов с уже имеющейся информацией в памяти различных типов для упрощения запоминания.

В этом случае, сопоставление абстрактному набору цифр отрывка текста наполняет его образами и позволяет упростить его запоминание. Как уже говорилось, идея заключается в том, чтобы подобрать этот текст автоматически. Это всё конечно известные вещи, я нисколько не претендую на то что их выдумал, тем кто заинтересуется самой мнемотехникой рекомендую почитать учебники [1].

Кодирование по первым буквам


Первоначальная идея заключалась в том, чтобы попробовать подобрать цитату из стихотворной части школьной программы, которая бы соответствовала заданному автомобильному номеру, то есть некоторой случайной последовательности буква-три_цифры-две_буквы (обычный номер без кода региона). При этом предполагалось, что первая буква даёт начало первому слову, каждая из трёх цифр кодируется согласной, каждая из которых также даёт начало слову и последние две буквы — ещё два слова. Притом в российском автомобильном номере не могут содержаться любые буквы, используются только 12 из них это: а, в, с, е, н, т, м, о, к, р, у, х. Было взято несколько крупных стихотворений: Евгений Онегин, Полтава, Руслан и Людмила, Ромео и Джульета + басни Крылова. В процессе анализа генерируется 1000 случайных номеров, для которых подбирается цитата из этих произведений
Был написан следующий скрипт:
#!/usr/bin/php
<?php
$path="school/";
$letters = array("а", "в", "с", "е", "н", "т", "м", "о", "к", "р", "у", "х");
$numbers = array("о", "р", "д", "т", "ч", "п", "ш", "с", "в", "м");

// получение случайного элемента из массива (отличие от array_rand в том, что возвращается значение, а не ключ)
function rn($a) { return $a[rand(0, count($a)-1)]; }

// получение длины и максимально возможной генерируемой последовательности
function getmax($handle, $required) {
	$result=array(); $max = 0; $queue = array();
	fseek($handle, 0);
	while (($buffer = fgets($handle, 4096)) !== false) {
		$words=explode(" ", $buffer);
		for ($j=0;$j<count($words); $j++) {
			// обрезаем лишние символы и понижаем регистр
			$w = mb_strtolower(trim($words[$j], " \t.,\n\r0123456789:-!;?"), "UTF-8");
			if (!$w) continue;
			$queue[]=$w;
			
			$avail = min(count($required), count($queue));
			$match = $avail; 
			for ($k=0;$k<$avail;$k++) {
				if (mb_strpos($queue[$k], $required[$k], 0, "UTF-8")!==0) {
					$match = $k; break;
				}
			}
			
			if ($max<$match) $max=$match;
			if ($match===count($required)) {
				$result[]=array_splice($queue, 0, $match);
				return array($max, $result);
			}
			
			if (count($queue)>=count($required))
				array_shift($queue);
		}
	}
	return array($max, $result);
}

$plates = array();
for ($i=0;$i<1000;$i++) $plates[]=array(rn($letters), rn($numbers), rn($numbers), rn($numbers), rn($letters), rn($letters));

$files=scandir($path);

for ($i=0;$i<count($files);$i++) { 
	if (is_dir($path.$files[$i])) continue;
	
	$handle = @fopen($path.$files[$i], "r");

	if ($handle) {
		$cnt=array(0,0,0,0,0,0,0); $max = 0; $avg = 0; $best = array();
		
		for ($j=0;$j<count($plates);$j++) {
			list($c, $seq) = getmax($handle, $plates[$j]);
			if (($max && $max<$c) || !$max) { $max = $c; $best=array(implode("", $plates[$j])=>$seq);}
			else if ($max===$c) $best[implode("", $plates[$j])]=$seq;
			$cnt[$c] += 1;
			$avg += $c;
		}
		$avg/=count($plates);
		print $files[$i]."\t".$avg;
		for ($j=0;$j<count($cnt);$j++) print "\t".$cnt[$j];
		print "\n";
		print_r($best);

	    fclose($handle);
	}
}


Если немного прокомментировать код, то все поступающие слова складываются в очередь, которая растёт не больше длины подбираемой последовательности. Длина максимального совпадения запоминается. Таким образом выясняется максимальное количество букв от начала, которые можно закодировать при помощи некоторого текста.

Результаты следующие:
Название Среднее 0 1 2 3 4 5 6 Объём
Басни Крылова 2.434 0 35 530 403 30 2 0 83Кб
Евгений Онегин 3.237 0 0 120 549 306 24 1 1.1Мб
Полтава 2.507 0 17 510 424 47 2 0 85Кб
Ромео и Джульетта 2.821 0 36 239 598 122 5 0 219Кб
Руслан и Людмила 2.617 0 68 359 469 97 6 1 138Кб


Можно сказать, что эти результаты меня не обрадовали, получается, что только для двух номеров из 1000 получилось подобрать цитату. Посмотрим на эти две цитаты: м052рк — “мой. Они, пристрастною душой Ревнуя к”; о817вс — “От воспалённого Руслана Сокрылись вдруг среди”. Некоторая логика в этих фразах конечно присутствует, но незаконченность и обрывчатость делает их запоминание не слишком простым делом. Тем не менее, тесты позволили сказать, что даже на основе этих текстов в большинстве случаев получается генерировать последовательность для трёх букв.

Конечно же я заинтересовался: что происходит когда тексты становятся больше? Быть может появляется большее количество фрагментов, из которых уже можно выбрать. Для следующего теста я выбрал из библиотеки Мошкова: два завета библии в синодальном переводе, все крупные стихи Бодлера, все романы Достоевского, “Хоббит, или Туда и обратно”, все романы Пушкина в стихах, всего Шекспира, все романы Толстого. Были получены следующие результаты:

Название Среднее 0 1 2 3 4 5 6 Объём
Ветхий завет 3.09 0 0 188 557 235 17 3 1.1Мб
Новый завет 3.126 0 13 180 498 289 17 3 1.5Мб
Достоевский 4.053 0 0 10 206 526 237 21 15Мб
Толкиен 3.12 0 10 148 581 234 27 0 807Кб
Пушкин 3.234 0 0 114 565 295 25 1 1.2Мб
Бодлер 2.943 0 4 231 594 160 11 0 461Кб
Шекспир 4.489 0 0 0 49 474 416 61 64Мб
Толстой 3.96 0 0 8 236 555 190 11 11Мб


Самих цитат получилось довольно много, чтобы не утомлять читателя я не буду приводить их все, только упомяну, что их характер остался прежним, какой-то незаконченно-загадочный: в488ом — “Вот что, Ваня верь одному: Маслобоев”, т380тт — “три тысячи, вскричал он, три тысячи”, м081не — “мне от вас рабство наслаждение. Есть”. Прочитав их все посещает мысль о каких-то гаданиях, которые устраивают по книгам (когда открывают случайную страницу, читают случайную строку и пытаются это как-то интерпретировать в рамках собственной жизни). Но я таких целей не ставил.


График зависимости среднего от десятичного логарифма объёма (по Y — среднее, плюс-минус стандартное отклонение, а по X — логарифм объёма используемого текста)

В принципе, такой вид зависимости можно было угадать, здесь немного выбиваются только два томика Библии, а в остальном среднее растёт пропорционально логарифму объёма.

Кодирование по длинам


Первое что приходит в голову это то что способ кодирования слишком много текста оставляет вне рассмотрения, то есть для цифр берутся только 10 букв и для букв 12, остальные слова только разрывают цепочки. Конечно, можно придумать другие способы кодирования, которые используют все буквы или хотя бы только согласные. Эти способы описаны в литературе, но моя идея заключалась в том, чтобы сделать простой в использовании инструмент, такой чтобы пользователь не ломал голову над тем как же соответствует фраза этому номеру, какие нужно выбрасывать буквы, а какие учитывать, в противном случае можно было бы применять кодирование до первой значимой буквы, оно даёт однозначность, но не удобно для человека. Пришла идея кодировать цифры количеством букв в слове. При таком кодировании возникает проблема представления ноля, но пока не будем на этом останавливаться. Для того чтобы сравнить я провёл серию тестов на том же наборе и по тем же правилам (код почти тот же, по этой причине листинг был бы одним повторением):

Название Среднее 0 1 2 3 4 5 6 Объём
Басни Крылова 2.831 0 96 203 490 197 13 1 83Кб
Онегин 3.497 0 96 85 166 536 113 4 1.1Мб
Полтава 2.808 0 96 231 459 199 13 2 85Кб
Ромео и Джульетта 3.149 0 96 116 377 371 34 6 219Кб
Руслан и Людмила 2.94 0 96 178 443 258 23 2 138Кб


Можно сказать, что ситуация гораздо лучше, только сразу же настораживает одинаковое число 96 в столбике “1”, здесь посчитаны номера, для которых нашлось слово на первую букву, но не нашлось на первую цифру. Это естественно номера начинающиеся на ноль, около 100 таких номеров ещё в столбцах 2 и 3, как можно заметить, их не больше 85. Пример получившейся цитаты: в325нм — “вам: рад бы… право не могу”. Обрывчатость в случае со стихами можно компенсировать тем, что приводить цитату от начала строки, пользователю потребуется дополнительно запомнить где в стихотворении начинается номер, например, приведённая цитата должна выдаваться как: “Клянусь вам: рад бы… право не могу.” или даже вместе с предыдущей строкой: “Ах, милостивый рыцарь, Клянусь вам: рад бы… право не могу”. Но так уже перестаёт быть явным начало фразы. Если запоминать начало фразы, то можно и запомнить положение нолей отдельно. Возможно кому-то покажется такая идея издевательством, но я считаю её применимой по крайней мере.
Применение этой идеи даёт следующие результаты:

Название Среднее 0 1 2 3 4 5 6 Объём
Басни Крылова 3.444 0 0 114 426 367 88 5 83Кб
Онегин 4.26 0 0 2 93 596 261 48 1.1Мб
Полтава 3.413 0 0 132 414 367 83 4 85Кб
Ромео и Джульетта 3.791 0 0 39 298 508 143 12 219Кб
Руслан и Людмила 3.611 0 0 83 356 445 99 17 138Кб
Ветхий завет 4.189 0 0 5 126 585 243 41 1.1Мб
Новый завет 4.292 0 0 3 83 581 285 48 1.5Мб
Достоевский 5.019 0 0 0 0 208 565 227 15Мб
Толкиен (Хоббит) 4.123 0 0 2 155 587 230 26 807Кб
Пушкин 4.251 0 0 3 94 593 269 41 1.2Мб
Бодлер 3.946 0 0 18 214 591 158 19 461Кб


По этим данным можно предположить, что для случайного номера с вероятностью 22% можно подобрать соответствующую цитату из Достоевского, уже не плохо. Цитаты конечно получаются весьма многозначительными, как и в прошлом случае: в725вр — “весело смотрит за нашей весёлой работой”, м582то — “мои слова казалось её тронули, она”, м385нс — “между тем каким-то чудом необыкновенное сходство”, к514нт — “кровавой битве и день настал толпы”.

А что если генерировать не для автомобильных номеров, а для телефонных? Сказано — сделано:

Название Среднее 1 2 3 4 5 6 7
Басни Крылова 4.145 0 23 270 387 214 71 35
Онегин 5.248 0 0 9 260 347 242 142
Полтава 4.131 0 16 293 385 193 76 37
Ромео и Джульетта 4.608 0 0 138 374 286 146 56
Руслан и Людмила 4.349 0 11 212 381 256 93 47


Эти результаты позволяют предположить, что для шестизначного случайного номера с вероятностью почти 40% найдётся соответствующая цитата из произведения “Евгений Онегин”, а это ведь стихи, которые гораздо приятней к запоминанию (не для всех скорее всего, но для большинства всё же, я надеюсь).

Другие способы


Какие ещё возможности остались за кадром: генерация текстов, а именно генерация соответствующих слов или предложений определённой структуры (с нужным количеством букв или ещё как) в принципе это уже давно сделано и без компьютеров. Указанный в литературе учебник предлагает для каждого числа от 0 до 1000 какое-то слово, которое уже подобрано автором, но, к сожалению, такой способ не даёт возможности запоминать большие числа, поскольку образы нельзя соединять, это по словам автора приводит к их стиранию. Оно и понятно, всё начинает наслаиваться и так далее. Вот например простой способ: можно закодировать цифры распространёнными ассоциациями — 3 (от 03) — врач, 7 — топор (из-за формы) и например 5 — пятница. В этом случае подобрав для каждой цифры по три образа (для каждого положения) все трёхзначные числа можно закодировать очень яркими историями вроде “375 — врача зарубили в пятницу”, но так можно запомнить только очень небольшое количество чисел, потому что всё начнёт мешаться, нужно проводить дополнительные параллели, чтобы запомнить когда именно зарубили врача в этот раз.

Заключение


Алгоритм генерации по длинам слов реализован в приложении, которое распознаёт номера авто на мобильных устройствах и является некоммерческой разработкой just for fun. Кроме того, такой подбор осуществляется на сайте YaZapomnil [2].

Мне показался довольно интересным тот факт, что разнообразие текстов относительно таких странных метрик как последовательность количеств букв или последовательность первых букв слов растёт при увеличении объёма текста. Притом результаты довольно хорошо ложатся на прямую. При увеличении текста возрастает возможность выбора между фрагментами, это возможно улучшит их качество.

На данный момент я думаю над источником, который бы содержал большое количество красивых текстов, а так же над способом сопоставления, который был бы очевиден для человека и позволял бы подбирать большее количество цитат.
Буду рад, если идея покажется интересной.

Ссылки


  1. Козаренко В. А. Учебник мнемотехники, 2002, электронная публикация
  2. Подбор цитаты по числу yazapomnil.ru/n/
Tags:мнемоникаобработка естественного языкателефонные номераавтомобильные номера
Hubs: PHP Programming
Total votes 29: ↑25 and ↓4 +21
Views12.6K
Programming Manager (C++)
from 250,000 ₽Game InsightRemote job
PHP-разработчик fullstack (Linux, Apache, MySQL, PHP)
from 250,000 ₽КАУССанкт-ПетербургRemote job
PHP-разработчик (Middle)
from 80,000 to 120,000 ₽Laptop.ruRemote job
PHP-программист по интеграциям (вторая линия поддержки)
to 80,000 ₽Улыбка радугиСанкт-Петербург
PHP-разработчик
from 100,000 to 150,000 ₽FINPAYМоскваRemote job

Top of the last 24 hours