Commit a68d343a authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Added 5-q QEC code



Added a factory function to retrieve utils for a specific QEC code

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent c6997a17
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
@@ -9,20 +9,22 @@ using namespace ftqc;

int main() {
  auto q = qalloc(4);
  bit_flip_encoder(q, 0, {1, 2});
  std::vector<int> syndromes;
  // Retrieve "bit-flip" code:
  auto [stabilizers, encodeFunc, recoverFunc] = getQecCode("bit_flip");
  encodeFunc(q, 0, {1, 2});  
  // If using a perfec simulator, apply a random X error to observe syndrome changes.
  applyError(q, 2);
  applyError(q, 0);
  
  std::vector<int> syndromes;
  // Measure the stabilizer syndromes:
  measure_stabilizer_generators(q, bit_flip_code_stabilizers(), {0, 1, 2}, 3, 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:
  bit_flip_recover(q, {0, 1, 2}, syndromes);
  recoverFunc(q, {0, 1, 2}, syndromes);
  // Measure again to check:
  syndromes.clear();
  measure_stabilizer_generators(q, bit_flip_code_stabilizers(), {0, 1, 2}, 3, syndromes);
  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
+1 −25
Original line number Diff line number Diff line
#pragma once
#include <qcor_common>

std::vector<std::vector<qcor::PauliOperator>> bit_flip_code_stabilizers() {
  static const std::vector<std::vector<qcor::PauliOperator>> STABILIZERS{
@@ -30,26 +29,3 @@ __qpu__ void bit_flip_recover(qreg q, std::vector<int> logicalReg,
    X(q[logicalReg[2]]);
  }
}
 No newline at end of file

#ifdef _QCOR_FTQC_RUNTIME
namespace ftqc {
__qpu__ void measure_stabilizer_generators(
    qreg q, std::vector<std::vector<qcor::PauliOperator>> stabilizerGroup,
    std::vector<int> logicalReg, int scratchQubitIdx,
    std::vector<int> &out_syndromes) {
  for (auto &stabilizer : stabilizerGroup) {
    for(auto &op : stabilizer) {
      // TODO: generalize for all codes
      std::map<int, int> bitMap;
      bitMap[0] = logicalReg[0];
      bitMap[1] = logicalReg[1];
      bitMap[2] = logicalReg[2];
      op.mapQubitSites(bitMap);
    }
    int syndromeResult;
    measure_basis_with_scratch(q, scratchQubitIdx, stabilizer, syndromeResult);
    out_syndromes.emplace_back(syndromeResult);
  }
}
} // namespace ftqc
#endif
 No newline at end of file
+79 −0
Original line number Diff line number Diff line
#pragma once

// Distance-3 quantum error correction code with 5 qubits
std::vector<std::vector<qcor::PauliOperator>> five_qubit_code_stabilizers() {
  static const std::vector<std::vector<qcor::PauliOperator>> STABILIZERS{
      {qcor::X(0), qcor::Z(1), qcor::Z(2), qcor::X(3)},
      {qcor::X(1), qcor::Z(2), qcor::Z(3), qcor::X(4)},
      {qcor::X(0), qcor::X(2), qcor::Z(3), qcor::Z(4)},
      {qcor::Z(0), qcor::X(1), qcor::X(3), qcor::Z(4)}};
  return STABILIZERS;
}

__qpu__ void five_qubit_code_encoder(qreg q, int dataQubitIdx,
                                     std::vector<int> scratchQubitIdx) {
  CX(q[dataQubitIdx], q[scratchQubitIdx[1]);
  H(q[dataQubitIdx]);
  H(q[scratchQubitIdx[0]]);
  CX(q[dataQubitIdx], q[scratchQubitIdx[2]]);
  CX(q[scratchQubitIdx[0]], q[dataQubitIdx]);
  CX(q[dataQubitIdx], q[scratchQubitIdx[1]]);
  CX(q[scratchQubitIdx[0]], q[scratchQubitIdx[3]]);
  H(q[scratchQubitIdx[0]]);
  H(q[dataQubitIdx]);
  CX(q[scratchQubitIdx[0]], q[scratchQubitIdx[2]]);
  CX(q[dataQubitIdx], q[scratchQubitIdx[3]]);
  X(q[scratchQubitIdx[2]]);
}

__qpu__ void five_qubit_code_recover(qreg q, std::vector<int> logicalReg,
                                     std::vector<int> syndromes) {
  auto syndromeIndex = syndrome_array_to_int(syndromes);
  if (syndromeIndex > 0) {
    if (syndromeIndex == 1) {
      X(q[logicalReg[1]]);
    }
    if (syndromeIndex == 2) {
      Z(q[logicalReg[4]]);
    }
    if (syndromeIndex == 3) {
      X(q[logicalReg[2]]);
    }
    if (syndromeIndex == 4) {
      Z(q[logicalReg[2]]);
    }
    if (syndromeIndex == 5) {
      Z(q[logicalReg[0]]);
    }
    if (syndromeIndex == 6) {
      X(q[logicalReg[3]]);
    }
    if (syndromeIndex == 7) {
      Y(q[logicalReg[2]]);
    }
    if (syndromeIndex == 8) {
      X(q[logicalReg[0]]);
    }
    if (syndromeIndex == 9) {
      Z(q[logicalReg[3]]);
    }
    if (syndromeIndex == 10) {
      Z(q[logicalReg[1]]);
    }
    if (syndromeIndex == 11) {
      Y(q[logicalReg[1]]);
    }
    if (syndromeIndex == 12) {
      X(q[logicalReg[4]]);
    }
    if (syndromeIndex == 13) {
      Y(q[logicalReg[0]]);
    }
    if (syndromeIndex == 14) {
      Y(q[logicalReg[4]]);
    }
    if (syndromeIndex == 15) {
      Y(q[logicalReg[3]]);
    }
  }
}
 No newline at end of file
+57 −0
Original line number Diff line number Diff line

#pragma once
#include <functional>
#include "bit_flip_code.hpp"
#include "five_qubit_code.hpp"

// Encode a physical qubit into a logical qubit using given scratch qubits.
// Inputs:
// - Qubit register
// - Data qubit index (int)
// - List of scratch qubits (vector<int>)
using encodeFn = std::function<void(qreg, int, std::vector<int>)>;
// Recover (apply error correction) based on syndrome data:
// Inputs:
// - Qubit register
// - Logical qubit register (vector<int>)
// - Syndrome data (vector<int>)
using recoverFn = std::function<void(qreg, std::vector<int>, std::vector<int>)>;

// Set of stabilizers define the QEC code
using stabilizerGroups = std::vector<std::vector<qcor::PauliOperator>>;

using QecCode = std::tuple<stabilizerGroups, encodeFn, recoverFn>;

// Get the set of utils to handle a specific QEC code
// Code name:
// - "bit-flip"
// - "five-qubit"
// - "seven-qubit"
// - "surface-code",
// etc.
QecCode getQecCode(const std::string &in_codeName) {
  if (in_codeName == "bit-flip") {
    encodeFn encoder(
        [](qreg q, int dataQubitIdx, std::vector<int> scratchQubitIdx) {
          bit_flip_encoder(q, dataQubitIdx, scratchQubitIdx);
        });
    recoverFn recover(
        [](qreg q, std::vector<int> logicalReg, std::vector<int> syndromes) {
          bit_flip_recover(q, logicalReg, syndromes);
        });
    return std::make_tuple(bit_flip_code_stabilizers(), encoder, recover);
  }
  if (in_codeName == "five-qubit") {
    encodeFn encoder(
        [](qreg q, int dataQubitIdx, std::vector<int> scratchQubitIdx) {
          five_qubit_code_encoder(q, dataQubitIdx, scratchQubitIdx);
        });
    recoverFn recover(
        [](qreg q, std::vector<int> logicalReg, std::vector<int> syndromes) {
          five_qubit_code_recover(q, logicalReg, syndromes);
        });
    return std::make_tuple(five_qubit_code_stabilizers(), encoder, recover);
  }
  throw std::runtime_error("Error: '" + in_codeName +
                           "' is not a valid QEC code.");
}
 No newline at end of file

lib/impl/qec_utils.hpp

0 → 100644
+33 −0
Original line number Diff line number Diff line
#pragma once
#include <qcor_common>

int syndrome_array_to_int(const std::vector<int> &syndromes) {
  int result = 0;
  for (int i = 0; i < syndromes.size(); ++i) {
    result += ((1 << i) * syndromes[i]);
  }
  return result;
}

#ifdef _QCOR_FTQC_RUNTIME
namespace ftqc {
__qpu__ void measure_stabilizer_generators(
    qreg q, std::vector<std::vector<qcor::PauliOperator>> stabilizerGroup,
    std::vector<int> logicalReg, int scratchQubitIdx,
    std::vector<int> &out_syndromes) {
  for (auto &stabilizer : stabilizerGroup) {
    for (auto &op : stabilizer) {
      // TODO: generalize for all codes
      std::map<int, int> bitMap;
      for (int i = 0; i < logicalReg.size(); ++i) {
        bitMap[i] = logicalReg[i];
      }
      op.mapQubitSites(bitMap);
    }
    int syndromeResult;
    measure_basis_with_scratch(q, scratchQubitIdx, stabilizer, syndromeResult);
    out_syndromes.emplace_back(syndromeResult);
  }
}
} // namespace ftqc
#endif
 No newline at end of file
Loading