59 programs, each with what the reader must do with it: the language specification's 21 example programs, unchanged (those that run held to their results, the rest to the code that names the first construct the reader cannot hold exactly, or the example's own error), and a program for each construct with a reference written without it. stdgates.qasm applies every standard gate once, and its reference writes each in U and CX alone. Expectations: refused (a code), warns (every warning's code), deterministic (every shot's outcome), distribution (exact outcome probabilities), expectations (exact Pauli values), equivalent (a reference's unitary up to a global phase), exact (the bit-exact circuit takes it or refuses it with a code), outputs, timing and calibrations. bundle.json holds the cases with their text inline for builds that read no files; a test holds it equal to the files. CI: wai-quantum-lang.yml runs the reader's tests, the corpus natively, the reader built without the lowerings, and the corpus under wasm32-wasip2 by wasmtime; wai-web's wasm32 tests read every case through the page's engine (the wasm32 count goes from 8 to 9). Co-Authored-By: Claude Opus 5.5 <[email protected]>
171 lines
4.5 KiB
Text
171 lines
4.5 KiB
Text
/*
|
|
* Magic state distillation and computation
|
|
*/
|
|
include "stdgates.inc";
|
|
|
|
const int[32] buffer_size = 6; // size of magic state buffer
|
|
|
|
// Y-basis measurement
|
|
def ymeasure(qubit q) -> bit {
|
|
s q;
|
|
h q;
|
|
return measure q;
|
|
}
|
|
|
|
/*
|
|
* Distillation subroutine takes 10 |H> magic states
|
|
* and 3 scratch qubits that will be reinitialized.
|
|
* The first two input magic states are the outputs.
|
|
* The subroutine returns a success bit that is true
|
|
* on success and false otherwise (see arXiv:1811.00566).
|
|
*/
|
|
def distill(qubit[10] magic, qubit[3] scratch) -> bool {
|
|
bit temp;
|
|
bit[3] checks;
|
|
// Encode two magic states in the [[4,2,2]] code
|
|
reset scratch[0: 1];
|
|
h scratch[1];
|
|
cx scratch[1], magic[0];
|
|
cx magic[1], scratch[0];
|
|
cx magic[0], scratch[0];
|
|
cx scratch[1], magic[1];
|
|
// Body of distillation circuit
|
|
cy magic[2], scratch[0];
|
|
h magic[1];
|
|
temp = ymeasure(magic[2]);
|
|
if(temp == 1) { ry(-pi / 2) scratch[0]; }
|
|
reset scratch[2];
|
|
h scratch[2];
|
|
cz scratch[2], scratch[0];
|
|
cy magic[3], scratch[0];
|
|
temp = ymeasure(magic[3]);
|
|
if(temp==0) { ry(pi / 2) scratch[0]; }
|
|
h scratch[0];
|
|
s scratch[0];
|
|
cy magic[4], scratch[1];
|
|
temp = ymeasure(magic[4]);
|
|
if(temp==1) { ry(-pi / 2) scratch[1]; }
|
|
cz scratch[3], scratch[2];
|
|
cy magic[5], scratch[1];
|
|
temp = ymeasure(magic[5]);
|
|
if(temp==0) { ry(pi / 2) scratch[1]; }
|
|
cy scratch[0], magic[1];
|
|
inv @ s scratch[1];
|
|
cz scratch[0], scratch[1];
|
|
h scratch[0];
|
|
cy scratch[1], magic[1];
|
|
cy magic[6], scratch[0];
|
|
temp = ymeasure(magic[6]);
|
|
if(temp == 1) { ry(-pi / 2) scratch[0]; }
|
|
cz scratch[2], scratch[1];
|
|
cz scratch[2], scratch[0];
|
|
cy magic[7], scratch[0];
|
|
temp = ymeasure(magic[7]);
|
|
if(temp == 0) ry(pi / 2) scratch[0];
|
|
cy magic[8], scratch[1];
|
|
temp = ymeasure(magic[8]);
|
|
if(temp==1) { ry(-pi / 2) scratch[1]; }
|
|
cz scratch[2], scratch[1];
|
|
cy magic[9], scratch[1];
|
|
temp = ymeasure(magic[9]);
|
|
if(temp == 0) { ry(pi / 2) scratch[1]; }
|
|
h scratch[2];
|
|
// Decode [[4,2,2]] code
|
|
cx magic[0], scratch[0];
|
|
cx scratch[1], magic[1];
|
|
cx magic[1], scratch[0];
|
|
cx scratch[1], magic[0];
|
|
h scratch[1];
|
|
checks = measure scratch;
|
|
success = ~(bool(checks[0]) | bool(checks[1]) | bool(checks[2]));
|
|
return success;
|
|
}
|
|
|
|
// Repeat level-0 distillation until success
|
|
def rus_level_0(qubit[10] magic, qubit[3] scratch) {
|
|
bool success;
|
|
while(~success) {
|
|
reset magic;
|
|
ry(pi / 4) magic;
|
|
success = distill(magic, scratch);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Run two levels of 10:2 magic state distillation.
|
|
* Both levels have two distillations running in parallel.
|
|
* The output pairs from the first level are separated and
|
|
* input to different second levels distillation circuits
|
|
* because a failure in a first level circuit can lead to
|
|
* errors on both outputs.
|
|
* Put the requested even number of copies into the buffer.
|
|
*/
|
|
def distill_and_buffer(int[32] num, qubit[33] work, qubit[buffer_size] buffer) {
|
|
int[32] index;
|
|
bit success_0;
|
|
bit success_1;
|
|
let magic_lvl0 = work[0: 9];
|
|
let magic_lvl1_0 = work[10: 19];
|
|
let magic_lvl1_1 = work[20: 29];
|
|
let scratch = work[30: 32];
|
|
|
|
// Run first-level circuits until 10 successes,
|
|
// storing the outputs for use in the second level
|
|
for uint i in [0: 9] {
|
|
rus_level_0 magic_lvl0, scratch;
|
|
swap magic_lvl0[0], magic_lvl1_0[i];
|
|
swap magic_lvl0[1], magic_lvl1_1[i];
|
|
}
|
|
|
|
// Run two second level circuits simultaneously
|
|
success_0 = distill(magic_lvl1_0, scratch);
|
|
success_1 = distill(magic_lvl1_1, scratch);
|
|
|
|
// Move usable magic states into the buffer register
|
|
if(success_0 && index < buffer_size) {
|
|
swap magic_lvl1_0[0: 1], buffer[index: index + 1];
|
|
index += 2;
|
|
}
|
|
if(success_1 && index < buffer_size) {
|
|
swap magic_lvl1_1[0: 1], buffer[index: index + 1];
|
|
index += 2;
|
|
}
|
|
}
|
|
|
|
// Apply Ry(pi/4) to a qubit by consuming a magic state
|
|
// from the magic state buffer at address "addr"
|
|
def Ty(int[32] addr, qubit q, qubit[buffer_size] buffer) {
|
|
bit outcome;
|
|
cy buffer[addr], q;
|
|
outcome = ymeasure(buffer[addr]);
|
|
if(outcome == 1) ry(pi / 2) q;
|
|
}
|
|
|
|
qubit[33] workspace;
|
|
qubit[buffer_size] buffer;
|
|
|
|
qubit[5] q;
|
|
bit[5] c;
|
|
int[32] address;
|
|
|
|
// initialize
|
|
reset workspace;
|
|
reset buffer;
|
|
reset q;
|
|
|
|
distill_and_buffer(buffer_size) workspace, buffer;
|
|
|
|
// Consume magic states to apply some gates ...
|
|
h q[0];
|
|
cx q[0], q[1];
|
|
Ty(address) q[0], buffer;
|
|
address += 1;
|
|
cx q[0], q[1];
|
|
Ty(address) q[1], buffer;
|
|
address += 1;
|
|
|
|
// In principle each Ty gate can execute as soon as the magic
|
|
// state is available at the address in the buffer register.
|
|
|
|
// We can continue alternating state distillation and computation
|
|
// to refill and empty a circular buffer.
|