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