quil_rs/instruction/
circuit.rs

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