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: Support getting and constructing BasicBlocks. #359

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
25 changes: 11 additions & 14 deletions quil-py/quil/program/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from typing import Dict, FrozenSet, Set, final, List, Optional, Sequence, Callable
from typing import Callable, Dict, FrozenSet, List, Optional, Sequence, Set, final

import numpy as np
from numpy.typing import NDArray

from quil.instructions import (
AttributeValue,
Calibration,
Expand All @@ -14,12 +15,12 @@ from quil.instructions import (
Measurement,
MemoryReference,
Qubit,
QubitPlaceholder,
Sharing,
Target,
TargetPlaceholder,
Vector,
Waveform,
TargetPlaceholder,
QubitPlaceholder,
)

@final
Expand Down Expand Up @@ -182,13 +183,11 @@ class Program:
.. _control flow graph: https://en.wikipedia.org/wiki/Control-flow_graph
"""

@final
class BasicBlock:
def as_schedule_seconds(self, program: Program) -> ScheduleSeconds:
"""
Return the ``ScheduleSeconds`` representing the timing of the instructions within the block.

This schedule is computed by:

* Expanding each instruction within the block using the program's calibration definitions
* Resolving the `ScheduleSeconds` of the expanded instructions
Expand Down Expand Up @@ -330,7 +329,9 @@ class CalibrationSet:
function returns the previous calibration. Otherwise, None is returned.
"""
...
def insert_measurement_calibration(self, calibration: MeasureCalibrationDefinition) -> Optional[MeasureCalibrationDefinition]:
def insert_measurement_calibration(
self, calibration: MeasureCalibrationDefinition
) -> Optional[MeasureCalibrationDefinition]:
"""
MarquessV marked this conversation as resolved.
Show resolved Hide resolved
Add another ``MeasureCalibrationDefinition`` (`DEFCAL MEASURE`) to the set

Expand All @@ -348,12 +349,11 @@ class CalibrationSet:
"""
...


@final
class ScheduleSecondsItem:
"""
A single item within a fixed schedule, representing a single instruction within a basic block.
"""

@property
def instruction_index(self) -> int:
"""
Expand All @@ -365,8 +365,6 @@ class ScheduleSecondsItem:
The time span during which the instruction is scheduled.
"""


@final
class ControlFlowGraph:
"""
Representation of a control flow graph (CFG) for a Quil program.
Expand All @@ -375,20 +373,19 @@ class ControlFlowGraph:
transition between two basic blocks.
"""

def has_dynamic_control_flow(self) -> bool:
def has_dynamic_control_flow(self) -> bool:
"""
Return ``True`` if the program has dynamic control flow, i.e. contains a conditional branch instruction.

``False`` does not imply that there is only one basic block in the program. Multiple basic blocks may have
non-conditional control flow among them, in which the execution order is deterministic and does not depend
on program state. This may be a sequence of basic blocks with fixed `JUMP`s or without explicit terminators.
"""
def basic_blocks(self) -> List["BasicBlock"]:
def basic_blocks(self) -> List["BasicBlock"]:
"""
Return a list of all the basic blocks in the control flow graph, in order of definition.
"""

@final
class ScheduleSeconds:
def items(self) -> List[ScheduleSecondsItem]:
"""
Expand All @@ -401,11 +398,11 @@ class ScheduleSeconds:
This is the maximum of the end time of all the items.
"""

@final
class TimeSpanSeconds:
"""
Representation of a time span in seconds.
"""

@property
def start(self) -> float:
"""
Expand Down
10 changes: 9 additions & 1 deletion quil-py/src/program/analysis.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use pyo3::exceptions::PyValueError;
use pyo3::{exceptions::PyValueError, types::PyType};
use quil_rs::program::analysis::{
BasicBlock, BasicBlockOwned, BasicBlockScheduleError, ControlFlowGraph, ControlFlowGraphOwned,
QubitGraph, QubitGraphError,
Expand All @@ -12,6 +12,7 @@ use crate::instruction::{PyInstruction, PyTarget};
use super::{scheduling::PyScheduleSeconds, PyProgram};

py_wrap_type! {
#[pyo3(subclass)]
PyControlFlowGraph(ControlFlowGraphOwned) as "ControlFlowGraph"
}

Expand All @@ -34,6 +35,7 @@ impl PyControlFlowGraph {
}

py_wrap_type! {
#[pyo3(subclass)]
PyBasicBlock(BasicBlockOwned) as "BasicBlock"
}
impl_repr!(PyBasicBlock);
Expand All @@ -51,6 +53,12 @@ py_wrap_error!(quil, RustQubitGraphError, PyQubitGraphError, PyValueError);

#[pymethods]
impl PyBasicBlock {
#[new]
#[classmethod]
pub fn new(_: Py<PyType>, instance: Self) -> Self {
instance
}

pub fn as_schedule_seconds(&self, program: &PyProgram) -> PyResult<PyScheduleSeconds> {
BasicBlock::from(self.as_inner())
.as_schedule_seconds(program.as_inner())
Expand Down
11 changes: 11 additions & 0 deletions quil-py/src/program/scheduling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use rigetti_pyo3::{
impl_repr, py_wrap_error, py_wrap_type, pyo3::prelude::*, wrap_error, PyWrapper,
};

use crate::impl_eq;

wrap_error!(RustComputedScheduleError(ComputedScheduleError));
py_wrap_error!(
quil,
Expand All @@ -14,10 +16,13 @@ py_wrap_error!(
PyValueError
);
py_wrap_type! {
#[pyo3(subclass)]
#[derive(Debug, PartialEq)]
PyScheduleSeconds(ScheduleSeconds) as "ScheduleSeconds"
}

impl_repr!(PyScheduleSeconds);
impl_eq!(PyScheduleSeconds);

#[pymethods]
impl PyScheduleSeconds {
Expand All @@ -35,10 +40,13 @@ impl PyScheduleSeconds {
}

py_wrap_type! {
#[derive(Debug, PartialEq)]
#[pyo3(subclass)]
PyScheduleSecondsItem(ComputedScheduleItem<Seconds>) as "ScheduleSecondsItem"
}

impl_repr!(PyScheduleSecondsItem);
impl_eq!(PyScheduleSecondsItem);

#[pymethods]
impl PyScheduleSecondsItem {
Expand All @@ -54,10 +62,13 @@ impl PyScheduleSecondsItem {
}

py_wrap_type! {
#[derive(Debug, PartialEq)]
#[pyo3(subclass)]
PyTimeSpanSeconds(TimeSpan<Seconds>) as "TimeSpanSeconds"
}

impl_repr!(PyTimeSpanSeconds);
impl_eq!(PyTimeSpanSeconds);

#[pymethods]
impl PyTimeSpanSeconds {
Expand Down
33 changes: 32 additions & 1 deletion quil-rs/src/program/analysis/control_flow_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,37 @@ pub struct BasicBlockOwned {
terminator: BasicBlockTerminatorOwned,
}

impl BasicBlockOwned {
pub fn new(
label: Option<Target>,
instructions: Vec<Instruction>,
instruction_index_offset: usize,
terminator: BasicBlockTerminatorOwned,
) -> Self {
BasicBlockOwned {
label,
instructions,
instruction_index_offset,
terminator,
}
}
pub fn label(&self) -> Option<&Target> {
self.label.as_ref()
}

pub fn instructions(&self) -> &[Instruction] {
&self.instructions
}

pub fn instruction_index_offset(&self) -> usize {
self.instruction_index_offset
}

pub fn terminator(&self) -> &BasicBlockTerminatorOwned {
&self.terminator
}
}
MarquessV marked this conversation as resolved.
Show resolved Hide resolved

impl From<BasicBlock<'_>> for BasicBlockOwned {
fn from(value: BasicBlock) -> Self {
let label = value.label.cloned();
Expand Down Expand Up @@ -352,7 +383,7 @@ impl BasicBlockTerminator<'_> {
}
}

#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, PartialEq)]
pub enum BasicBlockTerminatorOwned {
ConditionalJump {
condition: MemoryReference,
Expand Down
Loading