Skip to content

Commit

Permalink
Fix RuntimeError when converting qiskit instructions. (#203)
Browse files Browse the repository at this point in the history
* Don't use CustomGateDef in qiskit_to_tk

* add test for RealAmplitudes handling

* remove lines for debugging

* remove a single line

* fix assert for circuit naming

* remove some unused imports

* Add test of unitary equivalence

* add ipynb to .gitignore

* add isinstance check to keep mypy happy

* add a check for equivalence with the qiskit operator

* add comment with issue link

* remove spaces
  • Loading branch information
CalMacCQ authored Nov 15, 2023
1 parent e2981d8 commit fc18d49
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 16 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ obj
docs/extensions
.ipynb_checkpoints
pytket/extensions/qiskit/_metadata.py
*.ipynb
19 changes: 6 additions & 13 deletions pytket/extensions/qiskit/qiskit_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@
# Special types:
Barrier: OpType.Barrier,
Instruction: OpType.CircBox,
Gate: OpType.CustomGate,
Gate: OpType.CircBox,
Measure: OpType.Measure,
Reset: OpType.Reset,
Initialize: OpType.StatePreparationBox,
Expand Down Expand Up @@ -476,7 +476,7 @@ def add_qiskit_data(self, data: "QuantumCircuitData") -> None:

elif optype == OpType.Barrier:
self.tkc.add_barrier(qubits)
elif optype in (OpType.CircBox, OpType.CustomGate):
elif optype == OpType.CircBox:
qregs = (
[QuantumRegister(instr.num_qubits, "q")]
if instr.num_qubits > 0
Expand All @@ -490,17 +490,9 @@ def add_qiskit_data(self, data: "QuantumCircuitData") -> None:
builder = CircuitBuilder(qregs, cregs)
builder.add_qiskit_data(instr.definition)
subc = builder.circuit()
if optype == OpType.CircBox:
cbox = CircBox(subc)
self.tkc.add_circbox(cbox, qubits + bits, **condition_kwargs) # type: ignore
else:
# warning, this will catch all `Gate` instances
# that were not picked up as a subclass in _known_qiskit_gate
params = [param_to_tk(p) for p in instr.params]
gate_def = CustomGateDef.define(
instr.name, subc, list(subc.free_symbols())
)
self.tkc.add_custom_gate(gate_def, params, qubits + bits) # type: ignore
subc.name = instr.name
self.tkc.add_circbox(CircBox(subc), qubits + bits, **condition_kwargs) # type: ignore

elif optype == OpType.CU3 and type(instr) == qiskit_gates.CUGate:
if instr.params[-1] == 0:
self.tkc.add_gate(
Expand Down Expand Up @@ -744,6 +736,7 @@ def append_tk_command_to_qiskit(
_supported_tket_gates
| _additional_multi_controlled_gates
| {OpType.Unitary1qBox, OpType.Unitary2qBox, OpType.Unitary3qBox}
| {OpType.CustomGate}
)


Expand Down
33 changes: 30 additions & 3 deletions tests/qiskit_convert_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
ClassicalRegister,
execute,
)
from qiskit.quantum_info import Pauli, SparsePauliOp # type: ignore
from qiskit.quantum_info import SparsePauliOp # type: ignore
from qiskit.transpiler import PassManager # type: ignore
from qiskit.circuit.library import RYGate, MCMT, XXPlusYYGate, PauliEvolutionGate, UnitaryGate # type: ignore
from qiskit.circuit.library import RYGate, MCMT, XXPlusYYGate, PauliEvolutionGate, UnitaryGate, RealAmplitudes # type: ignore
import qiskit.circuit.library.standard_gates as qiskit_gates # type: ignore
from qiskit.circuit import Parameter
from qiskit.synthesis import SuzukiTrotter # type: ignore
from qiskit_aer import Aer # type: ignore
from qiskit.quantum_info import Statevector
from qiskit.quantum_info import Statevector, Operator

from pytket.circuit import (
Circuit,
Expand Down Expand Up @@ -1013,3 +1013,30 @@ def test_failed_conversion_error() -> None:
NotImplementedError, match=r"Conversion of qiskit's xx_plus_yy instruction"
):
qiskit_to_tk(qc)


# https://github.com/CQCL/pytket-qiskit/issues/200
def test_RealAmplitudes_numeric_params() -> None:
qc = QuantumCircuit(3)
params = [np.pi / 2] * 9
real_amps1 = RealAmplitudes(3, reps=2)
real_amps2 = real_amps1.assign_parameters(params)
qc.compose(real_amps2, qubits=[0, 1, 2], inplace=True)
# Unitary operator of the qiskit circuit. Order reversed from little -> big endian.
# The reversal means we can check it for equivalence with a tket unitary
qiskit_unitary = Operator(qc.reverse_bits()).data
converted_tkc = qiskit_to_tk(qc)
assert converted_tkc.n_gates == 1
assert converted_tkc.n_gates_of_type(OpType.CircBox) == 1
circbox_op = converted_tkc.get_commands()[0].op
assert isinstance(circbox_op, CircBox)
assert circbox_op.get_circuit().name == "RealAmplitudes"
DecomposeBoxes().apply(converted_tkc)
assert converted_tkc.n_gates_of_type(OpType.CX) == 4
assert converted_tkc.n_gates_of_type(OpType.Ry) == 9
unitary1 = converted_tkc.get_unitary()
qc2 = tk_to_qiskit(converted_tkc)
tkc2 = qiskit_to_tk(qc2)
unitary2 = tkc2.get_unitary()
assert compare_unitaries(qiskit_unitary, unitary1)
assert compare_unitaries(unitary1, unitary2)

0 comments on commit fc18d49

Please sign in to comment.