Skip to content

Commit

Permalink
Merge pull request #9 from CQCL/routing
Browse files Browse the repository at this point in the history
Routing and placement implementations with an "end to end" test that gets programs through the pipeline all the way up to phir generation.
  • Loading branch information
peter-campora authored Oct 17, 2023
2 parents 6dd0c63 + d6c41cf commit 4660303
Show file tree
Hide file tree
Showing 10 changed files with 2,105 additions and 3 deletions.
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

0 comments on commit 4660303

Please sign in to comment.