|
| 1 | +//! Test running tket1 passes on hugr circuit. |
| 2 | +
|
| 3 | +use tket1_passes::Tket1Circuit; |
| 4 | + |
| 5 | +use hugr::builder::{BuildError, Dataflow, DataflowHugr, FunctionBuilder}; |
| 6 | +use hugr::extension::prelude::qb_t; |
| 7 | +use hugr::types::Signature; |
| 8 | +use hugr::{HugrView, Node}; |
| 9 | +use rstest::{fixture, rstest}; |
| 10 | +use tket::extension::{TKET1_EXTENSION_ID, TKET_EXTENSION_ID}; |
| 11 | +use tket::serialize::pytket::{EncodeOptions, EncodedCircuit}; |
| 12 | +use tket::{Circuit, TketOp}; |
| 13 | + |
| 14 | +/// A flat quantum circuit inside a function. |
| 15 | +/// |
| 16 | +/// This should optimize to the identity. |
| 17 | +#[fixture] |
| 18 | +fn circ_flat_quantum() -> Circuit { |
| 19 | + fn build() -> Result<Circuit, BuildError> { |
| 20 | + let input_t = vec![qb_t(), qb_t()]; |
| 21 | + let output_t = vec![qb_t(), qb_t()]; |
| 22 | + let mut h = |
| 23 | + FunctionBuilder::new("preset_qubits", Signature::new(input_t, output_t)).unwrap(); |
| 24 | + |
| 25 | + let mut circ = h.as_circuit(h.input_wires()); |
| 26 | + |
| 27 | + circ.append(TketOp::X, [0])?; |
| 28 | + circ.append(TketOp::CX, [0, 1])?; |
| 29 | + circ.append(TketOp::X, [0])?; |
| 30 | + circ.append(TketOp::CX, [1, 0])?; |
| 31 | + circ.append(TketOp::X, [0])?; |
| 32 | + circ.append(TketOp::X, [1])?; |
| 33 | + circ.append(TketOp::CX, [0, 1])?; |
| 34 | + |
| 35 | + let wires = circ.finish(); |
| 36 | + // Implicit swap |
| 37 | + let wires = [wires[1], wires[0]]; |
| 38 | + |
| 39 | + let hugr = h.finish_hugr_with_outputs(wires).unwrap(); |
| 40 | + |
| 41 | + Ok(hugr.into()) |
| 42 | + } |
| 43 | + build().unwrap() |
| 44 | +} |
| 45 | + |
| 46 | +#[rstest] |
| 47 | +#[case(circ_flat_quantum(), 0)] |
| 48 | +fn test_clifford_simp(#[case] circ: Circuit, #[case] num_remaining_gates: usize) { |
| 49 | + let mut encoded = EncodedCircuit::new(&circ, EncodeOptions::new_with_subcircuits()).unwrap(); |
| 50 | + |
| 51 | + for (_region, serial_circuit) in encoded.iter_mut() { |
| 52 | + let mut circuit_ptr = Tket1Circuit::from_serial_circuit(serial_circuit).unwrap(); |
| 53 | + circuit_ptr |
| 54 | + .clifford_simp(tket_json_rs::OpType::CX, true) |
| 55 | + .unwrap(); |
| 56 | + *serial_circuit = circuit_ptr.to_serial_circuit().unwrap(); |
| 57 | + } |
| 58 | + |
| 59 | + let mut new_circ = circ.clone(); |
| 60 | + let updated_regions = encoded |
| 61 | + .reassemble_inline(new_circ.hugr_mut(), None) |
| 62 | + .unwrap(); |
| 63 | + |
| 64 | + let quantum_ops: usize = updated_regions |
| 65 | + .iter() |
| 66 | + .map(|region| count_quantum_gates(&new_circ, *region)) |
| 67 | + .sum(); |
| 68 | + assert_eq!(quantum_ops, num_remaining_gates); |
| 69 | +} |
| 70 | + |
| 71 | +/// Helper method to count the number of quantum operations in a hugr region. |
| 72 | +fn count_quantum_gates(circuit: &Circuit, region: Node) -> usize { |
| 73 | + circuit |
| 74 | + .hugr() |
| 75 | + .children(region) |
| 76 | + .filter(|child| { |
| 77 | + let op = circuit.hugr().get_optype(*child); |
| 78 | + op.as_extension_op() |
| 79 | + .is_some_and(|e| [TKET_EXTENSION_ID, TKET1_EXTENSION_ID].contains(e.extension_id())) |
| 80 | + }) |
| 81 | + .count() |
| 82 | +} |
0 commit comments