Gate Decomposition & Scheduling
Interactive tools for QFT compilation on neutral-atom hardware
1. \(CR_k\) Gate Decomposition
Each controlled rotation \(CR_k\) in the QFT must be decomposed into the hardware-native gate set: one CZ gate plus single-qubit \(R_z\) rotations. Select a gate to see its decomposition.
{
const theta = 2 * Math.PI / Math.pow(2, selectedK);
const thetaDeg = 360 / Math.pow(2, selectedK);
const halfTheta = theta / 2;
const halfThetaDeg = thetaDeg / 2;
return html`<div style="
background: #f0f4ff;
border-left: 4px solid #3b82f6;
padding: 16px 20px;
border-radius: 6px;
margin: 10px 0;
">
<div style="font-size: 18px; margin-bottom: 12px;">
<strong>CR<sub>${selectedK}</sub></strong> — rotation angle
θ = 2π/2<sup>${selectedK}</sup> = <strong>${thetaDeg.toFixed(2)}°</strong>
${selectedK === 1 ? ' (this is the CZ gate — no decomposition needed!)' : ''}
</div>
${selectedK > 1 ? html`
<div style="font-family: monospace; font-size: 14px; line-height: 2; background: white; padding: 12px 16px; border-radius: 4px;">
<strong>Native decomposition:</strong><br>
CR<sub>${selectedK}</sub> =
R<sub>z</sub>(${halfThetaDeg.toFixed(2)}°) ⊗ I
· I ⊗ R<sub>z</sub>(${halfThetaDeg.toFixed(2)}°)
· <span style="color: #dc2626; font-weight: bold;">CZ</span>
· I ⊗ R<sub>z</sub>(−${halfThetaDeg.toFixed(2)}°)
</div>
<div style="margin-top: 10px; font-size: 14px; color: #475569;">
<strong>Cost:</strong> 1 CZ gate + 3 single-qubit R<sub>z</sub> rotations.
<br>
<strong>Phase applied to |11⟩:</strong> e<sup>iθ</sup> = e<sup>i·${theta.toFixed(4)}</sup>
≈ ${Math.cos(theta).toFixed(4)} + ${Math.sin(theta).toFixed(4)}i
</div>
` : html`
<div style="font-family: monospace; font-size: 14px; background: white; padding: 12px 16px; border-radius: 4px;">
CR<sub>1</sub> = CZ (native gate — already in hardware gate set)
</div>
`}
</div>`;
}{
// Show the phase on the unit circle
const theta = 2 * Math.PI / Math.pow(2, selectedK);
const circleData = d3.range(0, 2 * Math.PI + 0.01, 0.02).map(a => ({
x: Math.cos(a),
y: Math.sin(a)
}));
const phasePoint = [{ x: Math.cos(theta), y: Math.sin(theta), label: `e^(2πi/2^${selectedK})` }];
const refPoint = [{ x: 1, y: 0, label: "1 (no phase)" }];
return Plot.plot({
title: `Phase applied by CR${selectedK} to |11⟩`,
width: 340,
height: 340,
marginLeft: 50,
x: { domain: [-1.4, 1.4], label: "Real" },
y: { domain: [-1.4, 1.4], label: "Imaginary" },
aspectRatio: 1,
marks: [
Plot.ruleX([0], { stroke: "#ddd" }),
Plot.ruleY([0], { stroke: "#ddd" }),
Plot.line(circleData, { x: "x", y: "y", stroke: "#e2e8f0", strokeWidth: 1.5 }),
Plot.line([[0, 0], [Math.cos(theta), Math.sin(theta)]], {
x: d => d[0],
y: d => d[1],
stroke: "#3b82f6",
strokeWidth: 2,
strokeDasharray: "4,4"
}),
Plot.dot(refPoint, { x: "x", y: "y", fill: "#94a3b8", r: 6 }),
Plot.dot(phasePoint, { x: "x", y: "y", fill: "#3b82f6", r: 8 }),
Plot.text(phasePoint, {
x: d => d.x * 1.2,
y: d => d.y * 1.2 + 0.08,
text: "label",
fill: "#3b82f6",
fontWeight: "bold",
fontSize: 12
}),
Plot.text(refPoint, {
x: d => d.x + 0.15,
y: d => d.y - 0.1,
text: "label",
fill: "#94a3b8",
fontSize: 11
})
]
});
}2. Routing Cost Comparison
Compare the cost of SWAP-based routing vs atom shuttling for a gate between two qubits at varying distances on a 2D grid.
{
const czError = 1 - czFidelity;
const shuttleDecoherencePerSite = 4e-5; // per-site decoherence
const czTimeUs = 0.5;
const shuttleTimePerSite = 4; // microseconds per site
const data = [];
for (let d = 1; d <= maxDist; d++) {
// SWAP routing: d SWAPs, each = 3 CZ gates
const swapCZCount = 3 * d;
const swapError = 1 - Math.pow(czFidelity, swapCZCount);
const swapTime = swapCZCount * czTimeUs;
// Shuttling: no gates, just transport
const shuttleError = d * shuttleDecoherencePerSite;
const shuttleTime = d * shuttleTimePerSite;
data.push({ distance: d, error: swapError * 100, time: swapTime, strategy: "SWAP routing" });
data.push({ distance: d, error: shuttleError * 100, time: shuttleTime, strategy: "Atom shuttling" });
}
return Plot.plot({
title: "Routing error vs distance",
width,
height: 340,
marginLeft: 60,
x: { label: "Distance (grid sites)", domain: [1, maxDist] },
y: { label: "Accumulated error (%)" },
color: {
domain: ["SWAP routing", "Atom shuttling"],
range: ["#ef4444", "#3b82f6"]
},
marks: [
Plot.line(data, {
x: "distance",
y: "error",
stroke: "strategy",
strokeWidth: 2.5
}),
Plot.dot(data, {
x: "distance",
y: "error",
fill: "strategy",
r: 3,
tip: true,
title: d => `d=${d.distance}: ${d.error.toFixed(2)}% error (${d.strategy})`
}),
Plot.ruleY([0])
]
});
}{
const czError = 1 - czFidelity;
const shuttleTimePerSite = 4;
const czTimeUs = 0.5;
const data = [];
for (let d = 1; d <= maxDist; d++) {
const swapTime = 3 * d * czTimeUs;
const shuttleTime = d * shuttleTimePerSite;
data.push({ distance: d, time: swapTime, strategy: "SWAP routing" });
data.push({ distance: d, time: shuttleTime, strategy: "Atom shuttling" });
}
return Plot.plot({
title: "Routing time vs distance",
width,
height: 340,
marginLeft: 60,
x: { label: "Distance (grid sites)", domain: [1, maxDist] },
y: { label: "Time (μs)" },
color: {
domain: ["SWAP routing", "Atom shuttling"],
range: ["#ef4444", "#3b82f6"]
},
marks: [
Plot.line(data, {
x: "distance",
y: "time",
stroke: "strategy",
strokeWidth: 2.5
}),
Plot.dot(data, {
x: "distance",
y: "time",
fill: "strategy",
r: 3,
tip: true,
title: d => `d=${d.distance}: ${d.time.toFixed(1)} μs (${d.strategy})`
}),
Plot.ruleY([0])
]
});
}{
const czError = 1 - czFidelity;
const shuttleDecoherencePerSite = 4e-5;
return html`<div style="
background: #f0fdf4;
border-left: 4px solid #22c55e;
padding: 12px 18px;
border-radius: 6px;
margin: 10px 0;
font-size: 14px;
">
<strong>Key insight:</strong>
SWAP routing error grows as 3d × ${(czError * 100).toFixed(1)}% ≈ ${(3 * czError * 100).toFixed(1)}% per site.
Shuttling error grows as d × ${(shuttleDecoherencePerSite * 100).toFixed(3)}% per site.
<br>
<strong>SWAP is ${(3 * czError / shuttleDecoherencePerSite).toFixed(0)}× noisier per unit distance</strong>,
but ${(4 / (3 * 0.5)).toFixed(1)}× faster.
The trade-off favors shuttling whenever fidelity matters more than speed.
</div>`;
}3. Compilation Strategy Comparison
Compare estimated fidelity across the three compilation strategies for QFT circuits of varying size.
{
const czErr = 1 - czFid2;
const data = [];
for (let n = 4; n <= 40; n += 2) {
// Raw gate count
let rawGates = n * (n - 1) / 2;
if (useApprox) {
const m = Math.ceil(2 * Math.log2(n) + 8);
rawGates = 0;
for (let i = 0; i < n; i++) rawGates += Math.min(n - i - 1, m);
}
// SWAP overhead: ~sqrt(n) SWAPs per gate on 2D grid, each = 3 CZ
const gridSize = Math.ceil(Math.sqrt(n));
const avgDist = gridSize / 2;
const swapGates = rawGates + rawGates * avgDist * 3;
const swapFidelity = Math.pow(czFid2, swapGates) * 100;
// Shuttle: no extra gates
const shuttleFidelity = Math.pow(czFid2, rawGates) * 100;
// Hybrid: short-range SWAP, long-range shuttle
const hybridGates = rawGates * 1.8; // ~80% overhead from short-range SWAPs
const hybridFidelity = Math.pow(czFid2, hybridGates) * 100;
data.push({ n, fidelity: swapFidelity, strategy: "SWAP" });
data.push({ n, fidelity: shuttleFidelity, strategy: "Shuttle" });
data.push({ n, fidelity: hybridFidelity, strategy: "Hybrid" });
}
return Plot.plot({
title: `Estimated QFT fidelity (${useApprox ? 'approximate' : 'exact'} QFT, CZ fidelity = ${(czFid2 * 100).toFixed(1)}%)`,
width,
height: 380,
marginLeft: 60,
x: { label: "Number of qubits n" },
y: { label: "Estimated fidelity (%)", domain: [0, 100] },
color: {
domain: ["SWAP", "Shuttle", "Hybrid"],
range: ["#ef4444", "#3b82f6", "#f59e0b"]
},
marks: [
Plot.ruleY([50], { stroke: "#ccc", strokeDasharray: "4,4" }),
Plot.text([{ x: 38, y: 53 }], {
x: "x", y: "y",
text: d => "50% threshold",
fill: "#aaa",
fontSize: 11
}),
Plot.line(data, {
x: "n",
y: "fidelity",
stroke: "strategy",
strokeWidth: 2.5
}),
Plot.dot(data, {
x: "n",
y: "fidelity",
fill: "strategy",
r: 3,
tip: true,
title: d => `n=${d.n}: ${d.fidelity.toFixed(1)}% (${d.strategy})`
})
]
});
}html`<div style="
background: #f8fafc;
border-left: 4px solid #64748b;
padding: 12px 18px;
border-radius: 6px;
margin: 10px 0;
font-size: 14px;
color: #475569;
">
<strong>How to read this:</strong>
Toggle "approximate QFT" to see the dramatic impact of truncation on all strategies.
Adjust CZ fidelity to simulate hardware improvements.
The shuttle strategy always has the best fidelity because it adds zero CZ gates for routing.
The SWAP strategy degrades fastest because each routing SWAP adds 3 CZ gates of error.
</div>`