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

Fix how an instruction's used/blocked frames are calculated #74

Merged
merged 87 commits into from
Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
956967b
New: Expression#substitute_variables
kalzoo Mar 7, 2022
20cdefb
New: ProgramError
kalzoo Mar 7, 2022
96c1228
Update: parse DEFCAL MEASURE
kalzoo Mar 7, 2022
be3e7e5
New: Instruction#apply_to_expressions
kalzoo Mar 7, 2022
abf3692
Fix: parse DEFCAL MEASURE
kalzoo Mar 7, 2022
d2a7204
Update: add DEFCAL MEASURE expansion
kalzoo Mar 7, 2022
d18e5fd
Fix: tolerate program composition instructions in ScheduledProgram#build
kalzoo Mar 7, 2022
fed814b
Fix: consider PRAGMA a classical compute instruction
kalzoo Mar 7, 2022
0bdd847
Chore: add thiserror
kalzoo Mar 7, 2022
44fce8c
Chore: fmt
kalzoo Mar 7, 2022
165c4a7
Chore: lint
kalzoo Mar 7, 2022
fbc7afd
Chore: improve docs
kalzoo Mar 8, 2022
d0e4448
Decompose parse_defcal function
kalzoo Mar 8, 2022
e090669
Improve type annotation for apply_to_expression
kalzoo Mar 8, 2022
7a7eeb6
Chore: improve inline docs
kalzoo Mar 8, 2022
3c7ff00
Fix: PRAGMA display
kalzoo Mar 8, 2022
bdc4c13
Fix: DEFCAL MEASURE parsing
kalzoo Mar 8, 2022
14ce2d1
Improve DEFCAL MEASURE expansion readability
kalzoo Mar 8, 2022
9e99f00
Fix: construct CalibrationSet::default()
kalzoo Mar 8, 2022
653d0b2
Chore: fmt
kalzoo Mar 8, 2022
ee16e7e
Merge branch 'main' into 43-program-calibration-ux
kalzoo Mar 8, 2022
0929ef3
Merge branch 'main' into 43-program-calibration-ux
kalzoo Mar 8, 2022
8de8287
Release v0.8.4 [skip ci]
semantic-release-bot Mar 8, 2022
472ac22
chore: include latest Cargo.lock
nilslice Mar 7, 2022
3eda533
feat: update program to use btreemap for deterministic ordering
nilslice Mar 7, 2022
1fbda96
fix: remove unused imports
nilslice Mar 7, 2022
75a47ca
chore: add update check to cargo.lock in CI, include in assets list
nilslice Mar 7, 2022
9a2beff
chore: use single string input, revert from slice to check indicies
nilslice Mar 7, 2022
91140a5
fix: move cargo update inline with semantic-release prepare cmd
nilslice Mar 7, 2022
5e15122
Update: update Cargo.lock version (#52)
nilslice Mar 8, 2022
11dfd03
Release v0.8.5 [skip ci]
semantic-release-bot Mar 8, 2022
6165a1b
Update: add automated benchmarks for parsing quilc test programs (#53)
nilslice Mar 10, 2022
fdbb088
Release v0.8.6 [skip ci]
semantic-release-bot Mar 10, 2022
9522237
test use of criterion default baselines with archive (#56)
nilslice Mar 10, 2022
e143dc1
Fix: change quilc submodule to use HTTPS
notmgsk Mar 11, 2022
701bc61
Release v0.8.7 [skip ci]
semantic-release-bot Mar 11, 2022
c7293e0
Move graphviz-dot format writer to own module
kalzoo Apr 4, 2022
f0f925b
Install dot_writer
kalzoo Apr 5, 2022
a053a41
Breaking: revise graphviz dot generation API
kalzoo Apr 5, 2022
3e9aaed
Update: represent instructions as rectangles in program graphviz dot …
kalzoo Apr 5, 2022
fbe3400
Merge branch 'main' into 43-program-calibration-ux
kalzoo Apr 5, 2022
d71d455
Fix: error in memory access dependencies
kalzoo Apr 5, 2022
1f93ec0
Merge branch '43-program-calibration-ux' into feat/improve-dot-graphs
kalzoo Apr 5, 2022
ee25389
Chore: linter fix
kalzoo Apr 5, 2022
a68466d
Merge branch 'main' into feat/improve-dot-graphs
kalzoo Apr 27, 2022
d6b6751
Merge branch 'main' into 43-program-calibration-ux
kalzoo May 3, 2022
49669fd
Chore: improve apply_to_expressions docstring
kalzoo May 3, 2022
f196f9c
Merge branch '43-program-calibration-ux' into feat/improve-dot-graphs
kalzoo May 3, 2022
988304d
Chore: add top-level crate docs with links
kalzoo May 3, 2022
879e654
Chore: fix copyright notice header formatting
kalzoo May 3, 2022
ae10135
Chore: fix inline docstrings
kalzoo May 3, 2022
e32999e
Prefix instruction text with [index] in dotfile output
kalzoo May 3, 2022
c886fea
Merge branch 'main' into feat/improve-dot-graphs
kalzoo May 31, 2022
da9b72f
Move graphviz dot utility behind a feature flag
kalzoo May 31, 2022
402d95a
Chore: fix docstring
kalzoo May 31, 2022
dce1db5
Merge branch 'main' into feat/improve-dot-graphs
kalzoo May 31, 2022
d4bb33e
Chore: Test with --all-features in CI
kalzoo May 31, 2022
638c57d
Fix: move graphviz-dot tests out to conditional module
kalzoo May 31, 2022
72e44da
Chore: update test snapshots to include instruction index
kalzoo May 31, 2022
a39fb74
Chore: fmt
kalzoo Jun 1, 2022
4dffc79
Add private method for parsing a single instruction from a string
kalzoo Jun 1, 2022
6e89899
WIP: Match frames by composable condition
kalzoo Jun 1, 2022
42d0e59
Remove extraneous println
kalzoo Jun 1, 2022
3e97880
Fix: instruction frame blocking
kalzoo Jun 1, 2022
c0ca7bc
Chore: fmt
kalzoo Jun 1, 2022
18f2cce
Fix visibility of Instruction::parse
kalzoo Jun 1, 2022
f770f5a
Fix: frame dependency calculation in ScheduledProgram
kalzoo Jun 1, 2022
000bf2a
Fix how FENCE uses frames
kalzoo Jun 1, 2022
f559868
Chore: fix tests for new frame-blocking behavior
kalzoo Jun 1, 2022
2ba1d1b
Chore: linter fixes
kalzoo Jun 1, 2022
48d5751
Chore: fmt
kalzoo Jun 1, 2022
b3958b8
Chore: linter fixes & inline doc
kalzoo Jun 1, 2022
23d5d00
Merge branch 'main' into feat/improve-dot-graphs
kalzoo Jun 1, 2022
c99dc16
Merge branch 'feat/improve-dot-graphs' into 72-instruction-frames
kalzoo Jun 1, 2022
083824b
Chore: fix inconsistent copyright headers
kalzoo Jun 1, 2022
d97394a
Chore: fix test
kalzoo Jun 1, 2022
87d84de
Chore: update snapshots after merge
kalzoo Jun 1, 2022
a48b73e
Chore: fix tests after merge from main
kalzoo Jun 1, 2022
093b922
Merge branch 'feat/improve-dot-graphs' into 72-instruction-frames
kalzoo Jun 1, 2022
68a2fde
Chore: code cleanup
kalzoo Jun 1, 2022
67a74aa
Fix bug in DELAY frame utilization
kalzoo Jun 1, 2022
41249bc
Chore: remove dead code
kalzoo Jun 1, 2022
3cacfcf
Chore: fix docstring
kalzoo Jun 1, 2022
2c86648
Chore: make test cases more readable
kalzoo Jun 1, 2022
98b903a
Simplify frame dependency code
kalzoo Jun 1, 2022
4cabba8
Add Instruction.get_frame_match_condition
kalzoo Jun 1, 2022
ed32aa4
Merge branch 'main' into 72-instruction-frames
kalzoo Jun 2, 2022
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
85 changes: 85 additions & 0 deletions src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fmt};

use crate::expression::Expression;
use crate::program::frame::FrameMatchCondition;

#[cfg(test)]
use proptest_derive::Arbitrary;
Expand Down Expand Up @@ -941,6 +942,90 @@ impl Instruction {
_ => {}
}
}

pub(crate) fn get_frame_match_condition(
&self,
include_blocked: bool,
) -> Option<FrameMatchCondition> {
match self {
Instruction::Pulse(Pulse {
blocking, frame, ..
})
| Instruction::Capture(Capture {
blocking, frame, ..
})
| Instruction::RawCapture(RawCapture {
blocking, frame, ..
}) => Some(if *blocking && include_blocked {
FrameMatchCondition::AnyOfQubits(&frame.qubits)
} else {
FrameMatchCondition::Specific(frame)
}),
Instruction::Delay(Delay {
frame_names,
qubits,
..
}) => Some(if frame_names.is_empty() {
FrameMatchCondition::ExactQubits(qubits)
} else {
FrameMatchCondition::And(vec![
FrameMatchCondition::ExactQubits(qubits),
FrameMatchCondition::AnyOfNames(frame_names),
])
}),
Instruction::Fence(Fence { qubits }) => Some(if qubits.is_empty() {
FrameMatchCondition::All
} else {
FrameMatchCondition::AnyOfQubits(qubits)
}),
Instruction::SetFrequency(SetFrequency { frame, .. })
| Instruction::SetPhase(SetPhase { frame, .. })
| Instruction::SetScale(SetScale { frame, .. })
| Instruction::ShiftFrequency(ShiftFrequency { frame, .. })
| Instruction::ShiftPhase(ShiftPhase { frame, .. }) => {
Some(FrameMatchCondition::Specific(frame))
}
Instruction::SwapPhases(SwapPhases { frame_1, frame_2 }) => {
Some(FrameMatchCondition::And(vec![
FrameMatchCondition::Specific(frame_1),
FrameMatchCondition::Specific(frame_2),
]))
}
Instruction::Gate(_)
| Instruction::CircuitDefinition(_)
| Instruction::GateDefinition(_)
| Instruction::Declaration(_)
| Instruction::Measurement(_)
| Instruction::Reset(_)
| Instruction::CalibrationDefinition(_)
| Instruction::FrameDefinition(_)
| Instruction::MeasureCalibrationDefinition(_)
| Instruction::Pragma(_)
| Instruction::WaveformDefinition(_)
| Instruction::Arithmetic(_)
| Instruction::Halt
| Instruction::Label(_)
| Instruction::Move(_)
| Instruction::Exchange(_)
| Instruction::Load(_)
| Instruction::Store(_)
| Instruction::Jump(_)
| Instruction::JumpWhen(_)
| Instruction::JumpUnless(_) => None,
}
}

#[cfg(test)]
/// Parse a single instruction from an input string. Returns an error if the input fails to parse,
/// or if there is input left over after parsing.
pub(crate) fn parse(input: &str) -> Result<Self, String> {
use crate::parser::{instruction::parse_instruction, lex};

let lexed = lex(input)?;
let (_, instruction) =
nom::combinator::all_consuming(parse_instruction)(&lexed).map_err(|e| e.to_string())?;
Ok(instruction)
}
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ mod macros;
mod common;
mod error;
mod expression;
mod instruction;
pub(crate) mod instruction;
mod lexer;

type ParserInput<'a> = &'a [Token];
Expand Down
73 changes: 61 additions & 12 deletions src/program/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,47 @@ impl FrameSet {
self.frames.keys().collect()
}

/// Return all contained FrameIdentifiers which include **exactly** these qubits (in any order)
/// and - if names are provided - match one of the names.
pub fn get_matching_keys(&self, qubits: &[Qubit], names: &[String]) -> Vec<&FrameIdentifier> {
let qubit_set: HashSet<&Qubit> = qubits.iter().collect();
self.frames
.iter()
.filter(|(identifier, _)| {
(names.is_empty() || names.contains(&identifier.name))
&& qubit_set == identifier.qubits.iter().collect()
})
.map(|(id, _)| id)
.collect::<Vec<_>>()
/// Return all frames in the set which match all of these conditions. If a frame _would_ match, but is
/// not present in this [FrameSet], then it is not returned (notably, the [FrameMatchCondition::Specific]
/// match condition).
pub(crate) fn get_matching_keys<'s, 'a>(
&'s self,
condition: FrameMatchCondition<'a>,
) -> HashSet<&'s FrameIdentifier> {
let keys = self.frames.keys();

match condition {
FrameMatchCondition::All => keys.collect(),
FrameMatchCondition::AnyOfNames(names) => {
keys.filter(|&f| names.contains(&f.name)).collect()
}
FrameMatchCondition::AnyOfQubits(qubits) => {
let any_of_set: HashSet<_> = qubits.iter().collect();

keys.filter(|&f| f.qubits.iter().any(|q| any_of_set.contains(q)))
.collect()
}
FrameMatchCondition::ExactQubits(qubits) => {
let exact_set: HashSet<_> = qubits.iter().collect();

keys.filter(|&f| f.qubits.iter().collect::<HashSet<_>>() == exact_set)
.collect()
}
FrameMatchCondition::Specific(frame) => {
// This unusual pattern (fetch key & value by key, discard value) allows us to return
// a reference to `self` rather than `condition`, keeping lifetimes simpler.
if let Some((frame, _)) = self.frames.get_key_value(frame) {
vec![frame].into_iter().collect()
} else {
HashSet::new()
}
}
FrameMatchCondition::And(conditions) => conditions
.into_iter()
.map(|c| self.get_matching_keys(c))
.reduce(|acc, el| acc.into_iter().filter(|&v| el.contains(v)).collect())
.unwrap_or_default(),
}
}

/// Retrieve the attributes of a frame by its identifier.
Expand Down Expand Up @@ -86,3 +115,23 @@ impl FrameSet {
.collect()
}
}

pub(crate) enum FrameMatchCondition<'a> {
/// Match all frames in the set
All,

/// Match all frames which share any one of these names
AnyOfNames(&'a [String]),

/// Match all frames which contain any of these qubits
AnyOfQubits(&'a [Qubit]),

/// Match all frames which contain exactly these qubits
ExactQubits(&'a [Qubit]),

/// Return these specific frames, if present in the set
Specific(&'a FrameIdentifier),

/// Return all frames which match all of these conditions
And(Vec<FrameMatchCondition<'a>>),
}
25 changes: 16 additions & 9 deletions src/program/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,19 +233,26 @@ impl InstructionBlock {
Ok(())
}
InstructionRole::RFControl => {
let frames = match program.get_frames_for_instruction(instruction, true) {
Some(frames) => frames,
None => vec![],
};

// Mark a dependency on the last instruction which executed in the context of each target frame
for frame in frames {
let used_frames = program
.get_frames_for_instruction(instruction, false)
.unwrap_or_default();
let blocked_frames = program
.get_frames_for_instruction(instruction, true)
.unwrap_or_default();

// Take a dependency on any previous instructions to _block_ a frame which this instruction _uses_.
for frame in used_frames {
let previous_node_id = last_instruction_by_frame
.entry(frame.clone())
.or_insert(ScheduledGraphNode::BlockStart);
.get(frame)
.unwrap_or(&ScheduledGraphNode::BlockStart);
add_dependency!(graph, *previous_node_id => node, ExecutionDependency::ReferenceFrame);
}

// We mark all "blocked" frames as such for later instructions to take a dependency on
for frame in blocked_frames {
last_instruction_by_frame.insert(frame.clone(), node);
}

Ok(())
}
InstructionRole::ControlFlow => Err(ScheduleError {
Expand Down
13 changes: 13 additions & 0 deletions src/program/graphviz_dot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ DEFFRAME 0 \"ro_rx\":
INITIAL-FREQUENCY: 1e6
DEFFRAME 0 \"ro_tx\":
INITIAL-FREQUENCY: 1e6
DEFFRAME 0 1 \"cz\":
INITIAL-FREQUENCY: 1e6
";

let program =
Expand Down Expand Up @@ -308,8 +310,19 @@ NONBLOCKING PULSE 0 \"rf\" test(duration: 1e6)
NONBLOCKING PULSE 1 \"rf\" test(duration: 1e6)
"
);

build_dot_format_snapshot_test_case!(fence_all, "FENCE");

build_dot_format_snapshot_test_case!(
fence_wrapper,
"
FENCE
NONBLOCKING PULSE 0 1 \"cz\" test(duration: 1e-6)
NONBLOCKING PULSE 1 \"rf\" test(duration: 1e-6)
FENCE 1
"
);

build_dot_format_snapshot_test_case!(
jump,
"DECLARE ro BIT
Expand Down
Loading