open-standards/wai/wai-quantum-py/python/wai_quantum/static/circuit.js
Transaction Science 22fdc7a3cb wai-quantum-py: WAI Quantum in Python and notebooks, in-process
A new crate, wai/wai-quantum-py, built by maturin 1.15.0 into one abi3 wheel
per platform (pyo3 0.29.3, Python 3.9 on), module wai_quantum. Its extension
module wraps the shared job engine and nothing else: run, plan, lint, draw
(text and the engine SVG), layout, critique, improve, shortcuts,
equivalent, verify, seal, canonical, digest, methods, accuracy_classes and
history, values crossing one to one with JSON (NaN, integers past 64 bits
and non-string keys refused). A job is the service form as a plain dict
with helpers (counts, probabilities, expectations, amplitudes, method,
accuracy, receipt); Key reads and writes the command line key files and
finds the same user key; bloch gives each qubit reduced state from the
engine expectation values. A refusal raises EngineError with the engine
message, its line, and a code slot for the engine diagnostic codes.

Service is a client in the standard library alone for the job service
(submit, status, result, cancel, run), naming itself
wai-quantum-python/<version>, its receipts checked here offline.

Widgets (the widgets extra): Circuit (the engine drawing, gates clickable,
authorship marks from a history), Result, Receipt (the engine verdict) and
Bloch (drag to turn), each a plain ES module, each with static HTML (and
SVG) fallbacks that render without the widget library.

Five doc notebooks run in CI and are held to their stored outputs.
ci/check.sh is the whole check; 62 pytest tests hold the package to the
command line (same results, plans, lints, critiques, drawings, methods,
equivalence verdicts; receipts verified both ways; the same user key; the
digest recomputed from Python canonical bytes), to the service run locally,
and run the front ends under node on the payloads; Python 3.9 smoke with
the wheel alone. Workflow wai-quantum-py.yml runs it on linux and macos.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 19:51:08 -04:00

65 lines
2.5 KiB
JavaScript

// The Circuit widget: a program's circuit as the engine drew it (engine::svg, the
// Studio's picture). Clicking a gate selects its operation (the model's
// `selected`, its index in the program; clicking it again clears it). When the
// drawing marks whose hand each gate is in, "Who wrote it" shows or hides the
// marks. Nothing here redraws the circuit: the SVG is the engine's, its labels
// escaped by the engine.
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 render({ model, el: host }) {
const root = el('div', { class: 'wq wq-circuit-widget' });
host.append(root);
let marked = true;
function draw() {
const d = model.get('data') || {};
const selected = model.get('selected');
const box = el('div', { class: 'wq-scroll' });
box.innerHTML = d.svg || '';
const svg = box.querySelector('svg');
const bar = el('div', { class: 'wq-bar' });
if (svg && Array.isArray(d.key) && d.key.length) {
const id = `wq-hands-${Math.random().toString(36).slice(2)}`;
const check = el('input', { type: 'checkbox', id });
check.checked = marked;
check.addEventListener('change', () => { marked = check.checked; svg.classList.toggle('wq-unmarked', !marked); });
bar.append(el('label', { for: id, class: 'wq-check' }, check, el('span', { text: 'Who wrote it' })));
svg.classList.toggle('wq-unmarked', !marked);
}
const status = el('span', { class: 'wq-muted' });
if (svg) {
for (const g of svg.querySelectorAll('.qc-item[data-op]')) {
const op = Number(g.dataset.op);
g.classList.add('wq-pick');
g.classList.toggle('wq-selected', selected === op);
if (selected === op) status.textContent = `operation ${op}: ${g.querySelector('title')?.textContent || ''}`;
g.addEventListener('click', () => {
model.set('selected', model.get('selected') === op ? null : op);
model.save_changes();
});
}
}
if (!status.textContent) status.textContent = 'Click a gate to select its operation.';
bar.append(status);
root.replaceChildren(box, bar);
}
draw();
model.on('change:data', draw);
model.on('change:selected', draw);
return () => {
model.off('change:data', draw);
model.off('change:selected', draw);
};
}
export default { render };