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