The Logging Mechanism for Experiments in Undergraduate Mathematics by Phillip Kent, Phil Ramsden and John Wood May 1995 Extracted from ``Recording and Evaluating Student Interactions with Mathematica'', by Phillip Kent, Phil Ramsden, John Wood and Richard Noss. "Mathematica in Education and Research", Volume 5, 1996. URL for this document: http://metric.ma.ic.ac.uk/Logging.html ------------------------------------------------------------------------------- How the mechanism works ======================= $PreRead is a special system variable that allows one to operate on each input to Mathematica at the stage in the evaluation process at which it is held as a text string; $Pre operates at the next stage where the input has been converted to an expression. We use $PreRead, for reasons given below, but there could be other interesting recording strategies based on $Pre. Here is an example of the use of $PreRead-this is a ``pure'' function where the ``slot'' # will contain the input string being evaluated: $PreRead= ( If[StringMatchQ[#,"Abracadabra"], Print["You typed the magic word. Greetings, O Master!"]]; #) & Having evaluated this assignment, Mathematica will respond appropriately when ``Abracadabra'' is typed. The command $PreRead = . will clear this assignment. Note that we can do anything we want within the $PreRead function without interfering in the evaluation process so long as the output of the function is just the input string ``#''. To use $PreRead in a recording mechanism there are two distinct steps. First, to decide if an input should be recorded; second, to record it: $PreRead = (If[, ]; #) & We wanted a mechanism with the flexibility to record either inputs containing a command name from a specified list (in the EUM modules we have deployed many custom commands and are interested to know when and how students use them), or all inputs. We also needed to be able to switch from one mode to the other, or to modify the command name list, dynamically during a Mathematica session. By acting on strings via $PreRead we can record the use of a certain function wherever it is used in an input, simply by doing a substring match. For example: StringMatchQ[#, "*Sin*"] (``*'' is the wildcard symbol for any character sequence) will work equally against the inputs Sin[Pi/5], N[Sin[Pi/5]] and Cos[x]^2 + Sin[x]^2. With $Pre one would need to work somewhat harder to do this. Basically, by choosing to act on input strings we are ignoring the syntactical structure of inputs, and this has the benefit that the things we choose to record need not be functions at all, but can be variable names, numbers and even strings within the input text. In situations where the syntactical structure is of interest, one could devise a mechanism similar to the one set out below but using $Pre, MatchQ and the other pattern-matching functions. The second step in the recording mechanism, saving the text string that we want to record in a file, is a relatively straight-forward process. We have defined a command WriteToLog to insert a line of data into the record file; its definition depends on the operating system in which Mathematica is working because of differences in the way that Mathematica's file manipulation commands behave in each operating system (see the code of StartUp.m for the details). The $PreRead function is assigned in two ways, according to whether all inputs are to be recorded, or a selection. In the first case: $PreRead = LogAllFunction where: LogAllFunction = (If[Not[# === ""], WriteToLog[{$Line,#}]]; #) & Every non-empty string will be recorded, and we also insert the value of the system variable $Line to record the ``In/Out'' number of each input. In the second case we set: $PreRead = LogSelectiveFunction LogSelectiveFunction = (If[LogCommandCall[#], WriteToLog[{$Line,#}]]; #) & LogCommandCall[s_String]:= Apply[Or, Map[StringMatchQ[s,"*"<>#<>"*"]&, logTheseCommandsList]] Here, the input is passed through the logical function LogCommandCall which performs a sub-string match against each of the strings defined in logTheseCommandsList. This produces a list containing True or False values and then by applying Or to the list we will get True if one or more of the values in the list is True, that is, the input matched against one or more elements of logTheseCommandsList. The recording mode can be changed at any time during a Mathematica session with a function that we've called Transcript. This is intended for use by observers wishing to make complete recordings in support of detailed observation of a student, or simply to capture anything going on that looks interesting. To switch from selective recording to complete recording, one types in Transcript[All], which is defined as: Transcript[All] := ( $PreRead = LogAllFunction; Return[logTheseCommandsList = {"*"}] (Note that logTheseCommandsList is set to the wild-card * for completeness' sake though it is not actually used.) To switch off complete recording, one can do Transcript[Default] to revert to the default commands list specified at the start of the session (see below for an example): Transcript[Default] := ( $PreRead = LogSelectiveFunction; Return[logTheseCommandsList = defaultLogCommandsList] ) Finally, here are the other Transcript functions: Transcript[None] := ( (*log no commands*) $PreRead = .; Return[logTheseCommandsList={}] ) Transcript[l_List] := ( (*log given list of commands*) $PreRead = LogSelectiveFunction; Return[logTheseCommandsList = l] ) Transcript[Add, new_List] := ( (*add new commands to the list*) $PreRead = LogSelectiveFunction; Return[logTheseCommandsList = Join[logTheseCommandsList, new]] ) Transcript[Status] := ( (*display the current list and LogFile*) Print["logfile = ",LogFile]; Return[logTheseCommandsList] ) Implementation in the EUM modules ================================= The EUM modules are structured according to conventional mathematical subject divisions, with between one and three modules covering each subject. Each module contains a set of experiments in which students are invited to explore and construct for themselves pieces of mathematical theory. For each subject we have prepared a package of custom functions to support the experiments, and we also expect students to use built-in commands where appropriate. Each package specifies at its head a default list of commands to be recorded, for example in diffpack.m: (* Run Start-up code *) NotebookCode="DF" defaultLogCommandsList = {"GiveQuestion","LastAnswer", "StraightLinesPicture","PlotChord","tangentGradient", "PlotWithSP","ImplicitPlot","ImplicitPictures"} <