Chapter 18. Tricks of the Trade

Meine tricks Don’t know what I would do without Tricks yeah yeah Gimme tricks Ihr wisst ich bin alleine ohne meine meine Tricks yeah That’s the only reason my heart still ticks Vishnu, Batu, Fu Manchu too Hu-Hu, Jonny Manushutu Dr. Wu, Peggy Sue Randy Andy too One thing in common when they get up to their tricks They do it for kicks So if you ever see me acting Like a kid from outer space And you think of lending a hand But if you look real close You’ll see a smile on my face Then I’m sure you’ll understand

Falco, "Tricks"

18.0 Introduction

This chapter’s recipes consist of Mathematica techniques and capabilities that every serious user should have in their tool box. Unlike other chapters, the recipes here are not tied together by any one theme. I include them because each recipe will give you some deeper insight into details that are unique to the Mathematica architecture. Each recipe has been a lifesaver to me at various times, and I hope that one or more of them will be helpful to you.

18.1 Cleaning Up During Incremental Development

Problem

You are solving a problem by incremental refinement of a set of functions. As you proceed to refactor and introduce alternative definitions for symbols, you find that code that was working before mysteriously breaks.

Solution

Make judicious use of Clear before every group of functions that are still undergoing development. First, I illustrate what can go wrong if you are sloppy. Suppose you define this function f.

f[x_Integer] := x^2;

Later, you decide that you should be more general about the valid types for argument x and also realize you really meant to compute x^2 +1, so you change the line to this (deleting the previous line from the notebook):

f[x_?NumericQ] := x^2 + 1

Later (possibly after you have forgotten the old version even existed), you try out your code and are surprised by the result.

f[2]
4

To avoid problems like this, you should clear old definitions before defining a function. Then you can redefine f to your heart’s content without worrying that old definitions will interfere.

Clear[f]
f[x_?NumericQ] := x^2 + 1

Discussion

Developers coming from other programming environments easily fall into the trap caused by the fact that the kernel holds all definitions created during a session unless they are specifically cleared or exactly redefined. This is not the expected behavior of languages that are compiled or interpreted, since in those environments old definitions do not persist. The solution shows one way problems can arise, but there are others. It is just as likely that conflicts can come from other notebooks that are sharing the same kernel instance. Many Mathematica veterans begin their notebooks with an expression to clear every symbol in the global context (a context is similar to what other languages call namespaces).

Clear["Global'*"]

The Global` context is the default context in which new symbols are defined.

You can also clear the command history. This is useful for freeing memory. Consider the following example.

In[192]:= MemoryInUse[]
Out[192]= 132430904

Let’s use a lot of memory.

In[193]:= x = Array[f, {1000, 1000}];
          MemoryInUse[]
Out[194]= 188 470 896

Simply clearing x does not get the memory back because it is cached in the history.

In[196]:=  Clear[x];
           MemoryInUse[]
Out[197]=  188 473 032

However, you can clear the In and Out history by unprotecting, clearing, and repro-tecting In and Out.

In[198]:=  Unprotect[In, Out];
           Clear[In, Out];
           Protect[In, Out];
           MemoryInUse[]
Out[201]=  132 287 208

See Also

Problems with name conflicts can also be mitigated by use of packages. See 18.4 Packaging Your Mathematica Solutions into Libraries for Others to Use.

18.2 Modifying Built-in Functions and Constants

Problem

You want to extend or alter the meaning of intrinsic functions that are built in to Mathematica. Perhaps you want to introduce a mathematical object that has its own natural definitions for the standard operations Plus, Times, etc.

Solution

The most straightforward way to modify Mathematica operations is to unprotect them, augment their meaning, and protect them again. However, the easiest way is frequently not the best or safest way, so be sure not to skip the "Discussion" section.

It is common in certain applications to consider 0^0 to be defined as 1; however, Mathematica considers this expression to be indeterminate and will issue a warning when it evaluates it (hence, the use of Quiet here).

0^0 // Quiet
Indeterminate

You can change this behavior quite easily.

Unprotect[Power];
Power[0,0] = 1;
Protect[Power];
0^0
1

This new behavior will persist only within the Mathematica kernel session and will be known to all notebooks associated with the notebook’s kernel. See 18.9 Initializing and Cleaning Up Automatically for a way to make such changes automatically active each time you use Mathematica.

Discussion

The solution shows a reasonable change to the meaning of an intrinsic function. It is reasonable because it is unlikely to change the behavior of Mathematica in a detrimental way since you are simply supplying meaning to an expression that had no meaning. Technically speaking, it is possible that third-party code you are also using depended on Power[0,0] evaluating to indeterminate; however, this possibility is farfetched. This is not the case for other seemingly reasonable changes. For example, you might be irked by the following result:

(-1) ^ (1/3) //N
0.5 + 0.866025 i

Clearly, an equally valid answer is -1. In fact, there are three valid answers. This is a question of which branch Mathematica takes by default.

Discussion

To remedy this choice, you might decide to take matters into your own hands and force Mathematica to take a different branch whenever it needs to evaluate a rational power of a negative number.

Unprotect[Power];
Power[a_ ?Negative, n_Rational] = Exp[n Log[a] + n 2 Pi I];
Protect[Power];
(-1) ^ (1/3) //N
-1.

This has an unfortunate consequence if you want Solve to work as before!

Discussion

Quitting the kernel will revert to the old behavior.

Discussion

Sometimes you want to temporarily change the meaning of a symbol. In that case, use of Unprotect is overkill, and it is better to introduce the new value within a Block. For example, E is the built-in symbol for the base of the natural logarithm, but in this block we use E as hex digit 14.

Block[{A = 10, B = 11, C = 12, D = 13, E = 14, F = 15}, A * 16 + E]
174

This technique is often used to temporarily change special global variables like $RecursionLimit. The following is a recursive implementation of the Ackermann function that would easily overflow the default stack limit of 256. This is for illustration purposes and not a good way to implement Ackermann.

(*Ackermann function*)
Block[{$RecursionLimit = 100000, A},
 A[0, n_] := n + 1; A[m_, 0] := A[m, 0] = A[m - 1,1];
 A[m_, n_] := A[m, n] = A[m-1, A[m, n-1]]; A[4, 1]]
65 533

18.3 Locating Undocumented Functions

Problem

You are wondering what undocumented functions might be hiding in your current version of Mathematica.

Solution

Inspect the Developer` and Experimental` contexts for hidden treasures. Here, //Short is used only to reduce clutter, so remove that before evaluating.

  In[891]:=  Names["Developer`*"] // Short
Out[891]//Short=

             {Developer`BesselSimplify, <<69>>, Developer`$SymbolSystemShadowing }

  In[892]:=  Names["Experimental`*"] // Short
Out[892]//Short=

             {Experimental`AngleRange, <<47>>, Experimental`Wait }

Discussion

Strictly speaking, the Developer` context is not entirely undocumented, but rather consists of low-level access to underlying algorithms that are typically used in the implementation of higher-level, built-in functions. Here is an example of such a function and its documentation. However, you can see that the documentation is much more sparse than that of a function available in standard System` context.

Discussion

In contrast, expect to find little information about functions in the Experimental` context.

Discussion

Even if you manage to figure out how these functions work, there is no guarantee the functions won’t change or be removed in a future version, so use them with caution. Sometimes an experimental function will tell you it has been deprecated and direct you to an alternative.

Discussion

See Also

PartitionMap was used in 2.6 Mapping a Function over a Moving Sublist.

18.4 Packaging Your Mathematica Solutions into Libraries for Others to Use

Problem

You have a nice collection of functions that are of general use within your organization or perhaps as a library that you want to distribute to others.

Solution

Mathematica provides a facility for defining custom packages that place functions in a unique namespace and also allow you to selectively expose some functions while leaving other low-level details hidden.

BeginPackage["CoolStuff'"]

Unique`::usage = "Unique[list] removes duplicates from a list (similar to
Union) but does not reorder elements of the list."

Begin["`Private`"]

Unique[list_List] := Module[{once},
    once[x_] := (once[x] = Sequence[];x);
    once /@ list]

End[]

EndPackage[]

Discussion

The solution follows a standard convention where actual definitions are placed in a Private context (Begin["`Private`"] ... End[]) while the function is exposed by defining its usage string (Unique`::usage) in the public part of the package. Having the definition of Unique inside Private does not mean you can’t access it. What it does mean is that any symbols introduced inside the definition of Unique will not be exported when the package is read in. The context Private` does not have any special semantics, but it is a convention used by most Mathematica package authors, and it would be wise to follow suit.

If a package depends on other packages, you can list the dependents as a second argument to BeginPackage. Here, CoolStuff` needs SuperCool` and Essential`.

BeginPackage["CoolStuff`", {"SuperCool`", "Essential`"}]

You can defer loading other packages until you know they are needed by using DeclarePackage. The syntax is DeclarePackage["context`", {"namel", "name2", ...}]. Here you are telling Mathematica to execute Needs["context`"] contingent on the use of one of the symbols namel, name2, and so on (typically functions or constants).

BeginPackage["CoolStuff`"]

Cool`::usage = "Cool[list] does something cool."
Cooler`::usage = "Cooler[list] does something even cooler."
ReallyRadCool'::usage = "ReallyRadCool[list]does something too cool for words."

(*If functions Cooler or ReallyRadCool are used, then execute
Needs["SuperCool'"].*)

DeclarePackage["SuperCool'", {"Cooler", "ReallyRadCool"}]

Begin["'Private'"]

Cool[list_List] := Module[{},
    (*...*)
    ]

Cooler[list_List] := Module[{x,y},
    (*... uses something in SuperCool' context.*)
    ]

ReallyRadCool[list_List] := Module[{elvis, jamesdean},
    (*... uses something in SuperCool' context ...
      If I show you, I'd have to kill you.*)
    ]

End[]

EndPackage[]

See Also

See the tutorial for setting up Mathematica packages: http://bit.ly/8Q9WIq .

Some good advice regarding the creation of packages can be found here in the Wolfram Research MathGroup Archive: http://bit.ly/7rZ60P .

It is also worth reading Michael A. Morrison’s "Mathematica Tips, Tricks, and Techniques" ( http://bit.ly/5Z5dI9 ), although this is less about creating packages and more about using them.

18.5 Compiling Functions to Improve Performance

Problem

You have a function that is called frequently and you want to optimize its performance.

Solution

In many cases, you can remove a significant amount of overhead from your functions by compiling them. You can compile functions that take Integer, Real, Complex, Boolean arguments (True | False), or uniform vectors and tensors of these types.

magnitude1[vector : {__Real}] := Sqrt[Plus @@ vector];
magnitude2 = Compile[{{vector, _Real, 1}}, Sqrt[Plus @@ vector]];

vec = RandomReal[{0, 10}, 1 000000];
Timing[magnitude1[vec]]
{0.485, 2236.01}

Timing[magnitude2[vec]]
{0.187, 2236.01}

Discussion

The syntax of Compile can be a bit confusing at first because it does not follow the traditional pattern-based syntax of an uncompiled function. This is partly due to the fact that Compile is far less flexible, and each argument must be entirely unambiguous in regard to its type. First note that Compile takes a list of argument specifications and that each argument specification is itself a list. The argument specifications must at minimum specify the argument name, but can also specify the type and the rank—if the argument is a vector (rank = 1), matrix (rank = 2), or tensor (rank > 2).

Table 18-1. Example argument specifications for compile

Argument specification

Description

{x}

x is some numeric type

{x, _Integer}

x is an Integer

{x, _Real}

x is a Real

{x, _Integer, 1}

x is a vector of Integers

{x, _Complex, 2}

x is a matrix of Complex

{x, _Real, 5}

x is a rank 5 tensor of Reals

{x, True | False, 1}

x is a vector of logical values

Note that functions that take strings or general symbolic arguments cannot be compiled. Also, if you specify a rank of two or higher, you must pass uniform arrays of the appropriate rank rather than jagged arrays (like {{1,2},{3}}), and you can’t mix types in vectors or higher-ranked tensors. If you violate these constraints, the function may still work, but Mathematica will use an uncompiled form, which defeats the advantage of compilation.

18.6 Automating and Standardizing the Appearance of Notebooks Using Stylesheets

Problem

You find yourself frequently needing to tweak formatting in your notebook or you find formatting tedious. You may be frustrated that your notebooks do not have the professional appearance of your peers’ or of notebooks you see at conferences or download from the Web.

Solution

Creating a basic stylesheet or modifying an existing stylesheet is easier than you might think, although there are some aspects that are tricky (or nearly impossible to figure out without help). The easiest way to proceed is to start with a built-in style. Starting with a new notebook, select Format, Stylesheet and select a style from one of the submenus. Figure 18-1 shows a notebook configured with the NaturalColor stylesheet, which is under the Creative submenu in Stylesheets.

A notebook using the built-in Mathematica 7 stylesheet

Figure 18-1. A notebook using the built-in Mathematica 7 stylesheet

Once you have a stylesheet selected that is close to how you want your notebook to look, you can customize it by selecting the Format, Edit Stylesheet menu. This will launch a special stylesheet notebook, shown in Figure 18-2. To modify an existing style, use the "Choose a style" drop-down menu. This will add a cell to the notebook that is styled in the selected style. By altering the style elements of this cell (using the Format menu), you update the stylesheet so this style now is associated with the style of the cell. Think of this as styling by example, which is a bit different than how stylesheets work in most word processors and certainly different than Cascading Style Sheets (CSS) used in web pages, but simple enough. You can also add a new style. In Figure 18-2, I add a style called Warning and give it a red font with gray background. New styles are added by typing their names in the "Enter a style" edit box and hitting Enter.

Editing a stylesheet to modify existing styles or add new styles

Figure 18-2. Editing a stylesheet to modify existing styles or add new styles

Discussion

Often when creating a new style you want to base it on an existing style. This inheritance of style attributes is a powerful capability because it reduces the effort for specifying a style and allows changes to the base style to automatically propagate to the derived. Creating derived styles involves getting your hands a bit dirty since you need to drill down into the underlying syntax of the stylesheet cells. As an example, imagine you want to create a base style called Note and a derived style called Warning. The intent is to use Note to provide some extra parenthetical information. Warning should derive from Note, but have a red font to emphasize that the extra information is cautionary.

When you select a cell (or cells) in a stylesheet and use Ctrl-Shift-E (or Command-Shift-E on Mac) you convert the cell to expression form, as shown in Figure 18-3. Here I show two cells that have been changed to expression form. The first cell defines the general properties I want to have for a note, including a special margin, bold font, and gray background. I’ll discuss MenuPosition later.

Editing style option in expression form

Figure 18-3. Editing style option in expression form

For now, consider the second style cell. Note in particular the expression for Style-Data. Here, in addition to the style’s name, there is a rule StyleDefinitions, which indicates the base style is "Note". This is what you must type by hand to link a new style to its base since there is presently no other way to establish this relationship. Once the relationship is established, the Warning style will inherit all the attributes of Note but will be able to override or augment them. Here you can see that I augment Warning to use a red font. Once the inheritance is defined, you can revert the style cells back to their normal form (Ctrl-Shift-E again) since most other changes can be affected using the Format.

When you create new styles, they are integrated into the frontend menus (Format, Style) as well as the window’s toolbar (assuming you show the toolbar; see Window, Show Toolbar). The position of the style within the choices is governed by the Menu-Position option in the stylesheet cell (Figure 18-3). You can set this value to whatever number you want, but a sensible scheme is to use either 1 or 10000 (the default). If you choose 1, the style will sort alphabetically within all styles that have the value 1. If you choose 10000, the style will appear after all styles with position 1, but again, sorted alphabetically. This sets up two groups, one for native styles (MenuPosition→1) and the other for custom styles (MenuPosition→10000). If you would like multiple groupings, use an intermediate value (like 5000), but don’t attempt to assign a unique value to every style because this is not the intention of the option and will create maintenance headaches for your stylesheet.

There are a few style settings that are tricky to set up. One in particular is a numbered style for a heading. Here you typically desire a series of headings and subheadings with a hierarchical numbering system. The NaturalColor stylesheet has styles called ItemNumbered and SubitemNumbered, so let’s look at these styles in expression form (Figure 18-4).

Expression form for numbered styles does not reveal the numbering options

Figure 18-4. Expression form for numbered styles does not reveal the numbering options

Do you see anything that would indicate that these styles have some auto-numbering capability? No? Me either. These settings are magical. You need to select the cell and invoke the options inspector. Let’s revert to normal cell form (important!) and use Ctrl-Shift-O to inspect options for ItemNumbered. Figure 18-5 shows how the item counters are maintained and Figure 18-6 shows how the displayed output is generated. These options are not visible in the stylesheet because they are inherited from the Default stylesheet. You can learn a great deal about Mathematica’s stylesheet capabilities by studying the Default stylesheet, which is located in $InstallationDirectory <> "/SystemFiles/FrontEnd/StyleSheets/Default.nb". Default itself inherits from Core, so you should inspect that as well. You should avoid changing either Core or Default; rather, customize your own stylesheet based on these, as explained in the Solution section.

Options inspector for ItemNumbered reveals numbering settings

Figure 18-5. Options inspector for ItemNumbered reveals numbering settings

The CellDingbat option controls how the number is generated into the output

Figure 18-6. The CellDingbat option controls how the number is generated into the output

Armed with this information, you can create your own numbered styles.

1-

This is h1 style.

1-1.

This is h2 style.

1-1-1

This is h3 style.

18.7 Transforming Notebooks into Other Forms

Problem

You want to extract content from notebooks to create other kinds of documents that Mathematica does not support as a straight export. You may also want to extract information from notebooks for other purposes.

Solution

Like everything in Mathematica, notebooks are expressions and can be manipulated using the powerful expression manipulation facilities of Mathematica. Here is an example that takes a chapter of Mathematica Cookbook and creates a recipe cross-reference to native Mathematica symbols (those in the System` package).

Solution

Here I run the transformation against Chapter 5 notebook.

In[521]:= crossRefCookbookChapter[5, NotebookDirectory[] <> "Strings.nb"]
Out[521]= {{5.0, {CharacterEncoding, FromCharacterCode,
             IgnoreCase, Input, NumberString, Partition, StringMatchQ,
             TableForm, ToCharacterCode, ToString, True, $CharacterEncoding,
             $CharacterEncodings, $SystemCharacterEncoding}}, {5.1,
            {Greater, GreaterEqual, Input, Less, LessEqual, Order, Protect, Unprotect}},
           {5.2, {Block, DateList, DatePattern, DatePlus, DateString,
             Except, FileNameJoin, IgnoreCase, Import, Input, InputForm, N,
             NotebookDirectory, NumberString, RegularExpression, Riffle, Shortest,
             ShortestMatch, StringCases, StringDrop, StringJoin, StringReplace,
             StringReplacePart, ToExpression, ToString, True, Whitespace}},
           {5.3, {All, Except, False, IgnoreCase, Input, Overlaps,
             RegularExpression, Repeated, Return, Shortest, StringCases,
             StringJoin, StringTake, TableForm, True, WordBoundary}},
           {5.4, {Array, Ceiling, Clear, Input, InputForm, Log, Mean,
             Nest, StringJoin, StringTake, Table, Timing}},
           {5.5, {DatePattern, False, FileNameJoin, FromDigits, Import,
             Input, Length, NotebookDirectory, NumberString, OddQ,
             Overlaps, Pick, Range, RegularExpression, SpellingCorrection,
             StringDrop, StringFreeQ, StringMatchQ, StringPosition,
             StringTake, TableForm, Transpose, True, With}},
           {5.6, {Blue, Bold, Brown, Except, FileNameJoin, FontColor,
              FontSlant, FontWeight, Import, Input, Italic, NotebookDirectory,
              Red, Row, StringSplit, Style, WhitespaceCharacter}},
           {5.7, {And, Block, Characters, Complement, DictionaryLookup,
              DistanceFunction, EditDistance, False, If, IgnoreCase, Input,
              Intersection, MapThread, MemberQ, Module, Nearest, SameTest, StringCount,
              StringReplace, StringReverse, Tally, Timing, True, WordData}},
           {5.8, {Apply, Cases, FileNameJoin, Head, ImageSize, Import,
              Infinity, Input, InputForm, List, NotebookDirectory,
              Symbol, TableForm, TreeForm, XMLElement, XMLObject}},
           {5.9, {Apply, Cases, ExportString, FileNameJoin, If, Import, Infinity,
              Input, Join, List, MatrixForm, NotebookDirectory, NumberString,
              Rule, StringMatchQ, StringReplace, ToExpression, XMLElement}},
           {5.10, {ClearAll, ExportString, FileNameJoin, Import, Input, List,
              Module, NotebookDirectory, Order, Rule, Sort, Split, StringJoin,
              StringReplace, ToExpression, ToString, XMLElement, XMLObject}},
           {5.11, {Append, Apply, Ceiling, Drop, First, Flatten, FoldList, Format,
              Hold, HoldAll, If, ImageSize, Infinity, Input, InputForm, Last, Length,
              List, Map, MemberQ, Module, N, Plus, RandomInteger, RandomReal, Rest,
              SeedRandom, SetAttributes, StringJoin, StringReplacePart, StringTake,
              Table, TableForm, Top, ToString, ToUpperCase, TreeForm, Union, While}}}

Discussion

The easiest way to get a notebook into another form is to leverage the conversions built into Save As. As of Mathematica 7, you can save a notebook as PDF, XHTML + MathML, plain text, Rich Text Format (RTF), and PostScript. However, if these formats are not what you’re after, you should not be afraid to take matters into your own hands as I did in the solution.

The command NotebookOpen is used to load the notebook from disk and produce a NotebookObject. You use the option Visible → False to prevent the notebook from being opened in a new window. NotebookGet is applied to the NotebookObject to return the raw symbolic form of the notebook for manipulation. Here the bulk of the work is done by the second version of crossRefCookbookChapter. Cases is used to parse out Cell expressions with the style Headingl or Input. The Headingl cells represent the recipe titles, and the Input cells are the ones you want to cross reference. GatherBy groups input cells with their associated recipes, and then Maplndexed processes each recipe using the index and the chapter number to generate the recipe number. The mapped function, crossRef, extracts strings and uses Intersection to locate just those strings that are in the set of native System` symbols.

One of the handiest uses of notebook manipulation is to create small bulk conversion utilities. For example, imagine you had a large number of notebooks and you needed to change one style into another. This would be tedious to do by hand, but is a breeze with Mathematica. The converter would look something like this.

Discussion

Here I introduce NotebookPut and NotebookSave, which are used to modify the original notebook object and save it back to disk, respectively. Here is an example of usage:

In[543]:= convertStyle[NotebookDirectory[]  <> "TestStyleConvert.nb",
           NotebookDirectory[] <> "TestStyleConvertOut.nb", "Section", "Subsection"]

See Also

Advanced notebook manipulations often require that you convert between strings, boxes, and expressions. See the tutorial/ConvertingBetweenStringsBoxesAndExpressions in the Mathematica documentation for details.

18.8 Calling into the Mathematica Frontend

Problem

You want to programmatically invoke functionality that is provided by the frontend rather than the kernel.

Solution

There are certain operations that are executed by the Mathematica frontend rather than the kernel. If you are running a program from the frontend, you generally don’t need to worry about the distinction, because Mathematica is designed to make the distinction appear seamless. However, you can bypass the kernel when using the frontend with FrontEndExecute.

In[2]:=  FrontEndExecute[
          FrontEnd`CellPrint[Cell["No Help From Kernel", "Emphasis"]]]

No Help From Kernel

You can also invoke actions typically performed via interaction with the frontend’s menu. For example, the following will open the Font dialog.

In[5]:=  FrontEndExecute[FrontEndToken["FontPanel"]]

Whereas FrontEndExecute is intended to be used in the frontend, UsingFrontEnd is intended to be executed from a kernel session to allow the kernel to invoke an operation in the frontend. The output here was created by executing the kernel directly on the command line.

In[1]:= nb = UsingFrontEnd[NotebookCreate[]]

Out[1]= -NotebookObject-

Note that a frontend must be installed on the system for this to work.

Discussion

You can see all the commands that can be executed directly in the frontend by executing

Names["FrontEnd'*"]

Sometimes you want to invoke features in the frontend that are not available via functions. For example, while doing some notebook manipulations a la 18.7 Transforming Notebooks into Other Forms, you wish to get the functionality available by selecting a cell and using CopyAs, Plain Text. You can do this like so:

In[885]:= someCell = Cell[
             BoxData[RowBox[{"N", "[", FractionBox["1", "9999"], "]"}]], "Input"];
          First[MathLink`CallFrontEnd[
            FrontEnd`ExportPacket[someCell, "PlainText"]]]
Out[886]= N[1/9999]

See Also

See the tutorial ExecutingNotebookCommandsDirectlyInTheFrontEnd for more details on frontend execution.

See guide/FrontEndTokens for tokens that can be used with FrontEndToken or FrontEndTokenExecute.

Also consult tutorial/ManipulatingTheFrontEndFromTheKernel for further commands useful for controlling the frontend from the kernel.

18.9 Initializing and Cleaning Up Automatically

Problem

You want to automatically execute code whenever the kernel or frontend starts. You may also want to execute code when the kernel is terminated.

Solution

There are several init.m files in which you can place function definitions or code you want executed automatically.

To execute code on kernel start for every user, modify the file given by

In[865]:=  ToFileName[{$BaseDirectory, "Kernel"}, "init.m"]
Out[865]=  /Library/Mathematica/Kernel/init.m

To execute code on kernel start for the currently logged-in user, modify the file given by

In[866]:=  ToFileName[{$UserBaseDirectory, "Kernel"}, "init.m"]
Out[866]=  /Users/smangano/Library/Mathematica/Kernel/init.m

To execute code on frontend start for every user, modify the file given by

In[867]:=  ToFileName[{$BaseDirectory, "FrontEnd"}, "init.m"]
Out[867]=  /Library/Mathematica/FrontEnd/init.m

To execute code on frontend start for the currently logged-in user, modify the file given by

In[868]:=  ToFileName[{$UserBaseDirectory, "FrontEnd"}, "init.m"]
Out[868]=  /Users/smangano/Library/Mathematica/FrontEnd/init.m

Clearly the results will vary depending on your particular OS.

Within these files, you can also modify the variable $Epilog to define code that executes right before the kernel exits.

Discussion

If you make frequent use of some utility functions or constants, you can make sure they are always available in every session. For example, if you always use a package called Essential`, you can add Needs["Essential`"] to the user-level version of init.m for the kernel.

Note that user-level initializations come after system-wide ones, so if you want to override some system-level definition, you can do so.

See Also

18.10 Customizing Frontend User Interaction shows a use case for init.m and $Epilog.

See ref/file/init.m in the Mathematica documentation for more information.

18.10 Customizing Frontend User Interaction

Problem

You want to hook into the processing performed by the frontend as you type and evaluate expressions.

Solution

You can intercept Mathematica’s message loop at various stages by defining functions for $PreRead, $Pre, $Post, $PrePrint, and $SyntaxHandler. For example, as an educator, you might want to study students’ experiences with learning Mathematica and log their interactions to a file. Here you can define $PreRead, which intercepts input before being fed to Mathematica; $SyntaxHandler, which is applied to lines with syntax errors; and $PrePrint, which gets the results before printing.

In[830]:=  InitializeStudentMonitoring[] :=
            Module[{logFile, stream},
             logFile =$UserName  <> DateString[{"Year", "", "Month", "", "Day",
                 "_", "Hour24", "", "Minute", "", "SecondExact"}] <>".log";
             stream = OpenWrite[logFile] ;
             $PreRead = (Write[stream, "Input >", #]; #)&;
             $PrePrint = (Write[stream, "Output> ", #]; #)&;
             $SyntaxHandler = (Write[stream, "Syntax:", #2, ">", #1]; $Failed) &;
             stream
            ]

In[845]:=  StopStudentMonitoring[stream_] := Module[{},
             $PreRead =.;
             $PrePrint =.;
             $SyntaxHandler =.;
             Close[ stream]]

You can then place a call to InitializeStudentMonitoring[] in the init.m file and set delayed $Epilog to StopStudentMonitoring[Evaluate[stream]].

In[850]:=  stream = InitializeStudentMonitoring[] ;
           $Epilog := StopStudentMonitoring[Evaluate[stream]]

Discussion

The solution shows a use case for capturing but not altering session input and output. However, you can also imagine advanced use cases where you want to use these hooks to do preprocessing or postprocessing. Here I use $PrePrint to force any string output into InputForm so I can see the quotes.

In[859]:=  $PrePrint = If[StringQ[#], InputForm[#], #]&;

In[860]:=  "SomeString"
Out[860]=  "SomeString"

Now revert to default behavior.

In[863]:=  $PrePrint =.
In[864]:=  "SomeString"
Out[864]=  SomeString

See Also

See the tutorial tutorial/TheMainLoop for more information.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset