Offline benchmarks#
The benchmark chapter of the tutorial runs its four methods in the browser through numbl. The scripts here run the two best of those methods, the harmonic basis and the graded-panel double layer, outside the browser, on the same Pac-Man problem and the same error lattice.
Run whichever of these your machine has, from the repository root:
python3 bench/python/bench_pacman.py # needs NumPy and SciPy
julia bench/julia/bench_pacman.jl # standard library only
matlab -batch "run('bench/matlab/bench_pacman.m')"
Each writes a bench-pacman-*.json file (the MATLAB one lands in the
repository root, the others in the current directory). Load those files from
the "load offline results" button under the benchmark chapter's
work-precision plot, and they appear as dashed curves beside the browser's.
The point of running the scripts yourself, rather than reading times measured on someone else's machine, is that your browser results and your offline results then share a clock and can honestly share an axis.
The MATLAB harness runs the chapter's own driver and editable script, unchanged, in real MATLAB. The Python and Julia scripts are ports; the check that they are faithful is that their error columns land on top of the browser's curves, since the error depends only on the mathematics. On the double layer the three environments agree bit for bit; on the basis method they agree to within a factor of two at the roundoff floor, where the order of the QR pivoting is all that separates them.
Comparing languages, not authors#
A cross-language benchmark measures how carefully each port was written unless that is deliberately controlled for, so three rules are held to here. The chapter's prose discusses them; in the code they look like this.
Each port uses the fastest shape its own language offers, and they differ. The kernel matrix is assembled by a scalar double loop in the MATLAB script (hence in numbl too) and in Julia, because that is about twice as fast as implicit expansion in MATLAB and numbl and much faster than broadcasting in Julia. NumPy cannot run that loop at any acceptable speed, so the Python port assembles with whole-array expressions, in place: the obvious version, one broadcast statement per line, needs five n-by-n temporaries and is about 1.6 times slower for that reason alone. Insisting on one shape everywhere would make the benchmark less fair, not more.
The same linear algebra is requested everywhere. numpy.linalg.lstsq is
an SVD, while MATLAB's and Julia's backslash are pivoted QR on a rectangular
system, so the Python port calls SciPy's QR driver (gelsy) instead. For the
square systems all three call the same LAPACK and land within ten per cent.
One timing protocol, everywhere, including in the page. Keep the fastest of several runs: at least three whenever a solve is cheap enough to allow it, many more when it is very cheap, one when it is expensive. A single measurement of a fifty-millisecond solve varies by a factor of two with whatever else the machine is doing.
Each label records the BLAS thread count, since that is a real difference between environments and otherwise an invisible one: on the machine these were developed on, MATLAB takes ten threads, NumPy twelve, and Julia six.
The file format#
{
"schema": "laplace-dirichlet-bench-1",
"label": "what the legend should call this run",
"kind": "both",
"date": "2026-08-20",
"methods": [
{
"name": "harmonic basis, least squares",
"slot": "mps",
"ns": [4, 8, 16],
"E": [8.1e-4, 6.3e-6, 3.6e-10],
"T": [0.2, 0.4, 0.9]
}
]
}
slot picks the plot colour and marker and is one of fd2, fd4,
spectral, fast, iterative, mps, bie; anything else falls back to
fd2. E is the maximum absolute error over the chapter's fixed interior
lattice, T the solve time in milliseconds, and entries may be null for a
resolution a method skipped. kind records which ground truth was measured
(both, sing, or smooth); the page warns if it differs from the one the
lab is currently showing. Nothing stops you from writing a file in this
format from any other language or machine; the legend will say whatever
label says.