# How to cache the results of a macro

TeX's ability as a programming language can be leveraged to produce documents that include fairly sophisticated calculations. Although not everybody's cup of tea, such documents are akin to literate programming in that you can describe what you are about to calculate, as well as perform the calculation.

In How to typeset large numbers, I used a simple macro to calculate the Mersenne prime for 1279, which took a few seconds to compile. (This is also noticeably slow using other scripting languages with big integer libraries).

How can I cache the result from a macro, so that the calculation is not repeated in following runs?

I was thinking of something using \pdfmdfivesum to create a hash for a filename and use this to cache the results. The reason for the hash is that one might want to call the macro with different values - so the md5 hash can for example be the macro name plus a value.

-

If the output of a macro is fully expandable I would store it in another macro which is also written to the .aux file. The name of that storage macro should be generic so that the calculation macro can test if it exists and use simply reuse it if so. You could use MD5 checksums calculated from the input as part of the macro names if the input is something which would cause issues inside \csname ... \endcsname, but for e.g. numbers this isn't necessary.

Using your Mersenne calculation as example:

\documentclass{article}
\usepackage[english]{babel}
\usepackage{numprint}
\usepackage{bigintcalc}
\begin{document}
\npthousandsep{ }
\makeatletter
\def\Mersenne#1{%
\begingroup
\par\noindent\parindent=0pt
$M_{#1}=$\par
% Calculate if not defined yet
\@ifundefined{Mersenne@#1}{%
\def\exponent##1{\bigintcalcPow{2}{##1}}%
\expandafter\xdef\csname Mersenne@#1\endcsname{%
\bigintcalcSub{\exponent{#1}}{1}%
}%
}{}%
% Write to aux file
\immediate\write\@auxout{\noexpand\expandafter\gdef\noexpand\csname Mersenne@#1\noexpand\endcsname{\csname Mersenne@#1\endcsname}}%
% Print
\expandafter\numprint\expandafter{\csname Mersenne@#1\endcsname}%
\endgroup
}
\makeatother

\Mersenne{1279}
\end{document}


The .aux file then contains the following line and future recalculations are avoided as long the .aux isn't deleted or not written properly due to a compilation error:

\expandafter \gdef \csname Mersenne@1279\endcsname {10407932194664399081925240327364085538615262247266704805319112350403608059673360298012239441732324184842421613954281007791383566248323464908139906605677320762924129509389220345773183349661583550472959420547689811211693677147548478866962501384438260291732348885311160828538416585028255604666224831890918801847068222203140521026698435488732958028878050869736186900714720710555703168729087}


If the the output of the macro is not fully expandable or even fragile (i.e. \edef would cause errors) it might be stored inside a box register instead. But this has several drawbacks: It can't be stored in the .aux file easily so the reuse is limited for several usages of the same macro in one compilation run. Also the typesetting is then fixed and e.g. the line breaking for long numbers won't be specific for each usage.

-
A similar form of buffering is used in my answer to Automatically avoid broken internal hyperlinks. –  Martin Scharrer Apr 17 '11 at 18:41
Thanks. Wouldn't storing it in a file on its own in this case be better, as you will avoid normal re-runs for references and the like? –  Yiannis Lazarides Apr 17 '11 at 18:45
@Yiannis: I'm not sure what you mean. You wouldn't need to recalculate it when you have references or anything else which requires reruns. In the first run the macro is calculated and written into the .aux file and in future runs it is read from there at-begin-document and then written into the new .aux file again when the macro is used. One drawback of using that file is when someone would delete the .aux file or if it isn't written completely because of an error. In this case you could simply create your own file for all the calculations. –  Martin Scharrer Apr 17 '11 at 18:51
sorry I see what you mean, it is getting late here and was a long day. Thanks again for the help. –  Yiannis Lazarides Apr 17 '11 at 19:23