Skip to main content

front end - What is the complete sequence of evaluations/transformations from submitting a cell to actual evaluation?


This question is inspired by that one. Reading it, I noticed that while (I think) I know what happens when entering an expression directly to the kernel (i.e. after typing math in the terminal), the notebook adds extra complications which I don't fully understand.


To start with, I describe what I think happens when interacting directly with the Kernel (so you can correct me if I'm wrong):



  • After the expression is input, it first is a string, which is passed to $PreRead (if set). That function is expected to return a string, which gets assigned to InString[$Line].

  • Then this string is parsed (I guess with MakeExpression), and the resulting expression assigned to In[$Line]

  • Then $Pre is applied to this expression, if defined.


  • Finally, the expression obtained this way is evaluated


(After the expression is evaluated, other things happen to generate the output, but that's outside the scope of this question.)


Now, for Notebooks, things are obviously more complicated:



  • To start with, as far as I understand, the notebook cells contain boxes, not strings. However I noticed that nevertheless InString is set. What is not clear to me is whether this string is part of the processing, or if the boxes-to-string conversion is only done in order to set InString.

  • Next, there's the Notation package, which also is involved in the pre-evaluation process. However being a package, I guess it has to hook into some lower-level interface to do its work.

  • There's also the fact that notebooks can define their own private contexts. Those contexts also have to somehow be communicated to the kernel. Since expressions from different notebooks can be sent to the kernel in arbitrary order, those contexts need to be associated with the expression, and setting them must thus be part of expression pre-evaluation.

  • There might be other things which I'm not aware of.



Therefore my question is:


What is the exact sequence of events which happens when submitting a notebook cell, as far as customizable behaviour is concerned?



Answer



Preamble


I will interpret your question in the narrow context of customizibility. Most of the information can be found in the documentation, but is alas scattered over several places. Below I will attempt to assemble a single sequence, mostly using this source. Where my description deviates from it, I will put the LS sign indicating that what follows ismy interpretation. Also, I have to make a disclaimer that some parts of this I haven't tested thoroughly enough to be fully sure that I am 100 percent correct, so I invite anyone to edit this if some mistakes are found.


Evaluation sequence


With that out of the way, here is what I believe is a reasonably accurate description of what happens when you press SHIFT+ENTER to evaluate a cell in the FrontEnd session:




  • Evaluate CellProlog, if defined for a given cell (LS: CellProlog is an option for the cell which defines a piece of code to evaluate, not a function of the input).





  • Evaluate CellEvaluationFunction, if defined for a given cell



    • In a StandardForm or TraditionalForm cell, CellEvaluationFunction is applied to the BoxData expression representing the input to be evaluated.

    • In an InputForm cell, it is applied to the string corresponding to the input to be evaluated.


    LS: In all cases, this is a function which is applied to the input (string or boxes). At this point, one can divert the entire evaluation loop as one wants, including evaluations not involving Mathematica kernel at all (e.g. code in other languages, processed externally. See this excellent answer by WReach for the exposition of the possibilities this offers).


    All the steps below assume the default CellEvaluationFunction, which is Identity





  • Read in input (LS: in a string or boxes form, presumably depends on the cell type).




  • Apply $PreRead function, if defined, to the input string (LS: also for a box expression if an input is read as boxes. Note that if CellEvaluationFunction has been defined and still calls the kernel to evaluate the result, then $PreRead is applied to the result of CellEvaluationFunction execution).




  • Print syntax warnings if necessary.





  • Apply $SyntaxHandler function if there is a syntax error.




  • LS: Call MakeExpression to create an expression from boxes




  • LS: As a part of expression creation, call $NewSymbol on every new symbol to be created, then create that symbol. The choice of context where the symbol is created is based on the current (at the time of symbol's creation) values of $Context and $ContextPath. Obviously, cell and notebook contexts, when enabled, must be communicated to the kernel as a part of the cell evaluation process. That this is indeed the case, you can confirm by evaluating $Context variable in such a cell. How and at which stage this is done I don't know, perhaps someone will add this info.




  • Assign InString[n].





  • Apply $Pre function, if defined, to the input expression.




  • Assign In[n].




  • Evaluate expression which is a process with many steps as explained at here.





  • Apply $Post function, if defined.




  • Assign Out[n], stripping off any formatting wrappers.




  • Apply $PrePrint function, if defined.





  • Assign MessageList[n] and clear $MessageList.




  • Print expression, if it is not Null.




  • Increment $Line.




  • Clear any pending aborts.





  • Evaluate CellEpilog, if defined for a given cell.




Notation` package


The Notation` package hooks into MakeExpression. What this means is that the notation changes one can do with it are limited to what is possible to do on the level of fully parsed boxes, rather than strings. In other words, your input must represent a syntactically valid string of Mathematica code, for the purposes of parsing to boxes.


This means that there will be a number of things you can not do, such as change the precedence of operators, or introduce syntax which won't normally parse to boxes. Generally, this means that you can not assign custom string syntax, rather you can somewhat augment Mathematica's one, within what can be done on the box level.


Another limitation of Notation` is that, since it is based on MakeExpression, and the latter is not called by Get (which is called to read in packages), Notation` will not work for packages without some extra work-arounds. One such work-around I suggested here. While it is really a rather ugly hack, it illustrates the way Notation` works, to some extent. More information about the workings of Notation` can be obtained, of course, by reading the source code of Notation.m.


Further information



Some additional sources of information include



  • Reference pages for the functions or options such as CellProlog,CellEpilog, CellEvaluationFunction, etc.

  • A good brief (but dated) description is the 1992 WRI technical report "Mathematica internals" by David Withoff (available online as .pdf).

  • Some interesting investigations on the order of some of the operations here were carried out by Alexey Popkov in this question.


Remarks


I am almost certain that I missed or misrepresented something, simply because I don't have a lot of personal experience with all this steps, or exhaustive tests performed to test this description. If you found a mistake, feel free to edit.


Comments

Popular posts from this blog

plotting - Filling between two spheres in SphericalPlot3D

Manipulate[ SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, Mesh -> None, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], {n, 0, 1}] I cant' seem to be able to make a filling between two spheres. I've already tried the obvious Filling -> {1 -> {2}} but Mathematica doesn't seem to like that option. Is there any easy way around this or ... Answer There is no built-in filling in SphericalPlot3D . One option is to use ParametricPlot3D to draw the surfaces between the two shells: Manipulate[ Show[SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], ParametricPlot3D[{ r {Sin[t] Cos[1.5 Pi], Sin[t] Sin[1.5 Pi], Cos[t]}, r {Sin[t] Cos[0 Pi], Sin[t] Sin[0 Pi], Cos[t]}}, {r, 1, 2 - n}, {t, 0, Pi}, PlotStyle -> Yellow, Mesh -> {2, 15}]], {n, 0, 1}]

plotting - Plot 4D data with color as 4th dimension

I have a list of 4D data (x position, y position, amplitude, wavelength). I want to plot x, y, and amplitude on a 3D plot and have the color of the points correspond to the wavelength. I have seen many examples using functions to define color but my wavelength cannot be expressed by an analytic function. Is there a simple way to do this? Answer Here a another possible way to visualize 4D data: data = Flatten[Table[{x, y, x^2 + y^2, Sin[x - y]}, {x, -Pi, Pi,Pi/10}, {y,-Pi,Pi, Pi/10}], 1]; You can use the function Point along with VertexColors . Now the points are places using the first three elements and the color is determined by the fourth. In this case I used Hue, but you can use whatever you prefer. Graphics3D[ Point[data[[All, 1 ;; 3]], VertexColors -> Hue /@ data[[All, 4]]], Axes -> True, BoxRatios -> {1, 1, 1/GoldenRatio}]

plotting - Mathematica: 3D plot based on combined 2D graphs

I have several sigmoidal fits to 3 different datasets, with mean fit predictions plus the 95% confidence limits (not symmetrical around the mean) and the actual data. I would now like to show these different 2D plots projected in 3D as in but then using proper perspective. In the link here they give some solutions to combine the plots using isometric perspective, but I would like to use proper 3 point perspective. Any thoughts? Also any way to show the mean points per time point for each series plus or minus the standard error on the mean would be cool too, either using points+vertical bars, or using spheres plus tubes. Below are some test data and the fit function I am using. Note that I am working on a logit(proportion) scale and that the final vertical scale is Log10(percentage). (* some test data *) data = Table[Null, {i, 4}]; data[[1]] = {{1, -5.8}, {2, -5.4}, {3, -0.8}, {4, -0.2}, {5, 4.6}, {1, -6.4}, {2, -5.6}, {3, -0.7}, {4, 0.04}, {5, 1.0}, {1, -6.8}, {2, -4.7}, {3, -1.