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

feat: Add methods for identifying Quil-T instructions and filtering instructions from Programs #323

Merged
merged 4 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
53 changes: 27 additions & 26 deletions quil-py/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions quil-py/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ maturin = "^1.2.3"
mypy = "^1.1.1"
pytest = "^7.2.2"
pdoc = "^14.1.0"
syrupy = "^3.0.6"

[tool.maturin]
features = ["pyo3/extension-module"]
Expand Down
5 changes: 5 additions & 0 deletions quil-py/quil/instructions/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ class Instruction:
"""
Returns a new ``Instruction`` from the given inner data.
"""
def is_quil_t(self) -> bool:
"""
Returns ``True`` if the instruction is a Quil-T instruction, ``False`` otherwise.
"""
...
def inner(
self,
) -> Union[
Expand Down
5 changes: 5 additions & 0 deletions quil-py/quil/program/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ class Program:
Convert the instruction to a Quil string. If any part of the instruction can't
be converted to valid Quil, it will be printed in a human-readable debug format.
"""
def filter_instructions(self, predicate: Callable[[Instruction], bool]) -> "Program":
"""
Return a new ``Program`` containing only the instructions for which ``predicate`` returns ``True``.
"""
...
def resolve_placeholders(self) -> None:
"""
Resolve ``TargetPlaceholder``s and ``QubitPlaceholder``s within the program using default resolvers.
Expand Down
5 changes: 5 additions & 0 deletions quil-py/src/instruction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use quil_rs::instruction::Instruction;
use rigetti_pyo3::{
create_init_submodule, impl_repr, py_wrap_union_enum,
pyo3::{pymethods, types::PyDict, PyResult, Python},
PyWrapper,
};

use crate::{impl_eq, impl_to_quil};
Expand Down Expand Up @@ -100,6 +101,10 @@ impl_eq!(PyInstruction);

#[pymethods]
impl PyInstruction {
pub fn is_quil_t(&self) -> bool {
self.as_inner().is_quil_t()
}

// Implement the __copy__ and __deepcopy__ dunder methods, which are used by Python's
// `copy` module.
//
Expand Down
13 changes: 13 additions & 0 deletions quil-py/src/program/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,19 @@ impl PyProgram {
.to_owned())
}

pub fn filter_instructions(&self, py: Python, predicate: Py<PyFunction>) -> PyResult<Self> {
let filtered = self.as_inner().filter_instructions(|inst| {
Python::with_gil(|py| {
predicate
.call1(py, (inst.to_python(py).unwrap(),))
.unwrap_or_else(|err| panic!("predicate function returned an error: {err}"))
.extract(py)
.unwrap_or_else(|err| panic!("predicate function must return a bool: {err}"))
})
});
filtered.to_python(py)
}

pub fn resolve_placeholders(&mut self) {
self.as_inner_mut().resolve_placeholders();
}
Expand Down
12 changes: 12 additions & 0 deletions quil-py/test/program/__snapshots__/test_program.ambr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# name: test_filter_instructions
'''
DECLARE foo REAL[1]
DEFGATE BAR AS MATRIX:
0, 1
1, 0

H 1
CNOT 2 3

'''
# ---
20 changes: 20 additions & 0 deletions quil-py/test/program/test_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import pytest
from typing import Optional

from syrupy.assertion import SnapshotAssertion

from quil.program import Program
from quil.instructions import Instruction, QubitPlaceholder, TargetPlaceholder, Gate, Qubit, Jump, Target

Expand Down Expand Up @@ -49,3 +51,21 @@ def target_resolver(target: TargetPlaceholder) -> Optional[str]:
print(program.to_quil_or_debug())

assert program.to_quil() == "H 9\nJUMP @test\n"


def test_filter_instructions(snapshot: SnapshotAssertion):
input = """DECLARE foo REAL[1]
DEFFRAME 1 "rx":
\tHARDWARE-OBJECT: "hardware"
DEFCAL I 1:
\tDELAY 0 1
DEFGATE BAR AS MATRIX:
\t0, 1
\t1, 0

H 1
CNOT 2 3
"""
program = Program.parse(input)
program_without_quil_t = program.filter_instructions(lambda instruction: not instruction.is_quil_t())
assert program_without_quil_t.to_quil() == snapshot
Loading
Loading