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]>
65 lines
2.5 KiB
JavaScript
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 };
|