From a25abb4acc1cc9c706ab60234eb6a6c17d85702e Mon Sep 17 00:00:00 2001 From: Ryan Meneses Date: Thu, 16 Feb 2023 15:46:46 -0800 Subject: [PATCH] Initial commit for LaTeX abstract factory model. --- Cargo.lock | 120 +----------- Cargo.toml | 3 +- src/program/latex.rs | 118 ++++++++++++ src/program/latex/README.md | 119 ++++++++++++ src/program/latex/generation.rs | 7 + src/program/latex/generation/diagram.rs | 51 ++++++ ...sts__tikz_operators__tikz_cnot_target.snap | 6 + ...__tests__tikz_operators__tikz_control.snap | 6 + ...s__tikz_operators__tikz_cphase_target.snap | 6 + ..._tests__tikz_operators__tikz_left_ket.snap | 6 + ...__tests__tikz_operators__tikz_measure.snap | 6 + ...tikz__tests__tikz_operators__tikz_nop.snap | 6 + ...ikz__tests__tikz_operators__tikz_swap.snap | 6 + ...sts__tikz_operators__tikz_swap_target.snap | 6 + src/program/latex/generation/diagram/tikz.rs | 80 ++++++++ .../latex/generation/diagram/tikz/quantikz.rs | 10 + src/program/latex/mod.rs | 173 ------------------ ...gram__latex__tests__gates__gate_x.snap.new | 6 - ...sts__tikz_operators__tikz_cnot_target.snap | 6 - ...__tests__tikz_operators__tikz_control.snap | 6 - ...s__tikz_operators__tikz_cphase_target.snap | 6 - ..._tests__tikz_operators__tikz_left_ket.snap | 6 - ...__tests__tikz_operators__tikz_measure.snap | 6 - ...atex__tests__tikz_operators__tikz_nop.snap | 6 - ...tex__tests__tikz_operators__tikz_swap.snap | 6 - ...sts__tikz_operators__tikz_swap_target.snap | 6 - ...tikz_default_diagram_gate_controlled.snap} | 0 ...tes__quantikz_default_diagram_gate_x.snap} | 0 ...tes__quantikz_default_diagram_gate_y.snap} | 0 29 files changed, 436 insertions(+), 347 deletions(-) create mode 100644 src/program/latex.rs create mode 100644 src/program/latex/README.md create mode 100644 src/program/latex/generation.rs create mode 100644 src/program/latex/generation/diagram.rs create mode 100644 src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_cnot_target.snap create mode 100644 src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_control.snap create mode 100644 src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_cphase_target.snap create mode 100644 src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_left_ket.snap create mode 100644 src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_measure.snap create mode 100644 src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_nop.snap create mode 100644 src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_swap.snap create mode 100644 src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_swap_target.snap create mode 100644 src/program/latex/generation/diagram/tikz.rs create mode 100644 src/program/latex/generation/diagram/tikz/quantikz.rs delete mode 100644 src/program/latex/mod.rs delete mode 100644 src/program/latex/snapshots/quil_rs__program__latex__tests__gates__gate_x.snap.new delete mode 100644 src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_cnot_target.snap delete mode 100644 src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_control.snap delete mode 100644 src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_cphase_target.snap delete mode 100644 src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_left_ket.snap delete mode 100644 src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_measure.snap delete mode 100644 src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_nop.snap delete mode 100644 src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_swap.snap delete mode 100644 src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_swap_target.snap rename src/program/{latex/snapshots/quil_rs__program__latex__tests__gates__gate_controlled.snap => snapshots/quil_rs__program__latex__tests__gates__quantikz_default_diagram_gate_controlled.snap} (100%) rename src/program/{latex/snapshots/quil_rs__program__latex__tests__gates__gate_x.snap => snapshots/quil_rs__program__latex__tests__gates__quantikz_default_diagram_gate_x.snap} (100%) rename src/program/{latex/snapshots/quil_rs__program__latex__tests__gates__gate_y.snap => snapshots/quil_rs__program__latex__tests__gates__quantikz_default_diagram_gate_y.snap} (100%) diff --git a/Cargo.lock b/Cargo.lock index 93947a46..90d94d8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "anes" version = "0.1.6" @@ -40,21 +25,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "backtrace" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - [[package]] name = "bit-set" version = "0.5.3" @@ -100,12 +70,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - [[package]] name = "cfg-if" version = "1.0.0" @@ -270,28 +234,6 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" -[[package]] -name = "failure" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" -dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.103", - "synstructure", -] - [[package]] name = "fastrand" version = "1.8.0" @@ -419,12 +361,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "gimli" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" - [[package]] name = "half" version = "1.8.2" @@ -508,15 +444,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "latex" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41cf333d23534df4dbd7513d5cbf52513b6b4741b9e642efa3e835c984ad241" -dependencies = [ - "failure", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -638,15 +565,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - [[package]] name = "nom" version = "7.1.1" @@ -696,15 +614,6 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.30.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.15.0" @@ -785,7 +694,7 @@ 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]] @@ -848,7 +757,6 @@ dependencies = [ "dot-writer", "indexmap", "insta", - "latex", "lexical", "nom", "nom_locate", @@ -1001,12 +909,6 @@ dependencies = [ "syn 1.0.103", ] -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - [[package]] name = "rustc_version" version = "0.4.0" @@ -1143,7 +1045,7 @@ checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" dependencies = [ "proc-macro2 0.4.30", "quote 0.6.13", - "unicode-xid 0.1.0", + "unicode-xid", ] [[package]] @@ -1157,18 +1059,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2 1.0.47", - "quote 1.0.21", - "syn 1.0.103", - "unicode-xid 0.2.4", -] - [[package]] name = "tempfile" version = "3.3.0" @@ -1241,12 +1131,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - [[package]] name = "wait-timeout" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index b96981a4..16a6c6cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ categories = ["parser-implementations", "science", "compilers", "emulators"] [dependencies] dot-writer = { version = "0.1.2", optional = true } -latex = { version = "0.3.1", optional = true } indexmap = "1.6.1" lexical = "6.1.1" nom = "7.1.1" @@ -30,7 +29,7 @@ rstest = "0.15.0" [features] graphviz-dot = ["dot-writer"] -to-latex = ["latex"] +latex = [] [[bench]] name = "parser" diff --git a/src/program/latex.rs b/src/program/latex.rs new file mode 100644 index 00000000..c5fc7977 --- /dev/null +++ b/src/program/latex.rs @@ -0,0 +1,118 @@ +use crate::Program; +use generation::{LatexFactory, diagram::DiagramFactory}; + +mod generation; + +pub struct Request { + document: Document, + settings: Option, +} + +impl Default for Request { + fn default() -> Self { + Self { document: Document::Diagram, settings: None} + } +} + +pub enum Document { + Diagram, + None, +} + +pub struct Settings; + +// TODO: Move inside of the ConcreteFactory +impl Default for Settings { + fn default() -> Self { + Self { } + } +} + +#[derive(thiserror::Error, Debug)] +pub enum LatexGenerationError { + // TODO: Add variants for each error type using `thiserror` crate to return detailed Result::Err. + #[error("This is an error on {qubit_index}.")] + SampleError{qubit_index: u32}, + #[error("Error NoRequest: A request is required to use this feature.")] + NoRequest, +} + +#[cfg(feature = "latex")] +pub trait Latex { + /// Returns a Result containing a string of LaTeX or a LatexGenerationError. + /// + /// # Arguments + /// * `option` - An Option containing a LaTeX Request. + /// * `Option::Some` - A valid Request that can be parsed. + /// * `Option::None` - An invalid Request that throws an error. + fn to_latex(self, request: Request) -> Result; +} + +impl Latex for Program { + fn to_latex(self, request: Request) -> Result { + match request.document { + Document::Diagram => { + let diagram_factory = Box::new(DiagramFactory {}); + let tikz_diagram_factory = diagram_factory.create_tikz_diagram(); + + tikz_diagram_factory.generate_default_quantikz_diagram(); + }, + Document::None => { + panic!("{}", LatexGenerationError::NoRequest); + }, + } + + // // TODO: Generate the Program LaTeX. + // let latex = ""; + + Ok("".to_string()) + } +} + +#[cfg(test)] +mod tests { + use super::{Program, Latex, Request, Document}; + use std::str::FromStr; + + /// Take an instruction and return the LaTeX using the to_latex method. + pub fn get_quantikz_diagram(instructions: &str) -> String { + let program = Program::from_str(instructions).expect("program should be returned"); + program.to_latex(Request::default()).expect("Quantikz diagram should generate without error") + } + + #[test] + #[should_panic(expected = "")] + /// Test functionality of to_latex using a request with a None document. + fn test_to_latex_should_panic_with_document_none() { + // Create an empty program as a string. + let program = Program::from_str("").expect("empty program should be created"); + program.to_latex(Request {document: Document::None, settings: None}).expect("function should panic with None document"); + } + + #[test] + /// Test functionality of to_latex using a default request of Document::Diagram and Settings::None. + fn test_to_latex_with_default_request() { + // Create an empty program as a string. + let program = Program::from_str("").expect("empty program should be created"); + program.to_latex(Request::default()).expect("function should work with default request"); + } + + mod gates { + use crate::program::latex::tests::get_quantikz_diagram; + + #[test] + fn test_quantikz_default_diagram_gate_x() { + insta::assert_snapshot!(get_quantikz_diagram("X 0")); + } + + #[test] + fn test_quantikz_default_diagram_gate_y() { + insta::assert_snapshot!(get_quantikz_diagram("Y 1")); + } + + #[test] + fn test_quantikz_default_diagram_gate_controlled() { + insta::assert_snapshot!(get_quantikz_diagram("CONTROLLED H 3 2")); + } + } +} diff --git a/src/program/latex/README.md b/src/program/latex/README.md new file mode 100644 index 00000000..bef64412 --- /dev/null +++ b/src/program/latex/README.md @@ -0,0 +1,119 @@ +# Quil LaTeX Generation using the AbstractFactory Design Pattern + +--- +## Context + +LaTeX is more than a circuit building utility, in general, it can be thought of as a powerful document generation tool with an expansive ecosystem of libraries each with their own unique packages. The abstract factory pattern used in this design opens LaTeX to quil-rs as more than a circuit building utility. It also narrows down LaTeX to documents that are explicitly made available (product branding opportunity) and specific to quantum programs which can be easily expanded upon, and encouraged to, using this design pattern. Provided the type of document is known, this feature can generate it in LaTeX. + + +--- +## User Compatibility + +If the user knows nothing about LaTeX but knows that the program can generate circuit diagrams that they can then copy and paste into a LaTeX renderer, they only need to call to_latex() using Python bindings. The default is to produce the same results with the same simplicity as pyQuil's to_latex feature, which is a Quantikz diagram of qubits and gates displayed on a circuit. + +With some knowledge of LaTeX, the user could also generate other documents made available, which this design encourages. For instance, if a user requests a graphical representation of a quil program that is made available, e.g. the probability density, a graph ConcreteFactory can be implemented that produces a pgfplots AbstractProduct which is defined stylistically in a, e.g. "quilplots", ConcreteProduct. + + +--- +## File Structure + +program/ +|-- latex.rs +|-- latex/ + |-- generation.rs + |-- generation/ + |-- diagram.rs + |-- diagram/ + |-- tikz.rs + |-- tikz/ + |-- quantikz.rs + +--- +## Directory and File Descriptions + +latex.rs +Defines the API to use the LaTeX generation feature. + +latex/ +Module containing all LaTeX generation code. + +generation.rs +Defines a LaTeX AbstractFactory that builds document-specific ConcreteFactories. + +generation/ +Module containing all LaTeX document-building ConcreteFactories and their products. + +diagram.rs +Defines a ConcreteFactory that builds AbstractDiagrams. + +diagram/ +Module containing the LaTeX AbstractDiagram and its ConcreteDiagrams. + +tikz.rs +Defines an AbstractDiagram TikZ that is an expansive diagram building library used to build ConcreteDiagrams. + +tikz/ +Module containing all ConcreteDiagrams that can be built using the TikZ library. + +quantikz.rs +Defines a ConcreteDiagram that is a Quantikz circuit from the TikZ library. + +**snapshots/ +Directories of snapshot unit tests. + + +--- +## Keywords + +LaTeX: a document generation tool. +TikZ: a LaTeX library used to generate a variety of LaTeX diagrams. +Quantikz: a TikZ package used to generate quantum circuits. +pgfplots: a LaTeX library used to visualize scientific/technical graphs. + + + +--- +## API Design + +quil-rs to_latex feature should be as flexible as Python's optional parameters. With Python bindings this can be as simple as calling to_latex(). The method signature for the same quil-rs function is + +`to_latex(self, request: Option) -> Result`. + +A Request is a struct with two attributes: + +document: Document, // An enum variant representing the type of document being requested. +settings: Settings, // Specific settings for how the document is rendered. + +Defaults +document: "diagram" // Specifically, a Quantikz diagram same as pyQuil. +settings: None // Default settings at the product level. + +Note on Settings + +- If settings are not specified then the default settings are defined in the ConcreteFactory if they can be generalized over all diagrams, or (inclusively) in the ConcreteProduct if they cannot be generalized but can only be applied on a specific type of diagram (e.q. Quantikz). Refer to the documentation for these specifications. + +- Without specifying them, settings are inferred depending on the type of document being created. More concretely, settings for diagrams are different from settings for plots. The program determines what type of settings are being used by matching it to the requested document type. This allows the document factory to apply the settings to the document being produced. + + +--- +## Program Flow + +Example generating a default (Quantikz) LaTeX diagram + +1. The Program makes a default request using the API defined in latex.rs. + +2. The request is parsed in latex.rs which is then passed to the create_diagram method on the AbstractFactory (latex/generation.rs) to build a diagram of a Quil Program with no settings. + +3. The AbstractFactory is then defined into a ConcreteFactory that builds diagrams (latex/generation/diagram.rs) with generalized settings. + +4. The ConcreteFactory then makes a request to generate a default diagram from the TikZ AbstractProduct (latex/generation/diagram/tikz.rs). + +5. The AbstractProduct is then defined defined into a ConcreteProduct that builds Quantikz diagrams (latex/generation/diagram/tikz/quantikz.rs). + +6. The Quantikz diagram is built at the ConcreteDiagram level and is returned to the Program + + +--- +## Conclusion + +The use of the AbstractFactory pattern opens several avenues within the LaTeX ecosystem for the rendering of any kind of document that might be useful in visualizing Quil programs or even generating reports (considering the many more uses for LaTeX beyond diagram rendering). The vision is that at some point, Quil Programs may want to be documented in another form that LaTeX will likely be able to provide. In this case, the LatexFactory can be expanded to implement a new factory that can construct the desired Quil document e.g. Pgfplots, a LaTeX package used to generate scientific/technical graphs. \ No newline at end of file diff --git a/src/program/latex/generation.rs b/src/program/latex/generation.rs new file mode 100644 index 00000000..5bfbdfea --- /dev/null +++ b/src/program/latex/generation.rs @@ -0,0 +1,7 @@ +use self::diagram::tikz::Tikz; + +pub mod diagram; + +pub trait LatexFactory { + fn create_tikz_diagram(&self) -> Box; +} \ No newline at end of file diff --git a/src/program/latex/generation/diagram.rs b/src/program/latex/generation/diagram.rs new file mode 100644 index 00000000..80f49bdd --- /dev/null +++ b/src/program/latex/generation/diagram.rs @@ -0,0 +1,51 @@ +use self::tikz::{Tikz, quantikz::Quantikz}; +use super::LatexFactory; + +pub mod tikz; + +pub struct DiagramFactory; + +impl LatexFactory for DiagramFactory { + fn create_tikz_diagram(&self) -> Box { + Box::new(Quantikz {}) + } +} + +#[derive(Debug)] +/// Settings to control the layout and rendering of circuits. +pub struct DiagramSettings { + /// Convert numerical constants, such as pi, to LaTeX form. + texify_numerical_constants: bool, + + /// Include qubits with indices between those explicitly referenced in the Quil program. + /// For example, if true, the diagram for `CNOT 0 2` would have three qubit lines: 0, 1, 2. + impute_missing_qubits: bool, + + /// Label qubit lines. + label_qubit_lines: bool, + + /// Write controlled rotations in a compact form. + /// For example, `RX(pi)` as `X_{\\pi}`, instead of the longer `R_X(\\pi)` + abbreviate_controlled_rotations: bool, + + /// The length by which qubit lines should be extended with open wires at the right of the diagram. + /// The default of 1 is the natural choice. The main reason for including this option + /// is that it may be appropriate for this to be 0 in subdiagrams. + qubit_line_open_wire_length: u32, + + /// Align measurement operations which appear at the end of the program. + right_align_terminal_measurements: bool, +} + +impl Default for DiagramSettings { + fn default() -> Self { + Self { + texify_numerical_constants: true, + impute_missing_qubits: false, + label_qubit_lines: true, + abbreviate_controlled_rotations: false, + qubit_line_open_wire_length: 1, + right_align_terminal_measurements: true, + } + } +} \ No newline at end of file diff --git a/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_cnot_target.snap b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_cnot_target.snap new file mode 100644 index 00000000..85acfa48 --- /dev/null +++ b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_cnot_target.snap @@ -0,0 +1,6 @@ +--- +source: src/program/latex/generation/diagram/tikz.rs +assertion_line: 52 +expression: "TikzOperator::get_tikz_operator(TikzOperator::TikzCnotTarget)" +--- +\targ{} diff --git a/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_control.snap b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_control.snap new file mode 100644 index 00000000..3cae6051 --- /dev/null +++ b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_control.snap @@ -0,0 +1,6 @@ +--- +source: src/program/latex/generation/diagram/tikz.rs +assertion_line: 47 +expression: "TikzOperator::get_tikz_operator(TikzOperator::TikzControl(2))" +--- +\ctrl{2} diff --git a/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_cphase_target.snap b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_cphase_target.snap new file mode 100644 index 00000000..91fe2967 --- /dev/null +++ b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_cphase_target.snap @@ -0,0 +1,6 @@ +--- +source: src/program/latex/generation/diagram/tikz.rs +assertion_line: 57 +expression: "TikzOperator::get_tikz_operator(TikzOperator::TikzCphaseTarget)" +--- +\control{} diff --git a/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_left_ket.snap b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_left_ket.snap new file mode 100644 index 00000000..350c39f3 --- /dev/null +++ b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_left_ket.snap @@ -0,0 +1,6 @@ +--- +source: src/program/latex/generation/diagram/tikz.rs +assertion_line: 42 +expression: "TikzOperator::get_tikz_operator(TikzOperator::TikzLeftKet(0))" +--- +\lstick{\ket{q_{0}}} diff --git a/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_measure.snap b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_measure.snap new file mode 100644 index 00000000..e6714223 --- /dev/null +++ b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_measure.snap @@ -0,0 +1,6 @@ +--- +source: src/program/latex/generation/diagram/tikz.rs +assertion_line: 77 +expression: "TikzOperator::get_tikz_operator(TikzOperator::TikzMeasure)" +--- +\meter{} diff --git a/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_nop.snap b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_nop.snap new file mode 100644 index 00000000..48334e6a --- /dev/null +++ b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_nop.snap @@ -0,0 +1,6 @@ +--- +source: src/program/latex/generation/diagram/tikz.rs +assertion_line: 72 +expression: "TikzOperator::get_tikz_operator(TikzOperator::TikzNop)" +--- +\qw diff --git a/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_swap.snap b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_swap.snap new file mode 100644 index 00000000..4bef445d --- /dev/null +++ b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_swap.snap @@ -0,0 +1,6 @@ +--- +source: src/program/latex/generation/diagram/tikz.rs +assertion_line: 62 +expression: "TikzOperator::get_tikz_operator(TikzOperator::TikzSwap(4))" +--- +\swap{4} diff --git a/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_swap_target.snap b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_swap_target.snap new file mode 100644 index 00000000..3acd2f2d --- /dev/null +++ b/src/program/latex/generation/diagram/snapshots/quil_rs__program__latex__generation__diagram__tikz__tests__tikz_operators__tikz_swap_target.snap @@ -0,0 +1,6 @@ +--- +source: src/program/latex/generation/diagram/tikz.rs +assertion_line: 67 +expression: "TikzOperator::get_tikz_operator(TikzOperator::TikzSwapTarget)" +--- +\targX{} diff --git a/src/program/latex/generation/diagram/tikz.rs b/src/program/latex/generation/diagram/tikz.rs new file mode 100644 index 00000000..43aaa9e5 --- /dev/null +++ b/src/program/latex/generation/diagram/tikz.rs @@ -0,0 +1,80 @@ +use std::fmt::format; + +pub mod quantikz; + +pub trait Tikz { + fn generate_default_quantikz_diagram(&self); +} + +pub enum TikzOperator { + TikzLeftKet(u32), + TikzControl(i32), + TikzCnotTarget, + TikzCphaseTarget, + TikzSwap(i32), + TikzSwapTarget, + TikzNop, + TikzMeasure, +} + +impl TikzOperator { + fn get_tikz_operator(tikz_operator: Self) -> String { + match tikz_operator { + Self::TikzLeftKet(qubit) => format(format_args!(r#"\lstick{{\ket{{q_{{{qubit}}}}}}}"#)), // \lstick{\ket{q_{qubit}}} + Self::TikzControl(offset) => format(format_args!(r#"\ctrl{{{offset}}}"#)), // \ctrl{offset} + Self::TikzCnotTarget => r"\targ{}".to_string(), // \targ{} + Self::TikzCphaseTarget => r"\control{}".to_string(), // \control{} + Self::TikzSwap(offset) => format(format_args!(r"\swap{{{offset}}}")), // \swap{offset} + Self::TikzSwapTarget => r"\targX{}".to_string(), // \targX{} + Self::TikzNop => r"\qw".to_string(), // \qw + Self::TikzMeasure => r"\meter{}".to_string(), // \meter{} + } + } +} + +#[cfg(test)] +mod tests { + mod tikz_operators { + use super::super::TikzOperator; + + #[test] + fn test_tikz_left_ket() { + insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzLeftKet(0))); + } + + #[test] + fn test_tikz_control() { + insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzControl(2))); + } + + #[test] + fn test_tikz_cnot_target() { + insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzCnotTarget)); + } + + #[test] + fn test_tikz_cphase_target() { + insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzCphaseTarget)); + } + + #[test] + fn test_tikz_swap() { + insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzSwap(4))); + } + + #[test] + fn test_tikz_swap_target() { + insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzSwapTarget)); + } + + #[test] + fn test_tikz_nop() { + insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzNop)); + } + + #[test] + fn test_tikz_measure() { + insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzMeasure)); + } + } +} \ No newline at end of file diff --git a/src/program/latex/generation/diagram/tikz/quantikz.rs b/src/program/latex/generation/diagram/tikz/quantikz.rs new file mode 100644 index 00000000..1665995f --- /dev/null +++ b/src/program/latex/generation/diagram/tikz/quantikz.rs @@ -0,0 +1,10 @@ +use super::Tikz; + +pub struct Quantikz; + +impl Tikz for Quantikz { + fn generate_default_quantikz_diagram(&self) { + // TODO: Generate a Quantikz diagram of the program with default settings. + println!("Generating default Quantikz circuit.") + } +} \ No newline at end of file diff --git a/src/program/latex/mod.rs b/src/program/latex/mod.rs deleted file mode 100644 index 49cf0ee9..00000000 --- a/src/program/latex/mod.rs +++ /dev/null @@ -1,173 +0,0 @@ -use std::fmt::format; - -use crate::Program; - -#[derive(Debug)] -/// Settings to control the layout and rendering of circuits. -pub struct DiagramSettings { - /// Convert numerical constants, such as pi, to LaTeX form. - texify_numerical_constants: bool, - - /// Include qubits with indices between those explicitly referenced in the Quil program. - /// For example, if true, the diagram for `CNOT 0 2` would have three qubit lines: 0, 1, 2. - impute_missing_qubits: bool, - - /// Label qubit lines. - label_qubit_lines: bool, - - /// Write controlled rotations in a compact form. - /// For example, `RX(pi)` as `X_{\\pi}`, instead of the longer `R_X(\\pi)` - abbreviate_controlled_rotations: bool, - - /// The length by which qubit lines should be extended with open wires at the right of the diagram. - /// The default of 1 is the natural choice. The main reason for including this option - /// is that it may be appropriate for this to be 0 in subdiagrams. - qubit_line_open_wire_length: u32, - - /// Align measurement operations which appear at the end of the program. - right_align_terminal_measurements: bool, -} - -impl Default for DiagramSettings { - fn default() -> Self { - Self { - texify_numerical_constants: true, - impute_missing_qubits: false, - label_qubit_lines: true, - abbreviate_controlled_rotations: false, - qubit_line_open_wire_length: 1, - right_align_terminal_measurements: true, - } - } -} - -pub enum TikzOperator { - TikzLeftKet(u32), - TikzControl(i32), - TikzCnotTarget, - TikzCphaseTarget, - TikzSwap(i32), - TikzSwapTarget, - TikzNop, - TikzMeasure, -} - -impl TikzOperator { - fn get_tikz_operator(tikz_operator: Self) -> String { - match tikz_operator { - Self::TikzLeftKet(qubit) => format(format_args!(r#"\lstick{{\ket{{q_{{{qubit}}}}}}}"#)), // \lstick{\ket{q_{qubit}}} - Self::TikzControl(offset) => format(format_args!(r#"\ctrl{{{offset}}}"#)), // \ctrl{offset} - Self::TikzCnotTarget => r"\targ{}".to_string(), // \targ{} - Self::TikzCphaseTarget => r"\control{}".to_string(), // \control{} - Self::TikzSwap(offset) => format(format_args!(r"\swap{{{offset}}}")), // \swap{offset} - Self::TikzSwapTarget => r"\targX{}".to_string(), // \targX{} - Self::TikzNop => r"\qw".to_string(), // \qw - Self::TikzMeasure => r"\meter{}".to_string(), // \meter{} - } - } -} - -#[derive(thiserror::Error, Debug)] -pub enum LatexGenError { - // TODO: Add variants for each error type using `thiserror` crate to return detailed Result::Err. - #[error("This is an error on {qubit_index}.")] - SomeError{qubit_index: u32}, -} - -pub trait ToLatex { - fn to_latex(self, diagram_settings: DiagramSettings) -> Result; -} - -impl ToLatex for Program { - fn to_latex(self, diagram_settings: DiagramSettings) -> Result { - // TODO: Generate the Program LaTeX. - let latex = ""; - - Ok(latex.to_string()) - } -} - -#[cfg(test)] -mod tests { - use super::{DiagramSettings, ToLatex}; - use crate::Program; - use std::str::FromStr; - - /// Take an instruction and return the LaTeX using the to_latex method. - pub fn get_latex(instructions: &str) -> String { - let program = Program::from_str(instructions).expect("Program should be returned."); - program - .to_latex(DiagramSettings::default()) - .expect("LaTeX should generate without error.") - } - - #[test] - /// Test functionality of to_latex using default settings. - fn test_to_latex() { - let program = Program::from_str("").expect(""); - program.to_latex(DiagramSettings::default()).expect(""); - } - - mod gates { - use crate::program::latex::tests::get_latex; - - #[test] - fn test_gate_x() { - insta::assert_snapshot!(get_latex("X 0")); - } - - #[test] - fn test_gate_y() { - insta::assert_snapshot!(get_latex("Y 1")); - } - - #[test] - fn test_gate_controlled() { - insta::assert_snapshot!(get_latex("CONTROLLED H 3 2")); - } - } - - mod tikz_operators { - use crate::program::latex::TikzOperator; - - #[test] - fn test_tikz_left_ket() { - insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzLeftKet(0))); - } - - #[test] - fn test_tikz_control() { - insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzControl(2))); - } - - #[test] - fn test_tikz_cnot_target() { - insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzCnotTarget)); - } - - #[test] - fn test_tikz_cphase_target() { - insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzCphaseTarget)); - } - - #[test] - fn test_tikz_swap() { - insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzSwap(4))); - } - - #[test] - fn test_tikz_swap_target() { - insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzSwapTarget)); - } - - #[test] - fn test_tikz_nop() { - insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzNop)); - } - - #[test] - fn test_tikz_measure() { - insta::assert_snapshot!(TikzOperator::get_tikz_operator(TikzOperator::TikzMeasure)); - } - } -} diff --git a/src/program/latex/snapshots/quil_rs__program__latex__tests__gates__gate_x.snap.new b/src/program/latex/snapshots/quil_rs__program__latex__tests__gates__gate_x.snap.new deleted file mode 100644 index 37015ec6..00000000 --- a/src/program/latex/snapshots/quil_rs__program__latex__tests__gates__gate_x.snap.new +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/program/latex/mod.rs -assertion_line: 116 -expression: "get_latex(\"X 0\")" ---- - diff --git a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_cnot_target.snap b/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_cnot_target.snap deleted file mode 100644 index 899f6ee6..00000000 --- a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_cnot_target.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/program/latex.rs -assertion_line: 157 -expression: "TikzOperators::get_tikz_operator(TikzOperators::tikz_cnot_target)" ---- -\targ{} diff --git a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_control.snap b/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_control.snap deleted file mode 100644 index e5f43424..00000000 --- a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_control.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/program/latex.rs -assertion_line: 150 -expression: "TikzOperators::get_tikz_operator(TikzOperators::tikz_control(2))" ---- -\ctrl{2} diff --git a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_cphase_target.snap b/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_cphase_target.snap deleted file mode 100644 index 07bd40b2..00000000 --- a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_cphase_target.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/program/latex.rs -assertion_line: 164 -expression: "TikzOperators::get_tikz_operator(TikzOperators::tikz_cphase_target)" ---- -\control{} diff --git a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_left_ket.snap b/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_left_ket.snap deleted file mode 100644 index f1cce67e..00000000 --- a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_left_ket.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/program/latex.rs -assertion_line: 143 -expression: "TikzOperators::get_tikz_operator(TikzOperators::tikz_left_ket(0))" ---- -\lstick{\ket{q_{0}}} diff --git a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_measure.snap b/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_measure.snap deleted file mode 100644 index 8daec78b..00000000 --- a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_measure.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/program/latex.rs -assertion_line: 190 -expression: "TikzOperators::get_tikz_operator(TikzOperators::tikz_measure)" ---- -\meter{} diff --git a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_nop.snap b/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_nop.snap deleted file mode 100644 index ebc5c10c..00000000 --- a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_nop.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/program/latex.rs -assertion_line: 185 -expression: "TikzOperators::get_tikz_operator(TikzOperators::tikz_nop)" ---- -\qw diff --git a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_swap.snap b/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_swap.snap deleted file mode 100644 index 06a9f7fe..00000000 --- a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_swap.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/program/latex.rs -assertion_line: 171 -expression: "TikzOperators::get_tikz_operator(TikzOperators::tikz_swap(4))" ---- -\swap{4} diff --git a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_swap_target.snap b/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_swap_target.snap deleted file mode 100644 index faf86045..00000000 --- a/src/program/latex/snapshots/quil_rs__program__latex__tests__tikz_operators__tikz_swap_target.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/program/latex.rs -assertion_line: 178 -expression: "TikzOperators::get_tikz_operator(TikzOperators::tikz_swap_target)" ---- -\targX{} diff --git a/src/program/latex/snapshots/quil_rs__program__latex__tests__gates__gate_controlled.snap b/src/program/snapshots/quil_rs__program__latex__tests__gates__quantikz_default_diagram_gate_controlled.snap similarity index 100% rename from src/program/latex/snapshots/quil_rs__program__latex__tests__gates__gate_controlled.snap rename to src/program/snapshots/quil_rs__program__latex__tests__gates__quantikz_default_diagram_gate_controlled.snap diff --git a/src/program/latex/snapshots/quil_rs__program__latex__tests__gates__gate_x.snap b/src/program/snapshots/quil_rs__program__latex__tests__gates__quantikz_default_diagram_gate_x.snap similarity index 100% rename from src/program/latex/snapshots/quil_rs__program__latex__tests__gates__gate_x.snap rename to src/program/snapshots/quil_rs__program__latex__tests__gates__quantikz_default_diagram_gate_x.snap diff --git a/src/program/latex/snapshots/quil_rs__program__latex__tests__gates__gate_y.snap b/src/program/snapshots/quil_rs__program__latex__tests__gates__quantikz_default_diagram_gate_y.snap similarity index 100% rename from src/program/latex/snapshots/quil_rs__program__latex__tests__gates__gate_y.snap rename to src/program/snapshots/quil_rs__program__latex__tests__gates__quantikz_default_diagram_gate_y.snap