fix: UnpackTuple error on disconnected outputs#2813
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2813 +/- ##
==========================================
- Coverage 83.71% 83.71% -0.01%
==========================================
Files 261 261
Lines 52637 52633 -4
Branches 47378 47374 -4
==========================================
- Hits 44064 44060 -4
Misses 6183 6183
Partials 2390 2390
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
acl-cqc
left a comment
There was a problem hiding this comment.
Looks good to me (even if you don't act on the other comment), thanks! One thought though: do we need to remove the MakeTuple's, or even the UnpackTuples? Or can we just change consumers of the UnpackTuple's to grab the inputs of the MakeTuple, and leave both nodes there for DeadCodeElimination to remove if possible?
Indeed (and definitely not for this PR), if we went that way, it'd be possible to use a dataflow analysis that would generalize this to deal with arbitrary Sums and Conditionals - including more cases of converting local edges + Input nodes to nonlocal edges.
hugr-passes/src/untuple.rs
Outdated
| // Wire the inputs directly to the unpack outputs | ||
| outputs.extend(replacement.input_wires().cycle().take(num_unpack_outputs)); | ||
| let replacement_inputs = replacement.input_wires().collect_vec(); | ||
| replacement_outputs.extend( |
There was a problem hiding this comment.
If we didn't care about calling Vec::with_capacity then we could combine these two Vec's and this would be simpler and significantly clearer IMHO. Is it really worth the complexity for that?
## 🤖 New release * `hugr-model`: 0.25.3 -> 0.25.4 (✓ API compatible changes) * `hugr-core`: 0.25.3 -> 0.25.4 (✓ API compatible changes) * `hugr-llvm`: 0.25.3 -> 0.25.4 (✓ API compatible changes) * `hugr-passes`: 0.25.3 -> 0.25.4 (✓ API compatible changes) * `hugr`: 0.25.3 -> 0.25.4 (✓ API compatible changes) * `hugr-cli`: 0.25.3 -> 0.25.4 (✓ API compatible changes) * `hugr-persistent`: 0.4.3 -> 0.4.4 <details><summary><i><b>Changelog</b></i></summary><p> ## `hugr-model` <blockquote> ## [0.25.0](hugr-model-v0.24.3...hugr-model-v0.25.0) - 2025-12-22 ### Bug Fixes - *(model)* avoid non abi-compatible pyo3 calls ([#2679](#2679)) ### New Features - [**breaking**] Upgrade pyo3 dependency to 0.27 ([#2736](#2736)) ### Refactor - Direct import of model representation to Python ([#2683](#2683)) </blockquote> ## `hugr-core` <blockquote> ## [0.25.3](hugr-core-v0.25.2...hugr-core-v0.25.3) - 2026-01-09 ### Bug Fixes - more nondeterminism in linking ([#2792](#2792)) ### Documentation - Add collection extension ops to the spec ([#2767](#2767)) </blockquote> ## `hugr-llvm` <blockquote> ## [0.25.0](hugr-llvm-v0.24.3...hugr-llvm-v0.25.0) - 2025-12-22 ### New Features - *(llvm)* [**breaking**] upgrade to inkwell 0.7 ([#2695](#2695)) ### Refactor - Deprecate Value::Function and inline_constant_functions ([#2770](#2770)) </blockquote> ## `hugr-passes` <blockquote> ## [0.25.4](hugr-passes-v0.25.3...hugr-passes-v0.25.4) - 2026-01-14 ### Bug Fixes - UnpackTuple error on disconnected outputs ([#2813](#2813)) </blockquote> ## `hugr` <blockquote> ## [0.25.4](hugr-v0.25.3...hugr-v0.25.4) - 2026-01-14 ### Bug Fixes - UnpackTuple error on disconnected outputs ([#2813](#2813)) </blockquote> ## `hugr-cli` <blockquote> ## [0.25.0](hugr-cli-v0.24.3...hugr-cli-v0.25.0) - 2025-12-22 ### New Features - *(cli, python)* programmatic interface to cli with python bindings ([#2677](#2677)) - return description output to python on error ([#2681](#2681)) - [**breaking**] Type-safe access for node metadata ([#2755](#2755)) - [**breaking**] GeneratorDesc metadata definition ([#2759](#2759)) ### Refactor - [**breaking**] move envelope reading to dedicated module with dedicated errors ([#2689](#2689)) - *(cli)* [**breaking**] remove deprecated hugr_json handling ([#2690](#2690)) - [**breaking**] Remove multiple deprecated definitions ([#2751](#2751)) </blockquote> ## `hugr-persistent` <blockquote> ## [0.4.0](hugr-persistent-v0.3.4...hugr-persistent-v0.4.0) - 2025-12-22 ### New Features - [**breaking**] Remove `RootCheckable` ([#2704](#2704)) - [**breaking**] Bump MSRV to Rust 1.89 ([#2747](#2747)) - [**breaking**] Type-safe access for node metadata ([#2755](#2755)) ### Refactor - [**breaking**] Remove multiple deprecated definitions ([#2751](#2751)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/).
## 🤖 New release * `hugr-model`: 0.25.4 -> 0.25.5 (✓ API compatible changes) * `hugr-core`: 0.25.4 -> 0.25.5 (✓ API compatible changes) * `hugr-llvm`: 0.25.4 -> 0.25.5 (✓ API compatible changes) * `hugr-passes`: 0.25.4 -> 0.25.5 (✓ API compatible changes) * `hugr-persistent`: 0.4.4 -> 0.4.5 (✓ API compatible changes) * `hugr`: 0.25.4 -> 0.25.5 (✓ API compatible changes) * `hugr-cli`: 0.25.4 -> 0.25.5 (✓ API compatible changes) <details><summary><i><b>Changelog</b></i></summary><p> ## `hugr-model` <blockquote> ## [0.25.0](hugr-model-v0.24.3...hugr-model-v0.25.0) - 2025-12-22 ### Bug Fixes - *(model)* avoid non abi-compatible pyo3 calls ([#2679](#2679)) ### New Features - [**breaking**] Upgrade pyo3 dependency to 0.27 ([#2736](#2736)) ### Refactor - Direct import of model representation to Python ([#2683](#2683)) </blockquote> ## `hugr-core` <blockquote> ## [0.25.5](hugr-core-v0.25.4...hugr-core-v0.25.5) - 2026-02-03 ### Refactor - make EnvelopeFormat::ModelWithExtensions the default ([#2816](#2816)) </blockquote> ## `hugr-llvm` <blockquote> ## [0.25.0](hugr-llvm-v0.24.3...hugr-llvm-v0.25.0) - 2025-12-22 ### New Features - *(llvm)* [**breaking**] upgrade to inkwell 0.7 ([#2695](#2695)) ### Refactor - Deprecate Value::Function and inline_constant_functions ([#2770](#2770)) </blockquote> ## `hugr-passes` <blockquote> ## [0.25.4](hugr-passes-v0.25.3...hugr-passes-v0.25.4) - 2026-01-14 ### Bug Fixes - UnpackTuple error on disconnected outputs ([#2813](#2813)) </blockquote> ## `hugr-persistent` <blockquote> ## [0.4.0](hugr-persistent-v0.3.4...hugr-persistent-v0.4.0) - 2025-12-22 ### New Features - [**breaking**] Remove `RootCheckable` ([#2704](#2704)) - [**breaking**] Bump MSRV to Rust 1.89 ([#2747](#2747)) - [**breaking**] Type-safe access for node metadata ([#2755](#2755)) ### Refactor - [**breaking**] Remove multiple deprecated definitions ([#2751](#2751)) </blockquote> ## `hugr` <blockquote> ## [0.25.5](hugr-v0.25.4...hugr-v0.25.5) - 2026-02-03 ### Refactor - make EnvelopeFormat::ModelWithExtensions the default ([#2816](#2816)) </blockquote> ## `hugr-cli` <blockquote> ## [0.25.5](hugr-cli-v0.25.4...hugr-cli-v0.25.5) - 2026-02-03 ### Refactor - make EnvelopeFormat::ModelWithExtensions the default ([#2816](#2816)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/).
Fixes Quantinuum/tket2#1347.
SiblingSubgraph::try_from_nodesignores disconnected ports, so when creating the replacement circuit we need to take some extra care when matching inputs to outputs.The linked issue showed an error when optimizing a pair of pack/unpack nodes like the following:
graph LR subgraph 0 ["(0) Module"] direction LR subgraph 1 ["(1) [**FuncDefn: #quot;test#quot;**]"] direction LR style 1 stroke:#832561,stroke-width:3px 2["(2) Input"] 3["(3) Output"] 4["(4) prelude.MakeTuple"] 5["(5) prelude.UnpackTuple"] 2--"0:0<br>Bool"-->4 2--"1:1<br>float64"-->4 4--"0:0<br>[Bool, float64]"-->5 5--"1:0<br>float64"-->3 end endNote that the unpack node only has its second output connected, so the replacement hugr must connect its only output to the second input instead of the first (as was the case before).