Insert correct checksums.
[mdwtools] / exercise.dtx
CommitLineData
86f6a31e 1% \begin{meta-comment}
2%
3% $Id: exercise.dtx,v 1.1 2002/02/03 20:49:03 mdw Exp $
4%
5% Exercises
6%
7% (c) 2001 Mark Wooding
8%
9%----- Revision history -----------------------------------------------------
10%
11% $Log: exercise.dtx,v $
12% Revision 1.1 2002/02/03 20:49:03 mdw
13% Checkin for new build system.
14%
15%
16% \end{meta-comment}
17%
18% \begin{meta-comment} <general public licence>
19%%
20%% exercise package -- useful macros for setting exercises with answers
21%% Copyright (c) 2001 Mark Wooding
22%%
23%% This program is free software; you can redistribute it and/or modify
24%% it under the terms of the GNU General Public License as published by
25%% the Free Software Foundation; either version 2 of the License, or
26%% (at your option) any later version.
27%%
28%% This program is distributed in the hope that it will be useful,
29%% but WITHOUT ANY WARRANTY; without even the implied warranty of
30%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31%% GNU General Public License for more details.
32%%
33%% You should have received a copy of the GNU General Public License
34%% along with this program; if not, write to the Free Software Foundation,
35%% Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
36% \end{meta-comment}
37%
38% \begin{meta-comment} <Package preambles>
39%<+package>\NeedsTeXFormat{LaTeX2e}
40%<+package>\ProvidesPackage{exercise}
41%<+package> [2001/09/21 1.0 Exercies with answers]
42% \end{meta-comment}
43%
44% \CheckSum{236}
45%% \CharacterTable
46%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
47%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
48%% Digits \0\1\2\3\4\5\6\7\8\9
49%% Exclamation \! Double quote \" Hash (number) \#
50%% Dollar \$ Percent \% Ampersand \&
51%% Acute accent \' Left paren \( Right paren \)
52%% Asterisk \* Plus \+ Comma \,
53%% Minus \- Point \. Solidus \/
54%% Colon \: Semicolon \; Less than \<
55%% Equals \= Greater than \> Question mark \?
56%% Commercial at \@ Left bracket \[ Backslash \\
57%% Right bracket \] Circumflex \^ Underscore \_
58%% Grave accent \` Left brace \{ Vertical bar \|
59%% Right brace \} Tilde \~}
60%%
61%
62% \begin{meta-comment}
63%
64%<*driver>
65\input{mdwtools}
66\describespackage{exercise}
67\let\epsilon\varepsilon
68\mdwdoc
69%</driver>
70%
71% \end{meta-comment}
72%
73%^^A-------------------------------------------------------------------------
74% \section{User guide}
75%
76% The \package{exercise} package allows you to typeset exercises and keep the
77% answers together with the questions in your source (so they don't get
78% lost) but typeset them all together at the end of your document.
79%
80% \subsection{Exercises and answers}
81%
82% \DescribeEnv{exercise}
83% Exercises are typset in an \env{exercise} environment. This takes no
84% arguments. There's a counter for exercises, named |exercise|, and you can
85% cross-reference exercises in the usual way.
86%
87% \DescribeMacro\answer
88% If you want to include an answer for your exercise, just say |\answer|
89% followed by your answer. The rest of the text up to the end of the
90% \env{exercise} environment is considered to be the answer, and is stored
91% away until asked for. This material can contain anything you like. It
92% \emph{isn't} a moving argument.
93%
94% \begin{figure}
95%\begin{demo}[w]{The \env{exercise} environment}
96%\begin{exercise}
97%Show that if $F\colon \{0, 1\}^k \times \{0, 1\}^* \to \{0, 1\}^L$
98%is a $(t, q + 1, \epsilon)$-secure PRF, then $F$~is also a
99%$(t, q, \epsilon + 2^{-L})$-secure MAC.
100%\answer
101%Let~$A$ be an adversary attacking~$F$ as a MAC. Consider the
102%adversary~$B$ \ldots
103%\end{exercise}
104%\end{demo}
105% \end{figure}
106%
107% \subsection{The answers file}
108%
109% \DescribeMacro\answrite
110% Answers are accumulated into a file, to be read later. Additional material
111% can be added to the file using the |\answrite| macro, which just writes its
112% argument. Note that this is a \emph{moving} argument, so fragile commands
113% need |\protect|ing.
114%
115% \DescribeMacro\exctrcheck
116% It's common to divide up the answers by section. You can tell the package
117% to check a collection of counters and perform actions if they've changed
118% since last time, giving you a chance to write the correct decorations to
119% the answers file. This is done by saying
120% \syntax{"\\exctrcheck{"<counter>"}{"<action>"}"}. Then, each |\answer|
121% command checks to see if \<counter> has changed since last time, and if it
122% has, it does \<action>, For example,
123%\begin{verbatim}
124%\exctrcheck{section}
125% {\answrite{\protect\subsection*{Section \thesection}}}
126%\end{verbatim}
127% starts a new (unnumbered) subsection in the answers for each section in the
128% main document.
129%
130% \subsection{Style tweaks}
131%
132% The \env{exercise} environment is very simple, and can be easily rewritten
133% to fit in with your style preferences. If you like exercises to look like
134% theorems, the easiest thing to do is say something like
135%\begin{verbatim}
136%\newtheorem{doexercise}[exercise]{\exercisename}
137%\renewenvironment{exercise}{\exfix\doexercise}{\enddoexercise}
138%\end{verbatim}
139% This makes the environment use the existing exercise counter. If you don't
140% want that, say
141%\begin{verbatim}
142%\newtheorem{doexercise}[othercounter]{\exercisename}
143%\renewenvironment{exercise}{\exfix\doexercise}{\enddoexercise}
144%\let\theexercise\theothercounter
145%\end{verbatim}
146% and all will be well.
147%
148% \DescribeEnv{doanswer}
149% Answers are typeset in a \env{doanswer} environment, which is given one
150% argument: the exercise number (as set by |\theexercise|). This can be
151% modified to do whatever you like.
152%
153% \DescribeMacro\exfix
154% The |\exfix| is a convenient hook which is run both in the \env{exercise}
155% and \env{doanswer} environments by default. The current implementation
156% just skips a level of \env{enumerate} depth, which usually means that
157% \env{enumerate} lists will go (a), (b), (c), \ldots\ rather than 1, 2, 3,
158% \ldots
159%
160% \subsection{Lists in paragraphs}
161%
162% \DescribeEnv{parenum}
163% Answers to subparts tend to be compressed together into a single
164% paragraph. It's nice, when you do this, not to have to worry about losing
165% your numbering of subparts. The \env{parenum} environment provides an
166% enumerated list in a paragraph. So, for example, you can say something
167% like this.
168%\begin{demo}[w]{Example of \env{parenum}}
169%\begin{exercise}
170%A PRG $g\colon \{0, 1\}^k \to \{0, 1\}^L$ is \emph{trivial} if
171%$k \ge L$.
172%\begin{enumerate}
173%\item Show that trivial PRGs exist.
174%\item Show that a non-trivial $(t, \epsilon)$-secure PRG is a
175% $(t, \epsilon + 2^{k-L})$-secure one-way function.
176%\end{enumerate}
177%\answer
178%\begin{parenum}
179%\item The identity function is a trivial PRG: the real and random
180% games are identically distributed.
181%\item Let~$A$ be an adversary attempting to invert~$g$: then we
182% can construct a distinguisher~$B$ as follows \ldots
183%\end{parenum}
184%\end{exercise}
185%\end{demo}
186%
187% \subsection{And finally}
188%
189% \DescribeMacro\answers
190% In order to extract your answers, say |\answers|.
191%\begin{demo}[w]{The \texttt{\string\answers} command}
192%\section*{Answers}
193%\answers
194%\end{demo}
195%
196% \implementation
197%
198%
199%^^A-------------------------------------------------------------------------
200% \section{Implementation}
201%
202% \begin{macrocode}
203%<*package>
204% \end{macrocode}
205%
206% \subsection{Initialization}
207%
208% The \textsf{within} option is handled by the \package{keyval} package.
209%
210% \begin{macrocode}
211\RequirePackage{keyval}
212% \end{macrocode}
213%
214% \begin{macro}{\ex@within}
215%
216% When the \textsf{within} option is seen, we set a command |\ex@within| to
217% the correct code, to be executed later when we've made our minds up.
218%
219% \begin{macrocode}
220\let\ex@within\relax
221\define@key{ex}{within}{%
222 \def\ex@within{%
223 \@addtoreset{exercise}{#1}%
224 \toks@\expandafter{\csname the#1\expandafter\endcsname%
225 \expandafter.\theexercise}%
226 \edef\theexercise{\the\toks@}%
227 }%
228}
229% \end{macrocode}
230% \end{macro}
231%
232% \begin{macro}{\ex@opts}
233%
234% The |\ex@opts| macro just runs the \package{keyval} kit to parse an option
235% string.
236%
237% \begin{macrocode}
238\def\ex@opts{\setkeys{ex}}
239% \end{macrocode}
240% \end{macro}
241%
242% Now do the options thing.
243%
244% \begin{macrocode}
245\DeclareOption*{\expandafter\ex@opts\expandafter{\CurrentOption}}
246\ProcessOptions*
247% \end{macrocode}
248%
249% Set up the |exercise| counter, and number it within some other sort of
250% counter as appropriate.
251%
252% \begin{macrocode}
253\newcounter{exercise}\ex@within
254% \end{macrocode}
255%
256% We also need the \package{sverb} package in order to do the delaying of the
257% answers.
258%
259% \begin{macrocode}
260\RequirePackage{sverb}
261% \end{macrocode}
262%
263% \subsection{Checking for counter changes}
264%
265% \begin{macro}{\ex@ctrcheck}
266%
267% The counter checking state is stored here. It's initially empty.
268%
269% \begin{macrocode}
270\def\ex@ctrcheck{}
271% \end{macrocode}
272% \end{macro}
273%
274% \begin{macro}{\exctrcheck}
275%
276% Adding a counter to the check list is relatively easy. We expand the
277% current list into a token register, add the new material to the end, and
278% put the list back in our macro using |\edef|. The `last' value of the
279% counter is set to |\relax|, to force out the change on the next |\answer|.
280%
281% \begin{macrocode}
282\def\exctrcheck#1#2{%
283 \toks@\expandafter{\ex@ctrcheck\ex@ctrdo{#1}{#2}}%
284 \edef\ex@ctrcheck{\the\toks@}%
285 \global\expandafter\let\csname ex@ctrlast@#1\endcsname\relax%
286}
287% \end{macrocode}
288% \end{macro}
289%
290% \begin{macro}{\ex@ctrdo}
291%
292% Here we actually check to see whether a counter has changed and execute the
293% appropriate code.
294%
295% \begin{macrocode}
296\def\ex@ctrdo#1#2{%
297 \edef\@tempa{\csname the#1\endcsname}%
298 \expandafter\ifx\csname ex@ctrlast@#1\endcsname\@tempa\else%
299 #2%
300 \global\expandafter\let\csname ex@ctrlast@#1\endcsname\@tempa%
301 \fi%
302}
303% \end{macrocode}
304% \end{macro}
305%
306% \subsection{The \env{exercise} environment}
307%
308% \begin{macro}{\exercisename}
309%
310% We store the string to print for each exercise in |\exercisename| as a
311% half-hearted attempt at internationalization.
312%
313% \begin{macrocode}
314\providecommand\exercisename{Exercise}
315% \end{macrocode}
316% \end{macro}
317%
318% \begin{macro}{\exfix}
319%
320% This is a dumping ground for style fixing common to both exercises and
321% answers. Here, we bump on the \env{enum} depth counter, so that it skips
322% labelling with digits.
323%
324% \begin{macrocode}
325\def\exfix{\advance\@enumdepth\@ne}
326% \end{macrocode}
327% \end{macro}
328%
329% \begin{environment}{exercise}
330%
331% This is pretty simple. The environment is list-based, with the number set
332% in bold in a label.
333%
334% \begin{macrocode}
335\def\exercise{%
336 \refstepcounter{exercise}%
337 \exfix%
338 \trivlist\advance\itemindent\labelsep%
339 \item[\textbf{\exercisename\ \theexercise}]%
340}
341\let\endexercise\endtrivlist
342% \end{macrocode}
343% \end{environment}
344%
345% \subsection{Answers}
346%
347% We need a file in which to store our answers.
348%
349% \begin{macrocode}
350\newwrite\ex@ansfile
351% \end{macrocode}
352%
353% \begin{macro}{\ex@ansfilename}
354%
355% In case anyone has a better idea for a filename than our default, we
356% provide a hook.
357%
358% \begin{macrocode}
359\def\ex@ansfilename{\jobname.ans}
360% \end{macrocode}
361% \end{macro}
362%
363% We open the file at the end of the preamble, to give the user a chance to
364% say |\nofiles|, or change |\ex@ansfilename|.
365%
366% \begin{macrocode}
367\AtBeginDocument{%
368 \if@filesw%
369 \immediate\openout\ex@ansfile=\ex@ansfilename\relax%
370 \answrite\relax%
371 \fi%
372}
373% \end{macrocode}
374%
375% \begin{macro}{\answrite}
376%
377% This writes stuff to the answers file. We make sure that it's
378% appropriately protected, so that you can insert section headings and so on.
379%
380% \begin{macrocode}
381\def\answrite#1{%
382 \if@filesw%
383 \begingroup%
384 \let\protect\@unexpandable@protect%
385 \immediate\write\ex@ansfile{#1}%
386 \endgroup%
387 \fi%
388}
389% \end{macrocode}
390% \end{macro}
391%
392% \begin{macro}{\answer}
393%
394% The |\answer| macro needs to read until the end of the enclosing
395% \env{exercise} environment (or whatever).
396%
397% \begin{macrocode}
398\def\answer{\sv@readenv\ex@answer}
399% \end{macrocode}
400%
401% Now for the main guts.
402%
403% \begin{macrocode}
404\def\ex@answer#1#2{%
405 \begingroup%
406 \@bsphack%
407% \end{macrocode}
408%
409% First of all, check to see whether any counters have changed.
410%
411% \begin{macrocode}
412 \ex@ctrcheck%
413% \end{macrocode}
414%
415% Start a \env{doanswer} environment in the file.
416%
417% \begin{macrocode}
418 \answrite{\noexpand\begin{doanswer}{\theexercise}}%
419% \end{macrocode}
420%
421% Set catcodes to be strange, and read lines one-at-a-time, writing them to
422% the file. When finished, continue at |\ex@endanswer|.
423%
424% \begin{macrocode}
425 \let\do\@makeother\dospecials%
426 \sv@safespc%
427 \sv@read{#1}\answrite{\ex@endanswer#2}%
428}
429% \end{macrocode}
430%
431% When that's done, we wind up here.
432%
433% \begin{macrocode}
434\def\ex@endanswer{%
435 \@esphack%
436 \answrite{\noexpand\end{doanswer}}%
437 \endgroup%
438}
439% \end{macrocode}
440% \end{macro}
441%
442% \begin{macro}{\answers}
443%
444% The |\answers| macro closes the file, makes sure that future
445% \env{exercise}s with answers cause an error, and reads in the file.
446%
447% \begin{macrocode}
448\def\answers{%
449 \immediate\closeout\ex@ansfile%
450 \global\let\answrite\exerr@toolate%
451 \input{\ex@ansfilename}%
452}
453% \end{macrocode}
454% \end{macro}
455%
456% \begin{environment}{doanswer}
457%
458% A very simple environment. We set the exercise number in bold and then
459% just write the text.
460%
461% \begin{macrocode}
462\def\doanswer#1{%
463 \exfix%
464 \trivlist\advance\itemindent\labelsep%
465 \item[\textbf{#1}]%
466}
467\let\enddoanswer\endtrivlist
468% \end{macrocode}
469% \end{environment}
470%
471% \subsection{Lists inside paragraphs}
472%
473% \begin{environment}{parlist}
474%
475% The \env{parlist} environment is a trimmed-down version of a normal list.
476% We todge the |\item| command, make |\list| and |\trivlist| make errors, and
477% do various normal list things.
478%
479% \begin{macrocode}
480\def\parlist#1#2{%
481 \let\@trivlist\exerr@parlist%
482 \def\@itemlabel{#1}%
483 \let\makelabel\relax%
484 \@nmbrlistfalse%
485 #2%
486 \let\item\pl@item%
487 \ignorespaces%
488}
489% \end{macrocode}
490% \end{environment}
491%
492% \begin{macro}{\pl@item}
493%
494% This is the implementation of |\item| within a \env{parlist}. The main
495% interesting point is the game with boxes, which has the objective of
496% extracting the text of the item, together with any style changes set by
497% |\makelabel|, but without any stupid bits of glue, or |\llap| or anything
498% like that.
499%
500% \begin{macrocode}
501\def\pl@item{\@ifnextchar[\pl@item@i{\pl@item@i[\@itemlabel]}}
502\def\pl@item@i[#1]{%
503 \if@nmbrlist\refstepcounter{\@listctr}\fi%
504 \setbox\z@\hbox{\makelabel{\global\setbox\@ne\hbox{#1}}}%
505 \ifvmode\leavevmode\else\unskip\hskip1em\fi\box\@ne~\ignorespaces%
506}
507% \end{macrocode}
508% \end{macro}
509%
510% \begin{macro}{\useparlist}
511%
512% We just set the \env{list} environment to use \env{parlist}.
513%
514% \begin{macrocode}
515\def\useparlist{\let\list\parlist\let\endlist\relax}
516% \end{macrocode}
517% \end{macro}
518%
519% \begin{environment}{parenum}
520%
521% Very simple, this. Note that we don't run |\endenumerate|, because that's
522% |\let| to |\endlist|.
523%
524% \begin{macrocode}
525\def\parenum{\useparlist\enumerate}
526\let\endparenum\endparlist
527% \end{macrocode}
528% \end{environment}
529%
530% \subsection{Errors}
531%
532% \begin{macrocode}
533\def\exerr@toolate{%
534 \PackageError{exercise}{Too late now for \string\answrite}{%
535 You can't write answers after you've read the file in. I've^^J%
536 ignored the text you attempted to write. This is why answers^^J%
537 go at the end of a book!%
538 }%
539}
540\def\exerr@parlist{%
541 \PackageError{exercise}{You can't nest a `list' inside a `parlist'.}{%
542 I've found a `list' or `trivlist' environment nested inside^^J%
543 a `parlist'. This isn't allowed.%
544 }%
545}
546%</package>
547% \end{macrocode}
548%
549% Done.
550%
551% \hfill Mark Wooding, \today
552%
553% \Finale
554%
555\endinput