Индуктивные функции на пространстве последовательностей
Решим еще одну задачу.
Задача 9.3. Напишите программу, вводящую последовательность вещественных чисел, и печатающую среднее арифметическое ее элементов (для непустой последовательности).
Решение
По условию задачи , где
.
Если
,
,
(цепочка из двух
нулей), то
, но
,
следовательно
не является индуктивной.
Построим ее индуктивное расширение .
Обозначив через
сумму элементов последовательности
,
получаем
.
Следовательно, в качестве
можно взять пару
.
Для
,
где
, преобразование
задается формулой
.
Проектируемая программа будет проще, если мы сможем продолжить на
с сохранением
. Попробуем
подобрать подходящую пару
такую, чтобы
и
. Так как
,
то из последнего равенства получаем
,
что справедливо при всех
. Следовательно, можно
положить,
например,
. Теперь
.
Отображение
тривиально:
, а
построенное нами расширение не является минимальным, так как значение
функцией
не принимается.
Текст программы
public class AverSeq{ public static void main(String[] args) { double y1 = 0., y2 = 0.; try { while (true) { double x = Xterm.inputDouble("x -> "); y1 = (y1*y2 + x) / (y2 + 1.); y2 += 1; } } catch(Exception e) { Xterm.println("\nf = " + y1); } } }
Рассмотрим задачу несколько другого типа.
Задача 9.4. Напишите программу, определяющую количество вхождений
образца в последовательность символов.
Решение
Пусть — множество всех символов, тогда функция
. Если
,
,
, то
, но
, следовательно
не является
индуктивной.
Заметив, что , будем строить ее индуктивное
расширение.

Введем дополнительную функцию ,
которая будет истинна только тогда, когда
кончается на
, и
рассмотрим функцию
. Для нее имеем
,

Необходимо ввести еще одну дополнительную функцию ,
которая будет истинна только тогда, когда
кончается на
.
Теперь можно рассмотреть
. Для нее имеем
,

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

Полученное равенство показывает, что — индуктивное
расширение
,
однако оно достаточно сложно и заведомо не является минимальным, так как
,
и
не являются
независимыми. У тройки величин
имеется всего четыре допустимых состояния, которые
можно представить одним числом:

Сейчас мы докажем, что функция ,
определенная соотношением
является минимальным индуктивным расширением
.
Для доказательства индуктивности достаточно предъявить преобразование :

Для доказательства
сюръективности функции предъявим прообраз произвольного
элемента
. Им может служить, например,
цепочка,
начинающаяся с
вхождений образца
, за которым
следует еще
первых символов этого образца. Для того чтобы проверить
второе условие критерия минимальности, необходимо убедиться в том, что
.
Пусть ,
и
либо
, либо
. Если
, то в качестве
можно взять пустую цепочку.
В противном случае без ограничения общности
можно считать, что
. Цепочка
заканчивается на
первых
символа образца
, поэтому если в качестве
взять
последних символа
этого образца, то
, что и завершает доказательство
минимальности
.
Текст программы
import java.io.*; public class ABCDSeq { public static void main(String[] args) { DataInputStream in = new DataInputStream(System.in); int f = 0, n = 0; try { while (true) { char x = (char)in.readByte(); if (x=='\n') continue; if (x=='d' && n==3) { f += 1; n = 0; } else if (x=='c' && n==2) { n = 3; } else if (x=='b' && n==1) { n = 2; } else if (x=='a') { n = 1; } else{ n = 0; } } } catch(Exception e) { Xterm.println("f = " + f); } } }
В данной программе используется метод "readByte", который позволяет вводить символы. При этом символ '\n' также оказывается введенным после того, как пользователь нажимает клавишу "Enter" на клавиатуре. Этот символ необходимо игнорировать, что и реализуется в программе оператором "if (x=='\n') continue".
Не использовавшиеся нами ранее операторы "import java.io.*" и "DataInputStream in = new DataInputStream(System.in)" необходимы для вызова метода "readByte". В остальном программа полностью соответствует проведенному перед ее построением исследованию.