From c424b24c42e646c6b51bcdd7076249091376164d Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:35:34 +0000 Subject: [PATCH 01/30] initial attempt at CircBox handling --- pytket/extensions/qiskit/qiskit_convert.py | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 0a84eee1..3c5d5f9c 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -82,6 +82,7 @@ Parameter, ParameterExpression, Reset, + IfElseOp, ) from qiskit.circuit.library import ( CRYGate, @@ -478,6 +479,37 @@ def _build_circbox(instr: Instruction, circuit: QuantumCircuit) -> CircBox: subc.name = instr.name return CircBox(subc) +from pytket.circuit.display import view_browser as draw + + +# TODO refactor to reduce duplication +def _pytket_boxes_from_IfElseOp(instr: Instruction) -> tuple[CircBox, CircBox]: + if_qc: QuantumCircuit = instr.params[0] + else_qc: QuantumCircuit = instr.params[1] + + default_qreg_if = QuantumRegister(if_qc.num_qubits, "q") + default_creg_if = ClassicalRegister(if_qc.num_clbits, "c") + default_qreg_else = QuantumRegister(else_qc.num_qubits, "q") + default_creg_else = ClassicalRegister(else_qc.num_clbits, "c") + + new_if_qc = QuantumCircuit(default_qreg_if, default_creg_if) + new_else_qc = QuantumCircuit(default_qreg_else, default_creg_else) + + if_builder = CircuitBuilder(new_if_qc.qregs, new_if_qc.cregs) + if_builder.add_qiskit_data(new_if_qc) + if_circuit = if_builder.circuit() + if_circuit.name = "If" + + + else_builder = CircuitBuilder(new_else_qc.qregs, new_else_qc.cregs) + else_builder.add_qiskit_data(new_else_qc) + else_circuit = else_builder.circuit() + else_circuit.name = "Else" + + return CircBox(if_circuit), CircBox(else_circuit) + + + class CircuitBuilder: def __init__( @@ -523,6 +555,11 @@ def add_qiskit_data( condition_kwargs = {} if instr.condition is not None: + if type(instr) is IfElseOp: + if_box, else_box = _pytket_boxes_from_IfElseOp(instr) + draw(if_box.get_circuit()) + draw(else_box.get_circuit()) + condition_kwargs = _get_pytket_condition_kwargs( instruction=instr, cregmap=self.cregmap, From 3b9189ae595b25b53deaaaa240f492cda108fe26 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:36:10 +0000 Subject: [PATCH 02/30] add temporary if-else test --- if-else.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 if-else.py diff --git a/if-else.py b/if-else.py new file mode 100644 index 00000000..037d6081 --- /dev/null +++ b/if-else.py @@ -0,0 +1,32 @@ +from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister +from qiskit.circuit import IfElseOp + +qubits = QuantumRegister(2) +clbits = ClassicalRegister(2) +circuit = QuantumCircuit(qubits, clbits) +(q0, q1) = qubits +(c0, c1) = clbits + +circuit.h(q0) +circuit.measure(q0, c0) + +with circuit.if_test((c0, 1)) as else_: + circuit.h(q1) +with else_: + circuit.x(q1) +circuit.measure(q1, c1) + +#print(circuit) + + +from pytket.extensions.qiskit import qiskit_to_tk +for datum in (circuit.data): + instr, qargs, cargs = datum.operation, datum.qubits, datum.clbits + if type(instr) is IfElseOp: + if_qc: QuantumCircuit = instr.params[0] + #print(if_qc.qregs) + #print(if_qc) + #tkc = qiskit_to_tk(if_qc) + #print(tkc.get_commands()) + +tkc = qiskit_to_tk(circuit) From 692506f50f2827cefd03358b9f2479edf14baf80 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:43:00 +0000 Subject: [PATCH 03/30] try adding data for conditional subcircuits --- pytket/extensions/qiskit/qiskit_convert.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 3c5d5f9c..0eb2535d 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -496,13 +496,13 @@ def _pytket_boxes_from_IfElseOp(instr: Instruction) -> tuple[CircBox, CircBox]: new_else_qc = QuantumCircuit(default_qreg_else, default_creg_else) if_builder = CircuitBuilder(new_if_qc.qregs, new_if_qc.cregs) - if_builder.add_qiskit_data(new_if_qc) + if_builder.add_qiskit_data(if_qc) if_circuit = if_builder.circuit() if_circuit.name = "If" else_builder = CircuitBuilder(new_else_qc.qregs, new_else_qc.cregs) - else_builder.add_qiskit_data(new_else_qc) + else_builder.add_qiskit_data(else_qc) else_circuit = else_builder.circuit() else_circuit.name = "Else" From 9be4d45abc164b4aa18906ca5f42f6087c2786b6 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:46:28 +0000 Subject: [PATCH 04/30] add a proper test --- if-else.py | 32 -------------------------------- tests/qiskit_convert_test.py | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 32 deletions(-) delete mode 100644 if-else.py diff --git a/if-else.py b/if-else.py deleted file mode 100644 index 037d6081..00000000 --- a/if-else.py +++ /dev/null @@ -1,32 +0,0 @@ -from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister -from qiskit.circuit import IfElseOp - -qubits = QuantumRegister(2) -clbits = ClassicalRegister(2) -circuit = QuantumCircuit(qubits, clbits) -(q0, q1) = qubits -(c0, c1) = clbits - -circuit.h(q0) -circuit.measure(q0, c0) - -with circuit.if_test((c0, 1)) as else_: - circuit.h(q1) -with else_: - circuit.x(q1) -circuit.measure(q1, c1) - -#print(circuit) - - -from pytket.extensions.qiskit import qiskit_to_tk -for datum in (circuit.data): - instr, qargs, cargs = datum.operation, datum.qubits, datum.clbits - if type(instr) is IfElseOp: - if_qc: QuantumCircuit = instr.params[0] - #print(if_qc.qregs) - #print(if_qc) - #tkc = qiskit_to_tk(if_qc) - #print(tkc.get_commands()) - -tkc = qiskit_to_tk(circuit) diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index c3ca48da..6e7c1e11 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1189,3 +1189,22 @@ def test_nonregister_bits() -> None: c.rename_units({Bit(0): Bit(1)}) with pytest.raises(NotImplementedError): tk_to_qiskit(c) + + +def test_ifelseop_handling() -> None: + qubits = QuantumRegister(2) + clbits = ClassicalRegister(2) + circuit = QuantumCircuit(qubits, clbits) + (q0, q1) = qubits + (c0, c1) = clbits + + circuit.h(q0) + circuit.measure(q0, c0) + + with circuit.if_test((c0, 1)) as else_: + circuit.h(q1) + with else_: + circuit.x(q1) + circuit.measure(q1, c1) + + tkc = qiskit_to_tk(circuit) From 80dddbee8b95eeddb025f25ae9e9926cc4cea832 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:47:24 +0000 Subject: [PATCH 05/30] cleanup --- pytket/extensions/qiskit/qiskit_convert.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 0eb2535d..ac93ab07 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -479,9 +479,6 @@ def _build_circbox(instr: Instruction, circuit: QuantumCircuit) -> CircBox: subc.name = instr.name return CircBox(subc) -from pytket.circuit.display import view_browser as draw - - # TODO refactor to reduce duplication def _pytket_boxes_from_IfElseOp(instr: Instruction) -> tuple[CircBox, CircBox]: if_qc: QuantumCircuit = instr.params[0] @@ -557,8 +554,8 @@ def add_qiskit_data( if instr.condition is not None: if type(instr) is IfElseOp: if_box, else_box = _pytket_boxes_from_IfElseOp(instr) - draw(if_box.get_circuit()) - draw(else_box.get_circuit()) + print(if_box.get_circuit().get_commands()) + print(else_box.get_circuit().get_commands()) condition_kwargs = _get_pytket_condition_kwargs( instruction=instr, From e38ca3e03776ffba57525454b9bd26ab14dfd091 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:48:03 +0000 Subject: [PATCH 06/30] add another TODO --- pytket/extensions/qiskit/qiskit_convert.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index ac93ab07..17e74dca 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -484,6 +484,7 @@ def _pytket_boxes_from_IfElseOp(instr: Instruction) -> tuple[CircBox, CircBox]: if_qc: QuantumCircuit = instr.params[0] else_qc: QuantumCircuit = instr.params[1] + # TODO handle non-simple register case? default_qreg_if = QuantumRegister(if_qc.num_qubits, "q") default_creg_if = ClassicalRegister(if_qc.num_clbits, "c") default_qreg_else = QuantumRegister(else_qc.num_qubits, "q") From 3843234e87e0c890e9bc3ee8f3b716f120248583 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:58:57 +0000 Subject: [PATCH 07/30] formatting --- pytket/extensions/qiskit/qiskit_convert.py | 12 +++++------- tests/qiskit_convert_test.py | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 17e74dca..a910d5b5 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -479,16 +479,17 @@ def _build_circbox(instr: Instruction, circuit: QuantumCircuit) -> CircBox: subc.name = instr.name return CircBox(subc) + # TODO refactor to reduce duplication def _pytket_boxes_from_IfElseOp(instr: Instruction) -> tuple[CircBox, CircBox]: if_qc: QuantumCircuit = instr.params[0] else_qc: QuantumCircuit = instr.params[1] # TODO handle non-simple register case? - default_qreg_if = QuantumRegister(if_qc.num_qubits, "q") - default_creg_if = ClassicalRegister(if_qc.num_clbits, "c") - default_qreg_else = QuantumRegister(else_qc.num_qubits, "q") - default_creg_else = ClassicalRegister(else_qc.num_clbits, "c") + default_qreg_if = QuantumRegister(if_qc.num_qubits, "q") + default_creg_if = ClassicalRegister(if_qc.num_clbits, "c") + default_qreg_else = QuantumRegister(else_qc.num_qubits, "q") + default_creg_else = ClassicalRegister(else_qc.num_clbits, "c") new_if_qc = QuantumCircuit(default_qreg_if, default_creg_if) new_else_qc = QuantumCircuit(default_qreg_else, default_creg_else) @@ -498,7 +499,6 @@ def _pytket_boxes_from_IfElseOp(instr: Instruction) -> tuple[CircBox, CircBox]: if_circuit = if_builder.circuit() if_circuit.name = "If" - else_builder = CircuitBuilder(new_else_qc.qregs, new_else_qc.cregs) else_builder.add_qiskit_data(else_qc) else_circuit = else_builder.circuit() @@ -507,8 +507,6 @@ def _pytket_boxes_from_IfElseOp(instr: Instruction) -> tuple[CircBox, CircBox]: return CircBox(if_circuit), CircBox(else_circuit) - - class CircuitBuilder: def __init__( self, diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index 6e7c1e11..9155042a 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1197,7 +1197,7 @@ def test_ifelseop_handling() -> None: circuit = QuantumCircuit(qubits, clbits) (q0, q1) = qubits (c0, c1) = clbits - + circuit.h(q0) circuit.measure(q0, c0) From 09a0ca22bd0f1c1396c37d6c2e9a001e015ba905 Mon Sep 17 00:00:00 2001 From: Melf Date: Tue, 17 Dec 2024 16:30:32 +0000 Subject: [PATCH 08/30] try if else with register from qiskit circuit --- pytket/extensions/qiskit/qiskit_convert.py | 23 +++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index a910d5b5..a1f028cf 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -481,25 +481,24 @@ def _build_circbox(instr: Instruction, circuit: QuantumCircuit) -> CircBox: # TODO refactor to reduce duplication -def _pytket_boxes_from_IfElseOp(instr: Instruction) -> tuple[CircBox, CircBox]: +def _pytket_boxes_from_IfElseOp( + qregs: list[QuantumRegister], cregs: list[ClassicalRegister], instr: Instruction +) -> tuple[CircBox, CircBox]: if_qc: QuantumCircuit = instr.params[0] else_qc: QuantumCircuit = instr.params[1] # TODO handle non-simple register case? - default_qreg_if = QuantumRegister(if_qc.num_qubits, "q") - default_creg_if = ClassicalRegister(if_qc.num_clbits, "c") - default_qreg_else = QuantumRegister(else_qc.num_qubits, "q") - default_creg_else = ClassicalRegister(else_qc.num_clbits, "c") + # default_qreg_if = QuantumRegister(if_qc.num_qubits, "q") + # default_creg_if = ClassicalRegister(if_qc.num_clbits, "c") + # default_qreg_else = QuantumRegister(else_qc.num_qubits, "q") + # default_creg_else = ClassicalRegister(else_qc.num_clbits, "c") - new_if_qc = QuantumCircuit(default_qreg_if, default_creg_if) - new_else_qc = QuantumCircuit(default_qreg_else, default_creg_else) - - if_builder = CircuitBuilder(new_if_qc.qregs, new_if_qc.cregs) + if_builder = CircuitBuilder(qregs, cregs) if_builder.add_qiskit_data(if_qc) if_circuit = if_builder.circuit() if_circuit.name = "If" - else_builder = CircuitBuilder(new_else_qc.qregs, new_else_qc.cregs) + else_builder = CircuitBuilder(qregs, cregs) else_builder.add_qiskit_data(else_qc) else_circuit = else_builder.circuit() else_circuit.name = "Else" @@ -552,7 +551,9 @@ def add_qiskit_data( condition_kwargs = {} if instr.condition is not None: if type(instr) is IfElseOp: - if_box, else_box = _pytket_boxes_from_IfElseOp(instr) + if_box, else_box = _pytket_boxes_from_IfElseOp( + self.qregs, self.cregs, instr + ) print(if_box.get_circuit().get_commands()) print(else_box.get_circuit().get_commands()) From 96d9efd9b9866eb1a2b9f79d18502302df489655 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 17 Dec 2024 23:05:19 +0000 Subject: [PATCH 09/30] minor cleanup --- pytket/extensions/qiskit/qiskit_convert.py | 6 ------ tests/qiskit_convert_test.py | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 5cb241f9..42a3c0b7 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -487,12 +487,6 @@ def _pytket_boxes_from_IfElseOp( if_qc: QuantumCircuit = instr.params[0] else_qc: QuantumCircuit = instr.params[1] - # TODO handle non-simple register case? - # default_qreg_if = QuantumRegister(if_qc.num_qubits, "q") - # default_creg_if = ClassicalRegister(if_qc.num_clbits, "c") - # default_qreg_else = QuantumRegister(else_qc.num_qubits, "q") - # default_creg_else = ClassicalRegister(else_qc.num_clbits, "c") - if_builder = CircuitBuilder(qregs, cregs) if_builder.add_qiskit_data(if_qc) if_circuit = if_builder.circuit() diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index a8b1a32a..ca924f09 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1192,6 +1192,7 @@ def test_nonregister_bits() -> None: with pytest.raises(NotImplementedError): tk_to_qiskit(c) + def test_ifelseop_handling() -> None: qubits = QuantumRegister(2) clbits = ClassicalRegister(2) From 65186287c4a50f4971c56174a5d5d400e3f61da7 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Wed, 18 Dec 2024 00:02:03 +0000 Subject: [PATCH 10/30] more progress on circuit building (still gives RuntimeError) --- pytket/extensions/qiskit/qiskit_convert.py | 44 ++++++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 42a3c0b7..16188c3f 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -480,12 +480,11 @@ def _build_circbox(instr: Instruction, circuit: QuantumCircuit) -> CircBox: return CircBox(subc) -# TODO refactor to reduce duplication def _pytket_boxes_from_IfElseOp( - qregs: list[QuantumRegister], cregs: list[ClassicalRegister], instr: Instruction + if_else_op: IfElseOp, qregs: list[QuantumRegister], cregs: list[ClassicalRegister] ) -> tuple[CircBox, CircBox]: - if_qc: QuantumCircuit = instr.params[0] - else_qc: QuantumCircuit = instr.params[1] + if_qc: QuantumCircuit = if_else_op.params[0] + else_qc: QuantumCircuit = if_else_op.params[1] if_builder = CircuitBuilder(qregs, cregs) if_builder.add_qiskit_data(if_qc) @@ -500,6 +499,32 @@ def _pytket_boxes_from_IfElseOp( return CircBox(if_circuit), CircBox(else_circuit) +def build_if_else_circuit( + if_else_op: IfElseOp, + qregs: list[QuantumRegister], + cregs: list[ClassicalRegister], + qubits: list[Qubit], + bits: list[Bit], +) -> Circuit: + if_box, else_box = _pytket_boxes_from_IfElseOp(if_else_op, qregs, cregs) + circ_builder = CircuitBuilder(qregs, cregs) + circ = circ_builder.circuit() + circ.add_circbox( + if_box, + qubits, + bits, + if_else_op.condition[1], + ) + circ.add_circbox( + else_box, + qubits, + bits, + # TODO negate condition properly + 1 - if_else_op.condition[1], + ) + return circ + + class CircuitBuilder: def __init__( self, @@ -545,11 +570,14 @@ def add_qiskit_data( condition_kwargs = {} if instr.condition is not None: if type(instr) is IfElseOp: - if_box, else_box = _pytket_boxes_from_IfElseOp( - self.qregs, self.cregs, instr + if_else_circ = build_if_else_circuit( + if_else_op=instr, + qregs=self.qregs, + cregs=self.cregs, + qubits=qubits, + bits=bits, ) - print(if_box.get_circuit().get_commands()) - print(else_box.get_circuit().get_commands()) + self.tkc.append(if_else_circ) condition_kwargs = _get_pytket_condition_kwargs( instruction=instr, From f87d814a2a5a78fcbbe88ef08a5cc8dfb18c9be1 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Wed, 18 Dec 2024 00:32:19 +0000 Subject: [PATCH 11/30] try to fix kwargs --- pytket/extensions/qiskit/qiskit_convert.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 16188c3f..64bf42c1 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -76,13 +76,13 @@ Clbit, ControlledGate, Gate, + IfElseOp, Instruction, InstructionSet, Measure, Parameter, ParameterExpression, Reset, - IfElseOp, ) from qiskit.circuit.library import ( CRYGate, @@ -510,17 +510,17 @@ def build_if_else_circuit( circ_builder = CircuitBuilder(qregs, cregs) circ = circ_builder.circuit() circ.add_circbox( - if_box, - qubits, - bits, - if_else_op.condition[1], + circbox=if_box, + args=qubits, + condition_bits=bits, + condition_value=if_else_op.condition[1], ) circ.add_circbox( - else_box, - qubits, - bits, + circbox=else_box, + args=qubits, + condition_bits=bits, # TODO negate condition properly - 1 - if_else_op.condition[1], + condition_value=0, ) return circ From 816e2bdc86c79efe6ee2dadbea6501c17b9714d3 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Wed, 18 Dec 2024 00:57:01 +0000 Subject: [PATCH 12/30] update test --- tests/qiskit_convert_test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index ca924f09..303d6047 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1193,6 +1193,9 @@ def test_nonregister_bits() -> None: tk_to_qiskit(c) +from pytket.circuit.display import view_browser as draw + + def test_ifelseop_handling() -> None: qubits = QuantumRegister(2) clbits = ClassicalRegister(2) @@ -1210,6 +1213,7 @@ def test_ifelseop_handling() -> None: circuit.measure(q1, c1) tkc = qiskit_to_tk(circuit) + assert tkc.n_gates_of_type(OpType.Conditional) == 2 def test_range_preds_with_conditionals(): From 2ff1b6f694449a8f23c34a14e29a4dd9c5fb5e9d Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Wed, 18 Dec 2024 00:58:37 +0000 Subject: [PATCH 13/30] remove import --- tests/qiskit_convert_test.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index 303d6047..47525019 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1193,9 +1193,6 @@ def test_nonregister_bits() -> None: tk_to_qiskit(c) -from pytket.circuit.display import view_browser as draw - - def test_ifelseop_handling() -> None: qubits = QuantumRegister(2) clbits = ClassicalRegister(2) From ea62c0b20ef20557b501789e4595a6df3d68cecd Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:36:56 +0000 Subject: [PATCH 14/30] push latest attempt --- pytket/extensions/qiskit/qiskit_convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 64bf42c1..55df9d7e 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -511,7 +511,7 @@ def build_if_else_circuit( circ = circ_builder.circuit() circ.add_circbox( circbox=if_box, - args=qubits, + args=qubits + bits, condition_bits=bits, condition_value=if_else_op.condition[1], ) From 73dc681ec4a1fb9266066d3d397b3f53977b6d43 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 31 Dec 2024 10:41:40 +0000 Subject: [PATCH 15/30] naming fixes --- pytket/extensions/qiskit/qiskit_convert.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 55df9d7e..0889d3d8 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -480,11 +480,11 @@ def _build_circbox(instr: Instruction, circuit: QuantumCircuit) -> CircBox: return CircBox(subc) -def _pytket_boxes_from_IfElseOp( +def _pytket_boxes_from_ifelseop( if_else_op: IfElseOp, qregs: list[QuantumRegister], cregs: list[ClassicalRegister] ) -> tuple[CircBox, CircBox]: - if_qc: QuantumCircuit = if_else_op.params[0] - else_qc: QuantumCircuit = if_else_op.params[1] + if_qc: QuantumCircuit = if_else_op.blocks[0] + else_qc: QuantumCircuit = if_else_op.blocks[1] if_builder = CircuitBuilder(qregs, cregs) if_builder.add_qiskit_data(if_qc) @@ -506,7 +506,7 @@ def build_if_else_circuit( qubits: list[Qubit], bits: list[Bit], ) -> Circuit: - if_box, else_box = _pytket_boxes_from_IfElseOp(if_else_op, qregs, cregs) + if_box, else_box = _pytket_boxes_from_ifelseop(if_else_op, qregs, cregs) circ_builder = CircuitBuilder(qregs, cregs) circ = circ_builder.circuit() circ.add_circbox( From d65a347292a0238499dde5a10abb6442543ec745 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 31 Dec 2024 11:27:53 +0000 Subject: [PATCH 16/30] a little more progress --- pytket/extensions/qiskit/qiskit_convert.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 0889d3d8..a8446522 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -490,11 +490,13 @@ def _pytket_boxes_from_ifelseop( if_builder.add_qiskit_data(if_qc) if_circuit = if_builder.circuit() if_circuit.name = "If" + if_circuit.remove_blank_wires() else_builder = CircuitBuilder(qregs, cregs) else_builder.add_qiskit_data(else_qc) else_circuit = else_builder.circuit() else_circuit.name = "Else" + else_circuit.remove_blank_wires() return CircBox(if_circuit), CircBox(else_circuit) @@ -509,9 +511,10 @@ def build_if_else_circuit( if_box, else_box = _pytket_boxes_from_ifelseop(if_else_op, qregs, cregs) circ_builder = CircuitBuilder(qregs, cregs) circ = circ_builder.circuit() + circ.add_circbox( circbox=if_box, - args=qubits + bits, + args=qubits, condition_bits=bits, condition_value=if_else_op.condition[1], ) @@ -586,7 +589,7 @@ def add_qiskit_data( ) optype = None - if type(instr) not in (PauliEvolutionGate, UnitaryGate): + if type(instr) not in (PauliEvolutionGate, UnitaryGate, IfElseOp): # Handling of PauliEvolutionGate and UnitaryGate below optype = _optype_from_qiskit_instruction(instruction=instr) From 52458ab1ed7e9c43392347cb563d24cddf56050c Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 31 Dec 2024 11:46:25 +0000 Subject: [PATCH 17/30] refactor: handle IfElseOp separately --- pytket/extensions/qiskit/qiskit_convert.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 0ae7d590..ad257bd6 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -571,17 +571,7 @@ def add_qiskit_data( bits: list[Bit] = [self.cbmap[bit] for bit in cargs] condition_kwargs = {} - if instr.condition is not None: - if type(instr) is IfElseOp: - if_else_circ = build_if_else_circuit( - if_else_op=instr, - qregs=self.qregs, - cregs=self.cregs, - qubits=qubits, - bits=bits, - ) - self.tkc.append(if_else_circ) - + if instr.condition is not None and type(instr) is not IfElseOp: condition_kwargs = _get_pytket_condition_kwargs( instruction=instr, cregmap=self.cregmap, @@ -602,6 +592,16 @@ def add_qiskit_data( # Append OpType found by stateprep helpers _add_state_preparation(self.tkc, qubits, instr) + elif type(instr) is IfElseOp: + if_else_circ = build_if_else_circuit( + if_else_op=instr, + qregs=self.qregs, + cregs=self.cregs, + qubits=qubits, + bits=bits, + ) + self.tkc.append(if_else_circ) + elif type(instr) is PauliEvolutionGate: qpo = _qpo_from_peg(instr, qubits) empty_circ = Circuit(len(qargs)) From 8e1edce8c1067e69369f1cf99bab8d72bb3eeb38 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Tue, 31 Dec 2024 12:32:09 +0000 Subject: [PATCH 18/30] make circuit builder function private --- pytket/extensions/qiskit/qiskit_convert.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index ad257bd6..9e4cb3e0 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -501,7 +501,7 @@ def _pytket_boxes_from_ifelseop( return CircBox(if_circuit), CircBox(else_circuit) -def build_if_else_circuit( +def _build_if_else_circuit( if_else_op: IfElseOp, qregs: list[QuantumRegister], cregs: list[ClassicalRegister], @@ -580,7 +580,7 @@ def add_qiskit_data( optype = None if type(instr) not in (PauliEvolutionGate, UnitaryGate, IfElseOp): - # Handling of PauliEvolutionGate and UnitaryGate below + # Handling of PauliEvolutionGate UnitaryGate and IfElseOp below optype = _optype_from_qiskit_instruction(instruction=instr) if optype == OpType.QControlBox: @@ -593,7 +593,7 @@ def add_qiskit_data( _add_state_preparation(self.tkc, qubits, instr) elif type(instr) is IfElseOp: - if_else_circ = build_if_else_circuit( + if_else_circ = _build_if_else_circuit( if_else_op=instr, qregs=self.qregs, cregs=self.cregs, From 4b382b0ff3af9cb5cd5e9604e33ae33f8749e62b Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Thu, 2 Jan 2025 13:13:40 +0000 Subject: [PATCH 19/30] add a test case for a single branch --- tests/qiskit_convert_test.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index 9c54f8a8..dd4bf602 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1193,7 +1193,7 @@ def test_nonregister_bits() -> None: tk_to_qiskit(c) -def test_ifelseop_handling() -> None: +def test_ifelseop_two_branches() -> None: qubits = QuantumRegister(2) clbits = ClassicalRegister(2) circuit = QuantumCircuit(qubits, clbits) @@ -1213,6 +1213,26 @@ def test_ifelseop_handling() -> None: assert tkc.n_gates_of_type(OpType.Conditional) == 2 +from pytket.circuit.display import view_browser as draw + + +def test_ifelseop_one_branch() -> None: + qubits = QuantumRegister(1) + clbits = ClassicalRegister(1) + circuit = QuantumCircuit(qubits, clbits) + (q0,) = qubits + (c0,) = clbits + + circuit.h(q0) + circuit.measure(q0, c0) + with circuit.if_test((c0, 1)): + circuit.x(q0) + circuit.measure(q0, c0) + + tket_circ = qiskit_to_tk(circuit) + draw(tket_circ) + + def test_range_preds_with_conditionals() -> None: # https://github.com/CQCL/pytket-qiskit/issues/375 c = Circuit(1, 1) From 4729114671abfb22fe7a8c5388eebf8776147eb7 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Thu, 2 Jan 2025 13:14:10 +0000 Subject: [PATCH 20/30] handle the single branch case --- pytket/extensions/qiskit/qiskit_convert.py | 33 ++++++++++++---------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 9e4cb3e0..7c6933f6 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -482,9 +482,8 @@ def _build_circbox(instr: Instruction, circuit: QuantumCircuit) -> CircBox: def _pytket_boxes_from_ifelseop( if_else_op: IfElseOp, qregs: list[QuantumRegister], cregs: list[ClassicalRegister] -) -> tuple[CircBox, CircBox]: +) -> tuple[CircBox, Optional[CircBox]]: if_qc: QuantumCircuit = if_else_op.blocks[0] - else_qc: QuantumCircuit = if_else_op.blocks[1] if_builder = CircuitBuilder(qregs, cregs) if_builder.add_qiskit_data(if_qc) @@ -492,13 +491,16 @@ def _pytket_boxes_from_ifelseop( if_circuit.name = "If" if_circuit.remove_blank_wires() - else_builder = CircuitBuilder(qregs, cregs) - else_builder.add_qiskit_data(else_qc) - else_circuit = else_builder.circuit() - else_circuit.name = "Else" - else_circuit.remove_blank_wires() + if len(if_else_op.blocks) == 2: + else_qc: QuantumCircuit = if_else_op.blocks[1] + else_builder = CircuitBuilder(qregs, cregs) + else_builder.add_qiskit_data(else_qc) + else_circuit = else_builder.circuit() + else_circuit.name = "Else" + else_circuit.remove_blank_wires() + return CircBox(if_circuit), CircBox(else_circuit) - return CircBox(if_circuit), CircBox(else_circuit) + return CircBox(if_circuit), None def _build_if_else_circuit( @@ -518,13 +520,14 @@ def _build_if_else_circuit( condition_bits=bits, condition_value=if_else_op.condition[1], ) - circ.add_circbox( - circbox=else_box, - args=qubits, - condition_bits=bits, - # TODO negate condition properly - condition_value=0, - ) + if else_box is not None: + circ.add_circbox( + circbox=else_box, + args=qubits, + condition_bits=bits, + # TODO negate condition properly + condition_value=0, + ) return circ From f69aa0424e2336267d00aafb0ce1110e9c88c39d Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Thu, 2 Jan 2025 13:33:53 +0000 Subject: [PATCH 21/30] improve validation for single branch case --- tests/qiskit_convert_test.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index dd4bf602..42e5a7cb 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1230,7 +1230,25 @@ def test_ifelseop_one_branch() -> None: circuit.measure(q0, c0) tket_circ = qiskit_to_tk(circuit) - draw(tket_circ) + tket_circ.name = "test_circ" + + expected_circ = Circuit() + expected_circ.name = "test_circ" + q1 = expected_circ.add_q_register("q1", 1) + c0_tk = expected_circ.add_c_register("c0", 1) + expected_circ.H(q1[0]) + expected_circ.Measure(q1[0], c0_tk[0]) + x_circ = Circuit() + x_circ.name = "If" + xq1 = x_circ.add_q_register("q1", 1) + x_circ.X(xq1[0]) + expected_circ.add_circbox( + CircBox(x_circ), [q1[0]], condition_bits=[c0_tk[0]], condition_value=1 + ) + + expected_circ.Measure(q1[0], c0_tk[0]) + + assert tket_circ == expected_circ def test_range_preds_with_conditionals() -> None: From 8573082c58f04bb83c9957d4342a64293a7ce590 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Thu, 2 Jan 2025 13:42:31 +0000 Subject: [PATCH 22/30] fix import --- tests/qiskit_convert_test.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index 42e5a7cb..70263295 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1213,9 +1213,6 @@ def test_ifelseop_two_branches() -> None: assert tkc.n_gates_of_type(OpType.Conditional) == 2 -from pytket.circuit.display import view_browser as draw - - def test_ifelseop_one_branch() -> None: qubits = QuantumRegister(1) clbits = ClassicalRegister(1) From 4d311f399a85e67b63119aeba134104261743368 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Thu, 2 Jan 2025 14:00:48 +0000 Subject: [PATCH 23/30] add some comments --- pytket/extensions/qiskit/qiskit_convert.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 7c6933f6..8d452c4f 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -480,17 +480,23 @@ def _build_circbox(instr: Instruction, circuit: QuantumCircuit) -> CircBox: return CircBox(subc) +# Used for handling of IfElseOp +# docs -> https://docs.quantum.ibm.com/api/qiskit/qiskit.circuit.IfElseOp +# Examples -> https://docs.quantum.ibm.com/guides/classical-feedforward-and-control-flow def _pytket_boxes_from_ifelseop( if_else_op: IfElseOp, qregs: list[QuantumRegister], cregs: list[ClassicalRegister] ) -> tuple[CircBox, Optional[CircBox]]: + # Extract the QuantumCircuit implementing true_body if_qc: QuantumCircuit = if_else_op.blocks[0] if_builder = CircuitBuilder(qregs, cregs) if_builder.add_qiskit_data(if_qc) if_circuit = if_builder.circuit() if_circuit.name = "If" + # Remove blank wires to ensure CircBox is the correct size. if_circuit.remove_blank_wires() + # The false_body arg is optional if len(if_else_op.blocks) == 2: else_qc: QuantumCircuit = if_else_op.blocks[1] else_builder = CircuitBuilder(qregs, cregs) @@ -500,6 +506,8 @@ def _pytket_boxes_from_ifelseop( else_circuit.remove_blank_wires() return CircBox(if_circuit), CircBox(else_circuit) + # If no false_body is specified IfElseOp.blocks is of length 1. + # In this case we return a CircBox implementing true_body and None. return CircBox(if_circuit), None @@ -510,7 +518,10 @@ def _build_if_else_circuit( qubits: list[Qubit], bits: list[Bit], ) -> Circuit: + # Get two CircBox objects which implement the true_body and false_body. if_box, else_box = _pytket_boxes_from_ifelseop(if_else_op, qregs, cregs) + # else_box can be None if no false_body is specified. + circ_builder = CircuitBuilder(qregs, cregs) circ = circ_builder.circuit() @@ -520,13 +531,14 @@ def _build_if_else_circuit( condition_bits=bits, condition_value=if_else_op.condition[1], ) + # If we have an else_box defined, add it to the circuit if else_box is not None: circ.add_circbox( circbox=else_box, args=qubits, condition_bits=bits, - # TODO negate condition properly - condition_value=0, + # TODO: handle conditions over multiple bits/registers? + condition_value=not bool(if_else_op.condition[1]), ) return circ From eec8fe5dac2a1389d68b9738748965b78228e5a9 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:20:34 +0000 Subject: [PATCH 24/30] add comments to test, change variable name --- tests/qiskit_convert_test.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index 70263295..88d6b8ee 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1226,9 +1226,11 @@ def test_ifelseop_one_branch() -> None: circuit.x(q0) circuit.measure(q0, c0) - tket_circ = qiskit_to_tk(circuit) - tket_circ.name = "test_circ" + tket_circ_if_else = qiskit_to_tk(circuit) + tket_circ_if_else.name = "test_circ" + # Manually build the expected pytket Circuit. + # Validate against tket_circ. expected_circ = Circuit() expected_circ.name = "test_circ" q1 = expected_circ.add_q_register("q1", 1) @@ -1245,7 +1247,7 @@ def test_ifelseop_one_branch() -> None: expected_circ.Measure(q1[0], c0_tk[0]) - assert tket_circ == expected_circ + assert tket_circ_if_else == expected_circ def test_range_preds_with_conditionals() -> None: From 9d66595d66ed89f3d5c015525ca23f1e42f579de Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:32:30 +0000 Subject: [PATCH 25/30] attempt to debug C.I. test case issue --- tests/qiskit_convert_test.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index 88d6b8ee..cf796679 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1214,8 +1214,8 @@ def test_ifelseop_two_branches() -> None: def test_ifelseop_one_branch() -> None: - qubits = QuantumRegister(1) - clbits = ClassicalRegister(1) + qubits = QuantumRegister(1, "q1") + clbits = ClassicalRegister(1, "c1") circuit = QuantumCircuit(qubits, clbits) (q0,) = qubits (c0,) = clbits @@ -1225,16 +1225,17 @@ def test_ifelseop_one_branch() -> None: with circuit.if_test((c0, 1)): circuit.x(q0) circuit.measure(q0, c0) - + print(circuit) tket_circ_if_else = qiskit_to_tk(circuit) tket_circ_if_else.name = "test_circ" + print(tket_circ_if_else.get_commands()) # Manually build the expected pytket Circuit. # Validate against tket_circ. expected_circ = Circuit() expected_circ.name = "test_circ" q1 = expected_circ.add_q_register("q1", 1) - c0_tk = expected_circ.add_c_register("c0", 1) + c0_tk = expected_circ.add_c_register("c1", 1) expected_circ.H(q1[0]) expected_circ.Measure(q1[0], c0_tk[0]) x_circ = Circuit() From 4b4b40a94ef0864267813a0173dc75ed50bcdbd6 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:41:45 +0000 Subject: [PATCH 26/30] remove debug prints --- tests/qiskit_convert_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index cf796679..c126d10b 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1225,10 +1225,9 @@ def test_ifelseop_one_branch() -> None: with circuit.if_test((c0, 1)): circuit.x(q0) circuit.measure(q0, c0) - print(circuit) + tket_circ_if_else = qiskit_to_tk(circuit) tket_circ_if_else.name = "test_circ" - print(tket_circ_if_else.get_commands()) # Manually build the expected pytket Circuit. # Validate against tket_circ. From 7950e77dc6e2df8b09d31bf97f3cd6c0b35707f2 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:59:11 +0000 Subject: [PATCH 27/30] correct some comments --- pytket/extensions/qiskit/qiskit_convert.py | 2 +- tests/qiskit_convert_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index 8d452c4f..e98643e1 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -595,7 +595,7 @@ def add_qiskit_data( optype = None if type(instr) not in (PauliEvolutionGate, UnitaryGate, IfElseOp): - # Handling of PauliEvolutionGate UnitaryGate and IfElseOp below + # Handling of PauliEvolutionGate, UnitaryGate and IfElseOp below optype = _optype_from_qiskit_instruction(instruction=instr) if optype == OpType.QControlBox: diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index c126d10b..ddd98ca5 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1230,7 +1230,7 @@ def test_ifelseop_one_branch() -> None: tket_circ_if_else.name = "test_circ" # Manually build the expected pytket Circuit. - # Validate against tket_circ. + # Validate against tket_circ_if_else. expected_circ = Circuit() expected_circ.name = "test_circ" q1 = expected_circ.add_q_register("q1", 1) From 25bfcd5e1629caecd7a8d674d1dac30fc5964203 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Thu, 2 Jan 2025 17:36:04 +0000 Subject: [PATCH 28/30] update changelog --- docs/changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 8e56bfa6..51b758fc 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,6 +4,10 @@ # Changelog +## 0.63.0 (January 2025) - UNRELEASED + +- Support conversion of qiskit circuits containing `IfElseOp` in the {py:func}`qiskit_to_tk` converter. + ## 0.62.0 (December 2024) - AerBackend now rejects circuits with too many qubits From ae6cbfed507614c332525dc4294509cc6e6cd7e7 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Thu, 2 Jan 2025 18:03:44 +0000 Subject: [PATCH 29/30] Better varible names for testing --- tests/qiskit_convert_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index ddd98ca5..24e04196 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1233,19 +1233,19 @@ def test_ifelseop_one_branch() -> None: # Validate against tket_circ_if_else. expected_circ = Circuit() expected_circ.name = "test_circ" - q1 = expected_circ.add_q_register("q1", 1) - c0_tk = expected_circ.add_c_register("c1", 1) - expected_circ.H(q1[0]) - expected_circ.Measure(q1[0], c0_tk[0]) + q1_tk = expected_circ.add_q_register("q1", 1) + c1_tk = expected_circ.add_c_register("c1", 1) + expected_circ.H(q1_tk[0]) + expected_circ.Measure(q1_tk[0], c1_tk[0]) x_circ = Circuit() x_circ.name = "If" xq1 = x_circ.add_q_register("q1", 1) x_circ.X(xq1[0]) expected_circ.add_circbox( - CircBox(x_circ), [q1[0]], condition_bits=[c0_tk[0]], condition_value=1 + CircBox(x_circ), [q1_tk[0]], condition_bits=[c1_tk[0]], condition_value=1 ) - expected_circ.Measure(q1[0], c0_tk[0]) + expected_circ.Measure(q1_tk[0], c1_tk[0]) assert tket_circ_if_else == expected_circ From e479c3e5b49925999171f507bdff58177aa83e95 Mon Sep 17 00:00:00 2001 From: CalMacCQ <93673602+CalMacCQ@users.noreply.github.com> Date: Thu, 2 Jan 2025 18:05:04 +0000 Subject: [PATCH 30/30] link to issue --- pytket/extensions/qiskit/qiskit_convert.py | 1 + tests/qiskit_convert_test.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/pytket/extensions/qiskit/qiskit_convert.py b/pytket/extensions/qiskit/qiskit_convert.py index e98643e1..fc3bed74 100644 --- a/pytket/extensions/qiskit/qiskit_convert.py +++ b/pytket/extensions/qiskit/qiskit_convert.py @@ -483,6 +483,7 @@ def _build_circbox(instr: Instruction, circuit: QuantumCircuit) -> CircBox: # Used for handling of IfElseOp # docs -> https://docs.quantum.ibm.com/api/qiskit/qiskit.circuit.IfElseOp # Examples -> https://docs.quantum.ibm.com/guides/classical-feedforward-and-control-flow +# pytket-qiskit issue -> https://github.com/CQCL/pytket-qiskit/issues/415 def _pytket_boxes_from_ifelseop( if_else_op: IfElseOp, qregs: list[QuantumRegister], cregs: list[ClassicalRegister] ) -> tuple[CircBox, Optional[CircBox]]: diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index 24e04196..d6bb7b52 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -1193,6 +1193,7 @@ def test_nonregister_bits() -> None: tk_to_qiskit(c) +# https://github.com/CQCL/pytket-qiskit/issues/415 def test_ifelseop_two_branches() -> None: qubits = QuantumRegister(2) clbits = ClassicalRegister(2) @@ -1213,6 +1214,7 @@ def test_ifelseop_two_branches() -> None: assert tkc.n_gates_of_type(OpType.Conditional) == 2 +# https://github.com/CQCL/pytket-qiskit/issues/415 def test_ifelseop_one_branch() -> None: qubits = QuantumRegister(1, "q1") clbits = ClassicalRegister(1, "c1")