Commit 8b1398a0 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

fix bug where X::ctrl or X.ctrl was called within a compute section

parent d3dee29c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ for i in [0:n_counting] {
}

// Run inverse QFT 
iqf2 counting;
iqft counting;

// Now lets measure the counting qubits
bit c[n_counting];
+103 −96
Original line number Diff line number Diff line
@@ -343,98 +343,6 @@ class QuantumKernel {
  virtual ~QuantumKernel() {}
};

template <typename... Args>
using callable_function_ptr =
    void (*)(std::shared_ptr<xacc::CompositeInstruction>, Args...);

template <typename... Args>
class KernelSignature {
 protected:
  callable_function_ptr<Args...> &function_pointer;

 public:
  KernelSignature(callable_function_ptr<Args...> &&f) : function_pointer(f) {}
  // Ctor from raw void* funtion pointer.
  // IMPORTANT: since function_pointer is kept as a *reference*,
  // we must keep a reference to the original f_ptr void* as well.
  KernelSignature(void *&f_ptr)
      : function_pointer((callable_function_ptr<Args...> &)f_ptr) {}

  void operator()(std::shared_ptr<xacc::CompositeInstruction> ir,
                  Args... args) {
    function_pointer(ir, args...);
  }
  void ctrl(std::shared_ptr<xacc::CompositeInstruction> ir, int ctrl_qbit,
            Args... args) {
    auto tempKernel = qcor::__internal__::create_composite("temp_control");
    function_pointer(tempKernel, args...);

    auto ctrlKernel = qcor::__internal__::create_ctrl_u();
    ctrlKernel->expand({
        std::make_pair("U", tempKernel),
        std::make_pair("control-idx", ctrl_qbit),
    });

    for (int instId = 0; instId < ctrlKernel->nInstructions(); ++instId) {
      ir->addInstruction(ctrlKernel->getInstruction(instId)->clone());
    }

    ::quantum::set_current_program(ir);
  }

  void ctrl(std::shared_ptr<xacc::CompositeInstruction> ir, qubit ctrl_qbit,
            Args... args) {
    int ctrl_bit = (int)ctrl_qbit.second;
    ctrl(ir, ctrl_bit, args...);
  }

  void adjoint(std::shared_ptr<CompositeInstruction> ir, Args... args) {
    auto tempKernel = qcor::__internal__::create_composite("temp_adjoint");
    function_pointer(tempKernel, args...);

    // get the instructions
    auto instructions = tempKernel->getInstructions();
    std::shared_ptr<CompositeInstruction> program = tempKernel;

    // Assert that we don't have measurement
    if (!std::all_of(
            instructions.cbegin(), instructions.cend(),
            [](const auto &inst) { return inst->name() != "Measure"; })) {
      error(
          "Unable to create Adjoint for kernels that have Measure operations.");
    }

    auto provider = qcor::__internal__::get_provider();
    for (int i = 0; i < instructions.size(); i++) {
      auto inst = tempKernel->getInstruction(i);
      // Parametric gates:
      if (inst->name() == "Rx" || inst->name() == "Ry" ||
          inst->name() == "Rz" || inst->name() == "CPHASE" ||
          inst->name() == "U1" || inst->name() == "CRZ") {
        inst->setParameter(0, -inst->getParameter(0).template as<double>());
      }
      // Handles T and S gates, etc... => T -> Tdg
      else if (inst->name() == "T") {
        auto tdg = provider->createInstruction("Tdg", inst->bits());
        program->replaceInstruction(i, tdg);
      } else if (inst->name() == "S") {
        auto sdg = provider->createInstruction("Sdg", inst->bits());
        program->replaceInstruction(i, sdg);
      }
    }

    // We update/replace instructions in the derived.parent_kernel composite,
    // hence collecting these new instructions and reversing the sequence.
    auto new_instructions = tempKernel->getInstructions();
    std::reverse(new_instructions.begin(), new_instructions.end());

    // add the instructions to the current parent kernel
    ir->addInstructions(new_instructions);

    ::quantum::set_current_program(ir);
  }
};

// We use the following to enable ctrl operations on our single
// qubit gates, X::ctrl(), Z::ctrl(), H::ctrl(), etc....
template <typename Derived>
@@ -456,7 +364,15 @@ using OneQubitKernel = QuantumKernel<Derived, qubit>;
      if (runtime_env == QrtType::FTQC) {                                 \
        quantum::set_current_buffer(q.results());                         \
      }                                                                   \
      bool cached_is_compute_section =                                    \
          ::quantum::qrt_impl->isComputeSection();                        \
      if (cached_is_compute_section) {                                    \
        ::quantum::qrt_impl->__end_mark_segment_as_compute();             \
      }                                                                   \
      ::quantum::QRTNAME(q);                                              \
      if (cached_is_compute_section) {                                    \
        ::quantum::qrt_impl->__begin_mark_segment_as_compute();           \
      }                                                                   \
      return;                                                             \
    }                                                                     \
    virtual ~CLASSNAME() {}                                               \
@@ -487,7 +403,6 @@ ONE_QUBIT_KERNEL_CTRL_ENABLER(Sdg, sdg)
template <typename... CaptureArgs>
class _qpu_lambda {
 private:

  // Private inner class for getting the type
  // of a capture variable as a string at runtime
  class TupleToTypeArgString {
@@ -596,4 +511,96 @@ class _qpu_lambda {

#define qpu_lambda(EXPR, ...) _qpu_lambda(#EXPR, #__VA_ARGS__, ##__VA_ARGS__)

template <typename... Args>
using callable_function_ptr =
    void (*)(std::shared_ptr<xacc::CompositeInstruction>, Args...);

template <typename... Args>
class KernelSignature {
 protected:
  callable_function_ptr<Args...> &function_pointer;

 public:
  KernelSignature(callable_function_ptr<Args...> &&f) : function_pointer(f) {}
  // Ctor from raw void* funtion pointer.
  // IMPORTANT: since function_pointer is kept as a *reference*,
  // we must keep a reference to the original f_ptr void* as well.
  KernelSignature(void *&f_ptr)
      : function_pointer((callable_function_ptr<Args...> &)f_ptr) {}

  void operator()(std::shared_ptr<xacc::CompositeInstruction> ir,
                  Args... args) {
    function_pointer(ir, args...);
  }
  void ctrl(std::shared_ptr<xacc::CompositeInstruction> ir, int ctrl_qbit,
            Args... args) {
    auto tempKernel = qcor::__internal__::create_composite("temp_control");
    function_pointer(tempKernel, args...);

    auto ctrlKernel = qcor::__internal__::create_ctrl_u();
    ctrlKernel->expand({
        std::make_pair("U", tempKernel),
        std::make_pair("control-idx", ctrl_qbit),
    });

    for (int instId = 0; instId < ctrlKernel->nInstructions(); ++instId) {
      ir->addInstruction(ctrlKernel->getInstruction(instId)->clone());
    }

    ::quantum::set_current_program(ir);
  }

  void ctrl(std::shared_ptr<xacc::CompositeInstruction> ir, qubit ctrl_qbit,
            Args... args) {
    int ctrl_bit = (int)ctrl_qbit.second;
    ctrl(ir, ctrl_bit, args...);
  }

  void adjoint(std::shared_ptr<CompositeInstruction> ir, Args... args) {
    auto tempKernel = qcor::__internal__::create_composite("temp_adjoint");
    function_pointer(tempKernel, args...);

    // get the instructions
    auto instructions = tempKernel->getInstructions();
    std::shared_ptr<CompositeInstruction> program = tempKernel;

    // Assert that we don't have measurement
    if (!std::all_of(
            instructions.cbegin(), instructions.cend(),
            [](const auto &inst) { return inst->name() != "Measure"; })) {
      error(
          "Unable to create Adjoint for kernels that have Measure operations.");
    }

    auto provider = qcor::__internal__::get_provider();
    for (int i = 0; i < instructions.size(); i++) {
      auto inst = tempKernel->getInstruction(i);
      // Parametric gates:
      if (inst->name() == "Rx" || inst->name() == "Ry" ||
          inst->name() == "Rz" || inst->name() == "CPHASE" ||
          inst->name() == "U1" || inst->name() == "CRZ") {
        inst->setParameter(0, -inst->getParameter(0).template as<double>());
      }
      // Handles T and S gates, etc... => T -> Tdg
      else if (inst->name() == "T") {
        auto tdg = provider->createInstruction("Tdg", inst->bits());
        program->replaceInstruction(i, tdg);
      } else if (inst->name() == "S") {
        auto sdg = provider->createInstruction("Sdg", inst->bits());
        program->replaceInstruction(i, sdg);
      }
    }

    // We update/replace instructions in the derived.parent_kernel composite,
    // hence collecting these new instructions and reversing the sequence.
    auto new_instructions = tempKernel->getInstructions();
    std::reverse(new_instructions.begin(), new_instructions.end());

    // add the instructions to the current parent kernel
    ir->addInstructions(new_instructions);

    ::quantum::set_current_program(ir);
  }
};

}  // namespace qcor
+1 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ class FTQC : public quantum::QuantumRuntime {

  void __begin_mark_segment_as_compute() override { mark_as_compute = true; }
  void __end_mark_segment_as_compute() override { mark_as_compute = false; }
  bool isComputeSection() override { return mark_as_compute; }
  const std::string name() const override { return "ftqc"; }
  const std::string description() const override { return ""; }

+3 −0
Original line number Diff line number Diff line
@@ -74,6 +74,9 @@ class NISQ : public ::quantum::QuantumRuntime,

  void __begin_mark_segment_as_compute() override { mark_as_compute = true; }
  void __end_mark_segment_as_compute() override { mark_as_compute = false; }
  bool isComputeSection() override {
    return mark_as_compute;
  }

  void h(const qubit &qidx) override { one_qubit_inst("H", qidx); }
  void x(const qubit &qidx) override { one_qubit_inst("X", qidx); }
+2 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ public:
  virtual void initialize(const std::string kernel_name) = 0;
  virtual void __begin_mark_segment_as_compute() = 0;
  virtual void __end_mark_segment_as_compute() = 0;
  virtual bool isComputeSection() = 0;
  
  virtual void h(const qubit &qidx) = 0;
  virtual void x(const qubit &qidx) = 0;