> G:= 64*y*z + 10*RootOf(x^5 – y + 59*y - 99*x^3/y, x):
> [type(G, algfun(rational)), type(G, algfun(rational, z))]; ⇒ [true, false]
> S:= arcsin(x*y): [type(S, arctrig(x)), type(S, arctrig(y))]; ⇒ [true, true]
> [type(sin(x)*cos(y) ,oddfunc(x)), type(sin(x)*cos(y), oddfunc(y))]; ⇒ [true, false]
> type((64^(1/5)*z^3 + 10*sqrt(x))^(1/6), 'radfunext'); ⇒ true
> typematch(GS(x, y, z, Art(h), Kr(t)), function, 't'); ⇒ true
> map(type, [WeierstrassSigma,InverseJacobiSD,MeijerG], 'mathfunc'); ⇒ [true, true, true]
Как следует из последнего примера фрагмента, для тестирования математических функций указываются только их идентификаторы. Наряду с рассмотренными выше возможностями {type|typematch}-функции по тестированию Maple-выражений, частным случаем которых является функция, представленные здесь новые возможности позволяют проводить достаточно детальную (насколько это вообще на сегодня возможно) апробацию как функционального типа выражений, так и математического типа собственно самих тестируемых функций.
В качестве весьма полезного тестирующего средства представляется также процедура: hasfun(<Выражение>, <IdF> {, <Ведущая переменная>})
позволяющая определять факт вхождения (true) в заданное первым аргументом выражение функции (или функций в случае их списка/множества), заданной вторым IdF-аргументом, возможно, по ведущей (ведущим в случае их списка/множества) переменной, заданной ее необязательным третьим аргументом, например:
> G:=(L(x)+AG(x+y)/Art(z)+Kr(t))/(V(x)+W(y)): hasfun(G, [W,AG,Art,Kr], {y, z, t}); ⇒ true
Данная функция часто используется для проверки вхождения заданных функций в подинтегральное выражение, а также в задачах символьной обработки выражений.
Функциональная структура анализируется рассмотренными выше функциями op и nops, возвращающими результаты согласно следующим соотношениям: nops(F(x1, ..., xn)) ⇒ n op(F(x1, ..., xn)) ⇒ x1, ..., xn op(0, F(x1, ..., xn)) ⇒ F op(k, F(x1, ..., xn)) ⇒ xk (k > 0)
Следующий простой фрагмент иллюстрирует вышесказанное:
> [op(0, G(x,y,z,h))], [op(G(x, y, z, h))], [nops(G(x, y, z, h))]; ⇒ [G], [x, y, z, h], [4]
> [op(k, G(x, y, z, h))]$'k' = 0 .. nops(G(x, y, z, h)); ⇒ [G], [x], [y], [z], [h]
При решении целого ряда математическиих задач определенный интерес представляет тип arity, отсутствующий в Maple релизов 6-10. Вызов процедуры type(F, arity(n)) [41,103] возвращает true-значение, если F является функцией или процедурой n-арности; в противном случае возвращается false-значение. Более того, через глобальную переменную 'narity' возвращается реальная арность произвольной функции/процедуры F, например:
proc(F::{procedure, function}, n::nonnegative) local a k, ; global `n-arity`; if type(F, 'procedure') then a := [op 1,( eval(F))] else assign(k = 0, a = [ ]); do k := k + 1; try a := [op(a), op(k F, )] catch : break end try end do end if; assign('`n-arity`' = nops(a)), `if`(`n-arity` = n true false, , ) end proc > F:= f(x1, x2, x3, x4, x5, x6): G:= g(x): S:= s(x1, x2, x3, x4, x5, x6): V:=v(a, b, c, d, e, f, h): > Art:= proc(x, y, z) [y, x, z] end proc: Kr:= proc(a, b, c, d, e, h) {a, b, c, d, e, h} end proc: > seq([type(k, arity(6)), `n-arity`], k = [F, G, S, V, Art, Kr]); [true, 6], [false, 1], [true, 6], [false, 7], [false, 3], [true, 6] |
Идентификаторы пакетных функций имеют protected-атрибут, защищающий их от модификации со стороны пользователя; для обеспечения подобной защиты пользовательских функций/процедур следует использовать protect-процедуру, рассмотренную выше, либо следующие две функции, обладающие более широкими возможностями: attributes(B) – тестирование наличия и типа атрибутов у В-выражения; setattribute({B, A|B}) – присвоение A-атрибутов В-выражению либо их отмена.
где в качестве В-выражения допускаются: идентификаторы, списки, множества, невычисляемые вызовы функций либо float-значения, тогда как А-атрибутом может быть любое корректное Maple-выражение либо их последовательность, определяющая набор атрибутов для В-выражения. По attributes-функции возвращается последовательность приписанных В-выражению атрибутов либо NULL-значение при их отсутствии. Тогда как по setattrubute-функции или приписываются А-атрибуты В-выражению, или отменяются приписанные ему при отсутствии у функции второго аргумента. Приписанные В-выражению атрибуты переносятся и на объект W (W:= B;), которому оно присваивается; при этом отмена атрибутов для одного из этих объектов автоматически отменяет их и для другого. Следует иметь в виду, что по предложению restart отменяются все атрибуты, приписанные выражениям в текущем сеансе. Следующий фрагмент иллюстрирует использование механизма атрибутов пакета:
> [attributes(sin), protect(GS), attributes(GS)]; ⇒ [protected, _syslib, protected] > Vasco = H(x, y): setattribute('Vasco', protected, 'float'); ⇒ Vasco > attributes('Vasco'); ⇒ protected, float > W:= Vasco: attributes(W); ⇒ protected, float > setattribute(W): [attributes(W), attributes(Vasco)]; ⇒ [] (пустой список атрибутов) > [setattribute(V, 64), setattribute(G, 59)]; ⇒ [V, G] > [attributes(V), attributes(G)]; ⇒ [64, 59] > setattribute('Vasco', 'protected', 'float'): restart; > [attributes(V), attributes(G), attributes(Vasco)]; ⇒ [] (пустой список атрибутов) |
Механизм атрибутов позволяет не только проводить их пакетную обработку, например, по распознаваемому ядром protected-атрибуту, но и пользователь имеет возможность организовывать достаточно интересные условные обработки выражений на основе приписанных им атрибутов, пример чему может дать следующий весьма простой пример:
> V:= 64: setattribute('V', 'integer'): [V, attributes('V')]; ⇒ [64, integer]
> V:= `if`(attributes('V') <> 'integer', 1995, 2006): V; ⇒ 2006
Вместе с тем следует отметить, что аналогичный механизм атрибутов, поддерживаемый пакетом Mathematica [6,7], представляется нам существенно более развитым.
Функциональный идентификатор может использоваться в алгебраических скобочных конструкциях в сочетании с @-оператором, определяющим композицию функций, образуя новые функциональные выражения. Следующие достаточно прозрачные функциональные правила поддерживаются Maple-языком, а именно:
> (S + G)(x, y, z), (S - G)(x, y, z), (-G)(x, y, z), (S@G)(x, y, z); S(x,y,z) + G(x,y,z), S(x,y,z) - G(x,y,z), -G(x,y,z), S(G(x,y,z)) > (S@G)(x, y, z), (G@@5)(x, y, z); ⇒ S(G(x,y,z)), (G(5))(x,y,z) > expand(%[2]); ⇒ G(G(G(G(G(x, y, z))))) > (S + G)(x[k]$k=1 .. n), (S@G)(x[k]$k=1 .. n); S(x $ (k = 1 .. n)) + G(x $ (k = 1 .. n)), S(G(x $ (k = 1 .. n))) k k k > (10*G@S@@2 + 17*S^2@G - S@G@H)(x, y, z)/(G@S@V@@2 - M^3@V + A@N@O)(x, y, z); (2) 10 G((S )(x y z, , )) + 17 S(G(x y z, , ))2 − S G(( H(x y z, , ))) (2) G S(( (V )(x y z, , ))) − M V( , , )( x y z )3 + A N(( O(x y z, , ))) > (sqrt@cos^2@ln + H@exp - G@(sin + cos)/(Art + Kr))(x); cos ln( )( x )2 + H(ex) − G(sin(x) + cos(x))Art( )x + Kr( )x |
где “@@n” обозначает n-кратную композицию функции, определяемую соотношением:
(G@@n)(...) = G(n)(...) = G(G(G...G(...)...))
иллюстрируемым примерами предыдущего фрагмента. В терминах @-оператора для функции seq имеют место (в ряде случаев весьма полезные) соотношения, а именно: seq(A(k), k =[B(x)]) ≡ seq(A(k), k ={B(x)}) ≡ (A@B)(x) ≡ A(B(x)) seq(A(k), k =x) ≡ seq(A(k), k =B(x)) ≡ A(x)
Активные и пассивные формы функций. Наряду с вычисляемыми в отмеченном выше смысле функциями, чьи идентификаторы начинаются со строчных букв, Maple-язык располагает т.н. пассивными (inert) функциями (операторами), идентификаторы которых начинаются с заглавной буквы. Maple-язык различает более 50 таких пассивных процедур/функций (Diff, Int, Limit, Sum, Produc, Normal и др.), суть которых нетрудно усматривается из самого их названия. В общем случае Maple-язык рассматривает идентификаторы видов Abb...b и abb...b (b - любой допустимый для имени символ) как имена соответственно пассивной и вычисляемой функции/процедуры одного и того же назначения. Пассивные функции/процедуры имеют два основных назначения: (1) для символьных вычислений и преобразований и (2) для вывода в Maple-документах конструкций в математической нотации. Для вычисления пассивных функций/процедур и выражений в целом служит процедура value(Выражение), например:
> Int(sqrt((1 + x)/(1 - y)), x); simplify(value(%)); ⌠ 11 − + yx dx 2 (1 + x) − 1y − + 1x⌡ 3 k> Product((1 + x)^k, k = 1 .. 10); value(%); ⇒ k = 1 (1 + x)55 |
> Limit((1 + 1/j)^j, j = infinity); value(%); ⇒ j → lim∞ 1 + 1j j e > Sum(k^4*ithprime(k), k = 1 .. 17)/Product(ithprime(k), k = 1 .. 10); value(%); ithprime( )k k = 1 10 ∏ ithprime( )kk = 1 |
Активная функция/процедура, начинающаяся со строчного символа, инициирует немедленное вычисление результата, тогда как пассивная функция/процедура, начинающаяся с прописного символа, возвращает невычисленный результат в стандартной математической нотации, для полного вычисления которого требуется применение value-процедуры. При этом, следует отметить, что value-процедура может быть распространена и на случай пользовательских функций. В случае невозможности вычислить выражение функция возвращает его в исходном виде. Многие из пассивных функций/процедур Maple-языка широко используются в конъюнкции с evala-процедурой и операторами mod, modp1 модульной арифметики пакета.