Skip to content

Commit

Permalink
add conditional circuit box (#55)
Browse files Browse the repository at this point in the history
* add conditional circuit box

* fix lint
  • Loading branch information
cqc-melf authored Jul 21, 2023
1 parent fe30fb6 commit ce2b64e
Show file tree
Hide file tree
Showing 6 changed files with 261 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Changelog
0.2.0rc14 (July 2023)
---------------------
* add simplification for RangePredicate in case of equal bounds
* allow conditional circboxes in the circuit
* update pytket requirement to 1.17

0.2.0rc13 (June 2023)
Expand Down
8 changes: 8 additions & 0 deletions pytket/qir/conversion/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from pyqir import Value, IntPredicate
import pyqir

from pytket.transform import Transform # type: ignore
from pytket import Circuit, OpType, Bit, Qubit, predicates # type: ignore
from pytket.qasm.qasm import _retrieve_registers # type: ignore
from pytket.circuit import ( # type: ignore
Expand Down Expand Up @@ -345,6 +346,13 @@ def _rebase_op_to_gateset(self, op: OpType, args: List) -> Optional[Circuit]:

circuit.add_gate(op, args)
return circuit
elif op.type == OpType.CircBox:
circuit = Circuit(self.circuit.n_qubits, self.circuit.n_bits)
circuit.add_circbox(op, args)
Transform.DecomposeBoxes().apply(circuit)

return circuit

else:
params = op.params
circuit = Circuit(self.circuit.n_qubits, self.circuit.n_bits)
Expand Down
64 changes: 63 additions & 1 deletion tests/conditional_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

from pytket.qir.conversion.api import pytket_to_qir, QIRFormat

from pytket.circuit import Circuit, Qubit, if_not_bit, Bit, OpType, reg_eq # type: ignore
from pytket.circuit import Circuit, Qubit, if_not_bit, Bit, OpType, reg_eq, CircBox # type: ignore


def test_pytket_qir_conditional() -> None:
Expand Down Expand Up @@ -171,6 +171,68 @@ def test_pytket_qir_conditional_7() -> None:
check_qir_result(result, "test_pytket_qir_conditional_7")


def test_pytket_qir_conditional_8() -> None:

c = Circuit(4)
c.H(0)
c.H(1)
c.H(2)
c.H(3)
cbox = CircBox(c)
d = Circuit(4)
a = d.add_c_register("a", 4)
d.add_circbox(cbox, [0, 2, 1, 3], condition=a[0])

result = pytket_to_qir(
d, name="test_pytket_qir_conditional_8", qir_format=QIRFormat.STRING
)

check_qir_result(result, "test_pytket_qir_conditional_8")


def test_pytket_qir_conditional_9() -> None:

c = Circuit(4)
c.X(0)
c.Y(1)
c.Z(2)
c.H(3)
cbox = CircBox(c)
d = Circuit(4)
a = d.add_c_register("a", 4)
d.add_circbox(cbox, [0, 2, 1, 3], condition=a[0])

result = pytket_to_qir(
d, name="test_pytket_qir_conditional_9", qir_format=QIRFormat.STRING
)

check_qir_result(result, "test_pytket_qir_conditional_9")


def test_pytket_qir_conditional_10() -> None:

box_circ = Circuit(4)
box_circ.X(0)
box_circ.Y(1)
box_circ.Z(2)
box_circ.H(3)
box_c = box_circ.add_c_register("c", 5)

box_circ.H(0)
box_circ.add_classicalexpbox_register(box_c | box_c, box_c)

cbox = CircBox(box_circ)
d = Circuit(4, 5)
a = d.add_c_register("a", 4)
d.add_circbox(cbox, [0, 2, 1, 3, 0, 1, 2, 3, 4], condition=a[0])

result = pytket_to_qir(
d, name="test_pytket_qir_conditional_10", qir_format=QIRFormat.STRING
)

check_qir_result(result, "test_pytket_qir_conditional_10")


if __name__ == "__main__":
test_pytket_qir_conditional()
test_pytket_qir_conditional_ii()
Expand Down
69 changes: 69 additions & 0 deletions tests/qir/test_pytket_qir_conditional_10.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
; ModuleID = 'test_pytket_qir_conditional_10'
source_filename = "test_pytket_qir_conditional_10"

%Qubit = type opaque
%Result = type opaque

@0 = internal constant [2 x i8] c"a\00"
@1 = internal constant [2 x i8] c"c\00"

define void @main() #0 {
entry:
%0 = call i64 @reg2var(i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false)
%1 = call i64 @reg2var(i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false)
%2 = call i1 @read_bit_from_reg(i64 %0, i64 0)
br i1 %2, label %then, label %else

then: ; preds = %entry
%3 = or i64 %1, %1
call void @set_all_bits_in_reg(i64 %1, i64 %3)
call void @__quantum__qis__x__body(%Qubit* null)
call void @__quantum__qis__z__body(%Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__y__body(%Qubit* inttoptr (i64 2 to %Qubit*))
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 3 to %Qubit*))
call void @__quantum__qis__h__body(%Qubit* null)
br label %continue

else: ; preds = %entry
br label %continue

continue: ; preds = %else, %then
call void @__quantum__rt__tuple_start_record_output()
call void @__quantum__rt__int_record_output(i64 %0, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @0, i32 0, i32 0))
call void @__quantum__rt__int_record_output(i64 %1, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @1, i32 0, i32 0))
call void @__quantum__rt__tuple_end_record_output()
ret void
}

declare i1 @read_bit_from_reg(i64, i64)

declare void @set_one_bit_in_reg(i64, i64, i1)

declare void @set_all_bits_in_reg(i64, i64)

declare i1 @__quantum__qis__read_result__body(%Result*)

declare i64 @reg2var(i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1)

declare void @__quantum__rt__int_record_output(i64, i8*)

declare void @__quantum__rt__tuple_start_record_output()

declare void @__quantum__rt__tuple_end_record_output()

declare void @__quantum__qis__x__body(%Qubit*)

declare void @__quantum__qis__z__body(%Qubit*)

declare void @__quantum__qis__y__body(%Qubit*)

declare void @__quantum__qis__h__body(%Qubit*)

attributes #0 = { "entry_point" "num_required_qubits"="4" "num_required_results"="4" "output_labeling_schema" "qir_profiles"="custom" }

!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}
57 changes: 57 additions & 0 deletions tests/qir/test_pytket_qir_conditional_8.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
; ModuleID = 'test_pytket_qir_conditional_8'
source_filename = "test_pytket_qir_conditional_8"

%Qubit = type opaque
%Result = type opaque

@0 = internal constant [2 x i8] c"a\00"

define void @main() #0 {
entry:
%0 = call i64 @reg2var(i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false)
%1 = call i1 @read_bit_from_reg(i64 %0, i64 0)
br i1 %1, label %then, label %else

then: ; preds = %entry
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*))
br label %continue

else: ; preds = %entry
br label %continue

continue: ; preds = %else, %then
call void @__quantum__rt__tuple_start_record_output()
call void @__quantum__rt__int_record_output(i64 %0, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @0, i32 0, i32 0))
call void @__quantum__rt__tuple_end_record_output()
ret void
}

declare i1 @read_bit_from_reg(i64, i64)

declare void @set_one_bit_in_reg(i64, i64, i1)

declare void @set_all_bits_in_reg(i64, i64)

declare i1 @__quantum__qis__read_result__body(%Result*)

declare i64 @reg2var(i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1)

declare void @__quantum__rt__int_record_output(i64, i8*)

declare void @__quantum__rt__tuple_start_record_output()

declare void @__quantum__rt__tuple_end_record_output()

declare void @__quantum__qis__h__body(%Qubit*)

attributes #0 = { "entry_point" "num_required_qubits"="4" "num_required_results"="4" "output_labeling_schema" "qir_profiles"="custom" }

!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}
63 changes: 63 additions & 0 deletions tests/qir/test_pytket_qir_conditional_9.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
; ModuleID = 'test_pytket_qir_conditional_9'
source_filename = "test_pytket_qir_conditional_9"

%Qubit = type opaque
%Result = type opaque

@0 = internal constant [2 x i8] c"a\00"

define void @main() #0 {
entry:
%0 = call i64 @reg2var(i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false)
%1 = call i1 @read_bit_from_reg(i64 %0, i64 0)
br i1 %1, label %then, label %else

then: ; preds = %entry
call void @__quantum__qis__x__body(%Qubit* null)
call void @__quantum__qis__z__body(%Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__y__body(%Qubit* inttoptr (i64 2 to %Qubit*))
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 3 to %Qubit*))
br label %continue

else: ; preds = %entry
br label %continue

continue: ; preds = %else, %then
call void @__quantum__rt__tuple_start_record_output()
call void @__quantum__rt__int_record_output(i64 %0, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @0, i32 0, i32 0))
call void @__quantum__rt__tuple_end_record_output()
ret void
}

declare i1 @read_bit_from_reg(i64, i64)

declare void @set_one_bit_in_reg(i64, i64, i1)

declare void @set_all_bits_in_reg(i64, i64)

declare i1 @__quantum__qis__read_result__body(%Result*)

declare i64 @reg2var(i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1, i1)

declare void @__quantum__rt__int_record_output(i64, i8*)

declare void @__quantum__rt__tuple_start_record_output()

declare void @__quantum__rt__tuple_end_record_output()

declare void @__quantum__qis__x__body(%Qubit*)

declare void @__quantum__qis__z__body(%Qubit*)

declare void @__quantum__qis__y__body(%Qubit*)

declare void @__quantum__qis__h__body(%Qubit*)

attributes #0 = { "entry_point" "num_required_qubits"="4" "num_required_results"="4" "output_labeling_schema" "qir_profiles"="custom" }

!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}

0 comments on commit ce2b64e

Please sign in to comment.