generated from CQCL/pytemplate
-
Notifications
You must be signed in to change notification settings - Fork 2
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
Improving shard handling and testing #3
Merged
Merged
Changes from 7 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
e5e09f1
Improving shard handling and testing
nealerickson-qtm 3faaa27
Apply suggestions from code review
neal-erickson 3d85f40
in progress
nealerickson-qtm e9add68
test progress
nealerickson-qtm 4af6e36
fixing ruff
nealerickson-qtm 4cfd423
removing commented
nealerickson-qtm 0b7a5dd
linting feedback
nealerickson-qtm 7336634
mypy
nealerickson-qtm 0fcbb0b
Merge branch 'main' into sharding-handling
nealerickson-qtm 7fd37fd
Adding test for partial barriers
nealerickson-qtm c8c634f
updating test
nealerickson-qtm e04dc69
cleanup comments
nealerickson-qtm fca9110
another classical test
nealerickson-qtm 029bbd3
big gate test
nealerickson-qtm 1face99
hash method for shards to allow sets
nealerickson-qtm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,21 @@ | ||
from pytket.circuit import Circuit, Command, Op, OpType | ||
from pytket.unit_id import UnitID | ||
from typing import cast | ||
|
||
from pytket.circuit import Circuit, Command, Conditional, Op, OpType | ||
from pytket.unit_id import Bit, UnitID | ||
|
||
from .shard import Shard | ||
|
||
NOT_IMPLEMENTED_OP_TYPES = [OpType.CircBox, OpType.WASM] | ||
|
||
SHARD_TRIGGER_OP_TYPES = [ | ||
OpType.Measure, | ||
OpType.Reset, | ||
OpType.Barrier, | ||
OpType.SetBits, | ||
OpType.ClassicalExpBox, # some classical operations are rolled up into a box | ||
OpType.RangePredicate, | ||
] | ||
|
||
|
||
class Sharder: | ||
""" | ||
|
@@ -15,9 +26,9 @@ class Sharder: | |
|
||
def __init__(self, circuit: Circuit) -> None: | ||
self._circuit = circuit | ||
print(f"Sharder created for circuit {self._circuit}") | ||
self._pending_commands: dict[UnitID, list[Command]] = {} | ||
self._shards: list[Shard] = [] | ||
print(f"Sharder created for circuit {self._circuit}") | ||
|
||
def shard(self) -> list[Shard]: | ||
""" | ||
|
@@ -28,6 +39,12 @@ def shard(self) -> list[Shard]: | |
# https://cqcl.github.io/tket/pytket/api/circuit.html#pytket.circuit.Command | ||
for command in self._circuit.get_commands(): | ||
self._process_command(command) | ||
self._cleanup_remaining_commands() | ||
|
||
print("--------------------------------------------") | ||
print("Shard output:") | ||
for shard in self._shards: | ||
print(shard.pretty_print()) | ||
return self._shards | ||
|
||
def _process_command(self, command: Command) -> None: | ||
|
@@ -41,41 +58,120 @@ def _process_command(self, command: Command) -> None: | |
raise NotImplementedError(msg) | ||
|
||
if self.should_op_create_shard(command.op): | ||
print(f"Building shard for command: {command}") | ||
print( | ||
f"Building shard for command: {command}", | ||
) | ||
self._build_shard(command) | ||
else: | ||
self._add_pending_command(command) | ||
self._add_pending_sub_command(command) | ||
|
||
def _build_shard(self, command: Command) -> None: | ||
""" | ||
Creates a Shard object given the extant sharding context and the schedulable | ||
Creates a Shard object given the extant sharding context and the primary | ||
Command object passed in, and appends it to the Shard list | ||
""" | ||
shard = Shard(command, self._pending_commands, set()) | ||
# TODO: Dependencies! | ||
self._pending_commands = {} | ||
# Rollup any sub commands (SQ gates) that interact with the same qubits | ||
sub_commands: dict[UnitID, list[Command]] = {} | ||
for key in ( | ||
key for key in list(self._pending_commands) if key in command.qubits | ||
): | ||
sub_commands[key] = self._pending_commands.pop(key) | ||
|
||
all_commands = [command] | ||
for sub_command_list in sub_commands.values(): | ||
all_commands.extend(sub_command_list) | ||
|
||
qubits_used = set(command.qubits) | ||
bits_written = set(command.bits) | ||
bits_read: set[Bit] = set() | ||
|
||
# def filter_to_bits: Callable[[UnitId], bool] = lambda x: isinstance(x, Bit) | ||
for sub_command in all_commands: | ||
bits_written.update(sub_command.bits) | ||
bits_read.update( | ||
set(filter(lambda x: isinstance(x, Bit), sub_command.args)), # type: ignore [misc, arg-type] # noqa: E501 | ||
) | ||
|
||
# Handle dependency calculations | ||
depends_upon: set[int] = set() | ||
for shard in self._shards: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wondering if dependency creation should be a self contained method. The overall |
||
# Check qubit dependencies (R/W implicitly) since all commands | ||
# on a given qubit need to be ordered as the circuit dictated | ||
if not shard.qubits_used.isdisjoint(command.qubits): | ||
print(f"...adding shard dep {shard.ID} -> qubit overlap") | ||
depends_upon.add(shard.ID) | ||
# Check classical dependencies, which depend on writing and reading | ||
# hazards: RAW, WAW, WAR | ||
# NOTE: bits_read will include bits_written in the current impl | ||
|
||
# Check for write-after-write (changing order would change final value) | ||
# by looking at overlap of bits_written | ||
elif not shard.bits_written.isdisjoint(bits_written): | ||
print(f"...adding shard dep {shard.ID} -> WAW") | ||
depends_upon.add(shard.ID) | ||
|
||
# Check for read-after-write (value seen would change if reordered) | ||
# elif not shard.bits_read.isdisjoint(bits_written): | ||
# print(f'...adding shard dep {shard.ID} -> ') | ||
# depends_upon.add(shard.ID) | ||
elif not shard.bits_written.isdisjoint(bits_read): | ||
print(f"...adding shard dep {shard.ID} -> RAW") | ||
depends_upon.add(shard.ID) | ||
|
||
# Check for write-after-read (no reordering or read is changed) | ||
elif not shard.bits_written.isdisjoint(bits_read): | ||
print(f"...adding shard dep {shard.ID} -> WAR") | ||
depends_upon.add(shard.ID) | ||
|
||
shard = Shard( | ||
command, | ||
sub_commands, | ||
qubits_used, | ||
bits_written, | ||
bits_read, | ||
depends_upon, | ||
) | ||
self._shards.append(shard) | ||
print("Appended shard:", shard) | ||
|
||
def _add_pending_command(self, command: Command) -> None: | ||
def _cleanup_remaining_commands(self) -> None: | ||
""" | ||
Checks for any remaining "unsharded" commands, and if found, adds them | ||
to Barrier op shards for each qubit | ||
""" | ||
remaining_qubits = [k for k, v in self._pending_commands.items() if v] | ||
for qubit in remaining_qubits: | ||
self._circuit.add_barrier([qubit]) | ||
# Easiest way to get to a command, since there's no constructor. Could | ||
# create an entire orphan circuit with the matching qubits and the barrier | ||
# instead if this has unintended consequences | ||
barrier_command = self._circuit.get_commands()[-1] | ||
self._build_shard(barrier_command) | ||
|
||
def _add_pending_sub_command(self, command: Command) -> None: | ||
""" | ||
Adds a pending sub command to the buffer to be flushed when a schedulable | ||
operation creates a Shard. | ||
""" | ||
# TODO: Need to make sure 'args[0]' is the right key to use. | ||
if command.args[0] not in self._pending_commands: | ||
self._pending_commands[command.args[0]] = [] | ||
self._pending_commands[command.args[0]].append(command) | ||
key = command.qubits[0] | ||
if key not in self._pending_commands: | ||
self._pending_commands[key] = [] | ||
self._pending_commands[key].append(command) | ||
print( | ||
f"Adding pending command {command}", | ||
) | ||
|
||
@staticmethod | ||
def should_op_create_shard(op: Op) -> bool: | ||
""" | ||
Returns `True` if the operation is one that should result in shard creation. | ||
This includes non-gate operations like measure/reset as well as 2-qubit gates. | ||
""" | ||
# TODO: This is almost certainly inadequate right now | ||
return ( | ||
op.type == OpType.Measure | ||
or op.type == OpType.Reset | ||
op.type in (SHARD_TRIGGER_OP_TYPES) | ||
or ( | ||
op.type == OpType.Conditional | ||
and cast(Conditional, op).op.type in (SHARD_TRIGGER_OP_TYPES) | ||
) | ||
or (op.is_gate() and op.n_qubits > 1) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
OPENQASM 2.0; | ||
include "hqslib1.inc"; | ||
|
||
qreg q[2]; | ||
creg c[2]; | ||
|
||
h q[0]; | ||
h q[1]; | ||
CX q[0], q[1]; | ||
|
||
measure q->c; | ||
|
||
h q[0]; | ||
|
||
h q[1]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
OPENQASM 2.0; | ||
include "hqslib1_dev.inc"; | ||
qreg q[1]; | ||
creg a[10]; | ||
creg b[10]; | ||
creg c[4]; | ||
|
||
// classical assignment of registers | ||
a[0] = 1; | ||
a = 3; | ||
// classical bitwise functions | ||
a = 1; | ||
b = 3; | ||
c = a ^ b; // XOR | ||
// evaluating a beyond creg == int | ||
a = 1; | ||
b = 2; | ||
if(a[0]==1) x q[0]; | ||
if(a!=1) x q[0]; | ||
if(a>1) x q[0]; | ||
if(a<1) x q[0]; | ||
if(a>=1) x q[0]; | ||
if(a<=1) x q[0]; | ||
if (a==10) b=1; | ||
measure q[0] -> c[0]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
OPENQASM 2.0; | ||
include "hqslib1.inc"; | ||
|
||
qreg q[1]; | ||
creg c[1]; | ||
creg z[1]; | ||
|
||
h q; | ||
measure q->c; | ||
reset q; | ||
if (c==1) h q; | ||
if (c==1) z=1; | ||
measure q->c; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want prints vs. some other form of logging? I'm ok with it for first cut merging PR in, but I imagine we won't want to keep these prints as is.