Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ДополнениеТеоремаГёделя_исправление.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
77.32 Кб
Скачать

4.4.2. Перечислимые множества

Рассмотрим теперь случай, когда алгоритм A не принимает на вход никаких данных, а будучи запущенным, вырабатывает некоторую последовательность результатов (см. п. 1.1.2). Тем самым алгоритм A определяет некоторое множество A, являющееся множеством слов в алфавите U, которое называется перечислимым:

A = {aU* | a:=A()}.

Совершенно аналогично вычислимым функциям, перечислимые множества могут быть реализованы бесконечным множеством алгоритмов, которые все эквивалентны. Условимся для каждого перечислимого множества выбирать представление в классе эквивалентных алгоритмов и не различать перечислимое множество и его представлении без нужды. Алгоритм, представляющий перечислимое множество, для краткости речи называется просто перечисляющим.

В используемом псевдокоде в теле алгоритма, перечисляющего множество, как правило, присутствует оператор yield a.

Замечание 1. Иногда оператор yield a отсутствует в явном виде, но тогда он всегда моделируется оператором A:=A+a добавления элемента a в изначально пустое множество A.

Замечание 2. Всякое конечное множество может быть задано перечислением элементов {a1, …, an} (п. 1.1.2) и тем самым является перечислимым. Действительно, алгоритм begin yield a1; …; yield an end очевидно, перечисляет это множество. В частности, алфавит U перечислим, перечисляющий его алгоритм обозначим U.

Замечание 3. Всякое перечислимое множество A линейно упорядочено (п. 1.8.1). Действительно, порядок выполнения операторов yield (или оператора добавления элемента) очевидно, линеен.

Замечание 4. Перечислимые множества (и только они!) могут появляться в заголовке цикла по множеству for aA do B(a) end for, где B — некоторый алгоритм. Действительно, чтобы реализовать этот цикл, достаточно в теле перечисляющего алгоритма A заменить оператор yield a вызовом алгоритма B(a).

Замечание 5. Конкретные перечисляющие алгоритмы, приводимые в примерах, генерируют каждый элемент ровно один раз, как это и требуется в обычных множествах. Однако явно накладывать такое ограничение на перечисляющие алгоритмы необязательно. Действительно, если имеется перечисляющий алгоритм, который перечисляет какие-то элементы несколько раз, то в его тело можно вставить проверку, исключающую повторные добавления элементов. Перечисляющие алгоритмы, генерирующие элементы по несколько раз, можно использовать для работы с мультимножествами, которые в этом разделе не понадобились.

Примеры.

1. Множество натуральных чисел перечислимо:

 = {n | n:= 0; while true do n:=n+1; yield n end while}.

2. Алгоритмы 1.1, 1.8–1.9 задают перечислимые множества.

Пустое множество  и множество всех слов U* перечислимы. Пустое множество перечислимо пустым алгоритмом skip, а множество всех слов перечислимо очевидным алгоритмом, который вначале перечисляет все слова длины 1, потом все слова длины 2 и так далее.

Теорема 1. Существуют невычислимые функции и неперечислимые множества.

Доказательство. Число различных слов в непустом конечном алфавите счётно. Всякий алгоритм — это слово в конечном алфавите, следовательно, число различных алгоритмов не более чем счётно. Фактор-множество (п. 1.7.2) не может превосходить исходное множество по мощности, поэтому множество классов функционально эквивалентных алгоритмов не более чем счётно. С другой стороны, множество всех подмножеств счетного множества несчётно. Значит число различных множеств слов и число различных функций из множеств слов в множества слов несчётно. Следовательно, невозможно взаимно-однозначное соответствие из множества алгоритмов в множество множеств и в множество функций. чтд

Следствие. Существуют перечислимые множества и вычислимые функции; их количества не более чем счётны.

Замечание. Наряду с вычислимыми функциями и перечислимыми множествами бывает полезно рассматривать и другие типы алгоритмов, например: итераторы, трансформации и др. В этом разделе другие типы не понадобились.

Пример. Множество  перечислимо, множество 2= также перечислимо. Например, следующий алгоритм N2 перечисляет пары натуральных чисел <a, b>:

s:=1; while true do s := s+1; for a from 1 to s–1 do yield <a, s–a> end for end while.

Перечислимость множеств тесно связана с вычислимыми функциями натурального ряда. Действительно, перечислимое множество  (и его отрезки, п. 1.2.5) — это удобное и естественное средство нумерации, то есть перечисления множеств слов. Пусть A — перечислимое множество, заданное алгоритмом A. Рассмотрим вычислимую функцию F :   A, заданную следующим алгоритмом:

func F (n: ) : A

k:=0;

for aA do

k := k+1;

if k = n then return a end if

end for

Построенная функция возвращает элемент перечислимого множества по его номеру. Такую перечисляющую функцию всегда можно и иногда удобно использовать в качестве представления перечислимого множества наряду с генерирующим алгоритмом.

Нетрудно сделать и обратное — узнать номер заданного элемента перечислимого множества:

proc –1 (x: A) : 

k:=0;

for aA do

k := k+1;

if x = a then return k end if

end for

Пример. Формула 2a (2b + 1) – 1 задает номер пары в некотором перечислении натуральных пар <a, b>.

Теорема 2. Объединение и пересечение перечислимых множеств перечислимы.

Доказательство. Пусть X и Y — перечислимые множества с перечисляющими функциями X: X и Y: Y.

[] Если хотя бы одно из множеств пусто, то утверждение тривиально. Иначе вычислимая функция Z: XY перечисляет объединение:

Z(n) := if n четно then return X(n/2) else return Y((n+1)/2) end if.

[] Если пересечение пусто, то оно перечислимо по определению. Иначе рассмотрим алгоритм N2, перечисляющий пары натуральных чисел (см. пример выше), и построим алгоритм, перечисляющий пересечение:

for <a, b>N2 do if X(a)=Y(b) then yield X(a) end if end for.

Замечание. Другие примеры перечисляющих алгоритмов в форме итераторов приведены в п. 1.3.8.