Skip to content

Commit

Permalink
feat!: introduce ExecutionDependency::Scheduled (#186)
Browse files Browse the repository at this point in the history
* feat!: introduce ExecutionDependency::Timing

* refactor: timing -> scheduling

---------

Co-authored-by: Mark Skilbeck <mark.skilbeck@rigetti.com>
  • Loading branch information
kalzoo and notmgsk committed Apr 21, 2023
1 parent 1b6b8ca commit ec7b1b2
Show file tree
Hide file tree
Showing 23 changed files with 479 additions and 167 deletions.
62 changes: 57 additions & 5 deletions src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1208,11 +1208,17 @@ impl Instruction {
FrameMatchCondition::AnyOfNames(frame_names),
])
}),
Instruction::Fence(Fence { qubits }) => Some(if qubits.is_empty() {
FrameMatchCondition::All
} else {
FrameMatchCondition::AnyOfQubits(Cow::Borrowed(qubits))
}),
Instruction::Fence(Fence { qubits }) => {
if include_blocked {
Some(if qubits.is_empty() {
FrameMatchCondition::All
} else {
FrameMatchCondition::AnyOfQubits(Cow::Borrowed(qubits))
})
} else {
None
}
}
Instruction::Reset(Reset { qubit }) => {
let qubits = match qubit {
Some(qubit) => {
Expand Down Expand Up @@ -1296,6 +1302,52 @@ impl Instruction {
nom::combinator::all_consuming(parse_instruction)(&lexed).map_err(|e| e.to_string())?;
Ok(instruction)
}

/// Per the Quil-T spec, whether this instruction's timing within the pulse
/// program must be precisely controlled so as to begin exactly on the end of
/// the latest preceding timed instruction
pub(crate) fn is_scheduled(&self) -> bool {
match self {
Instruction::Capture(_)
| Instruction::Delay(_)
| Instruction::Fence(_)
| Instruction::Pulse(_)
| Instruction::RawCapture(_) => true,
Instruction::Arithmetic(_)
| Instruction::BinaryLogic(_)
| Instruction::CalibrationDefinition(_)
| Instruction::CircuitDefinition(_)
| Instruction::Convert(_)
| Instruction::Comparison(_)
| Instruction::Declaration(_)
| Instruction::Exchange(_)
| Instruction::FrameDefinition(_)
| Instruction::Gate(_)
| Instruction::GateDefinition(_)
| Instruction::Halt
| Instruction::Include(_)
| Instruction::Jump(_)
| Instruction::JumpUnless(_)
| Instruction::JumpWhen(_)
| Instruction::Label(_)
| Instruction::Load(_)
| Instruction::MeasureCalibrationDefinition(_)
| Instruction::Measurement(_)
| Instruction::Move(_)
| Instruction::Nop
| Instruction::Pragma(_)
| Instruction::Reset(_)
| Instruction::SetFrequency(_)
| Instruction::SetPhase(_)
| Instruction::SetScale(_)
| Instruction::ShiftFrequency(_)
| Instruction::ShiftPhase(_)
| Instruction::Store(_)
| Instruction::SwapPhases(_)
| Instruction::UnaryLogic(_)
| Instruction::WaveformDefinition(_) => false,
}
}
}

#[cfg(test)]
Expand Down
56 changes: 45 additions & 11 deletions src/program/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,10 @@ pub enum ExecutionDependency {
/// The downstream instruction must wait for the given operation to complete.
AwaitMemoryAccess(MemoryAccessType),

/// The instructions share a reference frame
ReferenceFrame,
/// The schedule of the downstream instruction depends on the upstream instruction.
/// Per the Quil-T specification, the downstream instruction begins execution at
/// the time that its latest upstream neighbor completes.
Scheduled,

/// The ordering between these two instructions must remain unchanged
StableOrdering,
Expand Down Expand Up @@ -217,7 +219,8 @@ impl Default for InstructionBlock {
///
/// ## Examples
///
/// Note that "depends on" is equivalent to "must execute after completion of".
/// Note that "depends on" is equivalent to "must execute at or after completion of." The interpretation of
/// "at or after" depends on the type of dependency and the compiler.
///
/// ```text
/// user --> user # a second user takes a dependency on the first
Expand All @@ -236,12 +239,14 @@ struct PreviousNodes {

impl Default for PreviousNodes {
/// The default value for [PreviousNodes] is useful in that, if no previous nodes have been recorded
/// as using a frame, we should consider that the start of the instruction block "blocks" use of that frame
/// (in other words, this instruction cannot be scheduled prior to the start of the instruction block).
/// as using a frame, we should consider that the start of the instruction block "uses" of that frame
///
/// In other words, no instruction can be scheduled prior to the start of the instruction block
/// and all scheduled instructions within the block depend on the block's start time, at least indirectly.
fn default() -> Self {
Self {
using: None,
blocking: vec![ScheduledGraphNode::BlockStart].into_iter().collect(),
using: Some(ScheduledGraphNode::BlockStart),
blocking: HashSet::new(),
}
}
}
Expand Down Expand Up @@ -299,6 +304,8 @@ impl InstructionBlock {

// Store the instruction index of the last instruction to block that frame
let mut last_instruction_by_frame: HashMap<FrameIdentifier, PreviousNodes> = HashMap::new();
let mut last_timed_instruction_by_frame: HashMap<FrameIdentifier, PreviousNodes> =
HashMap::new();

// Store memory access reads and writes. Key is memory region name.
// NOTE: this may be refined to serialize by memory region offset rather than by entire region.
Expand All @@ -309,7 +316,7 @@ impl InstructionBlock {

let instruction_role = InstructionRole::from(instruction);
match instruction_role {
// Classical instructions must be strongly ordered by appearance in the program
// Classical instructions must be ordered by appearance in the program
InstructionRole::ClassicalCompute => {
add_dependency!(graph, last_classical_instruction => node, ExecutionDependency::StableOrdering);

Expand All @@ -328,23 +335,44 @@ impl InstructionBlock {
let blocked_but_not_used_frames = blocked_frames.difference(&used_frames);

for frame in &used_frames {
if instruction.is_scheduled() {
let previous_node_ids = last_timed_instruction_by_frame
.entry((*frame).clone())
.or_default()
.get_dependencies_for_next_user(node);

for previous_node_id in previous_node_ids {
add_dependency!(graph, previous_node_id => node, ExecutionDependency::Scheduled);
}
}

let previous_node_ids = last_instruction_by_frame
.entry((*frame).clone())
.or_default()
.get_dependencies_for_next_user(node);

for previous_node_id in previous_node_ids {
add_dependency!(graph, previous_node_id => node, ExecutionDependency::ReferenceFrame);
add_dependency!(graph, previous_node_id => node, ExecutionDependency::StableOrdering);
}
}

for frame in blocked_but_not_used_frames {
if instruction.is_scheduled() {
if let Some(previous_node_id) = last_timed_instruction_by_frame
.entry((*frame).clone())
.or_default()
.get_dependency_for_next_blocker(node)
{
add_dependency!(graph, previous_node_id => node, ExecutionDependency::Scheduled);
}
}

if let Some(previous_node_id) = last_instruction_by_frame
.entry((*frame).clone())
.or_default()
.get_dependency_for_next_blocker(node)
{
add_dependency!(graph, previous_node_id => node, ExecutionDependency::ReferenceFrame);
add_dependency!(graph, previous_node_id => node, ExecutionDependency::StableOrdering);
}
}

Expand Down Expand Up @@ -390,9 +418,15 @@ impl InstructionBlock {
// does not terminate until these are complete
add_dependency!(graph, last_classical_instruction => ScheduledGraphNode::BlockEnd, ExecutionDependency::StableOrdering);

for previous_nodes in last_timed_instruction_by_frame.into_values() {
for node in previous_nodes.drain() {
add_dependency!(graph, node => ScheduledGraphNode::BlockEnd, ExecutionDependency::Scheduled);
}
}

for previous_nodes in last_instruction_by_frame.into_values() {
for node in previous_nodes.drain() {
add_dependency!(graph, node => ScheduledGraphNode::BlockEnd, ExecutionDependency::ReferenceFrame);
add_dependency!(graph, node => ScheduledGraphNode::BlockEnd, ExecutionDependency::StableOrdering);
}
}

Expand Down
19 changes: 18 additions & 1 deletion src/program/graphviz_dot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl InstructionBlock {
MemoryAccessType::Write => "await write",
MemoryAccessType::Capture => "await capture",
},
ExecutionDependency::ReferenceFrame => "frame",
ExecutionDependency::Scheduled => "timing",
ExecutionDependency::StableOrdering => "ordering",
})
.collect::<Vec<&str>>();
Expand Down Expand Up @@ -352,6 +352,15 @@ FENCE 1
"
);

build_dot_format_snapshot_test_case!(
fence_one_wrapper,
r#"
FENCE 0
NONBLOCKING PULSE 0 "rf" flat(iq: 1, duration: 4e-7)
FENCE 0
"#
);

build_dot_format_snapshot_test_case!(
jump,
"DECLARE ro BIT
Expand Down Expand Up @@ -413,6 +422,14 @@ CAPTURE 0 \"ro_rx\" test ro
PULSE 0 \"rf\" test"
);

// assert that a block "waits" for a capture to complete even with a pulse after it
build_dot_format_snapshot_test_case!(
pulse_after_set_frequency,
r#"DECLARE ro BIT
SET-FREQUENCY 0 "rf" 3e9
PULSE 0 "rf" test"#
);

// assert that a block "waits" for a capture to complete
build_dot_format_snapshot_test_case!(
parametric_pulse,
Expand Down
8 changes: 2 additions & 6 deletions src/program/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,15 +471,11 @@ DEFFRAME 0 1 \"2q\":
vec![r#"0 1 "2q""#],
),
// A Fence with qubits specified uses and blocks all frames intersecting that qubit
(
r#"FENCE 1"#,
vec![r#"1 "c""#, r#"0 1 "2q""#],
vec![r#"1 "c""#, r#"0 1 "2q""#],
),
(r#"FENCE 1"#, vec![], vec![r#"1 "c""#, r#"0 1 "2q""#]),
// Fence-all uses and blocks all frames declared in the program
(
r#"FENCE"#,
vec![r#"0 "a""#, r#"0 "b""#, r#"1 "c""#, r#"0 1 "2q""#],
vec![],
vec![r#"0 "a""#, r#"0 "b""#, r#"1 "c""#, r#"0 1 "2q""#],
),
// Delay uses and blocks frames on exactly the given qubits and with any of the given names
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ digraph {
label="measure";
node [style="filled"];
"measure_start" [shape=circle, label="start"];
"measure_start" -> "measure_0" [label="frame"];
"measure_start" -> "measure_1" [label="frame"];
"measure_start" -> "measure_0" [label="ordering
timing"];
"measure_start" -> "measure_1" [label="ordering
timing"];
"measure_start" -> "measure_end" [label="ordering"];
"measure_0" [shape=rectangle, label="[0] NONBLOCKING PULSE 0 \"ro_tx\" test(duration: 1000000)"];
"measure_0" -> "measure_end" [label="frame"];
"measure_0" -> "measure_end" [label="ordering
timing"];
"measure_1" [shape=rectangle, label="[1] NONBLOCKING CAPTURE 0 \"ro_rx\" test(duration: 1000000) ro[0]"];
"measure_1" -> "measure_end" [label="await capture
frame"];
ordering
timing"];
"measure_end" [shape=circle, label="end"];
}
"measure_end" -> "end_start" [label="if ro[0] == 0"];
Expand All @@ -25,11 +29,13 @@ frame"];
label="feedback";
node [style="filled"];
"feedback_start" [shape=circle, label="start"];
"feedback_start" -> "feedback_0" [label="frame"];
"feedback_start" -> "feedback_end" [label="frame
ordering"];
"feedback_start" -> "feedback_0" [label="ordering
timing"];
"feedback_start" -> "feedback_end" [label="ordering
timing"];
"feedback_0" [shape=rectangle, label="[0] PULSE 0 \"rf\" test(duration: 1000000)"];
"feedback_0" -> "feedback_end" [label="frame"];
"feedback_0" -> "feedback_end" [label="ordering
timing"];
"feedback_end" [shape=circle, label="end"];
}
"feedback_end" -> "measure_start" [label="always"];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,27 @@ digraph {
label="block_0";
node [style="filled"];
"block_0_start" [shape=circle, label="start"];
"block_0_start" -> "block_0_0" [label="frame"];
"block_0_start" -> "block_0_1" [label="frame"];
"block_0_start" -> "block_0_2" [label="frame"];
"block_0_start" -> "block_0_end" [label="frame
ordering"];
"block_0_start" -> "block_0_0" [label="ordering
timing"];
"block_0_start" -> "block_0_1" [label="ordering
timing"];
"block_0_start" -> "block_0_2" [label="ordering
timing"];
"block_0_start" -> "block_0_end" [label="ordering
timing"];
"block_0_0" [shape=rectangle, label="[0] PULSE 0 \"rf\" test(duration: 1e-6)"];
"block_0_0" -> "block_0_2" [label="frame"];
"block_0_0" -> "block_0_end" [label="frame"];
"block_0_0" -> "block_0_2" [label="ordering
timing"];
"block_0_0" -> "block_0_end" [label="ordering
timing"];
"block_0_1" [shape=rectangle, label="[1] PULSE 1 \"rf\" test(duration: 1e-6)"];
"block_0_1" -> "block_0_2" [label="frame"];
"block_0_1" -> "block_0_end" [label="frame"];
"block_0_1" -> "block_0_2" [label="ordering
timing"];
"block_0_1" -> "block_0_end" [label="ordering
timing"];
"block_0_2" [shape=rectangle, label="[2] PULSE 0 1 \"cz\" test(duration: 1e-6)"];
"block_0_2" -> "block_0_end" [label="frame"];
"block_0_2" -> "block_0_end" [label="ordering
timing"];
"block_0_end" [shape=circle, label="end"];
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,29 @@ digraph {
label="block_0";
node [style="filled"];
"block_0_start" [shape=circle, label="start"];
"block_0_start" -> "block_0_0" [label="frame"];
"block_0_start" -> "block_0_1" [label="frame"];
"block_0_start" -> "block_0_2" [label="frame"];
"block_0_start" -> "block_0_end" [label="frame
ordering"];
"block_0_start" -> "block_0_0" [label="ordering
timing"];
"block_0_start" -> "block_0_1" [label="ordering
timing"];
"block_0_start" -> "block_0_2" [label="ordering
timing"];
"block_0_start" -> "block_0_end" [label="ordering
timing"];
"block_0_0" [shape=rectangle, label="[0] NONBLOCKING PULSE 0 \"ro_tx\" test(duration: 1000000)"];
"block_0_0" -> "block_0_1" [label="frame"];
"block_0_0" -> "block_0_2" [label="frame"];
"block_0_0" -> "block_0_end" [label="frame"];
"block_0_0" -> "block_0_1" [label="ordering
timing"];
"block_0_0" -> "block_0_2" [label="ordering
timing"];
"block_0_0" -> "block_0_end" [label="ordering
timing"];
"block_0_1" [shape=rectangle, label="[1] PULSE 0 \"rf\" test(duration: 1000000)"];
"block_0_1" -> "block_0_2" [label="frame"];
"block_0_1" -> "block_0_end" [label="frame"];
"block_0_1" -> "block_0_2" [label="ordering
timing"];
"block_0_1" -> "block_0_end" [label="ordering
timing"];
"block_0_2" [shape=rectangle, label="[2] PULSE 0 \"ro_rx\" test(duration: 1000000)"];
"block_0_2" -> "block_0_end" [label="frame"];
"block_0_2" -> "block_0_end" [label="ordering
timing"];
"block_0_end" [shape=circle, label="end"];
}
}
Expand Down

0 comments on commit ec7b1b2

Please sign in to comment.