From 0ae775f56f6bdca277501edee811a3b12a1b5238 Mon Sep 17 00:00:00 2001 From: Agustin Borgna Date: Tue, 29 Aug 2023 14:48:50 +0100 Subject: [PATCH] Update quartz circuit decoder It now tracks the any output renaming from the quartz definition --- src/extension.rs | 9 ++-- src/passes/taso/qtz_circuit.rs | 85 ++++++++++++---------------------- 2 files changed, 33 insertions(+), 61 deletions(-) diff --git a/src/extension.rs b/src/extension.rs index 7b8c2003..4716db58 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -4,11 +4,11 @@ use std::collections::HashMap; -use hugr::extension::{ExtensionId, ExtensionSet, SignatureError}; +use hugr::extension::{ExtensionId, SignatureError}; use hugr::ops::custom::{ExternalOp, OpaqueOp}; use hugr::ops::OpName; use hugr::types::type_param::{CustomTypeArg, TypeArg, TypeParam}; -use hugr::types::{CustomType, Type, TypeBound, TypeRow}; +use hugr::types::{CustomType, FunctionType, Type, TypeBound}; use hugr::Extension; use lazy_static::lazy_static; use smol_str::SmolStr; @@ -99,12 +99,11 @@ pub(crate) fn try_unwrap_json_op(ext: &ExternalOp) -> Option { } /// Compute the signature of a json-encoded TKET1 operation. -fn json_op_signature(args: &[TypeArg]) -> Result<(TypeRow, TypeRow, ExtensionSet), SignatureError> { +fn json_op_signature(args: &[TypeArg]) -> Result { let [TypeArg::Opaque(arg)] = args else { // This should have already been checked. panic!("Wrong number of arguments"); }; let op: JsonOp = serde_yaml::from_value(arg.value.clone()).unwrap(); // TODO Errors! - let sig = op.signature(); - Ok((sig.input, sig.output, sig.extension_reqs)) + Ok(op.signature()) } diff --git a/src/passes/taso/qtz_circuit.rs b/src/passes/taso/qtz_circuit.rs index 55e20755..affb1f0f 100644 --- a/src/passes/taso/qtz_circuit.rs +++ b/src/passes/taso/qtz_circuit.rs @@ -2,15 +2,12 @@ use std::collections::HashMap; use hugr::builder::{DFGBuilder, Dataflow, DataflowHugr}; use hugr::extension::prelude::QB_T; -// use crate::circuit::{ -// circuit::Circuit, -// dag::Edge, -// operation::{Op, WireType}, -// }; +use hugr::hugr::CircuitUnit; use hugr::ops::OpType as Op; use hugr::std_extensions::arithmetic::float_types::FLOAT64_TYPE; use hugr::types::{FunctionType, Type}; use hugr::Hugr as Circuit; +use itertools::Itertools; use serde::{Deserialize, Serialize}; use crate::utils::{cx_gate, h_gate, rz_f64}; @@ -52,76 +49,52 @@ fn map_op(opstr: &str) -> Op { .into() } -fn map_wt(wirestr: &str) -> (Type, usize) { - let wt = if wirestr.starts_with('Q') { - QB_T - } else if wirestr.starts_with('P') { - FLOAT64_TYPE - } else { - panic!("unknown op {wirestr}"); - }; - - (wt, wirestr[1..].parse().unwrap()) -} // TODO change to TryFrom impl From for Circuit { fn from(RepCircData { circ: rc, meta }: RepCircData) -> Self { let qb_types: Vec = vec![QB_T; meta.n_qb]; let param_types: Vec = vec![FLOAT64_TYPE; meta.n_input_param]; - let mut circ = DFGBuilder::new(FunctionType::new( - [param_types, qb_types.clone()].concat(), + let mut builder = DFGBuilder::new(FunctionType::new( + [qb_types.clone(), param_types].concat(), qb_types, )) .unwrap(); - let inputs: Vec<_> = circ.input_wires().collect(); - let (param_wires, qubit_wires) = inputs.split_at(meta.n_input_param); - // let param_wires: Vec = input_iter.f(meta.n_input_param).collect(); - // let qubit_wires: Vec = input_iter.collect(); + // Current map between quartz qubit and parameter identifiers, and + // circuit units. Since quartz defines output wires arbitrarily for each + // command, these may be altered mid-circuit. + let param_wires = builder.input_wires().skip(meta.n_qb); + let mut input_units: HashMap = + HashMap::with_capacity(builder.num_inputs()); + input_units.extend((0..meta.n_qb).map(|i| (format!("Q{}", i), CircuitUnit::Linear(i)))); + input_units.extend( + param_wires + .enumerate() + .map(|(i, w)| (format!("P{}", i), CircuitUnit::Wire(w))), + ); + + let circ_inputs = builder.input_wires().take(meta.n_qb).collect_vec(); + let mut circ = builder.as_circuit(circ_inputs); - let mut qubit_wires: Vec<_> = qubit_wires.into(); - let mut param_wires: Vec<_> = param_wires.iter().map(Some).collect(); for RepCircOp { opstr, - outputs, inputs, + outputs, } in rc.0 { let op = map_op(&opstr); - let incoming: Vec<_> = inputs - .into_iter() - .map(|is| { - let (wt, idx) = map_wt(&is); - if wt == QB_T { - qubit_wires[idx] - } else if wt == FLOAT64_TYPE { - *param_wires[idx].take().unwrap() - } else { - panic!("unexpected wire type.") - } - }) - .collect(); - let output_wires = circ.add_dataflow_op(op, incoming).unwrap().outputs(); - - for (os, wire) in outputs.into_iter().zip(output_wires) { - let (wt, idx) = map_wt(&os); - assert_eq!(wt, QB_T, "only qubits expected as output"); - - qubit_wires[idx] = wire; - } + // Translate the quartz inputs into circuit units. + let inputs = inputs.iter().map(|inp| *input_units.get(inp).unwrap()); + let hugr_outputs = circ.append_with_outputs(op, inputs).unwrap(); - // circ.add_vertex_with_edges(op, incoming, outgoing); + for (idx, wire) in outputs.iter().zip(hugr_outputs) { + input_units.insert(idx.to_string(), CircuitUnit::Wire(wire)); + } } - // circ.dag - // .connect_many( - // circ.boundary()[1], - // qubit_wire_map, - // Direction::Incoming, - // None, - // ) - // .unwrap(); - circ.finish_hugr_with_outputs(qubit_wires).unwrap() + + let circ_outputs = circ.finish(); + builder.finish_hugr_with_outputs(circ_outputs).unwrap() } }