Source browser
scripts/plot_results.py
Read the complete file below or download its original bytes. Line numbers provide stable links to a declaration or processing step.
File fingerprint
1#!/usr/bin/env python3
2"""Render SVG figures from the visible result tables and supplied fixtures.
3
4NumPy and Matplotlib render the figures. The visible HTML tables provide the
5recorded measurements, and prepared data files provide the example imagery.
6"""
7import argparse # Select a published result page or an alternate output directory.
8from html.parser import HTMLParser # Read visible table cells with the standard-library HTML parser.
9from pathlib import Path # Locate the versioned reports, fixtures and SVG outputs.
10import re # Add accessible descriptions to the standalone vector figures.
11
12
13class ReportTables(HTMLParser): # Collect the explicit publication tables and exact corpus scalar fields.
14 def __init__(self): # Initialize the active table and captured field state.
15 super().__init__(convert_charrefs=True) # Decode visible HTML entities back into their recorded text.
16 self.tables, self.values = {}, {} # Retain table rows and path-addressed corpus values.
17 self.active, self.row, self.cell = None, None, None # Track only the table currently being parsed.
18 self.row_attrs, self.capture = {}, None # Retain optional row identity and one scalar capture.
19
20 def handle_starttag(self, tag, attrs): # Recognize semantic table boundaries and report-value annotations.
21 attrs = dict(attrs) # Access attributes by their names.
22 if tag == "table" and attrs.get("id"): # Select tables carrying an authoritative identifier.
23 self.active = attrs["id"] # Remember the current publication table.
24 self.tables[self.active] = [] # Collect its rows in displayed order.
25 if self.active and tag == "tr": # Begin a row only within an identified table.
26 self.row, self.row_attrs = [], attrs # Preserve visible cells and any stable row identity.
27 if self.row is not None and tag in ("td", "th"): # Read both headings and ordinary data cells.
28 self.cell = [] # Begin accumulating this cell's visible text.
29 if attrs.get("data-report-path"): # Read exact scalar provenance already visible in the corpus page.
30 self.capture = (tag, attrs["data-report-path"], []) # Keep the closing tag and original dictionary path.
31
32 def handle_data(self, data): # Preserve human-readable table text and recorded scalar values.
33 if self.cell is not None: # Include nested code and link text in the current table cell.
34 self.cell.append(data) # Keep text until the cell closes.
35 if self.capture is not None: # Preserve the exact corpus value separately from surrounding table headings.
36 self.capture[2].append(data) # Retain line breaks and scalar spelling.
37
38 def handle_endtag(self, tag): # Finish each collected value at its semantic boundary.
39 if self.capture is not None and tag == self.capture[0]: # Store a complete path-addressed report field.
40 self.values[self.capture[1]] = "".join(self.capture[2]) # Avoid changing diagnostics or hash strings.
41 self.capture = None # Stop collecting after that scalar's closing tag.
42 if tag in ("td", "th") and self.cell is not None: # Finish one displayed table cell.
43 self.row.append(" ".join("".join(self.cell).split())) # Normalize only table-layout whitespace.
44 self.cell = None # Wait for the next cell.
45 if tag == "tr" and self.row is not None: # Finish one complete publication row.
46 self.tables[self.active].append((self.row_attrs, self.row)) # Retain attributes and cells together.
47 self.row = None # Stop collecting cells until another row begins.
48 if tag == "table": # Leave the current identified table.
49 self.active = None # Collect text inside the selected table cells.
50
51
52def read_tables(path): # Parse one local standalone HTML report.
53 reader = ReportTables() # Use only the standard HTML parser to recover the visible record.
54 reader.feed(path.read_text(encoding="utf-8")) # Read the complete published page.
55 return reader # Return both visible tables and exact corpus metadata.
56
57
58def numeric_rows(report, identifier, start): # Skip headings and return only rows with numeric measured fields.
59 result = [] # Keep the original visible row order.
60 for attrs, cells in report.tables[identifier]: # Visit each heading or data row.
61 try: # Parse measurements from numeric cells.
62 values = [float(value) for value in cells[start:]] # Read the exact rounded numbers published in the table.
63 except ValueError: # Keep headings out of the numerical record.
64 continue # Continue with the next displayed row.
65 result.append((attrs, cells[:start], values)) # Retain labels and row identities with their numerical values.
66 return result # Use the recorded measurement values and timing ratios.
67
68
69def save_svg(figure, output, title, description): # Export a self-contained scientific vector figure.
70 figure.savefig(output, format="svg", bbox_inches="tight", metadata={"Date": "2026-10-15", "Creator": "shdr publication plots", "Title": title}) # Preserve the recorded measurement date.
71 text = output.read_text(encoding="utf-8") # Add screen-reader text to the exported SVG root.
72 from html import escape # Keep plot descriptions safe inside XML.
73 description = f'<title id="plot-title">{escape(title)}</title><desc id="plot-description">{escape(description)}</desc>' # Explain units and scope inside the downloadable artifact.
74 text = re.sub(r"(<svg\b[^>]*)(>)", r'\1 role="img" aria-labelledby="plot-title plot-description"\2' + description, text, count=1) # Make the SVG usable independently of its HTML figure caption.
75 text = "\n".join(line.rstrip() for line in text.splitlines()) + "\n" # Remove exporter padding while preserving the SVG's paths and text.
76 output.write_text(text, encoding="utf-8") # Keep every plot as a portable standalone file.
77 print(output.name) # Report the artifact generated by this invocation.
78
79
80def benchmark_plot(report, host, title, graphics, output, np, plt): # Compare all 25 measured pipelines on one configuration.
81 rows = numeric_rows(report, "benchmark-" + host, 2) # Read the exact visible CPU, graphics and reported ratio columns.
82 labels = [label[0] for _, label, _ in rows] # Preserve names in the same order as the benchmark executable.
83 values = np.asarray([value for _, _, value in rows]) # Keep recorded rounded means and unrounded-derived reported ratios.
84 y = np.arange(len(rows)) # Assign one shared position to each pipeline.
85 figure, axes = plt.subplots(1, 2, figsize=(14.5, 12.2), gridspec_kw={"width_ratios": [2.6, 1]}, sharey=True) # Align time and relative-completion views for direct reading.
86 axes[0].barh(y - .17, values[:, 0], height=.32, color="#225d9b", label="C++11 CPU") # Plot the measured serial CPU means.
87 axes[0].barh(y + .17, values[:, 1], height=.32, color="#0c8a79", label=graphics) # Distinguish llvmpipe software from actual hardware in the legend.
88 axes[0].set_xscale("log") # Keep microsecond-scale and large neural workloads visible together.
89 axes[0].set_yticks(y, labels, fontsize=9) # Make every pipeline label readable in the vector export.
90 axes[0].invert_yaxis() # Match the published table's top-to-bottom ordering.
91 axes[0].set_xlabel("Mean completed workload time (ms, logarithmic axis)") # State the measured unit and nonlinear axis clearly.
92 axes[0].grid(axis="x", which="both", alpha=.2) # Help compare bars across the broad timing range.
93 axes[0].legend(loc="upper right", frameon=False) # Place the execution-path legend beside the row labels.
94 axes[1].axvline(1, color="#566071", linewidth=1, linestyle="--") # Mark equal completion time explicitly.
95 axes[1].scatter(values[:, 2], y, s=34, color="#bd5a2d", zorder=3) # Use the benchmark's recorded CPU/GPU ratio.
96 axes[1].set_xscale("log") # Show advantages in either direction on a symmetric ratio scale.
97 axes[1].set_xlim(.02, 40) # Use the same ratio range for all three configurations.
98 axes[1].set_xticks([.02, .1, 1, 10, 40], ["0.02×", "0.1×", "1×", "10×", "40×"]) # Avoid opaque scientific notation for the relative-completion view.
99 axes[1].set_xlabel("CPU time / graphics time") # Label the plotted value as the CPU/GPU time ratio.
100 axes[1].grid(axis="x", which="both", alpha=.2) # Retain readable ratio comparisons at small values.
101 axes[1].tick_params(axis="y", left=False, labelleft=False) # Keep a single shared pipeline-label column.
102 figure.suptitle(title, fontsize=18, x=.02, ha="left") # Name the tested CPU and graphics implementation.
103 figure.text(.02, .025, "20 measured repetitions · seed 12345 · scale 1 · ES 3.1 profile\nResident means exclude compilation, first upload and final readback. Hybrid transfers remain included.", fontsize=10, color="#46546a") # Keep timing scope attached to downloaded figures.
104 figure.tight_layout(rect=(0, .06, 1, .97)) # Reserve room for the title and measurement note.
105 save_svg(figure, output, title, "All 25 recorded pipeline timings and CPU-to-graphics ratios. Timing means are in milliseconds. Ratios greater than one favor the graphics path.") # Export the scientific plot with accessible units and interpretation.
106 plt.close(figure) # Release figure memory before generating the next configuration.
107
108
109def evaluation_plot(report, output, np, plt): # Compare the six recorded complete held-out evaluations.
110 rows = numeric_rows(report, "mnist-metrics", 2) # Read correct counts, image counts, accuracy, seconds and maximum error.
111 labels = [text[0] + " / " + text[1] for _, text, _ in rows] # Keep each CPU and graphics configuration explicit.
112 accuracy = np.array([values[2] for _, _, values in rows]) # Preserve the logged accuracy percentages.
113 seconds = np.array([values[3] for _, _, values in rows]) # Keep full-evaluation scope separate from resident benchmark time.
114 figure, axes = plt.subplots(1, 2, figsize=(14.5, 5.3)) # Show accuracy and completed duration side by side.
115 y = np.arange(len(rows)) # Assign the same row to each path in both panels.
116 axes[0].barh(y, accuracy, color="#0c8a79", label="Correct") # Show measured successful classifications on a full percentage scale.
117 axes[0].barh(y, 100 - accuracy, left=accuracy, color="#d9a06f", label="Incorrect") # Show the complete observed error fraction.
118 axes[0].set_xlim(0, 100) # Avoid exaggerating equal accuracies with a truncated axis.
119 axes[0].set_yticks(y, labels, fontsize=9) # Retain the identity of all six measured paths.
120 axes[0].invert_yaxis() # Match the accessible result table order.
121 axes[0].set_xlabel("Official held-out labels (%)") # State the denominator and unit.
122 axes[0].legend(frameon=False, loc="lower left", bbox_to_anchor=(0, 1.0), ncol=2) # Explain both correct and incorrect portions of every bar.
123 axes[1].barh(y, seconds, color=["#225d9b" if index % 2 == 0 else "#0c8a79" for index in y]) # Distinguish CPU and graphics durations consistently.
124 axes[1].set_yticks(y, labels, fontsize=9) # Keep the duration panel usable on its own.
125 axes[1].invert_yaxis() # Align paths with the accuracy panel.
126 axes[1].set_xlabel("Completed 10,000-image evaluation (seconds)") # Include preprocessing and comparison in the stated scope.
127 for index, value in enumerate(seconds): # Label actual recorded durations directly on the figure.
128 axes[1].text(value + .4, index, f"{value:g}", va="center", fontsize=9) # Avoid estimating values from the axis.
129 axes[1].set_xlim(0, max(seconds) * 1.18) # Leave room for the duration annotations.
130 axes[1].grid(axis="x", alpha=.2) # Help compare completed evaluation times.
131 figure.suptitle("Complete MNIST evaluation · 9,778 / 10,000 correct on every path", fontsize=16) # State the exact observed classification result.
132 figure.tight_layout(rect=(0, 0, 1, .94)) # Keep labels and title clear of each other.
133 save_svg(figure, output, "Complete held-out MNIST evaluations", "Every recorded path classified 9778 of 10000 labels correctly, or 97.78 percent. Duration includes batch construction, input preparation, native execution, result reads and reference comparison. llvmpipe uses the CPU.") # Keep model-evaluation scope with the plot.
134 plt.close(figure) # Release plotting resources.
135
136
137def coverage_plot(report, output, np, plt): # Show passed tests and skipped profiles as separate outcomes.
138 rows = numeric_rows(report, "runtime-tests", 1) # Read passed, skipped, failed and total counts.
139 values = np.array([value for _, _, value in rows], dtype=int) # Keep test outcomes as exact integer counts.
140 labels = [text[0] for _, text, _ in rows] # Label configurations by their public hardware names.
141 figure, axis = plt.subplots(figsize=(11.5, 4.2)) # Give each registered configuration a clearly separated bar.
142 y = np.arange(len(rows)) # Position the three platform totals.
143 axis.barh(y, values[:, 0], color="#0c8a79", label="Passed") # Count only tests that actually completed successfully.
144 axis.barh(y, values[:, 1], left=values[:, 0], color="#c5cedb", label="Unavailable context") # Show profile-availability skips explicitly.
145 axis.barh(y, values[:, 2], left=values[:, 0] + values[:, 1], color="#c3443b", label="Failed") # Keep a zero-valued failure category explicit in the legend.
146 for index, row in enumerate(values): # Label the plotted bars with exact counts.
147 axis.text(row[3] + 1, index, f"{row[0]} passed · {row[1]} skipped · {row[2]} failed", va="center", fontsize=10) # Include the absence of failures and the scope of skipped contexts.
148 axis.set_yticks(y, labels) # Identify the tested renderer configuration.
149 axis.invert_yaxis() # Preserve the order of the source table.
150 axis.set_xlim(0, max(values[:, 3]) + 47) # Reserve room for complete count labels.
151 axis.set_xlabel("Registered CTest cases") # Distinguish registered cases from individual shader/profile compilations.
152 axis.legend(frameon=False, loc="lower right") # Identify skips as profile-availability outcomes.
153 axis.set_title("Runtime and integration validation · no failed registered tests", loc="left", fontsize=15) # Describe observed outcomes with their unit of coverage.
154 figure.tight_layout() # Keep count labels inside the exported bounds.
155 save_svg(figure, output, "Registered test outcomes", "Passed, skipped and failed registered CTest cases for the three configurations. Some registered cases contain many numerical checks. The separate 250 shader/profile checks and eight frontend tests are described in the result tables.") # Prevent confusion between suite totals and inner assertion counts.
156 plt.close(figure) # Release the figure after export.
157
158
159def loss_plot(report, output, np, plt): # Plot the measured initial and final mini-batch losses.
160 rows = numeric_rows(report, "mini-batch-loss", 1) # Read step count, starting loss and final loss.
161 labels = [text[0] for _, text, _ in rows] # Keep the three small model names visible.
162 values = np.array([value for _, _, value in rows]) # Use the identical logged values observed across all six paths.
163 x = np.arange(len(rows)) # Separate the three architectures.
164 figure, axis = plt.subplots(figsize=(9, 4.8)) # Use bars because only the start and finish were recorded.
165 axis.bar(x - .18, values[:, 1], width=.35, color="#8ca7c5", label="Before updates") # Show the observed starting cross entropy.
166 axis.bar(x + .18, values[:, 2], width=.35, color="#0c8a79", label="After updates") # Show the observed final mini-batch cross entropy.
167 axis.set_xticks(x, [name + f"\n{int(value[0])} updates" for name, value in zip(labels, values)]) # Make differing update counts explicit.
168 axis.set_ylim(0, .82) # Show a true zero baseline for the loss comparison.
169 axis.set_ylabel("Mean binary cross entropy") # Use the models' actual scalar loss definition.
170 axis.legend(frameon=False) # Distinguish the two recorded observations.
171 axis.set_title("Real digit mini-batch training · 32 selected zero/one images", loc="left", fontsize=14) # Avoid calling training-set loss a held-out accuracy result.
172 axis.grid(axis="y", alpha=.2) # Help compare measured loss changes.
173 figure.tight_layout() # Keep model and update-count labels readable.
174 save_svg(figure, output, "Observed real-data mini-batch loss changes", "Recorded loss before and after training for ANN, CNN and transformer models on one 32-image training mini-batch. No intermediate learning curve or generalization metric was recorded.") # State the limited scope of these observations.
175 plt.close(figure) # Release plotting resources.
176
177
178def confusion_plot(report, output, np, plt): # Plot the complete independent-framework reference confusion table.
179 rows = numeric_rows(report, "reference-confusion", 1) # Read the ten visible ground-truth rows and predicted-class counts.
180 matrix = np.array([value for _, _, value in rows], dtype=int) # Preserve all 100 actual confusion counts.
181 from matplotlib.colors import LogNorm # Make rare confusions readable beside large correct-class totals.
182 figure, axis = plt.subplots(figsize=(8.5, 7.3)) # Keep each digit pair legible in the standalone SVG.
183 image = axis.imshow(np.ma.masked_equal(matrix, 0), cmap="Blues", norm=LogNorm(vmin=1, vmax=matrix.max())) # Leave zero-count cells white and display positive counts logarithmically.
184 for row in range(10): # Annotate every original digit class.
185 for column in range(10): # Annotate every predicted digit class.
186 value = matrix[row, column] # Use the exact displayed reference count.
187 axis.text(column, row, str(value), ha="center", va="center", fontsize=8, color="white" if value > 50 else "#17243a") # Keep large and small counts readable against the color scale.
188 axis.set_xticks(range(10)) # Label predictions with their original digit values.
189 axis.set_yticks(range(10)) # Label true classes with the official MNIST labels.
190 axis.set_xlabel("Predicted digit · independent framework reference") # Avoid claiming that native per-class predictions were archived.
191 axis.set_ylabel("Official test digit") # State the ground-truth source.
192 axis.set_title("Reference confusion · 10,000 official test images", loc="left", fontsize=14) # Define the complete evaluated population.
193 figure.colorbar(image, ax=axis, label="Reference predictions per cell (log scale)") # State the nonlinear color unit.
194 figure.tight_layout() # Keep axis labels and colorbar visible.
195 save_svg(figure, output, "Independent reference model confusion", "Exact confusion counts from the shipped independent framework logits and all 10000 official labels. Native per-class prediction matrices were not retained. Native complete scores and total accuracy were checked separately.") # Keep the distinction between native and reference predictions explicit.
196 plt.close(figure) # Release plotting resources.
197
198
199def fixture_plot(fixtures, output, np, plt): # Illustrate actual prepared inputs and an explicitly independent signal reference.
200 earth = np.frombuffer((fixtures / "earth_rgb.bin").read_bytes(), dtype=np.uint8).reshape(64, 64, 3) # Read the exact prepared NASA RGB image.
201 ecg = np.frombuffer((fixtures / "signal_ecg.bin").read_bytes(), dtype="<f4").reshape(2, 2048)[0].astype(float) # Read the channel-major MLII signal in millivolts.
202 digits = np.frombuffer((fixtures / "mnist_test.bin").read_bytes(), dtype=np.uint8).reshape(-1, 28, 28) # Read the shipped official test-image prefix.
203 labels = np.frombuffer((fixtures / "mnist_labels.bin").read_bytes(), dtype=np.uint8) # Retain the original digit labels.
204 indices = [int(np.flatnonzero(labels == value)[0]) for value in range(10)] # Show the first supplied instance of each class.
205 offsets = np.arange(65) - 32 # Center the documented odd-length FIR design.
206 coefficients = 2 * (40 / 360) * np.sinc(2 * (40 / 360) * offsets) * np.hamming(65) # Independently calculate the Hamming-sinc 40 Hz low-pass reference.
207 coefficients = (coefficients / coefficients.sum()).astype(np.float32).astype(float) # Match stored coefficient precision while keeping the reference accumulation independent.
208 filtered = np.convolve(ecg, coefficients)[:len(ecg)] # Apply the documented causal zero-prefix FIR convention.
209 time = np.arange(len(ecg)) / 360 # Express sample positions in seconds at the public recording's sample rate.
210 frequencies = np.fft.rfftfreq(len(ecg), 1 / 360) # Express the real-spectrum bins in hertz.
211 figure = plt.figure(figsize=(14.5, 8.5)) # Combine image, waveform, spectrum and digit examples into one clear fixture plate.
212 grid = figure.add_gridspec(3, 3, height_ratios=[1, 1, .65], width_ratios=[1, 1.1, 1.1]) # Reserve a full-width final row for the ten digit classes.
213 axis = figure.add_subplot(grid[:2, 0]) # Display the supplied low-resolution image.
214 axis.imshow(earth, interpolation="nearest") # Preserve the prepared RGB8 pixels.
215 axis.set_title("NASA Blue Marble · prepared 64 × 64 RGB", fontsize=11) # Identify the source and prepared image size.
216 axis.axis("off") # Avoid implying a geographic coordinate system for the RGB preview.
217 axis = figure.add_subplot(grid[0, 1:]) # Show the original ECG and independent filter reference together.
218 axis.plot(time, ecg, linewidth=.8, color="#7a8fa8", label="Prepared MLII") # Plot the actual float32 waveform from the fixture.
219 axis.plot(time, filtered, linewidth=1, color="#0c8a79", label="Independent 65-tap, 40 Hz FIR reference") # Clearly distinguish a computed reference from archived runtime output.
220 axis.set_xlim(0, 2.5) # Show the original samples from an initial waveform interval.
221 axis.set_xlabel("Time (s)") # State waveform time units.
222 axis.set_ylabel("Potential (mV)") # Preserve the published ADC scaling.
223 axis.legend(frameon=False, fontsize=9, ncol=2) # Identify source samples and reference filtering.
224 axis.grid(alpha=.2) # Make waveform amplitude comparisons readable.
225 axis = figure.add_subplot(grid[1, 1:]) # Show the independent full-fixture real Fourier spectrum.
226 for signal, color, name in [(ecg, "#7a8fa8", "Prepared MLII"), (filtered, "#0c8a79", "Independent FIR reference")]: # Use the same sources and colors as the waveform panel.
227 amplitude = np.abs(np.fft.rfft(signal)) / len(signal) # Compute a correctly normalized real-signal amplitude spectrum.
228 amplitude[1:-1] *= 2 # Double only the interior positive-frequency bins.
229 axis.semilogy(frequencies, np.maximum(amplitude, 1e-9), color=color, linewidth=.9, label=name) # Use an explicit small display floor on the logarithmic amplitude axis.
230 axis.set_xlabel("Frequency (Hz)") # Use physical frequency units on the axis.
231 axis.set_ylabel("Single-sided amplitude (mV)") # State the spectrum normalization and signal unit.
232 axis.set_xlim(0, 180) # Show the original 360 Hz recording's complete Nyquist range.
233 axis.grid(alpha=.2) # Help locate the low-pass attenuation region.
234 digit_grid = grid[2, :].subgridspec(1, 10) # Keep one original labeled sample per digit class.
235 for digit, index in enumerate(indices): # Preserve an explicit reproducible sample-selection rule.
236 axis = figure.add_subplot(digit_grid[0, digit]) # Give each test digit its own clean preview.
237 axis.imshow(digits[index], cmap="gray", vmin=0, vmax=255, interpolation="nearest") # Display the original unsigned-byte image values.
238 axis.set_title(f"Label {digit}\nTest index {index}", fontsize=9) # Distinguish ground-truth labels from model predictions.
239 axis.axis("off") # Keep pixel previews uncluttered.
240 figure.suptitle("Recorded public inputs · images, ECG and official handwritten digits", fontsize=16) # Describe the figure as actual input data and reference signal analysis.
241 figure.tight_layout(rect=(0, 0, 1, .95)) # Separate the title from the specimen panels.
242 save_svg(figure, output, "Actual prepared public fixtures", "Actual NASA image pixels, PhysioNet MLII samples at 360 Hz, independently calculated 40 Hz FIR and Fourier references, and first shipped MNIST instance of each class. This is an input illustration, not an invented runtime measurement.") # Keep source and reference distinctions with the standalone artifact.
243 plt.close(figure) # Release plotting resources.
244
245
246def main(): # Reproduce all figures from the published HTML and bundled data.
247 root = Path(__file__).resolve().parent.parent # Resolve paths relative to the project.
248 parser = argparse.ArgumentParser(description=__doc__) # Explain that plotting is an optional publication step.
249 parser.add_argument("--report", type=Path, default=root / "docs/results.html") # Read the authoritative visible measurement tables.
250 parser.add_argument("--output", type=Path, default=root / "docs/plots") # Choose where standalone SVGs are written.
251 parser.add_argument("--fixtures", type=Path, default=root / "examples/data") # Read the prepared public input bytes.
252 args = parser.parse_args() # Apply explicit caller paths before importing optional plotting packages.
253 import numpy as np # Calculate only reference illustrations and array-based plot coordinates.
254 import matplotlib # Keep scientific rendering outside normal library builds.
255 matplotlib.use("Agg") # Render figures with the headless plotting backend.
256 import matplotlib.pyplot as plt # Render standard scientific vector plots.
257 plt.rcParams.update({"font.family": "DejaVu Sans", "svg.fonttype": "none", "svg.hashsalt": "shdr-publication-2026-10-15", "axes.spines.top": False, "axes.spines.right": False, "axes.titlepad": 12}) # Keep selectable text, clear axes and consistent publication typography.
258 report = read_tables(args.report) # Recover all plotted measurements from their accessible tables.
259 args.output.mkdir(parents=True, exist_ok=True) # Create only the requested publication artifact directory.
260 for host, title, graphics in [("amd", "Ryzen 9 5900X · C++11 and llvmpipe software", "llvmpipe software"), ("intel", "Core i7-1260P · C++11 and Iris Xe", "Iris Xe hardware"), ("pi", "Raspberry Pi 5 · C++11 and V3D", "V3D hardware")]: # Generate the same benchmark views for all measured configurations.
261 benchmark_plot(report, host, title, graphics, args.output / ("benchmark-" + host + ".svg"), np, plt) # Preserve platform identity and exact recorded numbers.
262 evaluation_plot(report, args.output / "mnist-evaluation.svg", np, plt) # Show all six complete held-out measurements.
263 coverage_plot(report, args.output / "test-coverage.svg", np, plt) # Separate successful tests from unavailable-context skips.
264 loss_plot(report, args.output / "mini-batch-loss.svg", np, plt) # Plot only the before-and-after training observations actually recorded.
265 confusion_plot(report, args.output / "mnist-reference-confusion.svg", np, plt) # Reproduce the full visible reference confusion matrix.
266 fixture_plot(args.fixtures, args.output / "public-fixtures.svg", np, plt) # Illustrate the real shipped input bytes with clearly labeled reference analysis.
267
268
269if __name__ == "__main__": # Run plotting only when requested explicitly.
270 main() # Generate the standalone publication figures.