Skip to content

Commit

Permalink
feat: Add methods for identifying Quil-T instructions and filtering i…
Browse files Browse the repository at this point in the history
…nstructions from `Program`s (#323)



Co-authored-by: Mark Skilbeck <mark.skilbeck@rigetti.com>

---------

Co-authored-by: Mark Skilbeck <mark.skilbeck@rigetti.com>
  • Loading branch information
MarquessV and notmgsk authored Dec 14, 2023
1 parent 0b0c2c9 commit 556da96
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 26 deletions.
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 @@ -122,6 +122,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 wrap_in_loop(
self, loop_count_reference: MemoryReference, start_target: Target, end_target: Target, iterations: int
) -> "Program":
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 @@ -237,6 +237,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

0 comments on commit 556da96

Please sign in to comment.