microsoft/qdk
Publicmirrored from https://github.com/microsoft/qdkAvailable
source/compiler/qsc_circuit/src/circuit/tests.rs
471lines · 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 | is_conditional: false, |
| 70 | }) |
| 71 | } |
| 72 | |
| 73 | fn ctl_unitary(gate: &str, targets: Vec<Register>, controls: Vec<Register>) -> Operation { |
| 74 | Operation::Unitary(Unitary { |
| 75 | gate: gate.to_string(), |
| 76 | args: vec![], |
| 77 | is_adjoint: false, |
| 78 | controls, |
| 79 | targets, |
| 80 | children: vec![], |
| 81 | metadata: None, |
| 82 | is_conditional: false, |
| 83 | }) |
| 84 | } |
| 85 | |
| 86 | fn unitary_with_children(gate: &str, targets: Vec<Register>, children: ComponentGrid) -> Operation { |
| 87 | Operation::Unitary(Unitary { |
| 88 | gate: gate.to_string(), |
| 89 | args: vec![], |
| 90 | is_adjoint: false, |
| 91 | controls: vec![], |
| 92 | targets, |
| 93 | children, |
| 94 | metadata: None, |
| 95 | is_conditional: false, |
| 96 | }) |
| 97 | } |
| 98 | |
| 99 | fn ctl_unitary_with_children( |
| 100 | gate: &str, |
| 101 | targets: Vec<Register>, |
| 102 | controls: Vec<Register>, |
| 103 | children: ComponentGrid, |
| 104 | ) -> Operation { |
| 105 | Operation::Unitary(Unitary { |
| 106 | gate: gate.to_string(), |
| 107 | args: vec![], |
| 108 | is_adjoint: false, |
| 109 | controls, |
| 110 | targets, |
| 111 | children, |
| 112 | metadata: None, |
| 113 | is_conditional: false, |
| 114 | }) |
| 115 | } |
| 116 | |
| 117 | #[test] |
| 118 | fn deserialize_circuit() { |
| 119 | let contents = r#" |
| 120 | { |
| 121 | "qubits": [ { "id": 0 }, { "id": 1 } ], |
| 122 | "componentGrid": [ |
| 123 | { |
| 124 | "components": [ |
| 125 | { "kind": "unitary", "gate": "H", "targets": [{ "qubit": 0 }] }, |
| 126 | { "kind": "unitary", "gate": "X", "targets": [{ "qubit": 1 }] } |
| 127 | ] |
| 128 | }, |
| 129 | { |
| 130 | "components": [ |
| 131 | { "kind": "unitary", "gate": "Z", "targets": [{ "qubit": 0 }] } |
| 132 | ] |
| 133 | }, |
| 134 | { |
| 135 | "components": [ |
| 136 | { "kind": "unitary", "gate": "X", "targets": [{ "qubit": 1 }], "controls": [{ "qubit": 0 }] } |
| 137 | ] |
| 138 | } |
| 139 | ] |
| 140 | }"#; |
| 141 | |
| 142 | let c = serde_json::from_str::<Circuit>(contents).expect("Was not able to deserialize"); |
| 143 | |
| 144 | expect![[r#" |
| 145 | q_0 ── H ──── Z ──── ● ── |
| 146 | q_1 ── X ─────────── X ── |
| 147 | "#]] |
| 148 | .assert_eq(&c.to_string()); |
| 149 | } |
| 150 | |
| 151 | #[test] |
| 152 | fn empty() { |
| 153 | let c = Circuit { |
| 154 | qubits: vec![], |
| 155 | component_grid: vec![], |
| 156 | }; |
| 157 | expect![[""]].assert_eq(&c.to_string()); |
| 158 | } |
| 159 | |
| 160 | #[test] |
| 161 | fn no_gates() { |
| 162 | let c = Circuit { |
| 163 | qubits: vec![qubit(0), qubit(1)], |
| 164 | component_grid: vec![], |
| 165 | }; |
| 166 | |
| 167 | expect![[r" |
| 168 | q_0 |
| 169 | q_1 |
| 170 | "]] |
| 171 | .assert_eq(&c.to_string()); |
| 172 | } |
| 173 | |
| 174 | #[test] |
| 175 | fn bell() { |
| 176 | let operations = vec![ |
| 177 | unitary("H", vec![q_reg(0)]), |
| 178 | ctl_unitary("X", vec![q_reg(1)], vec![q_reg(0)]), |
| 179 | measurement(0, 0), |
| 180 | measurement(1, 0), |
| 181 | ]; |
| 182 | let qubits = vec![qubit_with_results(0, 1), qubit_with_results(1, 1)]; |
| 183 | let component_grid = operation_list_to_grid(operations, &qubits); |
| 184 | let c = Circuit { |
| 185 | qubits, |
| 186 | component_grid, |
| 187 | }; |
| 188 | |
| 189 | expect![[r" |
| 190 | q_0 ── H ──── ● ──── M ── |
| 191 | │ ╘═══ |
| 192 | q_1 ───────── X ──── M ── |
| 193 | ╘═══ |
| 194 | "]] |
| 195 | .assert_eq(&c.to_string()); |
| 196 | } |
| 197 | |
| 198 | #[test] |
| 199 | fn control_classical() { |
| 200 | let operations = vec![ |
| 201 | measurement(0, 0), |
| 202 | ctl_unitary("X", vec![q_reg(2)], vec![c_reg(0, 0)]), |
| 203 | ctl_unitary("X", vec![q_reg(2)], vec![q_reg(0)]), |
| 204 | ]; |
| 205 | let qubits = vec![qubit_with_results(0, 1), qubit(1), qubit(2)]; |
| 206 | let component_grid = operation_list_to_grid(operations, &qubits); |
| 207 | let c = Circuit { |
| 208 | qubits, |
| 209 | component_grid, |
| 210 | }; |
| 211 | |
| 212 | expect![[r" |
| 213 | q_0 ── M ─────────── ● ── |
| 214 | ╘═════ ● ═════╪═══ |
| 215 | q_1 ──────────┼──────┼─── |
| 216 | q_2 ───────── X ──── X ── |
| 217 | "]] |
| 218 | .assert_eq(&c.to_string()); |
| 219 | } |
| 220 | |
| 221 | #[test] |
| 222 | fn two_measurements() { |
| 223 | let operations = vec![measurement(0, 0), measurement(0, 1)]; |
| 224 | let qubits = vec![qubit_with_results(0, 2)]; |
| 225 | let component_grid = operation_list_to_grid(operations, &qubits); |
| 226 | let c = Circuit { |
| 227 | qubits, |
| 228 | component_grid, |
| 229 | }; |
| 230 | |
| 231 | expect![[r" |
| 232 | q_0 ── M ──── M ── |
| 233 | ╘══════╪═══ |
| 234 | ╘═══ |
| 235 | "]] |
| 236 | .assert_eq(&c.to_string()); |
| 237 | } |
| 238 | |
| 239 | #[test] |
| 240 | fn with_args() { |
| 241 | let c = Circuit { |
| 242 | qubits: vec![qubit(0)], |
| 243 | component_grid: op_grid_to_comp_grid(vec![vec![Operation::Unitary(Unitary { |
| 244 | gate: "rx".to_string(), |
| 245 | args: vec!["1.5708".to_string()], |
| 246 | is_adjoint: false, |
| 247 | controls: vec![], |
| 248 | targets: vec![Register::quantum(0)], |
| 249 | is_conditional: false, |
| 250 | children: vec![], |
| 251 | metadata: None, |
| 252 | })]]), |
| 253 | }; |
| 254 | |
| 255 | expect![[r" |
| 256 | q_0 ─ rx(1.5708) ── |
| 257 | "]] |
| 258 | .assert_eq(&c.to_string()); |
| 259 | } |
| 260 | |
| 261 | #[test] |
| 262 | fn two_targets() { |
| 263 | let c = Circuit { |
| 264 | qubits: vec![qubit(0), qubit(1), qubit(2)], |
| 265 | component_grid: op_grid_to_comp_grid(vec![vec![Operation::Unitary(Unitary { |
| 266 | gate: "rzz".to_string(), |
| 267 | args: vec!["1.0000".to_string()], |
| 268 | is_adjoint: false, |
| 269 | is_conditional: false, |
| 270 | controls: vec![], |
| 271 | targets: vec![Register::quantum(0), Register::quantum(2)], |
| 272 | children: vec![], |
| 273 | metadata: None, |
| 274 | })]]), |
| 275 | }; |
| 276 | |
| 277 | expect![[r" |
| 278 | q_0 ─ rzz(1.0000) ─ |
| 279 | q_1 ───────┆─────── |
| 280 | q_2 ─ rzz(1.0000) ─ |
| 281 | "]] |
| 282 | .assert_eq(&c.to_string()); |
| 283 | } |
| 284 | |
| 285 | #[test] |
| 286 | fn respect_column_info() { |
| 287 | let c = Circuit { |
| 288 | qubits: vec![qubit(0), qubit(1)], |
| 289 | component_grid: op_grid_to_comp_grid(vec![ |
| 290 | vec![unitary("X", vec![q_reg(0)])], |
| 291 | vec![unitary("Y", vec![q_reg(0)]), unitary("S", vec![q_reg(1)])], |
| 292 | vec![unitary("Z", vec![q_reg(0)])], |
| 293 | ]), |
| 294 | }; |
| 295 | |
| 296 | expect![[r#" |
| 297 | q_0 ── X ──── Y ──── Z ── |
| 298 | q_1 ───────── S ───────── |
| 299 | "#]] |
| 300 | .assert_eq(&c.to_string()); |
| 301 | } |
| 302 | |
| 303 | #[test] |
| 304 | fn group_single_row() { |
| 305 | let c = Circuit { |
| 306 | qubits: vec![qubit(0), qubit_with_results(1, 1)], |
| 307 | component_grid: vec![ |
| 308 | ComponentColumn { |
| 309 | components: vec![unitary("H", vec![q_reg(0)])], |
| 310 | }, |
| 311 | ComponentColumn { |
| 312 | components: vec![unitary_with_children( |
| 313 | "group", |
| 314 | vec![q_reg(0)], |
| 315 | vec![ComponentColumn { |
| 316 | components: vec![unitary("X", vec![q_reg(0)])], |
| 317 | }], |
| 318 | )], |
| 319 | }, |
| 320 | ComponentColumn { |
| 321 | components: vec![measurement(1, 0)], |
| 322 | }, |
| 323 | ComponentColumn { |
| 324 | components: vec![unitary("Z", vec![q_reg(0)])], |
| 325 | }, |
| 326 | ], |
| 327 | }; |
| 328 | |
| 329 | expect![[r#" |
| 330 | q_0 ── H ─── [ [group] ─── X ──── ] ─────────── Z ── |
| 331 | q_1 ──────────────────────────────────── M ───────── |
| 332 | ╘══════════ |
| 333 | "#]] |
| 334 | .assert_eq(&c.display_with_groups().to_string()); |
| 335 | } |
| 336 | |
| 337 | #[test] |
| 338 | fn group_multiple_rows() { |
| 339 | let c = Circuit { |
| 340 | qubits: vec![qubit(0), qubit_with_results(1, 1)], |
| 341 | component_grid: vec![ |
| 342 | ComponentColumn { |
| 343 | components: vec![unitary("H", vec![q_reg(0)])], |
| 344 | }, |
| 345 | ComponentColumn { |
| 346 | components: vec![unitary_with_children( |
| 347 | "group", |
| 348 | vec![q_reg(0), q_reg(1)], |
| 349 | vec![ |
| 350 | ComponentColumn { |
| 351 | components: vec![unitary("X", vec![q_reg(0)])], |
| 352 | }, |
| 353 | ComponentColumn { |
| 354 | components: vec![unitary("Y", vec![q_reg(1)])], |
| 355 | }, |
| 356 | ], |
| 357 | )], |
| 358 | }, |
| 359 | ComponentColumn { |
| 360 | components: vec![measurement(1, 0)], |
| 361 | }, |
| 362 | ComponentColumn { |
| 363 | components: vec![unitary("Z", vec![q_reg(0)])], |
| 364 | }, |
| 365 | ], |
| 366 | }; |
| 367 | |
| 368 | expect![[r#" |
| 369 | q_0 ── H ─── group[1] ─────────── Z ── |
| 370 | ┆ |
| 371 | q_1 ──────── group[1] ──── M ───────── |
| 372 | ╘══════════ |
| 373 | |
| 374 | [1] group: |
| 375 | q_0 ── X ───────── |
| 376 | q_1 ───────── Y ── |
| 377 | |
| 378 | "#]] |
| 379 | .assert_eq(&c.display_with_groups().to_string()); |
| 380 | } |
| 381 | |
| 382 | #[test] |
| 383 | fn controlled_group() { |
| 384 | let c = Circuit { |
| 385 | qubits: vec![qubit_with_results(0, 1), qubit_with_results(1, 1)], |
| 386 | component_grid: vec![ |
| 387 | ComponentColumn { |
| 388 | components: vec![unitary("H", vec![q_reg(0)])], |
| 389 | }, |
| 390 | ComponentColumn { |
| 391 | components: vec![measurement(0, 0)], |
| 392 | }, |
| 393 | ComponentColumn { |
| 394 | components: vec![measurement(1, 0)], |
| 395 | }, |
| 396 | ComponentColumn { |
| 397 | components: vec![ctl_unitary_with_children( |
| 398 | "group", |
| 399 | vec![q_reg(0), q_reg(1)], |
| 400 | vec![q_reg(1)], |
| 401 | vec![ComponentColumn { |
| 402 | components: vec![unitary("X", vec![q_reg(0)])], |
| 403 | }], |
| 404 | )], |
| 405 | }, |
| 406 | ComponentColumn { |
| 407 | components: vec![unitary("Z", vec![q_reg(0)])], |
| 408 | }, |
| 409 | ], |
| 410 | }; |
| 411 | |
| 412 | expect![[r#" |
| 413 | q_0 ── H ──── M ────────── group[1] ──── Z ── |
| 414 | ╘════════════════╪═════════════ |
| 415 | q_1 ──────────────── M ─────── ● ──────────── |
| 416 | ╘═══════════════════════ |
| 417 | |
| 418 | [1] group: |
| 419 | q_0 ── X ── |
| 420 | |
| 421 | q_1 ─────── |
| 422 | |
| 423 | "#]] |
| 424 | .assert_eq(&c.display_with_groups().to_string()); |
| 425 | } |
| 426 | |
| 427 | #[test] |
| 428 | fn classical_controlled_group() { |
| 429 | let c = Circuit { |
| 430 | qubits: vec![qubit_with_results(0, 0), qubit_with_results(1, 1)], |
| 431 | component_grid: vec![ |
| 432 | ComponentColumn { |
| 433 | components: vec![unitary("H", vec![q_reg(0)])], |
| 434 | }, |
| 435 | ComponentColumn { |
| 436 | components: vec![measurement(1, 0)], |
| 437 | }, |
| 438 | ComponentColumn { |
| 439 | components: vec![ctl_unitary_with_children( |
| 440 | "group", |
| 441 | vec![q_reg(0), q_reg(1)], |
| 442 | vec![c_reg(1, 0)], |
| 443 | vec![ |
| 444 | ComponentColumn { |
| 445 | components: vec![unitary("X", vec![q_reg(0)])], |
| 446 | }, |
| 447 | ComponentColumn { |
| 448 | components: vec![unitary("Y", vec![q_reg(1)])], |
| 449 | }, |
| 450 | ], |
| 451 | )], |
| 452 | }, |
| 453 | ComponentColumn { |
| 454 | components: vec![unitary("Z", vec![q_reg(0)])], |
| 455 | }, |
| 456 | ], |
| 457 | }; |
| 458 | |
| 459 | expect![[r#" |
| 460 | q_0 ── H ────────── group[1] ──── Z ── |
| 461 | │ |
| 462 | q_1 ───────── M ─── group[1] ───────── |
| 463 | ╘════════ ● ════════════ |
| 464 | |
| 465 | [1] group: |
| 466 | q_0 ── X ───────── |
| 467 | q_1 ───────── Y ── |
| 468 | |
| 469 | "#]] |
| 470 | .assert_eq(&c.display_with_groups().to_string()); |
| 471 | } |
| 472 | |