// The Result widget: a job's result as the engine gave it. Its counts as bars, the // most frequent first (or their sampled frequencies: each count over the shots), // its expectation values with the bound or standard error the method gives, its // amplitudes, the method and the accuracy class it names, and the receipt's check // made by the engine in Python. The model's `frequencies` and `top` choose what // the bars show. const SVG = 'http://www.w3.org/2000/svg'; const BAR = '#7aa0ff'; function el(tag, attrs = {}, ...kids) { const e = document.createElement(tag); for (const [k, v] of Object.entries(attrs)) { if (k === 'text') e.textContent = v; else if (v != null) e.setAttribute(k, String(v)); } for (const k of kids) if (k != null) e.append(k); return e; } function svgEl(tag, attrs = {}, text) { const e = document.createElementNS(SVG, tag); for (const [k, v] of Object.entries(attrs)) e.setAttribute(k, String(v)); if (text != null) e.textContent = text; return e; } const num = (x) => (typeof x === 'number' ? (Number.isInteger(x) ? String(x) : String(Number(x.toPrecision(6)))) : String(x)); function badge(ok) { return el('span', { class: `wq-badge ${ok ? 'wq-good' : 'wq-bad'}`, text: ok ? 'verified' : 'INVALID' }); } function histogram(counts, shots, top, frequencies) { const rows = Object.entries(counts).slice(0, top); if (!rows.length) return null; const labelW = Math.max(7.5 * Math.max(...rows.map(([k]) => k.length)) + 12, 40); const barW = 260, rowH = 18; const peak = Math.max(...rows.map(([, v]) => v)) || 1; const W = labelW + barW + 70, H = rowH * rows.length + 4; const s = svgEl('svg', { width: W, height: H, viewBox: `0 0 ${W} ${H}`, class: 'wq-histogram', role: 'img', 'aria-label': `Counts of ${rows.length} outcomes` }); rows.forEach(([k, v], i) => { const y = 2 + i * rowH; const w = Math.max((barW * v) / peak, 1); s.append(svgEl('text', { x: labelW - 6, y: y + 9, 'text-anchor': 'end', 'dominant-baseline': 'central', class: 'wq-mono' }, k)); const r = svgEl('rect', { x: labelW, y: y + 2, width: w.toFixed(1), height: rowH - 4, rx: 2, fill: BAR }); r.append(svgEl('title', {}, `${k}: ${v} of ${shots}`)); s.append(r); s.append(svgEl('text', { x: (labelW + w + 6).toFixed(1), y: y + 9, 'dominant-baseline': 'central', class: 'wq-small' }, frequencies && shots ? (v / shots).toFixed(4) : String(v))); }); return s; } function table(head, rows) { const t = el('table', { class: 'wq-table' }, el('tr', {}, ...head.map((h) => el('th', { text: h })))); for (const r of rows) t.append(el('tr', {}, ...r.map((c) => el('td', { class: 'wq-mono', text: c })))); return t; } function render({ model, el: host }) { const root = el('div', { class: 'wq wq-result-widget' }); host.append(root); function draw() { const d = model.get('data') || {}; const top = Math.max(1, model.get('top') || 16); const frequencies = !!model.get('frequencies'); const head = el('div', {}, el('b', { text: d.method || '?' }), ' · accuracy ', el('b', { text: d.accuracy || '?' })); if (d.accuracy_note) head.append(' ', el('span', { class: 'wq-muted', text: `(${d.accuracy_note})` })); const parts = [head]; if (d.why) parts.push(el('div', { class: 'wq-muted', text: d.why })); const counts = d.counts || {}; const n = Object.keys(counts).length; if (n) { const toggle = el('input', { type: 'checkbox' }); toggle.checked = frequencies; toggle.addEventListener('change', () => { model.set('frequencies', toggle.checked); model.save_changes(); }); const topBox = el('input', { type: 'number', min: 1, max: Math.max(n, 1), value: Math.min(top, n), class: 'wq-num' }); topBox.addEventListener('change', () => { model.set('top', Math.max(1, Number(topBox.value) || 1)); model.save_changes(); }); parts.push(el('div', { class: 'wq-bar' }, el('span', { text: `${d.shots} shots, ${d.distinct_outcomes ?? n} distinct outcomes; showing` }), topBox, el('label', { class: 'wq-check' }, toggle, el('span', { text: 'as sampled frequencies' })))); parts.push(histogram(counts, d.shots, top, frequencies)); const rest = Object.values(counts).slice(top).reduce((a, b) => a + b, 0) + (d.omitted_shots || 0); if (rest) parts.push(el('div', { class: 'wq-muted', text: `${rest} more shots fell on outcomes not drawn` })); } const exps = d.expectations || []; if (exps.length) { parts.push(table(['observable', 'value', 'error'], exps.map((e) => [ e.observable, num(e.value), e.bound != null ? `± ${num(e.bound)} (bound)` : e.stderr != null ? `± ${num(e.stderr)} (std. error)` : '', ]))); } const amps = d.amplitudes || []; if (amps.length) parts.push(table(['basis state', 're', 'im', '|a|²'], amps.map((a) => [a.bits, num(a.re), num(a.im), num(a.re * a.re + a.im * a.im)]))); if (d.receipt) { const r = d.receipt; const line = el('div', { class: 'wq-line' }, 'receipt ', badge(r.valid === true), ' signed by ', el('span', { class: 'wq-mono', title: r.signer || '', text: r.signer || r.key || '?' })); if (r.demo) line.append(' ', el('span', { class: 'wq-muted', text: '(the published demo key: it shows the result is unaltered, not who signed it)' })); parts.push(line); } root.replaceChildren(...parts.filter(Boolean)); } draw(); for (const ev of ['change:data', 'change:frequencies', 'change:top']) model.on(ev, draw); return () => { for (const ev of ['change:data', 'change:frequencies', 'change:top']) model.off(ev, draw); }; } export default { render };