Insert correct checksums.
[mdwtools] / exercise.dtx
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