авторефераты диссертаций БЕСПЛАТНАЯ БИБЛИОТЕКА РОССИИ

КОНФЕРЕНЦИИ, КНИГИ, ПОСОБИЯ, НАУЧНЫЕ ИЗДАНИЯ

<< ГЛАВНАЯ
АГРОИНЖЕНЕРИЯ
АСТРОНОМИЯ
БЕЗОПАСНОСТЬ
БИОЛОГИЯ
ЗЕМЛЯ
ИНФОРМАТИКА
ИСКУССТВОВЕДЕНИЕ
ИСТОРИЯ
КУЛЬТУРОЛОГИЯ
МАШИНОСТРОЕНИЕ
МЕДИЦИНА
МЕТАЛЛУРГИЯ
МЕХАНИКА
ПЕДАГОГИКА
ПОЛИТИКА
ПРИБОРОСТРОЕНИЕ
ПРОДОВОЛЬСТВИЕ
ПСИХОЛОГИЯ
РАДИОТЕХНИКА
СЕЛЬСКОЕ ХОЗЯЙСТВО
СОЦИОЛОГИЯ
СТРОИТЕЛЬСТВО
ТЕХНИЧЕСКИЕ НАУКИ
ТРАНСПОРТ
ФАРМАЦЕВТИКА
ФИЗИКА
ФИЗИОЛОГИЯ
ФИЛОЛОГИЯ
ФИЛОСОФИЯ
ХИМИЯ
ЭКОНОМИКА
ЭЛЕКТРОТЕХНИКА
ЭНЕРГЕТИКА
ЮРИСПРУДЕНЦИЯ
ЯЗЫКОЗНАНИЕ
РАЗНОЕ
КОНТАКТЫ


Pages:     | 1 |   ...   | 2 | 3 || 5 | 6 |   ...   | 20 |

«Международная Академия Ноосферы Балтийское отделение В.З. Аладьев, Д.С. Гринь Расширение функциональной среды системы Mathematica ...»

-- [ Страница 4 ] --

Map[Attributes,Flatten[{t, SetAttributes}]] Out[696]= {{Listable}, {Listable}, {Listable}, {HoldFirst, Protected}} В предыдущем фрагменте представлена строчная структура Headd, представляющая собой определение процедуры Head, одноименной со стандартной функцией Head с расширением функциональных возможностей последней. В качестве примера далее приведен вызов RepStandFunc[Headd, Head, {{{a}, {b, c}, {d}}}], в результате которого к списку NestList-типа разово применяется модифицированная версия функции Head (Headd), возвращая на таком списке его заголовок как NestList, тогда как стандартная функция Head на данном списке возвращает заголовок List.

Модификации процедуры Head в строчной структуре Headd довольно просты (путем соответствующего расширения списков, представляемых локальными переменными b и c), в принципе позволяя расширять список заголовков сколь угодно широко. Но в качестве составляющей шаблонов типа "x_h" данные заголовки Mathematica не распознаются, как это весьма наглядно иллюстрирует пример фрагмента с функцией G. Более того, данный результат имеет место как при использовании процедуры RepStandFunc, так и при пролонгированной замене (на весь период текущего сеанса) стандартной функции Head ее модификацией, находящейся в строчной структуре Headd. В результате этой процедуры требуется перезагрузка пакета для восстановления оригинальной версии функции Head, если до того она не была сохранена в файле mx–формата, из которого ее можно было бы загрузить в текущий сеанс, как делает процедура RepStandFunc.

Наконец, завершает фрагмент функция SetAttributes1, чей вызов SetAttributes1[x, y] расширяет стандартную функцию SetAttributes на форму представления первого x аргумента, в качестве которого могут выступать индексированные переменные, списки и др., например, обеспечивая установку атрибутов y для элементов списка. Между тем, описанный механизм разового применения одноименных заменителей стандартных функций в целом ряде случаев достаточно эффективен, тогда как пролонгирование таких заменителей на текущий сеанс пакета может вызвать конфликтные ситуации с его функциями, существенно использующими оригиналы замещенных средств. Итак, данный механизм следует использовать достаточно осмотрительно.

В.З. Аладьев, Д.С. Гринь 3.7. Определение тестирующих условий для шаблонов Пакет Mathematica обеспечивает общий механизм для определения ограничительных условий для шаблонов. Этот механизм весьма прост и состоит в размещении в конце шаблона конструкции формата "/;

Условие", что служит определителем, что такой шаблон применим, если Условие получает значение True. Наиболее используемыми форматами кодирования условий для шаблонов являются следующие, а именно:

Шаблон/;

Условие – шаблон применим лишь при достижения Условием True;

Lhs:Rhs/;

Условие – правило применимо лишь при достижения Условием True;

Lhs:=Rhs/;

Условие – определение применимо лишь при достижения Условием True.

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

Так, в типичных случаях задаются шаблоны, структурно соответствующие широкому диапазону выражений, например, "x_", в то время как применение ограничений дает возможность сократить диапазон допустимых выражений, например, "x_/;

ListQ[x]", когда для переменной x допускаются только выражения, для которых Head[x] = List.

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

In[1767]:= G[x_Integer, y_Integer, z_Integer] := x*y*z /;

x + y + z = In[1768]:= {G[42, 75, 6], G[16, 23, 2], G[35, 35, 0], G[35, 35, 1], G[3.5, 35, 1]} Out[1768]= {G[42, 75, 6], 736, 0, G[35, 35, 1], G[3.5, 35, 1]} Данный подход целесообразен, в частности, в том случае, когда условием необходимо связать все либо часть переменных из шаблонов формальных аргументов некоторого определения, как это и имело место в предыдущем примере – в качестве фактических аргументов допускаются не только целые числа, но и сумма их не должна превышать 70. При нарушении этих условий вызов функции G возвращается невычисленным.

В большинстве случаев для шаблонов используются условия, применяющиеся только к выражениям с определенными свойствами. Mathematica располагает целым рядом встроенных, т.н. Q–функций, для тестирования свойства выражения. Имена данных функций заканчиваются буквой Q (первая буква слова Question – вопрос), а количество таких функций порядка 60 для версии 8.0.4 пакета. Каждая из группы таких функций NameQ имеет простой смысл – вызов NameQ[w] возвращает True, если выражение w имеем искомый тип (как правило, легко усматриваемый из самого имени функции), и False в противном случае. Приведем некоторые из наиболее часто используемых функций данной группы, возвращающих на произвольном выражении x значение True, если:

IntegerQ[x] – целое число, иначе возвращается False;

EvenQ[x] – целое четное число, иначе возвращается False;

OddQ[x] – целое нечетное число, иначе возвращается False;

PrimeQ[x] – простое число, иначе возвращается False;

Расширение функциональной среды системы Mathematica NumberQ[x] – число любого вида, иначе возвращается False;

NumericQ[x] – числовое значение, иначе возвращается False;

VectorQ[x] – вектор, иначе возвращается False;

MatrixQ[x] – матрица, иначе возвращается False;

DigitQ[x] – все символы в строке x – десятичные цифры, иначе возвращается False;

StringQ[x] – x является строкой, иначе возвращается False;

LetterQ[x] – все символы в строке x являются буквами, иначе возвращается False;

UpperCaseQ[x] – все символы в строке x заглавные буквы, иначе возвращается False;

FreeQ[x, y] – в выражение x не входят подвыражения, соответствующие по форме или шаблону y, иначе возвращается False;

StringFreeQ[x, y] – в строку x не входят подстроки y, иначе возвращается False;

MemberQ[x, y] – в список x в качестве элементов входят выражения, соответствующие по форме или шаблону y, иначе возвращается False;

MatchQ[x, y] – выражение x соответствует по форме или шаблону y, иначе False;

SameQ[x, y] – выражение x идентично выражению y, иначе возвращается False;

UnsameQ[x, y] – выражение x не идентично выражению y, иначе возвращается False.

Практически, все из перечисленных функций используются в процедурах/функциях, представленных в настоящей книге, с остальными функциями данной группы можно ознакомиться в справке по пакету, смысл их довольно прозрачен и каких-либо особых пояснений не требует. Между тем, средства данной группы, на наш взгляд, довольно ограничены в функциональном отношении, поэтому пользователям пакета в целом ряде случаев вполне может оказаться целесообразным определить дополнительно и свои средства, расширяющие указанную группу стандартных Q–функций. Именно в данном контексте нами и был определен ряд процедур и функций, которые с полным основанием можно отнести к рассмотренной группе тестирующих функций. Данные средства появились в процессе программирования других средств, когда выяснилась целесообразность определения для них тестирующих средств, оказавшихся довольно широкого спектра применения. Эти средства рассматриваются в настоящей книге, а также включены в состав нашего пакета AVZ_Package [90] с FreeWare лицензией.

Наряду с рассмотренными выше Q-функциями нами определен ряд т.н. Is-функций, также носящих тестирующий характер и возвращающих True в случае удовлетворения соответствующего теста, и False в противном случае. Примерами таких процедур или функций выступают IsFile, IsFileOpen, IsMonotonic, IsPermutation, рассматриваемые в настоящей книге и находящиеся в уже упомянутом пакете AVZ_Package [90]. Между тем, в формальном отношении как Q–функции, так и Is–функции являются булевыми функциями и могут быть применены при программировании условий для шаблонов самого различного назначения. Наряду с вышеотмеченными для программирования условий вполне могут быть использованы произвольные выражения, возвращающие на значениях переменных, входящих как в них, так и в шаблоны, значения True либо False. Во многих примерах процедур и функций, представленных в настоящей книге, будут проиллюстрированы все упомянутые механизмы программирования условий.

В.З. Аладьев, Д.С. Гринь Второй способ наложения условий на шаблоны. Пакет вместо конструкций формата "Шаблон/;

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

In[3457]:= g[x_?IntegerQ] := x^2;

g1[x_ /;

IntegerQ[x]] := x^2;

{Map[g, {16.23, 70}], Map[g1, {16.23, 70}]} Out[3457]= {{g[16.23], 4900}, {g1[16.23], 4900}} In[3458]:= g[x_?IntegerQ && OddQ] := x^2;

g1[x_ /;

IntegerQ[x] && OddQ[x]] := x^2;

{Map[g, {16.23, 75}], Map[g1, {16.23, 75}]} Out[3458]= {{g[16.23], g[75]}, {g1[16.23], 5625}} Между тем, как второй пример иллюстрирует неприемлемость второго формата для наложения условий на шаблон в случае более сложных выражений некоторого типа, определяющих данное условие. В целом же оба рассмотренных способа определения условий для шаблонов с формальной точки зрения эквивалентны и более детально в настоящей книге не рассматриваются, отсылая читателя к справке по пакету.

Пакет допускает механизм использования в определениях альтернативные шаблоны, разделяемые символом вертикальной черты (|), как иллюстрируют простые примеры In[3494]:= H[x_Integer | x_Real] := x^2;

Map[H, {75.70, 75, 70, 16/23}] Out[3494]= {5730.49, 5625, 4900, H[16/23]} In[3495]:= H1[x_List | x_Symbol] := x^2;

Map[H1, {{75.70, 75}, agn, 70}] Out[3495]= {{5730.49, 5625}, agn^2, H1[70]} In[3505]:= H2[x_ /;

ListQ[x] || OddQ[x]] := x^2;

Map[H2, {75.70, 75, 70}] Out[3505]= {H2[75.7], 5625, H2[70]} In[3506]:= H2[(x_ /;

ListQ[x]) | (x_ /;

OddQ[x])] := x^2;

Map[H2, {75.70, 75, 70}] Out[3506]= {H2[75.7], 5625, H2[70]} В целом ряде случаев целесообразно определить последовательность шаблонов, более сложную, чем шаблоны x или x..;

для таких целей возможно использовать функцию PatternSequence[h1, h2, h3, …, hn] – последовательность аргументов, соответствующих шаблонам h1, h2, …, hn;

при этом, PatternSequence[] представляет последовательность нулевой длины. Весьма простые примеры иллюстрируют оба подхода, а именно:

In[3562]:= G[x, y_] := {{x}, {y}};

{G[70], G[42, 70, 75, 2012]} Out[3562]= {{{70}, {}}, {{42}, {70, 75, 2012}}} In[3563]:= G1[x : PatternSequence[_, _], z_] := {{x}, {z}};

{G1[70, 75], G1[42, 70, 75, 2012]} Out[3563]= {{{70, 75}, {}}, {{42, 70}, {75, 2012}}} В частности, PatternSequence позволяет группировать формальные аргументы, как это наглядно иллюстрирует последний из двух предыдущих примеров. Между тем, уже с помощью часто используемых шаблонов форматов {x_, x, x_} с условиями можно кодировать определения любой сложности. Ниже представлен целый ряд примеров, использующих шаблоны с условиями для определения процедур и функций.

Расширение функциональной среды системы Mathematica 3.8. Определение функций в программной среде Mathematica Пакет Mathematica располагает большим числом встроенных функций, в то же время он предоставляет весьма простые механизмы для определения собственных функций пользователя. Так, в простейшем случае функция F с одним формальным аргументом x представляет собой конструкцию следующего простого формата, а именно:

F[x_] := Выражение (как правило, зависящее от переменной x) Так, F[x_] := x^3 + 70 определяет функцию F(x)=x^3+70 в стандартной математической нотации;

вызов такой функции на конкретном фактическом аргументе определяется как F[x], в частности, как иллюстрирует следующий простой пример, а именно:

In[1699]:= F[x_] := x^3 + 70;

F[75] Out[1699]= Для получения определения любой функции (и не только функции, а любого определения по оператору соответственно отложенного ":=" или немедленного "=" присвоения), исключая встроенные в пакет функции, служит функция Definition, вызов которой Definition[x] возвращает определение символа x, если для x такое определение имеется, в противном случае вызов возвращает значение Null, т.е. ничего, как очень наглядно иллюстрирует следующий весьма простой фрагмент, а именно:

In[1704]:= F[x_] := x^3 + 70;

Definition[F] Out[1704]= F[x_] := x^3 + In[1705]:= Definition[x] Out[1705]= Null In[1706]:= y = 75;

Definition[y] Out[1706]= y = In[1707]:= z := a + b;

Definition[z] Out[1707]= z := a + b In[1708]:= Definition[Sin] Out[1708]= Attributes[Sin] = {Listable, NumericFunction, Protected} In[1709]:= SetAttributes[h, Listable];

Definition[h] Out[1709]= Attributes[h] = {Listable} Для присвоения атрибута символу, в частности определяющему функцию, пакет в своем распоряжениее имеет функцию SetAttributes, вызов которой SetAttributes[x, a] присваивает символу x атрибут a, в частности, Protected, который защищает символ x от модификации. Именно данным атрибутом наделены все встроенные функции. В случае обладания символом x атрибутами, они по вызову Definition[x] возвращаются вместе с определением x, если оно имеется;

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

Пакет располагает встроенными 19 атрибутами, определяющими раличные свойства объекта, которому они приписаны по функции SetAttributes. Среди таких атрибутов можно отметить такие, как Flat, Orderless, Listable, OneIdentity, NumericFunction и др.

В частности, кроме защиты от модификаций (Protected) атрибут Listable определяет, В.З. Аладьев, Д.С. Гринь что функция с Listable–атрибутом должна автоматически применяться к каждому из элементов списка в качестве ее фактического аргумента. Тогда как с назначением всех остальных атрибутов можно ознакомиться по справочной базе пакета Mathematica.

Между тем, стандартные средства работы с атрибутами имеют ряд весьма серьезных недостатков, оперируя непосредственно с символами, как иллюстрирует фрагмент:

In[3405]:= a = {m, n, p};

Attributes[n] Out[3405]= {} In[3406]:= Attributes[a[[2]]];

SetAttributes[a[[2]], Protected] Attributes::ssle: Symbol, string, or HoldPattern[symbol] expected at position 1 in Attributes[a[[2]]].

SetAttributes::sym: Argument a[[2]] at position 1 is expected to be a symbol.

Out[3406]= SetAttributes[a[[2]], Protected] In[3407]:= Attributes[n] Out[3407]= {} In[3408]:= SetAttributes1[a[[2]], {Protected, Listable}] In[3409]:= Attributes1[a[[2]]] Out[3409]= {Listable, Protected} In[3410]:= Attributes[70] Attributes::ssle: Symbol, string, or HoldPattern[symbol] expected at position 1 in Attributes[70].

Out[3410]= Attributes[70] In[3411]:= Attributes1[70] Out[3411]= $Failed С целью устранения данных недостатков и были созданы модификации стандартных средств для работы с атрибутами, не только расширяющие стандартные функции на аргументы, в качестве которых допустимы любые выражения, но и обеспечивающие более удобно непрерывные вычисления в процедурном режиме выполнения программ.

Конец предыдущего фрагмента иллюстрирует сравнение результатов использования как стандартных, так и наших средств на одном и том же весьма простом выражении.

Данные средства рассматриваются в настоящей книге и представлены в пакете [90].

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

Расширение функциональной среды системы Mathematica In[3454]:= Definition[x] Out[3454]= AladjevProceduresAndFunctions`x In[3455]:= Definition[Map12] Out[3455]= Map12[AladjevProceduresAndFunctions`Map12`F_ /;

SymbolQ[AladjevProceduresAndFunctions`Map12`F], x_ /;

NestListQ[x]] := Module[{c = {}, b, k = 1}, While[k = Length[x], b = x[[k]];

c = Append[c, If[ListQ[b], AladjevProceduresAndFunctions`Map12`F /@ b, AladjevProceduresAndFunctions`Map12`F[b]]];

k++];

c] In[3466]:= Definition["G"] Out[3466]= Attributes[G] = {Listable} G[x_Integer, y_Integer, z_Integer] := x*y*z /;

x + y + z = G[x_, y_, z_] := x*y*z Поэтому нами был предложен ряд средств, возвращающих определения как функций, так и других объектов, которые как расширяют функцию Definition, так и упрощают последующую обработку возвращаемых ею определений. Все они рассмотрены как в настоящей книге, так и представлены в пакете AVZ_Package [90]. В качестве примера представим здесь одно из них. Вызов процедуры Definition2[x] возвращает список, у которого первым элементом выступает значение "Undefined" либо "System", если x символ не определен или определяет системную функцию соответственно, тогда как вторым элементом является список атрибутов, приписанных символу x. В других же случаях определенного символа x первым элементом возвращаемого списка является последовательность всех определений в строчном формате для символа x, тогда как второй элемент возвращаемого списка остается таким же, как и ранее. Во фрагменте представлен исходный код процедуры с типичными примерами ее применения.

In[3460]:= Definition2[x_ /;

SymbolQ[x] || HowAct[x]] := Module[{a, b = Attributes[x], c}, Off[Part::partw];

ClearAttributes[x, b];

a = ToString[InputForm[Definition[x]]];

Mapp[SetAttributes, {Rule, StringJoin}, Listable];

c = StringReplace[a, Flatten[{Rule[StringJoin[Contexts1[], ToString[x] "`"], ""]}]];

c = StringSplit[c, "\n \n"];

Mapp[ClearAttributes, {Rule, StringJoin}, Listable];

SetAttributes[x, b];

a = AppendTo[c, b];

If[SameQ[a[[1]], "Null"] && a[[2]] == {}, On[Part::partw];

{"Undefined", Attributes[x]}, If[SameQ[a[[1]], "Null"] && a[[2]] != {} && ! SystemQ[x], On[Part::partw];

{"Undefined", Attributes[x]}, If[SameQ[a[[1]], "Null"] && a[[2]] != {} && a[[2]] != {}, On[Part::partw];

{"System", Attributes[x]}, On[Part::partw];

a]]]] In[3462]:= G[x_Integer, y_Integer, z_Integer] := x*y*z /;

x + y + z = 70;

G[x_, y_, z_] := x*y*z;

G[x_Real, y_Real] := x^2 + y^ In[3463]:= SetAttributes[G, Listable];

Definition[G] Out[3463]= Attributes[G] = {Listable} G[x_Integer, y_Integer, z_Integer] := x*y*z /;

x + y + z = G[x_, y_, z_] := x*y*z G[x_Real, y_Real] := x^2 + y^ In[3463]:= Definition2[G] В.З. Аладьев, Д.С. Гринь Out[3463]= {"G[x_Integer, y_Integer, z_Integer] := x*y*z /;

x + y + z = 70", "G[x_, y_, z_] := x*y*z", "G[x_Real, y_Real] := x^2 + y^2", {Listable}} In[3464]:= Definition2[Sin] Out[3464]= {"System", {Listable, NumericFunction, Protected}} In[3465]:= SetAttributes[H, Listable];

Map[Definition2, {H, V}] Out[3465]= {{"Undefined", {Listable}}, {"Undefined", {}}} Как несложно убедиться, результат, возвращаемый вызовом процедуры Definition2[x], существенно более удобен для последующей обработки определений объекта x.

Как отмечалось ранее, текущий сеанс может содержать несколько разных определений процедуры/функции с одним и тем же именем, которые различаются лишь на уровне их заголовков. Вызов предыдущей процедуры Definition2[x] в оптимальном формате возвращает список всех определений в строчном формате процедуры/функции под именем x, сопровождая его опциями и списком атрибутов приписанных символу x. В соответствии с соглашениями пакета одноименные процедуры/функции имеют одни и те же как опции, так и атрибуты, как иллюстрирует нижеследующий фрагмент.

In[1940]:= G[x_, y_] := x^2 + y^ In[1941]:= Options[G] = {Art – 23, Kr – 16} Out[1941]= {Art – 23, Kr – 16} In[1942]:= SetOptions[G, Art – 23, Kr – 16] Out[1942]= {Art – 23, Kr – 16} In[1943]:= Definition2[G] Out[1943]= {"G[x_, y_] := x^2 + y^2", "Options[G] := {Art – 23, Kr – 16}", {}} In[1944]:= G[x_] := x^2;

SetAttributes[G, Listable] In[1945]:= G[x_, y_, z_] := x + y + z In[1946]:= Definition2[G] Out[1946]= {"G[x_, y_] := x^2 + y^2", "G[x_] := x^2", "G[x_, y_, z_] := x + y + z", "Options[G] := {Art – 23, Kr – 16}", {Listable}} In[1947]:= DefOnHead[x_ /;

HeadingQ[x]] := Module[{h = RedSymbStr[StringReplace[x, "," – ", "], " ", " "], a, b, c, d}, a = HeadName[h];

b = Definition2[ToExpression[a]];

c = Select[b, SuffPref[#, h " := ", 1] &];

d = Select[b, SuffPref[#, "Options[" a "] := ", 1] &];

If[MemberQ[b, "Undefined"], $Failed, If[d == {}, AppendTo[c, b[[–1]]], Join[c, {d[[1]], b[[–1]]}]]]] In[1948]:= DefOnHead["G[x_, y_, z_]"] Out[1948]= {"G[x_, y_, z_] := x + y + z", "Options[G] := {Art – 23, Kr – 16}", {Listable}} In[1949]:= DefOnHead["G[x_,y_]"] Out[1949]= {"G[x_, y_] := x^2 + y^2", "Options[G] := {Art – 23, Kr – 16}", {Listable}} In[1850]:= DefOnHead["G[x_]"] Out[1850]= {"G[x_] := x^2", "Options[G] := {Art – 23, Kr – 16}", {Listable}} Расширение функциональной среды системы Mathematica Для получения определения процедуры/функции x с заданным заголовком (основным идентификатором) создан ряд средств, одно из которых и представлено предыдущим фрагментом, а точнее процедурой DefOnHead, чей вызов DefOnHead[h] возвращает список, первый элемент которого – определение в строчном формате процедуры или функции с заданным заголовком h, тогда как остальными элементами являются опции (если они есть) и список атрибутов, приписанных данной процедуре/функции x. При этом, имеет место следующее определяющее соотношение, а именно: HeadName[h] = x.

В целом, рекомендуется использовать уникальное имя для каждого определения, для обеспечения чего используются функции Clear, ClearAll при модификациях средств.

Таким образом, при вызове процедуры/функции из списка определений выбирается то, которое имеет заголовок, соответствующий фактическим аргументам, т.е. которые оказываются допустимыми для формальных аргументов с приписанными им тестами на допустимость. Более того, заголовок формата G[x_, y_, z_, …] имеет минимальный приоритет среди заголовков других форматов независимо от порядка вычисления в текущем сеансе определений одноименных процедур/функций, как весьма наглядно иллюстрирует следующий довольно простой фрагмент, а именно:

In[1863]:= G[x_, y_] := StringJoin[x, y] "RansIan" In[1864]:= G[x_Integer, y_Integer] := x + y In[1865]:= G[x_String, y_Integer] := y*StringLength[x] In[1866]:= Definition2[G] Out[1866]= {"G[x_Integer, y_Integer] := x + y", "G[x_String, y_Integer] := y*StringLength[x]", "G[x_, y_] := StringJoin[StringJoin[x, y], \"RansIan\"]", {}} In[1867]:= {G[70, 75], G["AvzAgnVsvArtKr", 450]} Out[1867]= {145, 6300} In[1868]:= G["AvzAgnVsvArtKr", "Tallinn"] Out[1868]= "AvzAgnVsvArtKrTallinnRansIan" In[1908]:= G[x_, y_] := If[{y} == {}, x^2, {y} = {x};

x^2] In[1909]:= G[70] Out[1909]= In[1910]:= {G[70, t], t} Out[1910]= {4900, 70} In[1911]:= ClearAll[G, t] In[1912]:= G[x_] := x^2;

G[x_, y_ /;

! HowAct[y] === Null] := {y = x, x^2}[[2]] In[1913]:= Definition2[G] Out[1913]= {"G[x_] := x^2", "G[x_, y_ /;

!HowAct[y] === Null] := {y = x, x^2}[[2]]", {}} In[1914]:= G[70] Out[1914]= In[1915]:= {G[70, t], t} Out[1915]= {4900, 70} Выше уже отмечалось, что в большинстве случаев целесообразно использовать только одно определение процедуры/функции, что, порой, довольно существенно упрощает В.З. Аладьев, Д.С. Гринь его обработку. Между тем, в некоторых случаях вполне уместно использование ряда одноименных процедур/функций, в частности, с целью упрощения их программной реализации. В качестве примера может служить реализация функции G второй части предыдущего фрагмента от неопределенного числа аргументов. Определение двух G функций, охватывающих все случаи функции G, в ряде случаев позволяет упростить реализацию. В приведенном примере не столь очевидно такое упрощение, т.к. он лишь иллюстрирует сам прием, тогда как в случае достаточно сложных процедур, которые в своем теле должны выполнять обработку получаемых фактических аргументов при неопределенном их количестве, такой подход может оказаться весьма эффективным.

Более того, в ряде случаев (детальнее об этом будет идти речь несколько ниже) функция либо процедура может возвращать результат, ассоциированный с контекстом пакета пользователя. Для устранения данной ситуации может оказаться довольно полезной процедура, чей вызов OptRes[x, y] возвращает оптимизированный для последующей обработки результат y, возвращаемый функцией/процедурой x. Следующий пример представляет исходный код процедуры OptRes наряду с примерами ее применения.

In[2755]:= OptRes[x_Symbol, y_] := If[Mapp[SetAttributes, {Rule, StringJoin}, Listable];

StringQ[y] && StringFreeQ[y, "`" ToString[x] "`"], Mapp[ClearAttributes, {Rule, StringJoin}, Listable];

y, {If[StringQ[y], Evaluate, ToExpression][StringReplace[ToString[y], Flatten[{Rule[StringJoin[Contexts1[], ToString[x] "`"], ""]}]]], Mapp[ClearAttributes, {Rule, StringJoin}, Listable]}[[1]]] In[2756]:= OptRes[ProcQ, AladjevProceduresAndFunctions`ProcQ`vsvartkr] Out[2756]= vsvartkr In[2757]:= OptRes[ProcQ, "AladjevProceduresAndFunctions`ProcQ`vsvartkr"] Out[2757]= "vsvartkr" In[2762]:= Definition[Map1] Out[2762]= Map1[AladjevProceduresAndFunctions`Map1`F_ /;

ListQ[AladjevProceduresAndFunctions`Map1`F], AladjevProceduresAndFunctions`Map1`args_ /;

ListQ[AladjevProceduresAndFunctions`Map1`args]] := Module[{a, b, c, k = 1}, {a, b, c} = {ToString /@ AladjevProceduresAndFunctions`Map1`F, {}, ToString[AladjevProceduresAndFunctions`Map1`args]};

For[k, k = Length[a], k++, b = Append[b, ToExpression[StringReplace[StringJoin[a[[k]], c], {"{" – "[", "}" – "]"}]]]];

b] In[2763]:= OptRes[Map1, Definition[Map1]] Out[2763]= "Map1[F_ /;

ListQ[F], args_ /;

ListQ[args]] := Module[{a, b, c, k = 1}, {a, b, c} = {ToString /@ F, {}, ToString[args]};

For[k, k = Length[a], k++, b = Append[b, ToExpression[StringReplace[StringJoin[a[[k]], c], {\"{\" – \"[\", \"}\" – \"]\"}]]]];

b]" Из последних примеров весьма наглядна разница применения функции Definition с целью получения определения процедуры Map1, находящейся в пакете AVZ_Package, и процедуры OptRes, примененной к полученному результату Definition[Map1]. При этом, строчный формат результата позволяет либо вычислять определение по вызову функции ToExpression, либо производить его обработку строчными средствами.

Расширение функциональной среды системы Mathematica Функции с переменным числом аргументов. Выше представлен формат определения функции с одним формальным аргументом, в частности, G[x_/;

Условие] := W(x), где Условие обязательным не является;

тогда как S[x_, y_] := H(x, y) определяет функцию с двумя обязательными аргументами, в качестве которых допустимы любые выражения.

Для определения функции с произвольным числом аргументов используется шаблон с двумя "" либо тремя "_" символами подчеркивания, определяющий допустимость соответственно одного или нескольких фактических аргументов либо ни одного или нескольких фактических аргументов. В целом же, в качестве простейших формальных аргументов используются вышерассмотренные шаблоны. Следующий весьма простой пример наглядно иллюстрирует принципиальные различия всех 3 типов шаблонов:

In[1752]:= S[x_] := {x};

S1[x] := {x};

S2[x_] := {x};

In[1753]:= {S[42], S[42, 70], S1[42, 70, 75, 450], S1[], S2[42, 70, 75, 450], S2[]} Out[1753]= {{42}, S[42, 70], {42, 70, 75, 450}, S1[], {42, 70, 75, 450}, {}} При использовании шаблонов "x" и "x_" достаточно часто встречается несколько вариантов, допустимых для распределения фактических аргументов в соответствии с такого типа шаблонами. По умолчанию пакет Mathematica в первую очередь пробует соответствия, которые присваивают самые короткие последовательности фактических аргументов первым формальным аргументам, определяемым шаблонами указанного типа. Данный порядок можно изменять, применяя к шаблонам, которые определяют формальные аргументы, оболочек Longest и Shortest. В этом случае оболочки Longest и Shortest отпределяют порядок соответствия фактических аргументов формальным аргументам, когда используются самые длинные и самые короткие последовательности фактических аргументов соответственно. Простой фрагмент наглядно иллюстрирует не только различные варианты использования шаблонов типа "x" и "x_", но и сам механизм использования оберток Longest и Shortest. При этом, следует иметь в виду, что всем формальным аргументам типа "x_" производится по одному назначению из последовательности фактических аргументов, если они не включены в эти оболочки.

In[1755]:= G[x, y_] := {{x}, {y}};

G[42, 70, 75, 450] Out[1755]= {{42}, {70, 75, 450}} In[1756]:= G1[Longest[x], y_] := {{x}, {y}};

G1[42, 70, 75, 450] Out[1756]= {{42, 70, 75, 450}, {}} In[1757]:= G2[x, Longest[y_], z] := {{x}, {y}, {z}};

G2[42, 70, 75, 450] Out[1757]= {{42}, {70, 75}, {450}} In[1758]:= G3[Longest[x], y_, z] := {{x}, {y}, {z}};

G3[42, 70, 75, 450] Out[1758]= {{42, 70, 75}, {}, {450}} In[1759]:= G4[x, y_, Longest[z]] := {{x}, {y}, {z}};

G4[42, 70, 75, 450] Out[1759]= {{42}, {}, {70, 75, 450}} In[1760]:= G5[x, y, Longest[z]] := {{x}, {y}, {z}};

G5[42, 70, 75, 450] Out[1760]= {{42}, {70}, {75, 450}} In[1761]:= G6[Shortest[x, y], Longest[z]] := {{x}, {y}, {z}};

G6[42, 70, 75, 450] Out[1761]= {{42}, {70}, {75, 450}} In[1762]:= G7[Longest[x, y], z] := {{x}, {y}, {z}};

G7[42, 70, 75, 450] Out[1762]= {{42, 70, 75}, {y}, {450}} В.З. Аладьев, Д.С. Гринь Таким образом, пакет располагает довольно развитым механизмом, поддерживающим определение функций как с переменным, так и неопределенным числом аргументов.

Значения по умолчанию для аргументов. В целом ряде случаев весьма целесообразно определять функции с аргументами, имеющими значения по умолчанию, т.е. значения, которые получает функция при вызове в случае отсутствия таких аргументов. С этой целью для определении формального аргумента используется шаблон формата x_: h.

В этом случае при отсутствии в вызове функции аргумента x он заменяется значением h. Следующий простой пример иллюстрирует сказанное, а именно:

In[1773]:= G[x_, y_: 70, z_] := x + y + z;

S[x_: 45, y_: 23, z_: 16] := x*y*z;

In[1774]:= {{G[42, 75, 450], G[42, 450]}, {S[42, 75, 450], S[450], S[]}} Out[1774]= {{567, 562}, {1417500, 165600, 16560}} In[1775]:= V[x_: a, y_: b, z_: c] := {x, y, z};

{V[], V[1, 2], V[1]} Out[1775]= {{a, b, c}, {1, 2, c}, {1, b, c}} In[1776]:= G[x_, y_: 70, z_: 450] := {x, y, z};

{G[x, y, z], G[x, y], G[42], G[]} Out[1776]= {{x, y, z}, {x, y, 450}, {42, 70, 450}, G[]} Пакет допускает следующие шаблоны, использующие значения по умолчанию:

x_: d – аргумент x имеет по умолчанию значение d;

x_ h : d – аргумент x с заголовком h имеет по умолчанию значение d;

x_. – аргумент x имеет встроенное значение по умолчанию.

Некоторые общие функции Mathematica имеют встроенные значения по умолчанию для своих аргументов. Для данных функций не требуется явно указывать значение по умолчанию в формате x_: d, вполне достаточно использовать более удобный формат x_., определяющий встроенное значение по умолчанию. Для функции пользователя с целью определения для ее аргументов значений по умолчанию можно использовать функцию Default, допускающую четыре формата кодирования, а именно:

Default[G]=a – для аргументов формата x_. функции G устанавливаются значения по умолчанию, равные a;

Default[G, n]=a – для n–го аргумента формата x_. функции G определяется значение по умолчанию, равное a;

Default[G, k, n]=a – для k–го аргумента формата x_. из общего количества n функции G определяется значение по умолчанию, равное a;

Default[G, k1, k2, …, kp]=a – для kj-х аргументов формата x_. функции G определяется значение по умолчанию, равное a.

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

In[1841]:= Default[H, 2] = 2;

H[x_, y_.] := {x^2, y^2};

{H[70, 16], H[70]} Out[1841]= {{4900, 256}, {4900, 4}} In[1842]:= Default[H1, 1, 2] = 2;

H1[x_., y_.] := {x^2, y^2};

{H1[70, 16], H1[70], H1[]} Out[1842]= {{4900, 256}, {4900, 4}, {4, 4}} Расширение функциональной среды системы Mathematica In[1858]:= Default[F, 2, 4] = 450;

F[x_, y_., z_, h_] := {x, y, z, h};

{F[70, 16, 23, 6], F2[70, 23, 16]} Out[1858]= {{70, 16, 23, 6}, {70, 450, 23, 16}} In[1833]:= Default1[x_Symbol, y_ /;

PosIntListQ[y], z_List] := Module[{k = 1, a = Min[Map[Length, {y, z}]]}, While[k = a, Default[x, y[[k]]] = z[[k]];

k++];

] In[1834]:= Default1[H3, {1, 2, 3, 4}, {a, b, c, d}];

H3[x_., y_., z_., t_.] := x^2 + y^2 + z^2 + t^2;

{H3[70, 16, 26, 42], H3[]} Out[1834]= {7596, a^2 + b^2 + c^2 + d^2} Между тем, стандартная функция Default не дает возможность за 1 вызов выполнять установку разных значений по умолчанию для разных аргументов функции, и в этом отношении в ряде случаев может оказаться достаточно полезной достаточно простая процедура, вызов которой Default1[x, y, z] возвращает Null, т.е. ничего, обеспечивая в то же самое время установку значений по умолчанию, определенных списком z, для аргументов функции/процедуры x, чьи позиции определены списком PosIntList-типа y. Исходный код процедуры Default1 наряду с примерами ее применения завершают предыдущий фрагмент. Используя конструкции, такие как x_., можно довольно легко создавать единичные шаблоны, отвечающие выражениям с несколькими различными структурами. В ряде случаев это довольно полезная возможность. Между тем, имеется и другой метод решения этого вопроса, суть которого достаточно наглядно проясняет следующий весьма простой пример, а именно:

In[1862]:= h = a;

Sv[x_, y_: If[h == a, b, c], z_] := {x, y, z};

{Sv[x, a, y], Sv[x, y]} Out[1862]= {{x, a, y}, {x, b, y}} In[1863]:= {y, z} = {a, b};

G[x_, y_: If[y === a, c, d], z_: If[z === b, m, n]] := {x, y, z};

{G[16, 23, 46], G[16, 23], G[16], G[]} Out[1863]= {{16, 23, 46}, {16, 23, m}, {16, c, m}, G[]} Из примера весьма прозрачно усматривается механизм предложенного решения. По вызову DefaultValues[F] можно получать значения по умолчанию для функции F, но если они были определены через Default, а не лишь в заголовке функции, например:

In[1757]:= Default1[H3, {1, 2, 3, 4}, {a, b, c, d}];

H3[x_., y_., z_., t_.] := {x, y, z, t};

In[1758]:= DefaultValues[H3] Out[1758]= {HoldPattern[Default[H3, 1]] : a, HoldPattern[Default[H3, 2]] : b, HoldPattern[Default[H3, 3]] : c, HoldPattern[Default[H3, 4]] : d} In[1759]:= S[x_: 45, y_: 23, z_: 16] := x*y*z;

DefaultValues[S] Out[1759]= {} Определять значения по умолчанию для аргументов функций/процедур можно как через Default, так и непосредственно в их заголовках по конструкциям формата x_:a, а также сочетая оба указанных способа. Однако, функция DefaultValues возвращает установки значений по умолчанию, выполненные только через Default, например:

In[1789]:= Default[V5, 2] = 70;

V5[x_, y_: 450, z_: 42] := {x, y, z};

DefaultValues[V5] Out[1789]= {HoldPattern[Default[V5, 2]] : 70} In[1790]:= V5[agn] Out[1790]= {agn, 450, 42} В.З. Аладьев, Д.С. Гринь In[1791]:= Default[V4, 2] = 70;

V4[x_, y_., z_: 42] := {x, y, z};

DefaultValues[V4] Out[1791]= {HoldPattern[Default[V4, 2]] : 70} In[1792]:= V4[agn] Out[1792]= {agn, 70, 42} При этом, если для аргумента определено значение по умолчанию и через Default, и непосредственно в заголовке по конструкции "_:", второй способ имеет максимальный приоритет, как весьма наглядно иллюстрирует предыдущий пример с функцией V5.

Между тем, стандартная функция DefaultValues обладает рядом довольно серьезных недостатков. Прежде всего, она не отражает значения по умолчанию, определенные в заголовке функции/процедуры, а только заданные через функцию Default. Однако в общем случае это некорректно, ибо аргументам допустимо присвоение значений по умолчанию как через функцию Default, так и непосредственно в заголовке;

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

Для устранения данных недостатков запрограммирована процедура DefaultValues1, вызов которой возвращает список формата {{N1} : V1, …, {Np} : Vp}, где Nj и Vj (j=1..p) определяют номера позиций формальных аргументов в заголовке функции/процедуры и присваиваемые им значения по умолчанию соответственно, независимо от способа их определения с учетом приоритета (высший приоритет имеет установка значений по умолчанию в заголовке функций/процедур). Следующий фрагмент определяет исходный код процедуры DefaultValues1 наряду с типичными примерами ее применения.

In[2079]:= DefaultValues1[x_ /;

ProcQ[x] || Quiet[QFunction[ToString[x]]]] := Module[{a = {SetAttributes[String, Listable]}, d = {}, h, k, b = Map[ToString, Args[x]], c = Map[ToString, DefaultValues[x]]}, ClearAttributes[ToString, Listable];

If[b != {}, For[a = 1, a = Length[b], a++, h = b[[a]];

If[! StringFreeQ[h, "_:"], d = Append[d, ToExpression["{" ToString[a] "} : " StringTake[h, {Flatten[StringPosition[h, "_:"]][[2]] + 1, –1}]]]]]];

If[c != {}, If[c != {}, c = ToExpression[Mapp[StringReplace, Mapp[StringReplace, c, {"HoldPattern[Default[" ToString[x] – "{", "]]" – "}"}], {"{, " – "{", "{}" – "{2012}"}]]];

h = c[[1]][[1]];

If[Op[h] == {2012}, a = {};

For[k = 1, k = Length[b], k++, a = Append[a, ToExpression[ToString[{k}] " : " ToString[c[[1]][[2]]]]]];

c = a];

If[PosIntListQ[h] && Length[h] 1, a = {};

b = h;

For[k = 1, k = Length[b], k++, a = Append[a, ToExpression[ToString[{k}] " : " ToString[c[[1]][[2]]]]]];

c = a]];

If[d == {} && c == {}, Return[{}], c = Sort[Join[d, c], Op[#1][[1]][[1]] = Op[#2][[1]][[1]] &]];

{k, h} = {1, {}};

While[k = Length[c] – 1, h = Append[h, If[Op[c[[k]]][[1]] == Op[c[[k + 1]]][[1]], k + 1]];

k++];

Select[ReplacePart[c, Mapp[Rule, Select[h, # != "Null" &], Null]], ! SameQ[#, Null] &]] Расширение функциональной среды системы Mathematica In[2080]:= Default[V] = 450;

V[x_, y_., z_: 70] := {x, y, z};

DefaultValues1[V] Out[2080]= {{1} : 450, {2} : 450, {3} : 70} In[2081]:= Default[V2, 2, 3] = 70;

V2[x_, y_., z_] := {x, y, z};

DefaultValues1[V2] Out[2081]= {{1} : 70, {2} : 70} In[2082]:= Default1[V3, {1, 2, 3}, {42, 47, 23}];

V3[x_: 450, y_., z_.] := {x, y, z};

DefaultValues1[V3] Out[2082]= {{1} : 450, {2} : 47, {3} : 23} In[2083]:= Default[V4, 2] = 2012;

V4[x_: 450, y_: 47, z_: 42] := {x, y, z};

DefaultValues1[V4] Out[2083]= {{1} : 450, {2} : 47, {3} : 42} In[2084]:= Default[V5, 2] = 70;

V5[x_, y_: 450, z_: 42] := {x, y, z};

DefaultValues1[V5] Out[2084]= {{2} : 450, {3} : 42} In[2085]:= Default1[H3, {1, 2, 3, 4}, {a, b, c, d}];

H3[x_., y_., z_., t_.] := {x, y, z, t};

DefaultValues1[H3] Out[2085]= {{1} : a, {2} : b, {3} : c, {4} : d} In[2086]:= Default1[H4, {1, 2, 3, 4}, {a, b, c, d}];

H4[x_., y_: 70, z_., t_: 75] := {x, y, z, t};

DefaultValues1[H4] Out[2086]= {{1} : a, {2} : 70, {3} : c, {4} : 75} Таким образом, наша процедура DefaultValues1 достаточно существенно расширяет возможности стандартной функции DefaultValues и вполне ее заменяет при условии наличия в программной среде Mathematica инсталлированного пакета AVZ_Package.

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

Данный метод наиболее удобен для использования определения функций/процедур, имеющих довольно большое количество необязательных параметров, из которых при каждом вызове используется только небольшое их количество. Иногда данный метод называется методом опций. В настоящей книге такой метод не рассматривается, тогда как заинтересованного читателя отсылаем к литературе [100,116] и справке по пакету.

Множественные шаблоны. Если шаблоны формата x и x_ позволяют определять любое количество допустимых аргументов функции/процедуры, операторы {"..", "..."} повторения шаблона позволяют создавать шаблоны, в которых определенные формы могут повторяться любое количество раз. Например, G[x…] определяет произвольное выражение формы G[x], G[x, x], G[x, x, x], G[x, x, x, x] и т.д.;

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

In[1788]:= G[x_, y_] := {x, y};

Cases[{G[b, a], G[a, a], G[b, b], G[a, a], G[a, a, a, b, b], G[a, a, a, b, b, b], G[a, a, b, a, a, a], G[a, a, a], G[b, b, a, a]}, G[a..., b...]] Out[1788]= {{a, a}, {b, b}, {a, a}, {a, a, a, b, b}, {a, a, a, b, b, b}, {a, a, a}} In[1789]:= Cases[{G[b, a], G[a, a], G[b, b], G[a, a], G[a, a, a, b, b], G[a, a, a, b, b, b], G[a, a, b, a, a, a], G[a, a, a], G[b, b, a, a]}, G[a..., b...]] Out[1790]= {{a, a, a, b, b}, {a, a, a, b, b, b}} В.З. Аладьев, Д.С. Гринь In[1790]:= Cases[{G[b, a], G[a, a], G[b, b], G[a, a], G[a, a, a, b, b], G[a, a, a, b, b, b], G[a, a, b, a, a, a], G[a, a, a], G[b, b, a, a]}, G[({a, a} | {b, b} | {b, b, a, a})...]] Out[1789]= {{a, a}, {b, b}, {a, a}, {b, b, a, a}} Операторы повторения в общем случае допускают четыре формата кодирования:

x.. или Repeated[x] – шаблон либо выражение x, повторенное один либо более раз;

Repeated[x, m] – шаблон x, повторенный не более, чем m раз;

Repeated[x, {n, m}] – шаблон x с числом повторений между n и m;

Repeated[x, {m}] – шаблон x, повторенный ровно m раз.

Весьма простые примеры иллюстрируют все перечисленные четыре формата:

In[3485]:= G[x] := {x};

Cases[{G[a], G[a, a], G[a, a, a], G[a, a, a, a], G[a, a, a, a, a], G[a, a, a, a, a, a, a], G[a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a, a, a]}, G[a..]] Out[3485]= {{a}, {a, a}, {a, a, a}, {a, a, a, a}, {a, a, a, a, a}, {a, a, a, a, a, a, a}, {a, a, a, a, a, a, a}, {a, a, a, a, a, a, a, a}, {a, a, a, a, a, a, a, a, a}, {a, a, a, a, a, a, a, a, a, a}} In[3486]:= Cases[{G[a], G[a, a], G[a, a, a], G[a, a, a, a], G[a, a, a, a, a], G[a, a, a, a, a, a, a], G[a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a, a, a]}, G[Repeated[a, 5]]] Out[3486]= {{a}, {a, a}, {a, a, a}, {a, a, a, a}, {a, a, a, a, a}} In[3487]:= Cases[{G[a], G[a, a], G[a, a, a], G[a, a, a, a], G[a, a, a, a, a], G[a, a, a, a, a, a, a], G[a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a, a, a]}, G[Repeated[a, {5, 9}]]] Out[3487]= {{a, a, a, a, a}, {a, a, a, a, a, a, a}, {a, a, a, a, a, a, a}, {a, a, a, a, a, a, a, a}, {a, a, a, a, a, a, a, a, a}} In[3488]:= Cases[{G[a], G[a, a], G[a, a, a], G[a, a, a, a], G[a, a, a, a, a], G[a, a, a, a, a, a, a], G[a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a, a, a]}, G[Repeated[a, {10}]]] Out[3488]= {{a, a, a, a, a, a, a, a, a, a}} In[3490]:= Clear[G];

Select[{G[a], G[a, a], G[a, a, a], G[a, a, a, a], G[a, a, a, a, a], G[a, a, a, a, a, a, a], G[a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a, a], G[a, a, a, a, a, a, a, a, a, a]}, Arity2[#] == 10 &] Out[3490]= {G[a, a, a, a, a, a, a, a, a, a]} In[3591]:= Arity1[x_] := Module[{a, k = 1}, While[k Infinity, a = Quiet[Check[Part[x, k], $Failed]];

If[a == $Failed, Return[k – 1]];

k++]] In[3592]:= Map[Arity1, {G[], G[a + b], G[a, a, a], G[a, b, c, d], G[42, 70, 75, 450, 2012]}] Out[3592]= {0, 1, 3, 4, 5} In[3601]:= Arity2[x_ /;

ProcQ[x] || QFunction[ToString[x]]] := Module[{a = Map[ToString, Args[x]], b = Length[Args[x]]}, If[DeleteDuplicates[Mapp[StringFreeQ, a, {"", "_"}]] == {True}, b, "Undefined"]] In[3602]:= G[x_, y_, z_] := {x, y, z};

G1[x_, y] := {x, y};

Map[Arity2, {G, G1, ProcQ}] Out[3602]= {3, "Undefined", 1} Расширение функциональной среды системы Mathematica Вопрос вычисления арности функции/процедуры представляется довольно важным, однако пакет не располагает средствами для ее определения, поэтому был создан ряд средств для решения этого вопроса. Прежде всего, простая процедура Arity1 с кодом, представленным в конце предыдущего фрагмента, возвращает арность формального вызова процедуры, заданного в формате G[x, y, z, …], где G – неопределенный символ.

С помощью этой процедуры несложно получать некоторые результаты, полученные с использованием операторов повторения, как иллюстрирует пример использования процедуры Arity1 в сочетании с функцией Select. Тогда как там же представленная и вторая процедура Arity2 обладает большими функциональными возможностями для выяснения арности функций/процедур, а именно. Вызов Arity2[x] возвращает арность функции/процедуры x;

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

Отметим еще один тип соответствия шаблонов как строгое, определяемое функцией Verbatim[x] – представляет выражение x в сопоставлении с шаблоном, требуя строгого соответствия без применения каких–либо преобразований. Весьма простые примеры иллюстрируют применение данной функции, а именно:

In[1758]:= Cases[{70, Art_, 70, a + b, a*x_, Kr, a*y_, a*x, a*x_}, Verbatim[a*x_]] Out[1758]= {a x_} In[1764]:= MatchQ[a + b/c + d – a*Sin[x], x_] Out[1764]= True In[1765]:= MatchQ[a + b/c + d – a*Sin[x], Verbatim[x_]] Out[1765]= False Строгое соответствие шаблонам играет весьма важную роль в обработке выражений.

Итак, используя средства, описанные выше, можно определять шаблоны для многих видов выражений. Между тем, следует иметь в виду, шаблоны должны представлять структуру выражений в формате внутренней формы пакета, определяемой функцией FullForm. При этом, специально для ряда видов выражений общего вида стандартный выходной формат, используемый пакетом, не совпадает с полной внутренней формой.

Однако он соответствует внутренней форме, поддерживаемой пакетом, и его следует использовать при определении шаблонов;

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

x_Integer – целое число x;

x_Real – действительное приближенное число x;

x_Complex – действительное приближенное число x;

Complex[x_, y_] – комплексное число в формате x + i*y;

Complex[x_Integer, y_Integer] – комплексное число x + i*y c целыми действительной и мнимой частями;

x_Rational – рациональное число x;

Rational[m_, n_] – рациональное число формата m/n;

x_/;

NumberQ[x] – произвольное число x любого типа.

В.З. Аладьев, Д.С. Гринь При обработке алгебраических выражений используются не только шаблоны, а и их представления в стандартной полной форме, определяемой функцией FullForm, чей вызов возвращает произвольное выражение в стандартной полной форме, например:

In[1748]:= (a + b)/(c*x^2 + d*Sin[z]) // FullForm Out[1748]//FullForm = Times[Plus[a, b], Power[Plus[Times[c, Power[x, 2]], Times[d, Sin[x]]], –1]] In[1749]:= (x_ /;

NumberQ[x]) // FullForm Out[1749]//FullForm = Condition[Pattern[x, Blank[]], NumberQ[x]] где FullForm[x] (x) // FullForm, Pattern – шаблон и Blank[] – символ подчеркивания;

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

In[1767]:= S[x_ /;

ListQ[x] && DeleteDuplicates[Map[IntegerQ, x]] == {True}] := x In[1768]:= {S[{a, b, c, 5, 6, h, a + b, 3, 8}], S[{42, 47, 67, 16, 23, 6}]} Out[1768]= {S[{a, b, c, 5, 6, h, a + b, 3, 8}], {42, 47, 67, 16, 23, 6}} In[1773]:= a = 5;

V[x_ /;

{t[y_Integer] := y^2, If[t[a] == 25, True, False]}[[2]]] := x^2;

V[70] Out[1773]= In[1774]:= a = 6;


V[70] Out[1774]= V[70] In[915]:= a = 7;

Art[If[a == 7, x_ /;

ListQ[x], xInteger], y_] := If[a == 7, Length[x]*y, {x, y}] In[916]:= Definition[Art] Out[916]= Art[x_ /;

ListQ[x], y_] := If[a == 7, Length[x] y, {x, y}] In[917]:= Art[{70, 42, 2012, 75, 47, 65, 34, 78, 56, 23, 16, 450, 56, 45, 44, 13}, 42] Out[917]= In[918]:= a = 6;

Art[If[a == 7, x_ /;

ListQ[x], xInteger], y_] := If[a == 7, Length[x]*y, {x, y}] In[919]:= Definition[Art] Out[919]= Art[x_ /;

ListQ[x], y_] := If[a == 7, Length[x] y, {x, y}] Art[xInteger, y_] := If[a == 7, Length[x] y, {x, y}] In[920]:= Art[70, 42, 2012, 75, 47, 65, 34, 78, 56, 23, 16, 450, 56, 45, 44, 13] Out[920]= {70, 42, 2012, 75, 47, 65, 34, 78, 56, 23, 16, 450, 56, 45, 44, 13} Наряду с определением весьма простой функции S, использующим шаблон вместе с составным условием, представлены функция V, заголовок которой включает условие, содержащее определение тестирующей функции, и функция Art, заголовок которой по значению внешней переменной позволяет динамически генерировать исходный код.

Mathematica наряду со стандартными средствами определения функций/процедур позволяет использовать нестандартные приемы, полезные в целом ряде приложений.

Итак, механизм шаблонов совместно с наложенными на них условиями представляет собой довольно мощное средства не только обработки выражений, но и определения функций/процедур. Несколько ниже данный вопрос будет более детализирован.

Расширение функциональной среды системы Mathematica 3.9. Механизм правил преобразования выражений в Mathematica В среде Mathematica правила преобразования в общем случае определяются функцией Rule, вызов которой Rule[a, b] возвращает правило преобразования в формате a – b.

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

ReplaceAll (/.), Replace, ReplaceRepeated (//.), ReplacePart, StringReplaceList, StringCases, StringReplace, которые используют или одно правило, или их список как простой, так и ListList–типа. Для динамической генерации таких правил может оказаться довольно полезной процедура GenRules, вызов которой GenRules[x, y] в зависимости от вида ее аргументов возвращает правило или список правил;

вызов GenRules[x, y, z] с третьим необязательным аргументом z, в качестве которого допустимо произвольное выражение, возвращает список с одним правилом или вложенный список ListList-типа. А именно, в зависимости от формата кодирования вызова процедуры возвращается результат:

GenRules[{x, y, z, …}, a] {x – a, y – a, z – a, …} GenRules[{x, y, z, …}, a, h] {{x – a}, {y – a}, {z – a}, …} GenRules[{x, y, z, …}, {a, b, c, …}] {x – a, y – b, z – c, …} GenRules[{x, y, z, …}, {a, b, c, …}, h] {{x – a}, {y – b}, {z – c}, …} GenRules[x, {a, b, c, …}] {x – a} GenRules[x, {a, b, c, …}, h] {x – a} GenRules[x, a] {x – a} GenRules[x, a, h] {x – a} Следующий фрагмент представляет исходный код процедуры GenRules с типичными примерами ее применения на все вышеуказанные случаи кодирования ее вызова.

In[1776]:= GenRules[x_, y_, z_] := Module[{a, b = Flatten[{x}], c = Flatten[If[Map[ListQ, {x, y}] == {True, False}, PadLeft[{}, Length[x], y], {y}]]}, a = Min[Map[Length, {b, c}]];

b = Map9[Rule, b[[1 ;

;

a]], c[[1 ;

;

a]]];

If[{z} == {}, b, b = Map[List, b];

If[Length[b] == 1, Flatten[b], b]]] In[1777]:= {GenRules[{x, y, z}, {a, b, c}], GenRules[x, {a, b, c}], GenRules[{x, y}, {a, b, c}], GenRules[x, a], GenRules[{x, y}, a]} Out[1777]= {{x – a, y – b, z – c}, {x – a}, {x – a, y – b}, {x – a}, {x – a, y – a}} In[1778]:= {GenRules[{x, y, z}, {a, b, c}, 70], GenRules[x, {a, b, c}, 42], GenRules[{x, y}, {a, b, c}, 47], GenRules[x, a, 6], GenRules[{x, y}, a, 65]} Out[1778]= {{{x – a}, {y – b}, {z – c}}, {{x – a}}, {{x – a}, {y – b}}, {{x – a}}, {{x – a, y – a}}} Процедура GenRules полезна, в частности, когда в некоторой процедуре необходимо динамически генерировать правила преобразований в зависимости от условий. Более того, в ряде случаев она позволяет довольно существенно сокращать исходный код.

Для преобразования выражений правила преобразования используются в сочетании с оператором замещения "/." (функция ReplaceAll), который обеспечивает применение правил преобразования (отдельного либо их списка) к каждому подвыражению данного выражения, как иллюстрируют следующие весьма простые примеры, а именно:

В.З. Аладьев, Д.С. Гринь In[1760]:= (a^x + x*b) /. x – h Out[1760]= a^h + b h In[1761]:= (x + y + z) /. {x – a, y – b, z – c} Out[1761]= a + b + c In[1762]:= (x + y + z) /. GenRules[{x, y, z}, {a, b, c}] Out[1762]= a + b + c In[1763]:= ReplaceAll[(x + y + z), GenRules[{x, y, z}, {a, b, c}, 70]] Out[1763]= {a + y + z, b + x + z, c + x + y} In[1764]:= (x + y + z) /. {{x – a}, {y – b}, {z – c}} Out[1764]= {a + y + z, b + x + z, c + x + y} В случае использования списка правил, каждое правило применяется по одному разу к каждому подвыражению выражения. Более того, при использовании списка правил ListList–типа в функции ReplaceAll (/.) возвращается список результатов замещений.

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

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

In[1769]:= (a^x + x*Sin[x] + d^x) /. {x – m, m – p} Out[1769]= a^m + d^m + m Sin[m] In[1770]:= (a^x + x*Sin[x] + d^x) //. {x – m, m – p} Out[1770]= a^p + d^p + p Sin[p] Из представленного примера весьма прозрачна разница между операторами "/." и "//.".

При использовании оператора "//." выполняется повторное применение к выражению каждого из правил до тех пор, пока не устанавливается идентичность результата на последовательных проходах. Однако при данном определении оператора "//." вполне возможны «зацикливания», когда правила носят круговой характер. В такой ситуации возникает ошибочная ситуация с выводом соответствующего сообщения с указанием числа произведенных итераций применения правил. Для устранения такой ситуации функция ReplaceRepeated располагает опцией MaxIterations, которая устанавливает максимальное число итераций для конкретного вызова функции, например:

In[771]:= (a^x + x*Sin[x] + d^x) //. {x – m, m – x} ReplaceRepeated::rrlim: Exiting after a^x+d^x+x Sin[x] scanned 65536 times.

Out[771]= a^x + d^x + x Sin[x] In[772]:= Quiet[ReplaceRepeated[a^x + x*Sin[x] + d^x, {x - m, m - x}, MaxIterations - 1]] Out[772]= a^m + d^m + m Sin[m] В любом случае обнаружения зацикливания функция ReplaceRepeated инициирует ошибочную ситуацию с выводом соответствующей диагностики, ее можно подавить с помощью функции Quiet, тогда как опция MaxIterations позволяет не только свести к Расширение функциональной среды системы Mathematica минимуму число итераций применения правил, но и получать искомый результат.

Если функция Replace применяет правила преобразований к выражению в целом, то для точечной обработки выражения можно использовать Replace вместе, например, с функцией Map и MapAt для точного указания частей выражения, к которым должны быть применены правила преобразований. Более того, можно использовать и второй формат функции Replace, позволяющий определять уровень выражения, к которому применимы правила преобразований. С такой же целью можно использовать также и функцию ReplacePart для замены конкретных частей выражения. Приведем примеры In[1782]:= (a^x + (x^x + x)*Sin[x] + d^x) /. x – m Out[1782]= a^m + d^m + (m + m^m) Sin[m] In[1783]:= Replace[a^x + (x^x + x)*Sin[x] + d^x, x – m, 2] Out[1783]= a^m + d^m + (x + x^x) Sin[x] In[1784]:= ReplacePart[a^x + (x^x + x)*Sin[x] + d^x, {2 – Cos[x], 3 – Tan[x] + Cot[y]}] Out[1784]= a^x + Cos[x] + Cot[y] + Tan[x] Списки правил могут представлять математические и иные отношения, для удобства их использования такие списки можно именовать, в последующем ссылаясь на имена.

Работа с длинными списками может потребовать заметных временных издержек. Для снижения этих издержек Mathematica позволяет предварительно обрабатывать списки правил так, чтобы оператор "/." мог обрабатывать их более быстро. Один из способов решения вопроса состоит в применении к списку правил преобразования функции, чей вызов Dispatch[{a – b, c – d,...}] генерирует оптимизирующую таблицу переходов, представляющую данный список правил. Данная таблица может быть использована в операторе "/." вместо исходного списка правил преобразования, например:

In[1788]:= T = Dispatch[{x – a, y – b, z – c, h – 70, s – 45, g – 65}];

{x, y, s, z, h, g} /.T Out[1788]= {a, b, 45, c, 70, 65} In[1789]:= %% Out[1789]= Dispatch[{x – a, y – b, z – c, h – 70, s – 45, g – 65}, –DispatchTables–] In[1790]:= Head[T] Out[1790]= Dispatch На тестах, использующих достаточно длинные списки правил, можно показать, что с целью снижения временных издержек указанного типа этот подход себя оправдывает.

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

Наряду с рассмотренными правилами типа a – b пакет допускает применение также отложенных правил (RuleDelayed) типа a : b или a : b, которые реализуются только в момент их применения. В остальном они аналогичны уже рассмотренным. С целью генерации списков данного типа правил преобразования может быть использована и представленная выше процедура GenRules, для которой функция Rule заменяется на функцию RuleDelayed, или используется ее модификация GenRules1, адаптируемая на использование той или иной функции путем соответствующего кодирования 3–го В.З. Аладьев, Д.С. Гринь фактического аргумента в вызове GenRules1[x, y, h, z], где x, y, z – аргументы, которые полностью аналогичны одноименным аргументам процедуры GenRules, тогда как h аргумент определяет режим генерации списка обычных либо отложенных правил на основе полученного им значения "r" (простое правило) либо "rd" (отложенное правило).


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

In[1803]:= GenRules1[x_, y_, h_ /;

h == "r" || h == "rd", z_] := Module[{a, b = Flatten[{x}], c = Flatten[If[Map[ListQ, {x, y}] == {True, False}, PadLeft[{}, Length[x], y], {y}]]}, a = Min[Map[Length, {b, c}]];

b = Map9[If[h == "r", Rule, RuleDelayed], b[[1 ;

;

a]], c[[1 ;

;

a]]];

If[{z} == {}, b, b = Map[List, b];

If[Length[b] == 1, Flatten[b], b]]] In[1804]:= GenRules1[{x, y, z}, {a, b, c}, "r", 70] Out[1804]= {{x – a}, {y – b}, {z – c}} In[1805]:= GenRules1[{x, y, z}, {a, b, c}, "rd", 70] Out[1805]= {{x : a}, {y : b}, {z : c}} In[1806]:= GenRules1[{x, y, z}, a, "r"] Out[1806]= {x – a, y – a, z – a} In[1807]:= GenRules1[{x, y, z}, a, "rd"] Out[1807]= {x : a, y : a, z : a} Определенный интерес для практического программирования в среде пакета может представить прием, примененный для настройки процедуры на режим выполнения.

3.10. Специальные формы присвоения значений в Mathematica Mathematica поддерживает весьма общее понятие операции присвоения, позволяющее определять данную операцию для достаточно широкого класса выражений, которые определены концепцией шаблонов пакета. Простейшие случаи отвечают присвоениям переменным, индексированным переменным и элементам структуры. Другие случаи присвоений определяют функции, процедуры или общие преобразования. Оператор "/.", определяющий применение правил преобразования к некоторому выражению, преобразовывает его только при явном применении, тогда как операторы присвоения "=" (немедленного) и ":=" (отложенного), рассмотренные выше, обеспечивают присвоения такие, которые выполняются в текущем сеансе автоматически, т.е. как только объект, получивший значение по одному из таких операторов, входит в состав какого-нибудь выражения, он автоматически выполняет его преобразование при любом обращении к такому выражению, как весьма наглядно иллюстрирует простой пример, а именно:

In[1762]:= x = Out[1762]= In[1763]:= y := In[1764]:= % In[1765]:= {x, y, x + y, x*y, (a + x)/(b + y)} Out[1765]= {70, 450, 520, 31500, (70 + a)/(450 + b)} Расширение функциональной среды системы Mathematica Следует помнить, исключая назначения локальным переменным процедур, сделанные присвоения текущего сеанса остаются доступными до тех пор, пока они не изменены.

Для очистки переменной от назначенного ей присвоения возможно использовать три способа, а именно: (1) оператор отмены назначения "=.", (2) функции Clear, ClearAll и (3) функция Remove. Однако, здесь имеет место одна особенность, а именно. Если в первых случаях переменная, очищенная от присвоенного ей значения, неопределенна и остается именем, распознаваемым пакетом, то очистка переменной функцией Remove удаляет имя полностью так, чтобы оно больше не распознавалось пакетом, например:

In[3527]:= agn = 65;

agn =.

In[3528]:= Names["`*"] Out[3528]= {"agn"} In[3529]:= agn = 65;

Clear[agn] In[3530]:= Names["`*"] Out[3530]= {"agn"} In[3531]:= agn = 65;

Remove[agn] In[3532]:= {Names["`*"], NameQ["agn"]} Out[3532]= {{}, False} Из последнего примера видно, что имя agn не принадлежит области имен пакета. Обе упомянутые функции имеют по два формата, из которых первый имеет простой вид:

Clear[x1, x2, x3, …, xp] Remove[x1, x2, x3, …, xp] и где xj (j=1..p) – символы (имена), очищаемые от присвоенных им значений (определений) с учетом вышеотмеченных различий, во многих случаях не имеющих значения. Тогда как функция ClearAll[x,y,…] очищает все значения, определения, атрибуты, значения по умолчанию и сообщения, ассоциированные с символами {x, y, …}.

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

k++ – приращение значения переменной k на 1 с возвратом старого значения;

k–– – уменьшение значения переменной k на 1 с возвратом старого значения;

++k – приращение значения переменной k на 1 с возвратом нового значения;

––k – уменьшение значения переменной k на 1 с возвратом нового значения;

k += b – приращение значения переменной k на b с возвратом нового значения;

k –= b – уменьшение значения переменной k на b с возвратом нового значения;

k *= b – умножение значения переменной k на b с возвратом нового значения;

k /= b – деление значения переменной k на b с возвратом нового значения.

В целом ряде случаев такая нотация не только позволяет существенно уменьшать код процедур/функций, но и входит в состав синтаксиса некоторых часто используемых форматов функций таких, как, например, For и While.

В.З. Аладьев, Д.С. Гринь Для присвоения одного и того же значения переменным можно использовать весьма простую конструкцию x = y = z = … = a, тогда как для присвоения переменным разных значений можно использовать конструкцию вида {x, y, z, …} = {a, b, c, …} при условии, что длины обоих списков идентичны, иначе инициируется ошибочная ситуация:

In[1762]:= {x, y, z, h, g, w, t} = {a, b, c} Set::shape: Lists {x, y, z, h, g, w, t} and {a, b, c} are not the same shape.

Out[1762]= {a, b, c} In[1773]:= ListsAssign[{x, y, z, h, g, w, t}, {a, b, c}];

{x, y, z} Out[1773]= {a, b, c} In[1774]:= ListAppValue[x_List, y_] := Quiet[x = PadLeft[{}, Length[x], y]] In[1775]:= x = 65;

ListAppValue[{x1, y, z, h, g, w, t}, 70];

{x1, y, z, h, g, w, t, x} Out[1775]= {70, 70, 70, 70, 70, 70, 70, 65} In[1776]:= Clear[x, y, z, h, g, w, t];

{x, y, z, h, g, w, t} = 70;

{x, y, z, h, g, w, t} Set::shape: Lists {x, y, z, h, g, w, t} and 70 are not the same shape.

Out[1776]= {x, y, z, h, g, w, t} Для устанения данного недостатка может быть использована процедура ListsAssign, рассматриваемая в данной книге несколько ниже, тогда как для присвоения одного и того же значения элементам списка используется функция ListAppValue, исходный код которой с примерами применения представлены предыдущим фрагментом. В то время как обмен значениями между x и y обеспечивает конструкция {x, y} = {y, x}.

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

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

In[1773]:= G[1] = 65;

G[2] = 47;

G[6] = 67;

G[8] = 23;

G[10] = 16;

In[1774]:= {s, k} = {{}, 1};

While[k = 10, s = Append[s, G[k]];

k++];

s Out[1774]= {65, 47, G[3], G[4], G[5], 67, G[7], 23, G[9], 16} In[1775]:= V[1, 1] = a;

V[1, 3] = b;

V[3, 3] = c;

V[2, 3] = d;

V[2, 2] = h;

In[1776]:= {s, k} = {{}, 1};

For[k, k = 3, k++, For[j = 1, j = 3, j++, s = Append[s, V[k, j]]]];

s Out[1776]= {a, V[1, 2], b, V[2, 1], h, d, V[3, 1], V[3, 2], c} In[1777]:= S[a] = 67;

S[b] = 45;

S[c] = 16;

S[d] = 23;

{s, k, j} = {{}, 1, CharacterRange["a", "k"]};

In[1778]:= For[k, k = 8, k++, s = Append[s, S[ToExpression[j[[k]]]]]];

s Out[1778]= {67, 45, 16, 23, S[e], S[f], S[g], S[h]} Из последнего примера следует, что в качестве значений для индексов массива можно использовать как целочисленные, так и символьные значения.

При использовании функции, определенной через оператор присвоения ":=", каждый ее вызов заново вычисляет результат. При многократных вычислениях, прежде всего, емких по временным затратам возможны весьма существенные временные издержки.

Расширение функциональной среды системы Mathematica Поэтому, с целью получения функций/процедур, запоминающих полученные ими в текущем сеансе результаты вызовов, можно использовать простой прием, состоящий в двойном присвоении при определении функции/процедуры, а именно:

G[x_, y_, …] := G[x, y, …] = Определение функции/процедуры Как иллюстрирует следующий простой пример определения такого типа процедуры In[1851]:= S[x_Integer, y_Real] := S[x, y] = Module[{a = 70}, Print[{x, y}];

a*(x + y)] In[1852]:= S[2012, 450.75] {2012, 450.75} Out[1852]= 172393.

In[1853]:= S[2012, 450.75] Out[1853]= 172393.

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

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

N[x] – возвращает численное значение для выражения x;

N[x, n] – возвращает численное значение выражения x с n–десятичной точностью.

Следующий простой пример иллюстрирует применение функции N 2–го формата:

In[1806]:= G[x_, n: Infinity] := N[x^2, n] In[1807]:= {Sin[450], G[Sin[450]], G[Sin[450], 6], G[Sin[450], 12], G[70], G[70, 8]} Out[1807]= {Sin[450], Sin[450]^2, 0.466877, 0.466876648898, 4900, 4900.0000} In[1808]:= N[Sin[70], Infinity] Out[1808]= Sin[70] Из вышеприведенного примера следует, что вызов N[x, Infinity] возвращает результат вычисления выражения x без конвертации его в числовой формат. В ряде случаев эта возможность представляется достаточно удобной при определении функций.

В заключение раздела отметим, что вопросы специальных присваиваний типа UpSet (a ^= b), присваивающего выражение b a и ассоциирующего присвоение b с символом на первом уровне a, и UpSetDelayed (a ^:= b), выполняющего отложенное присвоение выражения b a и ассоциирующего присвоение b с символом на первом уровне a, здесь не рассматриваются ввиду вводного характера данной главы, но они представляются достаточно важными при продвинутом программировании в среде Mathematica уже по той причине, что посредством данного типа присваиваний пользователь получает возможность выполнять присваивания определений, ассоциированных с различными символами, что в целом ряде случаев является довольно существенной возможностью.

Тогда как заинтересованный читатель отсылается, например, к работам [100,116] либо к справочной системе пакета Mathematica, довольно детально проработанной, которая обеспечивает пользователя справочной информацией по всем средствам пакета.

В.З. Аладьев, Д.С. Гринь 3.11. Определение процедур в программной среде Mathematica Процедуры в программной среде пакета Mathematica формально представляют собой функциональные объекты двух следующих простых форматов, а именно:

F[x_/;

Testx, y_/;

Testy,...] {:= | =} Module[{locals}, Body of Procedure] B[x_/;

Testx, y_/;

Testy,...] {:= | =} Block[{locals}, Body of Procedure] т.е., процедуры обоих типов представляют собой функции от двух аргументов – тела процедуры (Body) и локальных переменных (locals). Локальные переменные – список символов (имен), возможно, с приписанными им начальными значениями. Переменные носят относительно процедуры локальных характер, т.е. их значения не пересекаются со значениями одноименных символов вне процедуры. Все остальные переменные в процедуре носят глобальный характер, разделяя область переменных текущего сеанса.

В то время как часть определения процедуры/функции до оператора присваивания {:= | =} называется заголовком процедуры. Заголовок содержит кортеж формальных аргументов, возможно, с приписанными им тестирующими выражениями (условиями), определяющими допустимость передаваемых процедуре фактических аргументов в точке ее вызова. Значение фактического аргумента считается допустимым, если на нем тестирующее выражение получает значение True, и недопустимым в противном случае.

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

Формальный аргумент формата "x_" в качестве фактического значения допускает любое выражение. Между тем, более предпочтительным является определение процедуры на основе оператора отложенного присвоения ":=", а не "=", ибо во втором случае мы имеем влияние на переменные процедуры, определяемые ее аргументами, внешней по отношению к процедуре среды, как хорошо иллюстрирует пример с процедурой F2 из нижеследующего фрагмента – ее определение зависит от переменной x.

In[1808]:= F[x_] := Module[{a = 42}, x + a];

F1[x_] = Module[{a = 42}, x + a];

{F[70], F1[70]} Out[1808]= {112, 112} In[1809]:= Map[Definition, {F, F1}] Out[1809]= {F[x_] := Module[{a = 42}, x + a} In[1810]:= ?F Global`F F[x_] := Module[{a=42}, x + a] In[1811]:= ?F Global`F F1[x_] = 42 + x In[1812]:= x = 65;

{F1[70], x} Out[1812]= {112, 65} In[1813]:= x = 65;

F2[x_] = Module[{a = 42}, x + a];

F2[70] Out[1813]= In[1814]:= Definition[F2] Out[1814]= F2[x_] = Расширение функциональной среды системы Mathematica In[1815]:= Map[F2, {34, 56, 78, 98, 23, 16}] Out[1815]= {107, 107, 107, 107, 107, 107} In[1816]:= Map[F, {34, 56, 78, 98, 23, 16}] Out[1816]= {76, 98, 120, 140, 65, 58} In[1817]:= Map[ProcQ, {F, F1, F2}] Out[1817]= {True, False, False} In[1818]:= Map[QFunction, {"F", "F1", "F2"}] Out[1818]= {False, True, True} In[1819]:= Map[Head, {F, F1, F2}] Out[1819]= {Symbol, Symbol, Symbol} Таким образом, процедура F2 превращается в константную функцию в отличие от ее аналога F на основе оператора ":=" отложенного присвоения, возвращающего вполне ожидаемые результаты своих вызовов (см. предыдущий фрагмент). Итак, лишь оператор ":=" отложенного присвоения рекомендуется использовать в определениях процедур.

Тут же следует отметить, средства, поддерживающие процедурное программирование в среде Mathematica в достаточно значительной степени более ограничены средств в среде Maple, которые располагают довольно развитыми возможностями по обработке процедурных объектов. Именно поэтому нами был создан целый ряд средств, которые в значительной степени расширяют стандартные средства пакета, предназначенные для этой цели. Так, например, в предыдущем фрагменте использованы 2 процедуры ProcQ и QFunction, обеспечивающие тестирование объекта на предмет быть ему или процедурой, или функцией соответственно. Целый ряд других средств для работы с процедурами и функциями рассматривается и в настоящей книге несколько ниже. В седьмой главе наряду с дополнительной и специальной информацией по процедурным объектам представлен ряд средств, расширяющих Mathematica в этом направлении.

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

In[1786]:= G[x_Integer, y_ /;

{v[t_] := Module[{}, t^2], If[v[a] 2012, True, False]}[[2]]] := Module[{a = {g[z_] := Module[{}, z^3], If[g[b] 2012, 70, 90]}[[2]]}, Clear[v, g];

x*y + a] In[1787]:= {a, b} = {450, 70};

{G[42, 70], G[42, 450], G[0, 0]} Out[1787]= {3030, 18990, 90} In[1788]:= Map[Definition, {v, g}] Out[1788]= {Null, Null} In[1794]:= G[x_Integer, y_ /;

{v[t_] := Module[{}, t^2], If[v[a] 2012, True, False]}[[2]]] := Module[{a = {g[z_] := Module[{}, z^3], If[g[b] 2012, 70, 90]}[[2]]}, x*y + a] In[1795]:= {a, b} = {450, 70};

{G[42, 70], G[42, 450], G[0, 0]} Out[1795]= {3030, 18990, 90} In[1796]:= Map[Definition2, {v, g}] Out[1796]= {{"v[t_] := Module[{}, t^2]", {}}, {"g[z_] := Module[{}, z^3]", {}}} В.З. Аладьев, Д.С. Гринь Для возможности использования последовательности предложений, включая также и определения процедур, в качестве условия для формального аргумента y и начального значения для локальной переменной a использовался прием, базирующийся на списке.

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

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

Еще на одном достаточно важном моменте следует акцентировать внимание. Как уже отмечалось ранее, процедуры можно определять на основе конструкций как Module, так и Block. Но в общем случае рекомендуется отдавать предпочтение конструкциям именно типа Module, ибо в ряде случаев (здесь не рассматриваемых) конструкции типа Block выполняются некорректно, не выводя каких-либо диагностических сообщений.

В качестве иллюстрации приведем пример реализации процедуры Default1, которая была рассмотрена выше в теме относительно значений по умолчанию, двумя типами конструкций – на основе Module и Block. Следующий фрагмент представляет с точки зрения оформления, практически, идентичную реализацию определения процедуры Default1 на основе и Module, и Block. И если первая реализация выполняется вполне корректно вне зависимости от имен локальных переменных, то корректность второй, вообще говоря, зависит от пересечения списка имен локальных переменных со списком значений по умолчанию для аргументов анализируемой процедуры, как достаточно наглядно иллюстрирует следующий фрагмент, когда локальная переменная a имеется также дополнительно и в списке значений по умолчанию для простой функции G.

In[1792]:= Default1[x_Symbol, y_ /;

PosIntListQ[y], z_List] := Module[{k = 1, a = Min[Map[Length, {y, z}]]}, While[k = a, Default[x, y[[k]]] = z[[k]];

k++];

] In[1793]:= Default1[G, {1, 2}, {a, b}];

G[x_., y_.] := {x, y};

Clear[Default1];

DefaultValues[G] Out[1793]= {HoldPattern[Default[G, 1]] : a, HoldPattern[Default[G, 2]] : b} In[1794]:= Default1[x_Symbol, y_ /;

PosIntListQ[y], z_List] := Block[{k = 1, a = Min[Map[Length, {y, z}]]}, While[k = a, Default[x, y[[k]]] = z[[k]];

k++];

] In[1795]:= ClearAll[G];

Default1[G, {1, 2}, {a, b}];

G[x_., y_.] := {x, y};

DefaultValues[G] Out[1795]= {HoldPattern[Default[G, 1]] : 2, HoldPattern[Default[G, 2]] : b} In[1796]:= Default1[x_Symbol, y_ /;

PosIntListQ[y], z_List] := Module[{k = 1, h = Min[Map[Length, {y, z}]]}, While[k = h, Default[x, y[[k]]] = z[[k]];

k++];

] In[1797]:= Default1[G, {1, 2}, {a, b}];

G[x_., y_.] := {x, y};

Clear[Default1];

DefaultValues[G] Out[1797]= {HoldPattern[Default[G, 1]] : a, HoldPattern[Default[G, 2]] : b} In[1798]:= Default1[x_Symbol, y_ /;

PosIntListQ[y], z_List] := Block[{k = 1, h = Min[Map[Length, {y, z}]]}, While[k = h, Default[x, y[[k]]] = z[[k]];

k++];

] In[1799]:= ClearAll[G];

Default1[G, {1, 2}, {a, b}];



Pages:     | 1 |   ...   | 2 | 3 || 5 | 6 |   ...   | 20 |
 





 
© 2013 www.libed.ru - «Бесплатная библиотека научно-практических конференций»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.