cgnieder / xsim

eXercise Sheets IMproved
67 stars 23 forks source link

Nested exercises as subexercises #67

Open cgnieder opened 4 years ago

cgnieder commented 4 years ago

What should be possible or what would be features when nested exercises are used as subexercises?

\documentclass{article}
\usepackage[no-files]{xsim}

\DeclareExerciseType{subquestion}{
  exercise-env = question ,
  solution-env = answer ,
  exercise-name = Question ,
  solution-name = Answer ,
  exercise-template = item ,
  solution-template = item
}

\DeclareExerciseEnvironmentTemplate{item}{\item}{}

\begin{document}

\begin{exercise}
  \ExerciseType:\ExerciseID
  \begin{enumerate}
    \begin{question}[ID=sub-a]
      \ExerciseType:\ExerciseID
    \end{question}
    \begin{answer}
      \ExerciseType:\ExerciseID
    \end{answer}
    \begin{question}[ID=sub-b]
      \ExerciseType:\ExerciseID
    \end{question}
    \begin{answer}
      \ExerciseType:\ExerciseID
    \end{answer}
    \begin{question}[ID=sub-c]
      \ExerciseType:\ExerciseID
    \end{question}
    \begin{answer}
      \ExerciseType:\ExerciseID
    \end{answer}
  \end{enumerate}
  \ExerciseType:\ExerciseID
\end{exercise}

\begin{solution}[print]
  \ExerciseType:\ExerciseID
  \begin{enumerate}
    \printsolution{subquestion}{sub-a}
    \printsolution{subquestion}{sub-b}
    \printsolution{subquestion}{sub-c}
  \end{enumerate}
  \ExerciseType:\ExerciseID
\end{solution}

\end{document}

I encourage users to give their thoughts here.

jonascj commented 4 years ago

@cgnieder Great idea to collect thoughts on the issue here.

The output of your snippet should be here as well

After 2 minutes of thinking I agree that being able to nest exercises seems very flexible and powerful. I am unsure if the \begin{question}\end{question} is a new suggestion or if it is already a part of xsim, but it looks fine, albeit a bit verbose.

I would be looking to nest once, like:

# Exercise 1
Two cars are traveling in opposite directions. 
They are 2.7km apart, driving 50km/h and 65km/h, respectively.
a) Write the equations of motion for the two cars.
b) Find the time t at which the two cars will meet.
c) Find the distance traveled by the cars when they meet.

I can't imagine I would want to nest any deeper. The following I would try to avoid:

#Exercise 1
a)
   1)
   2)
b)
   1)
   2)
cgnieder commented 4 years ago

After 2 minutes of thinking I agree that being able to nest exercises seems very flexible and powerful. I am unsure if the \begin{question}\end{question} is a new suggestion or if it is already a part of xsim, but it looks fine, albeit a bit verbose.

The question environment was defined in my example in the OP.

As long as the no-files option is active (cf. #68 please) the environments can safely be put inside of custom commands. Customization like this and putting all the personal definitions in a separate style file is even very much encouraged by xsim, something I already had in mind when I started implementing it.

joneppie commented 3 years ago

We have already included subexercises as teilaufgaben in the package schule (see https://gitlab.com/gi-fg-ibnw/schule/-/blob/master/latex/schule.mod.Aufgaben.code.tex#L96 ). It would be appreciated if this would work directly with xsim, respecting the following points: The points of the subexercises should be added to the score of the exercise. When outputting the solution of a exercise, the solutions of the subexercises must also be output. Properties of the subexercises must also be accessible. About it we realize the expectation horizon, which works so far only for the exercise completely (see https://gitlab.com/gi-fg-ibnw/schule/-/blob/master/latex/schule.mod.Bewertung.code.tex#L80 ).

N-Coder commented 3 years ago

Sorry for taking some time to comment here. Here's a summary of what I've been trying to do with the steps mentioned in issue #57.

With the changes I described here, all the above features are working. Of course, it would be awesome if that would also work without the need for any monkey-patching, so I'd be happy to help in bringing this functionality to xsim. I guess an unopinionated, generic approach would again be suited best for xsim, leaving more opinionated, use-case specific solutions to further dependent packages like schule (or what I've been using locally for my exams).

Two further features which would be nice to have in combination with subexercises (but which I couldn't get to work yet):

cgnieder commented 3 years ago

Very much of this already is possible and it is possible without the need for nesting. Here is a quick example:

\documentclass[parskip=half]{scrartcl}
\usepackage{xsim}

\DeclareExerciseProperty{subpoints}
\newcommand*\thesubpoints{}

\newcounter{subexercise}[exercise]
\renewcommand\thesubexercise{\alph{subexercise})}
\NewDocumentCommand\question{O{}}{%
  \refstepcounter{subexercise}%
  \item[\thesubexercise]%
  \XSIMifblankF{#1}{%
    \xdef\thesubpoints{\thesubpoints\XSIMifblankF{\thesubpoints}{+}#1}%
    (\addpoints{#1})%
  }%
}

\DeclareExerciseEnvironmentTemplate{custom}{%
  \gdef\thesubpoints{}%
  \subsection*{\XSIMmixedcase{\GetExerciseName}~\GetExerciseProperty{counter}%
    \IfExercisePropertySetT{subtitle}
      { {\normalfont\itshape\GetExerciseProperty{subtitle}}}%
  }
  \GetExercisePropertyT{points}{%
    \begingroup
      \footnotesize\sffamily
      Points: \printgoal{\PropertyValue}%
      \IfExercisePropertySetT{subpoints}{ (\GetExerciseProperty{subpoints})}%
    \endgroup
    \par
  }
}{
  \XSIMifblankF{\thesubpoints}
    {\SetExpandedExerciseProperty{subpoints}{\thesubpoints}}%
  \par
}

\NewDocumentEnvironment{subexercise}{}
  {\begin{enumerate}}
  {\end{enumerate}}

\newcommand\answer[1]{\IfSolutionPrintT{\textbf{#1}}}

\xsimsetup{
  exercise/template=custom ,
  % solution/print
}

\begin{document}

\begin{exercise}[points=3, subtitle=Plain]
  Plain exercise. \answer{Plain answer}
\end{exercise}
\begin{exercise}[subtitle=With subexercises]
  \begin{subexercise}
    \question[2] One \answer{First answer}
    \question[3] Two \answer{Second answer}
  \end{subexercise}
  An exercise with subexercises.
  \begin{subexercise}
    \question[1] Three \answer{Third answer}
  \end{subexercise}
\end{exercise}

\end{document}

which gives

grafik

or

grafik

N-Coder commented 3 years ago

Very much of this already is possible and it is possible without the need for nesting. Here is a quick example:

Yes. This is actually not that different from what I did in my proof of concept here. But instead of defining custom "bare" LaTeX commands for the subexercises, I used a custom xsim exercise environment for the subexercises. Similar to what you did in your code, I used the hook system to collect the subpoints, sum them up, and then report the result to the parent exercise here. The seemingly complicated logic in the post hook is just to ensure that we don't add any dangling pluses when any of the concerned exercises doesn't have points assigned. If we don't care about these we could simply always use the True branch of the ifs and completely drop the False branch, making the total code size required for nested points in xsim roughly 100 lines (including all my comments, empty lines,...).

Thanks to your fix from 0f90bd6d3227ec3e41b9d89d492ef96047122698 and setting most variables locally, nesting is actually no big issue any more. The fixes for restoring the variables I included in previous versions of the POC are mostly no longer required. Now, I'm mostly setting nice-to-have properties related to nesting, i.e. a property for the ID of the parent exercise and its type and a full counter consisting of the concatenation of the parent's counter with the child's. The only thing that still needs to be restored after a nested subexercise is \g_xsim_exercise_id_tl (which is simply set to the ID of the parent), because that value needs to be global for a following solution to pick it up.

There is really nothing more required than what I just described here for nesting to work flawlessly. I did prefer using a solution via xsim environments instead of custom LaTeX commands because that seemed a lot cleaner, more flexible and extensible. If someone wants to have the subexercises listed individually in the grading table, this would be trivial thanks to the nested exercises. Same goes for using the property, template and hook infrastructure xsim already provides. Also, if xsim were to provide this functionality by default, the custom code a user would need for nesting to work would be minimal. Collecting all the subsolutions and only printing them after the whole body of the exercise would also be easy this way, e.g. by setting subsolutions/print=false, collecting all subsolutions encountered in the exercise body and then using \printsolution in the actual solution of the whole exercise.

Merging the code of my POC into xsim shouldn't be much work. The only thing that would need to be done is to throw out the monkey-patching via hooks and instead find the right places of the xsim code base to insert my additions. If I were to create and open this PR, would you be willing to consider it for merging?

cgnieder commented 3 years ago

I am inclined to add a subexercise mechanism to xsim that will not require nesting but will still be customizable through xsim's templates. I will present ideas here once they're ready to be tested.

I'm glad that the nested approach works for you but I am hesitating to officially support it. If I do I will always have to keep possible complications in mind whenever I try to add a new feature. That being said I'll still look at your code and will see if I can integrate it in a proper way.

N-Coder commented 3 years ago

I see, preventing regressions will probably become a bigger issue the more users and features xsim gets. Maybe it would make future releases easier to make and new features easier to incorporate if GitHub Actions or another Continuous Integration system would be used to check that, for every commit, the examples (or maybe also further test documents) still compile fine and continue to yield the same output. I'm already using CI to check that all the tex files my colleagues and me produce aren't broken by a certain commit and continue to compile fine (including automated e-mails reminding you about figures you forgot to check in, which is very useful), so the first half would be very easy to do. For the second half, checking that the output doesn't change, we could use some PDF diff tool (with an appropriate level of detail, e.g. only comparing word-by-word and not pixel-by-pixel) to compare the results with the PDFs of the examples already stored in the repo. If the results differ in an unintended way, there'll be an automated notification about that breaking change. If the results differ in an intended way, this would be a reminder to update the PDFs files in the repo. Should I try to set up an example configuration for this so that we can test this?

N-Coder commented 3 years ago

I encountered two further use-cases for nested subexercises:

Jowi-Ammerbuch commented 1 year ago

Hello, I find the discussion about exercises with subexercises very interesting, because in my teaching practice I need this all the time. For my learning objective checks I used the package exam by Philip Hirschhorn so far. However, XSIM seems to me potentially much more powerful, I especially appreciate the ability to have solutions output at the end, after the questions, this is very charming especially for practice sheets. But on the subject of tasks with sub-tasks: Frankly, what I don't like about N-Coder's interesting approach is that it further extends XSIM's already sophisticated code. By the way, I also feel uncomfortable with the package Schule, they also have tasks with subtasks and a lush functionality, mostly great design, but as a non-LATEX expert you are quickly lost if something does not go through at first, too confusing are the interweavings of different code collections. Can't it be simpler? I had the feeling from the beginning that XSIM already has everything to achieve my goal, but I can't really handle this tool yet. It should be possible to achieve with XSIM what exam by Philip Hirschorn can do, i.e. that subtasks have the functionalities as stand-alone tasks. That the evaluation points are displayed in the same way (I prefer on the right margin) and are added to one counter.

Translated with www.DeepL.com/Translator (free version) (Mein Englisch ist leider nicht sehr gut.)

Jowi-Ammerbuch commented 1 year ago

My feeling didn't deceive me, with this versatile XSIM package you can also realize nice exam tasks with subtasks, however it did take me some time. The code can certainly be optimized, I am not an expert and have read my eyes sore at the manual. Attached is an example of an exam template, based on the document class scrartcl and adapted to LuaLaTex. I would be very grateful for any optimization suggestions!

``

KA-Vorlage-KOMA-Lua.pdf XSIM-KA-Koma-Style.tex.txt KA-Vorlage-KOMA-Lua .tex.txt

projetmbc commented 1 year ago

This would be a great feature. I need for final exams to type problems divided in "parts" Part A, Part B, ... This could be implemented using the concept of sub-exercices.