Commit 46b17eda authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

setup mlir gen for openqasm to auto add gate impls not found in default staq

parent 49761e6f
Loading
Loading
Loading
Loading
Loading
+138 −1
Original line number Diff line number Diff line
@@ -17,6 +17,98 @@ static std::vector<std::string> search_for_inliner{
    "u3", "u2",  "u1", "cx",  "id", "u0", "x",  "y",  "z",  "h",
    "s",  "sdg", "t",  "tdg", "rx", "ry", "rz", "cz", "cy", "swap"};

static std::map<std::string, std::string> missing_builtins{
    {"u", R"#(
gate u(theta,phi,lambda) q { U(theta,phi,lambda) q; })#"},
    {"p", R"#(gate p(theta) a
{
  rz(theta) a;
})#"},
    {"sx", R"#(gate sx a { sdg a; h a; sdg a; })#"},
    {"sxdg", R"#(gate sxdg a { s a; h a; s a; })#"},
    {"cswap", R"#(gate cswap a,b,c
{
  cx c,b;
  ccx a,b,c;
  cx c,b;
})#"},
    {"crx", R"#(gate crx(lambda) a,b
{
  u1(pi/2) b;
  cx a,b;
  u3(-lambda/2,0,0) b;
  cx a,b;
  u3(lambda/2,-pi/2,0) b;
})#"},
    {"cry", R"#(gate cry(lambda) a,b
{
  u3(lambda/2,0,0) b;
  cx a,b;
  u3(-lambda/2,0,0) b;
  cx a,b;
  ry(lambda) a;
})#"},
    {"cp", R"#(gate cp(lambda) a,b
{
  p(lambda/2) a;
  cx a,b;
  p(-lambda/2) b;
  cx a,b;
  p(lambda/2) b;
})#"},
    {"csx", R"#(gate csx a,b { h b; cu1(pi/2) a,b; h b; })#"},
    {"cu", R"#(gate cu(theta,phi,lambda,gamma) c, t
{ p(gamma) c;
  p((lambda+phi)/2) c;
  p((lambda-phi)/2) t;
  cx c,t;
  u(-theta/2,0,-(phi+lambda)/2) t;
  cx c,t;
  u(theta/2,phi,0) t;
})#"},
    {"rxx", R"#(gate rxx(theta) a,b
{
  u3(pi/2, theta, 0) a;
  h b;
  cx a,b;
  u1(-theta) b;
  cx a,b;
  h b;
  u2(-pi, pi-theta) a;
})#"},
    {"rzz", R"#(gate rzz(theta) a,b
{
  cx a,b;
  u1(theta) b;
  cx a,b;
})#"},
    {"rccx", R"#(gate rccx a,b,c
{
  u2(0,pi) c;
  u1(pi/4) c;
  cx b, c;
  u1(-pi/4) c;
  cx a, c;
  u1(pi/4) c;
  cx b, c;
  u1(-pi/4) c;
  u2(0,pi) c;
})#"}};

template <class Op>
void split(const std::string &s, char delim, Op op) {
  std::stringstream ss(s);
  for (std::string item; std::getline(ss, item, delim);) {
    *op++ = item;
  }
}

inline std::vector<std::string> split(const std::string &s, char delim) {
  std::vector<std::string> elems;
  split(s, delim, std::back_inserter(elems));
  return elems;
}

void CountGateDecls::visit(GateDecl &g) {
  auto name = g.id();
  if (std::find(builtins.begin(), builtins.end(), name) == builtins.end()) {
@@ -222,9 +314,54 @@ void OpenQasmMLIRGenerator::initialize_mlirgen(bool _add_entry_point,

void OpenQasmMLIRGenerator::mlirgen(const std::string &src) {
  using namespace staq;

  std::string src_copy = src;

  // Make sure we have the preamble text
  std::string preamble = "OPENQASM 2.0;";
  auto preamble_start = src.find(preamble);
  if (preamble_start == std::string::npos) {
    std::cout << "[OpenQASM MLIR Gen] Error, no OPENQASM 2.0 preamble text.\n";
    exit(1);
  }

  preamble = "include \"qelib1.inc\";";
  preamble_start = src.find(preamble);
  if (preamble_start == std::string::npos) {
    std::cout << "[OpenQASM MLIR Gen] Error, no include \"qelib1.inc\" "
                 "preamble text.\n";
    exit(1);
  }

  // Add any required missing pre-defines that we 
  // know the impl for.
  std::vector<std::string> added;
  std::string extra_insts = "\n";
  bool hasMeasures = false;
  auto lines = split(src, '\n');
  for (auto line : lines) {
    if (line.find("OPENQASM") == std::string::npos &&
        line.find("include") == std::string::npos &&
        line.find("measure") == std::string::npos &&
        line.find("qreg") == std::string::npos &&
        line.find("creg") == std::string::npos) {
      auto inst_name = split(line, ' ')[0];
      if (inst_name.find("(") != std::string::npos) {
        inst_name = inst_name.substr(0, inst_name.find("("));
      }
      if (std::find(builtins.begin(), builtins.end(), inst_name) ==
              builtins.end() &&
          std::find(added.begin(), added.end(), inst_name) == added.end()) {
        extra_insts += missing_builtins[inst_name] + "\n";
        added.push_back(inst_name);
      }
    }
  }
  src_copy.insert(preamble_start+preamble.length(), extra_insts);

  ast::ptr<ast::Program> prog;
  try {
    prog = parser::parse_string(src);
    prog = parser::parse_string(src_copy);
    // transformations::inline_ast(*prog);
    transformations::desugar(*prog);
  } catch (std::exception &e) {
+29 −4
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include "xacc_service.hpp"
#include "qcor_config.hpp"
#include "xacc_config.hpp"
#include "config_file_parser.hpp"

Result ResultZero = 0;
Result ResultOne = 1;
@@ -16,10 +17,11 @@ unsigned long allocated_qbits = 0;
std::shared_ptr<xacc::AcceleratorBuffer> qbits;
std::shared_ptr<xacc::Accelerator> qpu;
std::string qpu_name = "qpp";
std::string qpu_config = "";
enum QRT_MODE { FTQC, NISQ };
QRT_MODE mode;
std::vector<std::unique_ptr<Array>> allocated_arrays;
int shots = 1024;
int shots = 0;
bool verbose = false;
bool external_qreg_provided = false;

@@ -29,11 +31,13 @@ void print_help() {
  std::cout << "QCOR QIR Runtime Help Menu\n\n";
  std::cout << "optional arguments:\n";
  std::cout << "  -qpu QPUNAME[:BACKEND] | example -qpu ibm:ibmq_vigo, -qpu aer:ibmq_vigo\n";
  std::cout << "  -qpu-config config_file.ini | example: -qpu ibm:ibmq_vigo -qpu-config ibm_config.ini\n";
  std::cout << "  -qrt QRT_MODE (can be nisq or ftqc) | example -qrt nisq\n";
  std::cout << "  -shots NUMSHOTS (number of shots to use in nisq run)\n";
  std::cout << "  -opt LEVEL | example -opt 1\n";
  std::cout << "  -print-opt-stats (turn on printout of optimization statistics) \n";
  std::cout << "  -v,-verbose,--verbose (run with printouts)\n\n";
  std::cout << "  -v,-verbose,--verbose (run with printouts)\n";
  std::cout << "  -xacc-verbose (turn on extra xacc verbose print-out)\n\n";
  exit(0);
}

@@ -46,10 +50,15 @@ void __quantum__rt__initialize(int argc, int8_t** argv) {
    auto arg = args[i];
    if (arg == "-qpu") {
      qpu_name = args[i + 1];
    } else if (arg == "-qpu-config") {
      qpu_config = args[i+1];
    } else if (arg == "-qrt") {
      mode = args[i + 1] == "nisq" ? QRT_MODE::NISQ : QRT_MODE::FTQC;
    } else if (arg == "-shots") {
      shots = std::stoi(args[i + 1]);
    } else if (arg == "-xacc-verbose") {
      verbose = true;
      xacc::set_verbose(true);
    } else if (arg == "-v") {
      verbose = true;
    } else if (arg == "-verbose") {
@@ -99,9 +108,20 @@ void initialize() {
      std::cout << "[qir-qrt] Running on " << qpu_name << " backend.\n";
    std::shared_ptr<xacc::Accelerator> qpu;

    xacc::HeterogeneousMap qpu_config_map;
    if (!qpu_config.empty()) {
        auto parser = xacc::getService<xacc::ConfigFileParsingUtil>("ini");
        qpu_config_map = parser->parse(qpu_config);
    }

    if (!qpu_config_map.keyExists<int>("shots") && shots > 0 && mode == QRT_MODE::NISQ) {
      if (verbose) printf("Automatically setting shots for nisq mode execution to %d\n", shots);
      qpu_config_map.insert("shots", shots);
    }
    
    if (mode == QRT_MODE::NISQ) {
      xacc::internal_compiler::__qrt_env = "nisq";
      qpu = xacc::getAccelerator(qpu_name, {{"shots", shots}});
      qpu = xacc::getAccelerator(qpu_name, qpu_config_map);
    } else {
      qpu = xacc::getAccelerator(qpu_name);
    }
@@ -187,6 +207,11 @@ void __quantum__qis__rz(double x, Qubit* q) {
  if (verbose) printf("[qir-qrt] Applying Rz(%f) %lu\n", x, qcopy);
  ::quantum::rz({"q", qcopy}, x);
}
void __quantum__qis__u3(double theta, double phi, double lambda, Qubit* q) {
    std::size_t qcopy = reinterpret_cast<std::size_t>(q);
  if (verbose) printf("[qir-qrt] Applying U3(%f, %f, %f) %lu\n", theta, phi, lambda, qcopy);
  ::quantum::u3({"q", qcopy}, theta, phi, lambda);
}

Result* __quantum__qis__mz(Qubit* q) {
  if (verbose)
@@ -240,7 +265,7 @@ void __quantum__rt__qubit_release_array(Array* q) {
    if (allocated_arrays[i].get() == q) {
      auto& array_ptr = allocated_arrays[i];
      auto array_size = array_ptr->size();
      if (verbose)
      if (verbose && mode == QRT_MODE::FTQC)
        printf("[qir-qrt] deallocating the qubit array of size %lu\n",
               array_size);
      for (int k = 0; k < array_size; k++) {
+1 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ void __quantum__qis__z(Qubit* q);
void __quantum__qis__rx(double x, Qubit* q);
void __quantum__qis__ry(double x, Qubit* q);
void __quantum__qis__rz(double x, Qubit* q);
void __quantum__qis__u3(double theta, double phi, double lambda, Qubit* q);

Result* __quantum__qis__mz(Qubit* q);

+1 −0
Original line number Diff line number Diff line
@@ -696,6 +696,7 @@ class KernelBuilder(object):
            setattr(KernelBuilder, instruction[0].lower(), result[instruction[0].lower()])

    def measure_all(self):
        self.qjit_str += '\n'
        self.qjit_str += self.TAB + 'for i in range({}.size()):\n'.format(self.qreg_name)
        self.qjit_str += self.TAB+self.TAB+'Measure({}[i])\n'.format(self.qreg_name)

+8 −5
Original line number Diff line number Diff line
@@ -191,6 +191,9 @@ def main(argv=None):
        if '-qpu-config' in sys.argv[1:]:
            idx = sys.argv.index('-qpu-config')
            config_file = sys.argv[idx+1]
            if not os.path.exists(config_file):
                print('Invalid qpu config file path:', config_file)
                exit(1)

        accidx = sys.argv.index('-qpu')
        accName = sys.argv[accidx+1]
@@ -198,11 +201,9 @@ def main(argv=None):
        sys.argv.remove('-qpu')

        if config_file:
            # FIXME use absolute path name
            if ']' in accName:
                idx = accName.index(']')
                accName = accName[:idx] + ',qcor_qpu_config:'+config_file+accName[idx:]
                print(accName)
                accName = accName[:idx] + ',qcor_qpu_config:'+os.path.abspath(config_file)+accName[idx:]
            else:
                accName += '[qcor_qpu_config:'+config_file+']'
            sys.argv.remove(config_file)
@@ -377,7 +378,9 @@ def main(argv=None):
                print(e.returncode)
                return e.returncode
        else:
            print('invalid command line arguments for qcor')
            print('invalid command line arguments for qcor:')
            print('source file name and type:', (None if filename == '' else filename), ',', (None if fileType == '' else fileType))
            if verbose: print('current args: ', sys.argv)
            exit(1)
    else:
        # This is a .o file, so execute the link phase