Loading examples/CMakeLists.txt +4 −1 Original line number Diff line number Diff line Loading @@ -15,3 +15,6 @@ add_test(NAME qrt_ftqc_simple COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CM add_test(NAME qrt_ftqc_rus COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/repeat-until-success.cpp) add_test(NAME qrt_ftqc_qec COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/bit-flip-code.cpp) add_test(NAME qrt_ftqc_deuteron COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/deuteron.cpp) add_test(NAME qrt_ftqc_bit_flip_qec_std_lib COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/error_correcting_code.cpp) add_test(NAME qrt_ftqc_five_qubit_qec_std_lib COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/five_qubit_qec_code.cpp) add_test(NAME qrt_ftqc_steane_qec_std_lib COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/steane_qec_code.cpp) No newline at end of file examples/ftqc_qrt/bit-flip-code.cpp +0 −3 Original line number Diff line number Diff line #include <qalloc> // Example demonstrates a simple 3-qubit bit-flip code. // Compile: // qcor -qpu aer[noise-model:<noise.json>] -qrt ftqc bit-flip-code.cpp Loading Loading @@ -93,7 +91,6 @@ __qpu__ void resetAll(qreg q) { // Error corrected Bell example: // Note: the 3-q bit-flip code can only protect against X errors. __qpu__ void bellQEC(qreg q, int nbRuns) { using qcor::xasm; int ancQbId = 6; for (int i = 0; i < nbRuns; ++i) { // Apply H before encoding. Loading examples/ftqc_qrt/error_correcting_code.cpp 0 → 100644 +30 −0 Original line number Diff line number Diff line #include <qcor_qec> __qpu__ void applyError(qreg q, int qIdx) { std::cout << "Apply X error @ q[" << qIdx << "].\n"; X(q[qIdx]); } using namespace ftqc; int main() { auto q = qalloc(4); // Retrieve "bit-flip" code: auto [stabilizers, encodeFunc, recoverFunc] = getQecCode("bit_flip"); encodeFunc(q, 0, {1, 2}); // If using a perfect simulator, apply a random X error to observe syndrome changes. applyError(q, 0); std::vector<int> syndromes; // Measure the stabilizer syndromes: measure_stabilizer_generators(q, stabilizers, {0, 1, 2}, 3, syndromes); assert(syndromes.size() == 2); std::cout << "Syndrome: <Z0Z1> = " << syndromes[0] << "; <Z1Z2> = " << syndromes[1] << "\n"; // Recover: recoverFunc(q, {0, 1, 2}, syndromes); // Measure again to check: syndromes.clear(); measure_stabilizer_generators(q, stabilizers, {0, 1, 2}, 3, syndromes); std::cout << "AFTER CORRECTION: \nSyndrome: <Z0Z1> = " << syndromes[0] << "; <Z1Z2> = " << syndromes[1] << "\n"; } No newline at end of file examples/ftqc_qrt/five_qubit_qec_code.cpp 0 → 100644 +65 −0 Original line number Diff line number Diff line #include <qcor_qec> // Note: although QEC encode and syndrome decode kernels don't need FTQC // runtime, in order to feed-forward syndrome, we need to use FTQC runtime. // Compile with: // $ qcor -qrt ftqc -qpu qpp five_qubit_qec_code.cpp // Helper kernel to verify error-correcting procedure __qpu__ void applyError(qreg q, int qIdx, int opId) { if (opId == 1) { std::cout << "Apply X error @ q[" << qIdx << "].\n"; X(q[qIdx]); } if (opId == 2) { std::cout << "Apply Y error @ q[" << qIdx << "].\n"; Y(q[qIdx]); } if (opId == 3) { std::cout << "Apply Z error @ q[" << qIdx << "].\n"; Z(q[qIdx]); } } using namespace ftqc; int main() { // Five-qubit code + 1 scratch qubit for syndrome measurement auto q = qalloc(6); const std::vector<int> LOGICAL_REG{0, 1, 2, 3, 4}; const int ANC_QUBIT = 5; // Retrieve "five-qubit" code: auto [stabilizers, encodeFunc, recoverFunc] = getQecCode("five-qubit"); // Encode the qubit: from qubit 0 to qubit register [0-4] encodeFunc(q, 0, {1, 2, 3, 4}); // Test all possible *single-qubit* error for (int qId = 0; qId < 5; ++qId) { for (int opId = 1; opId <= 3; ++opId) { // If using a perfect simulator, apply a random error to observe syndrome // changes. applyError(q, qId, opId); std::vector<int> syndromes; // Measure the stabilizer syndromes: measure_stabilizer_generators(q, stabilizers, LOGICAL_REG, ANC_QUBIT, syndromes); assert(syndromes.size() == 4); std::cout << "Syndrome: <X0Z1Z2Z3> = " << syndromes[0] << "; <X1Z2Z3X4> = " << syndromes[1] << "; <X0X2Z3Z4> = " << syndromes[2] << "; <Z0X1X3Z4> = " << syndromes[3] << "\n"; // Recover: recoverFunc(q, LOGICAL_REG, syndromes); // Measure again to check: syndromes.clear(); measure_stabilizer_generators(q, stabilizers, LOGICAL_REG, ANC_QUBIT, syndromes); std::cout << "AFTER CORRECTION: \nSyndrome: <X0Z1Z2Z3> = " << syndromes[0] << "; <X1Z2Z3X4> = " << syndromes[1] << "; <X0X2Z3Z4> = " << syndromes[2] << "; <Z0X1X3Z4> = " << syndromes[3] << "\n"; } } } No newline at end of file examples/ftqc_qrt/steane_qec_code.cpp 0 → 100644 +73 −0 Original line number Diff line number Diff line #include <qcor_qec> // Note: although QEC encode and syndrome decode kernels don't need FTQC // runtime, in order to feed-forward syndrome, we need to use FTQC runtime. // Compile with: // $ qcor -qrt ftqc -qpu qpp steane_qec_code.cpp // Helper kernel to verify error-correcting procedure __qpu__ void applyError(qreg q, int qIdx, int opId) { if (opId == 1) { std::cout << "Apply X error @ q[" << qIdx << "].\n"; X(q[qIdx]); } if (opId == 2) { std::cout << "Apply Y error @ q[" << qIdx << "].\n"; Y(q[qIdx]); } if (opId == 3) { std::cout << "Apply Z error @ q[" << qIdx << "].\n"; Z(q[qIdx]); } } using namespace ftqc; int main() { // Steane is a seven-qubit code + 1 scratch qubit for syndrome measurement auto q = qalloc(8); const std::vector<int> LOGICAL_REG{0, 1, 2, 3, 4, 5, 6}; const int ANC_QUBIT = 7; // Retrieve "steane" code: auto [stabilizers, encodeFunc, recoverFunc] = getQecCode("steane"); // Encode the qubit: from qubit 0 to qubit register [0-6] encodeFunc(q, 0, {1, 2, 3, 4, 5, 6}); // Test all possible *single-qubit* error for (int opId = 1; opId <= 3; ++opId) { for (int qId = 0; qId < 7; ++qId) { // If using a perfect simulator, apply a random error to observe syndrome // changes. applyError(q, qId, opId); std::vector<int> syndromes; // Measure the stabilizer syndromes: measure_stabilizer_generators(q, stabilizers, LOGICAL_REG, ANC_QUBIT, syndromes); assert(syndromes.size() == 6); const auto printSyndrome = [](const std::vector<int> &syndVals) { // First 3 are X syndromes std::cout << "X syndrome: "; for (int i = 0; i < 3; ++i) { std::cout << syndVals[i] << " "; } // Next 3 are Z syndromes std::cout << "\nZ syndrome: "; for (int i = 3; i < 6; ++i) { std::cout << syndVals[i] << " "; } std::cout << "\n"; }; printSyndrome(syndromes); // Recover: recoverFunc(q, LOGICAL_REG, syndromes); // Measure again to check: syndromes.clear(); measure_stabilizer_generators(q, stabilizers, LOGICAL_REG, ANC_QUBIT, syndromes); std::cout << "AFTER CORRECTION: \n"; printSyndrome(syndromes); } } } No newline at end of file Loading
examples/CMakeLists.txt +4 −1 Original line number Diff line number Diff line Loading @@ -15,3 +15,6 @@ add_test(NAME qrt_ftqc_simple COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CM add_test(NAME qrt_ftqc_rus COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/repeat-until-success.cpp) add_test(NAME qrt_ftqc_qec COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/bit-flip-code.cpp) add_test(NAME qrt_ftqc_deuteron COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/deuteron.cpp) add_test(NAME qrt_ftqc_bit_flip_qec_std_lib COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/error_correcting_code.cpp) add_test(NAME qrt_ftqc_five_qubit_qec_std_lib COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/five_qubit_qec_code.cpp) add_test(NAME qrt_ftqc_steane_qec_std_lib COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/steane_qec_code.cpp) No newline at end of file
examples/ftqc_qrt/bit-flip-code.cpp +0 −3 Original line number Diff line number Diff line #include <qalloc> // Example demonstrates a simple 3-qubit bit-flip code. // Compile: // qcor -qpu aer[noise-model:<noise.json>] -qrt ftqc bit-flip-code.cpp Loading Loading @@ -93,7 +91,6 @@ __qpu__ void resetAll(qreg q) { // Error corrected Bell example: // Note: the 3-q bit-flip code can only protect against X errors. __qpu__ void bellQEC(qreg q, int nbRuns) { using qcor::xasm; int ancQbId = 6; for (int i = 0; i < nbRuns; ++i) { // Apply H before encoding. Loading
examples/ftqc_qrt/error_correcting_code.cpp 0 → 100644 +30 −0 Original line number Diff line number Diff line #include <qcor_qec> __qpu__ void applyError(qreg q, int qIdx) { std::cout << "Apply X error @ q[" << qIdx << "].\n"; X(q[qIdx]); } using namespace ftqc; int main() { auto q = qalloc(4); // Retrieve "bit-flip" code: auto [stabilizers, encodeFunc, recoverFunc] = getQecCode("bit_flip"); encodeFunc(q, 0, {1, 2}); // If using a perfect simulator, apply a random X error to observe syndrome changes. applyError(q, 0); std::vector<int> syndromes; // Measure the stabilizer syndromes: measure_stabilizer_generators(q, stabilizers, {0, 1, 2}, 3, syndromes); assert(syndromes.size() == 2); std::cout << "Syndrome: <Z0Z1> = " << syndromes[0] << "; <Z1Z2> = " << syndromes[1] << "\n"; // Recover: recoverFunc(q, {0, 1, 2}, syndromes); // Measure again to check: syndromes.clear(); measure_stabilizer_generators(q, stabilizers, {0, 1, 2}, 3, syndromes); std::cout << "AFTER CORRECTION: \nSyndrome: <Z0Z1> = " << syndromes[0] << "; <Z1Z2> = " << syndromes[1] << "\n"; } No newline at end of file
examples/ftqc_qrt/five_qubit_qec_code.cpp 0 → 100644 +65 −0 Original line number Diff line number Diff line #include <qcor_qec> // Note: although QEC encode and syndrome decode kernels don't need FTQC // runtime, in order to feed-forward syndrome, we need to use FTQC runtime. // Compile with: // $ qcor -qrt ftqc -qpu qpp five_qubit_qec_code.cpp // Helper kernel to verify error-correcting procedure __qpu__ void applyError(qreg q, int qIdx, int opId) { if (opId == 1) { std::cout << "Apply X error @ q[" << qIdx << "].\n"; X(q[qIdx]); } if (opId == 2) { std::cout << "Apply Y error @ q[" << qIdx << "].\n"; Y(q[qIdx]); } if (opId == 3) { std::cout << "Apply Z error @ q[" << qIdx << "].\n"; Z(q[qIdx]); } } using namespace ftqc; int main() { // Five-qubit code + 1 scratch qubit for syndrome measurement auto q = qalloc(6); const std::vector<int> LOGICAL_REG{0, 1, 2, 3, 4}; const int ANC_QUBIT = 5; // Retrieve "five-qubit" code: auto [stabilizers, encodeFunc, recoverFunc] = getQecCode("five-qubit"); // Encode the qubit: from qubit 0 to qubit register [0-4] encodeFunc(q, 0, {1, 2, 3, 4}); // Test all possible *single-qubit* error for (int qId = 0; qId < 5; ++qId) { for (int opId = 1; opId <= 3; ++opId) { // If using a perfect simulator, apply a random error to observe syndrome // changes. applyError(q, qId, opId); std::vector<int> syndromes; // Measure the stabilizer syndromes: measure_stabilizer_generators(q, stabilizers, LOGICAL_REG, ANC_QUBIT, syndromes); assert(syndromes.size() == 4); std::cout << "Syndrome: <X0Z1Z2Z3> = " << syndromes[0] << "; <X1Z2Z3X4> = " << syndromes[1] << "; <X0X2Z3Z4> = " << syndromes[2] << "; <Z0X1X3Z4> = " << syndromes[3] << "\n"; // Recover: recoverFunc(q, LOGICAL_REG, syndromes); // Measure again to check: syndromes.clear(); measure_stabilizer_generators(q, stabilizers, LOGICAL_REG, ANC_QUBIT, syndromes); std::cout << "AFTER CORRECTION: \nSyndrome: <X0Z1Z2Z3> = " << syndromes[0] << "; <X1Z2Z3X4> = " << syndromes[1] << "; <X0X2Z3Z4> = " << syndromes[2] << "; <Z0X1X3Z4> = " << syndromes[3] << "\n"; } } } No newline at end of file
examples/ftqc_qrt/steane_qec_code.cpp 0 → 100644 +73 −0 Original line number Diff line number Diff line #include <qcor_qec> // Note: although QEC encode and syndrome decode kernels don't need FTQC // runtime, in order to feed-forward syndrome, we need to use FTQC runtime. // Compile with: // $ qcor -qrt ftqc -qpu qpp steane_qec_code.cpp // Helper kernel to verify error-correcting procedure __qpu__ void applyError(qreg q, int qIdx, int opId) { if (opId == 1) { std::cout << "Apply X error @ q[" << qIdx << "].\n"; X(q[qIdx]); } if (opId == 2) { std::cout << "Apply Y error @ q[" << qIdx << "].\n"; Y(q[qIdx]); } if (opId == 3) { std::cout << "Apply Z error @ q[" << qIdx << "].\n"; Z(q[qIdx]); } } using namespace ftqc; int main() { // Steane is a seven-qubit code + 1 scratch qubit for syndrome measurement auto q = qalloc(8); const std::vector<int> LOGICAL_REG{0, 1, 2, 3, 4, 5, 6}; const int ANC_QUBIT = 7; // Retrieve "steane" code: auto [stabilizers, encodeFunc, recoverFunc] = getQecCode("steane"); // Encode the qubit: from qubit 0 to qubit register [0-6] encodeFunc(q, 0, {1, 2, 3, 4, 5, 6}); // Test all possible *single-qubit* error for (int opId = 1; opId <= 3; ++opId) { for (int qId = 0; qId < 7; ++qId) { // If using a perfect simulator, apply a random error to observe syndrome // changes. applyError(q, qId, opId); std::vector<int> syndromes; // Measure the stabilizer syndromes: measure_stabilizer_generators(q, stabilizers, LOGICAL_REG, ANC_QUBIT, syndromes); assert(syndromes.size() == 6); const auto printSyndrome = [](const std::vector<int> &syndVals) { // First 3 are X syndromes std::cout << "X syndrome: "; for (int i = 0; i < 3; ++i) { std::cout << syndVals[i] << " "; } // Next 3 are Z syndromes std::cout << "\nZ syndrome: "; for (int i = 3; i < 6; ++i) { std::cout << syndVals[i] << " "; } std::cout << "\n"; }; printSyndrome(syndromes); // Recover: recoverFunc(q, LOGICAL_REG, syndromes); // Measure again to check: syndromes.clear(); measure_stabilizer_generators(q, stabilizers, LOGICAL_REG, ANC_QUBIT, syndromes); std::cout << "AFTER CORRECTION: \n"; printSyndrome(syndromes); } } } No newline at end of file