Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve implicit qubit permutations warning #421

Merged
merged 24 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions pytket/extensions/qiskit/qiskit_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

"""Methods to allow conversion between Qiskit and pytket circuit classes
"""
import warnings
from collections import defaultdict
from collections.abc import Iterable
from inspect import signature
Expand Down Expand Up @@ -861,8 +862,13 @@ def append_tk_command_to_qiskit(
supported_gate_rebase = AutoRebase(_protected_tket_gates)


def _has_implicit_permutation(circ: Circuit) -> bool:
"""Returns True if a Circuit has a non-trivial permutation of qubits, false otherwise."""
return any(q0 != q1 for q0, q1 in circ.implicit_qubit_permutation().items())


def tk_to_qiskit(
tkcirc: Circuit, replace_implicit_swaps: bool = False
tkcirc: Circuit, replace_implicit_swaps: bool = False, perm_warning: bool = True,
) -> QuantumCircuit:
"""
Converts a pytket :py:class:`Circuit` to a qiskit :py:class:`qiskit.QuantumCircuit`.
Expand All @@ -871,19 +877,29 @@ def tk_to_qiskit(
If no exact replacement can be found for a part of the circuit then an equivalent
circuit will be returned using the tket gates which are supported in qiskit.

Please note that implicit swaps in a pytket Circuit are not handled by default.
Note that implicit swaps in a pytket Circuit are not handled by default.
Consider using the replace_implicit_swaps flag to replace these implicit swaps with
SWAP gates.

:param tkcirc: A :py:class:`Circuit` to be converted
:param replace_implicit_swaps: Implement implicit permutation by adding SWAPs
to the end of the circuit.
:param perm_warnings: Warn on if input circuit has implicit qubit permutations, True by
default.
:return: The converted circuit
"""
tkc = tkcirc.copy() # Make a local copy of tkcirc
if replace_implicit_swaps:
tkc.replace_implicit_wire_swaps()

if _has_implicit_permutation(tkcirc) and perm_warning and not replace_implicit_swaps:
warnings.warn(
"The pytket Circuit contains implicit qubit permutations"
+ " which aren't handled by default."
+ " Consider using the replace_implicit_swaps flag in tk_to_qiskit or"
+ " replacing them using Circuit.replace_implicit_swaps()."
)

qcirc = QuantumCircuit(name=tkc.name)
qreg_sizes: dict[str, int] = {}
for qb in tkc.qubits:
Expand Down
20 changes: 19 additions & 1 deletion tests/qiskit_convert_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import warnings
from collections import Counter
from math import pi

Expand Down Expand Up @@ -62,7 +63,7 @@
reg_eq,
)
from pytket.extensions.qiskit import IBMQBackend, qiskit_to_tk, tk_to_qiskit
from pytket.extensions.qiskit.backends import qiskit_aer_backend
from pytket.extensions.qiskit.backends import qiskit_aer_backend, AerStateBackend, AerBackend
from pytket.extensions.qiskit.qiskit_convert import _gate_str_2_optype
from pytket.extensions.qiskit.result_convert import qiskit_result_to_backendresult
from pytket.extensions.qiskit.tket_pass import TketAutoPass, TketPass
Expand Down Expand Up @@ -1165,6 +1166,23 @@ def test_symbolic_param_conv() -> None:
}
)

def test_implicit_swap_warning() -> None:
c = Circuit(2).H(0).SWAP(0, 1)
c.replace_SWAPs()
with pytest.warns(UserWarning, match="The pytket Circuit contains implicit qubit"):
tk_to_qiskit(c)

state_backend = AerStateBackend()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote this test without the flag added to ensure that it failed.

The warning only appears for AerBackend and not AerStateBackend. I would've expected both to generate a warning (i.e. record to be of length 2)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah its because the state and unitary backends replace implicit swaps with SWAP gates whereas AerBackend does not.

shots_backend = AerBackend()
with pytest.warns(UserWarning) as record:
state_backend.run_circuit(c)
c.measure_all()
shots_backend.run_circuit(c)
assert len(record) == 0





# https://github.com/CQCL/pytket-qiskit/issues/337
def test_nonregister_bits() -> None:
Expand Down
Loading