Skip to content

Commit 8c9b810

Browse files
aborgna-qdoug-q
andauthored
feat!: Split the pytket extension encoder trait (#970)
Splits the `type_to_pytket` method out of the `PytketEmitter` trait implemented by extensions, and into a new `TypeTranslator` trait as we'll use them in the decoder trait too. Adds a `TypeTranslatorSet` used by the encoder/decoder config that caches the translation, since it gets called multiple times with the same types. BREAKING CHANGE: Moved `PytketEmitter::type_to_pytket` to new `TypeTranslator` trait. --------- Co-authored-by: Douglas Wilson <141026920+doug-q@users.noreply.github.com>
1 parent aeaf1e1 commit 8c9b810

File tree

12 files changed

+610
-358
lines changed

12 files changed

+610
-358
lines changed

Cargo.lock

Lines changed: 198 additions & 124 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tket2/src/serialize/pytket.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
//! Serialization and deserialization of circuits using the `pytket` JSON format.
22
3+
mod config;
34
mod decoder;
45
pub mod encoder;
56
pub mod extension;
67

7-
pub use encoder::{default_encoder_config, Tk1EncoderConfig, Tk1EncoderContext};
8+
pub use config::{default_encoder_config, Tk1EncoderConfig};
9+
pub use encoder::Tk1EncoderContext;
810
pub use extension::PytketEmitter;
911

1012
use hugr::core::HugrNode;
@@ -29,7 +31,6 @@ use tket_json_rs::register::{Bit, ElementId, Qubit};
2931
use crate::circuit::Circuit;
3032

3133
use self::decoder::Tk1DecoderContext;
32-
3334
pub use crate::passes::pytket::lower_to_pytket;
3435

3536
/// Prefix used for storing metadata in the hugr nodes.
@@ -53,9 +54,9 @@ const METADATA_INPUT_PARAMETERS: &str = "TKET1.input_parameters";
5354
///
5455
/// Implemented by [`SerialCircuit`], the JSON format used by tket1's `pytket` library.
5556
pub trait TKETDecode: Sized {
56-
/// The error type for decoding.
57+
/// Error type of decoding errors.
5758
type DecodeError;
58-
/// The error type for decoding.
59+
/// Error type of encoding errors.
5960
type EncodeError;
6061
/// Convert the serialized circuit to a circuit.
6162
fn decode(self) -> Result<Circuit, Self::DecodeError>;
@@ -178,12 +179,6 @@ pub fn save_tk1_json_str(circ: &Circuit) -> Result<String, Tk1ConvertError> {
178179
#[non_exhaustive]
179180
#[debug(bounds(N: HugrNode))]
180181
pub enum OpConvertError<N = hugr::Node> {
181-
/// The serialized operation is not supported.
182-
#[display("Cannot serialize tket2 operation: {op}")]
183-
UnsupportedOpSerialization {
184-
/// The operation.
185-
op: OpType,
186-
},
187182
/// Tried to decode a tket1 operation with not enough parameters.
188183
#[display(
189184
"Operation {} is missing encoded parameters. Expected at least {expected} but only \"{}\" were specified.",
@@ -277,8 +272,10 @@ pub enum Tk1ConvertError<N = hugr::Node> {
277272

278273
impl<N> Tk1ConvertError<N> {
279274
/// Create a new error with a custom message.
280-
pub fn custom(msg: impl Into<String>) -> Self {
281-
Self::CustomError { msg: msg.into() }
275+
pub fn custom(msg: impl ToString) -> Self {
276+
Self::CustomError {
277+
msg: msg.to_string(),
278+
}
282279
}
283280
}
284281

tket2/src/serialize/pytket/config.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//! Configuration structs for pytket encoders and decoders.
2+
3+
mod encoder_config;
4+
mod type_translators;
5+
6+
pub use encoder_config::Tk1EncoderConfig;
7+
use type_translators::TypeTranslatorSet;
8+
9+
use crate::serialize::pytket::extension::{
10+
BoolEmitter, FloatEmitter, PreludeEmitter, RotationEmitter, Tk1Emitter, Tk2Emitter,
11+
};
12+
use hugr::HugrView;
13+
14+
/// Default encoder configuration for [`Circuit`][crate::Circuit]s.
15+
///
16+
/// Contains emitters for std and tket2 operations.
17+
pub fn default_encoder_config<H: HugrView>() -> Tk1EncoderConfig<H> {
18+
let mut config = Tk1EncoderConfig::new();
19+
config.add_emitter(PreludeEmitter);
20+
config.add_emitter(BoolEmitter);
21+
config.add_emitter(FloatEmitter);
22+
config.add_emitter(RotationEmitter);
23+
config.add_emitter(Tk1Emitter);
24+
config.add_emitter(Tk2Emitter);
25+
26+
config.add_type_translator(PreludeEmitter);
27+
config.add_type_translator(BoolEmitter);
28+
config.add_type_translator(FloatEmitter);
29+
config.add_type_translator(RotationEmitter);
30+
31+
config
32+
}

tket2/src/serialize/pytket/encoder/config.rs renamed to tket2/src/serialize/pytket/config/encoder_config.rs

Lines changed: 27 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,18 @@ use std::collections::{BTreeSet, HashMap, VecDeque};
88

99
use hugr::extension::{ExtensionId, ExtensionSet};
1010
use hugr::ops::{ExtensionOp, Value};
11-
use hugr::types::{SumType, Type, TypeEnum};
11+
use hugr::types::{SumType, Type};
1212

1313
use crate::serialize::pytket::encoder::EncodeStatus;
14-
use crate::serialize::pytket::extension::{
15-
set_bits_op, BoolEmitter, FloatEmitter, PreludeEmitter, RotationEmitter, Tk1Emitter, Tk2Emitter,
16-
};
14+
use crate::serialize::pytket::extension::{set_bits_op, PytketTypeTranslator, RegisterCount};
1715
use crate::serialize::pytket::{PytketEmitter, Tk1ConvertError};
1816
use crate::Circuit;
1917

20-
use super::value_tracker::RegisterCount;
21-
use super::{Tk1EncoderContext, TrackedValues};
22-
use hugr::extension::prelude::bool_t;
18+
use super::super::encoder::{Tk1EncoderContext, TrackedValues};
19+
use super::TypeTranslatorSet;
2320
use hugr::HugrView;
2421
use itertools::Itertools;
2522

26-
/// Default encoder configuration for [`Circuit`]s.
27-
///
28-
/// Contains emitters for std and tket2 operations.
29-
pub fn default_encoder_config<H: HugrView>() -> Tk1EncoderConfig<H> {
30-
let mut config = Tk1EncoderConfig::new();
31-
config.add_emitter(PreludeEmitter);
32-
config.add_emitter(BoolEmitter);
33-
config.add_emitter(FloatEmitter);
34-
config.add_emitter(RotationEmitter);
35-
config.add_emitter(Tk1Emitter);
36-
config.add_emitter(Tk2Emitter);
37-
config
38-
}
39-
4023
/// Configuration for converting [`Circuit`] into
4124
/// [`tket_json_rs::circuit_json::SerialCircuit`].
4225
///
@@ -54,16 +37,14 @@ pub struct Tk1EncoderConfig<H: HugrView> {
5437
extension_emitters: HashMap<ExtensionId, Vec<usize>>,
5538
/// Emitters that request to be called for all operations.
5639
no_extension_emitters: Vec<usize>,
40+
/// Set of type translators used to translate HUGR types into pytket registers.
41+
type_translators: TypeTranslatorSet,
5742
}
5843

5944
impl<H: HugrView> Tk1EncoderConfig<H> {
6045
/// Create a new [`Tk1EncoderConfig`] with no encoders.
6146
pub fn new() -> Self {
62-
Self {
63-
emitters: vec![],
64-
extension_emitters: HashMap::new(),
65-
no_extension_emitters: vec![],
66-
}
47+
Self::default()
6748
}
6849

6950
/// Add an encoder to the configuration.
@@ -84,6 +65,14 @@ impl<H: HugrView> Tk1EncoderConfig<H> {
8465
self.emitters.push(Box::new(encoder));
8566
}
8667

68+
/// Add a type translator to the configuration.
69+
pub fn add_type_translator(
70+
&mut self,
71+
translator: impl PytketTypeTranslator + Send + Sync + 'static,
72+
) {
73+
self.type_translators.add_type_translator(translator);
74+
}
75+
8776
/// List the extensions supported by the encoders.
8877
///
8978
/// Some encoders may not specify an extension, in which case they will be called
@@ -98,7 +87,7 @@ impl<H: HugrView> Tk1EncoderConfig<H> {
9887
///
9988
/// Returns `true` if the operation was successfully converted and no further
10089
/// encoders should be called.
101-
pub(super) fn op_to_pytket(
90+
pub fn op_to_pytket(
10291
&self,
10392
node: H::Node,
10493
op: &ExtensionOp,
@@ -116,57 +105,12 @@ impl<H: HugrView> Tk1EncoderConfig<H> {
116105
Ok(result)
117106
}
118107

119-
/// Translate a HUGR type into a count of qubits, bits, and parameters,
120-
/// using the registered custom encoders.
121-
///
122-
/// Only tuple sums, bools, and custom types are supported.
123-
/// Other types will return `None`.
124-
pub fn type_to_pytket(
125-
&self,
126-
typ: &Type,
127-
) -> Result<Option<RegisterCount>, Tk1ConvertError<H::Node>> {
128-
match typ.as_type_enum() {
129-
TypeEnum::Sum(sum) => {
130-
if typ == &bool_t() {
131-
return Ok(Some(RegisterCount {
132-
qubits: 0,
133-
bits: 1,
134-
params: 0,
135-
}));
136-
}
137-
if let Some(tuple) = sum.as_tuple() {
138-
let count: Result<Option<RegisterCount>, Tk1ConvertError<H::Node>> = tuple
139-
.iter()
140-
.map(|ty| {
141-
match ty.clone().try_into() {
142-
Ok(ty) => Ok(self.type_to_pytket(&ty)?),
143-
// Sum types with row variables (variable tuple lengths) are not supported.
144-
Err(_) => Ok(None),
145-
}
146-
})
147-
.sum();
148-
return count;
149-
}
150-
}
151-
TypeEnum::Extension(custom) => {
152-
let type_ext = custom.extension();
153-
for encoder in self.emitters_for_extension(type_ext) {
154-
if let Some(count) = encoder.type_to_pytket(custom)? {
155-
return Ok(Some(count));
156-
}
157-
}
158-
}
159-
_ => {}
160-
}
161-
Ok(None)
162-
}
163-
164108
/// Encode a const value into the pytket context using the registered custom
165109
/// encoders.
166110
///
167111
/// Returns the values associated to the loaded constant, or `None` if the
168112
/// constant could not be encoded.
169-
pub(super) fn const_to_pytket(
113+
pub fn const_to_pytket(
170114
&self,
171115
value: &Value,
172116
encoder: &mut Tk1EncoderContext<H>,
@@ -216,6 +160,15 @@ impl<H: HugrView> Tk1EncoderConfig<H> {
216160
Ok(Some(values))
217161
}
218162

163+
/// Translate a HUGR type into a count of qubits, bits, and parameters,
164+
/// using the registered custom translator.
165+
///
166+
/// Only tuple sums, bools, and custom types are supported.
167+
/// Other types will return `None`.
168+
pub fn type_to_pytket(&self, typ: &Type) -> Option<RegisterCount> {
169+
self.type_translators.type_to_pytket(typ)
170+
}
171+
219172
/// Lists the emitters that can handle a given extension.
220173
fn emitters_for_extension(
221174
&self,
@@ -250,6 +203,7 @@ impl<H: HugrView> Default for Tk1EncoderConfig<H> {
250203
emitters: Default::default(),
251204
extension_emitters: Default::default(),
252205
no_extension_emitters: Default::default(),
206+
type_translators: TypeTranslatorSet::default(),
253207
}
254208
}
255209
}

0 commit comments

Comments
 (0)