NVIDIA / cuda-quantum

C++ and Python support for the CUDA Quantum programming model for heterogeneous quantum-classical workflows
https://nvidia.github.io/cuda-quantum/
Other
427 stars 149 forks source link

issue with if condition after mid circuit measurement #1875

Open marwafar opened 1 week ago

marwafar commented 1 week ago

Required prerequisites

Describe the bug

If I run example 1, it will work and print the register a. However, if I run example 2, it will not print the register a

Steps to reproduce the bug

Example 1:

import cudaq

@cudaq.kernel
def kernel_break():
    ancilla_a=cudaq.qubit()
    ancilla_b=cudaq.qubit()
    q=cudaq.qubit()

    h(ancilla_a)
    h(ancilla_b)
    x(q)

    aux_1=mz(ancilla_a)
    aux_2=mz(ancilla_b)
    if aux_1==0:
        if aux_2==0:
            x.ctrl(ancilla_a,q)
            a=mz(q)

count=cudaq.sample(kernel_break,shots_count=1000)
print(count)

Example 2:

import cudaq

@cudaq.kernel
def kernel_break():
    ancilla_a=cudaq.qubit()
    ancilla_b=cudaq.qubit()
    q=cudaq.qubit()

    h(ancilla_a)
    h(ancilla_b)
    x(q)

    aux_1=mz(ancilla_a)
    aux_2=mz(ancilla_b)
    if aux_1==0 and aux_2==0:
        #if aux_2==0:
        x.ctrl(ancilla_a,q)
        a=mz(q)

count=cudaq.sample(kernel_break,shots_count=1000)
print(count)

Expected behavior

if aux_1==0:
   if aux_2==0:
      ......

and

if aux_1==0 and axu_2==0:
   ....

I expect the two if statement should work.

Is this a regression? If it is, put the last known working version (or commit) here.

Not a regression

Environment

Suggestions

No response

schweitzpgi commented 5 days ago

Doing some triage, it looks like the and operator is lowering to correct code initially. But something is going sideways after that.

  func.func @__nvqpp__mlirgen__kernel_break() attributes {"cudaq-entrypoint"} {
    %false = arith.constant false
    %c0_i64 = arith.constant 0 : i64
    %0 = quake.alloca !quake.ref
    %1 = quake.alloca !quake.ref
    %2 = quake.alloca !quake.ref
    quake.h %0 : (!quake.ref) -> ()
    quake.h %1 : (!quake.ref) -> ()
    quake.x %2 : (!quake.ref) -> ()
    %measOut = quake.mz %0 name "aux_1" : (!quake.ref) -> !quake.measure
    %3 = quake.discriminate %measOut : (!quake.measure) -> i1
    %measOut_0 = quake.mz %1 name "aux_2" : (!quake.ref) -> !quake.measure
    %4 = quake.discriminate %measOut_0 : (!quake.measure) -> i1
    %5 = cc.cast unsigned %3 : (i1) -> i64
    %6 = arith.cmpi eq, %5, %c0_i64 : i64
    %7 = arith.cmpi eq, %6, %false : i1
    %8 = cc.if(%7) -> i1 {
      cc.continue %false : i1
    } else {
      %9 = cc.cast unsigned %4 : (i1) -> i64
      %10 = arith.cmpi eq, %9, %c0_i64 : i64
      cc.continue %10 : i1
    }
    cc.if(%8) {
      quake.x [%0] %2 : (!quake.ref, !quake.ref) -> ()
      %measOut_1 = quake.mz %2 name "a" : (!quake.ref) -> !quake.measure
    }
    return
  }