Skip to content

fix: Replace non-deterministic iterations on hash maps#3055

Open
aborgna-q wants to merge 2 commits into
mainfrom
ab/iter-over-hash-type
Open

fix: Replace non-deterministic iterations on hash maps#3055
aborgna-q wants to merge 2 commits into
mainfrom
ab/iter-over-hash-type

Conversation

@aborgna-q
Copy link
Copy Markdown
Collaborator

Enables the iter_over_hash_type clippy lint, and fixes all cases of iteration over hashmaps and hashsets that could cause non-deterministic outputs.

@aborgna-q aborgna-q requested a review from a team as a code owner May 12, 2026 10:21
@aborgna-q aborgna-q requested a review from mark-koch May 12, 2026 10:21
@codecov
Copy link
Copy Markdown

codecov Bot commented May 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.20%. Comparing base (90a165e) to head (88ec14d).
⚠️ Report is 8 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3055      +/-   ##
==========================================
+ Coverage   81.09%   81.20%   +0.11%     
==========================================
  Files         241      242       +1     
  Lines       45054    45629     +575     
  Branches    38822    39385     +563     
==========================================
+ Hits        36536    37055     +519     
- Misses       6542     6586      +44     
- Partials     1976     1988      +12     
Flag Coverage Δ
python 88.88% <ø> (-0.02%) ⬇️
rust 79.99% <100.00%> (+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.

blocks: Vec<Node>,
) -> (Node, Node, Node) {
let mut other_blocks = h.children(cfg).collect::<HashSet<_>>();
let mut other_blocks = h.children(cfg).collect::<BTreeSet<_>>();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not necessary - we only iterate through this to do an assert (line 489, five lines down) - you could either expect on the loop or rewrite to an .all (if that helps?)

Comment thread hugr-core/src/hugr/linking.rs Outdated
return Err(NodeLinkingError::NotChildOfRoot(sn));
}
for sn in other.children(other.module_root()) {
let Some(dirv) = children.get(&sn) else {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Eeek! This means we're now going through other.children which might be much bigger than children.

Nondeterminism only affects the error reported (NodeMultiplyReplaced), but to prevent that, you are probably better off copying children into a BTreeSet (avoiding the need for min_directive_key and so on)

Comment thread hugr-core/src/hugr.rs
/// sibling graph (since these must be the input and output nodes).
fn order_siblings_by_node_index(&mut self) {
let mut node_children: HashMap<Node, Vec<Node>> = HashMap::default();
let mut node_children = Vec::new();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not convinced there's any actual nondeterminism here; processing each element of node_children seems independent.

However, node_children seems like an enormous structure. Why not just merge the loops (move the self.hierarchy stuff in the second loop, into the first)? You'd need to do for node in self.nodes().collect::<Vec<_>>() but that vec would be much smaller than node_children after all!

.map(|&PatchNode(id, node)| (id, node))
.into_grouping_map()
.collect::<BTreeSet<_>>();
let mut new_invalid_nodes = IndexMap::<_, BTreeSet<_>>::new();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This feels independent/driveby? Map on LHS is BTreeMap not HashMap?

Copy link
Copy Markdown
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.

Love it, thanks @aborgna-q - a few suggestions but happy to approve unless you'd rather @mark-koch had a final look over?

Co-authored-by: Alan Lawrence <alan.lawrence@quantinuum.com>
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