Conversation
e58de1d to
57a2f0a
Compare
57a2f0a to
6b94a7d
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1052 +/- ##
==========================================
+ Coverage 79.09% 79.14% +0.04%
==========================================
Files 115 120 +5
Lines 13397 14147 +750
Branches 12615 13365 +750
==========================================
+ Hits 10597 11196 +599
- Misses 2146 2274 +128
- Partials 654 677 +23
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:
|
|
Three things on my mind
|
acl-cqc
left a comment
There was a problem hiding this comment.
In general I quite like this - the approach seems entirely reasonable within TKET, and perhaps a bit odd/overly-specialized in portgraph :). Haven't done a detailed code review but a few thoughts mostly on docs here.
My main question is - wtf CopyableValueID? Do you really want/use it, or did you just think you had to put something in for nonlinear ports? If the latter, would this PR work/make sense if you stripped it out?
tket/src/resource.rs
Outdated
| //! the circuit. Each resource has a unique [`ResourceId`] and operations on | ||
| //! the same resource are ordered by a [`Position`]. | ||
| //! - **Copyable values**: Regular values that can be copied and discarded | ||
| //! freely. Each is identified by a unique [`CopyableValueId`]. |
There was a problem hiding this comment.
I guess I will find out, but might be good to say that these are different/not-resource-tracked/something here.
tket/src/resource/flow.rs
Outdated
| /// The i-th entry is Some(resource_id) if the i-th port is a linear type, | ||
| /// None otherwise. Returns the resource IDs of the operation's outputs | ||
| /// in port order. Output resource IDs should be one of the input resource | ||
| /// IDs for resource-preserving operations, or None for new resources or |
There was a problem hiding this comment.
I'm inferring here that every None is a new resource-id exactly if (iff) it's linear
There was a problem hiding this comment.
Yes, I've clarified that!
tket/src/resource.rs
Outdated
| //! | ||
| //! - **Linear resources**: Non-copyable values that form resource paths through | ||
| //! the circuit. Each resource has a unique [`ResourceId`] and operations on | ||
| //! the same resource are ordered by a [`Position`]. |
There was a problem hiding this comment.
Say something like ResourceFlow allows to determine how resources are passed through, discarded or created by an op (for linear ports)
tket/src/resource/scope.rs
Outdated
| @@ -0,0 +1,596 @@ | |||
| //! Main ResourceScope implementation for tracking resources in HUGR subgraphs. | |||
There was a problem hiding this comment.
nit: Can you drop the first line and just run with "Provides the [ResourceScope] struct which...." or does clippy/etc. complain?
tket/src/resource/scope.rs
Outdated
| ) -> impl Iterator<Item = H::Node> + '_ { | ||
| let mut curr_node = start_node; | ||
|
|
||
| iter::from_fn(move || { |
There was a problem hiding this comment.
nit: does iter::successors let you avoid the mut curr_node?
There was a problem hiding this comment.
oh, super neat!! Did not know about it!
tket/src/resource/scope.rs
Outdated
| // order. | ||
| for node in toposort_subgraph(&self.hugr, &self.subgraph, self.find_sources()) { | ||
| if self.hugr.get_optype(node).dataflow_signature().is_none() { | ||
| // ignore non-dataflow ops |
There was a problem hiding this comment.
Whilst I think this is fine, I suspect non-dataflow nodes - like "dataflow" ops with no inputs or outputs - would just end any flows (and not start any new flows!) ?
There was a problem hiding this comment.
Yes that's true. As a result, nodes that are not dataflow ops will not have any opvalues assigned to their ports. However, any dataflow op downstream will assign fresh resource IDs if required on line 303:
self.assign_missing_op_values(node, &mut allocator);Do you have a better behaviour in mind for non-dataflow ops?
There was a problem hiding this comment.
No...certainly they feel like no-ops, and I think they are. I wonder whether the continue is necessary, will the skipped code actually do anything?
There was a problem hiding this comment.
the skipped code would panic on non-dataflow nodes. I have changed that to ignore any non-dataflow nodes, is definitely "better" code practice :)
tket/src/resource/scope.rs
Outdated
| } | ||
|
|
||
| /// All copyable values on the ports of `node` in the given direction. | ||
| pub fn get_copyable_values( |
There was a problem hiding this comment.
(I note this isn't used....)
There was a problem hiding this comment.
I have removed CopyableValueID and am using Wire instead. You were right -- it's much better.
|
I mean, if this went into Portgraph, it'd have to do so without any mention of linearity, so probably leaving out any (useful!) implementation of the ResourceFlow trait entirely; that would then have to be done in tket... |
|
I will address your comments one by one. Before that though, one question: I could replace
Of course, conversions between |
|
Having slept on it, I will try to use the CircuitUnit enum. Might want to wrap it into a tket-owned type... EDIT: There is now a |
|
Note: I've had to change fn map_resources(
&self,
node: H::Node,
hugr: &H,
inputs: &[Option<ResourceId>],
) -> Result<Vec<Option<ResourceId>>, UnsupportedOp>;This was required to implement I chose |
|
Yeah so I feel the Hugr |
acl-cqc
left a comment
There was a problem hiding this comment.
Looking good! I suspect I won't make any more comments but I'll send now just to give myself time to think ;-). Or @tatiana-s do you want to take a look?
tket/src/resource/scope.rs
Outdated
| // order. | ||
| for node in toposort_subgraph(&self.hugr, &self.subgraph, self.find_sources()) { | ||
| if self.hugr.get_optype(node).dataflow_signature().is_none() { | ||
| // ignore non-dataflow ops |
There was a problem hiding this comment.
No...certainly they feel like no-ops, and I think they are. I wonder whether the continue is necessary, will the skipped code actually do anything?
acl-cqc
left a comment
There was a problem hiding this comment.
Great stuff Luca, thanks for all the changes.
These are all 1-liner "nits" but there are a couple of wrong comments etc.
tket/src/resource.rs
Outdated
| //! introduces the notion of "Resource" to extend the lifetime of a linear value | ||
| //! over multiple ops. | ||
| //! | ||
| //! If a linear value appears both in an op's input and output, we say that it |
There was a problem hiding this comment.
IIUC, this means that: a linear value is called "resource-preserving" if it appears in op's input and output.
| //! If a linear value appears both in an op's input and output, we say that it | |
| //! If a linear value appears both in an op's input and output, we say that the op "preserves" that value. |
(or preserves that resource; perhaps "if a linear value appears in both input and output of an op")
There was a problem hiding this comment.
It's now longer but more precise:
Every linear value is associated with a resource. If a linear value passed as input to an op is also returned by the op as an output, then both input and output values are associated with the same resource. We say that the op "preserves" the resource.
| ) -> Result<Vec<Option<ResourceId>>, UnsupportedOp>; | ||
|
|
||
| /// Convert this ResourceFlow into a boxed trait object. | ||
| fn into_boxed<'a>(self) -> Box<dyn 'a + ResourceFlow<H>> |
There was a problem hiding this comment.
| fn into_boxed<'a>(self) -> Box<dyn 'a + ResourceFlow<H>> | |
| fn into_boxed<'a>(self) -> Box<dyn 'a + Self> |
There was a problem hiding this comment.
Maybe Box<dyn '_ + Self works without the <'a> ?
There was a problem hiding this comment.
I've tried, the compiler does not like it :(. I cannot replace ResourceFlow<H> with Self
expected trait, found self type
Self
and cannot make the lifetime implicit either.
tket/src/resource/flow.rs
Outdated
| /// This implementation considers that an operation is resource-preserving if | ||
| /// for all port indices i, either | ||
| /// - the i-th input and i-th output are both linear and are of the same type, | ||
| /// - or the i-th input and i-th output are both copyable, or one is copyable |
There was a problem hiding this comment.
| /// - or the i-th input and i-th output are both copyable, or one is copyable | |
| /// - or the i-th input and i-th output are both copyable, | |
| /// - or one is copyable and the other does not exist |
|
|
||
| /// Configuration for a ResourceScope. | ||
| pub struct ResourceScopeConfig<'a, H: HugrView> { | ||
| flows: Vec<Box<dyn 'a + ResourceFlow<H>>>, |
There was a problem hiding this comment.
Might be worth documenting that these will be tried in order (it wasn't obvious to me that the second would only be used if the first failed)
tket/src/resource/scope.rs
Outdated
| CircuitUnit::sentinel(), | ||
| &signature, | ||
| )) | ||
| .into() |
There was a problem hiding this comment.
The .into adds the Some here? I think it might be clearer to do Some(...) explicitly...
| } | ||
|
|
||
| /// Increment the position by 1. | ||
| pub fn increment(&self) -> Self { |
There was a problem hiding this comment.
You might want add_int(&self, usize) -> Self
There was a problem hiding this comment.
I'll leave this to a minimum for the time being, it's always easy to add more if needed.
tket/src/resource/types.rs
Outdated
| /// A value associated with a dataflow port, identified either by a resource ID | ||
| /// (for linear values) or by its wire (for copyable values). | ||
| /// | ||
| /// This can currently be converted to and from [`hugr::CircuitUnit`], but |
There was a problem hiding this comment.
Remove this comment now (I think conversions in both directions are gone)
| } | ||
|
|
||
| /// Get the underlying usize value of this ResourceId. | ||
| pub fn as_usize(self) -> usize { |
There was a problem hiding this comment.
I note this isn't used!! I guess it's reasonable to have it for indexing into an array etc.
There was a problem hiding this comment.
Yes pretty sure I need it in one of my many local branches 😅
tket/src/resource/types.rs
Outdated
| } | ||
| } | ||
|
|
||
| impl Default for ResourceAllocator { |
There was a problem hiding this comment.
I think you'll get this if you just derive Default, one could even argue there's no need for ::new()
There was a problem hiding this comment.
Yes that's true. Removed! I'll define new in terms of Default.
## 🤖 New release * `tket`: 0.14.0 -> 0.15.0 (✓ API compatible changes) * `tket-qsystem`: 0.20.1 -> 0.21.0 (✓ API compatible changes) <details><summary><i><b>Changelog</b></i></summary><p> ## `tket` <blockquote> ## [0.15.0](tket-v0.14.0...tket-v0.15.0) - 2025-09-15 ### Bug Fixes - [**breaking**] Fix rotation -> float param type conversion ([#1061](#1061)) - Pytket barrier operations not being decoded ([#1069](#1069)) - Always load parameter expressions as half turns in the decoder ([#1083](#1083)) - Move attribute to come after all the cases. ([#1112](#1112)) ### New Features - Capture pytket's output permutation explicitly in the hugr connectivity ([#1075](#1075)) - Add ResourceScope ([#1052](#1052)) - [**breaking**] Remove unnecessary Arc from PytketDecoder method ([#1114](#1114)) - [**breaking**] Remove deprecated definitions ([#1113](#1113)) </blockquote> ## `tket-qsystem` <blockquote> ## [0.21.0](tket-qsystem-v0.20.1...tket-qsystem-v0.21.0) - 2025-09-15 ### Bug Fixes - [**breaking**] Fix rotation -> float param type conversion ([#1061](#1061)) - Pytket barrier operations not being decoded ([#1069](#1069)) - *(qystem)* fix angle bug in CZ decomposition ([#1080](#1080)) - Always load parameter expressions as half turns in the decoder ([#1083](#1083)) ### New Features - Add a `borrow_array` type replacement pass ([#975](#975)) - Add gpu module ([#1090](#1090)) - [**breaking**] Remove unnecessary Arc from PytketDecoder method ([#1114](#1114)) - [**breaking**] Remove deprecated definitions ([#1113](#1113)) ### Refactor - [**breaking**] Factor out wasm extension code into compute module ([#1089](#1089)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). --------- Co-authored-by: Agustín Borgna <121866228+aborgna-q@users.noreply.github.com> Co-authored-by: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>

Alright, couldn't resist it. Here's a PR that moves a lot of the logic that I tried to put into
portgraphintotket. I think it makes much more sense this way.I'm interested to see what you think! (a lot of the diff is docs and snapshot tests, so don't worry :P)