quil_rs/instruction/
circuit.rs

1use crate::quil::{Quil, INDENT};
2
3use super::Instruction;
4
5#[derive(Clone, Debug, PartialEq)]
6pub struct CircuitDefinition {
7    pub name: String,
8    pub parameters: Vec<String>,
9    // These cannot be fixed qubits and thus are not typed as `Qubit`
10    pub qubit_variables: Vec<String>,
11    pub instructions: Vec<Instruction>,
12}
13
14impl CircuitDefinition {
15    pub fn new(
16        name: String,
17        parameters: Vec<String>,
18        qubit_variables: Vec<String>,
19        instructions: Vec<Instruction>,
20    ) -> Self {
21        Self {
22            name,
23            parameters,
24            qubit_variables,
25            instructions,
26        }
27    }
28}
29
30impl Quil for CircuitDefinition {
31    fn write(
32        &self,
33        writer: &mut impl std::fmt::Write,
34        fall_back_to_debug: bool,
35    ) -> Result<(), crate::quil::ToQuilError> {
36        write!(writer, "DEFCIRCUIT {}", self.name)?;
37        if !self.parameters.is_empty() {
38            write!(writer, "(")?;
39            let mut iter = self.parameters.iter();
40            if let Some(p) = iter.next() {
41                write!(writer, "%{}", p)?;
42            }
43            for p in iter {
44                write!(writer, ", %{}", p)?;
45            }
46            write!(writer, ")")?;
47        }
48        for qubit_variable in &self.qubit_variables {
49            write!(writer, " {}", qubit_variable)?;
50        }
51        writeln!(writer, ":")?;
52        for instruction in &self.instructions {
53            let lines = match fall_back_to_debug {
54                true => instruction.to_quil_or_debug(),
55                false => instruction.to_quil()?,
56            };
57            for line in lines.split('\n') {
58                writeln!(writer, "{INDENT}{line}")?;
59            }
60        }
61
62        Ok(())
63    }
64}
65
66#[cfg(test)]
67mod test_circuit_definition {
68    use crate::expression::Expression;
69    use crate::instruction::{Gate, Instruction, Qubit};
70    use crate::quil::Quil;
71
72    use super::CircuitDefinition;
73
74    use insta::assert_snapshot;
75    use rstest::rstest;
76
77    #[rstest]
78    #[case(
79        "CircuitDefinition No Params",
80        CircuitDefinition {
81            name: "BELL".to_owned(),
82            parameters: vec![],
83            qubit_variables: vec!["a".to_owned(), "b".to_owned()],
84            instructions: vec![
85                Instruction::Gate(Gate {
86                    name: "H".to_owned(),
87                    parameters: vec![],
88                    qubits: vec![Qubit::Variable("a".to_owned())],
89                    modifiers: vec![],
90                }),
91                Instruction::Gate(Gate {
92                    name: "CNOT".to_owned(),
93                    parameters: vec![],
94                    qubits: vec![
95                        Qubit::Variable("a".to_owned()),
96                        Qubit::Variable("b".to_owned())
97                    ],
98                    modifiers: vec![],
99                })
100            ]
101        }
102    )]
103    #[case(
104        "CircuitDefinition With Params",
105        CircuitDefinition {
106            name: "BELL".to_owned(),
107            parameters: vec!["a".to_owned(), "b".to_owned()],
108            qubit_variables: vec!["a".to_owned(), "b".to_owned()],
109            instructions: vec![
110                Instruction::Gate(Gate {
111                    name: "RZ".to_owned(),
112                    parameters: vec![Expression::Variable("a".to_owned())],
113                    qubits: vec![Qubit::Variable("a".to_owned())],
114                    modifiers: vec![],
115                }),
116                Instruction::Gate(Gate {
117                    name: "RZ".to_owned(),
118                    parameters: vec![Expression::Variable("b".to_owned())],
119                    qubits: vec![Qubit::Variable("a".to_owned())],
120                    modifiers: vec![],
121                }),
122                Instruction::Gate(Gate {
123                    name: "RX".to_owned(),
124                    parameters: vec![Expression::Variable("a".to_owned())],
125                    qubits: vec![Qubit::Variable("a".to_owned())],
126                    modifiers: vec![],
127                }),
128                Instruction::Gate(Gate {
129                    name: "RZ".to_owned(),
130                    parameters: vec![Expression::Variable("a".to_owned())],
131                    qubits: vec![Qubit::Variable("a".to_owned())],
132                    modifiers: vec![],
133                }),
134                Instruction::Gate(Gate {
135                    name: "CNOT".to_owned(),
136                    parameters: vec![],
137                    qubits: vec![
138                        Qubit::Variable("a".to_owned()),
139                        Qubit::Variable("b".to_owned())
140                    ],
141                    modifiers: vec![],
142                })
143            ]
144        }
145    )]
146    #[case(
147        "CircuitDefinition With Single Param",
148        CircuitDefinition {
149            name: "BELL".to_owned(),
150            parameters: vec!["a".to_owned()],
151            qubit_variables: vec!["a".to_owned(), "b".to_owned()],
152            instructions: vec![
153                Instruction::Gate(Gate {
154                    name: "RZ".to_owned(),
155                    parameters: vec![Expression::Variable("a".to_owned())],
156                    qubits: vec![Qubit::Variable("a".to_owned())],
157                    modifiers: vec![],
158                }),
159                Instruction::Gate(Gate {
160                    name: "RX".to_owned(),
161                    parameters: vec![Expression::Variable("a".to_owned())],
162                    qubits: vec![Qubit::Variable("a".to_owned())],
163                    modifiers: vec![],
164                }),
165                Instruction::Gate(Gate {
166                    name: "RZ".to_owned(),
167                    parameters: vec![Expression::Variable("a".to_owned())],
168                    qubits: vec![Qubit::Variable("a".to_owned())],
169                    modifiers: vec![],
170                }),
171                Instruction::Gate(Gate {
172                    name: "CNOT".to_owned(),
173                    parameters: vec![],
174                    qubits: vec![
175                        Qubit::Variable("a".to_owned()),
176                        Qubit::Variable("b".to_owned())
177                    ],
178                    modifiers: vec![],
179                })
180            ]
181        }
182    )]
183    fn test_display(#[case] description: &str, #[case] circuit_def: CircuitDefinition) {
184        insta::with_settings!({
185            snapshot_suffix => description,
186        }, {
187            assert_snapshot!(circuit_def.to_quil_or_debug())
188        })
189    }
190}