Skip to content

Conversation

aborgna-q
Copy link
Collaborator

@aborgna-q aborgna-q commented Aug 12, 2025

  • Adds a PytketDecoder trait that let us extend the decoding framework to external extensions.
  • Translations are no longer 1-to-1 between pytket commands and hugr ops, the decoding call has access to a hugr builder and its context.
  • Allows tracking wires with complex/composite types. We don't provide helpers to convert types yet, it's up to the extension emitter to look at the incoming wire types. (Note: I splitted this change to a previous PR, feat: Define a wire tracker for the new pytket decoder #1036)

TODO:

  • Implement the decoder trait for all standard extensions.
  • Fix remaining test errors.
  • Add a nicer guide for writing extension traits in the module docs.

BREAKING CHANGE: Split pytket encoder/decoder errors into separate structs.

@hugrbot
Copy link
Collaborator

hugrbot commented Aug 12, 2025

This PR contains breaking changes to the public Rust API.

cargo-semver-checks summary

--- failure enum_variant_missing: pub enum variant removed or renamed ---

Description:
A publicly-visible enum has at least one variant that is no longer available under its prior name. It may have been renamed or removed entirely.
      ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
     impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.43.0/src/lints/enum_variant_missing.ron

Failed in:
variant PytketEncodeError::MultiIndexedRegister, previously in file /home/runner/work/tket2/tket2/BASELINE_BRANCH/tket/src/serialize/pytket.rs:250
variant PytketEncodeError::InvalidJson, previously in file /home/runner/work/tket2/tket2/BASELINE_BRANCH/tket/src/serialize/pytket.rs:257
variant PytketEncodeError::InvalidJsonEncoding, previously in file /home/runner/work/tket2/tket2/BASELINE_BRANCH/tket/src/serialize/pytket.rs:261
variant PytketEncodeError::FileLoadError, previously in file /home/runner/work/tket2/tket2/BASELINE_BRANCH/tket/src/serialize/pytket.rs:265

--- failure trait_method_added: pub trait method added ---

Description:
A non-sealed public trait added a new method without a default implementation, which breaks downstream implementations of the trait
      ref: https://doc.rust-lang.org/cargo/reference/semver.html#trait-new-item-no-default
     impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.43.0/src/lints/trait_method_added.ron

Failed in:
trait method tket::serialize::pytket::TKETDecode::decode_with_config in file /home/runner/work/tket2/tket2/PR_BRANCH/tket/src/serialize/pytket.rs:73
trait method tket::serialize::TKETDecode::decode_with_config in file /home/runner/work/tket2/tket2/PR_BRANCH/tket/src/serialize/pytket.rs:73

@aborgna-q aborgna-q force-pushed the ab/decoder-extension branch 2 times, most recently from 273b870 to e5d3128 Compare August 12, 2025 12:38
Copy link

codecov bot commented Aug 13, 2025

Codecov Report

❌ Patch coverage is 60.80247% with 254 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.47%. Comparing base (2466ee2) to head (c015fad).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
tket/src/serialize/pytket/decoder.rs 63.34% 98 Missing and 16 partials ⚠️
tket/src/serialize/pytket/extension/bool.rs 8.10% 34 Missing ⚠️
tket/src/serialize/pytket/decoder/wires.rs 46.15% 26 Missing and 2 partials ⚠️
tket/src/serialize/pytket/extension/tket.rs 65.38% 26 Missing and 1 partial ⚠️
tket/src/serialize/pytket/extension.rs 9.52% 18 Missing and 1 partial ⚠️
tket/src/serialize/pytket/extension/prelude.rs 58.33% 9 Missing and 1 partial ⚠️
tket/src/serialize/pytket/extension/tk1.rs 75.00% 5 Missing and 5 partials ⚠️
tket/src/serialize/pytket.rs 52.63% 5 Missing and 4 partials ⚠️
tket/src/serialize/pytket/encoder.rs 50.00% 2 Missing ⚠️
tket/src/serialize/pytket/config/decoder_config.rs 98.03% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1030      +/-   ##
==========================================
+ Coverage   78.03%   78.47%   +0.43%     
==========================================
  Files          99       98       -1     
  Lines       12208    12461     +253     
  Branches    11929    12182     +253     
==========================================
+ Hits         9527     9779     +252     
+ Misses       2048     2035      -13     
- Partials      633      647      +14     
Flag Coverage Δ
python 81.00% <ø> (ø)
rust 78.41% <60.80%> (+0.44%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@aborgna-q
Copy link
Collaborator Author

aborgna-q commented Aug 13, 2025

Marking this as ready for release.
There's multiple items left for followup PRs:

  • Add an implementors guide to the tket::serialize::pytket::extension docs.
  • Add a qsystem encoder/decoder and a default config containing it
  • Add more tests
  • Decode unsupported hugrs from inside pytket barriers
  • Let the extension emiters define automatic type conversions (e.g. array destructuring, unpack tuple, etc.)

@aborgna-q aborgna-q marked this pull request as ready for review August 13, 2025 14:00
@aborgna-q aborgna-q requested a review from a team as a code owner August 13, 2025 14:00
@aborgna-q aborgna-q requested a review from ss2165 August 13, 2025 14:00
@aborgna-q aborgna-q force-pushed the ab/decoder-extension branch from fccf400 to 8fef667 Compare August 13, 2025 14:02
@aborgna-q aborgna-q requested a review from Copilot August 13, 2025 14:57
Copilot

This comment was marked as resolved.

@aborgna-q aborgna-q force-pushed the ab/decoder-extension branch from ab2dffe to fd0e745 Compare August 13, 2025 16:47
@aborgna-q aborgna-q changed the base branch from main to ab/decoder-wire-tracker August 13, 2025 16:47
@aborgna-q aborgna-q force-pushed the ab/decoder-extension branch from fd0e745 to 1f3cb42 Compare August 13, 2025 17:03
@aborgna-q aborgna-q force-pushed the ab/decoder-wire-tracker branch from 420e3ac to fbb74ac Compare August 13, 2025 17:03
@aborgna-q aborgna-q force-pushed the ab/decoder-wire-tracker branch from a92a1d2 to 0bb0c43 Compare August 14, 2025 11:13
@aborgna-q aborgna-q force-pushed the ab/decoder-extension branch from 1f3cb42 to e4e7686 Compare August 14, 2025 11:14
@aborgna-q aborgna-q requested review from lmondada and removed request for ss2165 August 14, 2025 14:22
@aborgna-q aborgna-q force-pushed the ab/decoder-extension branch from d9d9e28 to d53d071 Compare August 14, 2025 14:45
github-merge-queue bot pushed a commit that referenced this pull request Aug 14, 2025
No functionality changes, only renames that we didn't do in #987 

I'm not touching the decoder code, since it's already being modified by
#1030

BREAKING CHANGE: Renamed various pytket encoder-related structs and
methods from `tk1*` to `pytket`
@aborgna-q aborgna-q force-pushed the ab/decoder-extension branch from d53d071 to c32be5d Compare August 14, 2025 21:54
@aborgna-q aborgna-q force-pushed the ab/decoder-extension branch from c32be5d to 317d5ee Compare August 15, 2025 01:48
Copy link
Contributor

@lmondada lmondada left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool! None of my comments should take long to resolve, so I think we can definitely merge this in today.

Comment on lines 199 to 200
dfg.set_metadata(METADATA_Q_OUTPUT_REGISTERS, json!(output_qubits));
dfg.set_metadata(METADATA_B_OUTPUT_REGISTERS, json!(output_bits));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is outside this PR's diff, but hear me out:

It seems you only store the implicit_permutation as metadata. If this code is also used to load pytket circuits into HUGR, then the user would presumably expect that the HUGR respects the permutation, i.e. that the order of the outputs are shuffled accrodingly...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We take care of that in the hugr->pytket encoder logic :)

// Compute the final register permutations.
let (qubit_outputs, qubit_permutation) =
compute_final_permutation(qubit_outputs, &self.qubits, &self.output_qubits);

We compute the permutation from the registers we see at the output, and compose it with any METADATA_{B,Q}_OUTPUT_REGISTERS metadata originating from pytket.

That lets us do hugr rewrites that swap qubits around without caring about the pytket repr.

(We are surely missing tests for that though...)

///
/// A [decoder configuration](crate::serialize::pytket::PytketDecoderConfig)
/// contains a list of such decoders.
pub trait PytketDecoder {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a mention of PytketDecoder to the module docs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a paragraph. We'll expand the module docs in a followup PR

use hugr::extension::simple_op::MakeExtensionOp;
use hugr::extension::ExtensionId;
use hugr::ops::ExtensionOp;
use hugr::ops::{ExtensionOp, OpType};
use hugr::types::TypeArg;
use hugr::HugrView;
use tket_json_rs::optype::OpType as Tk1OpType;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to PytketOpType?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried, but we decided not to.
#1037

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok got it, but this would just be a file-local rename... You can probably do it 🙃

@lmondada
Copy link
Contributor

lmondada commented Aug 15, 2025

Urgh, I used github's PR VSCode extension, and it's very buggy. It lost some of the comments I had made. I've added them back myself, as far as I could remember, hopefully I didn't miss anything important :(

@lmondada
Copy link
Contributor

Coverage seems to say that impl PytketDecoder for BoolEmitter is not tested? Might be worth adding a test for that...

@aborgna-q aborgna-q requested a review from lmondada August 15, 2025 10:12
Copy link
Contributor

@lmondada lmondada left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks a lot!

Just one more suggestion: consider using "Resource" instead of "Wire", when referring to pytket wires. E.g. ResourceTracker instead of WireTracker.

Would be good if "wire" only referred to HUGR wires :)

EDIT: Reposting my earlier message that might have been lost:

Coverage seems to say that impl PytketDecoder for BoolEmitter is not tested? Might be worth adding a test for that...

use hugr::extension::simple_op::MakeExtensionOp;
use hugr::extension::ExtensionId;
use hugr::ops::ExtensionOp;
use hugr::ops::{ExtensionOp, OpType};
use hugr::types::TypeArg;
use hugr::HugrView;
use tket_json_rs::optype::OpType as Tk1OpType;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok got it, but this would just be a file-local rename... You can probably do it 🙃

let wire_tracker = Self::init_wire_tracker(
serialcirc,
&mut dfg,
&signature.input,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you can probably recover the input types from the dfg, and avoid a signature.clone() above?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're passing &mut dfg around, so we can't have a reference to the signature -.-

@@ -110,7 +114,7 @@ pub trait PytketDecoder {

/// Given a pytket [`tket_json_rs::circuit_json::Operation`] node in the
/// HUGR circuit and its operation type, try to convert it to a pytket
/// operation and add it to the pytket encoder.
/// operation and add it to the pytket decoder.
///
/// Returns an [`DecodeStatus`] indicating if the operation was successfully
/// converted. If the operation is not supported by the encoder, it's
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// converted. If the operation is not supported by the encoder, it's
/// converted. If the operation is not supported by the decoder, it's

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also on the two lines below.

Base automatically changed from ab/decoder-wire-tracker to main August 15, 2025 14:44
@aborgna-q
Copy link
Collaborator Author

Awesome, thanks a lot!

Just one more suggestion: consider using "Resource" instead of "Wire", when referring to pytket wires. E.g. ResourceTracker instead of WireTracker.

Would be good if "wire" only referred to HUGR wires :)

WireTracker is a mix of both, it tracks HUGR wires that carry pytket resources.

We could use some documentation standarisation about those terms, but thankfully they are all private types so we can rename them later 🤷

@aborgna-q aborgna-q added this pull request to the merge queue Aug 15, 2025
Merged via the queue into main with commit 6a1e604 Aug 15, 2025
19 of 20 checks passed
@aborgna-q aborgna-q deleted the ab/decoder-extension branch August 15, 2025 15:05
@hugrbot hugrbot mentioned this pull request Aug 15, 2025
github-merge-queue bot pushed a commit that referenced this pull request Aug 18, 2025
## 🤖 New release

* `tket`: 0.13.2 -> 0.14.0 (✓ API compatible changes)
* `tket-qsystem`: 0.18.1 -> 0.19.0 (✓ API compatible changes)

<details><summary><i><b>Changelog</b></i></summary><p>

## `tket`

<blockquote>

##
[0.14.0](tket-v0.13.2...tket-v0.14.0)
- 2025-08-18

### New Features

- [**breaking**] Allow PytketTypeTranslators to translate nested types
([#1038](#1038))
- Define a wire tracker for the new pytket decoder
([#1036](#1036))
- [**breaking**] Reworked pytket decoder framework
([#1030](#1030))
- [**breaking**] Use qsystem encoder/decoders in tket-py
([#1041](#1041))
- [**breaking**] Avoid eagerly cloning SerialCircuits when decoding from
pytket ([#1048](#1048))

### Refactor

- [**breaking**] Rename tk2 encoder names to tket
([#1037](#1037))
</blockquote>

## `tket-qsystem`

<blockquote>

##
[0.19.0](tket-qsystem-v0.18.1...tket-qsystem-v0.19.0)
- 2025-08-18

### New Features

- Add emitters for tket-qsystem
([#1039](#1039))
- [**breaking**] Avoid eagerly cloning SerialCircuits when decoding from
pytket ([#1048](#1048))
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants