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

Routing #9

Merged
merged 5 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ docs/_build/
.pybuilder/
target/

# vscode
.vscode/

# Jupyter Notebook
.ipynb_checkpoints

Expand Down
46 changes: 46 additions & 0 deletions pytket/phir/place_and_route.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import typing

from pytket.phir.machine_class import Machine
from pytket.phir.placement import optimized_place
from pytket.phir.routing import transport_cost
from pytket.phir.sharding.sharder import Sharder
from pytket.phir.sharding.shards2ops import parse_shards_naive
from tests.sample_data import ( # type: ignore [attr-defined]
Circuit,
get_qasm_as_circuit,
)


@typing.no_type_check
def place_and_route(machine: Machine, qasm: Circuit):
"""Get all the routing info needed for PHIR generation."""
circuit = get_qasm_as_circuit(qasm)
sharder = Sharder(circuit)
shards = sharder.shard()
shard_set = set(shards)
circuit_rep, shard_layers = parse_shards_naive(shard_set)
# print(circuit_rep)
initial_order = list(range(machine.size))
layer_num = 0
orders: list[list[int]] = []
layer_costs: list[int] = []
net_cost: float = 0.0
for layer in circuit_rep:
order = optimized_place(
layer,
machine.tq_options,
machine.sq_options,
machine.size,
initial_order,
)
orders.append(order)
cost = transport_cost(initial_order, order, machine.qb_swap_time)
layer_num += 1
initial_order = order
layer_costs.append(cost)
net_cost += cost

# don't need a custom error for this, "strict" parameter will throw error if needed
info = list(zip(orders, shard_layers, layer_costs, strict=True))

return info
16 changes: 14 additions & 2 deletions pytket/phir/placement.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def place( # noqa: PLR0912
raise PlacementCheckError


def optimized_place(
def optimized_place( # noqa: PLR0912
ops: list[list[int]],
tq_options: set[int],
sq_options: set[int],
Expand Down Expand Up @@ -209,7 +209,19 @@ def optimized_place(

# place the tq ops
order = place_tq_ops(tq_ops_sorted, placed_qubits, order, tq_zones, sq_zones)

# run a check to avoid unnecessary swaps
for zone in tq_zones:
# this condition is true if there was a swap due to the order of qubits_used
# in the shard creating the TQ op,
# even if those two qubits were already in a TQ zone
# example: ops = [[0,1]] prev_state = [0,1,2,3] new order = [1,0,2,3]
# this check s to prevent the above situation
if (order[zone] == prev_state[zone + 1]) & (
order[zone + 1] == prev_state[zone]
):
swapped = order[zone + 1]
order[zone + 1] = order[zone]
order[zone] = swapped
# place the sq ops
for op in sq_ops:
q1 = op[0]
Expand Down
44 changes: 44 additions & 0 deletions pytket/phir/sharding/shards2ops.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from pytket.phir.sharding.shard import Shard


def parse_shards_naive(shards: set[Shard]): # type: ignore [no-untyped-def]
"""Parse a set of shards and return a circuit representation for placement."""
layers: list[list[list[int]]] = []
shards_in_layer: list[list[Shard]] = []
scheduled: set[int] = set()
num_shards: int = len(shards)

while len(scheduled) < num_shards:
layer: list[list[int]] = []
to_schedule: list[Shard] = []
# get all the shards with no dependencies
for shard in enumerate(shards):
s = shard[1]
deps = s.depends_upon
# dependencies of the shard that have already been scheduled
scheduled_deps = deps.intersection(scheduled)
already_scheduled = s.ID in scheduled

if scheduled_deps == deps and not already_scheduled:
to_schedule.append(s)
shards_in_layer.append(to_schedule)

for shard in to_schedule: # type: ignore [assignment]
op: list[int] = []
# if there are more than 2 qubits used, treat them all as parallel sq ops
# one qubit will just be a single sq op
# 3 or more will be 3 or more parallel sq ops
if len(shard.qubits_used) != 2: # type: ignore [attr-defined, misc] # noqa: PLR2004
for qubit in shard.qubits_used: # type: ignore [attr-defined, misc]
op = qubit.index # type: ignore [misc]
layer.append(op)
else:
for qubit in shard.qubits_used: # type: ignore [attr-defined, misc]
op.append(qubit.index[0]) # type: ignore [misc]
layer.append(op)

scheduled.add(shard.ID) # type: ignore [attr-defined, misc]

layers.append(layer)

return layers, shards_in_layer
13 changes: 13 additions & 0 deletions tests/data/qasm/eztest.qasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
OPENQASM 2.0;
include "hqslib1.inc";

qreg q[3];
creg c[3];

CX q[0], q[2];
h q[0];
h q[1];
h q[2];


measure q->c;
14 changes: 14 additions & 0 deletions tests/data/qasm/n10_test.qasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
OPENQASM 2.0;
include "qelib1.inc";

creg c[12];
qreg q[12];

cx q[0],q[1];
cx q[2],q[3];
cx q[4],q[5];
cx q[5],q[7];
cx q[7],q[8];
cx q[9],q[10];

measure q->c;
84 changes: 84 additions & 0 deletions tests/data/qasm/oned_brickwork_circuit_n20.qasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
OPENQASM 2.0;
include "qelib1.inc";
qreg q[20];
creg c[20];
h q[0];
h q[1];
h q[2];
h q[3];
h q[4];
h q[5];
h q[6];
h q[7];
h q[8];
h q[9];
h q[10];
h q[11];
h q[12];
h q[13];
h q[14];
h q[15];
h q[16];
h q[17];
h q[18];
h q[19];
rzz(-pi/8) q[0],q[1];
rzz(-pi/8) q[2],q[3];
rzz(-pi/8) q[4],q[5];
rzz(-pi/8) q[6],q[7];
rzz(-pi/8) q[8],q[9];
rzz(-pi/8) q[10],q[11];
rzz(-pi/8) q[12],q[13];
rzz(-pi/8) q[14],q[15];
rzz(-pi/8) q[16],q[17];
rzz(-pi/8) q[18],q[19];
rzz(-pi/8) q[1],q[2];
rzz(-pi/8) q[3],q[4];
rzz(-pi/8) q[5],q[6];
rzz(-pi/8) q[7],q[8];
rzz(-pi/8) q[9],q[10];
rzz(-pi/8) q[11],q[12];
rzz(-pi/8) q[13],q[14];
rzz(-pi/8) q[15],q[16];
rzz(-pi/8) q[17],q[18];
rzz(-pi/8) q[0],q[19];
h q[0];
h q[1];
h q[2];
h q[3];
h q[4];
h q[5];
h q[6];
h q[7];
h q[8];
h q[9];
h q[10];
h q[11];
h q[12];
h q[13];
h q[14];
h q[15];
h q[16];
h q[17];
h q[18];
h q[19];
measure q[0] -> c[0];
measure q[1] -> c[1];
measure q[2] -> c[2];
measure q[3] -> c[3];
measure q[4] -> c[4];
measure q[5] -> c[5];
measure q[6] -> c[6];
measure q[7] -> c[7];
measure q[8] -> c[8];
measure q[9] -> c[9];
measure q[10] -> c[10];
measure q[11] -> c[11];
measure q[12] -> c[12];
measure q[13] -> c[13];
measure q[14] -> c[14];
measure q[15] -> c[15];
measure q[16] -> c[16];
measure q[17] -> c[17];
measure q[18] -> c[18];
measure q[19] -> c[19];
Loading