% \iffalse meta-comment % An Infrastructure for Problems % $URL: https://svn.kwarc.info/repos/stex/trunk/sty/problem/problem.dtx $ % $Rev: 1999 $; last modified by $Author: kohlhase $ % $Date: 2012-01-28 08:32:11 +0100 (Sat, 28 Jan 2012) $ % Copyright (c) 2006-2008 Michael Kohlhase, all rights reserved % this file is released under the % LaTeX Project Public License (LPPL) % \fi % % \iffalse %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{problem}[2012/01/28 v0.9c Semantic Markup for Problems] % %<*driver> \documentclass{ltxdoc} \usepackage{url,float,latexml} \usepackage[solutions,hints,notes]{problem} \usepackage[show]{ed} \usepackage[hyperref=auto,style=alphabetic]{biblatex} \bibliography{kwarc} \usepackage[eso-foot,today]{svninfo} \svnInfo $Id: problem.dtx 1999 2012-01-28 07:32:11Z kohlhase $ \svnKeyword $HeadURL: https://svn.kwarc.info/repos/stex/trunk/sty/problem/problem.dtx $ \usepackage{stex-logo} \usepackage{../ctansvn} \usepackage{hyperref} \makeindex \floatstyle{boxed} \newfloat{exfig}{thp}{lop} \floatname{exfig}{Example} \def\tracissue#1{\cite{sTeX:online}, \hyperlink{http://trac.kwarc.info/sTeX/ticket/#1}{issue #1}} \begin{document}\DocInput{problem.dtx}\end{document} % % \fi % % \CheckSum{396} % % \changes{v0.9}{2006/09/18}{First Version with Documentation} % \changes{v0.9a}{2007/01/02}{Renamed to \texttt{problem.sty}} % \changes{v0.9b}{2008/10/01}{added extraction} % \changes{v0.9c}{2010/01/03}{based on \texttt{omd.sty} now} % % \GetFileInfo{problem.sty} % % \MakeShortVerb{\|} % % \title{\texttt{problem.sty}: An Infrastructure for formatting Problems\thanks{Version {\fileversion} (last revised % {\filedate})}} % \author{Michael Kohlhase\\ % Jacobs University, Bremen\\ % \url{http://kwarc.info/kohlhase}} % \maketitle % % \begin{abstract} % The |problem| package supplies an infrastructure that allows specify problems and to % reuse them efficiently in multiple environments. % \end{abstract} % \setcounter{tocdepth}{2}\tableofcontents\newpage % %\section{Introduction}\label{sec:intro} % % The |problem| package supplies an infrastructure that allows specify problem. Problems % are text fragments that come with auxiliary functions: hints, notes, and % solutions\footnote{for the momenet multiple choice problems are not supported, but may % well be in a future version}. Furthermore, we can specify how long the solution to a % given problem is estimated to take and how many points will be awarded for a perfect % solution. % % Finally, the |problem| package facilitates the management of problems in small files, % so that problems can be re-used in multiple environment. % % \section{The User Interface}\label{sec:ui} % % \subsection{Package Options} % The |problem| package takes the options \DescribeMacro{solutions}|solutions| (should % solutions be output?), \DescribeMacro{notes}|notes| (should the problem notes be % presented?), \DescribeMacro{hints}|hints| (do we give the hints?), % \DescribeMacro{pts}|pts| (do we display the points awarded for solving the problem?), % \DescribeMacro{min}|min| (do we display the estimated minutes for problem soling). If % theses are specified, then the corresponding auxiliary parts of the problems are output, % otherwise, they remain invisible. % % The \DescribeMacro{boxed}|boxed| option specifies that problems should be formatted in % framed boxes so that they are more visible in the text. Finally, the % \DescribeMacro{test}|test| option signifies that we are in a test sitution, so this % option does not show the solutions (of course), but leaves space for the students to % solve them. % % The \DescribeMacro{extract}|extract| option can be set if we want to extract a problems % file, e.g. to display the solutions, see Section~\ref{sec:user:includeproblem} for a % discussion. % % Finally, if the \DescribeMacro{showmeta}|showmeta| is set, then the metadata keys are % shown (see~\cite{Kohlhase:metakeys:ctan} for details and customization options). % % \subsection{Problems and Solutions}\label{sec:user:probsols} % % \DescribeEnv{problem} The main enviornment provided by the |problem| package is % (surprise surprise) the |problem| environment. It is used to mark up problems and % excercises. The environment takes an optional KeyVal argument with the keys % \DescribeMacro{id}|id| as an identifier that can be reference later, % \DescribeMacro{pts}|pts| for the points to be gained from this exercise in homework or % quiz situations, \DescribeMacro{min}|min| for the estimated minutes needed to solve the % problem, and finally \DescribeMacro{title}|title| for an informative title of the % problem. For an example of a marked up problem see Figure~\ref{fig:problem} and the % resulting markup see Figure~\ref{fig:result}. % %\begin{exfig} % \begin{verbatim} % \usepackage[solutions,hints,pts,min]{problem} % \begin{document} % \begin{problem}[id=elefants,pts=10,min=2,title=Fitting Elefants] % How many Elefants can you fit into a Volkswagen beetle? % \begin{hint} Think positively, this is simple!\end{hint} % \begin{exnote}Justify your answer\end{exnote} % \begin{solution}[for=elefants,height=3cm] % Four, two in the front seats, and two in the back. % \end{solution} % \end{problem} % \end{document} % \end{verbatim} % \caption{A marked up Problem}\label{fig:problem} % \end{exfig} % % \DescribeEnv{solution} The |solution| environment can be to specify a solution to a % problem. If the \DescribeMacro{solutions}|solutions| option is set or |\solutionstrue| % is set in the text, then the solution will be presented in the output. The |solution| % environment takes an optional KeyVal argument with the keys \DescribeMacro{id}|id| for % an identifier that can be reference \DescribeMacro{for}|for| to specify which problem % this is a solution for, and \DescribeMacro{height}|height| that allows to specify the % amount of space to be left in test situations (i.e. if the \DescribeMacro{test}|test| % option is set in the |\usepackage| statement). % %\begin{exfig} % \begin{minipage}{.9\linewidth} % \begin{problem}[id=elefants.prob,title=Fitting Elefants] % How many Elefants can you fit into a Volkswagen beetle? % \begin{hint} Think positively, this is simple!\end{hint} % \begin{exnote}Justify your answer\end{exnote} % \begin{solution}%[for=elefants.prob,height=3cm] % Four, two in the front seats, and two in the back. % \end{solution} % \end{problem} % \end{minipage} % \caption{The Formmatted Problem from Figure~\ref{fig:problem}}\label{fig:result} % \end{exfig} % % \DescribeEnv{hint}\DescribeEnv{note}, the |hint| and |exnote| environments can be used % in a |problem| enviroment to give hints and to make notes that elaborate certain aspects % of the problem. % % \subsection{Including Problems}\label{sec:user:includeproblem} % % The \DescribeMacro{\includeproblem}|\includeproblem| macro can be used to include a % problem from another file. It takes an optional KeyVal argument and a second argument % which is a path to the file containing the problem (the macro assumes that there is only % one problem in the include file). The keys \DescribeMacro{title}|title|, % \DescribeMacro{min}|min|, and \DescribeMacro{pts}|pts| specify the problem title, the % estimated minutes for solving the problem and the points to be gained, and their values % (if given) overwrite the ones specified in the |problem| environment in the included % file. % % Sometimes we want to collect all the included problems into a separate file that can be % typeset independently. The main application is to have course notes into which the % problems are included (usually in boxed form to distinguish them from the rest of the % text and without solutions) and to have the problems with solutions in a separate file % (to encourage students to try and solve the problems before looking up solutions). In % this situation set the \DescribeMacro{extract}|extract| option on the notes file % \meta{notes}|.tex|, which causes a file \meta{notes}|-solutions.tex| to be generated % that has the |\includeproblem| statements with the respective numbers from the main % document. This can then be imported into a document with the respective front and % backmatter. In particular the frontmatter of the importing will ususlly specify the % \DescribeMacro{solutions}|solutions| option to generate solutions. % % \subsection{Reporting Metadata}\label{sec:user:reporting} % % The sum of the points and estimated minutes (that we specified in the |pts| and |min| % keys to the |problem| environment or the |\includeproblem| macro) to the log file and % the screen after each run. This is useful in preparing exams, where we want to make sure % that the students can indeed solve the problems in an alotted time period. % % The |\min| and |\pts| macros allow to specify (i.e. to print to the margin) the % distribution of time and reward to parts of a problem, if the |pts| and |pts| package % options are set. This allows to give students hints about the estimated time and the % points to be awarded. % % \section{Limitations}\label{sec:limitations} % % In this section we document known limitations. If you want to help alleviate them, % please feel free to contact the package author. Some of them are currently discussed in % the \sTeX TRAC~\cite{sTeX:online}. % \begin{compactenum} % \item none reported yet % \end{compactenum} % % \StopEventually{\newpage\PrintChanges} % \newpage % % \section{The Implementation}\label{sec:implementation} % % The |problem| package generates two files: the {\LaTeX} package (all the code between % {\textsf{$\langle$*package$\rangle$}} and {\textsf{$\langle$/package$\rangle$}}) and the % {\LaTeXML} bindings (between {\textsf{$\langle$*ltxml$\rangle$ and % $\langle$/ltxml$\rangle$}}). We keep the corresponding code fragments together, % since the documentation applies to both of them and to prevent them from getting out of % sync. % % \subsection{Package Options}\label{sec:impl:options} % % The first step is to declare (a few) package options that handle whether certain % information is printed or not. They all come with their own conditionals that are set by % the options. % % \begin{macrocode} %<*package> \DeclareOption{showmeta}{\PassOptionsToPackage{\CurrentOption}{metakeys}} \newif\ifexnotes\exnotesfalse\DeclareOption{notes}{\exnotestrue} \newif\ifhints\hintsfalse\DeclareOption{hints}{\hintstrue} \newif\ifsolutions\solutionsfalse\DeclareOption{solutions}{\solutionstrue} \newif\ifpts\ptsfalse\DeclareOption{pts}{\ptstrue} \newif\ifmin\minfalse\DeclareOption{min}{\mintrue} \newif\ifboxed\boxedfalse\DeclareOption{boxed}{\boxedtrue} \newif\ifextract\extractfalse\DeclareOption{extract}{\extracttrue} \ProcessOptions % % \end{macrocode} % % On the {\LaTeXML} side we only make sure that the switches are defined % \begin{macrocode} %<*ltxml> RawTeX(' \newif\ifexnotes\exnotesfalse \newif\ifhints\hintsfalse \newif\ifsolutions\solutionsfalse \newif\ifpts\ptsfalse \newif\ifmin\minfalse \newif\ifboxed\boxedfalse \newif\ifextract\extractfalse '); % % \end{macrocode} % Then we make sure that the necessary packages are loaded (in the right versions). % \begin{macrocode} %<*package> \RequirePackage{keyval}[1997/11/10] \RequirePackage{xcomment} \RequirePackage{sref} % % \end{macrocode} % % Here comes the equivalent header information for {\LaTeXML}, we also initialize the % package inclusions. Since {\LaTeXML} currently does not process package options, we have % nothing to do. % \begin{macrocode} %<*ltxml> # -*- CPERL -*- package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; RequirePackage('sref'); % % \end{macrocode} % % Then we register the namespace of the requirements ontology % \begin{macrocode} %<*ltxml> RegisterNamespace('prob'=>"http://omdoc.org/ontology/problems#"); RegisterDocumentNamespace('prob'=>"http://omdoc.org/ontology/problems#"); % % \end{macrocode} % % \subsection{Problems and Solutions}\label{sec:impl:probsols} % % We now prepare the KeyVal support for problems. The key macros just set appropriate % internal macros. % % \begin{macrocode} %<*package> \srefaddidkey[prefix=prob.]{problem} \addmetakey{problem}{pts} \addmetakey{problem}{min} \addmetakey*{problem}{title} \addmetakey{problem}{refnum} % \end{macrocode} % % Then we set up a box and a counter for problems % % \begin{macrocode} \newsavebox{\probbox} \newcounter{problem}[section] % \end{macrocode} % % \begin{macro}{\prob@number} % We consolidate the problem number into a reusable internal macro % \begin{macrocode} \def\prob@number{\ifx\inclprob@refnum\@empty \ifx\problem@refnum\@empty\thesection.\theproblem\else\problem@refnum\fi \inclprob@refnum\fi} % \end{macrocode} % \end{macro} % % We consolidate the problem header line into a separate internal macro that can be reused % in various settings. % % \begin{macro}{\prob@heading} % We consolidate the problem header line into a separate internal macro that can be % reused in various settings. % \begin{macrocode} \def\prob@heading{Problem \prob@number% \ifx\sref@id\@empty\else{\sref@label@id{Problem \thesection.\theproblem}}\fi% \ifx\inclprob@title\@empty% if there is no outside title \ifx\problem@title\@empty{:\quad}\else{\quad(\problem@title)\hfill\\}\fi \else\quad(\inclprob@title)\hfill\\\fi}% else show the outside title % \end{macrocode} % \end{macro} % % With this in place, we can now define the |problem| environment. It comes in two shapes, % depending on whether we are in boxed mode or not. In both cases we increment the problem % number and output the points and minutes (depending) on whehter the respective options % are set. % \begin{environment}{problem} % \begin{macrocode} \ifboxed \newenvironment{problem}[1][]{\metasetkeys{problem}{#1}\sref@target% \stepcounter{problem}\show@pts\show@min\record@problem% \begin{lrbox}{\probbox}\begin{minipage}{.9\textwidth}\ignorespaces} {\end{minipage}\end{lrbox} \setbox0=\hbox{\begin{minipage}{.9\textwidth}% \noindent\textbf\prob@heading\rm% \end{minipage}} \smallskip\noindent\fbox{\vbox{\box0\vspace*{.2em}\usebox\probbox}}\smallskip} \else \newenvironment{problem}[1][]{\metasetkeys{problem}{#1}\sref@target% \stepcounter{problem}\show@pts\show@min\record@problem% \par\noindent\textbf\prob@heading\rm\ignorespaces} {\smallskip} \fi%boxed % % \end{macrocode} % \end{environment} % % Note that we allow hints and solutions in the body of a |problem| environment so we have % to allow the |omdoc:CMP| and |ltx:p| elements to autoclose. % % \begin{macrocode} %<*ltxml> DefEnvironment('{problem} OptionalKeyVals:problem', "" . "?&KeyVal(#1,'title')(&KeyVal(#1,'title'))()" . "?&KeyVal(#1,'min')(" . "" . "&KeyVal(#1,'min')" . ")()" . "?&KeyVal(#1,'pts')(" . "" . "&KeyVal(#1,'pts')" . ")()" . "#body" ."", afterDigest => sub { my ($stomach,$kv)=@_; my $kvi = LookupValue('inclprob'); my @keys = qw(id title min pts); my @vals = $kvi && map($kvi->getValue($_), @keys); foreach my $i(0..$#vals) { $kv->setValue($keys[$i],$vals[$i]) if $vals[$i]; } return;});#$ % % \end{macrocode} % % \begin{macro}{\record@problem} % This macro records information about the problems in the |*.aux| file. % \begin{macrocode} %<*package> \def\record@problem{\protected@write\@auxout{}% {\string\@problem{\prob@number}% {\ifx\inclprob@pts\@empty\problem@pts\else\inclprob@pts\fi}% {\ifx\inclprob@min\@empty\problem@min\else\inclprob@min\fi}}} % % \end{macrocode} % \end{macro} % % \begin{macro}{\@problem} % This macro acts on a problem's record in the |*.aux| file. It does not have any % functionality here, but can be redefined elsewhere (e.g. in the |assignment| % package). % \begin{macrocode} %<*package> \def\@problem#1#2#3{} % % \end{macrocode} % \end{macro} % % The |solution| environment is similar to the |problem| environment, only that it is % independent of the boxed mode. It also has it's own keys that we need to define first. % % \begin{macrocode} %<*package> \define@key{soln}{id}{\def\soln@id{#1}} \define@key{soln}{for}{\def\soln@for{#1}} \define@key{soln}{height}{\def\soln@height{#1}} \ifsolutions \newenvironment{solution}[1][]% {\hrule\smallskip{\bf Solution: }\begin{small}}% {\hrule\end{small}} \else\newxcomment[]{solution}\fi % \newsavebox{\solution@box} % \newlength{\solution@width} % \setlength{\solution@width}{14cm} % \newenvironment{solution}[1][]% % {\begin{lrbox}{\solution@box}\begin{minipage}{\solution@width} % \hrule\smallskip{\bf Solution: }\small} % {\smallskip\hrule\end{minipage}\end{lrbox} % \ifsolutions\begin{center}\usebox{\solution@box}\end{center}\fi} % %<*ltxml> DefKeyVal('soln','id','Semiverbatim'); DefKeyVal('soln','height','Semiverbatim'); DefKeyVal('soln','for','Semiverbatim'); DefEnvironment('{solution} OptionalKeyVals:soln', "" . "#body" . ""); % % \end{macrocode} % % \begin{macrocode} %<*package> \ifexnotes \newenvironment{exnote}[1][]% {\par\noindent\hrule\smallskip{\bf Note: }\small} {\smallskip\hrule} \else%ifexnotes \newxcomment[]{exnote} \fi%ifexnotes \ifhints \newenvironment{hint}[1][]% {\par\noindent\hrule\smallskip{\bf Hint: }\small} {\smallskip\hrule} \else%ifhints \newxcomment[]{hint} \fi%ifhints % %<*ltxml> DefEnvironment('{exnote}',"#body"); DefEnvironment('{hint}',"#body"); DefConstructor('\pts{}',""); DefConstructor('\min{}',""); % % \end{macrocode} % % \subsection{Including Problems}\label{sec:impl:includeproblem} % % The first action is to make a \meta{jobname}|-problems.tex| file, if the |extract| % option is set. % % \begin{macrocode} %<*package> \ifextract \newwrite\problem@file \immediate\openout\problem@file=\jobname-problems.tex \AtEndDocument{\closeout\problem@file} \fi % % \end{macrocode} % % \begin{macro}{\includeproblem} % The |\includeproblem| command is essentially a glorified |\input| statement, it sets % some internal macros first that overwrite the local points. After that (so that the % included problem had time to step the problem number) it writes the |\includeproblem| % statement to the problems file, if the |extract| option is set. Here we add a key % |refnum=\prob@num| to the inlcudeproblem, so that we can remember the number from the % main document.\ednote{do something about the overwriting of problem metadata in the % {\LaTeXML} binding.} % % \begin{macrocode} %<*package> \addmetakey{inclprob}{pts} \addmetakey{inclprob}{min} \addmetakey*{inclprob}{title} \addmetakey{inclprob}{refnum} \clear@inclprob@keys \newcommand{\includeproblem}[2][]{% \bgroup\metasetkeys{inclprob}{#1}\input{#2}\ifsolutions\newpage\fi\egroup \ifextract\def\@test{#1} \def\prob@num{\ifx\inclprob@refnum\@empty\thesection.\theproblem\else\inclprob@refnum\fi} \def\inclprob@keys{#1\ifx\@test\@empty\else,\fi refnum=\prob@num} \protected@write\problem@file{}{\string\includeproblem[\inclprob@keys]{#2}} \fi} % %<*ltxml> DefKeyVal('prob','pts','Semiverbatim'); DefKeyVal('prob','min','Semiverbatim'); DefKeyVal('prob','title','Semiverbatim'); DefConstructor('\includeproblem OptionalKeyVals:prob Semiverbatim', "" . "?&KeyVal(#1,'title')(&KeyVal(#1,'title'))()" . "?&KeyVal(#1,'min')(" . "" . "&KeyVal(#1,'min')" . ")()" . "?&KeyVal(#1,'pts')(" . "" . "&KeyVal(#1,'pts')" . ")()" ."", afterDigest => sub{ my ($stomach,$kv) = @_; AssignValue('inclprob',$kv) if $kv; }); % % \end{macrocode} % \end{macro} % % \begin{macrocode} %<*ltxml> Tag('omdoc:exercise',afterOpen=>\&numberIt); Tag('omdoc:solution',afterOpen=>\&numberIt); Tag('omdoc:hint',afterOpen=>\&numberIt); % % \end{macrocode} % % \subsection{Reporting Metadata} % % \begin{macrocode} %<*package> \def\pts#1{\ifpts\marginpar{#1 pt}\fi} \def\min#1{\ifmin\marginpar{#1 min}\fi} % %<*ltxml> % % \end{macrocode} % % \begin{macrocode} %<*package> \AtEndDocument{\ifpts\message{Total: \arabic{pts} points}\fi \ifmin\message{Total: \arabic{min} minutes}\fi} % %<*ltxml> % % \end{macrocode} % % \begin{macro}{\show@pts} % The |\show@pts| shows the points: if no points are given from the outside and also no % points are given locally do nothing, else show and add. If there are outside points % then we show them in the margin. % \begin{macrocode} %<*package> \newcounter{pts} \def\show@pts{\ifx\inclprob@pts\@empty% \ifx\problem@pts\@empty\else% \ifpts\marginpar{\problem@pts pt\smallskip}\addtocounter{pts}{\problem@pts}\fi% \fi\else% \ifpts\marginpar{\inclprob@pts pt\smallskip}\addtocounter{pts}{\inclprob@pts}\fi% \fi} % \end{macrocode} % \end{macro} % and now the same for the minutes % \begin{macro}{\show@min} % \begin{macrocode} \newcounter{min} \def\show@min{\ifx\inclprob@min\@empty% \ifx\problem@min\@empty\else% \ifmin\marginpar{\problem@min min}\addtocounter{min}{\problem@min}\fi% \fi\else% \ifmin\marginpar{\inclprob@min min}\addtocounter{min}{\inclprob@min}\fi \fi} % % \end{macrocode} % \end{macro} % % \subsection{Providing IDs Elements}\label{sec:impl:ids} % % To provide default identifiers, we tag all elements that allow |xml:id| attributes by % executing the |numberIt| procedure from |omdoc.sty.ltxml|. % % \begin{macrocode} %<*ltxml> Tag('omdoc:exercise',afterOpen=>\&numberIt,afterClose=>\&locateIt); Tag('omdoc:solution',afterOpen=>\&numberIt,afterClose=>\&locateIt); Tag('omdoc:hint',afterOpen=>\&numberIt,afterClose=>\&locateIt); % % \end{macrocode} % % \subsection{Finale} % Finally, we need to terminate the file with a success mark for perl. % \begin{macrocode} %1; % \end{macrocode} % \Finale \endinput % \iffalse % LocalWords: GPL structuresharing STR dtx pts keyval xcomment CPERL DefKeyVal %%% Local Variables: %%% mode: doctex %%% TeX-master: t %%% End: % \fi % LocalWords: RequirePackage Semiverbatim DefEnvironment OptionalKeyVals soln % LocalWords: exnote DefConstructor inclprob