
KDP_book
.pdf
Mathematica: Functional and procedural programming
that the concept of file qualifier (FQ) defining the full path to the required file in file system of the computer or to its subdirectory, practically, completely coincides with similar concept for Maple system excepting that if in the Maple for FQ the format of type {symbol, string} is allowed whereas in the Mathematica for FQ the string format is admissible only.
The function call Directory[] returns an active directory of the current session whereas the call SetDirectory[x] returns a x directory, doing it active in the current session; in addition, as an active (current) directory is understood the directory whose datafiles are processed by means of tools of access if only their names, but not full paths to them are specified. Meanwhile, the SetDirectory function allows only real–life subdirectories as an argument, causing on nonexistent subdirectories an erroneous situation with returning $Failed. On the other hand, the SetDir2 procedure allows to sets the current working directory; at that, as an argument can be also nonexistent subdirectories even on inactive I/O devices as the current subdirectories. The fragment represents source code of the procedure SetDir2 and its use.
In[25]:= SetDir2[x_ /; StringQ[x]] := Module[{a, b, c, t, y}, a = Map[# <> ":" &, Adrive[]];
b = Map[ToUpperCase, StringCases[x, t_ ~~ ":"]]; If[FreeQ[a, b], y = StringReplace[x, b –> a[[1]], 1], y = x]; If[Set[c, Quiet[CreateDirectory[y]]] === $Failed, y, SetDirectory[c]]]
In[26]:= SetDirectory["F:\\Temp\\Grodno\\78"]
…SetDirectory: Cannot set current directory to F:\\Temp\\Grodno\\78.
Out[26]= $Failed
In[27]:= SetDir2["F:\\Temp\\Grodno\\78"]
Out[27]= "C:\\Temp\\Grodno\\78"
In[28]:= Adrive[] := Module[{a, b, c, d}, {b, a} = {{}, CharacterRange["A", "Z"]}; Do[d = Directory[]; c = a[[k]];
AppendTo[b, If[Quiet[SetDirectory[c <> ":\\"]] === $Failed, Nothing, SetDirectory[d]; c]], {k, 1, Length[a]}]; Sort[b]]
301

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov
In[29]:= Adrive[]
Out[29]= {"C", "D", "E", "F", "G"}
The SetDir2 procedure essentially uses a procedure whose call Adrive[] returns the list of the current active I/O devices of the computer. MathToolBox package [16] provides a number of means along with their certain modifications (SetDir, SetDir1, Adrive1, CopyDir, CopyFileToDir, etc.) that use different useful programming techniques in Mathematica and extending the built–in file access tools useful from a practical standpoint. At the same time, it should be borne in mind that for the reason that the MathToolBox package was developed (truth, with rather large intervals) from 2013 to November 2020, different versions of the Mathematica system were used, so in number of cases is necessary to re–debugging some package tools under the current version of the system. As a rule, this is not particularly difficult.
We programmed a number of rather interesting procedures for ensuring work with files of the Mathematica Input–format whose names have extensions {".nb", ".m", ".txt"}, etc. All such tools are based on analysis of structure of the contents of files returned by access functions, in particular, ReadFullFile. Some of them give a possibility to create rather effective user libraries containing definitions of the Mathematica objects. These and certain other tools have been implemented as a part of a special package supporting the releases 8 ÷ 12.1.1 of Mathematica [16].
Some remarks should be made concerning the system Save function which saves the objects in a file in the Append mode; in addition, indefinite symbols in this file are not saved without of any messages, i.e. the Save call returns Null, i.e. nothing. At the same time, at saving of procedure or function with a name Avz in a file by means of the Save in the file all active objects of the same Avz name in the current session with different headings – the identifiers of their originality – are saved too. For elimination of this situation a generalization of the Save function concerning the saving of Mathematica objects with concrete headings is offered. The Save1 procedure solves the problem whose source code with typical examples of its application are represented by
302

Mathematica: Functional and procedural programming
means of the following fragment.
In[1326]:= Save1[x_String, y_ /; DeleteDuplicates[Map[StringQ, Flatten[{y}]]][[1]]] := Module[{Rs, t = Flatten[{y}], k = 1}, Rs[n_, m_] := Module[{b, c = ToString[Unique[b]], a = If[SymbolQ[m], Save[n, m], If[StringFreeQ[m, "["], $Failed,
StringTake[m, {1, Flatten[StringPosition[m, "["]][[1]] – 1}]]]},
If[a === Null, Return[], If[a === $Failed, Return[$Failed], If[SymbolQ[a], b = DefFunc3[a], Return[$Failed]]]]; If[Length[b] == 1, Save[n, a], b = Select[b, SuffPref[#, m, 1] &]]; If[b != {}, b = c <> b[[1]], Return[$Failed]]; ToExpression[b]; a = c <> a; ToExpression["Save[" <> ToString1[n] <> "," <> ToString1[a] <> "]"]; BinaryWrite[n, StringReplace[ ToString[StringJoin[Map[FromCharacterCode, BinaryReadList[n]]]], c –> ""]]; Close[n];]; For[k, k <= Length[t], k++, Rs[x, t[[k]]]]]
In[1327]:= A[x_] := x^2; A[x_, y_] := x+y; A[x_, y_, z_] := x+y+z; A[x__] := {x}; DefFunc3[A]
Out[1327]= {"A[x_] := x^2", "A[x_, y_] := x + y", "A[x_, y_, z_] := x + y + z", "A[x__] := {x}"}
In[1328]:= Save1["rans.m", {"A[x_, y_, z_]", "A[x__]"}] In[1329]:= Clear[A]; << "rans.m"
In[1330]:= DefFunc3[A]
Out[1330]= {"A[x_, y_, z_] := x + y + z", "A[x__] := {x}"}
The call Save1[x, y] saves in a file x the definitions of the objects defined by the second factual y argument – the name of an active object in the current session or its heading in string format, or their combinations in the list format. The Save1 procedure can be used as built-in Save function, and solving a saving problem of the chosen objects activated in the current session in the file differentially on the basis of their headings. A successful call returns Null, doing the demanded savings; otherwise, $Failed or unevaluated call are returned. The previous fragment presents the result of application of the Save1 procedure for a selective saving of the objects activated in the current session in file. In a number of cases the procedure Save1 has undoubted interest.
The function call Save2[x, y], where Save2 – a modification of the Save function, appends to a file x the definitions of the
303

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov
means set by a name or by their list y in the format convenient for subsequent processing by a number of means, particularly, by the CallSave procedure. Thus, the function is a rather useful extension of the built–in Save function [7,11-16].
In a number of cases there is an urgent need of saving in a file of state of the current session with subsequent restoration by means of loading of the file to the current session different from the previous session. In this context, SaveCurrentSession and RestoreCS procedures are useful for saving and restoration of state of the current session respectively. Thus, the procedure call SaveCurrentSession[] saves the state of the Mathematica current session in the m–file "SaveCS.m" with returning of the name of the target file. Whereas the call SaveCurrentSession[x] saves the state of the Mathematica current session in a m–file x with returning of the name of the target x file; in addition, if a x file has not "m" extension then the extension is added to the x string. The call RestoreCS[] restores the Mathematica current session that has been previously stored by means of procedure
SaveCurrentSession in "SaveCS.m" file with returning Null, i.e. nothing. While the call RestoreCS[x] restores the Mathematica current session that has been previously stored by means of the procedure SaveCurrentSession in a m-file x with returning Null. In absence of the above m-file the procedure call returns $Failed. The fragment represents source codes of the above procedures along with some typical examples of their application.
In[47]:= SaveCurrentSession[x___String] :=
Module[{a = Names["*"], b = If[{x} == {}, "SaveCS.m", If[SuffPref[x, ".m", 2], x, x <> ".m"]]}, Save1[b, a]; b]
In[48]:= RestoreCS[x___String] := Module[{a = If[{x} == {},
"SaveCS.m", If[FileExistsQ[x] && FileExtension[x] == "m", x, $Failed]]}, If[a === $Failed, $Failed, On[General];
Quiet[Get[a]]; Off[General]]]
In[49]:= SaveCurrentSession["C:\\temp\\SaveCS.m"]
Out[49]= "C:\\Temp\\SaveCS.m"
In[50]:= RestoreCS["C:\\Temp\\SaveCS.m"]
304

Mathematica: Functional and procedural programming
So, the represented means are rather useful in a case when is required to create copies of the current Mathematica sessions at certain moments of operating with the system.
4.2. Tools of the Mathematica for work with external files
According to such a quite important indicator as means of access to files, the Mathematica, in our opinion, possesses a number of advantages in comparison with Maple. First of all, Mathematica does automatic processing of hundreds of data formats and their sub-formats on the basis of the unified use of symbolic expressions. For each specific format the correspondence between internal and external presentation of a format is defined using the general mechanism of data elements of Mathematica. For today Mathematica supports many various formats of files for various purposes, their list can be received by means of the variables $ImportFormats (the imported files) and $ExportFormats (the exported files) in quantities 226 and 188 respectively (version
Mathematica 12.1), while the basic formats of files for versions 8–12.1.1 are considered rather in details in [1-15].
By the function call FileFormat[x] an attempt to define an input format for a file given by a name x in the string format is made. In a case of existence for the file x of name extension the FileFormat function is, as a whole, similar to the FileExtension function, returning the available extension, except for a case of packages (m–datafiles) when instead of extension the file type "Package" is returned. In addition, in certain cases the format identification is done incorrectly, in particular, the attempt to test a doc–file without an extension returns "XLS", ascribing it to the files created by means of Excel 95/97/2000/XP/2003 that is generally incorrect. The FileFormat function also incorrectly tests I/O device base directories, for example:
In[3331]:= Map[FileFormat, {"C:/", "C:\\"}]
…General: Further output of General::cdir will be suppressed during this calculation.
…General: Cannot get deeper in directory tree:
C:\\Documents and Settings.
305

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov
…General: Cannot get deeper in directory tree: C:\\ProgramData\\Application Data.
…General: Cannot get deeper in directory tree: C:\\ProgramData\\Desktop.
…General: Further output of General::dirdep will be suppressed during this calculation.
Out[3331]= {"KML", "KML"}
In[3332]:= FileFormat["C:/Temp\\Burthday"]
Out[3332]= "XLS"
In this regard, the procedures FileFormat1 ÷ FileFormat3 have been programmed that extend the capabilities of the builtin FileFormat function and eliminate the above disadvantages. A version of the FileFormat function attempts to identify file type without its extension, being based on information of the creator of file that is contained in the contents of the file. The FileFormat3 procedure rather accurately identifies data files of the following often used types {DOC, DOCX, PDF, ODT, TXT, HTML}. In addition, concerning the TXT type the verification of a datafile is made in the latter case, believing that the datafile of this type has to consist only of symbols with the decimal codes:
0 ÷ 127 – ASCII symbols
1 ÷ 31 – the control ASCII symbols
32 ÷ 126 – the printed ASCII symbols
97 ÷ 122 – letters of the Latin alphabet in the lower register 129 ÷ 255 – Latin–1 symbols of ISO
192 ÷ 255 – letters of the European languages
The procedure call FileFormat3[x] returns the type of a file given by a name or a classifier x; in addition, if the data file has an extension, it relies as the extension of the data file. Whereas the call FileFormat3[x, y] with the second optional argument – an arbitrary y expression – in a case of file without extension returns its full name with extension defined for it, at the same time renaming the x data file, taking into account the calculated format. The following fragment represents source code of the FileFormat3 procedure and the most typical examples of its use.
In[3332]:= FileFormat3[x_ /; FileExistsQ[x], t___] := Module[{b, c, a = FileExtension[x]}, If[a != "", ToUpperCase[a],
306

Mathematica: Functional and procedural programming
c = If[Quiet[StringTake[Read[x, String], {1, 5}]] === "%PDF-", {Close[x], "PDF"}[[–1]], Close[x]; b = ReadFullFile[x];
c= If[! StringFreeQ[b, {"MSWordDoc", "Microsoft Office Word"}], "DOC",
If[! StringFreeQ[b, "docProps"], "DOCX"],
If[! StringFreeQ[b, ".opendocument.textPK"], "ODT",
If[! StringFreeQ[b, {"!DOCTYPE HTML", "text/html"}], "HTML",
If[MemberQ3[Range[0, 255], DeleteDuplicates[Flatten[ Map[ToCharacterCode[#] &, DeleteDuplicates[Characters[b]]]]]],
"TXT", Undefined]]]]]; If[{t} != {}, Quiet[Close[x]]; RenameFile[x, x <> "." <> c], c]]]
In[3333]:= Map[FileFormat2, {"C:/", "C:\\", "E:\\", "E:/",
"C:/Temp", "C:\\Temp"}]
Out[3333]= {"Directory", "Directory", "Directory",
"Directory", "Directory", "Directory"}
In[3334]:= FileFormat3["C:/Temp/Kiri"]
Out[3334]= "DOCX"
In[3335]:= FileFormat3["C:/Temp/Kiri", Agn]
Out[3335]= "C:\\Temp\\Kiri.DOCX"
In[3336]:= Map[FileFormat3, {"C:\\Temp.Burthday",
"c:\\Temp/cinema", "c:/Temp/ransian",
"c:/Temp/Grodno", "c:/Temp/Math_Trials"}]
Out[3336]= {"DOC", "TXT", "HTML", "PDF", "DOCX"}
Now, using the algorithm implemented by FileFormat3 it is rather simple to modify it for testing of other types of data files whose full names have no extension. That can be rather useful in the processing problems of data files. In a certain relation the FileFormat3 procedure complements the built–in FileFormat function along with procedures FileFormat1 and FileFormat2.
The Mathematica provides effective system–independent access to all aspects of data files of any size. At that, the opening and closing of files the following built-in functions of access are used: Close, OpenRead, OpenWrite, OpenAppend. Moreover, a name or full path to a file in the string format acts as a formal argument of the first three functions; at that, the function call OpenWrite[] without factual arguments is allowed, opening a new file located in a subdirectory intended for temporary files for writing. Whereas the Close function closes a file given by its
307

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov
name, full path or a Stream–object. In attempt to close a closed or nonexistent file the system causes an erroneous situation. For elimination of such situation, undesirable in many cases, it is possible to use the simple Closes function doing the closing of any file including a closed or nonexistent file without output of any erroneous messages with returning Null, i.e. nothing, but, perhaps, the name or full path to the closed file:
In[2331]:= Close["C:/Temp/Math/test77.txt"]
…General: C:/Temp/Math/test77.txt is not open.
Out[2331]= Close["C:/Temp/Math/test77.txt"]
In[2332]:= Closes[x_] := Quiet[Check[Close[x], Null]]
In[2333]:= Closes["C:/Temp/Math/test77.txt"]
An object of the following format is understood as a Stream object of the functions of access such as OpenRead, OpenWrite, OpenAppend, Read, BinaryWrite,Write, WriteString, etc:
{OutputStream|InputStream}[<File>, <Logical IO channel>]
The function call Streams[] returns the list of Stream objects of files opened in the current session including system files. For obtaining the list of all Stream objects of files different from the system files it is possible to use the function call StreamsU[]:
In[2214]:= StreamsU[] := Streams[][[3 ;; –1]] In[2215]:= StreamsU[]
Out[2215]= {OutputStream["C:/temp/galina.txt", 3]} In[2216]:= CloseAll[] := Map[Close, StreamsU[]] In[2217]:= CloseAll[]; StreamsU[]
Out[2217]= {}
It must be kept in mind that after the termination of work with an opened file, it remains opened up to its explicit closing by means of the Close function. For closing of all channels and files opened in the current session, excepting system files, it is possible to apply a quite simple CloseAll function, whose call CloseAll[] closes all open both files and channels with return of the list of the closed files.
Similar to the Maple the Mathematica also has opportunity to open the same file on different streams and in various modes,
308

Mathematica: Functional and procedural programming
using different coding of its name or path by using alternative registers for letters or/and replacement of "\\" separators of the subdirectories on "/", and vice versa at opening of files. The fragment below illustrates application of a similar approach for opening of the same file on two different channels on reading with the subsequent alternating reading of records from it.
In[2222]:= g = "C:\\temp\\cinema_2020.txt"; {S, S1} = {OpenRead[g], OpenRead[If[UpperCaseQ[StringTake[g, 1]], ToLowerCase[g], ToUpperCase[g]]]}
Out[2222]= {InputStream["C:/temp/cinema_2020.doc", 3], InputStream["c:\\temp\\cinema_2020.txt", 4]}
In[2223]:= t = {}; For[k = 1, k <= 3, k++, AppendTo[t, {Read[S], Read[S1]}]]
Out[2223]= {"ran1", "ran1", "ran2", "ran2", "ran3", "ran3"}
Meantime it must be kept in mind that the special attention at opening of the same file on different channels is necessary and, above all, at various modes of access to the file in order to avoid of the possible especial situations, including distortion of data in a file. Whereas in certain cases this approach at operating with large enough files can give a quite notable temporal effect with simplification of certain algorithms of data processing that are in files. The interesting enough examples of application of such approach can be found in our books [1-15].
The Mathematica has useful tools for operating with the pointer defining the current position of scanning of a file. The following functions provide such work: StreamPosition, Skip, SetStreamPosition and Find. So, functions StreamPosition and
SetStreamPosition allow to monitor of the current position of the pointer of an open file and to establish for it a new position respectively. Moreover, on the closed or nonexistent datafiles the calls of these functions cause erroneous situations.
Reaction of the Skip function to the status of a file is similar, whereas the function call Find opens a stream to reading from a file. The sense of the presented functions is a rather transparent and in more detail it is possible to familiarize oneself with them, for instance, in books [12-14]. In connection with these tools the
309

V.Z. Aladjev, M.L. Shishakov, V.A. Vaganov
question of definition of the status of a file – opened, closed or doesn't exist – arises. In this regard FileOpenQ procedure can be as a rather useful tool [16], whose call FileOpenQ[F] returns the nested list {{R, F, Channel},…} if a F file is open on reading/ writing (R = {"read"|"write"}), F defines actually the F file in the stylized format (LowerCase + all "\\" are replaced on "/") whereas
Channel defines the logical channel on which the F file in the mode specified by the first element of the R list was open; if F file is closed, the empty list is returned, i.e. {}, if F file is absent, then $Failed is returned. At that, the nested list is used with the purpose, that the F file can be opened according to syntactically various file specifiers, for example, "Agn47" and "AGN47", that allows to do its processing in the various modes simultaneously.
The FileOpenQ1 is a useful extension of FileOpenQ that was considered above. The call FileOpenQ1[f] returns the nested list of the format {{R, x, y,...,z}, {{R, x1, y1,...,z1}} if a f file is open for reading or writing (R = {"in"|"out"}), and f determines the file in any format (Register + "/" and/or "\\"); if the f file is closed or is absent, the empty list is returned, i.e. {}. Moreover, sub-lists {x, y,...,z} and {x1, y1,...,z1} define files or full paths to them that are open for reading and writing respectively. Moreover, if in the current session all user files are closed, except system files, the call FileOPenQ1[x] on an arbitrary x string returns $Failed. The files and paths to them are returned in formats which are determined in the list returned by the function call Streams[], irrespective of format of f file.
At last, the procedure call FileOpenQ2[x] returns True if a x file is open, and False otherwise (file is closed or absent). Whereas the call FileOpenQ2[x, y] also returns True or False depending on the openness of the file x, returning thru the second optional argument – a symbol y – the list in the string format of the file mode of x {"in", "out"} where x file is open for reading ("in") or writing ("out") accordingly. In addition, the x file can be opened in both modes at the same time. The fragment below represents source code of the FileOpenQ2 procedure and the most typical examples of its application.
310