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

Refactor AncAllocator for both NISQ and FTQC



Make FTQC tests executed as well

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent c70165ea
Loading
Loading
Loading
Loading
+20 −7
Original line number Diff line number Diff line
@@ -10,6 +10,17 @@ function(add_qcor_compile_and_exe_test test_name relative_source_location)
  )
endfunction()

# Compile with FTQC runtime and execute
function(add_qcor_ftqc_compile_and_exe_test test_name relative_source_location)
  add_test(
  NAME
    ${test_name}
  COMMAND
    bash -c "${CMAKE_BINARY_DIR}/qcor -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/${relative_source_location} -o ${test_name}; \
              ${CMAKE_CURRENT_BINARY_DIR}/${test_name}"
  )
endfunction()

add_qcor_compile_and_exe_test(qrt_bell_multi bell/bell_multi_qreg.cpp)
add_test(NAME qrt_add_3_5 COMMAND ${CMAKE_BINARY_DIR}/qcor -v -c ${CMAKE_CURRENT_SOURCE_DIR}/adder/add_3_5.cpp WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/adder)
add_qcor_compile_and_exe_test(qrt_mixed_language simple/mixed_language.cpp)
@@ -21,13 +32,15 @@ add_qcor_compile_and_exe_test(qrt_qpe_example qpe/qpe_example_qrt.cpp)
add_qcor_compile_and_exe_test(qrt_kernel_include simple/multiple_kernels.cpp)
add_qcor_compile_and_exe_test(qrt_grover grover/grover.cpp)
add_qcor_compile_and_exe_test(qrt_adapt 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)
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)
add_qcor_ftqc_compile_and_exe_test(qrt_ftqc_simple ftqc_qrt/simple-demo.cpp)
add_qcor_ftqc_compile_and_exe_test(qrt_ftqc_rus ftqc_qrt/repeat-until-success.cpp)
add_qcor_ftqc_compile_and_exe_test(qrt_ftqc_qec ftqc_qrt/bit-flip-code.cpp)
add_qcor_ftqc_compile_and_exe_test(qrt_ftqc_deuteron ftqc_qrt/deuteron.cpp)
add_qcor_ftqc_compile_and_exe_test(qrt_ftqc_bit_flip_qec_std_lib ftqc_qrt/error_correcting_code.cpp)
add_qcor_ftqc_compile_and_exe_test(qrt_ftqc_five_qubit_qec_std_lib ftqc_qrt/five_qubit_qec_code.cpp)
add_qcor_ftqc_compile_and_exe_test(qrt_ftqc_steane_qec_std_lib ftqc_qrt/steane_qec_code.cpp)
add_qcor_ftqc_compile_and_exe_test(qrt_ftqc_qalloc ftqc_qrt/qalloc_ftqc.cpp)
add_qcor_ftqc_compile_and_exe_test(qrt_ftqc_arithmetic ftqc_qrt/integer_add.cpp)
add_qcor_compile_and_exe_test(quasimo_vqe quasimo/VqeWithAnsatzCircuit.cpp)
add_qcor_compile_and_exe_test(quasimo_trotter quasimo/TrotterTdWorkflow.cpp)
add_qcor_compile_and_exe_test(quasimo_iqpe_vqe quasimo/IterativeQpeVqe.cpp)
+32 −0
Original line number Diff line number Diff line
#include <qcor_arithmetic>

__qpu__ void test_mul_integer_inline(qreg x, int a, int N, int &result) {
  // x = |1> + |3>
  X(x[0]);
  H(x[1]);
  // ==> |a*x> inline (save in x)
  // Note that this kernel will allocate qubits...
  mul_integer_mod_in_place(x, a, N);
  result = 0;
  for (int bitIdx = 0; bitIdx < x.size(); ++bitIdx) {
    if (Measure(x[bitIdx])) {
      result = result + (1 << bitIdx);
      X(x[bitIdx]);
    }
  }
}

int main(int argc, char **argv) {
  // Test in-place modular multiplication:
  // |x> ==> |ax mod N> on the same register.
  // x = |1> + |3>; a = 2
  // --> |2> + |6>
  // Simple test:
  int a_val = 2;
  int N_val = 8;
  auto x_reg2 = qalloc(3);
  int result = 0;
  test_mul_integer_inline(x_reg2, a_val, N_val, result);
  std::cout << "Result = " << result << "\n";
  return 0;
}
 No newline at end of file
+21 −80
Original line number Diff line number Diff line
@@ -13,54 +13,8 @@
using namespace cppmicroservices;

namespace {
class FtqcQubitAllocator : public AllocEventListener, public QubitAllocator {
class FtqcQubitAllocator : public qcor::AncQubitAllocator {
public:
  static inline const std::string ANC_BUFFER_NAME = "ftqc_temp_buffer";
  virtual void onAllocate(qubit *in_qubit) override {
    // std::cout << "Allocate: " << (void *)in_qubit << "\n";
  }

  // On deallocate: don't try to deref the qubit since it may have been gone.
  virtual void onDealloc(qubit *in_qubit) override {
    // std::cout << "Deallocate: " << (void *)in_qubit << "\n";
    // If this qubit was allocated from this pool:
    if (xacc::container::contains(m_allocatedQubits, in_qubit)) {
      const auto qIndex = std::find(m_allocatedQubits.begin(),
                                    m_allocatedQubits.end(), in_qubit) -
                          m_allocatedQubits.begin();
      // Strategy: create a storage copy of the returned qubit:
      // i.e. with the same index w.r.t. this global anc. buffer
      // but store it in the pool vector -> will stay alive
      // until giving out at the next allocate()
      qubit archive_qubit(ANC_BUFFER_NAME, qIndex, m_buffer.get());
      m_allocatedQubits[qIndex] = &archive_qubit;
      m_qubitPool.emplace_back(archive_qubit);
    }
  }

  virtual qubit allocate() override {
    if (!m_qubitPool.empty()) {
      auto recycled_qubit = m_qubitPool.back();
      m_qubitPool.pop_back();
      return recycled_qubit;
    }
    if (!m_buffer) {
      // This must be the first call.
      assert(m_allocatedQubits.empty());
      m_buffer = xacc::qalloc(1);
      m_buffer->setName(ANC_BUFFER_NAME);
    }

    // Need to allocate new qubit:
    // Each new qubit will have an incrementing index.
    const auto newIdx = m_allocatedQubits.size();
    qubit new_qubit(ANC_BUFFER_NAME, newIdx, m_buffer.get());
    // Just track that we allocated this qubit
    m_allocatedQubits.emplace_back(&new_qubit);
    m_buffer->setSize(m_allocatedQubits.size());
    return new_qubit;
  }

  static FtqcQubitAllocator *getInstance() {
    if (!g_instance) {
      g_instance = new FtqcQubitAllocator();
@@ -68,15 +22,6 @@ public:
    return g_instance;
  }
  static FtqcQubitAllocator *g_instance;

  std::shared_ptr<xacc::AcceleratorBuffer> get_buffer() { return m_buffer; }

private:
  std::vector<qubit> m_qubitPool;
  // Track the list of qubit pointers for those
  // that was allocated by this Allocator.
  std::vector<qubit *> m_allocatedQubits;
  std::shared_ptr<xacc::AcceleratorBuffer> m_buffer;
};

FtqcQubitAllocator *FtqcQubitAllocator::g_instance = nullptr;
@@ -103,13 +48,9 @@ class FTQC : public quantum::QuantumRuntime {
  virtual void y(const qubit &qidx) override { applyGate("Y", {qidx}); }
  virtual void z(const qubit &qidx) override { applyGate("Z", {qidx}); }
  virtual void t(const qubit &qidx) override { applyGate("T", {qidx}); }
  virtual void tdg(const qubit &qidx) override {
    applyGate("Tdg", {qidx});
  }
  virtual void tdg(const qubit &qidx) override { applyGate("Tdg", {qidx}); }
  virtual void s(const qubit &qidx) override { applyGate("S", {qidx}); }
  virtual void sdg(const qubit &qidx) override {
    applyGate("Sdg", {qidx});
  }
  virtual void sdg(const qubit &qidx) override { applyGate("Sdg", {qidx}); }

  // Common single-qubit, parameterized instructions
  virtual void rx(const qubit &qidx, const double theta) override {
@@ -130,9 +71,7 @@ class FTQC : public quantum::QuantumRuntime {
    applyGate("U", {qidx}, {theta, phi, lambda});
  }

  virtual void reset(const qubit &qidx) override {
    applyGate("Reset", {qidx});
  }
  virtual void reset(const qubit &qidx) override { applyGate("Reset", {qidx}); }

  // Measure-Z
  virtual bool mz(const qubit &qidx) override {
@@ -198,21 +137,23 @@ class FTQC : public quantum::QuantumRuntime {
  }

  // Some getters for the qcor runtime library.
  virtual void set_current_program(
      std::shared_ptr<xacc::CompositeInstruction> p) override {
  virtual void
  set_current_program(std::shared_ptr<xacc::CompositeInstruction> p) override {
    // Nothing to do
  }
  virtual std::shared_ptr<xacc::CompositeInstruction> get_current_program()
      override {
  virtual std::shared_ptr<xacc::CompositeInstruction>
  get_current_program() override {
    return nullptr;
  }

  void set_current_buffer(xacc::AcceleratorBuffer *buffer) override {
    if (!qReg) {
      qReg = xacc::as_shared_ptr(buffer);
      qubitIdToGlobalIdx.clear();
      // The base qreg will always have exact address in the global register.
    for (size_t i = 0; i < qReg->size(); ++i) {
      qubitIdToGlobalIdx[std::make_pair(qReg->name(), i)] = i;
      for (size_t i = 0; i < buffer->size(); ++i) {
        qubitIdToGlobalIdx[std::make_pair(buffer->name(), i)] = i;
      }
    }
  }

+1 −56
Original line number Diff line number Diff line
@@ -18,54 +18,8 @@ using namespace cppmicroservices;
using namespace xacc;

namespace {
class NisqQubitAllocator : public AllocEventListener, public QubitAllocator {
class NisqQubitAllocator : public qcor::AncQubitAllocator {
public:
  static inline const std::string ANC_BUFFER_NAME = "nisq_temp_buffer";
  virtual void onAllocate(qubit *in_qubit) override {
    // std::cout << "Allocate: " << (void *)in_qubit << "\n";
  }

  // On deallocate: don't try to deref the qubit since it may have been gone.
  virtual void onDealloc(qubit *in_qubit) override {
    // std::cout << "Deallocate: " << (void *)in_qubit << "\n";
    // If this qubit was allocated from this pool:
    if (xacc::container::contains(m_allocatedQubits, in_qubit)) {
      const auto qIndex = std::find(m_allocatedQubits.begin(),
                                    m_allocatedQubits.end(), in_qubit) -
                          m_allocatedQubits.begin();
      // Strategy: create a storage copy of the returned qubit:
      // i.e. with the same index w.r.t. this global anc. buffer
      // but store it in the pool vector -> will stay alive
      // until giving out at the next allocate()
      qubit archive_qubit(ANC_BUFFER_NAME, qIndex, m_buffer.get());
      m_allocatedQubits[qIndex] = &archive_qubit;
      m_qubitPool.emplace_back(archive_qubit);
    }
  }

  virtual qubit allocate() override {
    if (!m_qubitPool.empty()) {
      auto recycled_qubit = m_qubitPool.back();
      m_qubitPool.pop_back();
      return recycled_qubit;
    }
    if (!m_buffer) {
      // This must be the first call.
      assert(m_allocatedQubits.empty());
      m_buffer = xacc::qalloc(1);
      m_buffer->setName(ANC_BUFFER_NAME);
    }

    // Need to allocate new qubit:
    // Each new qubit will have an incrementing index.
    const auto newIdx = m_allocatedQubits.size();
    qubit new_qubit(ANC_BUFFER_NAME, newIdx, m_buffer.get());
    // Just track that we allocated this qubit
    m_allocatedQubits.emplace_back(&new_qubit);
    m_buffer->setSize(m_allocatedQubits.size());
    return new_qubit;
  }

  static NisqQubitAllocator *getInstance() {
    if (!g_instance) {
      g_instance = new NisqQubitAllocator();
@@ -73,15 +27,6 @@ public:
    return g_instance;
  }
  static NisqQubitAllocator *g_instance;

  std::shared_ptr<xacc::AcceleratorBuffer> get_buffer() { return m_buffer; }

private:
  std::vector<qubit> m_qubitPool;
  // Track the list of qubit pointers for those
  // that was allocated by this Allocator.
  std::vector<qubit *> m_allocatedQubits;
  std::shared_ptr<xacc::AcceleratorBuffer> m_buffer;
};

NisqQubitAllocator *NisqQubitAllocator::g_instance = nullptr;
+43 −1
Original line number Diff line number Diff line
@@ -342,3 +342,45 @@ QubitAllocator *getAncillaQubitAllocator() {
  return qrt_impl->get_anc_qubit_allocator();
}
}  // namespace quantum

namespace qcor {
void AncQubitAllocator::onDealloc(xacc::internal_compiler::qubit *in_qubit) {
  // std::cout << "Deallocate: " << (void *)in_qubit << "\n";
  // If this qubit was allocated from this pool:
  if (xacc::container::contains(m_allocatedQubits, in_qubit)) {
    const auto qIndex = std::find(m_allocatedQubits.begin(),
                                  m_allocatedQubits.end(), in_qubit) -
                        m_allocatedQubits.begin();
    // Strategy: create a storage copy of the returned qubit:
    // i.e. with the same index w.r.t. this global anc. buffer
    // but store it in the pool vector -> will stay alive
    // until giving out at the next allocate()
    qubit archive_qubit(ANC_BUFFER_NAME, qIndex, m_buffer.get());
    m_allocatedQubits[qIndex] = &archive_qubit;
    m_qubitPool.emplace_back(archive_qubit);
  }
}

xacc::internal_compiler::qubit AncQubitAllocator::allocate() {
  if (!m_qubitPool.empty()) {
    auto recycled_qubit = m_qubitPool.back();
    m_qubitPool.pop_back();
    return recycled_qubit;
  }
  if (!m_buffer) {
    // This must be the first call.
    assert(m_allocatedQubits.empty());
    m_buffer = xacc::qalloc(1);
    m_buffer->setName(ANC_BUFFER_NAME);
  }

  // Need to allocate new qubit:
  // Each new qubit will have an incrementing index.
  const auto newIdx = m_allocatedQubits.size();
  qubit new_qubit(ANC_BUFFER_NAME, newIdx, m_buffer.get());
  // Just track that we allocated this qubit
  m_allocatedQubits.emplace_back(&new_qubit);
  m_buffer->setSize(m_allocatedQubits.size());
  return new_qubit;
}
} // namespace qcor
 No newline at end of file
Loading