microsoft/qdk
Publicmirrored from https://github.com/microsoft/qdkAvailable
source/compiler/qsc_circuit/src/circuit/tests.rs
266lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | use super::*; |
| 5 | use expect_test::expect; |
| 6 | |
| 7 | /// Converts a 2D grid of operations into a component grid. |
| 8 | /// |
| 9 | /// # Arguments |
| 10 | /// |
| 11 | /// * `operations` - A 2D vector of operations to be converted. |
| 12 | /// |
| 13 | /// # Returns |
| 14 | /// |
| 15 | /// A component grid representing the operations. |
| 16 | pub fn op_grid_to_comp_grid(operations: Vec<Vec<Operation>>) -> ComponentGrid { |
| 17 | let mut component_grid = vec![]; |
| 18 | for col in operations { |
| 19 | let column = ComponentColumn { components: col }; |
| 20 | component_grid.push(column); |
| 21 | } |
| 22 | component_grid |
| 23 | } |
| 24 | |
| 25 | fn qubit(id: usize) -> Qubit { |
| 26 | Qubit { |
| 27 | id, |
| 28 | num_results: 0, |
| 29 | declarations: vec![], |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | fn qubit_with_results(id: usize, num_results: usize) -> Qubit { |
| 34 | Qubit { |
| 35 | id, |
| 36 | num_results, |
| 37 | declarations: vec![], |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | fn q_reg(id: usize) -> Register { |
| 42 | Register::quantum(id) |
| 43 | } |
| 44 | |
| 45 | fn c_reg(q_id: usize, c_id: usize) -> Register { |
| 46 | Register::classical(q_id, c_id) |
| 47 | } |
| 48 | |
| 49 | fn measurement(q_id: usize, c_id: usize) -> Operation { |
| 50 | Operation::Measurement(Measurement { |
| 51 | gate: "Measure".to_string(), |
| 52 | args: vec![], |
| 53 | qubits: vec![Register::quantum(q_id)], |
| 54 | results: vec![Register::classical(q_id, c_id)], |
| 55 | children: vec![], |
| 56 | metadata: None, |
| 57 | }) |
| 58 | } |
| 59 | |
| 60 | fn unitary(gate: &str, targets: Vec<Register>) -> Operation { |
| 61 | Operation::Unitary(Unitary { |
| 62 | gate: gate.to_string(), |
| 63 | args: vec![], |
| 64 | is_adjoint: false, |
| 65 | controls: vec![], |
| 66 | targets, |
| 67 | children: vec![], |
| 68 | metadata: None, |
| 69 | }) |
| 70 | } |
| 71 | |
| 72 | fn ctl_unitary(gate: &str, targets: Vec<Register>, controls: Vec<Register>) -> Operation { |
| 73 | Operation::Unitary(Unitary { |
| 74 | gate: gate.to_string(), |
| 75 | args: vec![], |
| 76 | is_adjoint: false, |
| 77 | controls, |
| 78 | targets, |
| 79 | children: vec![], |
| 80 | metadata: None, |
| 81 | }) |
| 82 | } |
| 83 | |
| 84 | #[test] |
| 85 | fn deserialize_circuit() { |
| 86 | let contents = r#" |
| 87 | { |
| 88 | "qubits": [ { "id": 0 }, { "id": 1 } ], |
| 89 | "componentGrid": [ |
| 90 | { |
| 91 | "components": [ |
| 92 | { "kind": "unitary", "gate": "H", "targets": [{ "qubit": 0 }] }, |
| 93 | { "kind": "unitary", "gate": "X", "targets": [{ "qubit": 1 }] } |
| 94 | ] |
| 95 | }, |
| 96 | { |
| 97 | "components": [ |
| 98 | { "kind": "unitary", "gate": "Z", "targets": [{ "qubit": 0 }] } |
| 99 | ] |
| 100 | }, |
| 101 | { |
| 102 | "components": [ |
| 103 | { "kind": "unitary", "gate": "X", "targets": [{ "qubit": 1 }], "controls": [{ "qubit": 0 }] } |
| 104 | ] |
| 105 | } |
| 106 | ] |
| 107 | }"#; |
| 108 | |
| 109 | let c = serde_json::from_str::<Circuit>(contents).expect("Was not able to deserialize"); |
| 110 | |
| 111 | expect![[r#" |
| 112 | q_0 ── H ──── Z ──── ● ── |
| 113 | q_1 ── X ─────────── X ── |
| 114 | "#]] |
| 115 | .assert_eq(&c.to_string()); |
| 116 | } |
| 117 | |
| 118 | #[test] |
| 119 | fn empty() { |
| 120 | let c = Circuit { |
| 121 | qubits: vec![], |
| 122 | component_grid: vec![], |
| 123 | }; |
| 124 | expect![[""]].assert_eq(&c.to_string()); |
| 125 | } |
| 126 | |
| 127 | #[test] |
| 128 | fn no_gates() { |
| 129 | let c = Circuit { |
| 130 | qubits: vec![qubit(0), qubit(1)], |
| 131 | component_grid: vec![], |
| 132 | }; |
| 133 | |
| 134 | expect![[r" |
| 135 | q_0 |
| 136 | q_1 |
| 137 | "]] |
| 138 | .assert_eq(&c.to_string()); |
| 139 | } |
| 140 | |
| 141 | #[test] |
| 142 | fn bell() { |
| 143 | let operations = vec![ |
| 144 | unitary("H", vec![q_reg(0)]), |
| 145 | ctl_unitary("X", vec![q_reg(1)], vec![q_reg(0)]), |
| 146 | measurement(0, 0), |
| 147 | measurement(1, 0), |
| 148 | ]; |
| 149 | let qubits = vec![qubit_with_results(0, 1), qubit_with_results(1, 1)]; |
| 150 | let component_grid = operation_list_to_grid(operations, qubits.len()); |
| 151 | let c = Circuit { |
| 152 | qubits, |
| 153 | component_grid, |
| 154 | }; |
| 155 | |
| 156 | expect![[r" |
| 157 | q_0 ── H ──── ● ──── M ── |
| 158 | │ ╘═══ |
| 159 | q_1 ───────── X ──── M ── |
| 160 | ╘═══ |
| 161 | "]] |
| 162 | .assert_eq(&c.to_string()); |
| 163 | } |
| 164 | |
| 165 | #[test] |
| 166 | fn control_classical() { |
| 167 | let operations = vec![ |
| 168 | measurement(0, 0), |
| 169 | ctl_unitary("X", vec![q_reg(2)], vec![c_reg(0, 0)]), |
| 170 | ctl_unitary("X", vec![q_reg(2)], vec![q_reg(0)]), |
| 171 | ]; |
| 172 | let qubits = vec![qubit_with_results(0, 1), qubit(1), qubit(2)]; |
| 173 | let component_grid = operation_list_to_grid(operations, qubits.len()); |
| 174 | let c = Circuit { |
| 175 | qubits, |
| 176 | component_grid, |
| 177 | }; |
| 178 | |
| 179 | expect![[r" |
| 180 | q_0 ── M ─────────── ● ── |
| 181 | ╘═════ ● ═════╪═══ |
| 182 | q_1 ──────────┼──────┼─── |
| 183 | q_2 ───────── X ──── X ── |
| 184 | "]] |
| 185 | .assert_eq(&c.to_string()); |
| 186 | } |
| 187 | |
| 188 | #[test] |
| 189 | fn two_measurements() { |
| 190 | let operations = vec![measurement(0, 0), measurement(0, 1)]; |
| 191 | let qubits = vec![qubit_with_results(0, 2)]; |
| 192 | let component_grid = operation_list_to_grid(operations, qubits.len()); |
| 193 | let c = Circuit { |
| 194 | qubits, |
| 195 | component_grid, |
| 196 | }; |
| 197 | |
| 198 | expect![[r" |
| 199 | q_0 ── M ──── M ── |
| 200 | ╘══════╪═══ |
| 201 | ╘═══ |
| 202 | "]] |
| 203 | .assert_eq(&c.to_string()); |
| 204 | } |
| 205 | |
| 206 | #[test] |
| 207 | fn with_args() { |
| 208 | let c = Circuit { |
| 209 | qubits: vec![qubit(0)], |
| 210 | component_grid: op_grid_to_comp_grid(vec![vec![Operation::Unitary(Unitary { |
| 211 | gate: "rx".to_string(), |
| 212 | args: vec!["1.5708".to_string()], |
| 213 | is_adjoint: false, |
| 214 | controls: vec![], |
| 215 | targets: vec![Register::quantum(0)], |
| 216 | children: vec![], |
| 217 | metadata: None, |
| 218 | })]]), |
| 219 | }; |
| 220 | |
| 221 | expect![[r" |
| 222 | q_0 ─ rx(1.5708) ── |
| 223 | "]] |
| 224 | .assert_eq(&c.to_string()); |
| 225 | } |
| 226 | |
| 227 | #[test] |
| 228 | fn two_targets() { |
| 229 | let c = Circuit { |
| 230 | qubits: vec![qubit(0), qubit(1), qubit(2)], |
| 231 | component_grid: op_grid_to_comp_grid(vec![vec![Operation::Unitary(Unitary { |
| 232 | gate: "rzz".to_string(), |
| 233 | args: vec!["1.0000".to_string()], |
| 234 | is_adjoint: false, |
| 235 | controls: vec![], |
| 236 | targets: vec![Register::quantum(0), Register::quantum(2)], |
| 237 | children: vec![], |
| 238 | metadata: None, |
| 239 | })]]), |
| 240 | }; |
| 241 | |
| 242 | expect![[r" |
| 243 | q_0 ─ rzz(1.0000) ─ |
| 244 | q_1 ───────┆─────── |
| 245 | q_2 ─ rzz(1.0000) ─ |
| 246 | "]] |
| 247 | .assert_eq(&c.to_string()); |
| 248 | } |
| 249 | |
| 250 | #[test] |
| 251 | fn respect_column_info() { |
| 252 | let c = Circuit { |
| 253 | qubits: vec![qubit(0), qubit(1)], |
| 254 | component_grid: op_grid_to_comp_grid(vec![ |
| 255 | vec![unitary("X", vec![q_reg(0)])], |
| 256 | vec![unitary("Y", vec![q_reg(0)]), unitary("S", vec![q_reg(1)])], |
| 257 | vec![unitary("Z", vec![q_reg(0)])], |
| 258 | ]), |
| 259 | }; |
| 260 | |
| 261 | expect![[r#" |
| 262 | q_0 ── X ──── Y ──── Z ── |
| 263 | q_1 ───────── S ───────── |
| 264 | "#]] |
| 265 | .assert_eq(&c.to_string()); |
| 266 | } |
| 267 | |