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

Proper handling of Controlled with single argument



Update the example to have Controlled application

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 13ebdef0
Loading
Loading
Loading
Loading
+15 −3
Original line number Diff line number Diff line
@@ -14,13 +14,25 @@

// QASM3 function wrapping the quantum sub-routine as a QIR Callable
extern "C" ::Callable* qasm_x__callable(); 
// Q# function
// Q# functions:
// Apply an op to all qubits using the ApplyToEachCA util of Q#
extern "C" void QCOR__ApplyKernelToEachQubit__body(::Callable *);

// Apply Controlled version of a Callable (X gate in QASM3)
// This will just be a Bell experiment.
extern "C" void QCOR__ApplyControlledKernel__body(::Callable *);
int main() {
  // Get the callable (QASM3)
  auto qasm3_callable = qasm_x__callable();
  // Pass it to Q#
  QCOR__ApplyKernelToEachQubit__body(qasm3_callable);
  // std::cout << "Apply the functor to each qubit:\n";
  // QCOR__ApplyKernelToEachQubit__body(qasm3_callable);

  // Run Bell experiment:
  constexpr int COUNT = 100;
  std::cout << "Apply controlled functor(Bell test):\n";
  for (int i = 0; i < COUNT; ++i) {
    std::cout << "Run " << i + 1 << ":\n";
    QCOR__ApplyControlledKernel__body(qasm3_callable);
  }
  return 0;
}
 No newline at end of file
+3 −1
Original line number Diff line number Diff line
#pragma no_entrypoint;

OPENQASM 3;
include "stdgates.inc";

def qasm_x qubit:qb {
  print("Call X gate from QASM3!");
  print("Hello from QASM3!");
  x qb;
}
+23 −0
Original line number Diff line number Diff line
@@ -16,4 +16,27 @@ operation ApplyKernelToEachQubit(singleElementOperation : (Qubit => Unit is Adj
    }
  }
}

operation ApplyControlledKernel(singleElementOperation : ((Qubit) => Unit is Adj + Ctl)): Unit {
  use q = Qubit[2];
  
  H(q[0]);
  // Apply controlled
  Controlled singleElementOperation([q[0]], (q[1])); 
  let res0 = M(q[0]);    
  if res0 == One {
    Message("Meas Q0 -> one");
    X(q[0]);
  } else {
    Message("Meas Q0 -> zero");
  }

  let res1 = M(q[1]);    
  if res1 == One {
    Message("Meas Q1 -> one");
    X(q[1]);
  } else {
    Message("Meas Q0 -> zero");
  }
}
}
 No newline at end of file
+60 −29
Original line number Diff line number Diff line
@@ -85,6 +85,36 @@ void add_callable_gen(mlir::OpBuilder &builder, const std::string &func_name,
    assert(arguments.size() == 3);
    mlir::Value arg_tuple = arguments[1];
    auto fn_type = wrapped_func.getType().cast<mlir::FunctionType>();
    // !IMPORTANT! The argument tuple will be flattened *iff* 
    // there is only one argument.
    // i.e. { Array, SingleArg}
    if (wrapped_func.getType().cast<mlir::FunctionType>().getInputs().size() ==
        1) {
      mlir::TypeRange arg_types(
          {array_type,
           wrapped_func.getType().cast<mlir::FunctionType>().getInputs()[0]});
      auto unpackOp = builder.create<mlir::quantum::TupleUnpackOp>(
          builder.getUnknownLoc(), arg_types, arg_tuple);
      mlir::Value control_array = unpackOp.result()[0];
      mlir::Value single_func_arg = unpackOp.result()[1];
      mlir::Value qubit_idx = builder.create<mlir::ConstantOp>(
          builder.getUnknownLoc(),
          mlir::IntegerAttr::get(builder.getI64Type(), 0));
      mlir::Value ctrl_qubit = builder.create<mlir::quantum::ExtractQubitOp>(
          builder.getUnknownLoc(), qubit_type, control_array, qubit_idx);

      // Call the function wrapped in StartCtrlURegion/EndCtrlURegion
      builder.create<mlir::quantum::StartCtrlURegion>(builder.getUnknownLoc());

      builder.create<mlir::CallOp>(builder.getUnknownLoc(), wrapped_func,
                                   single_func_arg);

      builder.create<mlir::quantum::EndCtrlURegion>(builder.getUnknownLoc(),
                                                    ctrl_qubit);
      builder.create<mlir::ReturnOp>(builder.getUnknownLoc());
      moduleOp.push_back(function_op);
      all_wrapper_funcs.emplace_back(function_op);
    } else {
      // Unpack to Array + Tuple (Array = controlled bits)
      // { Array + { Body Tuple } }
      // FIXME: currently, we can only handle single-qubit control
@@ -115,6 +145,7 @@ void add_callable_gen(mlir::OpBuilder &builder, const std::string &func_name,
      moduleOp.push_back(function_op);
      all_wrapper_funcs.emplace_back(function_op);
    }
  }
  {
    // Controlled Adjoint wrapper:
    const std::string wrapper_fn_name = func_name + CTRL_ADJOINT_WRAPPER_SUFFIX;