Skip to content

[Bug #21449] Fix Set#divide{|a,b|} using Union-find structure#13680

Merged
tompng merged 2 commits intoruby:masterfrom
tompng:set_divide_unionfind
Jun 23, 2025
Merged

[Bug #21449] Fix Set#divide{|a,b|} using Union-find structure#13680
tompng merged 2 commits intoruby:masterfrom
tompng:set_divide_unionfind

Conversation

@tompng
Copy link
Copy Markdown
Member

@tompng tompng commented Jun 23, 2025

Implement Set#divide by union-find structure with path compression.
https://en.wikipedia.org/wiki/Disjoint-set_data_structure
Since divide{|a,b|} calls the given block n**2 times in the worst case, there is no need to implement union-by-rank or union-by-size optimization.

Implements Union-find structure with path compression.
Since divide{|a,b|} calls the given block n**2 times in the worst case, there is no need to implement union-by-rank or union-by-size optimization.
@mame mame requested a review from jeremyevans June 23, 2025 13:36
Copy link
Copy Markdown
Contributor

@jeremyevans jeremyevans left a comment

Choose a reason for hiding this comment

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

Thank you for finding and fixing this.

Comment on lines +888 to +889
if (RTEST(rb_yield_values(2, item1, item2)) &&
RTEST(rb_yield_values(2, item2, item1))) {
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 is probably vulnerable to the same type of bug as https://bugs.ruby-lang.org/issues/21306, since the block could get access to the items array and shrink it while you are iterating.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

items is a snapshot of set_i_to_a(set)
Since union-find uses index, and items is used in the latter part of this function, item needs to be unmodified.

To avoid items and other internal arrays to be modified through ObjectSpace, I changed these in 99c5bf4

  • Freeze items rb_ary_freeze(items) before using it
  • Use ALLOCV_N instead of ruby array that stores index.

…vide

Internal arrays can be modified from yielded block through ObjectSpace.
Freeze readonly array, use ALLOCV_N instead of mutable array.
Copy link
Copy Markdown
Contributor

@jeremyevans jeremyevans left a comment

Choose a reason for hiding this comment

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

Awesome! Thank you again for fixing this.

@tompng tompng merged commit 67346a7 into ruby:master Jun 23, 2025
87 of 89 checks passed
@tompng tompng deleted the set_divide_unionfind branch June 23, 2025 17:56
headius added a commit to headius/jruby that referenced this pull request Nov 17, 2025
Based on code from CRuby by Tomoya Ishida:

ruby/ruby#13680
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