mirror of https://github.com/openqasm/openqasm.git
172 lines
4.5 KiB
Plaintext
172 lines
4.5 KiB
Plaintext
/*
|
|
* 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.
|