use crate::extension::rotation::rotation_type;
use crate::extension::{TKET1_EXTENSION, TKET1_EXTENSION_ID, TKET1_OP_NAME};
use crate::serialize::pytket::encoder::EncodeStatus;
use crate::serialize::pytket::{Tk1ConvertError, Tk1EncoderContext};
use crate::Circuit;
use super::PytketEmitter;
use hugr::extension::prelude::{bool_t, qb_t};
use hugr::extension::ExtensionId;
use hugr::ops::ExtensionOp;
use hugr::types::{Signature, TypeArg};
use hugr::{HugrView, IncomingPort};
use tket_json_rs::circuit_json;
#[derive(Debug, Clone, Default)]
pub struct Tk1Emitter;
impl<H: HugrView> PytketEmitter<H> for Tk1Emitter {
fn extensions(&self) -> Option<Vec<ExtensionId>> {
Some(vec![TKET1_EXTENSION_ID])
}
fn op_to_pytket(
&self,
node: H::Node,
op: &ExtensionOp,
circ: &Circuit<H>,
encoder: &mut Tk1EncoderContext<H>,
) -> Result<EncodeStatus, Tk1ConvertError<H::Node>> {
if op.qualified_id() != format!("{TKET1_EXTENSION_ID}.{TKET1_OP_NAME}") {
return Ok(EncodeStatus::Unsupported);
}
let Some(TypeArg::String { arg }) = op.args().first() else {
return Err(Tk1ConvertError::custom(
"Opaque TKET1 operation did not have a json-encoded type argument.",
));
};
let op: OpaqueTk1Op = serde_json::from_str(arg)?;
encoder.emit_node_command(
node,
circ,
|_args| Vec::new(),
move |_| op.serialised_op,
)?;
Ok(EncodeStatus::Success)
}
}
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct OpaqueTk1Op {
#[serde(rename = "op")]
pub serialised_op: circuit_json::Operation,
pub num_qubits: usize,
pub num_bits: usize,
pub param_inputs: Vec<Option<IncomingPort>>,
pub num_params: usize,
}
impl OpaqueTk1Op {
pub fn new_from_op(
mut op: circuit_json::Operation,
num_qubits: usize,
num_bits: usize,
) -> Self {
if op.signature.is_none() {
op.signature =
Some([vec!["Q".into(); num_qubits], vec!["B".into(); num_bits]].concat());
}
let mut op = Self {
serialised_op: op,
num_qubits,
num_bits,
param_inputs: Vec::new(),
num_params: 0,
};
op.compute_param_fields();
op
}
#[inline]
pub fn signature(&self) -> Signature {
let linear = [
vec![qb_t(); self.num_qubits],
vec![bool_t().clone(); self.num_bits],
]
.concat();
let params = vec![rotation_type(); self.num_params];
Signature::new([linear.clone(), params].concat(), linear)
}
pub fn param_ports(&self) -> impl Iterator<Item = IncomingPort> + '_ {
self.param_inputs.iter().filter_map(|&i| i)
}
pub fn as_extension_op(&self) -> ExtensionOp {
let payload = TypeArg::String {
arg: serde_json::to_string(self).unwrap(),
};
let op_def = TKET1_EXTENSION.get_op(&TKET1_OP_NAME).unwrap();
ExtensionOp::new(op_def.clone(), vec![payload]).unwrap_or_else(|e| panic!("{e}"))
}
fn compute_param_fields(&mut self) {
let Some(params) = self.serialised_op.params.as_ref() else {
self.param_inputs = vec![];
self.num_params = 0;
return;
};
self.num_params = params.len();
self.param_inputs = (0..params.len()).map(|i| Some(i.into())).collect();
}
}