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

stricter ordering checks #112

Merged
merged 8 commits into from
Jan 26, 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
1 change: 1 addition & 0 deletions pytket/phir/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def pytket_to_phir(circuit: "Circuit", qtm_machine: QtmMachine | None = None) ->
else:
phir_json = genphir(placed, machine_ops=bool(machine))
if logger.getEffectiveLevel() <= logging.INFO:
print("PHIR JSON:")
print(PHIRModel.model_validate_json(phir_json))
return phir_json

Expand Down
6 changes: 3 additions & 3 deletions pytket/phir/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# mypy: disable-error-code="misc"
# ruff: noqa: T201

import logging
from argparse import ArgumentParser
from importlib.metadata import version

Expand Down Expand Up @@ -70,10 +71,9 @@ def main() -> None:
case "H1-2":
machine = QtmMachine.H1_2

phir = pytket_to_phir(circuit, machine)
if args.verbose:
print("\nPHIR to be simulated:")
print(phir)
logging.basicConfig(level=logging.INFO)
phir = pytket_to_phir(circuit, machine)

print("\nPECOS results:")
print(
Expand Down
26 changes: 24 additions & 2 deletions pytket/phir/phirgen_parallel.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import json
import logging
from collections import OrderedDict
from typing import TYPE_CHECKING

import pytket.circuit as tk
Expand All @@ -29,14 +30,33 @@
logger = logging.getLogger(__name__)


def exec_order_preserved_helper(
ordered_dict: OrderedDict["UnitID", int], group_number: int, qubit_last_group: int
) -> bool:
"""A helper to determine whether order is preserved when adding qubits to groups."""
# determine whether the current group number is later in execution
# than the last group in which a qubit was used
group_eligible = group_number > qubit_last_group
if not group_eligible:
return False
for group in ordered_dict.values():
if group == qubit_last_group:
order_preserved = False
break
if group == group_number:
order_preserved = True
break
return order_preserved


def process_sub_commands(
sub_commands: dict["UnitID", list[tk.Command]], max_parallel_sq_gates: int
) -> dict[int, list[tk.Command]]:
"""Create parallelizable groups of sub-commands."""
groups: dict[
int, list[tk.Command]
] = {} # be sure to order by group number into a list when returning
qubits2groups = {} # track the most recent group in which a qubit was used
qubits2groups = OrderedDict() # the most recent group in which a qubit was used
# group numbers for each gate are incremented by 3 so they don't overlap
# and different gate types don't go in the same group
# RZ gates go in (mod 3)=0 groups, R1XY gates go in (mod 3)=1 groups,
Expand Down Expand Up @@ -78,7 +98,9 @@ def process_sub_commands(
group_available = group_number in groups
# is that group later in execution than the
# most recent group for an op on that qubit?
order_preserved = group_number > qubits2groups[qubit]
order_preserved = exec_order_preserved_helper(
qubits2groups, group_number, qubits2groups[qubit]
)
# is the group size still under the maximum allowed parallel ops?
group_size = len(groups[group_number]) if group_number in groups else 0
group_not_too_large = group_size < max_parallel_sq_gates
Expand Down
19 changes: 19 additions & 0 deletions tests/data/qasm/exec_order_two_qubits.qasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
OPENQASM 2.0;
include "qelib1.inc";
include "hqslib1_dev.inc";
qreg q[2];
creg c[2];
ry(3.5*pi) q[0];
rx(3.5*pi) q[1];
ZZ q[0],q[1];
rx(0.5*pi) q[0];
barrier q[0],q[1];
rx(3.5*pi) q[0];
rz(3.5*pi) q[1];
rx(1.0*pi) q[1];
ZZ q[0],q[1];
ry(0.5*pi) q[0];
ry(3.5*pi) q[1];
barrier q[0],q[1];
measure q[0] -> c[0];
measure q[1] -> c[1];
19 changes: 19 additions & 0 deletions tests/test_parallelization.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,22 @@ def test_single_qubit_circuit_with_parallel() -> None:
phir_with_parallel_phirgen["ops"][i]["args"]
== phir_with_standard_phirgen["ops"][i]["args"]
)


def test_two_qubit_exec_order_preserved() -> None:
"""Test that the order of gating in preserved in a 2 qubit circuit."""
phir = get_phir_json(QasmFile.exec_order_two_qubits, rebase=True)
# for this test, verify that the RX gates are NOT parallelized
# in the following section of the qasm file (lines 11-13):
# rx(3.5*pi) q[0];
assert phir["ops"][18]["qop"] == "R1XY"
assert phir["ops"][18]["angles"] == [[3.5, 0.0], "pi"]
assert phir["ops"][18]["args"] == [["q", 0]]
# rz(3.5*pi) q[1];
assert phir["ops"][20]["qop"] == "RZ"
assert phir["ops"][20]["angles"] == [[3.5], "pi"]
assert phir["ops"][20]["args"] == [["q", 1]]
# rx(1.0*pi) q[1];
assert phir["ops"][24]["qop"] == "R1XY"
assert phir["ops"][24]["angles"] == [[1.0, 0.0], "pi"]
assert phir["ops"][24]["args"] == [["q", 1]]
Copy link
Member

Choose a reason for hiding this comment

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

For these tests, it might be easier to compare directly with the JSON output per op, e.g.:

assert phir["ops"][18] == {
    "qop": "R1XY",
    "angles": [[3.5, 0.0], "pi"],
    "args": [["q", 0]],
}

1 change: 1 addition & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class QasmFile(Enum):
rxrz = auto()
classical_ordering = auto()
single_qubit_parallel_test = auto()
exec_order_two_qubits = auto()


class WatFile(Enum):
Expand Down