Skip to content

Commit

Permalink
add Kalan's suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
BatmanAoD authored Feb 9, 2024
2 parents 5f3345c + 67961f9 commit 7fc8b9c
Show file tree
Hide file tree
Showing 39 changed files with 551 additions and 473 deletions.
2 changes: 1 addition & 1 deletion quil-rs/benches/scheduled_program_from_program.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion};
use quil_rs::{instruction::InstructionHandler, program::graph::ScheduledProgram};
use quil_rs::{instruction::InstructionHandler, program::scheduling::ScheduledProgram};
use std::str::FromStr;

mod corpus;
Expand Down
1 change: 0 additions & 1 deletion quil-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ pub(crate) mod parser;
pub mod program;
pub mod quil;
pub mod reserved;
pub mod stats;
pub mod validation;

pub use program::Program;
153 changes: 153 additions & 0 deletions quil-rs/src/program/analysis/control_flow_graph.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use crate::{
instruction::{Instruction, Jump, JumpUnless, JumpWhen, Label, Target},
Program,
};

#[derive(Clone, Debug, Default)]
pub struct ControlFlowGraph<'p> {
blocks: Vec<BasicBlock<'p>>,
}

impl<'p> ControlFlowGraph<'p> {
pub fn into_blocks(self) -> Vec<BasicBlock<'p>> {
self.blocks
}
}

#[derive(Clone, Debug, Default)]
pub struct BasicBlock<'p> {
label: Option<&'p Target>,
instructions: Vec<&'p Instruction>,
terminator: BasicBlockTerminator<'p>,
}

impl<'p> BasicBlock<'p> {
pub fn label(&self) -> Option<&Target> {
self.label
}

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

pub fn terminator(&self) -> &BasicBlockTerminator<'p> {
&self.terminator
}
}

#[derive(Clone, Debug, Default)]
pub enum BasicBlockTerminator<'p> {
#[default]
Continue,
Jump(&'p Jump),
JumpWhen(&'p JumpWhen),
JumpUnless(&'p JumpUnless),
Halt,
}

impl Program {
pub fn as_control_flow_graph(&self) -> ControlFlowGraph {
let mut graph = ControlFlowGraph::default();

let mut current_label = None;
let mut current_block_instructions = Vec::new();
for instruction in &self.instructions {
match instruction {
Instruction::Arithmetic(_)
| Instruction::BinaryLogic(_)
| Instruction::Capture(_)
| Instruction::Convert(_)
| Instruction::Comparison(_)
| Instruction::Delay(_)
| Instruction::Fence(_)
| Instruction::Exchange(_)
| Instruction::Gate(_)
| Instruction::Load(_)
| Instruction::Pragma(_)
| Instruction::Measurement(_)
| Instruction::Move(_)
| Instruction::Nop
| Instruction::Pulse(_)
| Instruction::RawCapture(_)
| Instruction::Reset(_)
| Instruction::SetFrequency(_)
| Instruction::SetPhase(_)
| Instruction::SetScale(_)
| Instruction::ShiftFrequency(_)
| Instruction::ShiftPhase(_)
| Instruction::Store(_)
| Instruction::SwapPhases(_)
| Instruction::UnaryLogic(_)
| Instruction::Wait => current_block_instructions.push(instruction),

Instruction::CalibrationDefinition(_)
| Instruction::CircuitDefinition(_)
| Instruction::Declaration(_)
| Instruction::FrameDefinition(_)
| Instruction::GateDefinition(_)
| Instruction::Include(_)
| Instruction::MeasureCalibrationDefinition(_)
| Instruction::WaveformDefinition(_) => {}

Instruction::Jump(_)
| Instruction::JumpUnless(_)
| Instruction::JumpWhen(_)
| Instruction::Label(_)
| Instruction::Halt => {
let (terminator, new_label) = match instruction {
Instruction::Jump(jump) => (BasicBlockTerminator::Jump(jump), None),
Instruction::JumpUnless(jump_unless) => {
(BasicBlockTerminator::JumpUnless(jump_unless), None)
}
Instruction::JumpWhen(jump_when) => {
(BasicBlockTerminator::JumpWhen(jump_when), None)
}
Instruction::Label(Label { target }) => {
(BasicBlockTerminator::Continue, Some(target))
}
Instruction::Halt => (BasicBlockTerminator::Halt, None),
_ => unreachable!(),
};
if !current_block_instructions.is_empty() {
let block = BasicBlock {
label: current_label.take(),
instructions: std::mem::take(&mut current_block_instructions),
terminator,
};
graph.blocks.push(block);
current_block_instructions = Vec::new();
}
current_label = new_label;
}
}
}

if !current_block_instructions.is_empty() || current_label.is_some() {
let block = BasicBlock {
label: current_label.take(),
instructions: current_block_instructions,
terminator: BasicBlockTerminator::Continue,
};
graph.blocks.push(block);
}

graph
}

pub fn get_first_basic_block(&self) -> Option<BasicBlock> {
self.as_control_flow_graph().blocks.into_iter().next()
}

pub fn get_only_basic_block(&self) -> Result<BasicBlock, ProgramContainsMultipleBasicBlocks> {
let blocks = self.as_control_flow_graph().blocks;
if blocks.len() == 1 {
Ok(blocks.into_iter().next().unwrap())
} else {
Err(ProgramContainsMultipleBasicBlocks)
}
}
}

#[derive(Debug, thiserror::Error)]
#[error("Program is empty or contains multiple basic blocks")]
pub struct ProgramContainsMultipleBasicBlocks;
4 changes: 4 additions & 0 deletions quil-rs/src/program/analysis/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod control_flow_graph;
mod stats;

pub use control_flow_graph::{BasicBlock, BasicBlockTerminator, ControlFlowGraph};
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ use std::ops::Neg;

use crate::{
instruction::{Instruction, Qubit},
program::graph::InstructionBlock,
program::scheduling::graph::ScheduledBasicBlock,
Program,
};
use execution_graph::{Error as ExecutionGraphError, ExecutionGraph};

use super::control_flow_graph::BasicBlock;

pub trait InstructionsSource {
type QubitSet;

Expand Down Expand Up @@ -66,15 +68,41 @@ impl InstructionsSource for Program {
}
}

impl<'p> InstructionsSource for BasicBlock<'p> {
type QubitSet = HashSet<&'p Qubit>;

fn is_empty(&self) -> bool {
self.instructions().is_empty()
}

fn len(&self) -> usize {
self.instructions().len()
}

fn body_instructions(&self) -> impl Iterator<Item = &Instruction> + '_ {
self.instructions().iter().copied()
}

fn get_used_qubits(&self) -> &Self::QubitSet {
todo!()
}
}

struct InstructionBlockWithQubitSet<'a, 'b> {
block: &'a InstructionBlock<'b>,
block: &'a BasicBlock<'b>,
qubits: HashSet<&'a Qubit>,
}

impl<'a, 'b> From<&'a InstructionBlock<'b>> for InstructionBlockWithQubitSet<'a, 'b> {
fn from(block: &'a InstructionBlock<'b>) -> Self {
impl<'a, 'b> From<&'a ScheduledBasicBlock<'b>> for InstructionBlockWithQubitSet<'a, 'b> {
fn from(block: &'a ScheduledBasicBlock<'b>) -> Self {
block.basic_block().into()
}
}

impl<'a, 'b> From<&'a BasicBlock<'b>> for InstructionBlockWithQubitSet<'a, 'b> {
fn from(block: &'a BasicBlock<'b>) -> Self {
let qubits = block
.instructions
.instructions()
.iter()
.filter_map(|i| match i {
Instruction::Gate(_) | Instruction::Measurement(_) => Some(i.get_qubits()),
Expand All @@ -99,7 +127,7 @@ impl<'a> InstructionsSource for InstructionBlockWithQubitSet<'a, '_> {

fn body_instructions(&self) -> impl Iterator<Item = &Instruction> + '_ {
// 'copied' converts the iterator of `&&Instruction` to an iterator of `&Instruction`
self.block.instructions.iter().copied()
self.block.instructions().iter().copied()
}

fn get_used_qubits(&self) -> &Self::QubitSet {
Expand Down Expand Up @@ -131,7 +159,19 @@ impl<'a> ProgramStats<&'a Program> {
}

impl<'a, 'b> ProgramStats<InstructionBlockWithQubitSet<'a, 'b>> {
pub fn from_block(block: &'a InstructionBlock<'b>) -> Self {
pub fn from_basic_block(block: &'a BasicBlock<'b>) -> Self {

Check warning on line 162 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / Check (stable)

associated function `from_basic_block` is never used

Check failure on line 162 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / Clippy (stable)

associated function `from_basic_block` is never used

Check warning on line 162 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / publish-docs

associated function `from_basic_block` is never used

Check warning on line 162 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable)

associated function `from_basic_block` is never used

Check warning on line 162 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / Run benchmarks (ubuntu-latest, stable)

associated function `from_basic_block` is never used

Check warning on line 162 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / Run benchmarks (macOS-latest, stable)

associated function `from_basic_block` is never used

Check warning on line 162 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / Run benchmarks (windows-latest, stable)

associated function `from_basic_block` is never used
let source = block.into();
let execution_graph = make_execution_graph(&source);

Self {
source,
execution_graph,
}
}
}

impl<'a, 'b> ProgramStats<InstructionBlockWithQubitSet<'a, 'b>> {
pub fn from_scheduled_basic_block(block: &'a ScheduledBasicBlock<'b>) -> Self {

Check warning on line 174 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / Check (stable)

associated function `from_scheduled_basic_block` is never used

Check failure on line 174 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / Clippy (stable)

associated function `from_scheduled_basic_block` is never used

Check warning on line 174 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / publish-docs

associated function `from_scheduled_basic_block` is never used

Check warning on line 174 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / Test Suite (stable)

associated function `from_scheduled_basic_block` is never used

Check warning on line 174 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / Run benchmarks (ubuntu-latest, stable)

associated function `from_scheduled_basic_block` is never used

Check warning on line 174 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / Run benchmarks (macOS-latest, stable)

associated function `from_scheduled_basic_block` is never used

Check warning on line 174 in quil-rs/src/program/analysis/stats/mod.rs

View workflow job for this annotation

GitHub Actions / Run benchmarks (windows-latest, stable)

associated function `from_scheduled_basic_block` is never used
let source = block.into();
let execution_graph = make_execution_graph(&source);

Expand Down Expand Up @@ -257,8 +297,6 @@ impl<S: InstructionsSource> ProgramStats<S> {
mod tests {
use std::f64::consts;

use crate::instruction::InstructionHandler;
use crate::program::graph::ScheduledProgram;
use crate::Program;

use rstest::rstest;
Expand All @@ -275,31 +313,14 @@ mod tests {
#[case(KITCHEN_SINK_QUIL, &[Qubit::Fixed(0), Qubit::Fixed(1)])]
fn block_instructions_from_program(#[case] input: &str, #[case] expected: &[Qubit]) {
let program: Program = input.parse().unwrap();
let scheduled =
ScheduledProgram::from_program(&program, &mut InstructionHandler::default()).unwrap();
let block = scheduled.blocks.first().unwrap().1;
let stats = ProgramStats::from_block(block);
let block = program.get_first_basic_block().unwrap();
let stats = ProgramStats::from_basic_block(&block);
let qubits = stats.qubits_used();
let expected = expected.iter().collect::<HashSet<_>>();

assert_eq!(&expected, qubits);
}

#[rstest]
#[case(QUIL_WITH_JUMP)]
#[case(QUIL_WITH_JUMP_WHEN)]
#[case(QUIL_WITH_JUMP_UNLESS)]
fn program_with_jumps_cannot_be_used_as_block(#[case] input: &str) {
let program: Program = input.parse().unwrap();
InstructionBlock::build(
program.body_instructions().collect(),
None,
&program,
&mut InstructionHandler::default(),
)
.unwrap_err();
}

#[rstest]
#[case(QUIL_AS_TREE, 3)]
#[case(QUIL_AS_INVERSE_TREE, 3)]
Expand Down
File renamed without changes.
6 changes: 2 additions & 4 deletions quil-rs/src/program/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ pub use self::frame::FrameSet;
pub use self::frame::MatchedFrames;
pub use self::memory::{MemoryAccesses, MemoryRegion};

pub mod analysis;
mod calibration;
mod error;
pub(crate) mod frame;
pub mod graph;
mod memory;
pub mod scheduling;
pub mod type_check;

#[derive(Debug, thiserror::Error, PartialEq)]
Expand All @@ -60,9 +61,6 @@ pub enum ProgramError {

type Result<T> = std::result::Result<T, ProgramError>;

#[cfg(feature = "graphviz-dot")]
pub mod graphviz_dot;

/// A Quil Program instance describes a quantum program with metadata used in execution.
///
/// This contains not only instructions which are executed in turn on the quantum processor, but
Expand Down
Loading

0 comments on commit 7fc8b9c

Please sign in to comment.