7.11. Символьное дифференцирование

Символьным дифференцированием в математике называется операция преобразования одного арифметического выражения в другое арифметическое выражение, которое называется производной. Пусть U обозначает арифметическое выражение, которое может содержать переменную х. Производная от U по х записывается в виде dU/dx и определяется рекурсивно с помощью некоторых правил преобразования, применяемых к U. Вначале следуют два граничных условия. Стрелка означает «преобразуется в»; U и V обозначают выражения, а с – константу:

dc/dx → 0

dx/dx → 1

d(-U)/dx → -(dU/dx)

d(U+V)/dx → dU/dx+dV/dx

d(U-V)/dx → dU/dx-dV/dx

d(cU)/dx → c(dU/dx)

d(UV)/dx → U(dV/dx) + V(dU/dx)

d(U/V)dx → d(UV-1)/dx

d(Uc)/dx → cUc-l(dU/dx)

d(lnU)/dx → U-1(dU/dx)

Этот набор правил легко написать на Прологе, поскольку мы можем представить арифметические выражения как структуры и использовать знаки операций как функторы этих структур. Кроме того, сопоставление целевого утверждения с заголовком правила мы можем использовать как сопоставление образцов. Рассмотрим цель d(E,X, F), которая считается согласованной, когда производная выражения E по константе[12] X есть выражение F. Помимо знаков операций +, -, *, /, которые имеют встроенные определения, нам нужно определить операцию ^, такую, что X^Y означаете xy, а также одноместную операцию ~, такую что означает «минус X». Эти определения операций введены исключительно для того, чтобы облегчить распознавание синтаксиса выражений. Например, после того как d определен, можно было бы задать следующие вопросы:

?- d(x+1,x,X).

X = 1+0

?- d(x*x-2,x,X).

 X = х*1+1*х-0

Заметим, что само по себе простое преобразование одного выражения в другое (на основе правил) не всегда дает результат в приведенной (упрощенной) форме. Приведение результата должно быть записано в виде отдельной процедуры (см. разд. 7.12). Программа дифференцирования состоит из определений дополнительных операций и построчной трансляции приведенных выше правил преобразования в утверждения Пролога:

?- op(10,yfx,^).

?- op(9,fx,~).

d(X,X,1):-!.

d(C,X,0):- atomic(C).

d(~U,X,~A):- d(U,X,A).

d(U+V,X,A+B):- d(U,X,A), d(V,X,B).

d(U-V,X,A-В):- d(U,X,A), d(V,X,B).

d(C*U,X,C*A):- atomic(C), C\=X, d(U,X,A),!.

d(U*V,X,B*U+A*V):- d(U,X,A), d(V,X,B).

d(U/V,X,A):- d(U*V^~1),X,A).

d(U^C,X,C*U^(C-1)*W):- atomic(C),C\=X,d(U,X,W).

d(log(U),X,A*U^(~1)):- d(U,X,A).

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

Как уже говорилось, данная программа выдает решения в неприведенной форме (т. е. без упрощений). Например, всякое вхождение х*1 может быть приведено к х, а всякое вхождение вида х*1+1*х-0 может быть приведено к 2*х. В следующем разделе рассматривается программа алгебраических преобразований, которую можно использовать для упрощения арифметических выражений. Примененный способ очень похож на тот, каким выше выводились производные.

7.12. Отображение структур и преобразование деревьев

Если некоторая структура покомпонентно копируется с целью образования новой структуры, то мы говорим, что одна структура отображается в другую. Обычно при копировании каждая компонента слегка изменяется подобно тому, как в гл. 3 мы изменяли одно предложение, превращая его в другое. В том примере нам иногда нужно было скопировать какое-то слово в точности в том виде, в каком оно встретилось в исходном предложении, а иногда при копировании нам нужно было изменить слово. Для этого мы использовали следующую программу, которая отображает первый аргумент предиката преобразовать во второй его аргумент:

преобразовать([],[]).

преобразовать([А|В],[С|D]):- заменить(А,С),преобразовать(В,D).

Поскольку отображение имеет довольно широкое применение, мы можем определить предикат отобспис такой, что целевое утверждение отобспис(Р, L, M) согласуется с базой данных, применяя предикат Р к каждому элементу списка L и образуя в результате новый список М. При этом предполагается, что предикат Р имеет два аргумента: первый аргумент для передачи «входного» элемента, а второй аргумент – для измененного элемента, подлежащего включению в список М.

отобспис((_,[],[]).

отобспис((P,[X|L],[Y|M]):- Q =..[P,X,Y],call(Q),отобспис(Р,L,М).

Об этом определении следует сказать несколько слов. Во-первых, определение содержит граничное условие (первое утверждение) и общий рекурсивный случай (второе утверждение). Во втором утверждении используется оператор '=..', формирующий целевое утверждение на основе предиката (Р), входного элемента (X) и переменной (Y), которую предикат Р должен конкретизировать, чтобы образовать измененный элемент. Затем делается попытка согласовать цель Q, в результате чего Y конкретизируется, образуя голову третьего аргумента данного вызова предиката отобспис. Наконец, рекурсивный вызов отображает хвост первого аргумента в хвост второго.

Функции предиката преобразовать может выполнять предикат отобспис. Полагая, что предикат заменить определен как в гл. 3, такое использование отобспис могло бы выглядеть следующим образом:

?- отобспис(заменить,[уоu,аrе,а,computer],Z).

Z = [i, [am, not], a, computer]

Путем упрощения предиката отобспис получается предикат обрабспис, который просто обрабатывает список, применяя некоторый предикат от одного аргумента к каждому элементу списка. При этом новый список не порождается.

обрабспис(_,[]).

обрабспис(Р,[Х|L]):-Q =…[Р,Х],call(Q),обрабспис(Р,L).

Заметим, что предикат печать_строки из гл. 5 можно было бы заменить запросом вида обрабспис(put, L), где L – это строка, которую нужно напечатать.

Отображение применимо не только к спискам; оно может быть определено для структуры любого вида. Например, рассмотрим арифметическое выражение, составленное из функторов * и +, имеющих по два аргумента. Пусть мы хотим отобразить одно выражение в другое, устраняя при этом все умножения на 1. Это алгебраическое приведение могло быть определено с помощью предиката s такого, что s(Op, L, R,Ans) означает, что выражение, состоящее из операции Ор с левым аргументом L и правым аргументом R приводится к упрощенному выражению Ans. Факты, необходимые для устранения умножений на 1, могли бы выглядеть так (из-за коммутативности умножения нужны два факта):

вернуться

12

Имеется в виду константа в смысле Пролога. - Прим. ред.


Перейти на страницу:
Изменить размер шрифта: