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

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

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


Pages:     | 1 |   ...   | 3 | 4 || 6 | 7 |   ...   | 20 |

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

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

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

DefaultValues[G] Out[1799]= {HoldPattern[Default[G, 1]] : a, HoldPattern[Default[G, 2]] : b} Расширение функциональной среды системы Mathematica Таким образом, механизмы локальных переменных, используемые конструкциями на основе Module и Block, в общем случае идентичными не являются. Следовательно, в целом следует отдавать предпочтение определению процедур на основе конструкции Module, однако с учетом сказанного имеется довольно много случаев, когда оба типа организации процедур являются эквивалентными, требуя предварительного анализа на наличие такой эквивалентности. В целом же, рекомендуется использовать именно конструкцию на основе Module для определения процедур во избежание надобности проведения дополнительного анализа и универсальности на все случаи приложений.

Целому ряду функций в Mathematica, подобно функции Plot, приписаны т.н. опции, доступные как для установки, так и для переопределения. Пакет поддерживает общие механизмы для работы с такими опциями. По вызову Options[G] возвращается список текущих установок в формате {a – a1, b – b1, …} всех опций функции/процедуры G, в то время как по вызову Options[G, h] возвращается текущая установка для опции h.

По вызову SetOptions[G, a – a2, b – b2, …] обеспечивается переустановка значений для опций {a, b, …} функции/процедуры G, которая остается активной до следующей переустановки в текущем сеансе. Тогда как вызов SystemOptions[] возвращает список текущих установок для всех предустановленных внутренних опций и подопций пакета.

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

In[1762]:= CountOptions[h_] := Module[{a = SystemOptions[], b = {}, c = 1, d, k}, While[c = Length[a], d = a[[c]];

AppendTo[b, If[ListQ[Part[d, 2]], {Part[d, 1], Length[Part[d, 2]]}, d]];

c++];

b = Flatten[Gather[b, Head[#1] == Head[#2] &], 1];

If[{h} == {}, b, If[Definition1[{h}[[1]]] != "Null", Defer[CountOptions[h]], d = 0;

Do[If[ListQ[b[[k]]], d = d + b[[k]][[2]], d = d + 1], {k, Length[b]}]];

{h} = {d};

b]] In[1763]:= CountOptions[] Out[1763]= {{"AlgebraicsOptions", 5}, {"AlgebraicThreadThroughHeads", 16}, …..

"WaitUntilEnable" – True, "ZeroTestNumericalPrecision" – 80.} In[1764]:= CountOptions[g];

g Out[1764]= Вызов CountOptions[] возвращает вложенный список, элементами которого являются как списки, так и отдельные опции. Список первым элементом содержит имя группы опций, тогда как второй – число опций в этой группе. Тогда как вызов CountOptions[p] дополнительно через аргумент p – неопределенную переменную – возвращает общее количество предустановленных опций/ подопций пакета. Установки для конкретной системной опции p можно переопределять по функции SetSystemOptions[p – value], однако за исключением отдельных случаев их не следует переопределять во избежание возможных конфликтов с пакетом. Пакет не поддерживает функции удаления опций, поэтому следующий фрагмент представляет процедуру, решающую данную задачу.

В.З. Аладьев, Д.С. Гринь Вызов процедуры DeleteOptsAttr[x] возвращает Null, т.е. ничего, отменяя для символа x приписанные ему опции. Тогда как вызов процедуры DeleteOptsAttr[x,y], возвращая Null, т.е. ничего, отменяет для символа x приписанные ему как опции, так и атрибуты.

В качестве второго необязательного аргумента y выступает произвольное выражение.

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

In[2876]:= G[x_, y_] := x^2 + y^ In[2877]:= Options[G] = {Art – 23, Kr – 16} Out[2877]= {Art – 23, Kr – 16} In[2878]:= SetOptions[G, Art – 23, Kr – 16] Out[2878]= {Art – 23, Kr – 16} In[2879]:= SetAttributes[G, Listable] In[2880]:= Definition2[G] Out[2880]= {"G[x_, y_] := x^2 + y^2", "Options[G] := {Art – 23, Kr – 16}", {Listable}} In[2881]:= DeleteOptsAttr[x_ /;

ProcQ[x] || FunctionQ[x], y_] := Module[{a = Definition2[x], b, c = "Options[" ToString[x] "] "}, b = a[[–1]];

ClearAll[x];

ToExpression[Select[a, StringFreeQ[ToString[#], {c ":= ", c "= "}] &]];

If[{y} == {}, If[b != {}, SetAttributes[x, Sequences[b]]]]]] In[2882]:= DeleteOptions[G] In[2883]:= Definition2[G] Out[2883]= {"G[x_, y_] := x^2 + y^2", {Listable}} In[2884]:= Vsv[x_, y_] := x + y;

DeleteOptsAttr[Vsv, 70] In[2885]:= Definition2[Vsv] Out[2885]= {"Vsv[x_, y_] := x + y", {}} При этом, следует иметь ввиду, что данная процедура не применима к стандартным функциям пакета, возвращая на них вызов невычисленным, как иллюстрирует пример:

In[1915]:= {DeleteOptsAttr[Sin, 70], DeleteOptsAttr[Sin]} Out[1915]= {DeleteOptsAttr[Sin, 70], DeleteOptsAttr[Sin]} Ряду встроенных функций Mathematica, например Plot, приписаны опции, значения которых можно переопределять. Более того, если при вызове функции значения для допустимых опций не определяются, для них используются значения по умолчанию.

Вызов функции Options[function, option] позволяет получать значения по умолчанию для заданной вторым аргументом опции функции, определенной первым аргументом In[1912]:= Options[Plot, {PlotLabel, FrameStyle, PlotStyle, PlotRange, ColorOutput}] Out[1912]= {PlotLabel – None, FrameStyle – {}, PlotStyle – Automatic, PlotRange – {Full, Automatic}, ColorOutput – Automatic} Механизм опций, поддерживаемый Mathematica, может быть успешно использован в разработке различного типа как приложений, так и отдельных программных средств.

Детальнее с данным механизмом можно ознакомиться как в работах [100,110,113,116], так и в достаточно хорошо развитой справочной системе пакета Mathematica.

Расширение функциональной среды системы Mathematica Как известно, для обеспечения модульности программного обеспечения достаточно широко используются процедуры, которые в условиях среды Mathematica реализуют модульные и блочные конструкции, представленные выше. Как модуль (Module), так и блок (Block) обеспечивают замкнутую область переменных, которую обеспечивает механизм локальных переменных. Процедуры на основе как модульной, так и блочной структур поддерживают достаточно удовлетворительный механизм модульности. В то же время, процедуры на основе модульной структуры намного более применимы, чем на основе модульной структуры. Между тем, блочные процедуры зачастую удобны при организации интерактивных вычислений. Но не только лишь вкус программиста определяет значительно меньшую применимость процедур на блочной основе. Это, прежде всего, обусловлено тем обстоятельством, что механизм локальных пременных в процедурах на модульной основе более развит именно с точки зрения обеспечения более высокого уровня принципа черного ящика. Вкратце суть такого различия лежит в следующем. Традиционные языки программирования для работы с переменными используют т.н. механизм "лексического просмотра", который подобен модульному механизму в Mathematica, в то время как блочный механизм подобен "динамическому просмотру", используемому, например, таким символьным языком, как Lisp. Так, если лексический просмотр рассматривает локальные переменные связанными с процедурой, то динамический просмотр рассматривает значения локальных переменных связанными лишь с конкретным отрезком истории выполнения блока. В языках компилирующего типа, например, С++ имеется четкое различие между кодом и историей выполнения, тогда как доминирующий символьный характер Mathematica делает такое различие более скрытым, ибо код может генерироваться во время выполнения программы. Так, при вызове процедуры на модульной основе все появляющиеся в ее теле переменные полагаются локальными на время выполнения процедуры. Тогда как процедура на блочной основе не рассматривает тело процедуры, используя в течение выполнения процедуры локальные значения для ее переменных. Таким образом, в общем случае для обеспечения надежности рекомендуется использовать процедуры типа Module. В качестве примера различий процедур на обоих основах можно привести следующий:

In[1995]:= ClearAll[a, p, b];

a = p^3;

{Block[{p = b}, p + a], Module[{p = b}, p + a]} Out[1995]= {b + b^3, b + p^3} Для конвертации процедуры блочного типа в процедуры модульного типа используется довольно несложная процедура, представленная следующим фрагментом, а именно:

In[1989]:= BlockToModule[x_ /;

BlockQ[x]] := Module[{a = Definition2[x], c}, ClearAllAttributes[x];

ToExpression[StringReplace[a[[1]], "Block[{"– "Module[{", 1]];

SetAttributes[x, a[[2]]];

] In[1990]:= H[x_] := Block[{a = 70, b = 450, c = 75}, a*b*c + x] In[1991]:= SetAttributes[H, {Listable, Protected}] In[1992]:= BlockToModule[H];

Definition2[H] Out[1992]= {"H[x_] := Module[{a = 70, b = 450, c = 75}, a b c + x]", {Listable, Protected}} Вызов процедуры BlockToModule[x] возвращает Null, т.е. ничего, выполняя при этом В.З. Аладьев, Д.С. Гринь конвертацию процедуры x блочного типа в одноименную процедуру модульного типа с сохранением всех атрибутов исходной процедуры блочного типа.

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

In[1837]:= Sin[x^2]^2 + Cos[y + h]^2 /. {x^2 – x, y + h – x} Out[1837]= Cos[x]^2 + Sin[x]^ In[1838]:= Sin[a + b*c]*(Sin[x^2] + Cos[y + h]) /. {Sin[_] – x, Cos[_] – y} Out[1838]= x (x + y) Таким образом, между чисто символьными правилами преобразований и правилами, включающими шаблоны, в частности, "_" существует одно принципиальное отличие, а именно: если в первом случае правило преобразования производит строгую замену подвыражений преобразуемого выражения на правую часть правиль, чья левая часть строго совпадает с такими подвыражениями, во втором случае замены производятся на основе соответствия шаблонам, т.е. производится замена всех входящих в выражение подвыражений, соответствующих шаблонам – левым частям правил преобразования, как весьма наглядно иллюстрирует второй пример предыдущего фрагмента. С более детальным описанием механизмов того, как для любого выражения программировать шаблоны для правил его преобразования можно ознакомиться в спарвке по пакету. В то же время пакет не располагает механизмом применения правил преобразования к процедурам и в качестве такового может быть предложена процедура, вызов которой ReplaceProc[P, w] возвращает определение в строчном формате процедуры – результат применения к процедуре P правил преобразования w (одно правило или их список);

при этом, из правил w исключаются правила, чьи левые части совпадают с формальными аргументами процедуры P. Следующий фрагмент представляет не только исходный код процедуры с примерами ее применения, но и простую тестирующую функцию, чей вызов RuleQ[x] возвращает True, если x – правило, и False в противном случае. В определении процедуры ReplaceProc данная функция входит в ее заголовок.

In[1859]:= RuleQ[x_] := If[MemberQ[{Rule, RuleDelayed}, Head[x]], True, False] In[1860]:= Map[RuleQ, {a – b, c – d + h, Sin, a + b, ProcQ, a : b, c : d + h}] Out[1860]= {True, True, False, False, False, True, True} In[1861]:= ReplaceProc[x_ /;

ProcQ[x], r_ /;

DeleteDuplicates[Map[RuleQ, Flatten[{r}]]] == {True}] := Module[{a = Definition2[x], b = HeadPF[x], c, d = Flatten[{r}]}, c = ToExpression["Hold[" StringTrim[a[[1]], b " := "] "]"];

d = Select[d, ! MemberQ[Args1[x], ToString[Part[#, 1]]] &];

c = ToString1[ReplaceAll[c, d]];

b " := " StringTake[c, {6, –2}]] In[1862]:= ArtKr[x_ /;

IntegerQ[x], y_ /;

StringQ[y]] := Module[{a = StringLength[y], b = 70, ab = 450}, (a + x)*(b + y) + ab] Расширение функциональной среды системы Mathematica In[1863]:= ReplaceProc[ArtKr, {a – Art, b – Kr, y – 42, x – 450}] Out[1863]= "ArtKr[x_ /;

IntegerQ[x], y_ /;

StringQ[y]] := Module[{Art = StringLength[y], Kr = 70, ab = 450}, (Art + x)*(Kr + y) + ab]" Ниже будет представлен целый ряд средств, обеспечивающий более высокий уровень процедурного программирования в среде пакета Mathematica;

некоторые из которых в определенной степени были навеяны подобными средствами для пакета Maple.

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

Function[x, Тело функции] – чистая функция с одним формальным аргументом x;

Function[{x1, x2, …, xp}, Тело функции] – чистая функция с формальными аргументами x1, x2, …, xp;

(Тело функции) & – чистая функция с формальными аргументами #, #1, #2, …, #n.

При этом, при использовании третьего формата, часто называемого краткой формой чистой функции, его идентификатором служит символ амперсанда (&), чье отсутствие вызывает или ошибочные ситуации, или неверные результаты в виду невозможности идентифицировать требуемую чистую функцию.

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

# – первая переменная чистой функции;

#n – n–я первая переменная чистой функции;

## – последовательность всех переменных чистой функции;

##n – последовательность переменных чистой функции, начиная с n–й.

В отличие от ранее рассмотренных объектов таких, как функции и процедуры, при их применении необходимо явно кодировать их имена с указанием аргументов либо без оных, тогда как в случае применения чистых функций нет необходимости указывать их имена, позволяя кодировать их определения непосредственно в точке вызова, что обусловлено тем, что результаты вызова чистых функций зависят только от значений получаемых ими фактических аргументов. Например, выборка из списка L элементов, удовлетворяющих определенным условиям, и поэлементное применение функции к элементам списка может выполняться по конструкциям формата Select[L, Test[#] &] и Map[F[#] &, L] соответственно, как иллюстрирует следующий простой пример:

In[1141]:= L = {a, 70, c, 75, h, 42, g, Art, Kr, 2012, s, 450};

Select [L, IntegerQ[#] &] Out[1141]= {70, 75, 42, 2012, 450} В.З. Аладьев, Д.С. Гринь In[1142]:= Map[(#^2 + #) &, {1, 2, 3, 4, 5, 6, 7, 8, 9}] Out[1142]= {2, 6, 12, 20, 30, 42, 56, 72, 90} При использовании краткой формы чистой функции следует быть осторожным при ее кодировании, т.к. нотация амперсанда имеет довольно низкий приоритет. Поэтому выражение #1 + #2 – #3 + #2 & без круглых скобок корректно, тогда как, вообще говоря, они обязательны, в частности, при использовании чистой функции в качестве правой части правила преобразования, как иллюстрирует весьма простой пример, а именно:

In[1892]:= {a /. a – #1 + #2 + #3 &, a /. a – (#1 + #2 + #3 &)} Out[1892]= {a /. a – #1 + #2 + #3 &, #1 + #2 + #3 &} In[1893]:= {Replace[a, a – #1*#2*#3 &], a /. a – (#1*#2*#3 &)} Replace::reps: {a – #1 #2 #3 &} is neither a list of replacement rules nor a valid dispatch table, and so cannot be used for replacing.

Out[1893]= {Replace[a, a – #1 #2 #3 &], #1 #2 #3 &} В сочетании с рядом функций, например, Map, Select и некоторых других достаточно удобно использовать чистые функции, поэтому вопрос конвертации из традиционных функций в чистые представляется довольно актуальным;

для его решения могут быть использованы различные подходы, включая создание процедур–конверторов.

Следующая процедура обеспечивает конвертацию функции, определяемой форматом G[x_, y_, …] := W(x, y, …), в чистую функцию любого допустимого формата, а именно:

вызов FuncToPure[x] возвращает чистую функцию, являющуюся аналогом функции x, третьего формата, тогда как вызов FuncToPure[x, p], где p – произвольное выражение, возвращает чистую функцию 2–х первых форматов. Следующий фрагмент приводит исходный код процедуры FuncToPure с типичными примерами ее применения.

In[1822]:= FuncToPure[x_ /;

QFunction[ToString[x]], y_] := Module[{a = HeadPF[x], b = Map[ToString, Args[x]], c = Definition2[x][[1]], d, k = 1, h, t, g = {}, p}, d = Map[First, Mapp[StringSplit, b, "_"]];

p = StringTrim[c, a " := "];

h = "Hold[" p "]";

{t, h} = {Length[b], ToExpression[h]};

While[k = t, g = Append[g, d[[k]] " – #" ToString[k]];

k++];

h = ToString1[ReplaceAll[h, ToExpression[g]]];

g = StringTake[h, {6, –2}];

ToExpression[If[{y} != {}, "Function[" If[Length[b] == 1, StringTake[ToString[d], {2, –2}], ToString[d]] ", " p "]", g " &"]]] In[1823]:= G[x_Integer, y_Integer, z_Real] := z*(x + y) + Sin[x*y*z];

FuncToPure[G] Out[1823]= #3 (#1 + #2) + Sin[#1 #2 #3] & In[1824]:= G[x_Integer, y_Integer, z_Real] := z*(x + y) + Sin[x*y*z];

FuncToPure[G, 70] Out[1824]= Function[{x, y, z}, z (x + y) + Sin[x y z]] In[1825]:= V[x_ /;

IntegerQ[x]] := If[PrimeQ[x], True, False];

Select[{47, 70, 23, 16, 450, 13, 42, 567, 2, 123, 321, 17, 29}, FuncToPure[V]] Out[1825]= {47, 23, 13, 2, 17, 29} In[1826]:= {S[x_] := x^2 + 23*x + 16;

FuncToPure[S, 2], FuncToPure[S][70]} Out[1826]= {Function[x, x^2 + 23 x + 16], 6526} Расширение функциональной среды системы Mathematica Между тем, применяя данную процедуру для конвертации традиционной функции в чистую функцию, следует иметь в виду ряд существенных моментов, а именно. Во– первых, результирующая чистая функция не будет обладать атрибутами, опциями и начальными значениями аргументов, а также тестами на допустимость фактических аргументов. Во-вторых, конвертация автоматически не делает результатную функцию чистой, если исходная традиционная функция таковой не являлась, т.е. результат ее вызова зависит только от получаемых фактических аргументов. Ряд полезных средств работы с чистыми функциями будет рассмотрен несколько ниже.

Для идентификации функциональных объектов (традиционных и чистых функций) в программной среде пакета имеются довольно ограниченные средства, базирующиеся только на вызовах функций Part[x, 0] и Head[x], возвращающих заголовки выражения x;

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

In[1905]:= G[x_Integer, y_Real, z_Real] := x*y^2 + z In[1906]:= Map[Head, {#1 + #2*#3 &, Function[{x, y, z}, x + y*z], G, ProcQ}] Out[1906]= {Function, Function, Symbol, Symbol} In[1907]:= Mapp[Part, {#1 + #2*#3 &, Function[{x, y, z}, x + y*z], G, ProcQ}, 0] Out[1907]= {Function, Function, Symbol, Symbol} In[1908]:= Map[PureFuncQ, {#1 + #2*#3 &, Function[{x, y, z}, x + y*z], G, ProcQ}] Out[1908]= {True, True, False, False} In[1909]:= Map[QFunction, {#1 + #2*#3 &, Function[{x, y, z}, x + y*z], G, ProcQ}] Out[1909]= {False, False, True, False} In[1910]:= Map[FunctionQ, {#1 + #2*#3 &, Function[{x, y, z}, x + y*z], G, ProcQ}] Out[1910]= {True, True, True, False} In[1942]:= {m, n} = {#1 + #2*#3 &, Function[{x, y, z}, x + y*z]};

Map[Head, {m, n}] Out[1942]= {Function, Function} In[1943]:= {Mapp[Part, {m, n}, 0], Map[QFunction, {m, n}]} Out[1943]= {{Function, Function}, {False, False}} In[1944]:= {Map[FunctionQ, {m, n}], Map[PureFuncQ, {m, n}]} Out[1944]= {{True, True}, {True, True}} In[1945]:= FunctionQ[x_] := PureFuncQ[x] || QFunction[x] In[1946]:= Map[FunctionQ, {G, ProcQ, Function[{x, y, z}, x + y*z], #1 + #2*#3 &}] Out[1946]= {True, False, True, True} Прежде всего, определен ряд средств для дифференцированной идентификации как функций в целом, так и традиционных и чистых функций в частности – процедуры и функции FunctionQ, QFunction и PureFuncQ соответственно. Таким образом, данные средства обеспечивают дифференциацию такого базового элемента функционального и процедурного программирования, как функция. И завершает предыдущий фрагмент простая реализация функции FunctionQ, чей вызов FunctionQ[x] возвращает значение True, если x – функция произвольного типа (традиционного и чистого), и False иначе.

Эти и им подобные средства достаточно полезны в прикладном программировании.

В.З. Аладьев, Д.С. Гринь 3.13. Понятие контекста и его использование в Mathematica Понятие контекста введено в программную среду пакета для организации работы с символами, которые представляют различные объекты (переменные, функции, пакеты, процедуры и пр.), во избежание возможных конфликтов с одноименными символами.

Основная идея состоит в том, что полное имя любого символа состоит из двух частей:

контекст и краткое имя, т.е. полное имя некоторого объекта имеет следующий формат:

"контекст`краткое имя", где символ "`" (обратная кавычка) выполняет роль маркера, идентифицирующего контекст в программной среде пакета. Например, Avzagn`Vsv представляет символ с контекстом Avzagn и кратким именем Vsv. При этом, с такими символами можно производить операции, как с обычными именами, например:

In[1813]:= Rans`Ian := 75;

Rac`Ian := 450;

Rans`Ian^2 + Rac`Ian^ Out[1813]= In[1814]:= Rans`Ian === Rans`Rac Out[1814]= False При этом, пакет рассматривает символы aaaa`xyz и bbbb`xyz полностью различными.

Наиболее распространенным методом использования контекста является присвоение его функционально одинаковым или семантически связанным символам. Например, AladjevProceduresAndFunctions`ToString1, AladjevProceduresAndFunctions`ProcQ функция ToString1 и процедура ProcQ принадлежат одной и той же группе средств, имеющих контекст AladjevProceduresAndFunctions`. Текущий контекст определен для любого момента сеанса пакета, он находится в глобальной переменной $Context:

In[1815]:= $Context Out[1815]= "Global`" В текущем сеансе Mathematica текущим контекстом по умолчанию определен Global`.

Тогда как глобальная переменная $ContextPath определяет список контекстов после $Context для поиска введенного в текущий сеанс символа. Обращаться к символам из текущего контекста можно просто по их кратким именам;

при этом, если этот символ пересекается с символом из списка, определяемого переменной $ContextPath, именно второй будет использован вместо символа из текущего контекста, например:

In[1816]:= $ContextPath Out[1816]= {"AladjevProceduresAndFunctions`", "PacletManager`", "WebServices`", "System`", "Global`"} Тогда как вызовы Context[x] и Contexts[] возвращают контекст, приписанный символу x, и список всех контекстов соответственно, например:

In[1819]:= Context[ProcQ] Out[1819]= "AladjevProceduresAndFunctions`" In[1820]:= Contexts[] Out[1820]= {"AladjevProceduresAndFunctions`","AladjevProceduresAndFunctions`Arity`", ================================================================== "XML`MathML`Symbols`", "XML`NotebookML`", "XML`Parser`", "XML`RSS`"} Расширение функциональной среды системы Mathematica По аналогии с файловой системой компьютера, контексты можно вполне сравнивать с каталогами. Можно определять путь к файлу, указывая каталог, его содержащий, и само имя файла. В то же время, текущий контекст вполне может быть ассоциирован с текущим каталогом, к файлам которого можно обращаться просто по их именам. При этом, подобно файловой системе контексты могут иметь иерархическую структуру, в частности, "Visualization`VectorFields`VectorFieldsDump`". Итак, путь поиска контекста для символов в среде пакета Mathematica подобен пути поиска программных файлов.

В начале сессии Mathematica текущий контекст по умолчанию полагается Global`, и все вводимые символы будут ассоциированы именно с данным контекстом, исключая встроенные символы, например, While, приписанные контексту System`. Путь поиска контекстов по умолчанию включает контексты для системно–определенных символов.

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

In[1834]:= avz := 70;

Context["avz"] Out[1834]= "Global`" In[1835]:= Remove["avz"];

Context["avz"] Context::notfound: Symbol avz not found.

Out[1835]= Context["avz"] При использовании контекстов нет гарантии, что два одноименных символа имеются в различных контекстах. Поэтому пакет определяет максимальным приоритет выбора именно того символа с этим именем, чей контекст является первым в списке, который определяется глобальной переменной $ContextPath. Поэтому, для помещения такого контекста в начало указанного списка можно использовать простую конструкцию:

In[1843]:= $ContextPath Out[1843]= {"AladjevProceduresAndFunctions`", "PacletManager`", "WebServices`", "System`", "Global`"} In[1844]:= PrependTo[$ContextPath, "Ransianavz`"] Out[1844]= {"Ransianavz`", "AladjevProceduresAndFunctions`", "PacletManager`", "WebServices`", "System`", "Global`"} In[1845]:= $ContextPath Out[1845]= {"Ransianavz`", "AladjevProceduresAndFunctions`", "PacletManager`", "WebServices`", "System`", "Global`"} В результате символы с тем же самым кратким именем, контексты которых находятся в списке $ContextPath далее от начала, недоступны для обращения к ним по краткому имени. Поэтому для обращения к ним следует использовать полные имена формата Context`Name;

при этом, при вводе новых символов, перекрывающих одноименные в списке $ContextPath, выводится соответствующее сообщение. Для ввода в текущий сеанс символа s, перекрывающего уже существующие одноименные символы, следует предварительно реорганизовать $ContextPath или удалить этот символ по Remove[s].

Связь контекстов и пакетов в среде Mathematica.

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

При загрузке пакета в текущий сеанс, данный контекст добавляется в начале списка, определяемого глобальной переменной $ContextPath. Как правило, для обеспечения ассоциирования пакета с контекстом используется конструкция BeginPackage["xxx`"], кодируемая в его начале. При загрузке пакета в текущий сеанс именно контекст "xxx`" будет обновлять текущие значения глобальных переменных $Context и $ContextPath.

Так, пакет AVZ_Package содержит BeginPackage["AladjevProceduresAndFunctions`"] и при его загрузке значения указанных переменных принимают следующий вид:

In[3576]:= $ContextPath Out[3576]= {"AladjevProceduresAndFunctions`", "PacletManager`", "WebServices`", "System`", "Global`"} In[3577]:= MemberQ[Contexts["*"], "AladjevProceduresAndFunctions`"] Out[3577]= True In[3578]:= $Packages Out[3578]= {"AladjevProceduresAndFunctions`", "ResourceLocator`", "GetFEKernelInit`", "DocumentationSearch`", "JLink`", "PacletManager`", "WebServices`", "System`", "Global`"} In[1878]:= CNames[x_ /;

ContextQ[x], y_] := Module[{a = Names[StringJoin[x, "*"]], b}, b = Select[a, Quiet[ToString[Definition[ToString[#1]]]] != "Null" &];

If[{y} != {} && Definition1[{y}[[1]]] == "Null", {y} = {Select[a, ToString[Definition[ToString[#1]]] == "Null" &]}];

Select[b, Attributes[#] != {Temporary} && ToString[Definition[#]] != "Null" &]] Out[1879]= {"AcNb", "ActiveProcess", "ActRemObj", "ActUcontexts", "Adrive", "Adrive1", …, "$CallProc", "$HeadProc", "$Help", "$Line1", "$ProcName", "$TypeProc"} In[1880]:= Length[%] Out[1880]= In[1881]:= CNames["AladjevProceduresAndFunctions`", h];

h Out[1881]= {"a", "a$", "b", "b$", "c", "c$", "d", "d$", "k", "k$", "S", "S$", "x", "x$", "y", "y$"} In[1882]:= CNames["PacletManager`"] Out[1882]= {"CDFOpen", "GetVirtualCellGroup", …, "$UserBasePacletsDirectory"} При этом, в приведенном фрагменте вместо вывода полного списка, определяемого по вызову Contexts["*"], в целях экономии места проведено лишь тестирование наличия в нем указанного контекста. Из полного же списка Contexts["*"] легко усматривается, что в нем наряду с данным контекстом в качестве элементов имеются элементы вида "AladjevProceduresAndFunctions`Name`", определяющие полные имена всех объектов, определения которых находятся в пакете AVZ_Package. Представленная в завершении фрагмента процедура CNames позволяет дифференцированно получать списки всех кратких имен в пакете с заданным контекстом как имеющих определения в нем, так и неопределенных с точки зрения текущего сеанса. Так, вызов CNames[х] возвращает список всех кратких имен в пакете с контекстом х, имеющих в нем определения, тогда Расширение функциональной среды системы Mathematica как вызов CNames[х, y] дополнительно через аргумент y – неопределенную переменную – возвращает список всех неопределенных кратких имен в пакете с контекстом x. Наряду с этим, анализ списка, возвращаемого через необязательный аргумент y, обеспечивает дополнительную возможность проверки содержимого пакета на определенность всех объектов, запланированных для обеспечения аннонсируемых его функций. CNames обеспечивает простой способ дифференцированного анализа содержимого пакетов, оформленных в форме документов форматов {"nb", "cdf"}.

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

3.14. Определение пакетов и их использование в Mathematica Подобно многим развитым системам Mathematica является расширяемой системой, т.е. дополнительно к своим встроенным функциональным средствам, которые вполне покрывают потребности довольно широкого круга пользователей, система позволяет в среде своего встроенного Math-языка программировать недостающие конкретному пользователю средства, а также расширять и исправлять стандартные средства. Более того, недостающие средства, не являющиеся встроенными, пользователь может найти в многочисленных пакетах как поставляемых с Mathematica, так и существующих для различных прикладных областей. Вопрос лишь в нахождении нужного пакета. Пакет имеет стандартную организацию и содержит определения различных объектов, как– то функции, процедуры, переменные и т.д., рещающих определенные задачи. Перед использованием средств пакета его предварительно нужно загрузить в текущий сеанс по функции Пакет или Get[Пакет]. Детальнее об этом говорится несколько ниже.

Глобальная переменная $Packages определяет список контекстов, соответствующих всем пакетам, загруженным в текущий сеанс, как иллюстрирует следующий пример:

In[1791]:= $Packages Out[1791]= {"AladjevProceduresAndFunctions`", …, "System`", "Global`"} In[1792]:= Get[ "C:\\Avz_Package\\Aladjev.m"];

$Packages Out[1792]= {"Aladjev`", "AladjevProceduresAndFunctions`", …, "System`", "Global`"} Каждая загрузка в текущий сеанс нового пакета добавляет в начало списка $Packages соответствующий ему контекст, как иллюстрирует последний пример фрагмента. В В.З. Аладьев, Д.С. Гринь целом, при наличии загруженных пакетов их средства вполне можно рассматривать в качестве средств на уровне встроенных средств Mathematica. Фактически же, довольно существенное число функций, которые встроены в базовую систему Mathematica, было реализовано в виде пакетов. Между тем, в большинстве релизов системы Mathematica требуется предварительная загрузка пакетов для получения доступа к содержащимся в них средствам. Большинство релизов Mathematica обеспечено стандартным набором пакетов, которые содержат определения весьма большого количества функций. Для их использовать, как правило, такие пакеты необходимо загружать явно. Mathematica располагает механизмом как предварительной загрузки, так и автоматической загрузки пакетов по мере необходимости. При использовании данного механизма все средства таких пакетов можно рассматривать на уровне стандартных, однако здесь имеет место одно весьма существенное обстоятельство – справки по таким пакетным средствам не отражаются в справочной базе Mathematica, и к справкам по ним можно обращаться, например, по конструкции ?Name. Такая организация не совсем удобна, существенно уступая, в частности, подобному механизму системы Maple [21-23,25-27].

Основными формами сохранения определений объектов являются документ (notebook) и пакет (package), находящиеся в файлах форматов {nb, cdf} и {m, mx} соответственно. В то же время между ними существует определенное различие. Если загрузка первого в текущий сеанс позволяет работать с ним, как документом (просматривать, выполнять, редактировать, сохранять), то пакет предназначен лишь для загрузки в текущий сеанс.

Между тем, многие документы частично либо полностью можно рассматривать как пакеты. В частности, для удобства работы с пакетом AVZ_Package [90] он представлен нами в трех основных платформо–независимых форматах, а именно {nb, cdf, m}. Здесь же отметим, бинарные файлы mx-формата, оптимизированного под быструю загрузку их в текущий сеанс, являются непереносимыми как между релизами Mathematica, так и между операционными платформами. Поэтому здесь они не рассматриваются.

Загрузка пакета в текущий сеанс. В общем случае типичный пакете обеспечен двумя типами символов, определяющими как экспортируемые символы, так и символы для внутреннего использования. Для различия эти символы ассоциируются с различными контекстами. Стандартный прием состоит в помещении определений экспортируемых символов в контекст с именем Name`, который соответствует имени пакета. Тогда, при загрузке пакета он дополняет список $ContextPath для обеспечения вызова символов, находящихся в данном контексте, по их коротким именам. Тогда как определения всех символов, предназначенных для внутреннего использования, помещаются в контекст с именем Package`Private`, который не добавляется в список $ContextPath, не позволяя получать доступ к символам такого контекста по их коротким именам. Как правило, в целях настройки контекстов пакета и глобальных переменных $Context и $ContextPath используется стандартная последовательность функций в пакете, а именно:

BeginPackage["Package`"] – установка для пакета текущего контекста "Package`";

F::usage = "Текст" – справка по экспортируемому символу F;

в дальнейшем позволяет получать справку по конструкциям ?F и Information[F];

Begin["`Private`"] – установка контекста "`Private`" для локальных символов;

F[args] = Definition;

… – определения локальных и глобальных символов пакета;

Расширение функциональной среды системы Mathematica ============================================================== End[] EndPackage[] – закрывающая скобка для пакета;

одновременно добавляющая в начало списка $ContextPath контекст "Package`".

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

In[1972]:= BeginPackage["Kherson`"] G::usage = "Function G[x, y] := 70*x^2 + 65*y + 45 + S[x, y]."

Begin["`Private`"] S[x_, y_] := x^2 + y^ G[x_ /;

IntegerQ[x], y_ /;

IntegerQ[y]] := 70*x^2 + 65*y + 45 + S[x, y] End[] EndPackage[] Out[1972]= "Kherson`" Out[1973]= "Function G[x, y] := 70*x^2 + 65*y + 45 + S[x, y]."

Out[1974]= "Kherson`Private`" Out[1975]= "Kherson`Private`" In[1983]:= {S[75, 450], G[75, 450]} Out[1983]= {S[75, 450], 631170} In[1984]:= $ContextPath Out[1984]= {" Kherson`", "AladjevProceduresAndFunctions`", "PacletManager`", "WebServices`", "System`", "Global`"} In[1985]:= $Context Out[1985]= "Kherson`" In[1986]:= Information[S] Out[1986]= Kherson`S In[1987]:= Information[G] Out[1987]= Function G[x, y] := 70*x^2 + 65*y + 45 + S[x, y].

G[x_/;

IntegerQ[x], y_/;

IntegerQ[y]] := 70 x^2+65 y+45+Kherson`Private`S[x, y] In[1988]:= Kherson`Private`S[75, 450] Out[1988]= In[1989]:= $Packages Out[1989]= {"Kherson`", "AladjevProceduresAndFunctions`", "ResourceLocator`", "DocumentationSearch`", "GetFEKernelInit`", "JLink`", "PacletManager`", "WebServices`", "System`", "Global`"} Отметим, определение справок (usage) для средств, экспортируемых пакетом, служит своего рода индикатором того, что именно данные средства экспортируются пакетом, тогда как определения средств без справок определяют локальные символы, которые вне пакета невидимы, однако могут использоваться как локальными, так и глобальными символами пакета. Данная организация более проста. Ввиду этого организационная схема пакета может быть упрощена, приняв достаточно простой вид, а именно:

В.З. Аладьев, Д.С. Гринь BeginPackage["Package`"] – установка для пакета текущего контекста "Package`";

F::usage = "Текст справки" – справка по экспортируемым символам F;

в дальнейшем она позволяют получать справку по конструкциям ?F и Information[F];

Begin["`F`"] – установка контекста "`F`" для глобального символа;

F[Formal args] = Definition F;

… – определение глобального символа F пакета;

V1[Formal args] = Definition V1;

… – определение локального символа V1 пакета;

============================================================== End[] EndPackage[] – закрывающая скобка для пакета;

одновременно добавляющая в начало списка $ContextPath контекст "Package`".

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

In[1821]:= BeginPackage["Kherson5`"] G5::usage = "Function G5[x, y] := 70*x^2 + 65*y + 45 + S5[x, y]."

Begin["`G5`"] S5[x_, y_] := x^2 + y^ G5[x_ /;

IntegerQ[x], y_ /;

IntegerQ[y]] := 70*x^2 + 65*y + 45 + S5[x, y] End[] EndPackage[] Out[1821]= "Kherson5`" Out[1822]= "Function G5[x, y] := 70*x^2 + 65*y + 45 + S5[x, y]."

Out[1823]= "Kherson5`G5`" Out[1826]= "Kherson5`G5`" In[1828]:= {S5[75, 450], G5[75, 450]} Out[1828]= {S5[75, 450], 631170} In[1829]:= $ContextPath Out[1829]= {"Kherson5`", "AladjevProceduresAndFunctions`", "PacletManager`", "WebServices`", "System`", "Global`"} In[1830]:= $Packages Out[1830]= {"Kherson5`", "AladjevProceduresAndFunctions`", "ResourceLocator`", "DocumentationSearch`", "GetFEKernelInit`", "JLink`", "PacletManager`", "WebServices`", "System`", "Global`"} In[1831]:= Information[S5] Global`S In[1832]:= Information[G5] Function G5[x, y] := 70*x^2 + 65*y + 45 + S5[x, y].

G5[Kherson5`G5`x_/;

IntegerQ[Kherson5`G5`x], Kherson5`G5`y_/;

IntegerQ[Kherson5`G5`y]] := 70 Kherson5`G5`x^2 + 65 Kherson5`G5`y + 45 + Kherson5`G5`S5[Kherson5`G5`x, Kherson5`G5`y] Расширение функциональной среды системы Mathematica Для определения статуса существования контекста (отсутствует, текущий без файла, текущий с файлом m-формата, неактивный с файлом m-формата) может использоваться следующая процедура FindFileContext1, чей исходный код с типичными примерами применения представляет следующий фрагмент, а именно:

In[1879]:= FindFileContext1[x_ /;

ContextQ[x]] := Module[{a = FindFileContext[x], b = If[MemberQ[$ContextPath, x], "Current", {}]}, If[a != {} && ! SameQ[b, {}], {b, a}, If[a != {} && SameQ[b, {}], a, If[a == {} && ! SameQ[b, {}], b, {}]]]] In[1880]:= FindFileContext1["Kherson5`"] Out[1880]= "Current" In[1881]:= FindFileContext1["AladjevProceduresAndFunctions`"] Out[1881]= {"Current", {"c:\\avz_package\\avz_package.m"}} In[1882]:= FindFileContext1["Aladjev`"] Out[1882]= {"c:\\avz_package\\aladjev.m"} In[1883]:= FindFileContext1["Ransian`"] Out[1883]= {} In[1884]:= FindFileContext["PacletManager`"] Out[1884]= {"c:\\program files\\wolfram research\\mathematica\\8.0\\addons \\ applications\\resourcelocator\\resourcelocator.m", "c:\\program files \\wolfram research\\mathematica\\8.0\\systemfiles\\autoload\\pacletmanager \\pacletmanager.m", "c:\\program files\\wolfram research\\mathematica\\8. \\systemfiles\\links\\cudalink\\nvcccompiler.m"} В зависимости от статуса контекста x вызов процедуры FindFileContext1[x] возвращает:

– {"Current", {m–файлы}} – контекст x является текущим и находится в m–файлах;

– "Current" – контекст x является текущим, но не ассоциирован с m–файлами;

– {m–файлы} – контекст x находится в m–файлах, но не в списке $ContextPath;

– {} – контекст x является формально корректным, но не фактическим.

Процедура представляется достаточно полезной в работе с пакетами. Несколько ниже будет представлен ряд полезных процедур для работы с пакетами и контекстами.

Для получения доступа к пакетным средствам необходимо, чтобы пакет, содержащий их, был загружен в текущий сеанс, а список $ContextPath должен включать контекст, соответствующий данному пакету. Пакет можно загружать в любом месте документа по функции Get["context`"], либо по функции Needs["context`"] определять загрузку пакета, если контекст, ассоциированный с пакетом, отсутствует в списке $Packages. В случае, если пакет начинается BeginPackage["Package`"], то при его загрузке в списки $ContextPath и $Packages помещается лишь контекст "Package`", обеспечивая доступ к экспортам пакета и системным средствам. Если же пакет использует средства других пакетов, он должен начинаться BeginPackage["Package`", {"Package1`", …, "Package2`"}] с указанием списка контекстов, ассоциированных с такими пакетами. Это позволяет дополнительно включать в списки $ContextPath и $Packages требуемые контексты.

В.З. Аладьев, Д.С. Гринь Пакет подобно процедурам допускают вложенность;

при этом, в системе распознаются и регистрируются все входящие в него подпакеты. Более того, объекты, определенные как в главном пакете, так и в подпакетах, полностью доступны в текущем сеансе после загрузки в него вложенного пакета, как довольно наглядно иллюстрирует следующий весьма простой фрагмент. Между тем, для выполнения вышесказанного необходимо после загрузки вложенного пакета переопределить переменную $ContextPath, добавив в определяемый ею список все контексты подпакетов главного пакета, а именно:

In[1821]:= BeginPackage["Kiev`"] W::usage = "Help on W."

Begin["`W`"] W[x_Integer, y_Integer] := x^2 + y^ End[] BeginPackage["Kiev1`", {"Kiev`"}] W1::usage = "Help on W1."

Begin["`W1`"] W1[x_Integer, y_Integer] := x*y + W[x, y] End[] EndPackage[] EndPackage[] Out[1821]= "Kiev`" Out[1822]= "Help on W."

Out[1823]= "Kiev`W`" Out[1825]= "Kiev`W`" Out[1826]= "Kiev`" Out[1827]= "Help on W1."

Out[1828]= "Kiev`W1`" Out[1830]= "Kiev`W1`" In[1831]:= $ContextPath = AppendTo[$ContextPath, "Kiev1`"] Out[1831]= {"Kiev`", "PacletManager`", "WebServices`", "System`", "Global`", "Kiev1`"} In[1832]:= $Packages Out[1832]= {"Kiev1`", "Kiev`", "ResourceLocator`", "DocumentationSearch`", "GetFEKernelInit`", "JLink`", "PacletManager`", "WebServices`", "System`", "Global`"} In[1833]:= CNames["Kiev`"] Out[1833]= {"W"} In[1834]:= CNames["Kiev1`"] Out[1834]= {"W1"} In[1835]:= {W[42, 70], W1[42, 70]} Out[1835]= {6664, 9604} In[1836]:= Definition[W] Out[1836]= W[Kiev`W`x_Integer, Kiev`W`y_Integer] := Kiev`W`x^2 + Kiev`W`y^ In[1837]:= Definition[W1] Out[1837]= W1[Kiev`W1`x_Integer, Kiev`W1`y_Integer] := Kiev`W1`x Kiev`W1`y + W[Kiev`W1`x, Kiev`W1`y] Расширение функциональной среды системы Mathematica Пакет можно сохранять в файлах любого из следующих форматов, а именно:

File.nb – файл со стандартным документом (notebook) системы Mathematica;

более того, имеется возможность конвертации такого файла в файлы 9 форматов, включая {cdf, m};

File.m – файл с пакетом исходного формата системы Mathematica;

File.mx – файл с пакетом формата DumpSave системы Mathematica;

оптимизированный под конкретно используемую операционную платформу.

По функции Get["Имя`"] Mathematica, прежде всего, делает попытку автоматически загрузить версию файла "Имя.mx", который оптимизирован для текущей платформы, если же такой файл не найден, делается попытатка загрузить файл "Имя.m", который содержит код, переносимый на другие платформы. Если используется имя каталога, делается попытка считать "init.m", предназначенная для настройки пакетов каталога.

Для обеспечения режима автоматической загрузки пакетов используется специальная функция DeclarePackage. При этом, для удаления всех символов некоторого контекста, точнее, экпортов пакета с этим контекстом, используется вызов Remove["Name`"].

Как отмечалось ранее, для каждого экспортируемого объекта пакета для него следует определить справку (usage). В результате загрузки такого пакета в текущий сеанс все его экспорты становятся доступными, тогда как локальные объекты, расположенные в секции, скажем Private, в текущем сеансе недоступны. Для тестирования загруженного пакета на предмет наличия в нем как глобальных, так и локальных объектов может быть использована процедура, вызов которой DefInPackage[x] возвращает или список всех глобальных символов пакета, определяемого контекстом x, или вложенный список, чей первый подсписок определяет глобальные символы, тогда как второй – определения в строчном формате всех его локальных символов. Если x не является пакетом, то вызов DefInPackage[x] возвращается невычисленным. Фрагмент представляет исходный код процедуры DefInPackage с наиболее типичными примерами ее применения.

In[1804]:= BeginPackage["Kherson`"] Gs::usage = "Help on Gs."

Ga::usage = "Help on Ga."

Vgs::usage = "Help on Vgs."

Begin["`Private`"] W[x_, y_] := x + y Vt[y_] := y + Sin[y] Sv[x_] := x^2 + 23*x + End[] Begin["`Gs`"] Gs[x_Integer, y_Integer] := x^2 + y^ End[] Begin["`Ga`"] Ga[x_Integer, y_Integer] := x*y + Gs[x, y] End[] Begin["`Vgs`"] Vgs[x_Integer, y_Integer] := x*y В.З. Аладьев, Д.С. Гринь End[] EndPackage[];

Out[1804]= "Kherson`" Out[1805]= "Help on Gs."

Out[1806]= "Help on Ga."

Out[1807]= "Help on Vgs."

Out[1808]= "Kherson`Private`" Out[1812]= "Kherson`Private`" Out[1813]= "Kherson`Gs`" Out[1815]= "Kherson`Gs`" Out[1816]= "Kherson`Ga`" Out[1818]= "Kherson`Ga`" Out[1819]= "Kherson`Vgs`" Out[1821]= "Kherson`Vgs`" In[1822]:= Map[FunctionQ, {Ga, Gs, Vgs, W, Vt, Sv}] Out[1822]= {True, True, True, False, False, False} In[1823]:= BeginPackage["Kherson1`"] Gs1::usage = "Help on Gs1."

Ga1::usage = "Help on Ga1."

Begin["`Gs1`"] Gs1[x_Integer, y_Integer] := x^2 + y^ End[] Begin["`Ga1`"] Ga1[x_Integer, y_Integer] := x*y + Gs1[x, y] End[] EndPackage[];

Out[1823]= "Kherson1`" Out[1824]= "Help on Gs1."

Out[1825]= "Help on Ga1."

Out[1826]= "Kherson1`Gs1`" Out[1828]= "Kherson1`Gs1`" Out[1829]= "Kherson1`Ga1`" Out[1831]= "Kherson1`Ga1`" In[1837]:= DefInPackage[x_ /;

ContextQ[x]] := Module[{d = CNames[x], Q, f = "ArtKr", h, k = 1, t = {}, v, s = FromCharacterCode[16], w = {}}, If[d == {}, Return[Defer[DefInPackage[x]]]];

Q[np_] := Module[{a = Save[f, np], b = "", c = "", j = 1, p = {}}, For[j, j Infinity, j++, c = ToString[Read[f, String]];

If[c == "EndOfFile", Break[], b = b c]];

DeleteFile[Close[f]];

For[j = 1, j = Length[d], j++, p = Append[p, {x "Private`", x d[[j]] "`"}]];

RedSymbStr[StringReplace[b, GenRules[Flatten[p], ""]], " ", " "]];

d = Reverse[d];

t = {Q[d[[1]]]};

Расширение функциональной среды системы Mathematica For[k = 2, k = Length[d], k++, t = Append[t, {StringReplace[Q[d[[k]]], Q[d[[k – 1]]] – ""], StringReplace[Q[d[[k – 1]]], Q[d[[k]]] – ""]}]];

t = Map[StringTrim, DeleteDuplicates[Flatten[t]]];

k = 1;

While[k = Length[t], w = Append[w, Rule[t[[k]], ""]];

k++];

h = StringReplace[Q[x], w];

If[MemberQ[{"", " "}, h], Return[d], v = Quiet[Select[SubStrSymbolParity[h, "[", "]", 0], ! StringFreeQ[#, "_"] &]]];

v = Flatten[Map[First, StringPosition[h, v]]];

t = {};

For[k = 1, k = Length[v], k++, t = Append[t, SubsPosSymb[h, v[[k]], " ", 0]]];

{d, Map[StringTrim, StringSplit[StringReplace[h, GenRules[t, Map3[StringJoin, s, t]]], s]]}] In[1838]:= DefInPackage["Kherson`"] Out[1838]= {{"Vgs", "Gs", "Ga"}, {"W[x_, y_] := x + y", "Sv[x_] := x^2 + 23*x + 16", "Vt[y_] := y + Sin[y]"}} In[1839]:= DefInPackage["Kherson1`"] Out[1839]= {"Gs1", "Ga1"} In[1740]:= SubsPosSymb[x_ /;


StringQ[x], n_ /;

PosIntQ[n], y_ /;

ListQ[y] && DeleteDuplicates[Map[CharacterQ, y]] == {True}, z_ /;

z == 0 || z == 1] := Module[{a = "", k = n, b}, If[n StringLength[x], Return[Defer[SubsPosSymb[x, n, y, z]]], While[If[z == 0, k = 1, k = StringLength[x]], b = StringTake[x, {k, k}];

If[! MemberQ[y, b], If[z == 0, a = b a, a = a b], Break[]];

If[z == 0, k––, k++]];

a]] In[1741]:= SubsPosSymb["123456789abcdfght", 5, "g", 1] Out[1741]= "56789abcdf" In[1742]:= SubsPosSymb["123456789abcdfght", 16, "z", 0] Out[1742]= "123456789abcdfgh" Процедура предполагает, что локальные символы пакета располагаются в его секции Private, что является достаточно устоявшимся соглашением. Между тем, процедура в довольно несложной модификации может быть настроена также на пакеты с иными именами локальной секции либо без такой секции вовсе, т.е. определения локальных символов распагаются в пакете произвольно. Оставляем заинтересованному читателю это в качестве весьма полезного упражнения. И еще один момент следует упомянуть, а именно. С целью упрощения реализованного процедурой DefInPackage алгоритма по ходу программирования оказалось целесообразным определить процедуру, вызов которой SubsPosSymb[x, n, y, z] возвращает подстроку строки x, которая ограничена справа (слева) позицией n, и слева (справа) символом из списка y;

при этом, поиск в строке x производится слева направо (z=0) и справа налево (z=1). Вызов же на недопустимых аргументах возвращается невычисленным. Исходный код процедуры SubsPosSymb с типичными примерами ее применения и завершает предыдущий фрагмент. Данная процедура представляет вполне определенный интерес в качестве самостоятельного средства обработки строчных структур, что и характеризуют ее приложения. Данный В.З. Аладьев, Д.С. Гринь механизм является достаточно типичным при разработке программного обеспечения пользователя, когда возникает целесообразность создания собственного программного инструментария, расширяющего стандартные средства Mathematica. Именно таким способом во многом и создавался наш пакет AVZ_Package [90].

В целом ряде случаев возникает необходимость полного удаления из текущего сеанса загруженного в него пакета. Частично данную задачу решают стандартные функции Clear и Remove, однако они не очищают от пакетной информации списки $Packages, $ContextPath и Contexts[]. Данную задачу решает процедура RemovePackage, вызов которой RemovePackage[x] возвращает Null, т.е. ничего, полностью удаляя из сеанса пакет, определяемый контекстом x, включая все экспорты пакета x и соответственно обновив указанные системные списки. Следующий фрагмент представляет исходный код процедуры RemovePackage с наиболее типичными примерами ее применения.

In[1800]:= RemovePackage[x_ /;

ContextQ[x]] := Module[{a = CNames[x], b = ClearAttributes[{$Packages, Contexts}, Protected]}, Quiet[Map[Remove, a]];

$Packages = Select[$Packages, StringFreeQ[#, x] &];

Contexts[] = Select[Contexts[], StringFreeQ[#, x] &];

SetAttributes[{$Packages, Contexts}, Protected];

$ContextPath = Select[$ContextPath, StringFreeQ[#, x] &];

] In[1801]:= $ContextPath Out[1801]= {"AladjevProceduresAndFunctions`", "PacletManager`", "WebServices`", "System`", "Global`"} In[1802]:= $Packages Out[1802]= {"AladjevProceduresAndFunctions`", "ResourceLocator`", "GetFEKernelInit`", "DocumentationSearch`", "JLink`", "PacletManager`", "WebServices`", "System`", "Global`"} In[1803]:= Contexts[] Out[1803]= {"AladjevProceduresAndFunctions`", "AladjevProceduresAndFunctions`Aobj`", "AladjevProceduresAndFunctions`Adrive`", "AladjevProceduresAndFunctions`Args`", …} In[1804]:= RemovePackage["AladjevProceduresAndFunctions`"] In[1805]:= $ContextPath Out[1805]= {"PacletManager`", "WebServices`", "System`", "Global`"} In[1806]:= $Packages Out[1806]= {"ResourceLocator`", "DocumentationSearch`", "GetFEKernelInit`", "JLink`", "PacletManager`", "WebServices`", "System`", "Global`"} In[1807]:= Contexts[] Out[1807]= {"Algebra`", "Algebraics`Private`", "Algebra`Polynomial`", …} In[1808]:= Map[Definition, {ProcQ, Definition1, Definition2, ContextQ, Mapp, Map10}] Out[1808]= {Null, Null, Null, Null, Null, Null} Довольно удобный способ сохранения пакетов представляет функция DumpSave, чей вызов DumpSave[f, x] возвращает контекст x пакета, сохраняемого в бинарном файле f в формате, оптимизированном для его последующей загрузки в Mathematica. Данная Расширение функциональной среды системы Mathematica функция имеет четыре формата кодирования, из которых упомянутый представляет особый интерес для сохранения пакетов. Являясь бинарным, данный файл содержит в заголовочной части следующую текстовую информацию, а именно:

(*This is a Mathematica binary dump file. It can be loaded with Get.*) Windows CONT Контекст` ENDCONT … В текстовом формате представляются и справки (usage) по всем содержащимся в нем средствам. Пакет, сохраненный описанным способом, загружается в текущий сеанс по функции Get[f] с автоматической активацией всех содержащихся в нем определений;

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

в противном случае возвращая вызов невычисленным. Фрагмент представляет исходный код функции DumpSaveP с примерами ее применения.

In[1942]:= PackageQ[x_ /;

ContextQ[x]] := If[CNames[x] != {}, True, False] In[1947]:= DumpSaveP[f_ /;

StringQ[f], x_ /;

PackageQ[x]] := DumpSave[f, x] In[1957]:= DumpSave["AVZ_Package.mx", "AladjevProceduresAndFunctions`"] Out[1957]= {"AladjevProceduresAndFunctions`"} In[1958]:= RemovePackage["AladjevProceduresAndFunctions`"] In[1959]:= Map[Definition, {ProcQ, RemovePackage, Mapp, Map8, Definition2, StrStr}] Out[1959]= {Null, Null, Null, Null, Null, Null} In[1960]:= Get["AVZ_Package.mx"] In[1961]:= Definition2[StrStr] Out[1961]= {StrStr[x_] := If[StringQ[x], StringJoin["\"", x, "\""], ToString[x]], {}} In[1962]:= PackageQ["AvzAgnVsvArtKr`"] Out[1962]= False In[1963]:= DumpSave["AvzAgnVsvArtKr.mx", "AvzAgnVsvArtKr`"] Out[1963]= {"AvzAgnVsvArtKr`"} In[1964]:= DumpSaveP["AvzAgnVsvArtKr.mx", "AvzAgnVsvArtKr`"] Out[1964]= DumpSaveP["AvzAgnVsvArtKr.mx", "AvzAgnVsvArtKr`"] Заголовок функции DumpSaveP в качестве теста на допустимость второго аргумента использует логическую функцию, вызов которой PackageQ[x] возвращает True, если x – пакет, содержащий глобальные символы, и False в противном случае. Естественно, пакет без глобальных символов какого-либо интереса не представляет. В данной связи вызов DumpSaveP[f, x], где x не является пакетом, возвращается невычисленным, что дает возможность программно обрабатывать ситуации данного типа. Ниже приведен простой фрагмент, иллюстрирующий тестирования формально корректных пакетов на предмет идентификации их в качестве пакетов, определяющих глобальные символы, т.е. символы, определяющие объекты, становящиеся глобальными при загрузке пакета:

В.З. Аладьев, Д.С. Гринь In[1853]:= BeginPackage["Kiev`"] Avz::usage = "Help on Avz."

Agn::usage = "Help on Agn."

EndPackage[] Out[1853]= "Kiev`" Out[1854]= "Help on Avz."

Out[1855]= "Help on Agn."

In[1857]:= BeginPackage["Kiev1`"] EndPackage[] Out[1857]= "Kiev1`" In[1859]:= $Packages Out[1859]= {"Kiev1`", "Kiev`", "AladjevProceduresAndFunctions`", "ResourceLocator`", "DocumentationSearch`", "GetFEKernelInit`", "JLink`", "PacletManager`", "WebServices`", "System`", "Global`"} In[1860]:= Map[PackageQ, {"Kiev`", "Kiev1`"}] Out[1860]= {False, False} Результат тестирования контекстов {"Kiev1`", "Kiev`"} в простейшего формата пакетах не ассоциирует их с пакетами. Действительно, в соответствии с соглашениями пакет должен определять глобальные символы, без чего он таковым считаться не может.

Довольно актуальной представляется задача определения контекста, ассоциированного с пакетом, находящимся в бинарном mx-файле. Такую задачу решает процедура, чей вызов PackageMxCont[x] возвращает контекст mx-файла x, тогда как вызов процедуры PackageMxCont[x, y], где 2-й необязательный аргумент y – неопределенная переменная – возвращает список глобальных и определения локальных символов пакета из файла x.

Фрагмент представляет исходный код процедуры с примерами ее применения.

In[2138]:= BeginPackage["Kherson`"] Gs::usage = "Help on Gs."

Ga::usage = "Help on Ga."

Vgs::usage = "Help on Vgs."

Begin["`Private`"] W[x_, y_] := x + y Vt[y_] := y + Sin[y] End[] Begin["`Gs`"] Gs[x_Integer, y_Integer] := x^2 + y^ End[] Begin["`Ga`"] Ga[x_Integer, y_Integer] := x*y + Gs[x, y] End[] Begin["`Vgs`"] Vgs[x_Integer, y_Integer] := x*y End[] EndPackage[];

Расширение функциональной среды системы Mathematica ===================================== In[2157]:= DumpSave["Kherson.mx", "Kherson`"] Out[2157]= {"Kherson`"} In[2158]:= PackageMxCont[x_ /;

FileExistsQ[x] && FileExtension[x] == "mx", y_] := Module[{a = $Packages, b}, Get[x];

b = $Packages[[1]];

If[{y} != {} && ! HowAct[y], {y} = {DefInPackage[b]}];

If[! MemberQ[a, b], RemovePackage[b]];

b] In[2159]:= {PackageMxCont["Kherson.mx", s], s} Out[2159]= {"Kherson`", {{"Vgs", "Gs", "Ga"}, {"W[x_, y_] := x + y", "Vt[y_] := y^2"}}} In[2160]:= CurrentPackageQ[x_ /;


ContextQ[x]] := MemberQ[$Packages, x] In[2161]:= CurrentPackageQ["Kherson`"] Out[2161]= True In[2162]:= RemovePackage["Kherson`"] In[2163]:= {PackageMxCont["Kherson.mx", g], g} Out[2163]= {"Kherson`", {{"Vgs", "Gs", "Ga"}, {"W[x_, y_] := x + y", "Vt[y_] := y^2"}}} In[2164]:= CurrentPackageQ["Kherson`"] Out[2164]= False In[2165]:= PackageMxCont["Kherson.mx"] Out[2165]= "Kherson`" In[2238]:= Packages[] := Select[$Packages, Quiet[PackageQ[#]] &] In[2239]:= Packages[] Out[2239]= {"AladjevProceduresAndFunctions`", "ResourceLocator`", "DocumentationSearch`", "JLink`", "PacletManager`", "WebServices`", "System`", "Global`"} Вызов простой, но полезной функции CurrentPackageQ[w] возвращает True, если w – контекст активного в текущем сеансе Mathematica, и False в противном случае. Итак, несмотря на формальную корректность определения пакетов без экспортируемых ими глобальных символов, что Mathematica подтвержает помещением соответствующих им контекстов в список, определяемый глобальной переменной $Packages, все же имеет смысл определения индикатора фактических пакетов, загруженных в текущий сеанс, что и обеспечивает простая функция, вызов которой Packages[] возвращает список из фактических пакетов, загруженных в текущий сеанс Mathematica. Два предыдущих фрагмента содержат как примеры двух формально корректных пакетов с контекстами {"Kiev`", "Kiev1`"}, так и примеры тестирования данных объектов с иллюстрацией их регистрации в глобальной переменной $Packages, наряду с исходным кодом функции Packages вместе с примерами ее использования для выявления фактических пакетов, активных в текущем сеансе Mathematica. Работа с пакетами несколько более детально обсуждается ниже, там же приводится ряд дополнительных средств, обеспечивающих поддержку более эффективной работы с ними. Все данные средства включены в наш пакет AVZ_Package [90], имеющий FreeWare лицензию. Его использование в создании целого ряда различного типа приложений оказалось достаточно эффективным.

В.З. Аладьев, Д.С. Гринь 3.15. Средства работы с файлами данных в среде Mathematica Средства Mathematica работы с файлами можно условно подразделить на 2 группы:

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

– платформо–независимый файл с пакетом Mathematica на Math–языке file.m – платформо–независимый файл с документом (notebook) Mathematica file.nb – файл с документом, формата пригодного для плэйера Mathematica file.cdf – платформо–зависимый оптимизированный бинарный файл Mathematica file.mx Имеется еще ряд системных файлов и других форматов, здесь не рассматриваемых. С ними можно ознакомиться как в справке по системе, так и в изданиях, например, [100, 116]. В настоящей книге рассматриваются, в основном, средства, ориентированные на обработку файлов именно указанных форматов. По этой причине обработке файлов других форматов специального внимания не уделяется.

Функция Get["Файл"] ( Файл) читает Файл в текущий сеанс с возвратом последнего содержащегося в нем выражения. При этом, если в качестве файла указан контекст, то обеспечивается поиск файла, ассоциированного с данным контекстом. Функция Get может читать файлы форматов {".m", ".nb", ".cdf"}, однако наиболее оптимальным для загрузки является формат ".mx" при условии, что файлы создавались на той же самой операционной платформе посредством функции DumpSave. При этом, поиск файла по умолчанию Get производит в каталогах, определенных переменной $Path. Между тем, Get допускает использование опции Path, обеспечивающей режим поиска файла в указанном списке каталогов {d1, d2, …, dp}, а именно: Get[File, Path – {d1, d2, …, dp}].

На период загрузки файла по Get глобальные переменные $Input и $InputFileName устанавливаются соответственно в имя загружаемого файла и полный путь к данному файлу. Детальнее с функцией Get можно ознакомиться несколько ниже и в [100,116].

Обратной к Get является функция Put (), имеющая три формата кодирования:

Выражение Файл, Put[Выражение, Файл] – пишет выражение в заданный файл;

Put[V1, V2, …, Vp, Файл] – пишет выражения {V1, V2, …, Vp} в заданный файл;

Put[Файл] – создает пустой файл с указанным именем.

Функция PutAppend () допускает те же три формата кодирования, но в отличие от Put она пишет информацию в файл не в режиме полного обновления, а в режиме дополнения (Append). По умолчанию обе эти функции пишут выражения во входном Расширение функциональной среды системы Mathematica формате InputForm, завершая их символом перевода строки. Более того, как функция Get, так и Put, PutAppend после успешной обработки файла оставляют его закрытым.

Тогда как вызов функции FilePrint[f] на монитор выводит тестовое содержимое файла f. Поэтому из файлов упомянутых форматов данной функцией корректно выводятся лишь файлы форматов {".m", ".nb", ".cdf"}, тогда как mx–файл выводится некорректно.

Между тем, для файлов достаточно большого размера форматов {".nb", ".cdf"} вполне возможны проблемы вывода, в ряде случаев требующие перезагрузки пакета. В связи с тем, что средства доступа к файлам даже форматов, автоматически распознаваемых пакетом, при их большей развитости, чем, в частности, Maple не решают целого ряда достаточно важных задач, пользователь вынужден программировать собственные на основе стандартных и, возможно, с использованием своих средств. В качестве одного полезного примера приведем процедуру DefFromPackage, вызов DefFromPackage[x] которой возвращает 2–х элементный список, первый элемент которого – определение в строчном формате символа x, контекст которого отличен от {"Global`", "System`"}, в то время как второй элемент – справка (usage) по нему, тогда как третий определяет атрибуты символа. На символах, ассоциированных с указанными контекстами, вызов процедуры возвращает пустой список. Следующий фрагмент представляет исходный код процедуры DefFromPackage с типичными примерами ее применения.

In[1973]:= DefFromPackage[x_ /;

SymbolQ[x]] := Module[{a = Context[x], b = "", c = "", p, d = ToString[x], k = 1, h}, If[MemberQ[{"Global`", "System`"}, a], Return[{}], h = a d;

ToExpression["Save[" ToString1[d] "," ToString1[h] "]"]];

For[k, k Infinity, k++, c = Read[d, String];

If[c === " ", Break[], b = b c]];

p = StringReplace[RedSymbStr[b, " ", " "], h "`" – ""];

{c, k, b} = {"", 1, ""};

For[k, k Infinity, k++, c = Read[d, String];

If[c === " " || c === EndOfFile, Break[], b = b If[StringTake[c, {–1, –1}] == "\\", StringTake[c, {1, –2}], c]]];

DeleteFile[Close[d]];

{p, StringReplace[b, " /: " d – ""]}] In[1985]:= DefFromPackage[StrStr] Out[1985]= {StrStr[x_] := If[StringQ[x], StringJoin["\"", x, "\""], ToString[x]], StrStr::usage = "The call StrStr[x] returns an expression x in string format if x is different from string;

otherwise, the double string obtained from an expression x is returned."} In[1986]:= DefFromPackage[AvzAgn] Out[1986]= {} In[1987]:= DefFromPackage[Cos] Out[1987]= {} Процедура DefFromPackage предназначена для получения полной информации по символу x, определение которого находится в некотором загруженном в текущий сеанс пакете. В отличие от стандартных функций FilePrint и Definition данная процедура, во-первых, не выводит, а возвращает указанную информацию, полностью доступную для последующей обработки, и, во-вторых, информация возвращается в оптимальном В.З. Аладьев, Д.С. Гринь формате. В частности, в целом ряде случаев при выводе определения символа, которое находится в активном пакете, вывод его стандартными средствами сопровождается и ассоциированным с пакетом контекстом, что не только затрудняет его просмотр, но и последующую обработку. Возврат DefFromPackage устраняет и данную проблему.

Алгоритм, реализуемый данной процедурой, базируется на анализе структуры файла, полученного в результате сохранения контекста "y`x", в котором x – символ в вызове DefFromPackage[x], "y`" – контекст, ассоциированный с загруженным в текущий сеанс пакетом, содержащим определение символа x. Для создания временного файла "x" в текущем каталоге используется функция Save, располагающая четырьмя форматами, из которых для наших целей наиболее приемлем формат Save[файл, "контекст`"], по которому в указанном файле сохраняются определения всех символов, находящихся в заданном контексте. Используя знания о структуре созданного файла и стандартную функцию чтения Read наряду с другими стандартными функциями, включая и нашу процедуру RedSymbStr, рассмотренную в книге, получаем искомый результат. Более детально алгоритм, реализованный процедурой, усматривается из ее исходного кода.

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

In[3835]:= FullCalls[x_ /;

ProcQ[x] || FunctionQ[x]] := Module[{a = {}, b, c = "::usage = ", d, k = 1}, Save[b = ToString[x], x];

For[k, k Infinity, k++, d = Read[b, String];

If[d === EndOfFile, Break[], If[StringFreeQ[d, c], Continue[], a = Append[a, StringSplit[StringTake[d, {1, Flatten[StringPosition[d, c]][[1]] – 1}], " /: "][[1]]]]]];

a = Select[a, SymbolQ[#] &];

DeleteFile[Close[b]];

a = Map[{#, Context[#]} &, DeleteDuplicates[a]];

a = If[Length[a] == 1, a, Map[DeleteDuplicates, Map[Flatten, Gather[a, #1[[2]] === #2[[2]] &]]]];

{d, k} = {{}, 1};

While[k = Length[a], b = Select[a[[k]], ContextQ[#] &];

c = Select[a[[k]], ! ContextQ[#] &];

d = Append[d, Flatten[{b, Sort[c]}]];

k++];

d = MinusList[If[Length[d] == 1, Flatten[d], d], {ToString[x]}];

If[d == {Context[x]}, {}, d]] In[3836]:= FullCalls[StrStr] Out[3836]= {} In[3837]:= G[x_] := StrStr[x] "RansIan70";

FullCalls[G] Out[3837]= {"AladjevProceduresAndFunctions`", "StrStr"} In[3838]:= F[x_Integer, y_Integer] := x^2 + y^2;

FullCalls[F] Out[3838]= {} Расширение функциональной среды системы Mathematica In[3839]:= FullCalls[ProcQ] Out[3839]= {"AladjevProceduresAndFunctions`", "CharacterQ", "DefFunc", "HeadPF", "HowAct", "Sequences", "StrDelEnds", "SubsDel", "SubStr", "SymbolQ", "ToString1", "WhatObj"} In[3840]:= FullCalls[FullCalls] Out[3840]= {"AladjevProceduresAndFunctions`", "CharacterQ", "ContextQ", "Contexts1", "DefFunc", "Definition2", "FunctionQ", "HeadPF", "HowAct", "ListStrToStr", "Mapp", "MinusList", "ProcQ", "PureFuncQ", "QFunction", "Sequences", "StrDelEnds", "SubsDel", "SubStr", "SuffPref", "SymbolQ", "SysFuncQ", "SysFuncQ1", "SystemQ", "ToString1", "WhatObj"} In[3841]:= GS[x_ /;

RuleQ[x], y_String] := ArtKr[StringLength[StringReplace[y, x]], 42] + Vgs[StringLength[y], 70];

FullCalls[GS] Out[3841]= {{"AladjevProceduresAndFunctions`", "RuleQ"}, {"Kherson`", "ArtKr", "Vgs"}} In[3842]:= GS["Avz" – "2012", "AgnAvzVsvArtKr"] Out[3842]= 46. Таким образом, вызов процедуры FullCalls[x] обеспечивает возможность тестирования процедуры либо функции, отличной от стандартной, на предмет использования ею средств, определения которых находятся в пакетах, загруженных в текущий сеанс. В развитие данной процедуры может быть предложена процедура FullCalls1, исходный код которой с примерами применения представлены следующим фрагментом.

In[968]:= FullCalls1[x_ /;

ProcQ[x] || FunctionQ[x]] := Module[{a = {}, b, c = "", d, k = 1, n, p}, Save[b = ToString[x], {x, c}];

For[k, k Infinity, k++, d = Read[b, String];

If[d === EndOfFile, Break[], If[d != " ", c = c d, If[n = Flatten[StringPosition[c, " := "]];

n != {}, If[Quiet[HeadingQ[p = StringTake[c, {1, n[[1]] – 1}]]], a = Append[a, Quiet[HeadName[StringTake[c, {1, n[[1]] – 1}]]]]]];

c = ""]]];

DeleteFile[Close[b]];

{b = FullCalls[x], Select[MinusList[a, {ToString[x]}], ! MemberQ[Flatten[b], #] &]}] In[969]:= ArtKr[x_Integer, y_Integer] := Module[{}, N[Sqrt[x^2 + y^2]]];

Vgs[x_Integer, y_Integer] := N[Sin[x] + Cos[y]];

GS[x_ /;

RuleQ[x], y_String] := ArtKr[StringLength[StringReplace[y, x]], 42] + Vgs[StringLength[y], 70];

In[970]:= FullCalls1[GS] Out[970]= {{"AladjevProceduresAndFunctions`", "RuleQ"}, {"ArtKr", "Vgs"}} In[971]:= FullCalls1[StrStr] Out[971]= {{}, {}} In[972]:= FullCalls1[ProcQ] Out[972]= {{"AladjevProceduresAndFunctions`", "CharacterQ", "DefFunc", "HeadPF", "HowAct", "Sequences", "StrDelEnds", "SubsDel", "SubStr", "SymbolQ", "ToString1", "WhatObj"}, {}} В.З. Аладьев, Д.С. Гринь Процедура FullCalls1 тестирует процедуру/функцию x на предмет использования ею как пакетных, так и иных средств, отличных от стандартных. Так, вызов FullCalls1[x] возвращает вложенный список, первый элемент которой соответствует FullCalls[x], в то время как второй определяет список имен средств, используемых x, исключая, при этом, средства, принадлежащие загруженным пользовательским пакетам. Между тем, следует иметь ввиду, что обе процедуры обрабатывают лишь средства, используемые x, которые определены механизмом отложенных вычислений. Распространение этих процедур на механизм немедленных вычислений каких-либо особых затруднений не вызывает, и такое расширение может представить достаточно полезное упражнение заинтересованному читателю. Мы же исходили из того, что определения процедур и функций по целому ряду довольно существенных причин целесообразнее определять именно механизмом отложенных вычислений. Обе процедуры FullCalls и FullCalls оказываются довольно полезными при программировании целого ряда приложений.

Использованная в реализации процедур FullCalls и FullCalls1 функция Save может оказаться довольно полезной для организации библиотек пользовательских средств.

Действительно, вызов Save[f, {a, b, c, …}] сохраняет в файле f текстового формата все определения не только объектов с именами {a, b, c, …}, но и все определения средств, с которыми связаны указанные объекты на всех уровнях их структурных деревьев. В то же самое время, вызов функции производит запись в файл в режиме дописывания (Append), оставляя файл закрытым. Созданный файл легко редактируется текстовыми редакторами, позволяя относительно несложно создавать программные средства его редактирования (удаление объектов, добавление объектов, замену объектов и др. функции).

Для загрузки такой библиотеки в текущий сеанс достаточно вызова Get[f], обеспечив доступ ко всем средствам, определения которых были сохранены в файле f. Фрагмент представляет примеры ряда операций с функциями Save и Get, которые определяют основу библиотечной организации программных средств пользователя. Ниже данный вопрос рассматривается несколько детальнее с иллюстрацией примера библиотеки.

In[1857]:= ArtKr[x_Integer, y_Integer] := Module[{}, N[Sqrt[x^2 + y^2]]];

Vgs[x_Integer, y_Integer] := N[Sin[x] + Cos[y]];

GS[x_ /;

RuleQ[x], y_String] := ArtKr[StringLength[StringReplace[y, x]], 42] +Vgs[StringLength[y], 70];

In[1858]:= Rans[x_, y_] := Module[{}, x + y];

Save["Library.txt", {GS, Rans}] In[1859]:= {GS["Agn" – "2012", "AvzAgnVsvArtKr"], Rans[42, 70]} Out[1859]= {46.2221, 112} In[1860]:= Remove[GS, Rans] In[1861]:= {GS["Agn" – "2012", "AvzAgnVsvArtKr"], Rans[42, 70]} Out[1861]= {GS["Agn" – "2012", "AvzAgnVsvArtKr"], Rans[42, 70]} In[1862]:= Get["Library.txt"] In[1863]:= {GS["Agn" – "2012", "AvzAgnVsvArtKr"], Rans[42, 70]} Out[1863]= {46.2221, 112} На этом краткое рассмотрение средств доступа к файлам в среде пакета Mathematica завершается и будет продолжено на более детальном уровне в десятой главе книги.

Расширение функциональной среды системы Mathematica Глава 4. Базовые управляющие структуры пакета Mathematica Для описания произвольного вычислительного алгоритма структур, базирующихся на сугубо последовательностных операциях, совершенно недостаточно без средств по управлению собственно вычислительным процессом. Настоящая глава служит задаче рассмотрения управляющих структур встроенного языка пакета Mathematica.

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

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

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

Следование отражает принцип последовательного выполнения предложений той или иной программы, пока не встретится предложение, изменяющее последовательность.

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

Ветвление характеризует собой выбор одного из всех возможных путей последующих вычислений;

типичными предложениями, обеспечивающими данную управляющую структуру, являются предложения формата «IF A THEN B ELSE C». Структура «цикл»

реализует повторное выполнение группы предложений до тех пор, пока выполняется некоторое логическое условие;

типичными предложениями, обеспечивающими такую управляющую структуру, являются предложения DO, DO_WHILE, DO_UNTIL. Итак, базисные структуры определяют соответственно последовательную (следование), условную (ветвление) и итеративную (цикл) передачи управления в программах [1-3]. Показано, что корректная структурированная программа теоретически любой сложности может быть написана с использованием только управляющих структур следования, WHILE– циклов и IF–операторов ветвления. Однако расширение набора указанных средств, в первую очередь, за счет обеспечения вызовов функций и механизма процедур может весьма существенно облегчить программирование, не нарушая структурированности программ и повышая уровень их модульности и робастности (надежности).



Pages:     | 1 |   ...   | 3 | 4 || 6 | 7 |   ...   | 20 |
 





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

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