Commit 3a210233 authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Fixed a bug in handling modifier region qubit operand



(to handle nested modifier regions appropriately)

Add tests for CCX expansion and adjoint + ctrl nested.

Extend the number of gate operation pass runs to 10 (from 5): testing show that 5 runs is not enough to completely cancel the CCX + inv(CCX) circuit.

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 1d6142b5
Loading
Loading
Loading
Loading
+72 −0
Original line number Diff line number Diff line
@@ -355,6 +355,78 @@ ctrl @ t q[0], q[1];
    EXPECT_EQ(countSubstring(llvm, "__quantum__rt__start_ctrl_u_region"), 1);
    EXPECT_EQ(countSubstring(llvm, "__quantum__rt__end_ctrl_u_region"), 1);
  }
  {
    const std::string src = R"#(OPENQASM 3;
include "qelib1.inc";
qubit q[3];
ctrl @ cx q[0], q[1], q[2];
)#";
    auto llvm =
        qcor::mlir_compile(src, "ctrl_test", qcor::OutputType::LLVMIR, false);
    std::cout << "LLVM:\n" << llvm << "\n";
    llvm = llvm.substr(llvm.find("@__internal_mlir_ctrl_test"));
    const auto last = llvm.find_first_of("}");
    llvm = llvm.substr(0, last + 1);
    std::cout << "LLVM:\n" << llvm << "\n";
    // CCX => 15 gates
    EXPECT_EQ(countSubstring(llvm, "__quantum__qis"), 15);
    // 6 CNOT's, 2 H, 4 T, 3 Tdg
    EXPECT_EQ(countSubstring(llvm, "__quantum__qis__cnot("), 6);
    EXPECT_EQ(countSubstring(llvm, "__quantum__qis__h("), 2);
    EXPECT_EQ(countSubstring(llvm, "__quantum__qis__t("), 4);
    EXPECT_EQ(countSubstring(llvm, "__quantum__qis__tdg("), 3);
    // No runtime involved
    EXPECT_EQ(countSubstring(llvm, "__quantum__rt__start_ctrl_u_region"), 0);
    EXPECT_EQ(countSubstring(llvm, "__quantum__rt__end_ctrl_u_region"), 0);
  }
  // Check inv (adjoint) of controlled
  {
    const std::string src = R"#(OPENQASM 3;
include "qelib1.inc";
qubit q[3];
inv @ ctrl @ cx q[0], q[1], q[2];
)#";
    auto llvm =
        qcor::mlir_compile(src, "ctrl_test", qcor::OutputType::LLVMIR, false);
    std::cout << "LLVM:\n" << llvm << "\n";
    llvm = llvm.substr(llvm.find("@__internal_mlir_ctrl_test"));
    const auto last = llvm.find_first_of("}");
    llvm = llvm.substr(0, last + 1);
    std::cout << "LLVM:\n" << llvm << "\n";
    // CCX => 15 gates (same number when inverse)
    EXPECT_EQ(countSubstring(llvm, "__quantum__qis"), 15);
    // 6 CNOT's, 2 H, 4 T, 3 Tdg => 6 CNOT's, 2 H, 4 Tdg, 3 T
    // Note: T is mapped to Tdg and vice verssa
    EXPECT_EQ(countSubstring(llvm, "__quantum__qis__cnot("), 6);
    EXPECT_EQ(countSubstring(llvm, "__quantum__qis__h("), 2);
    EXPECT_EQ(countSubstring(llvm, "__quantum__qis__t("), 3);
    EXPECT_EQ(countSubstring(llvm, "__quantum__qis__tdg("), 4);
    // No runtime involved
    EXPECT_EQ(countSubstring(llvm, "__quantum__rt__start_ctrl_u_region"), 0);
    EXPECT_EQ(countSubstring(llvm, "__quantum__rt__end_ctrl_u_region"), 0);
  }
  // Check fully expanded and gate cancellation
  {
    const std::string src = R"#(OPENQASM 3;
include "qelib1.inc";
qubit q[3];
// Controlled then adjoint of controlled
ctrl @ cx q[0], q[1], q[2];
inv @ ctrl @ cx q[0], q[1], q[2];
)#";
    auto llvm =
        qcor::mlir_compile(src, "ctrl_test", qcor::OutputType::LLVMIR, false);
    std::cout << "LLVM:\n" << llvm << "\n";
    llvm = llvm.substr(llvm.find("@__internal_mlir_ctrl_test"));
    const auto last = llvm.find_first_of("}");
    llvm = llvm.substr(0, last + 1);
    std::cout << "LLVM:\n" << llvm << "\n";
    // No gate left
    EXPECT_EQ(countSubstring(llvm, "__quantum__qis"), 0);
    // No runtime involved
    EXPECT_EQ(countSubstring(llvm, "__quantum__rt__start_ctrl_u_region"), 0);
    EXPECT_EQ(countSubstring(llvm, "__quantum__rt__end_ctrl_u_region"), 0);
  }
}

int main(int argc, char **argv) {
+3 −2
Original line number Diff line number Diff line
@@ -471,6 +471,7 @@ antlrcpp::Any qasm3_visitor::visitQuantumGateCall(
    if (auto ctrlOp =
            llvm::dyn_cast_or_null<mlir::quantum::CtrlURegion>(modifierOpPtr)) {
      returnedValues.insert(returnedValues.begin(), 1, ctrlOp.ctrl_qubit());
      qbit_values.insert(qbit_values.begin(), 1, ctrlOp.ctrl_qubit());
    }
    auto modifierYieldOp = builder.create<mlir::quantum::ModifierEndOp>(location, returnedValues);
    returnedValues.clear();
@@ -491,9 +492,9 @@ antlrcpp::Any qasm3_visitor::visitQuantumGateCall(
      }
    } else if (auto ctrlOp =
                   llvm::dyn_cast_or_null<mlir::quantum::CtrlURegion>(modifierOpPtr)) {
      assert(ctrlOp.getResults().size() == qbit_values.size() + 1);
      assert(ctrlOp.getResults().size() == qbit_values.size());
      symbol_table.replace_symbol(ctrlOp.ctrl_qubit(), ctrlOp.getResult(0));
      for (int i = 0; i < qbit_values.size() + 1; ++i) {
      for (int i = 0; i < qbit_values.size(); ++i) {
        symbol_table.replace_symbol(modifierYieldOp.getOperand(i),
                                    ctrlOp.getResult(i));
        returnedValues.emplace_back(ctrlOp.getResult(i));
+1 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ void configureOptimizationPasses(mlir::PassManager &passManager) {
  passManager.addPass(std::make_unique<SimplifyQubitExtractPass>());
  // TODO: configure the pass pipeline to handle repeated applications of
  // passes. Add passes
  constexpr int N_REPS = 5;
  constexpr int N_REPS = 10;
  for (int i = 0; i < N_REPS; ++i) {
    // Simple Identity pair removals
    passManager.addPass(std::make_unique<SingleQubitIdentityPairRemovalPass>());