diff --git a/.github/workflows/msrv.yml b/.github/workflows/msrv.yml index d9435365..c8e744bf 100644 --- a/.github/workflows/msrv.yml +++ b/.github/workflows/msrv.yml @@ -48,6 +48,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test + args: --all-features fmt: name: Rustfmt diff --git a/.gitignore b/.gitignore index c6c647ef..224fdc61 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /target node_modules +Cargo.lock # JetBrains Editors .idea/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index e3d3fa8f..ab39f226 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,6 +224,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "dot-writer" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1defb949b123415131ecae40ab5dca70e9f39eedda3de2cebb03a8a98fdf5894" + [[package]] name = "either" version = "1.6.1" @@ -297,9 +303,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" dependencies = [ "autocfg", "hashbrown", @@ -307,9 +313,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.14.0" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "689960f187c43c01650c805fb6bc6f55ab944499d86d4ffe9474ad78991d8e94" +checksum = "bcc3e639bcba360d9237acabd22014c16f3df772db463b7446cd81b070714767" dependencies = [ "console", "once_cell", @@ -345,9 +351,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "js-sys" @@ -389,9 +395,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "linked-hash-map" @@ -466,9 +472,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "oorandom" @@ -526,16 +532,16 @@ version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" dependencies = [ - "unicode-xid 0.1.0", + "unicode-xid", ] [[package]] name = "proc-macro2" -version = "1.0.37" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" dependencies = [ - "unicode-xid 0.2.3", + "unicode-ident", ] [[package]] @@ -586,6 +592,7 @@ name = "quil-rs" version = "0.9.3" dependencies = [ "criterion", + "dot-writer", "indexmap", "insta", "lexical", @@ -614,7 +621,7 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ - "proc-macro2 1.0.37", + "proc-macro2 1.0.39", ] [[package]] @@ -664,9 +671,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" dependencies = [ "autocfg", "crossbeam-deque", @@ -676,9 +683,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -697,9 +704,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.5" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "regex-syntax", ] @@ -712,9 +719,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "remove_dir_all" @@ -798,9 +805,9 @@ version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ - "proc-macro2 1.0.37", + "proc-macro2 1.0.39", "quote 1.0.18", - "syn 1.0.92", + "syn 1.0.95", ] [[package]] @@ -809,7 +816,7 @@ version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ - "itoa 1.0.1", + "itoa 1.0.2", "ryu", "serde", ] @@ -846,18 +853,18 @@ checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" dependencies = [ "proc-macro2 0.4.30", "quote 0.6.13", - "unicode-xid 0.1.0", + "unicode-xid", ] [[package]] name = "syn" -version = "1.0.92" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" dependencies = [ - "proc-macro2 1.0.37", + "proc-macro2 1.0.39", "quote 1.0.18", - "unicode-xid 0.2.3", + "unicode-ident", ] [[package]] @@ -914,9 +921,9 @@ version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ - "proc-macro2 1.0.37", + "proc-macro2 1.0.39", "quote 1.0.18", - "syn 1.0.92", + "syn 1.0.95", ] [[package]] @@ -929,6 +936,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + [[package]] name = "unicode-width" version = "0.1.9" @@ -941,12 +954,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -[[package]] -name = "unicode-xid" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" - [[package]] name = "version_check" version = "0.9.4" @@ -998,9 +1005,9 @@ dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.37", + "proc-macro2 1.0.39", "quote 1.0.18", - "syn 1.0.92", + "syn 1.0.95", "wasm-bindgen-shared", ] @@ -1020,9 +1027,9 @@ version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ - "proc-macro2 1.0.37", + "proc-macro2 1.0.39", "quote 1.0.18", - "syn 1.0.92", + "syn 1.0.95", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 8e04ab8f..d5d3b8ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ keywords = ["Quil", "Quantum", "Rigetti"] categories = ["parser-implementations", "science", "compilers", "emulators"] [dependencies] +dot-writer = { version = "0.1.2", optional = true } indexmap = "1.6.1" lexical = "5.2.0" nom = "6.1.0" @@ -24,6 +25,9 @@ proptest = "1.0.0" proptest-derive = "0.3.0" criterion = { version = "0.3.5", features = ["html_reports"] } +[features] +graphviz-dot = ["dot-writer"] + [[bench]] name = "parser" harness = false diff --git a/src/expression.rs b/src/expression.rs index 596f1983..949d9be1 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use num_complex::Complex64; use std::collections::{hash_map::DefaultHasher, HashMap}; use std::f64::consts::PI; @@ -799,7 +798,7 @@ mod tests { fn complexes_are_parseable_as_expressions(value in arb_complex64()) { let parsed = Expression::from_str(&format_complex(&value)); assert!(parsed.is_ok()); - assert_eq!(Expression::Number(value), parsed.unwrap().simplify()); + assert_eq!(Expression::Number(value), parsed.unwrap().into_simplified()); } } diff --git a/src/instruction.rs b/src/instruction.rs index bd273d11..c770eabf 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fmt}; @@ -886,7 +885,7 @@ impl Instruction { /// let mut instructions = program.to_instructions(true); /// instructions.iter_mut().for_each(|inst| inst.apply_to_expressions(Expression::simplify)); /// - /// assert_eq!(instructions[0].to_string(), String::from("SHIFT-PHASE 0 \"rf\" 4")) + /// assert_eq!(instructions[0].to_string(), String::from("SHIFT-PHASE 0 \"rf\" 4.0")) /// /// ``` pub fn apply_to_expressions(&mut self, mut closure: impl FnMut(&mut Expression)) { diff --git a/src/lib.rs b/src/lib.rs index e8e0af24..a60ee34f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,18 +1,40 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Welcome to the Rust implementation of the +//! [Quil quantum programming language](https://github.com/quil-lang/quil). +//! +//! Within this crate you'll find: +//! +//! * Builder utilities for Quil [programs], [instructions], and [expressions] +//! * A [parser] and [serializer] for converting Quil to and from text strings +//! * A [constructor for timing graphs], for understanding and debugging Quil-T +//! pulse control programs +//! +//! This crate is still early in its development and does not fully support all +//! Quil features, nor claim a stable API. Prior to `v1.0`, minor-version changes +//! are considered breaking changes. Please pin your versions when needed, and +//! closely follow the +//! [changelog](https://github.com/rigetti/quil-rust/releases) when upgrading. +//! +//! [constructor for timing graphs]: crate::program::graph::ScheduledProgram#method.get_dot_format +//! [expressions]: crate::expression::Expression +//! [instructions]: crate::instruction::Instruction +//! [parser]: crate::program::Program#method.from_str +//! [programs]: crate::program::Program +//! [serializer]: crate::program::Program#method.to_string + pub mod expression; pub mod instruction; mod macros; diff --git a/src/macros.rs b/src/macros.rs index fa6340da..b0c05e59 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,18 +1,16 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. /// Construct a complex number with the provided real component. #[macro_export] diff --git a/src/parser/command.rs b/src/parser/command.rs index 7ce0937d..d885b2ee 100644 --- a/src/parser/command.rs +++ b/src/parser/command.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use nom::{ combinator::opt, multi::{many0, many1, separated_list0, separated_list1}, diff --git a/src/parser/common.rs b/src/parser/common.rs index 2ddffcf6..0e76497c 100644 --- a/src/parser/common.rs +++ b/src/parser/common.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::collections::HashMap; use nom::{ diff --git a/src/parser/error.rs b/src/parser/error.rs index 508cdb2e..22da6ea7 100644 --- a/src/parser/error.rs +++ b/src/parser/error.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::fmt; use super::lexer::{Command, Token}; diff --git a/src/parser/expression.rs b/src/parser/expression.rs index b211c20d..1a068413 100644 --- a/src/parser/expression.rs +++ b/src/parser/expression.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use nom::combinator::opt; use crate::{ diff --git a/src/parser/gate.rs b/src/parser/gate.rs index 59350d6a..7a3499d6 100644 --- a/src/parser/gate.rs +++ b/src/parser/gate.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use nom::{combinator::opt, multi::many0, multi::separated_list0, sequence::delimited}; use crate::{instruction::Instruction, token}; diff --git a/src/parser/instruction.rs b/src/parser/instruction.rs index e94752a0..d12dbadf 100644 --- a/src/parser/instruction.rs +++ b/src/parser/instruction.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use nom::{ combinator::all_consuming, multi::{many0, many1}, diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 4db79e2a..6a88f6e6 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use nom::{ branch::alt, bytes::complete::{is_a, is_not, tag, take_until, take_while, take_while1}, diff --git a/src/parser/macros.rs b/src/parser/macros.rs index 5d750d39..da6638b0 100644 --- a/src/parser/macros.rs +++ b/src/parser/macros.rs @@ -1,18 +1,16 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #[macro_export] macro_rules! expected_token { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 42a86582..d45268a0 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use nom::IResult; use error::Error; diff --git a/src/program/calibration.rs b/src/program/calibration.rs index c82ccf62..89bca9ff 100644 --- a/src/program/calibration.rs +++ b/src/program/calibration.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::collections::HashMap; use crate::{ @@ -301,7 +300,7 @@ impl CalibrationSet { } /// Add another gate calibration to the set. - /// Deprecated in favor of [`push_calibration`] + /// Deprecated in favor of [`Self::push_calibration`] #[deprecated = "use ScheduledProgram#push_calibration instead"] pub fn push(&mut self, calibration: Calibration) { self.push_calibration(calibration) @@ -375,7 +374,7 @@ mod tests { " PULSE 0 \"xy\" gaussian(duration: 1, fwhm: 2, t0: 3)\n", "X 0\n" ), - expected: "PULSE 0 \"xy\" gaussian(duration: 1, fwhm: 2, t0: 3)\n", + expected: "PULSE 0 \"xy\" gaussian(duration: 1.0, fwhm: 2.0, t0: 3.0)\n", }, TestCase { input: concat!( diff --git a/src/program/error.rs b/src/program/error.rs index 00686fb4..155c5c29 100644 --- a/src/program/error.rs +++ b/src/program/error.rs @@ -1,3 +1,17 @@ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use thiserror::Error; use crate::instruction::Instruction; diff --git a/src/program/frame.rs b/src/program/frame.rs index 8b2ed984..fa0ee052 100644 --- a/src/program/frame.rs +++ b/src/program/frame.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::collections::{HashMap, HashSet}; use crate::instruction::{FrameAttributes, FrameDefinition, FrameIdentifier, Instruction, Qubit}; diff --git a/src/program/graph.rs b/src/program/graph.rs index 127b97fd..042f718e 100644 --- a/src/program/graph.rs +++ b/src/program/graph.rs @@ -1,22 +1,20 @@ //! Utilities for analysis of the dependency graph of a Quil Program -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::collections::{HashMap, HashSet}; -use std::fmt; use indexmap::IndexMap; use petgraph::graphmap::GraphMap; @@ -138,16 +136,14 @@ impl MemoryAccessQueue { }); } + self.pending_capture = None; + self.pending_write = None; + match access { - // Mark the given node as reading from this memory region. If there was a write pending, - // return it to be used as a dependency. Read => { self.pending_reads.push(node_id); - result } - // Mark the given node as writing to this memory region. If there were any reads or another - // write or capture pending, return those as a dependency list. - Capture | Write => { + Capture => { for upstream_node_id in self.pending_reads.iter() { result.push(MemoryAccessDependency { node_id: *upstream_node_id, @@ -155,21 +151,24 @@ impl MemoryAccessQueue { }); } - match access { - Capture => { - self.pending_capture = Some(node_id); - self.pending_write = None; - } - Write => { - self.pending_capture = None; - self.pending_write = Some(node_id); - } - _ => panic!("expected Capture or Write memory dependency"), + self.pending_reads = vec![]; + self.pending_capture = Some(node_id); + } + + Write => { + for upstream_node_id in self.pending_reads.iter() { + result.push(MemoryAccessDependency { + node_id: *upstream_node_id, + access_type: Read, + }); } - result + self.pending_reads = vec![]; + self.pending_write = Some(node_id); } } + + result } } @@ -197,7 +196,7 @@ pub type DependencyGraph = GraphMap, - graph: DependencyGraph, + pub(super) graph: DependencyGraph, pub terminator: BlockTerminator, } @@ -261,9 +260,6 @@ impl InstructionBlock { }), }?; - // FIXME: This will handle reads, writes, and captures in arbitrary order, which is a bug. - // Must be handled as reads -> (writes / captures). Instructions read all values prior to any - // writes they make to those values. let accesses = instruction.get_memory_accesses(); for (regions, access_type) in [ (accesses.reads, MemoryAccessType::Read), @@ -322,92 +318,6 @@ impl InstructionBlock { &self.graph } - /// Write a DOT-formatted string to the provided writer for use with GraphViz. - /// This output can be used within a `subgraph` or at the top level of a `digraph`. - /// - /// Parameters: - /// - /// * line_prefix: The prefix for each new line in the output. This can be used to indent this - /// output for readability in a larger definition. - /// * element_prefix: The prefix for each graph element (node and edge). This can be used to - /// namespace this block when used with other blocks which may have conflicting labels. - pub fn write_dot_format( - &self, - f: &mut fmt::Formatter, - line_prefix: &str, - element_prefix: &str, - ) -> fmt::Result { - self.graph.nodes().try_for_each(|node| { - match &node { - ScheduledGraphNode::BlockEnd => { - writeln!( - f, - "{}\"{}end\" [ label=end, shape=circle ]", - line_prefix, element_prefix - ) - } - ScheduledGraphNode::BlockStart => { - writeln!( - f, - "{}\"{}start\" [ label=start, shape=circle ]", - line_prefix, element_prefix - ) - } - ScheduledGraphNode::InstructionIndex(index) => { - write!( - f, - "{}\"{}{}\" [label=\"", - line_prefix, element_prefix, index - )?; - write_escaped(f, &format!("{}", self.instructions.get(*index).unwrap()))?; - writeln!(f, "\"]") - } - }?; - self.graph.edges(node).try_for_each(|(src, dest, edge)| { - match &src { - ScheduledGraphNode::BlockEnd => { - write!(f, "{}\"{}end\"", line_prefix, element_prefix) - } - ScheduledGraphNode::BlockStart => { - write!(f, "{}\"{}start\"", line_prefix, element_prefix) - } - ScheduledGraphNode::InstructionIndex(index) => { - write!(f, "{}\"{}{}\"", line_prefix, element_prefix, index) - } - }?; - write!(f, " -> ")?; - match &dest { - ScheduledGraphNode::BlockEnd => write!(f, "\"{}end\"", element_prefix), - ScheduledGraphNode::BlockStart => { - write!(f, "\"{}start\"", element_prefix) - } - ScheduledGraphNode::InstructionIndex(index) => { - write!(f, "\"{}{}\"", element_prefix, index) - } - }?; - let mut labels = edge - .iter() - .map(|dependency| match dependency { - ExecutionDependency::AwaitMemoryAccess(access_type) => match access_type { - MemoryAccessType::Read => "await read", - MemoryAccessType::Write => "await write", - MemoryAccessType::Capture => "await capture", - }, - ExecutionDependency::ReferenceFrame => "frame", - ExecutionDependency::StableOrdering => "ordering", - }) - .collect::>(); - - // We sort them so that graph output is deterministic; iterating over the set - // without sorting would cause flaky tests. - labels.sort_unstable(); - let label = labels.join("\n"); - writeln!(f, " [ label=\"{}\" ]", label) - }) - })?; - Ok(()) - } - /// Return a particular-indexed instruction (if present). pub fn get_instruction(&self, node_id: usize) -> Option<&Instruction> { self.instructions.get(node_id) @@ -442,26 +352,6 @@ pub enum BlockTerminator { Halt, } -/// Escape strings for use as DOT format quoted ID's -fn write_escaped(f: &mut fmt::Formatter, s: &str) -> fmt::Result { - for c in s.chars() { - write_char(f, c)?; - } - Ok(()) -} - -/// Escape a single character for use within a DOT format quoted ID. -fn write_char(f: &mut fmt::Formatter, c: char) -> fmt::Result { - use std::fmt::Write; - match c { - '"' | '\\' => f.write_char('\\')?, - // \l is for left justified linebreak - '\n' => return f.write_str("\\l"), - _ => {} - } - f.write_char(c) -} - #[derive(Clone, Debug)] pub struct ScheduledProgram { /// All blocks within the ScheduledProgram, keyed on string label. @@ -637,291 +527,4 @@ impl ScheduledProgram { } label } - - /// Write a DOT format string to the provided writer for use with Graphviz. - /// - /// This outputs a `digraph` object with a `subgraph` for each block to inform the layout engine. - /// Each `subgraph` ID is prefixed with `cluster_` which instructs some supporting layout engines - /// to enclose the subgraph with a border. This improves readability of the graph. - /// - /// Lines on the graph indicate scheduling dependencies within blocks and control flow among blocks. - /// Each node representing an instruction is labeled with the contents of that instruction. - pub fn write_dot_format(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f, "digraph {{")?; - - let mut iter = self.blocks.iter().peekable(); - - writeln!(f, "\tentry [label=\"Entry Point\"]")?; - - if let Some((first_label, _)) = iter.peek() { - writeln!(f, "\tentry -> \"{}_start\"", first_label)?; - } - - while let Some((label, block)) = iter.next() { - writeln!(f, "\tsubgraph \"cluster_{}\" {{", label)?; - writeln!(f, "\t\tlabel=\"{}\"", label)?; - writeln!(f, "\t\tnode [ style=\"filled\" ]")?; - - let line_prefix = "\t\t"; - // let element_prefix = format!("b{}_", index); - let element_prefix = format!("{}_", label); - - block.write_dot_format(f, line_prefix, &element_prefix)?; - writeln!(f, "\t}}")?; - - let next_block_label = iter.peek().map(|(next_label, _)| (*next_label).clone()); - match &block.terminator { - BlockTerminator::Conditional { - condition, - target, - jump_if_condition_true, - } => { - let equality_operators = if *jump_if_condition_true { - ("==", "!=") - } else { - ("!=", "==") - }; - writeln!( - f, - "\"{}_end\" -> \"{}_start\" [label=\"if {} {} 0\"]", - label, target, condition, equality_operators.0, - )?; - if let Some(next_label) = next_block_label { - writeln!( - f, - "\"{}_end\" -> \"{}_start\" [label=\"if {} {} 0\"]", - label, next_label, condition, equality_operators.1 - )?; - }; - } - BlockTerminator::Unconditional { target } => { - writeln!( - f, - "\"{}_end\" -> \"{}_start\" [label=\"always\"]", - label, target - )?; - } - BlockTerminator::Continue => { - if let Some(next_label) = next_block_label { - writeln!( - f, - "\"{}_end\" -> \"{}_start\" [label=\"always\"]", - label, next_label - )?; - }; - } - BlockTerminator::Halt => {} - } - } - writeln!(f, "}}") - } -} - -#[cfg(test)] -mod tests { - mod graph { - use std::str::FromStr; - - use crate::program::Program; - - use super::super::ScheduledProgram; - - /// Build a test case which compiles the input program, builds the dot-format string from the program, - /// and then compares that to a "correct" snapshot of that dot format. This makes diffs easy to compare and - /// understand; if a test is failing, you can copy the snapshot contents out to your preferred Graphviz - /// viewer to help understand why. - /// - /// NOTE: because this relies on direct string comparison, it will be brittle against changes in the way - /// that the `write_dot_format` methods work. If _all_ or _most_ of these tests are failing, examine the - /// diffs closely to determine if it's only a matter of reformatting. - macro_rules! build_dot_format_snapshot_test_case { - ($name: ident, $input:expr) => { - #[test] - fn $name() { - use std::fmt; - const FRAME_DEFINITIONS: &'static str = " -DEFFRAME 0 \"rf\": - INITIAL-FREQUENCY: 1e6 -DEFFRAME 1 \"rf\": - INITIAL-FREQUENCY: 1e6 -DEFFRAME 2 \"rf\": - INITIAL-FREQUENCY: 1e6 -DEFFRAME 0 \"ro_rx\": - INITIAL-FREQUENCY: 1e6 -DEFFRAME 0 \"ro_tx\": - INITIAL-FREQUENCY: 1e6 -"; - - let program = - Program::from_str(&format!("{}\n{}", FRAME_DEFINITIONS, $input)).unwrap(); - let scheduled_program = ScheduledProgram::from_program(&program).unwrap(); - - for block in scheduled_program.blocks.values() { - let graph = block.get_dependency_graph(); - assert!( - !petgraph::algo::is_cyclic_directed(graph), - "cycle in graph: {:?}", - graph - ); - } - - struct ProgramDebugWrapper<'a> { - pub program: &'a ScheduledProgram, - } - - impl<'a> fmt::Debug for ProgramDebugWrapper<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.program.write_dot_format(f) - } - } - - insta::assert_debug_snapshot!(ProgramDebugWrapper { - program: &scheduled_program - }); - } - }; - } - - build_dot_format_snapshot_test_case!( - single_instruction, - "PULSE 0 \"rf\" test(duration: 1e6)" - ); - - build_dot_format_snapshot_test_case!( - single_dependency, - " -PULSE 0 \"rf\" test(duration: 1e6) -PULSE 0 \"rf\" test(duration: 1e6) -" - ); - - build_dot_format_snapshot_test_case!( - chained_pulses, - " -PULSE 0 \"rf\" test(duration: 1e6) -PULSE 0 \"rf\" test(duration: 1e6) -PULSE 0 \"rf\" test(duration: 1e6) -PULSE 0 \"rf\" test(duration: 1e6) -PULSE 0 \"rf\" test(duration: 1e6) -" - ); - - build_dot_format_snapshot_test_case!( - different_frames_blocking, - " -PULSE 0 \"rf\" test(duration: 1e6) -PULSE 1 \"rf\" test(duration: 1e6) -PULSE 2 \"rf\" test(duration: 1e6) -" - ); - - build_dot_format_snapshot_test_case!( - different_frames_nonblocking, - " -NONBLOCKING PULSE 0 \"rf\" test(duration: 1e6) -NONBLOCKING PULSE 1 \"rf\" test(duration: 1e6) -NONBLOCKING PULSE 2 \"rf\" test(duration: 1e6) -" - ); - - build_dot_format_snapshot_test_case!( - fence_all_with_nonblocking_pulses, - " -NONBLOCKING PULSE 0 \"rf\" test(duration: 1e6) -NONBLOCKING PULSE 1 \"rf\" test(duration: 1e6) -FENCE -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!( - jump, - "DECLARE ro BIT -LABEL @first-block -PULSE 0 \"rf\" test(duration: 1e6) -JUMP-UNLESS @third-block ro[0] -LABEL @second-block -PULSE 0 \"rf\" test(duration: 1e6) -LABEL @third-block -PULSE 0 \"rf\" test(duration: 1e6) -" - ); - - build_dot_format_snapshot_test_case!( - active_reset_single_frame, - "DECLARE ro BIT -LABEL @measure -NONBLOCKING PULSE 0 \"ro_tx\" test(duration: 1e6) -NONBLOCKING CAPTURE 0 \"ro_rx\" test(duration: 1e6) ro -JUMP-WHEN @end ro[0] -LABEL @feedback -PULSE 0 \"rf\" test(duration: 1e6) -JUMP @measure -LABEL @end -" - ); - - build_dot_format_snapshot_test_case!( - labels_only, - "LABEL @a -LABEL @b -LABEL @c -" - ); - - // assert that read and write memory dependencies are expressed correctly - build_dot_format_snapshot_test_case!( - simple_memory_access, - "DECLARE a INTEGER -DECLARE b INTEGER -MOVE a 1 -MOVE b 2 -ADD a b -" - ); - - // assert that a block "waits" for a capture to complete - build_dot_format_snapshot_test_case!( - simple_capture, - "DECLARE ro BIT -CAPTURE 0 \"ro_rx\" test ro" - ); - - // assert that a block "waits" for a capture to complete even with a pulse after it - build_dot_format_snapshot_test_case!( - pulse_after_capture, - "DECLARE ro BIT -CAPTURE 0 \"ro_rx\" test ro -PULSE 0 \"rf\" test" - ); - - // assert that a block "waits" for a capture to complete - build_dot_format_snapshot_test_case!( - parametric_pulse, - "DECLARE ro BIT -DECLARE param REAL -PULSE 0 \"rf\" test(a: param[0]) -CAPTURE 0 \"ro_rx\" test(a: param[0]) ro" - ); - - // Assert that all pulses following a capture block on that capture, until the next capture - build_dot_format_snapshot_test_case!( - parametric_pulses_using_capture_results, - "DECLARE ro BIT -DECLARE param REAL -CAPTURE 0 \"ro_rx\" test(a: param[0]) ro -NONBLOCKING PULSE 0 \"rf\" test(a: ro[0]) -NONBLOCKING PULSE 1 \"rf\" test(a: ro[0]) -CAPTURE 0 \"ro_rx\" test(a: param[0]) ro -NONBLOCKING PULSE 0 \"rf\" test(a: ro[0]) -NONBLOCKING PULSE 1 \"rf\" test(a: ro[0])" - ); - - build_dot_format_snapshot_test_case!( - multiple_classical_instructions, - "DECLARE ro INTEGER[2]\nMOVE ro[0] 1\nMOVE ro[1] 0\nADD ro[0] 5\nSUB ro[1] ro[0]" - ); - } } diff --git a/src/program/graphviz_dot.rs b/src/program/graphviz_dot.rs new file mode 100644 index 00000000..97cd99aa --- /dev/null +++ b/src/program/graphviz_dot.rs @@ -0,0 +1,401 @@ +//! Utilities for working with Graphviz dot format files + +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use dot_writer::{Attributes, DotWriter, Shape, Style}; + +use crate::program::graph::{ + BlockTerminator, ExecutionDependency, InstructionBlock, MemoryAccessType, ScheduledGraphNode, + ScheduledProgram, +}; + +impl InstructionBlock { + /// Given a [`dot_writer::Scope`] representing a subgraph/cluster, write the timing graph for this block into it. + /// Uses the `node_prefix` argument for namespacing so that node IDs remain unique within the overall graph. + fn write_dot_format(&self, cluster: &mut dot_writer::Scope, node_prefix: &str) { + self.graph.nodes().for_each(|node| { + let node_id = get_node_id(&node, node_prefix); + match &node { + ScheduledGraphNode::BlockEnd => { + cluster + .node_named(node_id) + .set_shape(Shape::Circle) + .set_label("end"); + } + ScheduledGraphNode::BlockStart => { + cluster + .node_named(node_id) + .set_shape(Shape::Circle) + .set_label("start"); + } + ScheduledGraphNode::InstructionIndex(index) => { + cluster + .node_named(node_id) + .set_shape(Shape::Rectangle) + .set_label(&escape_label(&format!( + "[{}] {}", + index, + self.instructions.get(*index).unwrap() + ))); + } + }; + self.graph.edges(node).for_each(|(src, dest, edge)| { + let source = get_node_id(&src, node_prefix); + let target = get_node_id(&dest, node_prefix); + let mut labels = edge + .iter() + .map(|dependency| match dependency { + ExecutionDependency::AwaitMemoryAccess(access_type) => match access_type { + MemoryAccessType::Read => "await read", + MemoryAccessType::Write => "await write", + MemoryAccessType::Capture => "await capture", + }, + ExecutionDependency::ReferenceFrame => "frame", + ExecutionDependency::StableOrdering => "ordering", + }) + .collect::>(); + + // We sort them so that graph output is deterministic; iterating over the set + // without sorting would cause flaky tests. + labels.sort_unstable(); + let label = labels.join("\n"); + cluster + .edge(source, target) + .attributes() + .set_label(label.as_str()); + }) + }); + } +} + +impl ScheduledProgram { + /// Return a DOT format string (as bytes) for use with Graphviz. + /// + /// This outputs a `digraph` object with a `subgraph` for each block to inform the layout engine. + /// Each `subgraph` ID is prefixed with `cluster_` which instructs some supporting layout engines + /// to enclose the subgraph with a border. This improves readability of the graph. + /// + /// Lines on the graph indicate scheduling dependencies within blocks and control flow among blocks. + /// Each node representing an instruction is labeled with the contents of that instruction. + pub fn get_dot_format(&self) -> Vec { + let mut output_bytes = Vec::new(); + + { + let mut writer = DotWriter::from(&mut output_bytes); + writer.set_pretty_print(true); + let mut digraph = writer.digraph(); + + let mut iter = self.blocks.iter().peekable(); + if let Some((first_label, _)) = iter.peek() { + digraph.edge( + "entry", + get_node_id(&ScheduledGraphNode::BlockStart, first_label), + ); + } + digraph.node_named("entry").set_label("Entry Point"); + + while let Some((label, block)) = iter.next() { + let node_prefix = label; + { + let mut cluster = digraph.cluster(); + cluster.set_label(label); + cluster.node_attributes().set_style(Style::Filled); + + block.write_dot_format(&mut cluster, node_prefix); + } + + let next_block_label = iter.peek().map(|(next_label, _)| (*next_label).clone()); + let terminator_source_label = + get_node_id(&ScheduledGraphNode::BlockEnd, node_prefix); + match &block.terminator { + BlockTerminator::Conditional { + condition, + target, + jump_if_condition_true, + } => { + let equality_operators = if *jump_if_condition_true { + ("==", "!=") + } else { + ("!=", "==") + }; + digraph + .edge( + &terminator_source_label, + get_node_id(&ScheduledGraphNode::BlockStart, target), + ) + .attributes() + .set_label( + format!("if {} {} 0", condition, equality_operators.0).as_str(), + ); + if let Some(next_label) = next_block_label { + digraph + .edge( + &terminator_source_label, + get_node_id(&ScheduledGraphNode::BlockStart, &next_label), + ) + .attributes() + .set_label( + format!("if {} {} 0", condition, equality_operators.1).as_str(), + ); + }; + } + BlockTerminator::Unconditional { target } => { + digraph + .edge( + &terminator_source_label, + get_node_id(&ScheduledGraphNode::BlockStart, target), + ) + .attributes() + .set_label("always"); + } + BlockTerminator::Continue => { + if let Some(next_label) = next_block_label { + digraph + .edge( + &terminator_source_label, + get_node_id(&ScheduledGraphNode::BlockStart, &next_label), + ) + .attributes() + .set_label("always"); + }; + } + BlockTerminator::Halt => {} + } + } + } + + output_bytes + } +} + +/// Escape a string for safe use as a Graphviz node ID or label +fn escape_label(original: &str) -> String { + original.replace('\"', "\\\"") +} + +/// Return a string to be used as the node ID within the graph text. +/// `prefix` parameter allows namespacing for uniqueness. +fn get_node_id(node: &ScheduledGraphNode, prefix: &str) -> String { + match node { + ScheduledGraphNode::BlockEnd => { + format!("\"{}_end\"", prefix) + } + ScheduledGraphNode::BlockStart => { + format!("\"{}_start\"", prefix) + } + ScheduledGraphNode::InstructionIndex(index) => { + format!("\"{}_{}\"", prefix, index) + } + } +} + +#[cfg(test)] +mod tests { + mod graph { + use std::str::FromStr; + + use crate::program::Program; + + use super::super::ScheduledProgram; + + /// Build a test case which compiles the input program, builds the dot-format string from the program, + /// and then compares that to a "correct" snapshot of that dot format. This makes diffs easy to compare and + /// understand; if a test is failing, you can copy the snapshot contents out to your preferred Graphviz + /// viewer to help understand why. + /// + /// NOTE: because this relies on direct string comparison, it will be brittle against changes in the way + /// that the `get_dot_format` method works. If _all_ or _most_ of these tests are failing, examine the + /// diffs closely to determine if it's only a matter of reformatting. + macro_rules! build_dot_format_snapshot_test_case { + ($name: ident, $input:expr) => { + #[test] + fn $name() { + const FRAME_DEFINITIONS: &'static str = " +DEFFRAME 0 \"rf\": + INITIAL-FREQUENCY: 1e6 +DEFFRAME 1 \"rf\": + INITIAL-FREQUENCY: 1e6 +DEFFRAME 2 \"rf\": + INITIAL-FREQUENCY: 1e6 +DEFFRAME 0 \"ro_rx\": + INITIAL-FREQUENCY: 1e6 +DEFFRAME 0 \"ro_tx\": + INITIAL-FREQUENCY: 1e6 +"; + + let program = + Program::from_str(&format!("{}\n{}", FRAME_DEFINITIONS, $input)).unwrap(); + let scheduled_program = ScheduledProgram::from_program(&program).unwrap(); + + for block in scheduled_program.blocks.values() { + let graph = block.get_dependency_graph(); + assert!( + !petgraph::algo::is_cyclic_directed(graph), + "cycle in graph: {:?}", + graph + ); + } + + let dot_format_bytes = scheduled_program.get_dot_format(); + let dot_format = String::from_utf8_lossy(&dot_format_bytes); + + insta::assert_snapshot!(dot_format); + } + }; + } + + build_dot_format_snapshot_test_case!( + single_instruction, + "PULSE 0 \"rf\" test(duration: 1e6)" + ); + + build_dot_format_snapshot_test_case!( + single_dependency, + " +PULSE 0 \"rf\" test(duration: 1e6) +PULSE 0 \"rf\" test(duration: 1e6) +" + ); + + build_dot_format_snapshot_test_case!( + chained_pulses, + " +PULSE 0 \"rf\" test(duration: 1e6) +PULSE 0 \"rf\" test(duration: 1e6) +PULSE 0 \"rf\" test(duration: 1e6) +PULSE 0 \"rf\" test(duration: 1e6) +PULSE 0 \"rf\" test(duration: 1e6) +" + ); + + build_dot_format_snapshot_test_case!( + different_frames_blocking, + " +PULSE 0 \"rf\" test(duration: 1e6) +PULSE 1 \"rf\" test(duration: 1e6) +PULSE 2 \"rf\" test(duration: 1e6) +" + ); + + build_dot_format_snapshot_test_case!( + different_frames_nonblocking, + " +NONBLOCKING PULSE 0 \"rf\" test(duration: 1e6) +NONBLOCKING PULSE 1 \"rf\" test(duration: 1e6) +NONBLOCKING PULSE 2 \"rf\" test(duration: 1e6) +" + ); + + build_dot_format_snapshot_test_case!( + fence_all_with_nonblocking_pulses, + " +NONBLOCKING PULSE 0 \"rf\" test(duration: 1e6) +NONBLOCKING PULSE 1 \"rf\" test(duration: 1e6) +FENCE +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!( + jump, + "DECLARE ro BIT +LABEL @first-block +PULSE 0 \"rf\" test(duration: 1e6) +JUMP-UNLESS @third-block ro[0] +LABEL @second-block +PULSE 0 \"rf\" test(duration: 1e6) +LABEL @third-block +PULSE 0 \"rf\" test(duration: 1e6) +" + ); + + build_dot_format_snapshot_test_case!( + active_reset_single_frame, + "DECLARE ro BIT +LABEL @measure +NONBLOCKING PULSE 0 \"ro_tx\" test(duration: 1e6) +NONBLOCKING CAPTURE 0 \"ro_rx\" test(duration: 1e6) ro +JUMP-WHEN @end ro[0] +LABEL @feedback +PULSE 0 \"rf\" test(duration: 1e6) +JUMP @measure +LABEL @end +" + ); + + build_dot_format_snapshot_test_case!( + labels_only, + "LABEL @a +LABEL @b +LABEL @c +" + ); + + // assert that read and write memory dependencies are expressed correctly + build_dot_format_snapshot_test_case!( + simple_memory_access, + "DECLARE a INTEGER +DECLARE b INTEGER +MOVE a 1 +MOVE b 2 +ADD a b +" + ); + + // assert that a block "waits" for a capture to complete + build_dot_format_snapshot_test_case!( + simple_capture, + "DECLARE ro BIT +CAPTURE 0 \"ro_rx\" test ro" + ); + + // assert that a block "waits" for a capture to complete even with a pulse after it + build_dot_format_snapshot_test_case!( + pulse_after_capture, + "DECLARE ro BIT +CAPTURE 0 \"ro_rx\" test ro +PULSE 0 \"rf\" test" + ); + + // assert that a block "waits" for a capture to complete + build_dot_format_snapshot_test_case!( + parametric_pulse, + "DECLARE ro BIT +DECLARE param REAL +PULSE 0 \"rf\" test(a: param[0]) +CAPTURE 0 \"ro_rx\" test(a: param[0]) ro" + ); + + // Assert that all pulses following a capture block on that capture, until the next capture + build_dot_format_snapshot_test_case!( + parametric_pulses_using_capture_results, + "DECLARE ro BIT +DECLARE param REAL +CAPTURE 0 \"ro_rx\" test(a: param[0]) ro +NONBLOCKING PULSE 0 \"rf\" test(a: ro[0]) +NONBLOCKING PULSE 1 \"rf\" test(a: ro[0]) +CAPTURE 0 \"ro_rx\" test(a: param[0]) ro +NONBLOCKING PULSE 0 \"rf\" test(a: ro[0]) +NONBLOCKING PULSE 1 \"rf\" test(a: ro[0])" + ); + + build_dot_format_snapshot_test_case!( + multiple_classical_instructions, + "DECLARE ro INTEGER[2]\nMOVE ro[0] 1\nMOVE ro[1] 0\nADD ro[0] 5\nSUB ro[1] ro[0]" + ); + } +} diff --git a/src/program/memory.rs b/src/program/memory.rs index f71a31bf..dd0c8200 100644 --- a/src/program/memory.rs +++ b/src/program/memory.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::collections::HashSet; use crate::expression::Expression; diff --git a/src/program/mod.rs b/src/program/mod.rs index a6d5d56d..c04f8a73 100644 --- a/src/program/mod.rs +++ b/src/program/mod.rs @@ -1,18 +1,17 @@ -/** - * Copyright 2021 Rigetti Computing - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ +// Copyright 2021 Rigetti Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::collections::BTreeMap; use std::str::FromStr; @@ -33,6 +32,9 @@ mod frame; pub mod graph; mod memory; +#[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 diff --git a/src/program/snapshots/quil_rs__program__graph__tests__graph__fence_all.snap b/src/program/snapshots/quil_rs__program__graph__tests__graph__fence_all.snap deleted file mode 100644 index e9f5b3e1..00000000 --- a/src/program/snapshots/quil_rs__program__graph__tests__graph__fence_all.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: quil/src/program/graph.rs -expression: "ProgramDebugWrapper{program: &scheduled_program,}" - ---- -digraph { - entry [label="Entry Point"] - entry -> "block_0_start" - subgraph "cluster_block_0" { - label="block_0" - node [ style="filled" ] - "block_0_start" [ label=start, shape=circle ] - "block_0_start" -> "block_0_0" [ label="frame" ] - "block_0_start" -> "block_0_end" [ label="ordering" ] - "block_0_0" [label="FENCE"] - "block_0_0" -> "block_0_end" [ label="frame" ] - "block_0_end" [ label=end, shape=circle ] - } -} - diff --git a/src/program/snapshots/quil_rs__program__graph__tests__graph__labels_only.snap b/src/program/snapshots/quil_rs__program__graph__tests__graph__labels_only.snap deleted file mode 100644 index 6da250e1..00000000 --- a/src/program/snapshots/quil_rs__program__graph__tests__graph__labels_only.snap +++ /dev/null @@ -1,33 +0,0 @@ ---- -source: quil/src/program/graph.rs -expression: "ProgramDebugWrapper{program: &scheduled_program,}" - ---- -digraph { - entry [label="Entry Point"] - entry -> "a_start" - subgraph "cluster_a" { - label="a" - node [ style="filled" ] - "a_start" [ label=start, shape=circle ] - "a_start" -> "a_end" [ label="ordering" ] - "a_end" [ label=end, shape=circle ] - } -"a_end" -> "b_start" [label="always"] - subgraph "cluster_b" { - label="b" - node [ style="filled" ] - "b_start" [ label=start, shape=circle ] - "b_start" -> "b_end" [ label="ordering" ] - "b_end" [ label=end, shape=circle ] - } -"b_end" -> "c_start" [label="always"] - subgraph "cluster_c" { - label="c" - node [ style="filled" ] - "c_start" [ label=start, shape=circle ] - "c_start" -> "c_end" [ label="ordering" ] - "c_end" [ label=end, shape=circle ] - } -} - diff --git a/src/program/snapshots/quil_rs__program__graph__tests__graph__multiple_classical_instructions.snap b/src/program/snapshots/quil_rs__program__graph__tests__graph__multiple_classical_instructions.snap deleted file mode 100644 index fd3e5a95..00000000 --- a/src/program/snapshots/quil_rs__program__graph__tests__graph__multiple_classical_instructions.snap +++ /dev/null @@ -1,30 +0,0 @@ ---- -source: quil/src/program/graph.rs -expression: "ProgramDebugWrapper{program: &scheduled_program,}" - ---- -digraph { - entry [label="Entry Point"] - entry -> "block_0_start" - subgraph "cluster_block_0" { - label="block_0" - node [ style="filled" ] - "block_0_start" [ label=start, shape=circle ] - "block_0_start" -> "block_0_0" [ label="ordering" ] - "block_0_0" [label="MOVE ro[0] 1"] - "block_0_0" -> "block_0_1" [ label="await write -ordering" ] - "block_0_1" [label="MOVE ro[1] 0"] - "block_0_1" -> "block_0_2" [ label="await write -ordering" ] - "block_0_2" [label="ADD ro[0] 5"] - "block_0_2" -> "block_0_3" [ label="await write -ordering" ] - "block_0_3" [label="SUB ro[1] ro[0]"] - "block_0_3" -> "block_0_end" [ label="await read -await write -ordering" ] - "block_0_end" [ label=end, shape=circle ] - } -} - diff --git a/src/program/snapshots/quil_rs__program__graph__tests__graph__parametric_pulse.snap b/src/program/snapshots/quil_rs__program__graph__tests__graph__parametric_pulse.snap deleted file mode 100644 index 109f559a..00000000 --- a/src/program/snapshots/quil_rs__program__graph__tests__graph__parametric_pulse.snap +++ /dev/null @@ -1,25 +0,0 @@ ---- -source: quil/src/program/graph.rs -expression: "ProgramDebugWrapper{program: &scheduled_program,}" - ---- -digraph { - entry [label="Entry Point"] - entry -> "block_0_start" - subgraph "cluster_block_0" { - label="block_0" - node [ style="filled" ] - "block_0_start" [ label=start, shape=circle ] - "block_0_start" -> "block_0_0" [ label="frame" ] - "block_0_start" -> "block_0_end" [ label="ordering" ] - "block_0_0" [label="PULSE 0 \"rf\" test(a: param[0])"] - "block_0_0" -> "block_0_1" [ label="frame" ] - "block_0_0" -> "block_0_end" [ label="await read" ] - "block_0_1" [label="CAPTURE 0 \"ro_rx\" test(a: param[0]) ro[0]"] - "block_0_1" -> "block_0_end" [ label="await capture -await read -frame" ] - "block_0_end" [ label=end, shape=circle ] - } -} - diff --git a/src/program/snapshots/quil_rs__program__graph__tests__graph__parametric_pulses_using_capture_results.snap b/src/program/snapshots/quil_rs__program__graph__tests__graph__parametric_pulses_using_capture_results.snap deleted file mode 100644 index 5af50007..00000000 --- a/src/program/snapshots/quil_rs__program__graph__tests__graph__parametric_pulses_using_capture_results.snap +++ /dev/null @@ -1,48 +0,0 @@ ---- -source: quil/src/program/graph.rs -expression: "ProgramDebugWrapper{program: &scheduled_program,}" - ---- -digraph { - entry [label="Entry Point"] - entry -> "block_0_start" - subgraph "cluster_block_0" { - label="block_0" - node [ style="filled" ] - "block_0_start" [ label=start, shape=circle ] - "block_0_start" -> "block_0_0" [ label="frame" ] - "block_0_start" -> "block_0_end" [ label="ordering" ] - "block_0_0" [label="CAPTURE 0 \"ro_rx\" test(a: param[0]) ro[0]"] - "block_0_0" -> "block_0_1" [ label="await capture -frame" ] - "block_0_0" -> "block_0_2" [ label="await capture -frame" ] - "block_0_0" -> "block_0_3" [ label="await capture -frame" ] - "block_0_0" -> "block_0_end" [ label="await read" ] - "block_0_1" [label="NONBLOCKING PULSE 0 \"rf\" test(a: ro[0])"] - "block_0_1" -> "block_0_3" [ label="await read -frame" ] - "block_0_1" -> "block_0_end" [ label="await read" ] - "block_0_2" [label="NONBLOCKING PULSE 1 \"rf\" test(a: ro[0])"] - "block_0_2" -> "block_0_3" [ label="await read -frame" ] - "block_0_2" -> "block_0_end" [ label="await read" ] - "block_0_3" [label="CAPTURE 0 \"ro_rx\" test(a: param[0]) ro[0]"] - "block_0_3" -> "block_0_4" [ label="await capture -frame" ] - "block_0_3" -> "block_0_5" [ label="await capture -frame" ] - "block_0_3" -> "block_0_end" [ label="await capture -await read -frame" ] - "block_0_4" [label="NONBLOCKING PULSE 0 \"rf\" test(a: ro[0])"] - "block_0_4" -> "block_0_end" [ label="await read -frame" ] - "block_0_5" [label="NONBLOCKING PULSE 1 \"rf\" test(a: ro[0])"] - "block_0_5" -> "block_0_end" [ label="await read -frame" ] - "block_0_end" [ label=end, shape=circle ] - } -} - diff --git a/src/program/snapshots/quil_rs__program__graph__tests__graph__pulse_after_capture.snap b/src/program/snapshots/quil_rs__program__graph__tests__graph__pulse_after_capture.snap deleted file mode 100644 index c551098e..00000000 --- a/src/program/snapshots/quil_rs__program__graph__tests__graph__pulse_after_capture.snap +++ /dev/null @@ -1,23 +0,0 @@ ---- -source: quil/src/program/graph.rs -expression: "ProgramDebugWrapper{program: &scheduled_program,}" - ---- -digraph { - entry [label="Entry Point"] - entry -> "block_0_start" - subgraph "cluster_block_0" { - label="block_0" - node [ style="filled" ] - "block_0_start" [ label=start, shape=circle ] - "block_0_start" -> "block_0_0" [ label="frame" ] - "block_0_start" -> "block_0_end" [ label="ordering" ] - "block_0_0" [label="CAPTURE 0 \"ro_rx\" test() ro[0]"] - "block_0_0" -> "block_0_1" [ label="frame" ] - "block_0_0" -> "block_0_end" [ label="await capture" ] - "block_0_1" [label="PULSE 0 \"rf\" test()"] - "block_0_1" -> "block_0_end" [ label="frame" ] - "block_0_end" [ label=end, shape=circle ] - } -} - diff --git a/src/program/snapshots/quil_rs__program__graph__tests__graph__simple_capture.snap b/src/program/snapshots/quil_rs__program__graph__tests__graph__simple_capture.snap deleted file mode 100644 index b25ecc53..00000000 --- a/src/program/snapshots/quil_rs__program__graph__tests__graph__simple_capture.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: quil/src/program/graph.rs -expression: "ProgramDebugWrapper{program: &scheduled_program,}" - ---- -digraph { - entry [label="Entry Point"] - entry -> "block_0_start" - subgraph "cluster_block_0" { - label="block_0" - node [ style="filled" ] - "block_0_start" [ label=start, shape=circle ] - "block_0_start" -> "block_0_0" [ label="frame" ] - "block_0_start" -> "block_0_end" [ label="ordering" ] - "block_0_0" [label="CAPTURE 0 \"ro_rx\" test() ro[0]"] - "block_0_0" -> "block_0_end" [ label="await capture -frame" ] - "block_0_end" [ label=end, shape=circle ] - } -} - diff --git a/src/program/snapshots/quil_rs__program__graph__tests__graph__simple_memory_access.snap b/src/program/snapshots/quil_rs__program__graph__tests__graph__simple_memory_access.snap deleted file mode 100644 index 0b073dd8..00000000 --- a/src/program/snapshots/quil_rs__program__graph__tests__graph__simple_memory_access.snap +++ /dev/null @@ -1,28 +0,0 @@ ---- -source: quil/src/program/graph.rs -expression: "ProgramDebugWrapper{program: &scheduled_program,}" - ---- -digraph { - entry [label="Entry Point"] - entry -> "block_0_start" - subgraph "cluster_block_0" { - label="block_0" - node [ style="filled" ] - "block_0_start" [ label=start, shape=circle ] - "block_0_start" -> "block_0_0" [ label="ordering" ] - "block_0_0" [label="MOVE a[0] 1"] - "block_0_0" -> "block_0_1" [ label="ordering" ] - "block_0_0" -> "block_0_2" [ label="await write" ] - "block_0_1" [label="MOVE b[0] 2"] - "block_0_1" -> "block_0_2" [ label="await write -ordering" ] - "block_0_1" -> "block_0_end" [ label="await write" ] - "block_0_2" [label="ADD a[0] b[0]"] - "block_0_2" -> "block_0_end" [ label="await read -await write -ordering" ] - "block_0_end" [ label=end, shape=circle ] - } -} - diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__active_reset_single_frame.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__active_reset_single_frame.snap new file mode 100644 index 00000000..c000579d --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__active_reset_single_frame.snap @@ -0,0 +1,43 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "measure_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + 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_end" [label="ordering"]; + "measure_0" [shape=rectangle, label="[0] NONBLOCKING PULSE 0 \"ro_tx\" test(duration: 1000000.0)"]; + "measure_0" -> "measure_end" [label="frame"]; + "measure_1" [shape=rectangle, label="[1] NONBLOCKING CAPTURE 0 \"ro_rx\" test(duration: 1000000.0) ro[0]"]; + "measure_1" -> "measure_end" [label="await capture +frame"]; + "measure_end" [shape=circle, label="end"]; + } + "measure_end" -> "end_start" [label="if ro[0] == 0"]; + "measure_end" -> "feedback_start" [label="if ro[0] != 0"]; + subgraph cluster_1 { + label="feedback"; + node [style="filled"]; + "feedback_start" [shape=circle, label="start"]; + "feedback_start" -> "feedback_0" [label="frame"]; + "feedback_start" -> "feedback_end" [label="ordering"]; + "feedback_0" [shape=rectangle, label="[0] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "feedback_0" -> "feedback_end" [label="frame"]; + "feedback_end" [shape=circle, label="end"]; + } + "feedback_end" -> "measure_start" [label="always"]; + subgraph cluster_2 { + label="end"; + node [style="filled"]; + "end_start" [shape=circle, label="start"]; + "end_start" -> "end_end" [label="ordering"]; + "end_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__chained_pulses.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__chained_pulses.snap new file mode 100644 index 00000000..8022d73d --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__chained_pulses.snap @@ -0,0 +1,27 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + 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_end" [label="ordering"]; + "block_0_0" [shape=rectangle, label="[0] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "block_0_0" -> "block_0_1" [label="frame"]; + "block_0_1" [shape=rectangle, label="[1] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "block_0_1" -> "block_0_2" [label="frame"]; + "block_0_2" [shape=rectangle, label="[2] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "block_0_2" -> "block_0_3" [label="frame"]; + "block_0_3" [shape=rectangle, label="[3] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "block_0_3" -> "block_0_4" [label="frame"]; + "block_0_4" [shape=rectangle, label="[4] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "block_0_4" -> "block_0_end" [label="frame"]; + "block_0_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__different_frames_blocking.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__different_frames_blocking.snap new file mode 100644 index 00000000..56de0ae4 --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__different_frames_blocking.snap @@ -0,0 +1,23 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + 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_end" [label="ordering"]; + "block_0_0" [shape=rectangle, label="[0] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "block_0_0" -> "block_0_1" [label="frame"]; + "block_0_1" [shape=rectangle, label="[1] PULSE 1 \"rf\" test(duration: 1000000.0)"]; + "block_0_1" -> "block_0_2" [label="frame"]; + "block_0_2" [shape=rectangle, label="[2] PULSE 2 \"rf\" test(duration: 1000000.0)"]; + "block_0_2" -> "block_0_end" [label="frame"]; + "block_0_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__different_frames_nonblocking.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__different_frames_nonblocking.snap new file mode 100644 index 00000000..7f76fefd --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__different_frames_nonblocking.snap @@ -0,0 +1,25 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + 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="ordering"]; + "block_0_0" [shape=rectangle, label="[0] NONBLOCKING PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "block_0_0" -> "block_0_end" [label="frame"]; + "block_0_1" [shape=rectangle, label="[1] NONBLOCKING PULSE 1 \"rf\" test(duration: 1000000.0)"]; + "block_0_1" -> "block_0_end" [label="frame"]; + "block_0_2" [shape=rectangle, label="[2] NONBLOCKING PULSE 2 \"rf\" test(duration: 1000000.0)"]; + "block_0_2" -> "block_0_end" [label="frame"]; + "block_0_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__fence_all.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__fence_all.snap new file mode 100644 index 00000000..469d4bad --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__fence_all.snap @@ -0,0 +1,19 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + 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_end" [label="ordering"]; + "block_0_0" [shape=rectangle, label="[0] FENCE"]; + "block_0_0" -> "block_0_end" [label="frame"]; + "block_0_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__fence_all_with_nonblocking_pulses.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__fence_all_with_nonblocking_pulses.snap new file mode 100644 index 00000000..9bc61a13 --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__fence_all_with_nonblocking_pulses.snap @@ -0,0 +1,31 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + 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="ordering"]; + "block_0_0" [shape=rectangle, label="[0] NONBLOCKING PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "block_0_0" -> "block_0_2" [label="frame"]; + "block_0_1" [shape=rectangle, label="[1] NONBLOCKING PULSE 1 \"rf\" test(duration: 1000000.0)"]; + "block_0_1" -> "block_0_2" [label="frame"]; + "block_0_2" [shape=rectangle, label="[2] FENCE"]; + "block_0_2" -> "block_0_3" [label="frame"]; + "block_0_2" -> "block_0_4" [label="frame"]; + "block_0_2" -> "block_0_end" [label="frame"]; + "block_0_3" [shape=rectangle, label="[3] NONBLOCKING PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "block_0_3" -> "block_0_end" [label="frame"]; + "block_0_4" [shape=rectangle, label="[4] NONBLOCKING PULSE 1 \"rf\" test(duration: 1000000.0)"]; + "block_0_4" -> "block_0_end" [label="frame"]; + "block_0_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__jump.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__jump.snap new file mode 100644 index 00000000..822216f0 --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__jump.snap @@ -0,0 +1,42 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "first-block_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + label="first-block"; + node [style="filled"]; + "first-block_start" [shape=circle, label="start"]; + "first-block_start" -> "first-block_0" [label="frame"]; + "first-block_start" -> "first-block_end" [label="ordering"]; + "first-block_0" [shape=rectangle, label="[0] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "first-block_0" -> "first-block_end" [label="frame"]; + "first-block_end" [shape=circle, label="end"]; + } + "first-block_end" -> "third-block_start" [label="if ro[0] != 0"]; + "first-block_end" -> "second-block_start" [label="if ro[0] == 0"]; + subgraph cluster_1 { + label="second-block"; + node [style="filled"]; + "second-block_start" [shape=circle, label="start"]; + "second-block_start" -> "second-block_0" [label="frame"]; + "second-block_start" -> "second-block_end" [label="ordering"]; + "second-block_0" [shape=rectangle, label="[0] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "second-block_0" -> "second-block_end" [label="frame"]; + "second-block_end" [shape=circle, label="end"]; + } + "second-block_end" -> "third-block_start" [label="always"]; + subgraph cluster_2 { + label="third-block"; + node [style="filled"]; + "third-block_start" [shape=circle, label="start"]; + "third-block_start" -> "third-block_0" [label="frame"]; + "third-block_start" -> "third-block_end" [label="ordering"]; + "third-block_0" [shape=rectangle, label="[0] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "third-block_0" -> "third-block_end" [label="frame"]; + "third-block_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__labels_only.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__labels_only.snap new file mode 100644 index 00000000..b610baeb --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__labels_only.snap @@ -0,0 +1,32 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "a_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + label="a"; + node [style="filled"]; + "a_start" [shape=circle, label="start"]; + "a_start" -> "a_end" [label="ordering"]; + "a_end" [shape=circle, label="end"]; + } + "a_end" -> "b_start" [label="always"]; + subgraph cluster_1 { + label="b"; + node [style="filled"]; + "b_start" [shape=circle, label="start"]; + "b_start" -> "b_end" [label="ordering"]; + "b_end" [shape=circle, label="end"]; + } + "b_end" -> "c_start" [label="always"]; + subgraph cluster_2 { + label="c"; + node [style="filled"]; + "c_start" [shape=circle, label="start"]; + "c_start" -> "c_end" [label="ordering"]; + "c_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__multiple_classical_instructions.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__multiple_classical_instructions.snap new file mode 100644 index 00000000..d422ef84 --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__multiple_classical_instructions.snap @@ -0,0 +1,28 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + label="block_0"; + node [style="filled"]; + "block_0_start" [shape=circle, label="start"]; + "block_0_start" -> "block_0_0" [label="ordering"]; + "block_0_0" [shape=rectangle, label="[0] MOVE ro[0] 1"]; + "block_0_0" -> "block_0_1" [label="await write +ordering"]; + "block_0_1" [shape=rectangle, label="[1] MOVE ro[1] 0"]; + "block_0_1" -> "block_0_2" [label="await write +ordering"]; + "block_0_2" [shape=rectangle, label="[2] ADD ro[0] 5"]; + "block_0_2" -> "block_0_3" [label="await write +ordering"]; + "block_0_3" [shape=rectangle, label="[3] SUB ro[1] ro[0]"]; + "block_0_3" -> "block_0_end" [label="await write +ordering"]; + "block_0_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__parametric_pulse.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__parametric_pulse.snap new file mode 100644 index 00000000..0dce3c01 --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__parametric_pulse.snap @@ -0,0 +1,24 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + 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_end" [label="ordering"]; + "block_0_0" [shape=rectangle, label="[0] PULSE 0 \"rf\" test(a: param[0])"]; + "block_0_0" -> "block_0_1" [label="frame"]; + "block_0_0" -> "block_0_end" [label="await read"]; + "block_0_1" [shape=rectangle, label="[1] CAPTURE 0 \"ro_rx\" test(a: param[0]) ro[0]"]; + "block_0_1" -> "block_0_end" [label="await capture +await read +frame"]; + "block_0_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graph__tests__graph__parametric_pulse_using_capture_results.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__parametric_pulse_using_capture_results.snap similarity index 94% rename from src/program/snapshots/quil_rs__program__graph__tests__graph__parametric_pulse_using_capture_results.snap rename to src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__parametric_pulse_using_capture_results.snap index 50e4cf7c..c2f1dd71 100644 --- a/src/program/snapshots/quil_rs__program__graph__tests__graph__parametric_pulse_using_capture_results.snap +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__parametric_pulse_using_capture_results.snap @@ -1,5 +1,5 @@ --- -source: quil/src/program/graph.rs +source: quil/src/program/graphviz_dot.rs expression: "ProgramDebugWrapper{program: &scheduled_program,}" --- diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__parametric_pulses_using_capture_results.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__parametric_pulses_using_capture_results.snap new file mode 100644 index 00000000..5330e3de --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__parametric_pulses_using_capture_results.snap @@ -0,0 +1,41 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + 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_end" [label="ordering"]; + "block_0_0" [shape=rectangle, label="[0] CAPTURE 0 \"ro_rx\" test(a: param[0]) ro[0]"]; + "block_0_0" -> "block_0_1" [label="await capture +frame"]; + "block_0_0" -> "block_0_2" [label="frame"]; + "block_0_0" -> "block_0_3" [label="frame"]; + "block_0_0" -> "block_0_end" [label="await read"]; + "block_0_1" [shape=rectangle, label="[1] NONBLOCKING PULSE 0 \"rf\" test(a: ro[0])"]; + "block_0_1" -> "block_0_3" [label="await read +frame"]; + "block_0_2" [shape=rectangle, label="[2] NONBLOCKING PULSE 1 \"rf\" test(a: ro[0])"]; + "block_0_2" -> "block_0_3" [label="await read +frame"]; + "block_0_3" [shape=rectangle, label="[3] CAPTURE 0 \"ro_rx\" test(a: param[0]) ro[0]"]; + "block_0_3" -> "block_0_4" [label="await capture +frame"]; + "block_0_3" -> "block_0_5" [label="frame"]; + "block_0_3" -> "block_0_end" [label="await read +frame"]; + "block_0_4" [shape=rectangle, label="[4] NONBLOCKING PULSE 0 \"rf\" test(a: ro[0])"]; + "block_0_4" -> "block_0_end" [label="await read +frame"]; + "block_0_5" [shape=rectangle, label="[5] NONBLOCKING PULSE 1 \"rf\" test(a: ro[0])"]; + "block_0_5" -> "block_0_end" [label="await read +frame"]; + "block_0_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__pulse_after_capture.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__pulse_after_capture.snap new file mode 100644 index 00000000..c78798ff --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__pulse_after_capture.snap @@ -0,0 +1,22 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + 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_end" [label="ordering"]; + "block_0_0" [shape=rectangle, label="[0] CAPTURE 0 \"ro_rx\" test() ro[0]"]; + "block_0_0" -> "block_0_1" [label="frame"]; + "block_0_0" -> "block_0_end" [label="await capture"]; + "block_0_1" [shape=rectangle, label="[1] PULSE 0 \"rf\" test()"]; + "block_0_1" -> "block_0_end" [label="frame"]; + "block_0_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__simple_capture.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__simple_capture.snap new file mode 100644 index 00000000..aeacf601 --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__simple_capture.snap @@ -0,0 +1,20 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + 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_end" [label="ordering"]; + "block_0_0" [shape=rectangle, label="[0] CAPTURE 0 \"ro_rx\" test() ro[0]"]; + "block_0_0" -> "block_0_end" [label="await capture +frame"]; + "block_0_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__simple_memory_access.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__simple_memory_access.snap new file mode 100644 index 00000000..891fbd04 --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__simple_memory_access.snap @@ -0,0 +1,26 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + label="block_0"; + node [style="filled"]; + "block_0_start" [shape=circle, label="start"]; + "block_0_start" -> "block_0_0" [label="ordering"]; + "block_0_0" [shape=rectangle, label="[0] MOVE a[0] 1"]; + "block_0_0" -> "block_0_1" [label="ordering"]; + "block_0_0" -> "block_0_2" [label="await write"]; + "block_0_1" [shape=rectangle, label="[1] MOVE b[0] 2"]; + "block_0_1" -> "block_0_2" [label="await write +ordering"]; + "block_0_2" [shape=rectangle, label="[2] ADD a[0] b[0]"]; + "block_0_2" -> "block_0_end" [label="await read +await write +ordering"]; + "block_0_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__single_dependency.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__single_dependency.snap new file mode 100644 index 00000000..708c543c --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__single_dependency.snap @@ -0,0 +1,21 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + 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_end" [label="ordering"]; + "block_0_0" [shape=rectangle, label="[0] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "block_0_0" -> "block_0_1" [label="frame"]; + "block_0_1" [shape=rectangle, label="[1] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "block_0_1" -> "block_0_end" [label="frame"]; + "block_0_end" [shape=circle, label="end"]; + } +} + diff --git a/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__single_instruction.snap b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__single_instruction.snap new file mode 100644 index 00000000..4fcc3157 --- /dev/null +++ b/src/program/snapshots/quil_rs__program__graphviz_dot__tests__graph__single_instruction.snap @@ -0,0 +1,19 @@ +--- +source: src/program/graphviz_dot.rs +expression: dot_format +--- +digraph { + entry -> "block_0_start"; + entry [label="Entry Point"]; + subgraph cluster_0 { + 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_end" [label="ordering"]; + "block_0_0" [shape=rectangle, label="[0] PULSE 0 \"rf\" test(duration: 1000000.0)"]; + "block_0_0" -> "block_0_end" [label="frame"]; + "block_0_end" [shape=circle, label="end"]; + } +} +