Skip to content
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

Optimisation: Use heapify in MutableBinaryHeap #712

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/heaps/mutable_binary_heap.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Binary heap

include("arrays_as_heaps.jl")

struct MutableBinaryHeapNode{T}
value::T
handle::Int
Expand Down Expand Up @@ -131,10 +133,10 @@ end

function _make_mutable_binary_heap(ord::Ordering, ty::Type{T}, values) where T
# make a static binary index tree from a list of values

n = length(values)
nodes = Vector{MutableBinaryHeapNode{T}}(undef, n)
nodemap = Vector{Int}(undef, n)
values = heapify!(values, ord)

i::Int = 0
for v in values
Expand All @@ -143,9 +145,6 @@ function _make_mutable_binary_heap(ord::Ordering, ty::Type{T}, values) where T
@inbounds nodemap[i] = i
end

for i = 1 : n
_heap_bubble_up!(ord, nodes, nodemap, i)
end
return nodes, nodemap
end

Expand Down
15 changes: 12 additions & 3 deletions test/test_mutable_binheap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@ end

@testset "MutableBinheap" begin

vs = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]
vs2 = collect(enumerate(vs))
ordering = Base.Order.By(last)

@testset "construct heap" begin
vs = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]
vs2 = collect(enumerate(vs))
Comment on lines +58 to +59
Copy link
Contributor Author

@rushabh-v rushabh-v Dec 11, 2020

Choose a reason for hiding this comment

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

The new implementation was overwriting vs. So, the tests were failing because of updated vs (The value of vs was not as expected because it was updated during some other test). So, I updated it to use separate vs and vs2 for each test (the values are still the same).

Copy link
Member

Choose a reason for hiding this comment

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

It is not OK for MutableBinaryMinHeap(vs) to mutate vs.
We should add a copy to the constructor if that is the case.

(we can consider later adding a MutableBinaryMinHeap! or something that does do so. but lets not worry about it in this PR)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

list_values related tests (i.e., this one) started failing after adding copy in the constructor. the reason for that is because nodemap is not updated as I mentioned here. Those tests were not failing before because vs was being mutated.

I am trying to think if there is an efficient way to update nodemap after the heapify! call.

It might be that not being able to update nodemap efficiently (with O(n) implementation) is the reason they implemented it in O(nlogn) in the first place.


MutableBinaryHeap{Int, Base.ForwardOrdering}()
MutableBinaryHeap{Int, Base.ForwardOrdering}(vs)

Expand Down Expand Up @@ -88,6 +89,7 @@ end
end

@testset "make mutable binary minheap" begin
vs = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]
h = MutableBinaryMinHeap(vs)

@test length(h) == 10
Expand All @@ -99,17 +101,20 @@ end
end

@testset "make mutable binary maxheap" begin
vs = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]
h = MutableBinaryMaxHeap(vs)

@test length(h) == 10
@test !isempty(h)
@test first(h) == 16
@test isequal(list_values(h), vs)
@test isequal(heap_values(h), [16, 14, 10, 8, 7, 3, 9, 1, 4, 2])
@test isequal(heap_values(h), [16, 14, 10, 8, 7, 9, 3, 2, 4, 1])
Copy link
Contributor Author

@rushabh-v rushabh-v Dec 11, 2020

Choose a reason for hiding this comment

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

I think this is just due to the difference in the implementation of heapify and the previous method _heap_bubble_up. Otherwise, there is no problem IMO, so I updated the test. (Let me know if that's not the case)

Copy link
Member

Choose a reason for hiding this comment

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

Do these both follow the heap rule about being larger than children?
(I don't know how to read heaps when written in array form TBH)

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, they both are valid heaps. I also confirmed it using this function here.

Copy link
Member

Choose a reason for hiding this comment

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

seems fine then

@test sizehint!(h, 100) === h
end

@testset "make mutable binary custom ordering heap" begin
vs = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]
vs2 = collect(enumerate(vs))
h = MutableBinaryHeap(ordering, vs2)

@test length(h) == 10
Expand All @@ -121,6 +126,7 @@ end
end

@testset "hmin / push! / pop!" begin
vs = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]
Copy link
Member

Choose a reason for hiding this comment

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

this is a good change anyway. Testsets hould be indipendent.
Though maybe we move this down to after ss is declared?

hmin = MutableBinaryMinHeap{Int}()
@test length(hmin) == 0
@test isempty(hmin)
Expand Down Expand Up @@ -152,6 +158,7 @@ end
end

@testset "hmax / push! / pop!" begin
vs = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]
hmax = MutableBinaryMaxHeap{Int}()
@test length(hmax) == 0
@test isempty(hmax)
Expand Down Expand Up @@ -183,6 +190,8 @@ end
end

@testset "Custom ordering push! / pop!" begin
vs = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]
vs2 = collect(enumerate(vs))
heap = MutableBinaryHeap{Tuple{Int,Int}}(ordering)
@test length(heap) == 0
@test isempty(heap)
Expand Down