← Back to Projects

ExamEngineer

Automatic exam and solution generation for engineering courses

Writing exams by hand in LaTeX is tedious and error-prone — copy formulas, plug in numbers, hope you didn't make a sign error in the solution, and repeat. ExamEngineer eliminates that entire class of mistakes. You write each equation once; the system computes numeric results, converts units, and typesets both the exam paper and the matching solution booklet automatically.

Built for day-to-day use at Technische Hochschule Deggendorf. In production use across multiple engineering modules in Mechanical Engineering & Mechatronics.

How It Works

problem.yaml  ─┐
problem.yaml  ─┤──▶  Python pipeline  ──▶  exam.tex      ──▶  exam.pdf
exam.yaml     ─┘     (SymPy + Pint)       solution.tex  ──▶  solution.pdf

Problems are defined as YAML files with typed content modules — variables, equations, display instructions, images, plots. An exam YAML simply lists which problems to include and sets header metadata. The Python pipeline loads everything, solves the equations symbolically, renders LaTeX via Jinja2 templates, and compiles to PDF with LuaLaTeX. One source, two outputs, zero manual arithmetic.

Example problem definition

id: "impedance_001"
title: "AC Circuit Impedance"
language: "de"

modules:
  - type: variables
    variables:
      R: { value: "10 ohm" }
      C: { value: "47 uF" }
      f: { value: "50 Hz" }

  - type: question
    credits: 3
    question: "Calculate the impedance $Z$."
    modules:
      - type: unknowns
        unknowns:
          Z: { unit: "ohm" }
      - type: equation
        equation: "Z = R + 1/(j*2*pi*f*C)"
        show: solution   # only appears in solution booklet

The system computes Z, formats it as a complex number with units, and places the full solution step in the solution booklet while showing only the question in the exam version.

Key Features

  • Automatic solution generation

    Equations are solved symbolically with SymPy and evaluated with full unit tracking via Pint. No manual calculations, no transcription errors. The same equation definition produces both the exam question and the worked solution.

  • Exam randomization

    Define value ranges for each variable and constraints on computed results. The system generates valid random instances via rejection sampling — every student can receive a unique exam with guaranteed solvable, realistic numbers.

  • Reusable problem library

    Problems are YAML building blocks. Once written, they can be dropped into any future exam. Variable values can be overridden per exam without modifying the original problem. The library grows with every semester.

  • Composable content modules

    Each problem is assembled from typed modules: text, equations, variables, unknowns, images, function plots (pgfplots), code listings (minted), and raw LaTeX. No LaTeX knowledge required for everyday authoring.

  • Web-based frontend

    All functions are available through a browser-based frontend — create and edit problems and exams, browse and search the library, and trigger PDF builds without touching the command line. A schema-assisted problem editor guides authoring and catches errors early. Problems and exams can be previewed as PDF directly in the browser before publishing. Built with Flask and HTMX.

  • Correction assistant

    A grading helper lets instructors enter student results and pin wrong intermediate values. Downstream results recalculate automatically, making partial-credit grading faster and more consistent.

  • Incremental builds & validation

    A Make-based build system only recompiles exams whose dependencies have changed. YAML inputs are validated against JSON schemas before processing — errors surface as plain-language messages, not Python tracebacks.

  • Multi-language & accessible typography

    German and English, with locale-aware number formatting. Body text in Atkinson Hyperlegible Next and formulas in IBM Plex Math — optimized for readability under exam conditions.

Technical Stack

Component Role
Python 3.12 Core pipeline, symbolic computation (SymPy), unit handling (Pint), templating (Jinja2)
LuaLaTeX PDF compilation via fontspec, minted (code), pgfplots (function plots)
Flask + HTMX Web frontend for problem and exam authoring, library management, schema-assisted editing, PDF preview, and build triggering
JSON Schema Validation of all YAML inputs before processing
GNU Make Incremental, dependency-tracked builds with parallel compilation support

Status

In production use for multiple engineering modules at THD — Electrical Engineering, Mechatronics, and Mechanical Engineering. The problem library is continuously growing as legacy exams are migrated to the YAML format. ExamEngineer is being prepared for open-source release. If you teach engineering courses at a university and are looking for a better way to manage exams, I'd love to hear from you — early adopters who can bring additional problem types and field experience are especially welcome.

Interested?

If you'd like to use ExamEngineer in your own courses or institution, I'm happy to help get you started.

Get in touch