qBraid / qbraid-qir

qBraid-SDK QIR transpiler integration
https://docs.qbraid.com/qir
GNU General Public License v3.0
16 stars 4 forks source link

Support loop statements in `qasm3` converter #67

Closed TheGupta2012 closed 3 months ago

TheGupta2012 commented 6 months ago

Feature Description

Implementation (Optional)

Example

A minimum reproducible example would be the following -

QASM

OPENQASM 3.0;
include "stdgates.inc";

qubit[4] q;
bit[4] c;

h q;
for int i in range[0:2]{ 
    cx q[i], q[i+1];
} 
measure q->c;

Expected QIR

; ModuleID = 'my-circuit'
source_filename = "my-circuit"

%Qubit = type opaque
%Result = type opaque

define void @main() #0 {
entry:
  call void @__quantum__rt__initialize(i8* null)
  call void @__quantum__qis__h__body(%Qubit* null)
  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*))
  call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 3 to %Qubit*))
  call void @__quantum__qis__cnot__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__cnot__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 2 to %Qubit*))
  call void @__quantum__qis__cnot__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Qubit* inttoptr (i64 3 to %Qubit*))
  call void @__quantum__qis__mz__body(%Qubit* null, %Result* null)
  call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
  call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 2 to %Result*))
  call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* inttoptr (i64 3 to %Result*))
  call void @__quantum__rt__result_record_output(%Result* null, i8* null)
  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 2 to %Result*), i8* null)
  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 3 to %Result*), i8* null)
  ret void
}

declare void @__quantum__rt__initialize(i8*)

declare void @__quantum__qis__h__body(%Qubit*)

declare void @__quantum__qis__cnot__body(%Qubit*, %Qubit*)

declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1

declare void @__quantum__rt__result_record_output(%Result*, i8*)

attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="custom" "required_num_qubits"="4" "required_num_results"="4" }
attributes #1 = { "irreversible" }

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 1, !"qir_major_version", i32 1}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
!3 = !{i32 1, !"dynamic_result_management", i1 false

An advice would be to start from the simpler cases and then build up iteratively.

ejthomas commented 3 months ago

Hi there! I've started work on this issue and added a draft PR (#110). I'd be very interested in feedback if possible, especially regarding remaining looping features that I haven't yet been able to figure out - instantiating the loop range using a BitstringLiteral or ArrayLiteral seem to run into issues where these types cannot be evaluated in BasicQasmVisitor._evaluate_expression(). I looked into while loops as well before opening the PR, but I can't easily see how to generalize the branching logic from BasicQasmVisitor._visit_branching_statement() as that seems to apply to specific comparisons with specific argument types (e.g. x < 5 doesn't appear to be allowed). Any tips on where I can focus next would be much appreciated :)

ejthomas commented 3 months ago

Thanks for merging my PR! It would be very helpful for UnitaryHack if you could assign this issue to me if you're satisfied that this is resolved :)

TheGupta2012 commented 3 months ago

Closed through PR #110