Commit 1551bfee authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

Merge branch 'master' of https://github.com/ornl-qci/qcor

parents f83bd7d8 60e3a051
Loading
Loading
Loading
Loading
Loading
+19 −3
Original line number Diff line number Diff line
@@ -4,7 +4,6 @@
include "QuantumDialect.td"
include "mlir/Interfaces/SideEffectInterfaces.td"


def QubitType : OpaqueType<"quantum", "Qubit", "opaque qubit type">;
def ResultType : OpaqueType<"quantum", "Result", "opaque result type">;
def ArrayType : OpaqueType<"quantum", "Array", "opaque array type">;
@@ -228,10 +227,27 @@ def TupleUnpackOp : QuantumOp<"tupleUnpack", []> {
}

def CreateCallableOp : QuantumOp<"createCallable", []> {
    let arguments = (ins FlatSymbolRefAttr:$functors);
    let arguments = (ins FlatSymbolRefAttr:$functors, Variadic<AnyType>:$captures);
    let results = (outs CallableType:$callable);
    let printer = [{  auto op = *this;
  p << "q.createCallable" << "(" << op.functors() << ") : " << op.callable().getType(); }];
      p << "q.createCallable" << "(" << op.functors() << ") ";
      if (!op.captures().empty()) {
        p << "capture " << op.captures() << "(" << op.captures().getType()
          << ")";
      }
    }];
}

def ConditionalOp : QuantumOp<"ifOp", []> {
  let summary = "if-then-else operation conditioned on a quantum Measure";
  // Must be conditioned on a Result type (only then clause for now...)
  let arguments = (ins ResultType:$result_bit, CallableType:$then_callable);
  let results = (outs);

  let printer = [{
    auto op = *this;
    p << "q.If " << op.result_bit() << " { invoke " << op.then_callable() << " }";
  }];
}

#endif // Quantum_OPS
 No newline at end of file
+80 −0
Original line number Diff line number Diff line
OPENQASM 3;
include "qelib1.inc";

// NISQ-mode lowering to conditional (If) statements
// Compile targeting nisq runtime and a capable QPU:
// (1) Qpp simulator (default):
// qcor -qrt nisq -shots 1024 measure_conditional.qasm -print-final-submission 
// (2) Aer simulator (inspect the QObj to see the use of "conditional" to control quantum instructions)
// qcor -qrt nisq -qpu aer -shots 1024 measure_conditional.qasm -print-final-submission 
// (3) Honeywell: see the OpenQASM2 with if statements.
// qcor -qrt nisq -qpu honeywell:HQS-LT-S1-APIVAL -shots 1024 measure_conditional.qasm -print-final-submission 

// Expected to get 4 bits (iteratively) of 1011 (or 1101 LSB) = 11(decimal):
// phi_est = 11/16 (denom = 16 since we have 4 bits)
// => phi = 2pi * 11/16 = 11pi/8 = 2pi - 5pi/8
// i.e. we estimate the -5*pi/8 angle...
qubit q[2];
const bits_precision = 4;
bit c[bits_precision];

// Prepare the eigen-state: |1>
x q[1];

// First bit
h q[0];
// Controlled rotation: CU^k
for i in [0:8] {
  cphase(-5*pi/8) q[0], q[1];
}
h q[0];
// Measure and reset
measure q[0] -> c[0];
reset q[0];

// Second bit
h q[0];
for i in [0:4] {
  cphase(-5*pi/8) q[0], q[1];
}
// Conditional rotation
if (c[0] == 1) {
  rz(-pi/2) q[0];
}
h q[0];
// Measure and reset
measure q[0] -> c[1];
reset q[0];

// Third bit
h q[0];
for i in [0:2] {
  cphase(-5*pi/8) q[0], q[1];
}
// Conditional rotation
if (c[0] == 1) {
  rz(-pi/4) q[0];
}
if (c[1] == 1) {
  rz(-pi/2) q[0];
}
h q[0];
// Measure and reset
measure q[0] -> c[2];
reset q[0];

// Fourth bit
h q[0];
cphase(-5*pi/8) q[0], q[1];
// Conditional rotation
if (c[0] == 1) {
  rz(-pi/8) q[0];
}
if (c[1] == 1) {
  rz(-pi/4) q[0];
}
if (c[2] == 1) {
  rz(-pi/2) q[0];
}
h q[0];
measure q[0] -> c[3];
 No newline at end of file
+24 −1
Original line number Diff line number Diff line
@@ -51,6 +51,28 @@ void OpenQasmV3MLIRGenerator::initialize_mlirgen(
  file_name = function;
  add_entry_point = _add_entry_point;

  // Only enable the rewrite to NISQ If-statements when the compilation 
  // targets NISQ qrt for some specific QPUs:
  static const std::vector<std::string> IF_STMT_CAPABLE_QPUS{"qpp", "aer",
                                                             "honeywell"};
  if (extra_quantum_args.find("qrt") != extra_quantum_args.end() &&
      extra_quantum_args["qrt"] == "nisq") {
    // Default is qpp (i.e., not provided)
    if (extra_quantum_args.find("qpu") == extra_quantum_args.end()) {
      enable_qir_apply_ifelse = true;
    } else {
      for (const auto &name_to_check : IF_STMT_CAPABLE_QPUS) {
        const auto qpu_name = extra_quantum_args["qpu"];
        if (qpu_name.rfind(name_to_check, 0) == 0) {
          // QPU start with aer, honeywell, etc.
          // (it could have backend name customization after ':')
          enable_qir_apply_ifelse = true;
          break;
        }
      }
    }
  }

  // Useful opaque type defs
  llvm::StringRef qubit_type_name("Qubit"), array_type_name("Array"),
      result_type_name("Result");
@@ -146,7 +168,8 @@ void OpenQasmV3MLIRGenerator::mlirgen(const std::string &src) {
  using namespace qasm3;

  if (!visitor) {
    visitor = std::make_shared<qasm3_visitor>(builder, m_module, file_name);
    visitor = std::make_shared<qasm3_visitor>(builder, m_module, file_name,
                                              enable_qir_apply_ifelse);
  }

  ANTLRInputStream input(src);
+3 −1
Original line number Diff line number Diff line
@@ -11,7 +11,9 @@ class OpenQasmV3MLIRGenerator : public qcor::QuantumMLIRGenerator {
  std::string file_name = "main";
  bool add_entry_point = true;
  bool add_custom_return = false;

  // Enable special code-gen mode for specific targets that
  // support NISQ-like conditional statements.
  bool enable_qir_apply_ifelse = false;
  mlir::Type return_type;

  mlir::Type qubit_type;
+5 −3
Original line number Diff line number Diff line
@@ -30,8 +30,10 @@ class qasm3_visitor : public qasm3::qasm3BaseVisitor {
  ScopedSymbolTable* getScopedSymbolTable() { return &symbol_table; }

  // The constructor, instantiates commonly used opaque types
  qasm3_visitor(mlir::OpBuilder b, mlir::ModuleOp m, std::string& fname)
      : builder(b), file_name(fname), m_module(m) {
  qasm3_visitor(mlir::OpBuilder b, mlir::ModuleOp m, std::string &fname,
                bool enable_nisq_conditional = false)
      : builder(b), file_name(fname), m_module(m),
        enable_nisq_ifelse(enable_nisq_conditional) {
    auto context = b.getContext();
    llvm::StringRef qubit_type_name("Qubit"), array_type_name("Array"),
        result_type_name("Result");
@@ -189,7 +191,7 @@ class qasm3_visitor : public qasm3::qasm3BaseVisitor {
  mlir::OpBuilder builder;
  mlir::ModuleOp m_module;
  std::string file_name = "";

  bool enable_nisq_ifelse = false;  
  // We keep reference to these blocks so that
  // we can handle break/continue correctly
  mlir::Block* current_loop_exit_block;
Loading