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

Bug out of order seq #35

Merged
merged 6 commits into from
Jan 4, 2024
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
5 changes: 1 addition & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "quantum-pecos"
version = "0.5.0.dev4"
version = "0.5.0.dev5"
authors = [
{name = "The PECOS Developers"},
]
Expand Down Expand Up @@ -99,9 +99,6 @@ where = ["python"]
include = ["pecos*"]
namespaces = true

[tool.pytest.ini_options]
filterwarnings = ["ignore:::dateutil.tz.tz.*"]

# Linting and autorefactoring tools
# ---------------------------------

Expand Down
1 change: 1 addition & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ markers =
# TODO: comment this to deal with ProjectQ gate warnings
filterwarnings =
ignore::PendingDeprecationWarning:projectq.ops._gates
ignore::DeprecationWarning:dateutil.tz.tz.*
45 changes: 20 additions & 25 deletions python/pecos/classical_interpreters/phir_classical_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,29 @@ def initialize_cenv(self) -> None:
self.cenv.append(dtype(0))
self.cid2dtype.append(dtype)

def execute(self, sequence: Sequence) -> Generator[list, Any, None]:
def _flatten_blocks(self, seq: Sequence):
"""Flattens the ops of blocks to be processed by the execute() method."""
for op in seq:
if isinstance(op, pt.block.SeqBlock):
yield from self._flatten_blocks(op.ops)

elif isinstance(op, pt.block.IfBlock):
if self.eval_expr(op.condition):
yield from self._flatten_blocks(op.true_branch)
elif op.false_branch:
yield from self._flatten_blocks(op.false_branch)
else: # For case of no false_branch (no else)
pass

else:
yield op

def execute(self, seq: Sequence) -> Generator[list, Any, None]:
"""A generator that runs through and executes classical logic and yields other operations via a buffer."""

op_buffer = []

for op in sequence:
for op in self._flatten_blocks(seq):
if isinstance(op, pt.opt.QOp):
op_buffer.append(op)

Expand All @@ -141,14 +158,11 @@ def execute(self, sequence: Sequence) -> Generator[list, Any, None]:
elif isinstance(op, pt.opt.COp):
self.handle_cops(op)

elif isinstance(op, pt.block.Block):
yield from self.execute_block(op)

elif isinstance(op, pt.opt.MOp):
op_buffer.append(op)

else:
msg = f"Statement not recognized: {op}"
msg = f"Statement not recognized: {op} of type: {type(op)}"
raise TypeError(msg)

if op_buffer:
Expand Down Expand Up @@ -279,25 +293,6 @@ def handle_cops(self, op):
msg = f"Unsupported COp: {op}"
raise Exception(msg)

def execute_block(self, op):
"""Execute a block of ops."""
if isinstance(op, pt.block.IfBlock):
if self.eval_expr(op.condition):
yield from self.execute(op.true_branch)

elif op.false_branch:
yield from self.execute(op.false_branch)

else:
yield from self.execute([])

elif isinstance(op, pt.block.SeqBlock):
yield from self.execute(op.ops)

else:
msg = f"block not implemented! {op}"
raise NotImplementedError(msg)

def receive_results(self, qsim_results: list[dict]):
"""Receive measurement results and assign as needed."""
for meas in qsim_results:
Expand Down
2 changes: 2 additions & 0 deletions python/pecos/engines/hybrid_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@


class HybridEngine:
"""Engine that runs hybrid quantum/classical programs."""

def __init__(
self,
cinterp: ClassicalInterpreter | None = None,
Expand Down
4 changes: 2 additions & 2 deletions python/pecos/machines/generic_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def process(self, op_buffer: list[QOp | MOp]) -> list:
def leak(self, qubits: set) -> list[QOp]:
"""Starts tracking qubits as leaked qubits and calls the quantum simulation appropriately to trigger leakage."""
self.leaked_qubits |= qubits
return [QOp(name="Init", args=list(qubits), metadata={})]
return [QOp(name="Init", args=list(qubits))]

def unleak(self, qubits: set) -> None:
"""Untrack qubits as leaked qubits and calls the quantum simulation appropriately to trigger leakage."""
Expand All @@ -58,5 +58,5 @@ def unleak(self, qubits: set) -> None:
def meas_leaked(self, qubits: set) -> list[QOp]:
self.leaked_qubits -= qubits
return [
QOp(name="Init -Z", args=list(qubits), metadata={}),
QOp(name="Init -Z", args=list(qubits)),
]
7 changes: 6 additions & 1 deletion python/pecos/reps/pypmir/op_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@


class Op:
"""Parent class of operations."""

def __init__(
self,
name: str,
Expand All @@ -39,7 +41,7 @@ def __init__(
raise TypeError(msg)

def __str__(self) -> str:
return f"{self.name}, {self.args}, {self.returns}, {self.metadata}, {self.angles}"
return f"{self.name}, {self.args}, {self.returns}, {self.metadata}"


class QOp(Op):
Expand All @@ -61,6 +63,9 @@ def __init__(
)
self.angles = angles

def __str__(self):
return self.__repr__()

def __repr__(self):
return (
f"<QOP: {self.name} angles: {self.angles} args: {self.args} returns: {self.returns} "
Expand Down
12 changes: 6 additions & 6 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@ annotated-types==0.6.0
colorama==0.4.6
contourpy==1.2.0
cycler==0.12.1
fonttools==4.46.0
fonttools==4.47.0
iniconfig==2.0.0
kiwisolver==1.4.5
markdown-it-py==3.0.0
matplotlib==3.8.2
mdurl==0.1.2
networkx==2.8.8
numpy==1.26.2
numpy==1.26.3
packaging==23.2
phir==0.2.1
pillow==10.1.0
pillow==10.2.0
pluggy==1.3.0
pydantic==2.5.2
pydantic-core==2.14.5
pydantic==2.5.3
pydantic-core==2.14.6
pygments==2.17.2
pyparsing==3.1.1
pytest==7.4.3
pytest==7.4.4
python-dateutil==2.8.2
rich==13.7.0
scipy==1.11.4
Expand Down
11 changes: 11 additions & 0 deletions tests/end2end/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2024 The PECOS developers
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
# the License.You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
"""End-to-end tests"""
22 changes: 22 additions & 0 deletions tests/integration/phir/bell_qparallel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"format": "PHIR/JSON",
"version": "0.1.0",
"metadata": {"source": "pytket-phir v0.2.0", "strict_parallelism": "true"},
"ops": [
{"data": "qvar_define", "data_type": "qubits", "variable": "q", "size": 2},
{"data": "cvar_define", "data_type": "u32", "variable": "m", "size": 2},
{"qop": "RZ", "angles": [[1.0], "pi"], "args": [["q", 0], ["q", 1]]},
{"block": "qparallel", "ops": [
{"qop": "R1XY", "angles": [[0.5, 0.5], "pi"], "args": [["q", 0]]},
{"qop": "R1XY", "angles": [[1.5, 0.5], "pi"], "args": [["q", 1]]}
]},
{"qop": "RZ", "angles": [[1.0], "pi"], "args": [["q", 0]]},
{"qop": "RZZ", "angles": [[0.5], "pi"], "args": [[["q", 0], ["q", 1]]]},
{"block": "qparallel", "ops": [
{"qop": "RZ", "angles": [[1.5], "pi"], "args": [["q", 0]]},
{"qop": "RZ", "angles": [[0.5], "pi"], "args": [["q", 1]]}
]},
{"qop": "R1XY", "angles": [[1.5, 0.5], "pi"], "args": [["q", 1]]},
{"qop": "Measure", "args": [["q", 0], ["q", 1]], "returns": [["m", 0], ["m", 1]]}
]
}
22 changes: 22 additions & 0 deletions tests/integration/phir/bell_qparallel_cliff.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"format": "PHIR/JSON",
"version": "0.1.0",
"metadata": {"source": "pytket-phir v0.2.0", "strict_parallelism": "true"},
"ops": [
{"data": "qvar_define", "data_type": "qubits", "variable": "q", "size": 2},
{"data": "cvar_define", "data_type": "u32", "variable": "m", "size": 2},
{"qop": "Z", "args": [["q", 0], ["q", 1]]},
{"block": "qparallel", "ops": [
{"qop": "SY", "args": [["q", 0]]},
{"qop": "SYdg", "args": [["q", 1]]}
]},
{"qop": "Z", "args": [["q", 0]]},
{"qop": "SZZ", "args": [[["q", 0], ["q", 1]]]},
{"block": "qparallel", "ops": [
{"qop": "SZdg", "args": [["q", 0]]},
{"qop": "SZ", "args": [["q", 1]]}
]},
{"qop": "SYdg", "args": [["q", 1]]},
{"qop": "Measure", "args": [["q", 0], ["q", 1]], "returns": [["m", 0], ["m", 1]]}
]
}
26 changes: 26 additions & 0 deletions tests/integration/test_phir.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,29 @@ def test_qparallel():

m = results["m"]
assert m.count("1111") == len(m)


@pytest.mark.optional_dependency() # uses projectq / state-vector
def test_bell_qparallel():
"""Testing a program creating and measuring a Bell state and using qparallel blocks returns expected results."""

results = HybridEngine(qsim="state-vector").run(
program=json.load(Path.open(this_dir / "phir" / "bell_qparallel.json")),
shots=20,
)

m = results["m"]
assert m.count("00") + m.count("11") == len(m)


def test_bell_qparallel_cliff():
"""Testing a program creating and measuring a Bell state and using qparallel blocks returns expected results (with
Clifford circuits and stabilizer sim)."""

results = HybridEngine(qsim="stabilizer").run(
program=json.load(Path.open(this_dir / "phir" / "bell_qparallel_cliff.json")),
shots=20,
)

m = results["m"]
assert m.count("00") + m.count("11") == len(m)
Loading