Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

KDP_book

.pdf
Скачиваний:
19
Добавлен:
03.01.2021
Размер:
2.46 Mб
Скачать

Mathematica: Functional and procedural programming

In the context of testing blocks for procedural nature in the above sense, the LocVars1 procedure may be of interest whose call LocVars1[x] returns True if x is a module or a block x has no local variables without initial values, or the list of local variables is empty, otherwise False is returned. While calling LocVars1[x,y] with the 2nd optional argument y – an undefined symbol through y additionally returns the 2-element list whose the first element defines the list of all local variables of x, while the 2nd element defines the list of local variables without initial values. Below, fragment represents source code of the procedure with its use.

In[4]:= LocVars1[x_ /; BlockModQ[x], y___] := Module[{a, b, d = {}}, a = Locals5[x, b]; Do[AppendTo[d, If[Length[b[[k]]] < 2, a[[k]], Nothing]],

{k, Length[a]}]; If[{y} != {} && SymbolQ[y], y = {a, d}, 7];

If[ModuleQ[x], True, If[a == d, True, False]]]

In[5]:= B[x_] := Block[{a = 7, b, c = 8, d}, x*a*b*c*d]; B1[x_] := Block[{a, b, c, d}, x*a*b*c*d]

In[6]:= {LocVars1[B, t1], t1}

Out[6]= {False, {{"a = 7", "b", "c = 8", "d"}, {"b", "d"}}}

In[7]:= {LocVars1[B1, t2], t2}

Out[7]= {True, {{"a", "b", "c", "d"}, {"a", "b", "c", "d"}}}

In[8]:= G[x_] := Block[{}, x^2]; {LocVars1[G, t72], t72} Out[8]= {True, {{}, {}}}

Considering importance of modular approach to software organization when a program code consists of set of the linked independent objects and reaction of objects is defined only by their inputs, in this quality to us the most preferable the modules are presented. In general software code of the modular structure, the output of the module is the input for another module. For this reason the lion share of tools of our package MathToolBox [16] is programmed in the form of modules.

Once again, pertinently to pay attention to one moment. A number of tools represented in the package are focused on the solution of identical problems, but they use various algorithms programmed with usage of various approaches. They not only illustrate variety of useful enough receptions but also revealing their shortcomings and advantages useful both in practical and

31

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov

system programming. In our opinion, such approach opens a rather wide field for awakening of creative activity of the reader in respect of improvement of his skills in the programming in Mathematica system. Now let's consider module components in more detail.

Let's note that in certain cases duplication of definitions of blocks, modules and functions under new names on condition of saving their former definitions invariable is required. So, for assignment of a name that is unique in the current session to the new means, the procedure whose call DupDef[x] returns a name (unique in the current session) whose definition will be equivalent to definition of the x symbol can be used. In addition, the given procedure successfully works with the means having multiple definitions too. The following fragment represents source code of the procedure with an example of its application.

In[3331]:= DupDef[x_ /; BlockFuncModQ[x]] :=

Module[{a = Flatten[{Definition1[x]}], b = Unique[ToString[x]]},

ToExpression[Map[StringReplace[#, ToString[x] <> "[" > ToString[b] <> "[", 1] &, a]]; b]

In[3332]:= Gs[x_, y_] := x + y

In[3333]:= Gs[x_] := Module[{a = 77}, a*x^2]

In[3334]:= DupDef[Gs]

Out[3334]= Gs78

In[3335]:= Definition[Gs78]

Out[3335]= Gs78[x_, y_] := x + y

Gs78[x_] := Module[{a = 77}, a*x^2]

In particular, the DupDef procedure is useful enough when debugging of the user software.

The call Definition[x] of the standard function in a number of cases returns the definition of some x object with the context corresponding to it what at a rather large definitions becomes badly foreseeable and less acceptable for subsequent program processing as evidently illustrates a number of examples [6-15]. Moreover, the name of an object or its string format also can act as an actual argument. For elimination of this shortcoming we

32

Mathematica: Functional and procedural programming

defined a number of tools allowing to obtain definitions of the procedures or functions in a certain optimized format. As such means it is possible to note the following: DefOptimum, DefFunc,

Definition1, Definition2, Definition3÷Definition5, DefFunc1, DefOpt, DefFunc2 and DefFunc3. These means along with some others are represented in [4-9] and included in the MathToolBox package [16]. The following fragment represents the source code of the most used tool of them with an example of its application.

In[49]:= Definition2[x_ /; SameQ[SymbolQ[x], HowAct[x]]] := Module[{a, b = Attributes[x], c},

If[SystemQ[x], Return[{"System", Attributes[x]}],

Off[Part::partw]]; ClearAttributes[x, b]; Quiet[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[50]:= a[x_] := x + 6; a[x_, y_] := Module[{}, x/y]; a[t_Integer] := 7 In[51]:= SetAttributes[a, {Protected, Listable}]; Definition2[a]

Out[51]= {"a[t_Integer] := 7", "a[x_] := x + 6",

"a[x_, y_] := Module[{}, x/y]", {Listable, Protected}}

The Definition2 call on system functions returns the nested list, whose first element – "System", while the second element – the list of attributes ascribed to a factual argument. On the user function or procedure x the call Definition2[x] also returns the nested list, whose first element the optimized definitions of x

(in the sense of absence of contexts in them, at a series definitions in a case of multiplicity of x definition), whereas the second element the list of attributes ascribed to x; in their absence the empty list acts as the second element of the returned list. In a case of False

33

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov

value on a test ascribed to a formal x argument, the procedure call Definition2[x] will be returned unevaluated. Analogously to the above procedures, the procedure Definition2 processes the main both the erroneous and especial situations.

Using the Definition2 procedure and the list representation, we give an example of a simple enough Info procedure whose call Info[x] in a convenient form returns the complete definition of a symbol x, including its usage. While the call Info[x, y] with the second optional y argument an indefinite symbol through it additionally returns the usage for x symbol in string format. The following fragment represents the source code of the Info procedure with examples of its typical application.

In[3221]:= Info[x_ /; SymbolQ[x], y___] :=

If[! HowAct[x], $Failed, {If[StringQ[x::usage], Print[If[{y} != {} && ! HowAct[y], y = x::usage, x::usage]],

Print["Usage on " <> ToString[x] <> " is absent"]], ToExpression[Definition2[x][[1 ;; –2]]]; Definition[x]}[[–1]]]

In[3222]:= Info[StrStr]

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.

Out[3222]= StrStr[x_] := If[StringQ[x], "\"" <> x <> "\"", ToString[x]]

In[3223]:= x[x_] := x; x[x_, y_] := x*y; x[x_, y_, z_] := x*y*z In[3224]:= Info[x]

Usage on x is absent Out[3224]= x[x_] := x

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

In[3225]:= Info[StrStr, g47]

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.

Out[3225]= StrStr[x_] := If[StringQ[x], "\"" <> x <> "\"", ToString[x]]

In[3226]:= g47

Out[3226]= "The call StrStr[x] returns an expression x in string format if x is different from the string; otherwise, the double string obtained from an expression x is returned."

34

Mathematica: Functional and procedural programming

In[3227]:= Info[agn]

Out[3227]= $Failed

If the first x argument – an indefined symbol, the procedure call Info[x] returns $Failed.

Another moment should be mentioned. In some cases, the above procedural objects can be represented in functional form based on the list structures of the format:

F[x_, …, z_] := {Save[w, a, b, c, …]; Clear[a, b, c, …]; Procedure body, Get[w]; DeleteFile[w]}[[–2]]

The Save function saves all values of local and global procedure variables in a certain w file, then clears all these variables, and then executes the procedure body. Finally, Get function loads the w file into the current session, restoring {a, b, c,...} variables, and then deletes the w file. The result of the function call of the type described is the second list element, beginning with its end in a case if the procedure returns the result of the call through the last sentence of its body, which is a fairly frequent case. We can use {;|,} as the list element separators, depending on need. Thus, on the basis of the above design it is possible to program functional equivalents of quite complex procedures. An example is the functional equivalent of the SubsDel procedure described in section 3.4.

In[77]:= SubsDel[S_ /; StringQ[S], x_ /; StringQ[x], y_ /; ListQ[y] &&

AllTrue[Map[StringQ, y], TrueQ] && Plus[Sequences[Map[StringLength, y]]] == Length[y], p_ /; MemberQ[{–1, 1}, p]] := {Save["#$#", {"b", "c", "d", "h", "k"}]; Clear[b, c, d, h, k]; {b, c = x, d, h = StringLength[S], k};

If[StringFreeQ[S, x], Return[S], b = StringPosition[S, x][[1]]]; For[k = If[p == 1, b[[2]] + 1, b[[1]] – 1], If[p == 1, k <= h, k >= 1], If[p == 1, k++, k––], d = StringTake[S, {k, k}];

If[MemberQ[y, d] || If[p == 1, k == 1, k == h], Break[], If[p == 1, c = c <> d, c = d <> c]; Continue[]]]; StringReplace[S, c –> ""], Get["#$#"]; DeleteFile["#$#"]}[[–2]]

In[78]:= SubsDel["12345avz6789", "avz", {"8", "5"}, 1]

Out[78]= "1234589"

A comparative analysis of both implementations confirms aforesaid.

35

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov

It is well known [8-12,16], that the user package uploaded into the current session can contains tools x whose definitions obtained by means of the call Definition[x] aren't completely optimized, i.e. contain constructions of the kind j <> "x`" where j – a context from the system list $Packages. We have created a number of tools [16] that solve various problems of processing unoptimized definitions of both individual means and means in the user packages located in files of {"m", "mx"} formats. So, the call DefFunc1[x] provides return of the optimized definition of an object x whose definition is located in the user package or nb–document and that has been loaded into the current session. At that, a name x should define an object without any attributes and options or with attributes and/or options. Fragment below represents source code of the DefFunc1 procedure along with an example of its application.

In[7]:= Definition[ListListQ]

Out[7]= ListListQ[Global`ListListQ`L_] := If[ListQ[Global`ListListQ`L] && Global`ListListQ`L != {} && Length[Global`ListListQ`L] >= 1 && Length[Select[Global`ListListQ`L, ListQ[#1] && Length[#1] == Length[Global`ListListQ`L[[1]]] &]] == Length[Global`ListListQ`L], True, False]

In[8]:= DefFunc1[x_ /; SymbolQ[x] || StringQ[x]] := Module[{a = GenRules[Map14[StringJoin, {"Global`",

Context[x]}, ToString[x] <> "`"], ""], b = Definition2[x][[1]]},

ToExpression[Map[StringReplace[#, a] &, b]]; Definition[x]] In[9]:= DefFunc1[ListListQ]

Out[9]= ListListQ[L_] := If[ListQ[L] && L != {} && Length[L] >= 1 && Length[Select[L, ListQ[#1] &&

Length[#1] == Length[L[[1]]] &]] == Length[L], True, False]

So, the procedure call DefFunc1[x] in an optimized format returns the definition of an object x contained in a package or a notebook loaded into the current session. The object name is set in string format or symbol format depending on the object type

(procedure, function, global variable, procedure variable, etc.). Thus, in the 2nd case the definition is essentially more readably, above all, for rather large source codes of procedures, functions, along

36

Mathematica: Functional and procedural programming

with other objects. The TypesTools procedure is rather useful.

Calling TypesTools[x] procedure returns the three-element list whose elements are sub-lists containing names in the string format of tools with context x in the terms of the objects such as

Functions, Procedures, and Others, accordingly. During the procedure run, lists of the form {n, "Name"} are intermediately output, where n is the number of the tool being tested from the tools list with context x, and Name is the name of the tool being tested. The following fragment represents the source code of the TypesTools procedure, followed by its application.

In[3325]:= TypesTools[x_ /; ContextQ[x]] := Module[{a = {},

b = {}, c = {}, d = CNames[x], t, j}, Monitor[j = 1;

While[j <= Length[d], Pause[0.1]; t = d[[j]]; If[QFunction[t], AppendTo[a, t], If[ProcQ[t], AppendTo[b, t], AppendTo[c, t]]]; j++], {j, t}]; {a, b, c}]

In[3326]:= TypesTools["AladjevProcedures`"]

{1, "AcNb"}

==============

{1416, "$Version2"}

Out[3326]:= {{"AcNb", "ActBFM", …, "XOR1"}, {"ActCsProcFunc", …, "$SysContextsInM1"}, {"AddDelPosString", "Args", …, "$Version2"}}

Calling ContextMonitor[x] procedure during its execution outputs the lists of the form {n, N, Tp, PI} where n is the number of the tool being tested from the tools list with context x, N – is the name of the tool being tested, Tp – its type {Function, Block, Module, Other} and PI a progress indicator; returning nothing. The source code of the procedure is represented below.

ContextMonitor[x_/; ContextQ[x]] := Module[{c, d = CNames[x], t, j}, Monitor[c = 0; Map[{t = #, c++, j = TypeBFM[#], Pause[0.5]} &, d], {c, t, If[! MemberQ[{"Block", "Function", "Module"}, j], "Other", j], ProgressIndicator[c, {1, Length[d]}]}];]

TypesTools & ContextMonitor procedures use the Monitor function whose call Monitor[x,y] generates a temporary monitor place in which the continually updated current y value will be displayed during the course of evaluation of x. Such approach may be a rather useful in many rather important applications.

37

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov

2.2. Headings of procedures in Mathematica software

Procedures in Mathematica system are formally presented by Modules and Blocks whose program structure begins with a Heading, i.e. heading the header part of a procedure definition, preceded to the sign {:= | =} of the delayed, as a rule, or instant assignment. The components of the heading are the procedure name and its formal arguments with patterns "_", possibly also with testing functions assigned to them.

It is necessary to highlight that in Mathematica system as correct procedural objects {Block, Module} only those objects are considered which contain the patterns of the formal arguments located in a certain order, namely:

1.The coherent group of formal arguments with patterns "_" has to be located at the very beginning of the tuple of formal arguments in headings of the above procedural objects;

2.Formal arguments with patterns "__" or "___" can to finish the tuple of formal arguments; at that, couples of adjacent arguments

with patterns consisting from {"__", "___"} are inadmissible because of possible violation of correctness (in context of scheduled computing algorithm) of calls of the above procedural objects as a simple enough fragment illustrates:

In[1221]:= A[x_, y__, z__] := x*y^2*z^3

In[1222]:= {A[x, y, z], A[x, y, h, z], A[x, y, h, x, a, b]} Out[1222]= {x*y^2*z^3, h^z^3*x*y^2, h^x^a^b^3*x*y^2} In[1223]:= G[x_, y__, z___] := x + y + z

In[1224]:= {G[x, y, z], G[x, y, m, n, z], G[x, y, z, h]} Out[1224]= {x + y + z, m + n + x + y + z, h + x + y + z}

Other rather simple examples illustrate told. Thus, the real correctness of tuple of formal arguments can be coordinated to their arrangement in the tuple in context of patterns {“_”, “__”, “___”}. At the same time, for all patterns for formal arguments the testing Testx function of a rather complex kind can be used as the following evident fragment illustrates:

In[1567]:= Sg[x_ /; StringQ[x], y__ /; If[Length[{y}] == 1,

38

Mathematica: Functional and procedural programming

IntegerQ[y], MemberQ3[{Integer, List, String}, Map[Head, {y}]]]] := {x, y}

In[1568]:= Sg["agn", 72, 77, "sv", {a, b}]

Out[1568]= {"agn", 72, 77, "sv", {a, b}}

In[1569]:= Sg1[x_ /; StringQ[x], y___ /; If[{y} == {}, True,

If[Length[{y}] == 1, IntegerQ[y], MemberQ3[{List, String, Integer}, Map[Head, {y}]]]]] := {x, y}

In[1570]:= Sg1["agn", 72, 77, "sv", {a, b}, a + b]

Out[1570]= Sg1["agn", 72, 77, "sv", {a, b}, a + b]

Furthermore, a procedure and function headings in testing functions are allowed to use procedure and function definitions (using the list structure) that are activated in the current session at the time the objects containing them are called, for example:

In[1620]:= M1[x_ /; {SetDelayed[h[a_], Module[{}, 42*a]], h[x] < 2020}[[2]], y_] := Module[{a=5, b=7}, a*x^2 + b*y^2] In[1621]:= M1[42, 47]

Out[1621]= 24283 In[1622]:= Definition[h]

Out[1622]= h[a_] := Module[{}, 42*a]

Right there once again it should be noted one an essential moment. Definition of the testing Testx function can be directly included to the procedure or function heading, becoming active in the current session by the first procedure or function call:

In[2]:= P[x_, y_ /; {IntOddQ[t_] := IntegerQ[t] && OddQ[t], IntOddQ[y]}[[1]]] := x*y

In[3]:= P[72, 77]

Out[3]= 5544

In[4]:= Definition[IntOddQ]

Out[4]= IntOddQ[t_] := IntegerQ[t] && OddQ[t]

In[5]:= t = 77; Save["#", t]

In[6]:= P[x_ /; Module[{}, If[x^2 < Read["#"], Close["#"];

True, Close["#"]; False]], y_] := x*y

In[7]:= P[8, 7]

Out[7]= 56

39

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov

Generally speaking, Mathematica's syntax and semantics, when defining procedures (modules and blocks), allow the use of procedure definitions in both the definition of test functions for formal arguments and the definitions of local variables, as the following fairly simple fragment illustrates quite clearly, while for classical functions similar assumptions are only possible for test functions, of course.

In[9]:= Avz[x_ /; If[SetDelayed[g[t_], Module[{a = 42}, t^2 + a]]; g[x] < 777, True, False]] := Module[{a = SetDelayed[v[t_], Module[{b = 47, c = 67}, b*t^3 + c]]}, a = 77; a*v[x]]

In[10]:= Avz[7]

Out[10]= 1246476

In[11]:= Avz[100]

Out[11]= Avz[100] In[12]:= Definition[g]

Out[12]= g[t_] := Module[{a = 42}, t^2 + a] In[13]:= Definition[v]

Out[13]= v[t_] := Module[{b = 47, c = 67}, b*t^3 + c] In[14]:= Context[g]

Out[14]= "AladjevProcedures`"

In[15]:= Context[v]

Out[15]= "Global`"

In[16]:= $Context

Out[16]= "Global`"

In[17]:= Contexts[]

Out[17]= {"AladjevProcedures`", "AladjevProcedures`BitGet1`", "AladjevProcedures`CharacterQ`", }

In[18]:= Length[%]

Out[18]= 1611

The procedures whose definitions are contained in the test functions or in the local variables domain are activated in the current session when the procedure contains them is called. In addition, the symbol v defined in the local area has the current context, while the symbol g defined in the test function obtains the context being the first in the list Contexts[] of all contexts of the current session. The feasibility of using the above approach to defining procedures is discussed in some detail in [8,11,15].

40

Соседние файлы в предмете Математические пакеты