Commit 0ee83973 authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Clean-up the Qsharp kernel integration example



Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 65716d04
Loading
Loading
Loading
Loading
+0 −66
Original line number Diff line number Diff line
#include <iostream> 
#include <vector>
#include "qcor.hpp"
using Qubit = uint64_t;
using QReg = std::vector<Qubit*>;
// Include the external QSharp function.
qcor_include_qsharp(XACC__TestGhz__body, void, Array *);

class TestGhz : public qcor::QuantumKernel<class TestGhz, qreg> {
private:
  // Use deque to prevent re-alloc
  std::deque<Qubit> m_qubits;
  friend class qcor::QuantumKernel<class TestGhz, qreg>;

protected:
  void operator()(qreg q) {
    if (!parent_kernel) {
      parent_kernel = qcor::__internal__::create_composite(kernel_name);
    }
    quantum::set_current_program(parent_kernel);
    if (runtime_env == QrtType::FTQC) {
      quantum::set_current_buffer(q.results());
    }
    QReg qReg;
    for (int i = 0; i < q.size(); ++i) {
      m_qubits.push_back(i);
      qReg.emplace_back(&m_qubits.back());
    }
    XACC__TestGhz__body(&qReg);
    std::cout << "INVOKE:\n" << parent_kernel->toString();
  }

public:
  inline static const std::string kernel_name = "TestGhz";
  TestGhz(qreg q) : QuantumKernel<TestGhz, qreg>(q) {}
  TestGhz(std::shared_ptr<qcor::CompositeInstruction> _parent, qreg q)
      : QuantumKernel<TestGhz, qreg>(_parent, q) {}
  virtual ~TestGhz() {
    if (disable_destructor) {
      return;
    }
    auto [q] = args_tuple;
    operator()(q);
    xacc::internal_compiler::execute_pass_manager();
    if (optimize_only) {
      return;
    }
    if (is_callable) {
      quantum::submit(q.results());
    }
  }
};

// Compile with:
// Include both the qsharp source and this driver file
// in the command line.
// $ qcor -qpu aer:ibmqx2 -shots 1024 ghz_nisq.qs ghz_nisq_driver.cpp
// Run with:
// $ ./a.out
int main() {
  auto q = qalloc(3);
  qcor::set_verbose(true);
  { TestGhz kernel(q); }
  q.print();
  return 0;
}
 No newline at end of file
+101 −0
Original line number Diff line number Diff line
// Helper macros to generate QCOR kernel wrapper for
// external Q# kernel (compiled to QIR)

#define STRINGIZE(arg)  STRINGIZE1(arg)
#define STRINGIZE1(arg) STRINGIZE2(arg)
#define STRINGIZE2(arg) #arg

#define CONCATENATE(arg1, arg2)   CONCATENATE1(arg1, arg2)
#define CONCATENATE1(arg1, arg2)  CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2)  arg1##arg2

#define FOR_EACH_1(what, x, ...) what(x, 1)
#define FOR_EACH_2(what, x, ...)\
  what(x, 2)\
  FOR_EACH_1(what,  __VA_ARGS__)
#define FOR_EACH_3(what, x, ...)\
  what(x, 3)\
  FOR_EACH_2(what, __VA_ARGS__)
#define FOR_EACH_4(what, x, ...)\
  what(x, 4)\
  FOR_EACH_3(what,  __VA_ARGS__)
#define FOR_EACH_5(what, x, ...)\
  what(x, 5)\
 FOR_EACH_4(what,  __VA_ARGS__)
#define FOR_EACH_6(what, x, ...)\
  what(x, 6)\
  FOR_EACH_5(what,  __VA_ARGS__)
#define FOR_EACH_7(what, x, ...)\
  what(x, 7)\
  FOR_EACH_6(what,  __VA_ARGS__)
#define FOR_EACH_8(what, x, ...)\
  what(x, 8)\
  FOR_EACH_7(what,  __VA_ARGS__)

#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) FOR_EACH_ARG_N(__VA_ARGS__) 
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N 
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0

#define FOR_EACH_(N, what, ...) CONCATENATE(FOR_EACH_, N)(what, __VA_ARGS__)
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)

#define CONSTRUCT_ARGS_LIST_(type_name, var_name) , type_name var_name
#define CONSTRUCT_ARGS_LIST(type_name, counter) CONSTRUCT_ARGS_LIST_(type_name, __internal__var__##counter)
#define CONSTRUCT_VAR_NAME_LIST(type_name, counter) , __internal__var__##counter

// Macro to use to construct list of types and var names.
#define ARGS_LIST_FOR_FUNC_SIGNATURE(...) FOR_EACH(CONSTRUCT_ARGS_LIST, __VA_ARGS__)
#define ARGS_LIST_FOR_FUNC_INVOKE(...) FOR_EACH(CONSTRUCT_VAR_NAME_LIST, __VA_ARGS__)

#define qcor_import_qsharp_kernel(OPERATION_NAME, ...) \
  extern "C" void OPERATION_NAME##__body(QReg *, __VA_ARGS__); \
  class OPERATION_NAME : public qcor::QuantumKernel<class OPERATION_NAME, qreg, __VA_ARGS__> { \
  private: \
    std::deque<Qubit> m_qubits; \
    friend class qcor::QuantumKernel<class OPERATION_NAME, qreg, __VA_ARGS__>; \
  protected: \
    void operator()(qreg q ARGS_LIST_FOR_FUNC_SIGNATURE(__VA_ARGS__)) { \
      if (!parent_kernel) { \
        parent_kernel = qcor::__internal__::create_composite(kernel_name); \
      } \
      quantum::set_current_program(parent_kernel); \
      if (runtime_env == QrtType::FTQC) { \
        quantum::set_current_buffer(q.results()); \
      } \
      QReg qReg; \
      for (int i = 0; i < q.size(); ++i) { \
        m_qubits.push_back(i); \
        qReg.emplace_back(&m_qubits.back()); \
      } \
      OPERATION_NAME##__body(&qReg ARGS_LIST_FOR_FUNC_INVOKE(__VA_ARGS__)); \
      /* std::cout << "INVOKE:\n" << parent_kernel->toString(); */\
    } \
  public: \
    inline static const std::string kernel_name = #OPERATION_NAME; \
    OPERATION_NAME(qreg q ARGS_LIST_FOR_FUNC_SIGNATURE(__VA_ARGS__)) : QuantumKernel<OPERATION_NAME, qreg, __VA_ARGS__>(q ARGS_LIST_FOR_FUNC_INVOKE(__VA_ARGS__)) {} \
    OPERATION_NAME(std::shared_ptr<qcor::CompositeInstruction> _parent, qreg q ARGS_LIST_FOR_FUNC_SIGNATURE(__VA_ARGS__)) \
        : QuantumKernel<OPERATION_NAME, qreg, __VA_ARGS__>(_parent, q ARGS_LIST_FOR_FUNC_INVOKE(__VA_ARGS__)) {} \
    virtual ~OPERATION_NAME() { \
      if (disable_destructor) { \
        return; \
      } \
      auto [q ARGS_LIST_FOR_FUNC_INVOKE(__VA_ARGS__)] = args_tuple; \
      operator()(q ARGS_LIST_FOR_FUNC_INVOKE(__VA_ARGS__)); \
      xacc::internal_compiler::execute_pass_manager(); \
      if (is_callable) { \
        quantum::submit(q.results()); \
      } \
    } \
  }; \
  void OPERATION_NAME(qreg q ARGS_LIST_FOR_FUNC_SIGNATURE(__VA_ARGS__)) { \
    class OPERATION_NAME kernel(q ARGS_LIST_FOR_FUNC_INVOKE(__VA_ARGS__)); \
  } 

// Usage:
// qcor_import_qsharp_kernel(MyQsharpKernel, double, int);
// This will inject a QCOR kernel of signature:
// void MyQsharpKernel(qreg, double, int);
// which can be used in QCOR, e.g. supporting NISQ remote submit API
// and runtime pass manager, etc.
+2 −1
Original line number Diff line number Diff line
namespace XACC 
{
open Microsoft.Quantum.Intrinsic;
operation TestGhz(q : Qubit[]) : Unit {
operation TestKernel(q : Qubit[], theta: Double) : Unit {
    H(q[0]);
    Ry(theta, q[1]);
    CNOT(q[0],q[1]);
    CNOT(q[0],q[2]);
    let res0 = M(q[0]);
+29 −0
Original line number Diff line number Diff line
#include <iostream> 
#include <vector>
#include "qcor.hpp"
#include "import_kernel_utils.hpp"

using Qubit = uint64_t;
using QReg = std::vector<Qubit*>;
// Util pre-processor to wrap Q# operation in a QCOR QuantumKernel.
qcor_import_qsharp_kernel(XACC__TestKernel, double);

// Compile with:
// Include both the qsharp source and this driver file
// in the command line.
// $ qcor -qpu aer:ibmqx2 -shots 1024 kernel_nisq.qs kernel_nisq_driver.cpp
// Run with:
// $ ./a.out
int main() {
  auto q = qalloc(3);
  qcor::set_verbose(true);
  // XACC__TestKernel(q, 1.0);
  // q.print();

  // Integrate w/ QCOR's kernel utility...
  // e.g. kernel print-out...
  std::cout << "HELLO:\n";
  XACC__TestKernel::print_kernel(std::cout, q, M_PI/4);

  return 0;
}
 No newline at end of file