% \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