Индуктивные функции на пространстве последовательностей
Решим еще одну задачу.
Задача 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". В остальном программа полностью соответствует проведенному перед ее построением исследованию.