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 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}