Skip to content

Commit

Permalink
Update CustomGate handling in circuit_from_qasm_... (#1739)
Browse files Browse the repository at this point in the history
* check number of paramters are equal before doing circuit comparison

* Update qasm.py

* Update qasm.py

* Update changelog.rst

* Update pytket/pytket/qasm/qasm.py

Co-authored-by: Alec Edgington <[email protected]>

* Update qasm.py

---------

Co-authored-by: Alec Edgington <[email protected]>
  • Loading branch information
sjdilkes and cqc-alec authored Jan 16, 2025
1 parent a443386 commit cde5f28
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 17 deletions.
4 changes: 4 additions & 0 deletions pytket/docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Features:

* Add `RemovePhaseOps` pass.

Fixes:

* Fix issue with custom gates in qasm to circuit conversion.

1.38.0 (January 2025)
---------------------

Expand Down
53 changes: 36 additions & 17 deletions pytket/pytket/qasm/qasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,16 @@ class QASMUnsupportedError(Exception):
"fsim": OpType.FSim,
}

N_PARAMS_EXTRA_COMMANDS = {
OpType.TK2: 3,
OpType.ISWAP: 1,
OpType.PhasedISWAP: 2,
OpType.YYPhase: 1,
OpType.XXPhase3: 1,
OpType.ESWAP: 1,
OpType.FSim: 2,
}

_tk_to_qasm_noparams = dict((item[1], item[0]) for item in NOPARAM_COMMANDS.items())
_tk_to_qasm_noparams[OpType.CX] = "cx" # prefer "cx" to "CX"
_tk_to_qasm_params = dict((item[1], item[0]) for item in PARAM_COMMANDS.items())
Expand Down Expand Up @@ -859,9 +869,7 @@ def transform(self, tree: Tree) -> dict[str, Any]:

def gdef(self, tree: list) -> None:
child_iter = iter(tree)

gate = next(child_iter).value

next_tree = next(child_iter)
symbols, args = [], []
if isinstance(next_tree, ParsMap):
Expand All @@ -882,6 +890,9 @@ def gdef(self, tree: list) -> None:
# check to see whether gate definition was generated by pytket converter
# if true, add op as pytket Op
existing_op: bool = False
# NOPARAM_EXTRA_COMMANDS and PARAM_EXTRA_COMMANDS are
# gates that aren't in the standard qasm spec but in the standard TKET
# optypes
if gate in NOPARAM_EXTRA_COMMANDS:
qubit_args = [
Qubit(gate + "q" + str(index), 0) for index in list(range(len(args)))
Expand All @@ -894,25 +905,33 @@ def gdef(self, tree: list) -> None:
) == circuit_to_qasm_str(gate_circ, maxwidth=self.maxwidth):
existing_op = True
elif gate in PARAM_EXTRA_COMMANDS:
qubit_args = [
Qubit(gate + "q" + str(index), 0) for index in list(range(len(args)))
]
comparison_circ = _get_gate_circuit(
PARAM_EXTRA_COMMANDS[gate],
qubit_args,
[Symbol("param" + str(index) + "/pi") for index in range(len(symbols))],
)
# checks that each command has same string
existing_op = all(
str(g) == str(c)
for g, c in zip(
gate_circ.get_commands(), comparison_circ.get_commands()
optype = PARAM_EXTRA_COMMANDS[gate]
# we check this here, as _get_gate_circuit will find issue if it isn't true
# the later existing_op=all check will make sure it's the same circuit later
if len(symbols) != N_PARAMS_EXTRA_COMMANDS[optype]:
existing_op = False
else:
qubit_args = [
Qubit(gate + "q" + str(index), 0) for index in range(len(args))
]
comparison_circ = _get_gate_circuit(
optype,
qubit_args,
[
Symbol("param" + str(index) + "/pi")
for index in range(len(symbols))
],
)
# checks that each command has same string
existing_op = all(
str(g) == str(c)
for g, c in zip(
gate_circ.get_commands(), comparison_circ.get_commands()
)
)
)
if not existing_op:
gate_circ.symbol_substitution(symbol_map)
gate_circ.rename_units(cast(dict[UnitID, UnitID], rename_map))

self.gate_dict[gate] = {
"definition": gate_circ.to_dict(),
"args": symbols,
Expand Down
18 changes: 18 additions & 0 deletions pytket/tests/qasm_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,23 @@ def test_multibitop() -> None:
)


def test_existing_name_conversion() -> None:
# https://github.com/CQCL/tket/issues/1605
assert (
circuit_from_qasm_str(
"""OPENQASM 2.0;
include "qelib1.inc";
gate iswap q0,q1 { s q0; s q1; h q0; cx q0,q1; cx q1,q0; h q1; }
qreg qr[3];
creg cr[3];
iswap qr[1],qr[2];"""
)
.get_commands()[0]
.op.type
== OpType.CustomGate
)


if __name__ == "__main__":
test_qasm_correct()
test_qasm_qubit()
Expand Down Expand Up @@ -1247,3 +1264,4 @@ def test_multibitop() -> None:
test_classical_expbox_arg_order(True)
test_classical_expbox_arg_order(False)
test_register_name_check()
test_existing_name_conversion()

0 comments on commit cde5f28

Please sign in to comment.