Unverified Commit 94bc79fa authored by Mccaskey, Alex's avatar Mccaskey, Alex Committed by GitHub
Browse files

Merge pull request #38 from tnguyen-ornl/tnguyen/std-lib

Implements some QEC codes in QCOR lib
parents 8a736f11 68955173
Loading
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -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
+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 
@@ -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.
+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
+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
+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