Commit e8b831b5 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

Merge branch 'qrt_impls'

parents 6e6bb230 1af5b5ce
Loading
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -11,3 +11,6 @@ add_test(NAME qrt_kernel_include COMMAND ${CMAKE_BINARY_DIR}/qcor -c -I${CMAKE_C
add_test(NAME qrt_period_finding COMMAND ${CMAKE_BINARY_DIR}/qcor -c -I${CMAKE_CURRENT_SOURCE_DIR}/shared ${CMAKE_CURRENT_SOURCE_DIR}/simple/period_finding.cpp)
add_test(NAME qrt_grover COMMAND ${CMAKE_BINARY_DIR}/qcor -c ${CMAKE_CURRENT_SOURCE_DIR}/grover/grover.cpp)
add_test(NAME qrt_adapt COMMAND ${CMAKE_BINARY_DIR}/qcor -c ${CMAKE_CURRENT_SOURCE_DIR}/hybrid/adapt_h2.cpp)
add_test(NAME qrt_ftqc_simple COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/simple-demo.cpp)
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)
 No newline at end of file
+132 −0
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 
// ./a.out

bool getLogicalVal(qreg q, int logicalIdx) {
  if (q.creg[logicalIdx*3] == q.creg[logicalIdx*3]) {
    // First two bits matched.
    return q.creg[logicalIdx*3];
  }
  // The last bit is the tie-breaker.
  return q.creg[logicalIdx*3 + 2];
}

// Encode qubits into logical qubits:
// Assume q[0], q[3], q[6] are initial physical qubits
// that will be mapped to logical qubits q[0-2], q[3-5], etc.
__qpu__ void encodeQubits(qreg q) {
  int nbLogicalQubits = q.size() / 3;
  for (int i = 0; i < nbLogicalQubits; ++i) {
    int physicalQubitIdx = 3 * i;
    CX(q[physicalQubitIdx], q[physicalQubitIdx + 1]);
    CX(q[physicalQubitIdx], q[physicalQubitIdx + 2]);
  }
}

// Logical CNOT b/w two logical qubits
__qpu__ void cnotLogical(qreg q) {
  for (int i = 0; i < 3; ++i) {
    CX(q[i], q[3 + i]);
  }
}

__qpu__ void measureLogical(qreg q, int logicalIdx) {
  int physicalIdx = logicalIdx * 3;
  for (int i = physicalIdx; i < physicalIdx + 3; ++i) {
    Measure(q[i]);
  }
}

__qpu__ void correctLogicalQubit(qreg q, int logicalIdx, int ancIdx) {
  int physicalIdx = logicalIdx * 3;
  // Assume that we only has 1 ancilla qubit
  CX(q[physicalIdx], q[ancIdx]);
  CX(q[physicalIdx + 1], q[ancIdx]);
  const bool parity01 = Measure(q[ancIdx]);
  if (parity01) {
    // Reset anc qubit for reuse
    X(q[ancIdx]);
  }

  CX(q[physicalIdx + 1], q[ancIdx]);
  CX(q[physicalIdx + 2], q[ancIdx]);
  const bool parity12 = Measure(q[ancIdx]);
  if (parity12) {
    // Reset anc qubit
    X(q[ancIdx]);
  }

  // Correct error based on parity results
  if (parity01 && !parity12) {
    X(q[physicalIdx]);
  }  
  
  if (parity01 && parity12) {
    X(q[physicalIdx + 1]);
  }  

  if (!parity01 && parity12) {
    X(q[physicalIdx + 2]);
  }
}

__qpu__ void runQecCycle(qreg q) {
  int nbLogicalQubits = q.size() / 3;
  int ancBitIdx = q.size() - 1;
  for (int i = 0; i < nbLogicalQubits; ++i) {
    correctLogicalQubit(q, i, ancBitIdx);
  }
}

__qpu__ void resetAll(qreg q) {
  for (int i = 0; i < q.size(); ++i) {
    // Reset qubits by measure + correct.
    if (Measure(q[i])) {
      X(q[i]);
    }
  }
}

// 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.
    H(q[0]);
    // Encode the qubits into logical qubits.
    encodeQubits(q);
    // Run a QEC cycle
    runQecCycle(q);
    // Apply *logical* CNOT
    cnotLogical(q);
    // Run a QEC cycle
    runQecCycle(q);
    
    // Measure *logical* qubits
    measureLogical(q, 0);
    measureLogical(q, 1);

    // Get *logical* results
    const bool logicalReq0 = getLogicalVal(q, 0);
    const bool logicalReq1 = getLogicalVal(q, 1);
    
    if (logicalReq0 == logicalReq1) {
      std::cout << "Iter " << i << ": Matched!\n";
    } else {
      std::cout << "Iter " << i << ": NOT Matched!\n";
    }
    resetAll(q);
  }
}

int main() {
  // Note: we need 3 physical qubits for each logical qubit +
  // an ancilla qubit for syndrom measurement.
  auto q = qalloc(7);
  bellQEC(q, 100);
}
 No newline at end of file
+43 −0
Original line number Diff line number Diff line
#include <qalloc>
// Compile with: qcor -qpu qpp -qrt ftqc repeat-until-success.cpp
// Execute: ./a.out
// We should get the print out conditioned by the measurement.
// If not using the "ftqc" QRT, this will cause errors since the Measure results
// are not available yet.

// Using Repeat-Until-Success pattern to prepare a quantum state.
// https://docs.microsoft.com/en-us/quantum/user-guide/using-qsharp/control-flow#rus-to-prepare-a-quantum-state
__qpu__ void PrepareStateUsingRUS(qreg q, int maxIter) {
  using qcor::xasm;
  // Note: target = q[0], aux = q[1]
  H(q[1]);
  // We limit the max number of RUS iterations.
  for (int i = 0; i < maxIter; ++i) {
    std::cout << "Iter: " << i << "\n";
    Tdg(q[1]);
    CNOT(q[0], q[1]);
    T(q[1]);

    // In order to measure in the PauliX basis, changes the basis.
    H(q[1]);
    if (!Measure(q[1])) {
      // Success (until (outcome == Zero))
      std::cout << "Success after " << i + 1 << " iterations.\n";
      break;
    } 
    else {
      // Measure 1: |1> state
      // Fix up: Bring the auxiliary and target qubits back to |+> state.
      X(q[1]);
      H(q[1]);
      X(q[0]);
      H(q[0]);
    }
  }
}

int main() {
  // qcor::set_verbose(true);
  auto q = qalloc(2);
  PrepareStateUsingRUS(q, 100);
}
+33 −0
Original line number Diff line number Diff line
#include <qalloc>
// Compile with: qcor -qpu qpp -qrt ftqc simple-demo.cpp
// or with noise: qcor -qpu aer[noise-model:noise_model.json] -qrt ftqc simple-demo.cpp
// Execute: ./a.out
// We should get the print out conditioned by the measurement.
// If not using the "ftqc" QRT, this will cause errors since the Measure results
// are not available yet.
__qpu__ void bell(qreg q, int nbRuns) {
  using qcor::xasm;
  for (int i = 0; i < nbRuns; ++i) {
    H(q[0]);
    CX(q[0], q[1]);
    const bool q0Result = Measure(q[0]);
    const bool q1Result = Measure(q[1]);
    if (q0Result == q1Result) {
      std::cout << "Iter " << i << ": Matched!\n";
    } else {
      std::cout << "Iter " << i << ": NOT Matched!\n";
    }
    // Reset qubits
    if (q0Result) {
      X(q[0]);
    }
    if (q1Result) {
      X(q[1]);
    }
  }
}

int main() {
  auto q = qalloc(2);
  bell(q, 100);
}
+34 −0
Original line number Diff line number Diff line
#include <iomanip>

__qpu__ void x_gate(qreg q) { X(q[1]); }
__qpu__ void h_gate(qreg q) { H(q[1]); }

__qpu__ void htest(qreg q) {
  // Create the superposition on the first qubit
  H(q[0]);

  // create the |1> on the second qubit
  x_gate(q);

  // create superposition on second qubit
  // h_gate(q);

  // apply ctrl-U
  x_gate::ctrl(q[0], q);

  // add the last hadamard
  H(q[0]);

  // measure
  Measure(q[0]);
}

int main() {
  auto q = qalloc(2);
  htest(q);
  q.print();
  auto count1 = q.counts().find("1")->second;
  auto count2 = q.counts().find("0")->second;
  std::cout << "<X> = " << std::setprecision(12)
            << std::fabs((count1 - count2) / (double)(count1 + count2)) << "\n";
}
 No newline at end of file
Loading