Skip to content

feat: Add PersistentHugr #2080

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 10 commits into
base: release-rs-v0.16.0
Choose a base branch
from
Open

Conversation

lmondada
Copy link
Contributor

@lmondada lmondada commented Apr 15, 2025

The base of this PR will be moved to main once #2070 has been merged in.

Status: The API and main structs have been defined. Most of the core logic has yet to be implemented.

Status: PR is ready. The trait implementations for HugrView, VerifyPatch and ApplyPatch will be in a separate PR once progress on those is unblocked.

Closes #2096

@lmondada lmondada changed the base branch from main to feat/rewrite-trait April 15, 2025 10:48
@lmondada lmondada force-pushed the feat/persistenthugr branch from 44c3fe9 to 5780cda Compare April 15, 2025 10:49
@lmondada lmondada requested a review from aborgna-q April 15, 2025 10:52
@lmondada lmondada force-pushed the feat/persistenthugr branch from 5780cda to 6659c40 Compare April 17, 2025 13:14
@lmondada lmondada marked this pull request as ready for review April 17, 2025 13:17
@lmondada lmondada requested a review from a team as a code owner April 17, 2025 13:17
@lmondada lmondada force-pushed the feat/persistenthugr branch from 6659c40 to c480927 Compare April 17, 2025 13:23
@lmondada
Copy link
Contributor Author

bus factor considerations: we might want to fold RelRc into Hugr at some point (at least the parts that we care about), but I'd suggest first figuring out what works/if it works before putting efforts into that.

Base automatically changed from feat/rewrite-trait to release-rs-v0.16.0 April 29, 2025 13:20
@lmondada lmondada force-pushed the feat/persistenthugr branch from 7fd00f3 to aa7d5cb Compare April 29, 2025 14:49
Copy link

codecov bot commented Apr 29, 2025

Codecov Report

Attention: Patch coverage is 89.54869% with 44 lines in your changes missing coverage. Please review.

Project coverage is 83.44%. Comparing base (f0738b1) to head (fd7662d).

Files with missing lines Patch % Lines
hugr-core/src/hugr/persistent/resolver.rs 15.00% 17 Missing ⚠️
hugr-core/src/hugr/persistent/state_space.rs 88.72% 11 Missing and 4 partials ⚠️
hugr-core/src/hugr/persistent.rs 90.32% 9 Missing and 3 partials ⚠️
Additional details and impacted files
@@                  Coverage Diff                   @@
##           release-rs-v0.16.0    #2080      +/-   ##
======================================================
+ Coverage               83.37%   83.44%   +0.06%     
======================================================
  Files                     219      223       +4     
  Lines                   42281    42702     +421     
  Branches                38383    38804     +421     
======================================================
+ Hits                    35252    35632     +380     
- Misses                   5209     5243      +34     
- Partials                 1820     1827       +7     
Flag Coverage Δ
python 85.73% <ø> (ø)
rust 83.21% <89.54%> (+0.07%) ⬆️

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 requested review from cqc-alec and removed request for aborgna-q April 29, 2025 15:06
Copy link
Collaborator

@cqc-alec cqc-alec left a comment

Choose a reason for hiding this comment

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

Thanks, this looks great. Most of my comment are minor ones on the docs ... and some umming and aahing about the name.

.all_node_ids()
.exactly_one()
.ok()
.expect("just added one commit");
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the expect message could be improved. What would the caller have done wrong to get this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does the new phrasing clarify things? This can never happen: graph was just created with a single commit, which will be the graph's only node.

Comment on lines +91 to +96
if base_commits.len() != 1 {
Err(InvalidCommit::NonUniqueBase(base_commits.len()))
} else {
let base_commit = base_commits[0];
Ok(Self { graph, base_commit })
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we use exactly_one() here for conciseness?

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 absolutely, good spot!

#[non_exhaustive]
pub enum InvalidCommit {
/// The commit conflicts with existing commits in the state space.
#[error("Incompatible history: children commits conflict in {0:?} conflict in {1:?}")]
Copy link
Collaborator

Choose a reason for hiding this comment

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

The message seems a bit garbled?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed, fixed!

let (base_hugr, nodes) = simple_hugr;
let base_hugr_clone = base_hugr.clone();

println!("{}", base_hugr.mermaid_string());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we want to keep these println!s in the tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That slipped through. Removed :)

assert_eq!(direct_hugr.validate(), Ok(()));
assert_eq!(persistent_final_hugr.validate(), Ok(()));
assert_eq!(
direct_hugr.mermaid_string(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this the best method we have for equality checking of hugrs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It actually works with direct comparison! So will go with that, although this might break in the future if the node indexing changes for some reason.

Ideally, we'd use something like a hash-based comparison. I'll add a TODO comment about it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, spoke too soon! This seems to be non-deterministic (maybe it depends on the total order in which replacements are applied?) :/

I've reverted to mermaid_string comparisons, but left the comment that we should ideally use hash-based comparisons once this is implemented.

for (parent, new_invalid_nodes) in new_invalid_nodes {
let invalidation_set = self.deleted_nodes(parent).collect();
if let Some(&node) = new_invalid_nodes.intersection(&invalidation_set).next() {
return Err(InvalidCommit::IncompatibleHistory(parent, node));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would like to see a test for this.

}
}

/// A Hugr-like object that supports persistent mutation.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think "supports persistent mutation" is a rather odd way to describe it: maybe "... that includes its mutation history"? I'm still a bit doubtful about the name, though I don't have a great alternative. Would something like HugrRecord or HugrHistoryGraph be workable? They sound less "Hugr-like" though. Hmm ... perhaps PersistentHugr is best after all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, "persistent mutation" is an awkward phrasing. I like and have adopted your suggested phrasing.

That being said, I do like the PersistentHugr name. I think using the adjective "persistent" is correct and helpful in this context, referring to an established pattern of functional programming. I'm open to other suggestions though.

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