Основы программирования


Индуктивные функции на последовательностях и индуктивные расширения


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

Sn = {a0, a1, ..., an-1}

длины n. С помощью знака & обозначим операцию приписывания нового элемента справа к последовательности (ее называют также конкатенацией):

Sn+1 = Sn&an = {a0, a1, ..., an-1, an}

Пусть f(S) - некоторая функция на множестве последовательностей, например, сумма элементов последовательности. Функция называется индуктивной, если при добавлении нового элемента к последовательности новое значение функции можно вычислить, зная только старое значение функции и добавленный элемент. На математическом языке функция

f:W

Y

где W - множество всех последовательностей, составленных из элементов некоторого множества X, индуктивна, если существует функция G от двух аргументов

G:Y*X

Y

такая, что для любой последовательности S из W и любого элемента a из X значение функции f на последовательности S, к которой добавлен элемент a, вычисляется с помощью функции G:

f(S&a) = G(f(S), a).

Функция G по паре (y, a), где y - старое значение функции f на последовательности S и a - элемент, добавленный к последовательности, вычисляет новое значение y, равное значению функции f на новой последовательности.

В примере с суммой элементов последовательности функция G равна сумме элементов y и a:

G(y, a) = y+a.

В примере с максимальным элементом последовательности функция G равна максимуму:

G(y, a) = max(y,a).

В примере со схемой Горнера вычисления значения многочлена в точке t, где коэффициенты многочлена заданы в последовательности по убыванию степеней, функция G равна

G(y, a) = yt+a.

Во всех трех случаях рассматриваемая функция на последовательности индуктивна.

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

алгоритм значение индуктивной функции( вх: последовательность S ) | дано: последовательность S | надо: вычислить функцию y = f(S) начало алгоритма | y := значение функции f на пустой последовательности; | встать в начало последовательности S; | цикл пока в последовательности S есть | | непрочитанные элементы | | прочесть очередной элемент | | последовательности S в (вых:x); | | y := G(y, x); | конец цикла | ответ := y; конец алгоритма

Таким образом, для каждой конкретной индуктивной функции надо лишь правильно задать ее значение на пустой последовательности (инициализация) и определить, как новое значение функции вычисляется через старое при добавлении к последовательности очередного элемента, т.е. задать функцию G(y,x). Схема вычисления для всех индуктивных функций одна и та же.

Однако не все функции на последовательностях являются индуктивными. Рассмотрим следующий пример. Пусть коэффициенты многочлена заданы в последовательности по убыванию степеней. Надо вычислить значение производной многочлена в точке x = 2. Обозначим через

S = {a0, a1, ..., an}

последовательность коэффициентов многочлена

p(x) = a0xn+a1xn-1+...+an

и через f(S) значение производной многочлена p'(x) в точке x =2:

f(S) = p'(2)

Покажем, что функция f не индуктивна. Достаточно указать две последовательности S1 и S2, такие, что значения функции f на них совпадают, но при добавлении к последовательностям S1 и S2 одного и того же элемента a новые значения функции уже не равны:

f(S1) = f(S2), f(S1&a)

f(S2&a)

Возьмем последовательности

S1 = {1}, S2 = {1, -4,1}.

Им соответствуют многочлены

p1(x) = 1, p2(x) = x2-4x+1

Производные многочленов равны

p'(x) = 0, p'2(x)= 2x-4

Значения обеих производных в точке x=2 равны нулю, т.е.

f(S1) = p'1(2) = 0, f(S2) = p'2(2) = 2*2-4 = 0

Припишем теперь к обеим последовательностям элемент a = 1:

S1&1 = {1,1}, S2&1 = {1, -4,1,1}.

Новым последовательностям соответствуют многочлены

g1(x) = x+1, g2(x) = x3-4x2+x+1

Их производные равны

g1(x) = 1, g2(x) = 3x2-8x+1

Значения производных в точке x=2 равны соответственно

f(S1&1) = g'1(2) = 1 f(S2&1) = g'2(2) = 12-16+1 = -3

Мы видим, что значения f(S1) и f(S2) совпадают, но значения f(S1&1) и f(S2&1) не совпадают. Следовательно, функция f не индуктивна.

Как поступать в случае, когда функция f не индуктивна? Общий рецепт следующий: надо придумать индуктивную функцию F, такую, что, зная значение F, легко можно вычислить исходную функцию f. Функция F называется индуктивным расширением функции f.

Приведем формальные определения. Пусть исходная функция на множестве W всех последовательностей

f:W

Y

не индуктивна. Индуктивная функция

F:W

Z

называется индуктивным расширением функции f, если существует отображение

P:Z

Y

такое, что для всякой последовательности S, принадлежащей W, выполняется равенство

f(S) = P(F(S))

(т.е. функция f равна композиции отображений F и P, f = P?F.) Отображение P обычно называют проекцией множества Z на Y.

Как построить индуктивное расширение функции f? Это творческий момент, готового рецепта на все случаи не существует. Неформальный рецепт следующий: надо понять, какой информации не хватает для того, чтобы уметь вычислять новое значение функции на последовательности при добавлении к последовательности нового элемента. Эту информацию надо хранить дополнительно к значению функции. Отсюда и появился термин расширение: вычисляется более сложная, расширенная, функция, чтобы по ней затем восстановить исходную. Как правило, значением индуктивного расширения F является пара (y, h), где y - значение исходной функции f, а h - некоторая дополнительная информация, позволяющая перевычислять значение y при добавлении нового элемента к последовательности. Таким образом, множество Z значений индуктивного расширения

F:W

Z

чаще всего является множеством пар (y, h), т.е. декартовым произведением:

Z = Y*H

Отображение P на практике должно легко вычисляться. Так оно и есть в случае декартово произведения - это просто проекция на первый аргумент.

P(y, h) = y

Рассмотрим пример с вычислением производной многочлена в точке; коэффициенты многочлена заданы в последовательности по убыванию степеней. При добавлении к последовательности

Sk = {a0, a1, ...,ak}

нового коэффициента ak+1 получаем последовательность

Sk+1 = S&ak+1 = {a0, a1, ...,ak, ak+1}

Пусть этим двум последовательностям соответствуют многочлены pk(x) и pk+1(x). Тогда

pk+1(x) = pk(x)*x + ak+1.

Дифференцируя это равенство, получим:

p'k+1(x) = p'k(x)*x + pk(x).

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

F:S

(p'(t), p(t))

Новое значение производной вычисляется по приведенной выше формуле через старое значение производной и старое значение многочлена. После этого вычисляется новое значение многочлена по схеме Горнера.

Выпишем алгоритм вычисления производной многочлена.

вещ алг. значение производной(вх: цел n, вещ a[n+1], вещ t) | дано: n -- степень многочлена | a[n+1] -- массив коэффициентов многочлена по | возрастанию степеней | надо: найти значение производной многочлена в точке t начало алгоритма | вещ p, dp; цел i; | p := 0.0; // Инициализация значения многочлена | dp := 0.0; // Инициализация значения производной | цикл для i от 0 до n | | dp := dp * x + p; // Новое значение производной | | p := p * t + a[i]; // Новое значение многочлена | конец цикла | ответ := dp; конец алгоритма

Другой пример неиндуктивной функции - это среднее арифметическое значение элементов последовательности. Индуктивным расширением является пара (сумма элементов последовательности, длина последовательности):

F(S) = (сумма(S), длина(S)).

Легко видеть, что функция F индуктивна. При известном значении функции F не составляет труда вычислить исходную функцию:

среднее арифметическое(S) = сумма(S)/длина(S).

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

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




- Начало -  - Назад -  



Книжный магазин