Смекни!
smekni.com

Программирование и разработка приложений в Maple (стр. 55 из 135)

Для обеспечения возможности вывода из процедур полезной для пользователя информации в теле процедуры можно помещать специальную встроенную функцию userinfo, имеющую следующий простой формат кодирования:

userinfo(<Уровень>, <Id>, <Выражение_1> {, ... , <Выражение_n>})

и позволяющую в соответствии с указанным уровнем выводить информацию, представляемую ее аргументами, начиная с третьего (обязательного), для процедур, чьи идентификаторы задаются вторым аргументом функции, допускающим как отдельное имя, так и их множество. Вывод информации, получаемой в результате вычисления выражений_к, производится только в том случае, если определенный первым аргументом функции уровень не превышает установленного в infolevel-таблице для ее all-входа. Исходным состоянием таблицы является: print(infolevel); ⇒ table([hints=1])). Ее единственный hintsвход определяет вывод результата вызова функции/процедуры невычисленным, если невозможно получить его точное значение. Вычисленные выражения userinfo-функции выводятся в lprint-формате, разделенные тремя пробелами.

Предложение infolevel[all]:=m определяет общий уровень вывода для всех последующих процедур, содержащих userinfo-функцию. Соответствующая информация выводится только тогда, когда определяемый их первым аргументом уровень не превышает указанного в предложении infolevel уровня m, например:

> infolevel[all]:= 10; ⇒ infolevel[all] := 10 > P1:=proc() userinfo(5,P1, `Суммирование `||nargs||` аргументов`); `+`(args) end proc: > P2:=proc() userinfo(12,P2,`Суммирование `||nargs||` аргументов`); `+`(args) end proc: > P1(10, 17, 39, 44, 59, 64); restart: ⇒ 233 P1: Суммирование 6 аргументов

> P1:= proc() global infolevel; infolevel[P1]:= 6: userinfo(5, P1, `Суммирование `||nargs|| ` аргументов`); `+`(args) end proc:

> P2:= proc() global infolevel; infolevel[P2]:= 9: userinfo(12, P2, `Суммирование `||nargs|| ` аргументов`); `+`(args) end proc: > P1(10, 17, 39, 44, 59, 64); restart: ⇒ 233 P1: Суммирование 6 аргументов

> P2(10, 17, 39, 44, 59, 64); ⇒ 233

> print(infolevel); ⇒ table([hints = 1, P1 = 6, P2 = 9])

В частности, библиотечные процедуры пакета используют следующие информационные уровни вывода: (1) - обязательная информация; (2, 3) - общая информация, включая метод решения проблемы, и (4, 5) - детальная информация по процедуре.

При отсутствии для процедур общего уровня вывода информации он определяется на основе индивидуальных infolevel-предложений, кодируемых либо в теле самих процедур, либо вне их в виде infolevel[<Имя процедуры>]:= Уровень. По данному предложению соответствующая информация заносится в infolevel-таблицу, с которой работают функции userinfo процедур. Последний пример предыдущего фрагмента иллюстрирует сказанное. Средство userinfo-функции довольно полезно для обеспечения пользователя документированными процедурами.

В случае определения выхода процедуры через RETURN-функцию (return-предложение) следует кодировать предложения infolevel и userinfo перед ним, ибо в противном случае действие последних подавляется, как это иллюстрирует следующий простой фрагмент:

> infolevel[all]:= 10; ⇒ infolevel[all] := 10

> P1:= proc() local infolevel; userinfo(5, P1, `Суммирование `||nargs||` аргументов`); `+`(args); end proc:

> P2:= proc() local infolevel; return `+`(args); userinfo(5, P2, `Суммирование `||nargs||` аргументов`); end proc:

> P1(10, 17, 39, 44, 59, 64); ⇒ 233

P1: Суммирование 6 аргументов

> P2(10, 17, 39, 44, 59, 64); restart: ⇒ 233

> P1:= proc() local infolevel; infolevel[P1]:= 10: userinfo(2, P1, `Суммирование `||nargs||` аргументов`); `+`(args); end proc:

> P2:= proc() global infolevel; infolevel[P2]:=10: userinfo(2, P2, `Суммирование `||nargs||` аргументов`); `+`(args) end proc:

> P1(10, 17, 39, 44, 59, 64); print(infolevel); ⇒ 233 table([hints = 1])

> P2(10, 17, 39, 44, 59, 64); print(infolevel); ⇒ 233 table([hints = 1, P2 = 10])

P2: Суммирование 6 аргументов

При этом, последние два примера фрагмента иллюстрируют необходимость глобального определения infolevel-переменной, иначе она не редактирует соответственно infolevelтаблицы пакета и не влияет на вывод userinfo-информации.

Для обеспечения мониторинга основных вычислительных ресурсов, затребованных при выполнении процедур/функций, служит группа profile-процедур, позволяющих получать оперативную информацию по выполнению указанных процедур или функций в разрезе: количество вызовов, временные издержки, требуемая оперативная память и др. Информация выводится в табличном виде, смысл которой особых пояснений не требует. Для инициации режима мониторинга процедур/функций используется процедура profile(P1, ..., Pn), которая в случае успешного вызова возвращает значение NULL и по которой устанавливается режим мониторинга вызовов Pj-процедур, определяемых ее фактическими аргументами. При этом, следует иметь в виду, что попытка вызова процедуры profile для уже находящейся в режиме profile-мониторинга процедуры либо функции вызывает ошибочную ситуацию, как это иллюстрирует пример нижеследующего фрагмента. По вызову profile() производится мониторинг вызовов всех процедур и функций в текущем сеансе. Однако, в таком объеме profile-средство рекомендуется использовать с большой осторожностью во избежание существенных замедления вычислений и увеличения используемой памяти, вплоть до критического.

Результаты мониторинга носят кумулятивный характер и их можно периодически выводить по showprofile({ |P1,...,Pn})-процедуре в разрезе или всех профилируемых процедур, или только относительно Pj-указанных в качестве фактических аргументов процедуры. По вызову unprofile({|P1 ,..., Pn})-процедуры производится прекращение режима мониторинга в разрезах, аналогичных предыдущей процедуры. Результатом успешного вызова unprofile-процедуры является возврат NULL-значения, удаление профильной информации и прекращение режима мониторинга по соответствующим процедурам или функциям. Повторное применение unprofile-процедуры вызывает ошибочную ситуацию. Следующий фрагмент иллюстрирует применение рассмотренных средств для мониторинга пользовательской VSV-процедуры и некоторых встроенных функций языка.

> VSV:= proc() local k; product(args[k], k=1 .. nargs) end proc: profile(VSV); > [VSV(10, 17, 39, 44, 59, 64), VSV(96, 89, 67, 62, 47, 42), VSV(k$k=1..9)];

[1101534720, 70060765824, 362880]

> showprofile(VSV);

function depth calls time time% bytes bytes% -----------------------------------------------------------------------------------

VSV 1 3 0.000 0.00 23896 100.00 ----------------------------------------------------------------------------------- total: 1 3 0.000 0.00 23896 100.00

> profile(VSV);

Error, (in profile) VSV is already being profiled.

> profile(sin, exp); [sin(6.4), sin(4.2), exp(0.59), sin(17)*exp(10)]: showprofile();

function depth calls time time% bytes bytes% ------------------------------------------------------------------------------------ sin 1 3 .016 100.00 16172 35.00 exp 1 2 0.000 0.00 6140 13.29 VSV 1 3 0.000 0.00 23896 51.71 ------------------------------------------------------------------------------------ total: 3 8 .016 100.00 46208 100.00

> unprofile(): showprofile(); function depth calls time time% bytes bytes%

------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------- total: 0 0 0.000 0.00 0 0.00

С учетом сказанного особых пояснений примеры фрагмента не требуют. Близкой по назна-чению к profile-процедуре является и exprofile-процедура, обеспечивающая мониторинг всех вызовов пакетных процедур и функций. С другими типами мониторинга различных аспектов выполнения процедур и/или функций в среде Maple-языка можно ознакомиться в [31, 33,43,84,103]. Рассмотренные средства мониторинга предоставляют полезную информацию, в частности, для оптимизации вычислений.

Создав собственную серьезную процедуру с использованием других своих и пакетных процедур и функций, поместив ее в свою библиотеку, естественно возникает задача ее оптимизации, в частности, с целью раскрытия частоты использования средств, содержащихся в ней, и основных компьютерных ресурсов, используемых ими. В этом контексте, проблема оптимизации пользовательских процедур весьма актуальна. Для этих целей достаточно полезной представляется процедура StatLib(L) [103], обеспечивающая сбор основной статистики по заданной L-библиотеке и возврату статистики для последующего анализа. В процессе своего выполнения StatLib-процедура требует некоторых дополнительных ресурсов памяти и времени. Подробнее о ней будет идти речь при рассмотрении создания библиотек пользователя.

В заключение настоящего раздела отметим, что более искушенный пользователь может при работе с процедурами воспользоваться специальными двумя процедурами procbody и procmake. По вызову процедуры procbody(P) возвращается специальная невычисленная форма процедуры с P-именем, которая может быть протестирована и модифицирована, не затрагивая исходной P-процедуры. Обратной к ней является процедура procmake(G), возвращающая на основе специальной G-формы выполняемую Maple-процедуру. Следующий простой фрагмент иллюстрирует вышесказанное:

> AGN:= proc() `+`(args)/nargs end proc: AGN1:= procbody(AGN); procmake(AGN1); > AGN1:= procbody(AGN); procmake(AGN1);

 , &expseq( ), &expseq( ), &expseq( ),

AGN1 := &proc &expseq( )

+ &function&expseq(&args-1 ) 

, &expseq( ), &expseq( ), &expseq( ) &args0 proc () `+`(args)/nargs end proc

Использование данных функций предполагает достаточную искушенность пользователя по работе в среде Maple-языка, поэтому за детальной информацией заинтересованный читатель отсылается к интересным работам, цитированным в книгах [12,13].

Отметим теперь некоторые принципиальные новации относительно процедур, появившиеся в последнем релизе 10. Во-первых, как правило, количество передаваемых процедуре при вызове фактических аргументов не обязательно должно совпадать с количеством ее формальных аргументов. Однако, если при определении процедуры в конце ее формальных аргументов закодирован символ-маркер «$», то передача процедуре при вызове дополнительных фактических аргументов вызывает ошибочную ситуацию с диагностикой "invalid input: %1 arguments passed to %2 but only %3 positional parameters specified", как это весьма наглядно иллюстрирует следующий простой фрагмент: