Advanced Typesetting (Workshop)

Jason Harris

Wolfram Research

This workshop will give you a hands on tutorial for creating your own advanced typeset structures in Mathematica.You will be exposed to, evaluate, and experiment — in a hands on fashion — some of the core technologies that underlie the typesetting system in Mathematica. At the conclusion of the workshop you should be able to create and use your own typeset structures. For instance, have you ever looked at the output of say Binomial[a, b] // TraditionalForm and wondered how you can create something like that yourself? If so then this workshop is for you! The topics covered are:

Boxes and the representation of typeset structures

MakeBoxes & MakeExpression and how the typesetting system interacts between the Kernel and the FrontEnd

The Notation Package and how to short cut much of the work required in using MakeBoxes and MakeExpression

StyleSheets and how to package up the typeset structures onto the style sheet

TemplateBoxes and how to use these modern mechanisms which significantly advance typesetting

Miscellaneous topics.

Please Fire Up Your Copy Mathematica

This will be a hands on tutorial. Grab a copy of this notebook!

Hands On!

Please type and work the exercises as we go...

The Schedule

Introduction To Boxes (10 minutes)

The “guts” (35 minutes)

Problem solving clinic / difficult questions (last 15+ minutes, continuation...)

Our Goal

Our goal is to introduce new notations which can do computations.

For instance something like (Subscript[a, ∂]) and make this parse and format as the operator ADiff, etc.

Throughout the notebook there are various encrypted cells, so you have the answers to the questions in the notebook but you just can’t reveal them until I give you the answer code.

Decryptify[Code_pvi,code]

Encryption Code

MyPermutations @ code_String:=
Module[{
chars = DeleteDuplicates @ Characters @ code, imageChars},
imageChars = Take[CharacterRange["a","z"],Length @ chars];
Flatten[{Inner[Rule,chars,imageChars,List],Inner[Rule,imageChars,chars,List]}]
]

CryptoTransform[str_String,code_String]:=StringReplace[str,MyPermutations @ code]
Decryptify[str_String,code_String]:=CellPrint @Uncompress@CryptoTransform[str,code]
Decryptify[str_String,code_Symbol]:=Decryptify[str,ToString @ code]

Random3Letters[]:=FromCharacterCode[Take[DeleteDuplicates[RandomInteger[25,100]+97],3]]

CreatePalette @ Button["encrypt",
With[{
theContents=NotebookRead @ InputNotebook[],
theShownCode="Code_"<>Random3Letters[],
thePassCode=Random3Letters[]},
With[{
encrypted="\""<>CryptoTransform[Compress@ theContents,thePassCode]<>"\""},
Print @ theContents;
Pause[0.5];
SelectionMove[InputNotebook[],Before,Cell];
NotebookWrite[InputNotebook[],Cell[BoxData[RowBox[{"Decryptify","[",RowBox[{InterpretationBox[theShownCode,encrypted],",",TagBox[FrameBox["code"],"Placeholder"]}],"]"}]],"Input"]];
NotebookWrite[InputNotebook[],Cell[BoxData[thePassCode],"MyCode"]];
]
]
];

Everything is Boxes!

(x^3)+2

(∫_0^∞)(E^(-(x^z)))\[DifferentialD]x

%/.z->3

Visual form vs. Internal form

theboxes = "";InputField[Dynamic@theboxes,Boxes,ContinuousAction->True]

Dynamic@Style[theboxes,ShowStringCharacters->True]

Its all about boxes! Everything is a Box.

Generators and Graphics Boxes

All displayed graphics are actually boxes.

Graphics @ Table[Line @ {{Random[],Random[]},{Random[],Random[]}},{7}]

pts={{0,0},{1,1},{2,-1},{3,0}};

Graphics[{BezierCurve[pts],Green,Line[pts],Red,Point[pts]}]

Similarly all box control are also boxes:

3+Style[bob,FontSize->50]

Button["Hi There",Print @ "Hello"]

Slider[Dynamic[mn],{1,100,1}]

Dynamic[Factor[(y^mn)+1]]

MakeExpression & MakeBoxes

We need to be able to do computation with our boxes.

Generators are not sufficient.

Style[foo,FontSize->20]+Style[foo,FontSize->30]

Our goal is to introduce new notations which can do computations.

Evaluation Model

Parsing 	⟷ 	MakeExpression
Formatting 	⟷ 	MakeBoxes

(∂_y)Sin[y]

?MakeBoxes

?MakeExpression

Example Vectors

Consider a new notation for “Vectors” by underscripting by ‘~’ and having “FullForm” MyVector.

(Underscript[t, ~])

MyVector[t]

Typically in MakeExpression we transform to another MakeExpression of something Mathematica actually can make.

MakeExpression[UnderscriptBox[t_,"~"],StandardForm]:=
MakeExpression[RowBox[{"MyVector","[",t,"]"}],StandardForm]

In MakeBoxes we transform from expressions to boxes and we need to further call MakeBoxes on any subparts.

MakeBoxes[MyVector[t_],StandardForm]:=UnderscriptBox[MakeBoxes[t,StandardForm],"~"]

We can then define rules using this new notation.

MyVector/:(Underscript[t_, ~])+(Underscript[y_, ~]):=(Underscript[t+y, ~])

(Underscript[r, ~])+(Underscript[t, ~])

Maybe this notation is not the best since it’s visually ambiguous.

Decryptify[Code_ixm,code]

Trick: Often it is best to create the notation you want using the 2D editing tools in Mathematica and then just copy the underlying boxes.

ConvertTo uses MakeBoxes and Expression

Trick: You can use the menu Cell > Convert To > StandardForm (⌘⇧N) to format an expression in 2D. To enter tricky notations you can enter the full form of a notation and then convert the cell to StandardForm.

Conversions only work with syntactically valid structures.

Evaluation In MakeBoxes and Expression

You have to be very careful that we don’t let evaluation occur as a side effect of our transformations. (Mostly in MakeBoxes)

Example Function Notation

(a|->s)

Decryptify[Code_ygi,code]

Example Up and Down

Decryptify[Code_gcs,code]

Decryptify[Code_gcs,"fux"]

(b^↑)+(t^↓)

FullForm @ %

Example LegendreP

Decryptify[Code_fxi,code]

Example Format ‘List Of Lists’ as Matrix

{{2+2,a},{b,c}}

Answer

Decryptify[Code_qrs,code]

{{2+2,a},{b,c}}

Answer With Correct Holding

Now modeling your answer on how the TraditionalForm output looks, define a MakeBoxes rule which has the correct holding attributes

Decryptify[Code_fud,code]

{{2+2,a},{b,c}}

Tag Boxes

TagBoxes are invisible tags that have the form TagBox[boxes,tag]. tag can be any expression.TagBoxes are used to invisibly “tag” a box structure so we can identify it later.

( In Mathematica 8 we have now transitioned to TemplateBoxes in the vast majority of cases.)

TagBoxes are still used to guide interpretation in some cases. Eg Grid

Grid[{{a,b},{c,d}}]

MakeTemplate creates generalized placeholders. These placeholders are based on TagBoxes.

Plot

The ⇥ key takes you between placeholders.

Another example of TagBox usage is in event handlers (See Faisal & Lou’s talk). Or eg

We also hijack TagBoxes for MouseAppearance

MouseAppearance[bob, "x"]

Modified LegendreP

These are the MakeExpression and MakeBoxes rules from the last example on LegendreP

MakeBoxes[LegendreP[n_,x_],StandardForm]:=RowBox[{SubscriptBox["P",MakeBoxes[n,StandardForm]],"[",MakeBoxes[x,StandardForm],"]"}]

MakeExpression[RowBox[{SubscriptBox["P",n_],"[",arg_,"]"}],StandardForm]:=MakeExpression[RowBox[{"LegendreP","[",RowBox[{n,",",x}],"]"}],StandardForm]

Subscript[P,n][x]

(Subscript[P, n])[x]+1//FullForm

Ouch!

Decryptify[Code_jmg,code]

LegendreP[n,x]+1

FullForm @ %

However whatever you come up with here, the P is likely to be detachable from the rest of the notation, as well as having other problems. This gives rise to TemplateBoxes.

The Notation package

<<Notation`

The notation package allows us to automate the process that has been described for creating notations. A notation statement is of the form:
  Notation[ExternalForm ⟺ InternalForm]

Example: ring addition, ring multiplication.

a(Subscript[*, ℛ])b(Subscript[+, ℛ])c

FullForm @ %

Notation[a_(Subscript[+, ℛ])b_ ⟺ RingPlus[a_,b_]]
Notation[a_(Subscript[*, ℛ])b_ ⟺ RingTimes[a_,b_]]

Notation Package Functioning

The notation package internally is a notation compiler. It takes a box structure representing the notation to be compiled and returns the equivalent MakeBoxes and MakeExpression rules.

Notation[a_(Subscript[+, ℛ])b_ ⟺ RingPlus[a_,b_],Action->PrintNotationRules]
Notation[a_(Subscript[*, ℛ])b_ ⟺ RingTimes[a_,b_],Action->PrintNotationRules]

Example Up and Down Revisited

Quickly Entering Notations

Trick: You can quick create shortcuts for notations through an “add input alias” statement. (EscaddiaEsc)

AddInputAlias["opu"->(NotationTemplateTag[(\[SelectionPlaceholder]^↑)])]

BaseStyle

Lets revisit the previous example of vector with a shaded background. Assume we had put the style box around the whole underscript to yield a structure like the following:

RawBoxes @ StyleBox[UnderscriptBox["v","~"],Background->GrayLevel[0.8]]

So instead we can add the style into the base style.

RawBoxes @ UnderscriptBox["v","~",BaseStyle->{Background->GrayLevel[0.8]}]

Sometimes there are lots of styles we would like to add to the base style so we can just encapsulate all these styles into a new style and add that to the style sheet.

BaseStyle and DefaultBaseStyle are options to almost every box.

TemplateBoxes

Almost all composite typesetting in Mathematica is now done through TemplateBox. TemplateBox is:

TemplateBox[{(Subscript[box, 1]),(Subscript[box, 2]),...},tag]

is a low level box structure which displays as the DisplayFunction of the template box filled in with the (Subscript[box, i])

TemplateBox is low-level notebook structure used to represent a parameterized box structure. The DisplayFunction option of the TemplateBox is applied to the box arguments to yield a new box structure which is displayed.

The DisplayFunction option is normally specified on the style sheet in order that when the style sheet changes all displayed instances of the template box change uniformly.

If the tag of the TemplateBox is a string then that style will be used for the TemplateBox.

TemplateBoxes can be nested to any level

TemplateBox[{TemplateBox[{"n","x"},"LegendreP"],"b"},"Binomial"]//RawBoxes//TraditionalForm

You can write MakeBoxes and MakeExpression rules which use TemplateBoxes in order to define new notations.

Change Binomial Formatting

Consider the display function for traditional form typesetting of Binomial. How is this done?

Binomial[n,k]//TraditionalForm

RawBoxes @ TemplateBox[{"a","b"},"FooLegendreP",DisplayFunction:>(RowBox[{SubscriptBox["P",#1],"[",#2,"]"}]&),Tooltip->"MyLegendreP"]

Putting it on the StyleSheet

So consider the following:

c+RawBoxes @ TemplateBox[{"a","b"},"MyCommutator",DisplayFunction:>(RowBox[{"[",RowBox[{#1,",",#2}],"]"}]&)]

Note: the option template box option InterpretationFunction->Automatic means Mathematica chooses the tag name by default as the function name.

Decryptify[Code_kib,code]

Miscellaneous

I should talk here about precedence’s and SyntaxForm:

a+(∂_x)func+b

Also note that Graphics does context sensitive typesetting. Eg:

Point[{0,0}]

Graphics[ Point[{0,0}],ImageSize->50]

This is achieved by having the MakeExpression rules in Graphics be context sensitive.

Interesting Irrelevant note: The Mathematica box model to css box model, and BaseStyle to styles, ImageMargins, FrameMargins, to html margins and padding.

Conclusions

Steps to create a TemplateBox notation:

Enter a structure in 2D typesetting.

Copy the boxes for that structure into a display function replacing the arguments you want parameterized with #n

Put the resulting style on the style sheet.

Create a MakeBoxes rule for the given notation.

Bonus points: create an input alias for the notation.