Python · ddmin delta debugging
A bug report is usually buried in noise — a thousand lines of input when four would do. Bugpoint takes a failing case and a way to test "does this still fail?", and automatically shrinks the input to a minimal, 1-minimal reproduction. The engine is the classic ddmin delta-debugging algorithm (Zeller & Hildebrandt, 2002): a smart bisection over the input that drops chunks, checks the failure survives, and increases granularity until nothing more can go.
What it is
When something crashes on a huge input, the first real task is always the same: find the minimal reproduction. Bugpoint automates it. Given a failing case and a way to test "does this still fail?", it systematically removes pieces of the input and keeps whatever still triggers the bug — converging on a tiny reproducer that points straight at the cause.
It turns hours of manual "comment-it-out-and-rerun" into an automatic search — and the minimal case it spits out is often half the debugging battle won. The result is guaranteed 1-minimal: removing any single remaining element makes the failure disappear. Identical candidates are memoized so the same subset is never re-tested.
The stack
A reduction engine wrapped around a simple pass/fail oracle.
The large input that triggers the bug — the raw material to be shrunk.
A check that answers one question: does this reduced candidate still reproduce the failure?
Bisect the input, drop chunks, keep what still fails — recurse until nothing more can go.
Start with big chunks, then finer ones, balancing speed against how small the result gets.
Keep reductions well-formed enough to actually run, so failures stay genuine.
The smallest input that still breaks — handed back ready to debug.
Architecture
Reduction is a guided search, each step validated by the oracle:
Verify the original input really does reproduce the failure.
Divide the input into chunks at the current granularity.
Try removing chunks and ask the oracle if it still fails.
Retain any reduction that preserves the failure; discard the rest.
Increase granularity and recurse until the case can't shrink further.
The API
The core is ddmin(elements, interesting) over any list; minimize_lines and minimize_chars wrap it for source text. The predicate returns True when a candidate still reproduces the failure, and must be True for the full input.
from bugpoint import ddmin, minimize_lines
elements = list(range(1000))
required = {17, 256, 743, 999} # the hidden trigger
ddmin(elements, lambda s: required.issubset(set(s)))
# -> [17, 256, 743, 999] (1-minimal)
minimize_lines(program_text, still_crashes) # minimal failing lines
The CLI
The interestingness test is any external command — Bugpoint writes each candidate to a temp file and treats a non-zero exit code as "still failing", the same convention as a crashing program. It reports the real number of test evaluations.
$ printf 'alpha\nbeta\nCRASH\ngamma\ndelta\n' > in.txt
$ python -m bugpoint --input in.txt \
--test "... exit 1 if 'CRASH' in file ..." --output in.min
bugpoint: 6 -> 1 lines in 4 test evaluations. Wrote in.min
# in.min now contains exactly: CRASH