@@ -9,6 +9,8 @@ pub use param::{LoadedParameter, ParameterType};
99pub use tracked_elem:: { TrackedBit , TrackedQubit } ;
1010pub use wires:: TrackedWires ;
1111
12+ pub ( super ) use wires:: FindTypedWireResult ;
13+
1214use std:: sync:: Arc ;
1315
1416use hugr:: builder:: {
@@ -34,8 +36,8 @@ use crate::extension::rotation::rotation_type;
3436use crate :: serialize:: pytket:: config:: PytketDecoderConfig ;
3537use crate :: serialize:: pytket:: decoder:: wires:: WireTracker ;
3638use crate :: serialize:: pytket:: extension:: { build_opaque_tket_op, RegisterCount } ;
37- use crate :: serialize:: pytket:: opaque:: OpaqueSubgraphs ;
38- use crate :: serialize:: pytket:: { DecodeInsertionTarget , PytketDecodeErrorInner } ;
39+ use crate :: serialize:: pytket:: opaque:: { OpaqueSubgraphPayloadType , OpaqueSubgraphs } ;
40+ use crate :: serialize:: pytket:: { DecodeInsertionTarget , DecodeOptions , PytketDecodeErrorInner } ;
3941use crate :: TketOp ;
4042
4143/// State of the tket circuit being decoded.
@@ -46,19 +48,17 @@ use crate::TketOp;
4648/// The generic parameter `H` is the HugrView type of the Hugr that was encoded
4749/// into the circuit, if any. This is required when the encoded pytket circuit
4850/// contains opaque barriers that reference subgraphs in the original HUGR. See
49- /// [`OpaqueSubgraphPayload`][super::opaque::OpaqueSubgraphPayload]
50- /// for more details.
51+ /// [`OpaqueSubgraphPayload`][super::opaque::OpaqueSubgraphPayload] for more details.
5152#[ derive( Debug ) ]
5253pub struct PytketDecoderContext < ' h , H : HugrView > {
5354 /// The Hugr being built.
5455 pub builder : DFGBuilder < & ' h mut Hugr > ,
5556 /// A tracker keeping track of the generated wires and their corresponding types.
56- pub ( super ) wire_tracker : WireTracker ,
57- /// Configuration for decoding commands .
57+ pub ( super ) wire_tracker : Box < WireTracker > ,
58+ /// Options used when decoding the circuit .
5859 ///
59- /// Contains custom operation decoders, that define translation of legacy tket
60- /// commands into HUGR operations.
61- config : Arc < PytketDecoderConfig < H > > ,
60+ /// `DecodeOptions::config` is
61+ options : DecodeOptions < H > ,
6262 /// The HugrView type of the Hugr that originated the circuit, if any.
6363 original_hugr : Option < & ' h H > ,
6464 /// A registry of opaque subgraphs from `original_hugr`, that are referenced by opaque barriers in the pytket circuit
@@ -107,12 +107,16 @@ impl<'h, H: HugrView> PytketDecoderContext<'h, H> {
107107 serialcirc : & SerialCircuit ,
108108 hugr : & ' h mut Hugr ,
109109 target : DecodeInsertionTarget ,
110- signature : Option < Signature > ,
111- input_params : impl IntoIterator < Item = String > ,
112- config : impl Into < Arc < PytketDecoderConfig < H > > > ,
110+ mut options : DecodeOptions < H > ,
113111 ) -> Result < Self , PytketDecodeError > {
114- let config: Arc < PytketDecoderConfig < H > > = config. into ( ) ;
115- let signature = signature. unwrap_or_else ( || {
112+ // Ensure that the set of decoders is present, use a default one if not.
113+ if options. config . is_none ( ) {
114+ options. with_default_config ( ) ;
115+ }
116+
117+ // Compute the signature of the decoded region, if not provided, and
118+ // initialize the DFG builder.
119+ let signature = options. signature . clone ( ) . unwrap_or_else ( || {
116120 let num_qubits = serialcirc. qubits . len ( ) ;
117121 let num_bits = serialcirc. bits . len ( ) ;
118122 let types: TypeRow = [ vec ! [ qb_t( ) ; num_qubits] , vec ! [ bool_t( ) ; num_bits] ]
@@ -143,8 +147,8 @@ impl<'h, H: HugrView> PytketDecoderContext<'h, H> {
143147 serialcirc,
144148 & mut dfg,
145149 & signature. input ,
146- input_params,
147- & config ,
150+ options . input_params . iter ( ) . cloned ( ) ,
151+ options . get_config ( ) ,
148152 ) ?;
149153
150154 if !serialcirc. phase . is_empty ( ) {
@@ -156,8 +160,8 @@ impl<'h, H: HugrView> PytketDecoderContext<'h, H> {
156160
157161 Ok ( PytketDecoderContext {
158162 builder : dfg,
159- wire_tracker,
160- config ,
163+ wire_tracker : Box :: new ( wire_tracker ) ,
164+ options ,
161165 original_hugr : None ,
162166 opaque_subgraphs : None ,
163167 } )
@@ -354,22 +358,32 @@ impl<'h, H: HugrView> PytketDecoderContext<'h, H> {
354358 /// `original_hugr`, that are referenced by opaque barriers in the pytket
355359 /// circuit via their [`SubgraphId`].
356360 /// - `original_hugr`: The [`Hugr`] that originated the circuit, if any.
357- #[ expect( unused) ]
358361 pub ( super ) fn register_opaque_subgraphs (
359362 & mut self ,
360363 opaque_subgraphs : & ' h OpaqueSubgraphs < H :: Node > ,
361364 original_hugr : & ' h H ,
362365 ) {
363366 self . opaque_subgraphs = Some ( opaque_subgraphs) ;
364367 self . original_hugr = Some ( original_hugr) ;
368+
369+ // Add the hugr's extensions to the extension registry used when loading
370+ // subcircuits.
371+ if self . options . extensions . is_none ( ) {
372+ self . options . extensions = Some ( self . options . extension_registry ( ) . clone ( ) ) ;
373+ }
374+ self . options
375+ . extensions
376+ . as_mut ( )
377+ . unwrap ( )
378+ . extend ( original_hugr. extensions ( ) ) ;
365379 }
366380
367381 /// Decode a list of pytket commands.
368382 pub ( super ) fn run_decoder (
369383 & mut self ,
370384 commands : & [ circuit_json:: Command ] ,
371385 ) -> Result < ( ) , PytketDecodeError > {
372- let config = self . config . clone ( ) ;
386+ let config = self . config ( ) . clone ( ) ;
373387 for com in commands {
374388 let op_type = com. op . op_type ;
375389 self . process_command ( com, config. as_ref ( ) )
@@ -411,9 +425,32 @@ impl<'h, H: HugrView> PytketDecoderContext<'h, H> {
411425 Ok ( ( ) )
412426 }
413427
414- /// Returns the configuration used by the decoder.
415- pub fn config ( & self ) -> & Arc < PytketDecoderConfig < H > > {
416- & self . config
428+ /// Returns a tracked opaque subgraph encoded in an opaque barrier in the pytket circuit.
429+ ///
430+ /// See [`OpaqueSubgraphPayload`][super::opaque::OpaqueSubgraphPayload]
431+ /// for more details.
432+ pub ( super ) fn get_opaque_subgraph (
433+ & self ,
434+ payload : & OpaqueSubgraphPayloadType ,
435+ ) -> Result < Hugr , PytketDecodeError > {
436+ match payload {
437+ OpaqueSubgraphPayloadType :: Inline { hugr_envelope } => {
438+ let hugr = Hugr :: load_str ( hugr_envelope, Some ( self . options . extension_registry ( ) ) )
439+ . map_err ( |e| PytketDecodeErrorInner :: UnsupportedSubgraphPayload {
440+ source : e,
441+ } ) ?;
442+ Ok ( hugr)
443+ }
444+ OpaqueSubgraphPayloadType :: External { id } => {
445+ match ( self . opaque_subgraphs , self . original_hugr ) {
446+ ( Some ( subgraphs) , Some ( original_hugr) ) if subgraphs. contains ( * id) => {
447+ let hugr = subgraphs[ * id] . extract_subgraph ( original_hugr, id. to_string ( ) ) ;
448+ Ok ( hugr)
449+ }
450+ _ => Err ( PytketDecodeErrorInner :: OpaqueSubgraphNotFound { id : * id } . wrap ( ) ) ,
451+ }
452+ }
453+ }
417454 }
418455}
419456
@@ -452,7 +489,7 @@ impl<'h, H: HugrView> PytketDecoderContext<'h, H> {
452489 params : & [ LoadedParameter ] ,
453490 ) -> Result < TrackedWires , PytketDecodeError > {
454491 self . wire_tracker
455- . find_typed_wires ( & self . config , types, qubit_args, bit_args, params)
492+ . find_typed_wires ( self . config ( ) , types, qubit_args, bit_args, params)
456493 }
457494
458495 /// Connects the input ports of a node using a list of input qubits, bits,
@@ -518,12 +555,12 @@ impl<'h, H: HugrView> PytketDecoderContext<'h, H> {
518555 let op_input_count: RegisterCount = sig
519556 . input_types ( )
520557 . iter ( )
521- . map ( |ty| self . config . type_to_pytket ( ty) . unwrap_or_default ( ) )
558+ . map ( |ty| self . config ( ) . type_to_pytket ( ty) . unwrap_or_default ( ) )
522559 . sum ( ) ;
523560 let op_output_count: RegisterCount = sig
524561 . output_types ( )
525562 . iter ( )
526- . map ( |ty| self . config . type_to_pytket ( ty) . unwrap_or_default ( ) )
563+ . map ( |ty| self . config ( ) . type_to_pytket ( ty) . unwrap_or_default ( ) )
527564 . sum ( ) ;
528565
529566 // Validate input counts
@@ -675,7 +712,7 @@ impl<'h, H: HugrView> PytketDecoderContext<'h, H> {
675712 let mut port_types = sig. output_ports ( ) . zip ( sig. output_types ( ) . iter ( ) ) ;
676713 while let Some ( ( port, ty) ) = port_types. next ( ) {
677714 let wire = Wire :: new ( node, port) ;
678- let counts = self . config . type_to_pytket ( ty) . unwrap_or_default ( ) ;
715+ let counts = self . config ( ) . type_to_pytket ( ty) . unwrap_or_default ( ) ;
679716 reg_count += counts;
680717
681718 // Get the qubits and bits for this wire.
@@ -685,7 +722,7 @@ impl<'h, H: HugrView> PytketDecoderContext<'h, H> {
685722 let expected_qubits = reg_count. qubits - counts. qubits + wire_qubits. len ( ) ;
686723 let expected_bits = reg_count. bits - counts. bits + wire_bits. len ( ) ;
687724 return Err ( make_unexpected_node_out_error (
688- & self . config ,
725+ self . config ( ) ,
689726 port_types,
690727 reg_count,
691728 expected_qubits,
@@ -732,6 +769,16 @@ impl<'h, H: HugrView> PytketDecoderContext<'h, H> {
732769 . load_half_turns_parameter ( & mut self . builder , param, Some ( typ) )
733770 . with_type ( typ, & mut self . builder )
734771 }
772+
773+ /// Returns the configuration used by the decoder.
774+ pub fn config ( & self ) -> & Arc < PytketDecoderConfig < H > > {
775+ self . options . get_config ( )
776+ }
777+
778+ /// Returns the options used by the decoder.
779+ pub fn options ( & self ) -> & DecodeOptions < H > {
780+ & self . options
781+ }
735782}
736783
737784/// Result of trying to decode pytket operation into a HUGR definition.
0 commit comments