Skip to content

feat: PersistentHugr Walker API #2168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: luca/persistent-impl-hugrview
Choose a base branch
from

Conversation

lmondada
Copy link
Contributor

@lmondada lmondada commented May 7, 2025

Closes #2074
Closes #2190

@lmondada lmondada requested a review from a team as a code owner May 7, 2025 18:46
@lmondada lmondada requested review from cqc-alec and removed request for a team May 7, 2025 18:46
@lmondada lmondada marked this pull request as draft May 7, 2025 18:46
@lmondada lmondada removed the request for review from cqc-alec May 7, 2025 18:46
Copy link

codecov bot commented May 7, 2025

Codecov Report

Attention: Patch coverage is 95.76720% with 8 lines in your changes missing coverage. Please review.

Project coverage is 82.38%. Comparing base (08e3eb0) to head (13caf29).

Files with missing lines Patch % Lines
hugr-core/src/hugr/persistent/walker/pinned.rs 93.15% 4 Missing and 1 partial ⚠️
hugr-core/src/hugr/persistent/walker.rs 97.32% 3 Missing ⚠️
Additional details and impacted files
@@                        Coverage Diff                        @@
##           luca/persistent-impl-hugrview    #2168      +/-   ##
=================================================================
+ Coverage                          82.24%   82.38%   +0.14%     
=================================================================
  Files                                235      237       +2     
  Lines                              41984    42173     +189     
  Branches                           38083    38272     +189     
=================================================================
+ Hits                               34528    34743     +215     
+ Misses                              5479     5452      -27     
- Partials                            1977     1978       +1     
Flag Coverage Δ
python 85.64% <ø> (ø)
rust 82.04% <95.76%> (+0.15%) ⬆️

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.

@lmondada lmondada force-pushed the feat/persistenthugr branch from a7729f3 to cb812be Compare May 8, 2025 07:05
@lmondada lmondada force-pushed the feat/persistentwalker branch 2 times, most recently from fd0c21f to 3b27b4d Compare May 10, 2025 15:51
@lmondada lmondada marked this pull request as ready for review May 10, 2025 15:52
@lmondada lmondada force-pushed the feat/persistentwalker branch 2 times, most recently from 2206368 to b81ed94 Compare May 10, 2025 16:07
@lmondada
Copy link
Contributor Author

lmondada commented May 10, 2025

EDIT: resolved!

I'm currently unhappy with the state of the end_to_end test within the walker folder, but this can't be simplified and moved out of the repo into tests until further enhancements to the API.

It is nonetheless a very useful test to have, even in its current form.

See #2190

@lmondada lmondada force-pushed the feat/persistentwalker branch 2 times, most recently from 782e1ba to ca5d841 Compare May 10, 2025 21:43
@lmondada lmondada force-pushed the feat/persistentwalker branch from ca5d841 to 7874237 Compare May 12, 2025 14:37
@lmondada lmondada changed the base branch from feat/persistenthugr to luca/persistent-impl-hugrview May 12, 2025 14:43
@lmondada lmondada force-pushed the feat/persistentwalker branch from 7874237 to b1685fd Compare May 12, 2025 14:44
@lmondada lmondada requested a review from acl-cqc May 12, 2025 14:45
@lmondada lmondada force-pushed the feat/persistentwalker branch from b1685fd to 654c4fc Compare May 12, 2025 16:37
@lmondada lmondada force-pushed the feat/persistentwalker branch from 654c4fc to b4bae59 Compare May 12, 2025 16:43
Copy link
Contributor

@acl-cqc acl-cqc left a comment

Choose a reason for hiding this comment

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

Thanks @lmondada, this is great! Not what you'd call easy stuff, but great job in making it comprehensible :-). I have about 60 small suggestions, there are only two big enough to justify not immediately approving:

  • Have I understand PinnedWire always has at least one endpoint pinned? I wasn't clear from the doc so I had to guess a bit, if that's not right then this may need some more thought
  • That equivalent_descendant_ports method....what is all the direction-changing doing...

@@ -0,0 +1,624 @@
//! Exploration of a [`PersistentHugr`] through incremental traversal of
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with "exploration of a [CommitStateSpace]" just below, but a PersistentHugr is a non-conflicting subgraph of a CommitStateSpace, right?

Maybe "Explores a CommitStateSpace (and allows) to establish/identify/build a PersistentHugr by incrementally" and then either "traversing connected subgraphs" as you have here (not sure if I've quite followed that yet though) or "pinning nodes resulting from particular rewrites" ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right! How do you find the following

Incremental traversal and construction of [PersistentHugr]s from [CommitStateSpace]s

?

It's hard to keep it to a high-level one-line summary

//! This module provides the [`Walker`] type, which enables intuitive
//! exploration of a [`CommitStateSpace`] by traversing wires and gradually
//! pinning (selecting) nodes that match a desired pattern. Unlike direct
//! manipulation of a [`PersistentHugr`], the Walker presents a familiar
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure what this "direct manipulation of a PersistentHugr" is that is so different from the "familiar nodes-and-wires interface". PersistentHugr implements HugrView, which is exactly that familiar nodes-and-wires interface....?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, PersistentHugr -> CommitStateSpace. I've added a bit more context to this sentence, does it make sense in its new form?

//! The key concept is that of "pinning" nodes - marking specific nodes as fixed
//! points in the exploration. As more nodes are pinned, the space of possible
//! HUGRs that are considered narrows; a Walker instance where all nodes are
//! pinned corresponds to a unique HUGR in the [`PersistentHugr`].
Copy link
Contributor

Choose a reason for hiding this comment

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

Like this, but don't you mean "...corresponds to a particular PersistentHugr (in the CommitStateSpace)"? As a PersistentHugr is a Hugr(View)...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. Re-reading this makes me think I must have done a wrong renaming operation (in one of the many renames haha) -- or just brain fog. Mostly we are refering to CommitStateSpaces, not PersistentHugrs!

//! exploration typically branches out into several parallel walkers.
//! 4. As walkers are expanded, more nodes get pinned, narrowing down the space
//! of possible HUGRs.
//! 5. Once exploration is complete (e.g. a pattern was fully matched), the
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes! Nice :)

//! 5. Once exploration is complete (e.g. a pattern was fully matched), the
//! walker can be converted into a [`PersistentHugr`] instance using
//! [`Walker::into_hugr`]. The matched nodes and ports can then be used to
//! create a [`SimpleReplacement`](crate::SimpleReplacement) object, which
Copy link
Contributor

Choose a reason for hiding this comment

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

I'll suspend disbelief here - the SimpleReplacement is the combination of all of the selected patches?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, you've done well to highlight this point. What I intended to say is that the pinned nodes can be used to specify a subgraph of the current PersistentHugr, which in turn can be used to define a new SimpleReplacement.

.contains(&pinned_node.1),
"pinned node is deleted"
);
for walker in walker.expand(&wire, None) {
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
for walker in walker.expand(&wire, None) {
for subwalker in walker.expand(&wire, None) {


// enqueue new wires added by the replacement
// (this will also add a lot of already visited wires, but they will
// be deduplicated)
Copy link
Contributor

Choose a reason for hiding this comment

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

IIUC, if you moved the outermost loop in enqueue_all to the first callsite, then you could skip that loop here because you are adding only a single replacement? Would that address this comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no -- you'd need to consider all commits that could be neighbours (but disjoint) with the newly added commit. It's a bit iffy, another area where the API will probably have to improve in the future.

state_space
}

fn create_replacement(wire: PinnedWire, walker: &Walker) -> Result<PersistentReplacement, ()> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Result -> Option

Copy link
Contributor Author

Choose a reason for hiding this comment

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

absolutely!

}

/// Get all pinned ports of the wire.
pub fn all_ports(&self) -> impl Iterator<Item = (PatchNode, Port)> + '_ {
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider calling these pinned_outport, pinned_inports and all_pinned_ports...reading the client code it's easy to miss that you have a PinnedWire not a Wire

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good names!

@@ -0,0 +1,406 @@
//! A test of the walker as it would typically be used by a user in practice.
Copy link
Contributor

Choose a reason for hiding this comment

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

This is fab**, although I wonder if it should be in persistent/tests.rs or persistent/walker_example.rs

** and seeing usage examples has lead to several suggestions for API improvements above and below ;)

Copy link
Contributor Author

@lmondada lmondada May 14, 2025

Choose a reason for hiding this comment

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

Sure thing, I'll put it within a persistent subfolder.

Strangely, cargo doesn't find the test file if I put it within a subfolder. I've called it persistent_walker_example.rs instead. (We can go for a more nested structure once there are more than two files in the directory)

@lmondada lmondada force-pushed the luca/persistent-impl-hugrview branch from 08e3eb0 to 7cd85d7 Compare May 19, 2025 11:14
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.

2 participants