[Tex/LaTex] Showcase of “programming your document” paradigm

big-listexamplesscripts

A feature of latex is that you can "program your document". You can do this by using TeX/LaTeX directly (remember that it is Turing complete) or by other languages like lua or python (especially sage) or other languages where a package exists to use that code to program in latex. In particular TeX or lua is heavily used when developing a new package.

However I want examples which show this "paradigm" from the point of view of a user.

The examples should be at best real use cases. For example if you have made use of this paradigm to set up a nice document using loops and other programming features in the past and you are (a bit) proud of it, please post it. It is also welcome if you come up with new examples just for this question.

Please post the source code and the result. It would be nice if you could pay attention to commented, clean (perhaps elegant) source code.

I think great answers to this would be both educational and inspiring and would also provide further arguments why to prefer LaTeX over other software for example some text-processors…

Best Answer

I'm not sure if this is appropriate, but in the distant past, before I was aware of packages like Tikz, I wrote some routines for performing arithmetic operations in plain TeX using dimensions (plain TeX can do this also, but discards remainders).

I apologize for the, most likely, horrendous code.

Here are some utility macros (these are used for other routines I've made. Some of these may not be used in what follows):

    \catcode`\!=11               % To help prevent macros being redefined in the main document
    \catcode`\@=11               %

    \def\dlap#1{\vbox to 0pt{#1\vss}}      \def\ulap#1{\vbox to 0pt{\vss#1}}
    \def\chlap#1{\hbox to 0pt{\hss#1\hss}} \def\cvlap#1{\vbox to 0pt{\vss#1\vss}}
    \def\clap#1{\chlap{\cvlap{\hbox{#1}}}}

    %  List/token manipulatuion routines
    %  See The TeXboox, pg. 378-379
    %
    \toksdef\ta=0 \toksdef\tb=2 %
    \long\def\leftappend#1\to#2{\ta={\\{#1}}\tb=\expandafter{#2}%
             \edef#2{\the\ta\the\tb}}
    \long\def\rightappend#1\to#2{\ta={\\{#1}}\tb=\expandafter{#2}%
             \edef#2{\the\tb\the\ta}}
    \def\concat#1=#2&#3{\ta=\expandafter{#2}\tb=\expandafter{#3}%
             \edef#1{\the\ta\the\tb}}
    \def\lopl#1{\expandafter\lopoffl#1\lopoffl#1\to}      
    \long\def\lopoffl\\#1#2\lopoffl#3\to{\gdef#3{#2}{#1}}
    \def\lop#1\to#2{\expandafter\lopoff#1\lopoff#1#2}     
    \long\def\lopoff\\#1#2\lopoff#3#4{\def#4{#1}\def#3{#2}}
    \def\alop#1\to#2{\expandafter\alopoff#1\alopoff#1#2}     
    \long\def\alopoff\\#1#2\alopoff#3#4{\global#4=#1\def#3{#2}}
    \def\select#1\of#2\to#3{\def#3{\outofrange}%
        \long\def\\##1{\advance#1-1 \ifnum#1=0 \def#3{##1}\fi}#2}
    \def\assign#1\of#2\to#3{%
        \long\def\\##1{\advance#1-1 \ifnum#1=0 \global#3=##1\fi}#2}
    \def\card#1\to#2{#2=0 \long\def\\##1{\advance#2 by1 }#1}
    \def\outofrange{}
    \def\sevenea{\expandafter\expandafter\expandafter\expandafter
        \expandafter\expandafter\expandafter}              
    \def\length#1\to#2{{\count0=0 \getlength#1\end \global#2=\the\count0 }}
    \def\getlength#1{\ifx#1\end \let\next=\relax
        \else\advance\count0 by1 \let\next=\getlength\fi \next}
    {\catcode`p=12 \catcode`t=12 \gdef\GrabI#1.#2pt{#1} \gdef\GrabD#1.#2pt{#2}}
    \def\ItPart#1{\expandafter\GrabI\the#1}
    \def\DecPart#1{\expandafter\GrabD\the#1}
\def\GRLABEL#1(#2,#3){\ulap{\vbox{\rlap{\kern#2\relax#1}\kern#3\relax}}}

Here are the (very much unoptimized) math routines:

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %                                                                            %
    %                            MATH ROUTINES                                   %
    %                                                                            %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    \newcount\!!!     
    \newdimen\t@mpthree
    \newdimen\t@mp
    \newdimen\t@mptwo
    \newcount\k@
    \newcount\j@
    \newcount\l!
    \newcount\R@M
    \newcount\S!GN
    \newtoks\@ns
    %
    %
    %   Multiplication/Division routines
    %
    %
    \def\MulDim#1#2\to#3{#3=\ItPart{#1}.\DecPart{#1}#2}
    \def\DivDim#1#2\to#3{{\l!=\ItPart{#1}\DecPart{#1}\j@=\ItPart{#2}\DecPart{#2}% 
        \ifdim#1=0.0pt\global#3=0.0pt    %added global 0ct 16 2010
        \else
             \ifnum\l!<0 \ifnum\j@<0 \S!GN=1 \l!=-\l! \j@=-\j@ \else\l!=-\l! \S!GN=-1 \fi
                   \else\ifnum\j@<0 \j@=-\j@ \S!GN=-1 \else\S!GN=1 \fi
        \fi
        \sevenea\length\DecPart{#2}\to\k@ \sevenea\length\DecPart{#1}\to\!!! 
        \ifnum\!!!<\k@ \advance\k@ by-\!!! 
              \multiply\l! by\ifcase\k@ 1 \or10 \or100 \or1000 \or10000 \or100000\fi
        \else\advance\!!! by-\k@     
             \multiply\j@ by\ifcase\!!! 1 \or10 \or100 \or1000 \or10000 \or100000\fi  
        \fi
        \k@=\l! \divide\k@ by \j@ \@ns=\expandafter{\the\k@.}%
        \R@M=\k@ \multiply\R@M by-\j@ \advance\R@M by \l!
        \G@TN@XT\G@TN@XT\G@TN@XT\G@TN@XT\G@TN@XT\G@TN@XT\G@TN@XT  
            \global#3=\the\@ns pt \global\multiply#3 by \S!GN \fi}}
    \def\G@TN@XT{%
        \ifnum\R@M=0
        \else\multiply\R@M by 10 \k@=\R@M \divide\k@ by \j@  
             \edef\tmp{\the\@ns \the\k@}\@ns=\expandafter{\tmp}%  
             \multiply\k@ by\j@ \advance\R@M by -\k@
        \fi}
    \def\MidPoint#1#2\to#3{\t@mp=#2\advance\t@mp-#1\divide\t@mp by2%
                                                          \advance\t@mp#1#3=\t@mp}
    %
    %  Cosine\Sin routine
    %
    %
    \def\Cos#1\to#2{\S!GN=1\ifdim#1<0.0pt#2=-#1\else#2=#1\fi
        \loop\ifdim#2>6.2831853072pt\advance#2-6.2831853072pt\repeat
        \ifdim#2<4.7123889804pt\ifdim#2>1.5707963268pt\advance#2-3.14159265pt%
                                                                  \S!GN=-1 \fi\fi
            \ifdim#2<6.2831853072pt\ifdim#2>4.7123889804pt\advance#2-6.2831853072pt%
                                                                  \fi\fi                                                                                                
        \MulDim#2#2\to\t@mp
        #2=.0178571\t@mp\advance#2-1pt
        \MulDim\t@mp{#2}\to{#2}#2=0.033333333 #2\advance#21pt
        \MulDim\t@mp{#2}\to{#2}#2=0.083333333 #2\advance#2-1pt
        \MulDim\t@mp{#2}\to{#2}#2=0.50000 #2\advance#21pt\global #2=\S!GN #2}
    \def\Sin#1\to#2{\t@mptwo=#1\advance\t@mptwo by-1.5707963268pt\Cos\t@mptwo\to{#2}}
\catcode`\!=12
\catcode`\@=12 

(Incidentally, I was particularly proud of using a "seven \expandafter" in the \DivDim routine. I wonder if it's needed...)

One application of these routines is to produce graphs. Here are some macros I made to produce polar curves:

\newcount\iii
\newdimen\tempx
\newdimen\tempy
\newdimen\Slope
\newdimen\temp
\newdimen\temptwo
\newdimen\tempthree
\newdimen\tempfour
\newdimen\cinc
\newdimen\x
\setbox46\hbox{{\kern-.1pt\vrule width.6 pt height .4pt depth0pt}}
\setbox48\hbox{{\kern-.1pt\vrule width.6 pt height .4pt depth0pt}}
    %
    %    Sketch the graph of r=#1(#2+#3 cos(#4 \theta) from theta = #5 to #6.  #7 controls the resolution (higher for finer resolution) )
    %    The produced size will be r_max=#1*(#2+#3) points.  Arguments are numbers (no ''pt'')
    %
    \newdimen\ct\newdimen\st
    \def\CosPolarGraph#1#2#3#4#5#6#7{% 
          \x=#5 pt  
                \temptwo=#7pt \ifdim\temptwo<0 pt \temptwo=-\temptwo\fi \cinc=.01pt \DivDim\cinc\temptwo\to\cinc 
                \temp=#4pt 
                \tempthree=#3 pt
          \loop\ifdim\x<#6pt%
                     {\Cos{\x}\to\ct 
                        \Sin{\x}\to\st  
                        \MulDim\temp\x\to\tempfour              %
                        \Cos\tempfour\to\tempfour               %   compute r
                        \MulDim\tempfour\tempthree\to\tempfour  %
                        \tempthree=#1 pt                        % 
                        \advance\tempfour by #2 pt              % 
                        \MulDim\tempfour\tempthree\to\tempfour  %
                        \MulDim\st\tempfour\to\tempy
                        \MulDim\ct\tempfour\to\tempx
                        \GRLABEL{\copy46}(\tempx,\tempy)}%
                      \advance\x by \cinc
           \repeat} 
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    %
    %    Sketch the graph of r=#1(#2+#3 sin(#4 \theta) from #5 to #6.  #7 controls the resolution (higher for finer resolution) )
    %    The produced size will be r_max=#1*(#2+#3) points.  Arguments are numbers (no ''pt'')
    %                                                                       
    \def\SinPolarGraph#1#2#3#4#5#6#7{%  
          \x=#5 pt  
                \temp=#7pt \ifdim\temp<0 pt \temp=-\temp\fi \cinc=.01pt \DivDim\cinc\temp\to\cinc 
                \loop\ifdim\x<#6pt%
                     {\temp=#4pt
                      \MulDim\temp\x\to\tempfour              %
                        \Sin\tempfour\to\tempfour               % 
                        \temp=#3 pt                             %   compute r
                        \MulDim\tempfour\temp\to\tempfour       %
                        \temp=#1 pt                             % 
                        \advance\tempfour by #2 pt              % 
                        \MulDim\tempfour\temp\to\tempfour       %%%%%
                        \Sin{\x}\to\temp
                        \MulDim\temp\tempfour\to\tempy           
                        \Cos{\x}\to\temp                            
                        \MulDim\temp\tempfour\to\tempx           
                        \GRLABEL{\copy46}(\tempx,\tempy)}%
                      \advance\x by \cinc
           \repeat}     
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % Archimedian Spiral. Sketch the graph of r=#1 * \theta from #2 to #3  
    %
    %                           
    \def\Spiral#1#2#3{% 
          \x=#2 pt% 
                \cinc=.01pt%  
                \loop\ifdim\x<#3pt%
                     \temp=#1pt
                      \MulDim\temp\x\to\tempfour                   % Compute r
                        {\Sin{\x}\to\temp
                        \MulDim\temp\tempfour\to\tempy                
                        \Cos{\x}\to\temp                            
                        \MulDim\temp\tempfour\to\tempx                
                        \GRLABEL{\copy46}(\tempx,\tempy)}%
                      \advance\x by \cinc
           \repeat}                                                                                 
    %%%%%%%%%%%%        

Here is some sample output (which looks much better than the screen capture would indicate)

enter image description here

The command \SinPolarGraph{8}{.5}{-2}{3}{0}{6.28}{2}, for example, produced the "nested rose" in the "Other" box (TeX needs to be in horizontal mode when \SinPolarGraph is called). Here is a close up:

enter image description here

All done using only plain TeX!