
2.3. Алгебраические правила подстановок для
символьных вычислений
Для решения задач символьной обработки, имеющих дело с формальными системами подстановок, Maple-язык располагает средствами обеспечения работы с алгебраическими правилами подстановок. Данные средства представляют основной аппарат при исследованиях формальных систем обработки слов в конечных алфавитах и абстрактных моделей вычислений. Основным понятием здесь является правило подстановки, определяемое группой функций subs, subsop и процедур algsubs, asubs.
По первой уже рассматриваемой функции subs({x=a|<УР>}, V) производится подстановка a- выражения вместо каждого вхождения х-выражения в V-выражение или одновременная подстановка правых частей уравнений (УР), заданных списком/множеством, вместо всех вхождений в V-выражение соответствующих им левых частей уравнений. При этом, по subs-функции делаются подстановки лишь для вхождений левых частей уравнений (правил подстановки) в качестве операндов V-выражения. Такого типа подстановки носят своего рода синтаксический характер, глубоко не затрагивая структуры V-выражения. Результатом подстановки не является вычисление и при необходимости выполнения полного вычисления результата подстановки требуется применение eval-функции, как показано на последующем фрагменте.
Для возможности обеспечения выборочных подстановок служит специальная subsop(n1=V1, n2=V2, ...., np=Vp, W)-функция, по которой производится замена на правые Vj-части уравнений операндов W-выражения, определяемых их nj-номерами. При этом, в качестве левых nj- частей допустимо использование списков целочисленных выражений, определяя подоперан- ды W-выражения в порядке понижения их уровней вложенности. Целочисленные значения должны находиться в диапазоне [-nops(), nops(W)], а нуль-значение допустимо только для функций, индексированных выражений и рядов. В случае nj-отрицательного номер полагается равным nops(W) + nj + 1.
По процедуре asubs(∑ = V, W {, x|, x, always|, always}) производится подстановка в W-выра- жение аналогично случаю subs-функции, однако она носит скорее алгебраический, чем син- таксический характер, допуская в качестве левой ∑-части уравнения (правила подстановки) использование сумм операндов полиномиального типа, замещающих соответствующие им суммы в исходном W-выражении. При этом, замена сумм производится лишь в том случае, если левая ∑-часть правила подстановки и соответствующее ей подвыражение W-выражения являются развернутыми полиномами по ведущей х-переменной. Необязательная always-опция позволяет представлять каждое заменяемое П-подвыражение W-выражения в виде П - ∑ + V. Аналогично рассмотренному выше случаю subs-функции результатом подстановки на основе asubs-процедуры не является вычисление и при необходимости выполнения полного вычисления результата подстановки требуется применение eval-функции, как это проиллюстрировано в нижеследующем фрагменте.
Наконец, по процедуре algsubs(a=b, V {, x|, x, <Опция>}) производится алгебраическая подстановка b-подвыражения вместо каждого вхождения a-подвыражения в V-выражение. В данном отношении algsubs-процедура является обобщением вышерассмотренной subs-функции, осуществляющей синтаксического характера подстановки. Расширенные возможности первой функции относительно второй хорошо иллюстрируют примеры нижеследующего фрагмента. Более того, в отличие от subs-функции, процедура algsubs выполняет подстановку в V-выра- жение рекурсивно, не делая подстановок внутри индексированных подвыражений. Между тем, она также перед подстановкой не производит раскрытия степеней и произведений, что требует в ряде случаев предварительного применения к V-выражению expand-функции.
В случае выполнения подстановок в W-выражение от нескольких ведущих переменных возможно появление неопределенностей, связанных с неоднозначностью толкования правила
111

применения подстановки. Для устранения подобных ситуаций при проведении подстановок в W-выражение используются необязательные третий и четвертый аргументы algsubs-про- цедуры. Прежде всего, третий х-аргумент функции, кодируемый в виде списка, устанавливает порядок ведущих переменных, определяющий сам режим подстановки. При отсутствии данного аргумента порядок переменных устанавливается на основе правила подстановки, заданного первым фактическим аргументом функции. Совместно с третьим аргументом может использоваться и опция, допускающая два значения: remainder (по умолчанию) и exact, определяющие режим выполнения подстановки в обрабатываемое W-выражение. В частности, при отсутствии четвертого аргумента в результате подстановки в рациональное W-выраже- ние вычисляется обобщенный остаток. Тогда как по exact-опции в случае, если в правиле подстановки a=b левая ее a-часть является суммой термов, то подстановка производится только тогда, когда a-часть является точным делителем замещаемого ею подвыражения в W-выражении.
Вотличие от вышерассмотренных функции subs и процедуры asubs, результатом подстановки на основе algsubs-процедуры является вычисление, поэтому не требуется последующего применения eval-функции для обеспечения полного вычисления результата подстановки. Данное свойство функции позволяет успешно использовать ее для обеспечения символьно- численных вычислений, включающих как символьные преобразования, так и численные вычисления. Рассмотренные функциональные средства Subs-группы играют весьма важную роль во многих задачах символьной обработки алгебраических выражений в среде Maple
Вотличие от рассмотренных средств Subs-группы, обеспечивающих, в первую очередь, сим- вольную обработку выражений на основе синтаксически-алгебраических подстановок, applyop- процедура, имеющая следующий простой формат кодирования:
applyop(F, <Операнды>, W {, <F-аргументы>})
обеспечивает выборочное применение F-функции к указанным вторым фактическим аргументом applyop-процедуры операндам W-выражения с возможностью передачи ей фактических F- аргументов, определяемых необязательным четвертым аргументом. При указании в качестве второго фактического аргумента целочисленного р-выражения имеет место соотношение: applyop(F, p, W) = subsop(p=F(op(p, W)), W), которое сохраняет силу и в случае списка целочисленных выражений в качестве второго фактического аргумента applyop-поцедуры, позволяя производить выборочную F-обработку подвыражений W-выражения. В случае указания в качестве второго фактического аргумента applyop-процедуры множества целочисленных выражений F-обработке одновременно подвергаются соответствующие элементам множества операнды W-выражения. Необязательный четвертый аргумент applyop-процедуры позволяет передавать F-функции дополнительные фактические аргументы в порядке их кодирования. Данная функция позволяет выборочно обрабытывать операнды выражений.
С детализирующими замечаниями по всем представленным выше средствам подстановок можно ознакомиться в наших книгах [9-14]. Следующий сводный фрагмент иллюстрирует примеры применения рассмотренных средств обеспечения подстановок различных типов:
> subs({ab=d, ac=h, cd=g}, [ac, ab+cd, d*ab, h+cd]); [h, d + g, d2, h + g]
> [subs(x=0, exp(x) + cos(x)), eval(subs(x=0, exp(x) + cos(x)))]; [eo + cos(0), 2]
> subsop(1=GS, 3=Art, 4=99, z^2 + 64*x + 59*y + 99); |
GS + 64 x + Art + 99 |
> subsop(1=G, 2=NULL, 3=[a, b, c, d, e, g], [x, y, z]); |
[G, [a, b, c, d, e, g]] |
> subsop(0=G, 1=g(x, y), 2=exp(x), 3=s(t), H(x, y, z)); |
G(g(x,y), ex, s(t)) |
> subsop(0=G, [2, 0]=W, [3, 1]=t, H(x, g(x, y, z), x)); |
G(x, W(x, y, z), t) |
> subs(y^2 + 64*y + 59 = G(x), sin(y^2 + 64*y + 59) - 10); sin(G(x)) - 10
> asubs(x^3+y+17 = W-17*x, (x^3+x^2+3*x+17+y-64*y^2)^2 + 10*x + 99, 'always');
(W − 14 x + x2 − 64 y2 )2 + 10 x + 99
> [asubs(x^3+x=0, exp(x^3+x)), eval(asubs(x^3+x=0, exp(x^3 + x)))]; [1, 1]
> [subs(x^3=h+x^2, x^5+x^2), algsubs(x^3=h+x^2, x^5+x^2)]; [x5 + x2, x4 + (h + 1) x2]
112

> [subs(a+b=c, 10+a+b+3*c), algsubs(a+b=c, 10+a+b+3*c)]; [10 + a + b + 3 c, 10 + 4 c] > [subs(a*x*y = b, 10*a*x*y^2 + 3*b*x*y), algsubs(a*x*y = b, 10*a*x*y^2 + 3*b*x*y)];
[10 a x y2 + 3 b x y, 10 y b + 3 b x y]
> [subs(a*b/c=d, 3*a^2*b^2/c + sqrt(a*b*d/c)), algsubs(a*b/c=d, 3*a^2*b^2 + sqrt(a*b*d/c))];
3 a2 |
b2 |
|
a b d |
|
2 |
|
2 |
|
|
2 |
|
|
|
|
|
+ |
|
, 3 a |
|
b |
|
+ |
d |
|
|
|
|
|
|
|
|
|||||||
|
|
|
c |
|
|
|
|
|
|
|
|
|
c |
|
|
|
|
|
|
|
|
|
|
> subs(x^3=Pi, exp(10 – Pi + x^3 + x^5 - x^6)), algsubs(x^3=Pi, exp(10 – Pi + x^3 + x^5 - x^6));
e(10 + x5 − x6 ), e( π x2 + 10 − π2 )
> [algsubs(x^2 + 3*x = 64, (x + 2)^2 + 59), algsubs(x^2 + 3*x = 64, expand((x + 2)^2 + 59))];
[(x + 2)2 + 59, x + 127]
> algsubs(x*y^2=G, x^2*y^4 + x^3*y^2 + y^4*x), algsubs(x*y^2=G, x^2*y^4 + x^3*y^6, x);
Gx2 + y2 G + G2, G3 + G2
>algsubs(x^2 + 10*y=S, 3*x^2 + 17*y), algsubs(x^2 + 10*y=S, 3*x^2 + 17*y, 'exact');
-13 y + 3 S, 3 x2 + 17 y
>G:= s^3 + 2*s^2*h - 3*s^2/h + 3*s*h^2 - 6*s + 3*s/h^2 + h^3 - 3*h + 3/h - 9/h^3:
>algsubs(s^2=1, G), algsubs(s^2=1, G, [h, s]), algsubs(1/h=h, G, [s, h]), algsubs(s*h=1, G);
|
(3 h4 − 5 h2 + 3) s |
+ |
|
−h4 |
− 9 + h6 |
, h3 |
+ 3 s h2 |
− h − 5 s + |
3 s |
|
− |
|
9 |
, |
|
|
|
||||||||||||||
|
|
h2 |
|
|
|
h3 |
h2 |
h3 |
|
|
|
||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
s3 − s2 h − 6 s + 6 s h |
2 − 8 h3, s3 − |
3 s2 |
− 4 s + |
3 s |
|
− |
9 |
+ |
3 |
|
+ h3 |
|
|
|||||||||||||||||
|
|
|
|
|
h2 |
|
|
|
|
|
|
|
|||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
h |
|
|
|
|
h3 |
|
h |
|
|
|
|
|
|
|
|||||||
> SV:= (a + b - 3)*x/(a + b) + a*y/(a + b) - b*(a + b)/z; |
|
|
SV := |
(a + b − 3) x |
|
+ |
|
a y |
− |
b (a + b) |
|||||||||||||||||||||
|
|
|
a + b |
z |
|||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a + b |
|
|
|
|
|
|
|
|||||||
> simplify([algsubs(a + b = 1/h^2, SV), algsubs(a + b = 1/h^2, SV, [a, b], 'exact')]); |
|||||||||||||||||||||||||||||||
−x z h2 |
+ 3 x z h4 + y h4 z b − y h2 z + b x z h2 − 3 x z h4 + y a h |
4 z − b |
|
|
|||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
− |
|
|
z h |
2 |
|
|
|
|
|
|
|
z h |
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
> restart: applyop(G, {[1, 2], [3, 2]}, x^y + x + y^h, z); xG(y, z) + x + yG(h, z) |
|
|
|||||||||||||||||||||||||||||
> applyop(G, 3, x + y + z, t, h) = subsop(3 = G(op(3, x + y + z), t, h), x + y + z); |
|
|
|||||||||||||||||||||||||||||
> applyop(evalf, {[1, 2], [3, 2]}, x^sin(59) + R + y^ln(17), 2); |
x0.64 + R + y2.8 |
|
|
||||||||||||||||||||||||||||
> n, h:= 1, 2: applyop(Art, [n + 1, h^n], H(x) + G(x, y), t); |
H(x) + G(x, Art(y, t)) |
С учетом сказанного особых пояснений примеры фрагмента не требуют. Вместе с тем, наряду с рассмотренными функциями поддержки подстановок в целом ряде случаев эффективно использовать две ранее рассмотренные функции numboccur(V,h) и has(V,h), возвращающие число вхождений и сам факт вхождения {true|false} h-подвыражения в V-выражение соответственно. В качестве примера ниже приводится PSubs-процедура, существенно использующая первую из указанных функций Maple-языка, т.е. numboccur-функцию.
В качестве первого аргумента PSubs-процедуры выступает последовательность, элементами которой могут быть отдельные уравнения (правила подстановок) либо их множества/списки. Вторым аргументом процедуры выступает собственно само обрабатываемое выражение. Процедура возвращает результат последовательного применения заданных первым фактическим аргументом правил в выражение, заданное ее вторым фактическим аргументом. Одновременно выводится информация по применению каждого из правил подстановки. Читателю рекомендуется разобраться в организации процедуры. С целью лучшего усвоения принципов и особенностей выполнения рассмотренных средств, имеющих важные приложения, читателю рекомендуется провести с ними определенную наработку. В частности, в качестве весьма полезного упражнения читателю рекомендуется в терминах алгебраических правил подстановок запрограммировать в среде Maple-языка хорошо известные абстрактные модели вычислителей, например машину Тьюринга (последовательная модель вычислений) и классические однородные структуры (параллельная модель вычислений) [1-3,36,40,92-96,98,100-102].
Нижеслелующий фрагмент представляет исходный текст процедуры PSubs и примеры ее применения.
113

PSubs := proc () local k, h, L, W;
`if`(nargs = 0, RETURN( ), assign(W = args[nargs ], L = 63));
for k to nargs − 1 do L := L, `if`(type(args[k], 'equation '), args[k], `if`( type(args[k], 'set'('equation ')) or type(args[k], 'list'('equation ')),
op(args[k]), RETURN("Substitution rules are incorrect" )))
end do ;
`if`(nops([L]) − 1 = nargs, RETURN(WARNING(
"Substitution rules %1 are not applicable to absent expression" , [args])),
NULL );
for k from 2 to nops([L]) do
h := numboccur (W, lhs(L[k]));
`if`(h = 0, print(cat(`Rule (`, convert(L[k], 'symbol'), `) is inactive` )), [ print(cat(`Rule (`, convert(L[k], 'symbol'), `) was applied `, convert(h, 'symbol'), ` times` )), assign('W' = subs(L[k], W ))])
end do ; W
end proc
> PSubs(x=a, {y=b, z=c}, [t=h, k=v], (Kr(x^2 + y^2 + z^2))/(t + k + sqrt(x*y - t*k)) - Art(x+z+t+k));
Ryle (x = a) was applied 3 times Ryle (y = b) was applied 2 times Ryle (z = c) was applied 2 times Ryle (t = h) was applied 3 times Ryle (k = v) was applied 3 times
Kr(a2 + b2 + c2 ) |
− Art(a + c + h + v) |
||
h + v + |
a b − h v |
||
|
> PSubs(h=a*b*c, Kr(x+y+z)*Art(x+z)+VSV(y+z)); Kr(x + y + z) Art(x + z) + VSV(y + z)
Ryle (h = a b c) is no active
Учитывая важность различного рода подстановок при работе с символьными и строчными выражениями – одними из основных составляющих символьных вычислений и обработки – нами был определен целый ряд средств данного типа, ориентированных на различные случаи приложений [41,103]. В частности, процедура Sub_st(E, S, R {, `insensitive`}) возвращает результат подстановки правых частей уравнений, определенных первым фактическим аргументом Е, в строку или символ, указанный вторым аргументом S, вместо всех вхождений в нее левых частей уравнений Е. При этом, обработке подвергаются и пересекающиеся вхождения левых частей уравнений подстановок. Более того, тип возвращаемого результата соответствует типу второго фактического аргумента S.
Результат обработки строки или символа S посредством системы подстановок Е есть только первый элемент возвращаемой 2-элементной последовательности, тогда как в качестве ее второго элемента выступает целочисленный вектор, определяющий количество выполненных применений к S соответствующих подстановок из Е. Если же левые части подстановок из Е не принадлежат S, или по меньшей мере одна подстановка инициирует бесконечный процесс, то процедура выводит соответствующее информационное предупреждение.
Правила подстановок Е задаются списком уравнений вида [Y1=X1, Y2=X2, …, Yn=Xn]; где для обеих частей уравнений предполагаются выражения типа {string, symbol}. При этом, алгоритм применения системы подстановок Е состоит в следующем: первая подстановка Е применяется к S до ее полного исчерпания в S, затем аналогичная операция проделывается со второй подстановкой из Е, и так далее до полного исчерпания всех подстановок Е.
114

При кодировании четвертого дополнительного аргумента insensitive процедура Sub_st поддерживает регистро-независимый, в противном случае выполняется регистро-зависимый поиск вхождений левых частей подстановок. Наконец, через третий фактический аргумент R возвращается следующее значение: (1) true, если обработка S была завершена успешно, (2) результат обработки S до ситуации обнаружения подстановки, ведущей к бесконечному процессу (циклическая работа). Ниже представлен фрагмент с исходным текстом процедуры Sub_st и результатами ее применения.
Sub_st := proc (E::list(equation ), S::{string , symbol}, R::evaln) local k, h, G, v, ω, p;
assign(p = {args},
ω = ((s, v) → `if`(member(insensitive , v), Case(s, 'lower'), s))); `if`(nops(E) = 0, WARNING("Substitutions system <%1> is absent" , E),
assign(G = cat("", S), R = true,
v = array(1 .. nops(E), [0 $ (k = 1 .. nops(E))])));
`if`(Search2(ω(S, p), {seq(ω(lhs(E[k]), p), k = 1 .. nops(E))}) = [ ], RETURN(assign('R' = false), S,
WARNING("Substitutions system %1 is not applicable to <%2>" , E, S)),
NULL );
for k to nops(E) do
`if`(ω(lhs(E[k]), p) = ω(rhs(E[k]), p), [assign('R' = G), RETURN(S, WARNING("Substitution <%1> generates an infinite process" , E[k])) ], assign('v[k]' = 0));
while search(ω(G, p ), ω(lhs(E[k]), p )) do
assign('h' = searchtext(ω(lhs(E[k]), p), ω(G, p)), 'v[k]' = v[k] + 1)
;
G := cat(G[1 .. h − 1], rhs(E[k]),
G[h + length(lhs(E[k])) .. length(G)])
end do end do ;
convert(G, whattype (S )), evalm(v) end proc
> S:="ARANS95IANGIANRANS95RAEIAN99RACREAIANRANSIANR99ANSRANS": Sv:=["RANS"="Art", "IAN"=" ", "95"="S", "99"="Kr"]: Sub_st(Sv, S, Z);
"AArtS G ArtSRAE KrRACREA Art RKrANSArt", [4, 5, 2, 2]
> S:="ARANS95IANGIANRANS95RAEIAN99RACREAIANRANSIANR99ANSRANS": Sv:=["RANS"="Art", "IAN"=" ", "95"="S", "99"="Kr"]: Sub_st(Sv, S, Z), Z;
"AArtS G ArtSRAE KrRACREA Art RKrANSArt", [4, 5, 2, 2], true
Наряду с целым рядом средств, обеспечивающих разнообразную обработку символьных и строчных выражений, наша библиотека [103] содержит и средства поддержки ряда полезных в практическом отношении подстановок. Читатель и сам может запрограммировать требуемые для своих конкретных приложений интересные средства, используемые многократно.
В определенной мере к средствам, обеспечивающим подстановки в выражения, примыкает и специальное use-предложение языка, имеющее следующий формат кодирования:
use <ПВ> in <ПП> end use
где ПВ – последовательность выражений типа {`=`, equation} и ПП – последовательность предложений Maple (тело use-предложения). ПВ определяет последовательность связывающих форм. В простейшем виде связывающая форма представляет собой уравнение (точнее, правило подстановки), чья левая сторона представляет имя, тогда как правой стороной уравнения может быть
115

любое выражение языка, но не их последовательность. Другие виды связывающих форм определяются в терминах эквациональных связывающих форм. В качестве связывающих форм могут выступать выражения выбора члена модуля; связывающая форма вида М:- e эквивалентна эквациональной связывающей форме e = М:- e. Наконец, в качестве связывающей формы может выступать модульное выражение либо его имя. Использование модуля М в качестве связывающей формы эквивалентно определению уравнения e = М:- e для всех экспортов e модуля М. Предложение use отличается от всех других предложений Maple-языка тем, что оно разрешается в течение автоматического упрощения, а не в процессе вычислений. Предложение use не может быть вычислено.
Предложение use вызывает синтаксическое преобразование его тела согласно подстановкам, указанным в последовательности связывающих форм. Однако, оно в отличие от простых подстановок производит их в соответствии со статическими правилами просмотра Maple-языка. Каждое use-предложение вводит новый контур связывания, в пределах которого в течение упрощения имена левых частей каждого из уравнений связывания заменяются соответствующими выражениями правых частей уравнений. Тело use-предложения "перезаписывается", выполняя указанные замены.
Каждое вхождение связующего имени (левая часть) заменяется соответствующим ему выражением (правая часть) всюду по телу use-предложения. Когда тело use-предложения вычисляется, значение связующего имени вычисляется один раз для каждого его вхождения. Это означает, что в то время как само use-предложение не налагает никаких ограничений в процессе вычисления, следует проявлять внимательность в случае, когда правые части уравнений связывания могут выполнять важные вычисления. Правые части связывающих форм не вычисляются при обработке use-предложения. Детальнее с use-предложением можно ознакомиться по конструкции ?use, здесь же мы представим примеры, иллюстрирующие применение use- предложения в различных ситуациях:
> use a = 64, b = 59, c = 39, d = 17 in (a + b)/(c+d) end use; 123/56 > P:= proc(n::posint) add(a+k, k=1..n) end proc: P(17); 153 + 17 a > use a = 64 in proc(n::posint) add(a + k, k=1..n) end proc end use;
proc(n::posint) add(64 + k, k = 1 .. n) end proc
>%(17); 1241
>use b = 64 in proc(n::posint) local b; add(b+k, k=1..n) end proc end use;
proc(n::posint) local b; add(b + k, k = 1 .. n) end proc > use add = seq in proc(n::posint) local b; add(b+k, k=1..n) end proc end use;
proc(n::posint) local b; :-seq(b + k, k = 1 .. n) end proc
>%(10); b + 1, b + 2, b + 3, b + 4, b + 5, b + 6, b + 7, b + 8, b + 9, b + 10
>use `+` = `*` in proc(n::posint) local b; add(k, k=1..n); b:=proc() global c; c*`+`(args) end proc end proc end use;
proc (n::posint) local b; add(k,k = 1 .. n); b := proc () global c; c*`+`(args) end proc end proc
> use `+` = ((a, b) -> a * b) in 64 + 56 end use; 3584
> use a = b in module() export a; a:=() -> add(args[k], k=1..nargs) end module end use; module() export a; end module
> %:- a(64, 59, 39, 10, 17); 189
> use `and` = `or` in proc() if nargs > 6 and args[1] = 64 then 2006 end if end proc end use; proc() if :-`or`(6 < nargs, args[1] = 64) then 2006 end if end proc
> %(64); 2006
Из примеров фрагмента следует, что use-предложение в процедурах и модулях игнорирует замены локальных, глобальных и экспортируемых переменных, возвращая свое тело лишь упрощенным без выполнения тех замен, левые части которых определяют имена указанного типа переменных. Более того, use-предложение не производит прямых замен, в частности, бинарных инфиксных операторов (например, `+` и `*`) или унарных префиксных или постфиксных операторов, как это иллюстрирует 8-й пример фрагмента. Тогда как такие операторы мож-
116

но заменять, если правые части связывающей формы определяют процедуры или модули, как это иллюстрирует 9-й пример фрагмента. По use-предложению можно заменять такие операторы как: `+`, `*`, `-`, `/`, `^`, `!`, `and`, `or`, `not`, `=`, `<>`, `<`, `<=`.
Представленная ниже процедура Use(P, x=x1, y=y1, …) в ряде случаев оказывается неплохим дополнением use-предложению, обеспечивая подстановки правых частей уравнений, определяемых фактическими аргументами, начиная со второго, вместо вхождений в выражение Р соответствующих им левых частей. При этом, в качестве первого аргумента Р может выступать любое выражение, кроме модулей; в противном случае вызов процедуры возвращает исходное выражение с выводом соответствующего предупреждения. На остальных выражениях Р вызов процедуры Use(P, x=x1, y=y1,…) во многом подобен результатам применения use- предложения, тогда как имеется и целый ряд особенностей. Например, Use-процедура позволяет делать прямые замены вышеуказанных операторов, обрабатывает особые и ошибочные ситуации и др. Следующий фрагмент представляет исходный текст процедуры Use и примеры ее применения.
> Use:= proc(P::anything) if nargs = 1 then P elif type(P, `module`) then WARNING("1st argument is a module; apply the `use`-clause"); return P else try eval(parse(SUB_S([seq(`if`(type(args[k], 'equation') and type(lhs(args[k]), 'symbol'), lhs(args[k]) = convert(rhs(args[k]), 'string'), NULL), k=2..nargs)], convert(eval(P), 'string')))) catch : P end try end if end proc;
Use := proc (P::anything ) if nargs = 1 then P
elif type(P, `module`) then
WARNING("1st argument is a module; apply the `use`-clause" ); return P
else
try eval(parse(SUB_S([seq(`if`(
type(args[k], 'equation ') and type(lhs(args[k]), 'symbol'),
lhs(args[k]) = convert(rhs(args[k]), 'string '), NULL ), k = 2 .. nargs ) ], convert(eval(P), 'string '))))
catch : P end try
end if end proc
>Use(proc(n::posint) local b; add(k, k=1..n); b:= proc() global c; c*`+`(args) end proc end proc, `+` = `*`);
proc(n::posint) local b; add(k, k = 1 .. n); b := proc() global c; c*`*`(args) end proc end proc
>Use(proc(n::posint) local b; add(k, k=1..n); b:=proc() global c; c*`+`(args) end proc end proc, c = d);
proc(n::posint) local b; add(k, k = 1 .. n); b := proc() global c; c*`+`(args) end proc end proc
>Use(proc(n::posint) local b; add(k, k=1..n); b:=proc() global c; c*`+`(args) end proc end proc, a = c);
proc(n::posint) local b; add(k, k = 1 .. n); b := proc() global c; c*`+`(args) end proc end proc
>Use(proc(n::posint) local b; add(k, k=1..n); b:=proc() global c; c*`+`(args) end proc end proc, k = j);
proc(n::posint) local b; add(j, j = 1 .. n); b := proc() global c; c*`+`(args) end proc end proc
>Use((a+b)/d, d = 0);
a + b
d
> use d = 0 in (a+b)/d end use;
Error, numeric exception: division by zero
117

> Use(proc(n::posint) local b; add(b+k, k=1..n) end proc, b = 64); proc(n::posint) local b; add(b + k, k = 1 .. n) end proc
> Use(module() export a; a:=() -> add(args[k], k=1..nargs) end module, a=b);
Warning, 1st argument is a module; apply the `use`-clause module() export a; end module
> %:- a(64, 59, 39, 10, 17); 189
> Use(proc() if nargs > 6 and args[1] = 64 then 2006 end if end proc, `and` = `or`); proc() if 6 < nargs or args[1] = 64 then 2006 end if end proc
> Use(proc() Digits:= 40; a*1/100000000000000000000001.0, (64 + Digits^a) end proc, a = 2); proc () Digits := 40; 0.2000000000*10^(-22), 64 + Digits^2 end proc
> %(); 0.2000000000 10 -22, 1664
При этом, если необходимо произвести обработку Use-процедурой последовательности выражений или предложений, то их можно обрамлять процедурой, как иллюстрирует последний пример фрагмента. В ряде приложений Use-процедура предпочтительнее use-предложения.
118
2.4. Средства Maple-языка для обработки выражений
Выросший из системы символьных (алгебраических) вычислений, пакет Maple располагает достаточно развитыми средствами символьных вычислений и различного рода математических преобразований, что делает его одним из наиболее мощных ПС данного типа. Такого рода средства позволяют не только получать решения в строгом алгебраическом виде, но и производить различного рода математические преобразования, важные при решении многих качественных вопросов из различных приложений. В этом плане они могут оказаться весьма полезным инструментом при исследовании целого ряда вопросов и в чистой математике. Прежде всего остановимся на группе средств, позволяющих производить различного рода преобразования выражений из одной формы в другую, упрощающие их для последующей алгебраической обработки. Данные средства важны и в практическом программировании.
Упрощение выражений. Одной из важнейших задач при работе с алгебраическими выражениями является упрощение как конечных, так и основных промежуточных результатов символьных вычислений. Для этих целей Maple-язык располагает специальной simplify-процедурой имеющей следующий формат кодирования:
simplify(<Выражение> {, <Тип упрощения>} {, assume = <Свойство>})
и производящей упрощение заданного своим первым фактическим аргументом выражения путем применения к нему специальных процедур упрощения. Если процедура содержит единственный аргумент-выражение, то производится анализ выражения на предмет вхождения в него вызовов функций, квадратных корней, радикалов и степеней.
После этого к выражению применяются подходящие упрощающие процедуры, включающие функции: Бесселя, Гамма, Ламберта, ex, ln, √x, тригонометрические, гиперболические и др., т.е. производится возможное упрощение исходного выражения по всему спектру возможностей функции. Третий необязательный фактический аргумент функции позволяет приписывать всем переменным упрощаемого выражения определенные свойства, которые будут приписаны переменным упрощенного выражения, либо определять параметры, управляющие применением правил упрощения. Второй аргумент функции также является необязательным и определяет принцип упрощения исходного выражения, определяемого первым аргументом, согласно специальным типам упрощающих правил. В качестве второго аргумента simplify-про- цедуры могут выступать отдельный идентификатор, список или множество идентификаторов, определяющих специальные типы упрощения исходного выражения. В качестве таких идентификаторов допускаются следующие, определяемые в табл. 9:
|
Таблица 9 |
|
|
Тип |
Производится упрощение выражения, содержащего: |
`@` |
операторы; как правило при работе с обратными функциями |
Ei |
экспоненциальные интегралы; Ei(1, x*I) → -Ci(x) + Sin(x)*I - π*I/2 |
GAMMA |
GAMMA-функции |
hypergeom |
гипергеометрические функции; представление в виде степенного ряда |
ln |
логарифмические функции |
piecewise |
кусочно-определенные функции; например: abs, sign, Signum и др. |
polar |
комплексные выражения, представленные в полярных координатах |
power |
степени, экспоненты и логарифмы; допускается symbolic-параметр |
radical |
радикальные конструкции различного типа |
RootOf |
RootOf-функцию; упрощаются полиномы от нее и их обращения |
sqrt |
корни квадратные и/или их степени; допускается symbolic-параметр |
siderel |
комбинации упрощающих уравнений из заданного {списка|множества} |
trig |
тригонометрические и/или гиперболические функции |
wronskian |
подвыражения вида xy' - yx', где x, y - специальные функции |
119

Смысл и назначение каждого из представленных в табл. 9 значений для второго фактического аргумента simplify-процедуры достаточно прозрачны и проиллюстрированы в нижеследующем фрагменте, однако по отдельным необходимы пояснения.
> [x@exp@ln, simplify(x@exp@ln, `@`)]; [x@exp@ln, x]
> simplify(GAMMA(p+1)*(p^2+3*p+2)*x + GAMMA(p+3), GAMMA); (1 + x) Г(p + 3) > simplify(ln(95), ln), simplify(ln(64*x+42*r), ln);
ln(5) + ln(19), ln(2) + ln(32 x + 21 r)
> simplify(64*signum(x) + 59*abs(x) - 39*sign(x), piecewise);
−59 x − 103 |
x < 0 |
|
|
|
|
|
-39 |
x = 0 |
|
||
|
|
|
|
59 x + 25 |
0 < x |
|
> map(simplify, [x*3**y*10, (x**y)^(x**z), exp(3*ln(x^3) + 10**x)], power);
[10 x 3y, (xy )( xz ), x9 e(10x ) ]
>G:= [64^(1/4), 180^(2/3), (-1999)^(1/3), sqrt(191)]: simplify(G, radical);
|
(2/3 ) (1 + 3 I ) 1999( 1/3 ) |
|
|
|
|
|
|
2 2, 180 |
, |
|
, 191 |
|
|||
|
|
2 |
|
> simplify((x^6 + x^5*y - 2*x^4*y^2 - 2*x^3*y^3 + x^2*y^4 + x*y^5)^(1/3));
(x (x − y)2 (x + y)3 )(1/3 )
>s:= RootOf(t^2 – 13 = 0, t): [3*s^2 – s + 10, simplify(3*s^2 – s + 10, RootOf)];
[3 RootOf(_Z2 − 13)2 − RootOf(_Z2 − 13) + 10, 49 − RootOf(_Z2 − 13)]
>h:= (64*s - 59)/(s^2 + 10*s + 17): [h, simplify(h, RootOf)];
|
64 RootOf(_Z2 − 13) − 59 |
|
|
251 |
|
|
||||||
|
|
|
|
|
|
|
|
, − |
|
|
RootOf(_Z2 |
− 13) |
|
|
|
2 |
|
|
|
|
|
||||
|
|
2 |
|
|
2 |
|
|
40 |
|
|
|
|
|
RootOf(_Z |
− 13) |
|
+ 10 RootOf(_Z |
− 13) + 17 |
|
|
|
||||
|
|
|
|
|
|
|
|
> p:= (12*v^2 - 191*v + 243)^(1/2): [p, simplify(p, sqrt, symbolic)];
[ 12 v2 − 191 v + 243, 12 v2 − 191 v + 243 ]
> [(64/(x - 10)^2)^(1/2), simplify((64/(x - 10)^2)^(1/2), sqrt, symbolic)];
|
|
1 |
|
|
8 |
|
|
64 |
|
|
, |
|
|
|
|
x − 10 |
||||
|
|
(x − 10) |
2 |
|
|
|
|
|
|
|
|
|
> [sin(x)^2 - cos(x)^2, simplify(sin(x)^2 - cos(x)^2, trig)];
[sin(x)2 − cos(x)2, −2 cos(x)2 + 1]
>[sinh(x)^2*cosh(x) - cosh(x)^3, sin(x)*tan(x) + sec(x)+cos(x)];
[sinh(x)2 cosh(x) − cosh(x)3, sin(x) tan(x) + sec(x) + cos(x)]
>map(simplify, %, trig);
1009
+
40
cosh(x), cos(x)
>simplify(57*x^4-52*x^3+32*x^2-10*x+3, {13*x^2+3*x+10 = 0});2
865232197x + 12012197
> SV:= 6*z*y^2 + 6*z^4*y^3 - 18*z^2*y + 112 + 53*z^2 + 14*z*y - 306/5*y^2 + 3*x*z - 3*x*y + 18*z^4 + 8*z^3*y - 4*z^2*y^2 - 8*z*y^3 + 4*y^4:
> simplify(SV, {x*z - y^2=x, x*y^2 + z^2=z, (z+y)^2=x, (x+y)^2=z}, {x,y,z}); 112 + 74 x
>Sideral:= {sin(x)^2 + cos(x)^2 = 1, 2*sin(x)*cos(x) = 1 - (cos(x) - sin(x))}:
>Expression:= sin(x)^3 - 3*sin(x)^2*cos(x) - cos(x)^3 - sin(x)*cos(x) + sin(x)^2 + 2*cos(x):
> H1:= BesselJ: H2:= BesselY: simplify(Expression, Sideral); cos(x)3
> simplify(Pi*y*(H1(x + 1, y)*H2(x, y) - H1(x,y)*H2(x + 1, y)), wronskian); 2
> simplify(cos(x)*diff(sin(x), x) - sin(x)*diff(cos(x), x), wronskian); sin(x)2 + cos(x)2
За более детальным описанием и особенностями применения simplify-процедуры можно обращаться к справке по пакету или к нашей книге [12], принимая во внимание, что и релиз накладывает свои особенности. Вместе с тем, представленной информации вполне достато-
120