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

Support Q# nested transformation and multi-control generation



- Resolve the nested structure of functor argument when multiple control layers were applied.

- Leverage the start_ctrl_u and end_ctrl_u runtime function: adding a version to support multiple controls.

- Fixed a bug in FTQC making the global reg to shrink unexpectedly.

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 6cac1dda
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -149,8 +149,15 @@ void __quantum__qis__x__ctl(Array *ctls, Qubit *q) {
    Qubit *ctrl_qubit = *(reinterpret_cast<Qubit **>(arrayPtr));
    __quantum__qis__cnot(ctrl_qubit, q);
  } else {
    // TODO:
    std::cout << "Multiple-control is not supported yet.\n";
    std::vector<Qubit *> ctrl_qubits;
    for (int i = 0; i < ctls->size(); ++i) {
      int8_t *arrayPtr = (*ctls)[i];
      Qubit *ctrl_qubit = *(reinterpret_cast<Qubit **>(arrayPtr));
      ctrl_qubits.emplace_back(ctrl_qubit);
    }
    __quantum__rt__start_ctrl_u_region();
    __quantum__qis__x__body(q);
    __quantum__rt__end_multi_ctrl_u_region(ctrl_qubits);
  }
}
void __quantum__qis__x__ctladj(Array *ctls, Qubit *q) {
+41 −0
Original line number Diff line number Diff line
@@ -342,6 +342,10 @@ void __quantum__rt__end_adj_u_region() {
}

void __quantum__rt__start_ctrl_u_region() {
  // Cache the current runtime into the stack if not already.
  if (internal_runtimes.empty()) {
    internal_runtimes.push(::quantum::qrt_impl);
  }
  // Create a new NISQ based runtime so that we can
  // queue up instructions and get them as a CompositeInstruction
  auto tmp_runtime = xacc::getService<::quantum::QuantumRuntime>("nisq");
@@ -387,6 +391,43 @@ void __quantum__rt__end_ctrl_u_region(Qubit *ctrl_qbit) {
  return;
}

void __quantum__rt__end_multi_ctrl_u_region(
    const std::vector<Qubit *> &ctrl_qubits) {
  // Get the temp runtime created by start_adj_u_region.
  auto runtime = internal_runtimes.top();
  // Get the program we built up
  auto program = runtime->get_current_program();
  // Remove the tmp runtime
  internal_runtimes.pop();

  // Set the quantum runtime to the one before this
  // temp one we just popped off
  ::quantum::qrt_impl = internal_runtimes.top();

  std::vector<int> ctrl_bits;
  for (auto &qb : ctrl_qubits) {
    ctrl_bits.emplace_back(qb->id);
  }

  auto ctrlKernel = std::dynamic_pointer_cast<xacc::CompositeInstruction>(
      xacc::getService<xacc::Instruction>("C-U"));
  ctrlKernel->expand({
      std::make_pair("U", program),
      std::make_pair("control-idx", ctrl_bits),
  });

  std::cout << "Running Ctrl on ";
  for (const auto &bit : ctrl_bits) {
    std::cout << bit << " ";
  }
  std::cout << ":\n" << ctrlKernel->toString() << "\n";
  for (int instId = 0; instId < ctrlKernel->nInstructions(); ++instId) {
    ::quantum::qrt_impl->general_instruction(
        ctrlKernel->getInstruction(instId));
  }
  return;
}

int8_t *__quantum__rt__array_get_element_ptr_1d(Array *q, uint64_t idx) {
  Array &arr = *q;
  int8_t *ptr = arr[idx];
+3 −0
Original line number Diff line number Diff line
@@ -69,6 +69,9 @@ Qubit *__quantum__rt__qubit_allocate();

void __quantum__rt__start_ctrl_u_region();
void __quantum__rt__end_ctrl_u_region(Qubit *ctrl_qubit);
// Multi-control
void __quantum__rt__end_multi_ctrl_u_region(
    const std::vector<Qubit *> &ctrl_qubits);
void __quantum__rt__start_adj_u_region();
void __quantum__rt__end_adj_u_region();
void __quantum__rt__start_pow_u_region();
+16 −3
Original line number Diff line number Diff line
@@ -184,6 +184,17 @@ struct TupleHeader {
    qcor::internal::AllocationTracker::get().onAllocate(th);
    return th;
  }
  static TupleHeader *create(TupleHeader *other) {
    const auto size = other->m_tupleSize;
    int8_t *buffer = new int8_t[sizeof(TupleHeader) + size];
    TupleHeader *th = reinterpret_cast<TupleHeader *>(buffer);
    th->m_tupleSize = size;
    th->m_refCount = 1;
    memcpy(th->m_data, other->m_data, size);
    qcor::internal::AllocationTracker::get().onAllocate(th);
    return th;
  }

  static TupleHeader *getHeader(TuplePtr tuple) {
    return reinterpret_cast<TupleHeader *>(tuple -
                                           offsetof(TupleHeader, m_data));
@@ -266,13 +277,15 @@ struct Callable {
    if (functorIdx == Callable::AdjointIdx) {
      m_functorIdx ^= Callable::AdjointIdx;
      if (m_functionTable[m_functorIdx] == nullptr) {
        throw "The Callable doesn't have Adjoint implementation.";
        printf("The Callable doesn't have Adjoint implementation.");
        throw;
      }
    }
    if (functorIdx == Callable::ControlledIdx) {
      m_functorIdx |= Callable::ControlledIdx;
      if (m_functionTable[m_functorIdx]) {
        throw "The Callable doesn't have Controlled implementation.";
      if (m_functionTable[m_functorIdx] == nullptr) {
        printf("The Callable doesn't have Controlled implementation.");
        throw;
      }
      m_controlledDepth++;
    }
+5 −1
Original line number Diff line number Diff line
@@ -24,8 +24,12 @@ void __quantum__rt__callable_invoke(Callable *clb, TuplePtr args,
Callable *__quantum__rt__callable_copy(Callable *clb, bool force) {
  if (verbose)
    std::cout << "CALL: " << __PRETTY_FUNCTION__ << "\n";
  if (clb == nullptr) {
    return nullptr;
  }
  auto clone = new Callable(*clb);
  return clone;
}
void __quantum__rt__capture_update_reference_count(Callable *clb,
                                                   int32_t count) {
  if (verbose)
Loading