Commit 21aeaafb authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

update to support qubit kernel arguments and qreg extract_qubits and...


update to support qubit kernel arguments and qreg extract_qubits and extract_range. enabled quantum gate broadcasting on qreg. update qft and iqft to use qreg instead of start stop index. update qpe_callable_kernel to demonstrate new features.

Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent 00345260
Loading
Loading
Loading
Loading
Loading
+30 −41
Original line number Diff line number Diff line
#include <qcor_qft>

// Here, we are saying this is what our QPE algorithm 
// expects as a kernel signature for user-provided 
// oracles. All oracles in this example must take a qreg and and int.
using QPEOracleSignature = KernelSignature<qreg, int>;

// Define our QPE algorithm, taking as input the 
// qreg to run on and an Oracle provided as a 
// qcor quantum kernel of the required function signature.
__qpu__ void QuantumPhaseEstimation(qreg q, QPEOracleSignature oracle) {
  // We have nQubits, the last one we use
  // as the state qubit, the others we use as the counting qubits
  const auto nQubits = q.size();
  const auto nCounting = nQubits - 1;
  const auto state_qubit_idx = nQubits - 1;
// QPE Problem
// In this example, we demonstrate a simple QPE algorithm, i.e.
// i.e. Oracle(|State>) = exp(i*Phase)*|State>
// and we need to estimate that Phase value.
// The Oracle in this case is a T gate and the eigenstate is |1>
// i.e. T|1> = exp(i*pi/4)|1>
// We use 3 counting bits => totally 4 qubits.

// Our qpe kernel requires oracles with 
// the following signature.
using QPEOracleSignature = KernelSignature<qubit>;

__qpu__ void qpe(qreg q, QPEOracleSignature oracle) {
  // Extract the counting qubits and the state qubit
  auto counting_qubits = q.extract_range({0,3});
  // could also do this...
  // auto counting_qubits = q.extract_qubits({0,1,2});
  auto state_qubit = q[3];

  // Put it in |1> eigenstate
  X(q[state_qubit_idx]);
  X(state_qubit);

  // Create uniform superposition
  for (auto i : range(nCounting)) {
    H(q[i]);
  }
  // Create uniform superposition on all 3 qubits
  H(counting_qubits);

  for (auto i : range(nCounting)) {
  // run ctr-oracle operations
  for (auto i : range(counting_qubits.size())) {
    const int nbCalls = 1 << i;
    for (auto j : range(nbCalls)) {
      oracle.ctrl(i, q, state_qubit_idx);
      oracle.ctrl(counting_qubits[i], state_qubit);
    }
  }

  // Run Inverse QFT, on 0:nCounting qubits
  int startIdx = 0;
  int shouldSwap = 1;
  iqft(q, startIdx, nCounting, shouldSwap);
  // Run Inverse QFT on counting qubits
  iqft(counting_qubits);

  for (int i : range(nCounting)) {
    Measure(q[i]);
  // Measure the counting qubits
  Measure(counting_qubits);
}
}

// QPE Problem
// In this example, we demonstrate a simple QPE algorithm, i.e.
// i.e. Oracle(|State>) = exp(i*Phase)*|State>
// and we need to estimate that Phase value.
// The Oracle in this case is a T gate and the eigenstate is |1>
// i.e. T|1> = exp(i*pi/4)|1>
// We use 3 counting bits => totally 4 qubits.

// Oracle I want to consider
__qpu__ void compositeOp(qreg q, int idx) { T(q[idx]); }
__qpu__ void oracle(qubit q) { T(q); }

int main(int argc, char **argv) {
  auto q = qalloc(4);

  // Just pass the oracle kernel to the 
  // phase estimation algorithm.
  QuantumPhaseEstimation(q, compositeOp);
  qpe(q, oracle);
  q.print();
}
+4 −3
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ __qpu__ void compositeOp(qreg q) {
// i.e. T|1> = exp(i*pi/4)|1>
// We use 3 counting bits => totally 4 qubits.
__qpu__ void QuantumPhaseEstimation(qreg q) {
  const auto nQubits = q.size();
  const std::size_t nQubits = q.size();
  // Last qubit is the eigenstate of the unitary operator 
  // hence, prepare it in |1> state
  X(q[nQubits - 1]);
@@ -33,7 +33,7 @@ __qpu__ void QuantumPhaseEstimation(qreg q) {

  // Apply Controlled-Oracle: in this example, Oracle is T gate;
  // i.e. Ctrl(T) = CPhase(pi/4)
  const auto bitPrecision = nQubits - 1;
  const std::size_t bitPrecision = nQubits - 1;
  for (int32_t i = 0; i < bitPrecision; ++i) {
    const int nbCalls = 1 << i;
    for (int j = 0; j < nbCalls; ++j) {
@@ -46,7 +46,8 @@ __qpu__ void QuantumPhaseEstimation(qreg q) {
  // Inverse QFT on the counting qubits:
  int startIdx = 0;
  int shouldSwap = 1;
  iqft(q, startIdx, bitPrecision, shouldSwap);
  auto r = q.extract_range({0, bitPrecision});
  iqft(r);

  // Measure counting qubits
  for (int qIdx = 0; qIdx < bitPrecision; ++qIdx) {
+2 −2
Original line number Diff line number Diff line
@@ -10,10 +10,10 @@ __qpu__ void f(qreg q) {
  // Call qft kernel (defined in a separate header file)
  int startIdx = 0;
  int shouldSwap = 1;
  qft(q, startIdx, nQubits, shouldSwap);  
  qft(q);  
  
  // Inverse QFT:
  iqft(q, startIdx, nQubits, shouldSwap);
  iqft(q);
  
  // Measure all qubits
  for (int qIdx = 0; qIdx < nQubits; ++qIdx) {
+4 −1
Original line number Diff line number Diff line
@@ -48,6 +48,9 @@ void QCORSyntaxHandler::GetReplacement(Preprocessor &PP, Declarator &D,
    } else if (type == "qcor::qreg") {
      bufferNames.push_back(ident->getName().str());
      type = "qreg";
    } else if (type.find("xacc::internal_compiler::qubit") != std::string::npos) {
      bufferNames.push_back(ident->getName().str());
      type = "qubit";
    }

    program_arg_types.push_back(type);
+2 −2
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ void StaqTokenCollector::collect(clang::Preprocessor &PP,
    // Note - we don't know the size of the buffer
    // at this point, so just create one with max size
    // and we can provide an IR Pass later that updates it
    auto q = qalloc(std::numeric_limits<int>::max());
    auto q = qalloc(1000);
    q.setNameAndStore(b.c_str());

    xx << "qreg " << b << "[" << q.size() << "];\n";
@@ -220,7 +220,7 @@ void StaqTokenCollector::collect(clang::Preprocessor &PP,
    next->accept(visitor);
  }
  if (hasOracle) {
    ss << "auto anc = qalloc(" << std::numeric_limits<int>::max() << ");\n";
    ss << "auto anc = qalloc(" << 1000 << ");\n";
  }

  if (!qreg_calls.empty() && bufferNames.size() == qreg_calls.size()) {
Loading