binary_heap 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: faaa2815340f3e63149991ade157103211160d2fa957e72c4ab2a19025adb10a
4
+ data.tar.gz: 97c61d6a57e6fdb3d217c300568951193eeec8741139c1dc92dcfc902097696d
5
+ SHA512:
6
+ metadata.gz: 3d492d350927815d34b1c5403c12488986bdf44746b0adaf73fc1e7fc28fdaa8ebf8727181b7fd9cb747eecf220b2befa89f8eac82661caf2d06f2db9c2ca46a
7
+ data.tar.gz: 93d1571f07f19b3ae36fa48232f673b3e6cd92c64836d80808aa26551f7a16cd8344bd8fee20df744602fa09ca6f7dd902bbfb932426b3b6a2972143a050e34a
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2025-03-06
4
+
5
+ - Initial release
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # BinaryHeap
2
+
3
+ BinaryHeap is a pure ruby implementation of a binary heap, that can be used as a priority queue.
4
+
5
+ ## Installation
6
+
7
+ Install the gem and add to the application's Gemfile by executing:
8
+
9
+ $ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
10
+
11
+ If bundler is not being used to manage dependencies, install the gem by executing:
12
+
13
+ $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
14
+
15
+ ## Usage
16
+
17
+ ````ruby
18
+
19
+ require 'binary_heap'
20
+ q = BinaryHeap::Base.new([4,5,7])
21
+ q.push(2)
22
+ q.min # => 2
23
+ q.pop # => 2
24
+ q.min # => 4
25
+
26
+ ````
27
+
28
+ ## Benchmarks
29
+
30
+ On modern Ruby (>= 3.2) with YJIT enabled it is about as fast as priority_queue_cxx
31
+ which is a Heap Implementation written as a C++-Extension to Ruby. In any case it compares
32
+ favorably against other heap implementations written in pure Ruby.
33
+
34
+ Library | user |system | total | real
35
+ --------------------|------------|-----------|----------|------------
36
+ binary_heap | 3.089522 | 0.005000 | 3.094522 |( 3.094816)
37
+ priority_queue_cxx | 0.726967 | 0.000000 | 0.726967 |( 0.726975)
38
+ lazy-priority-queue | 10.646469 | 0.032996 |10.679465 |( 10.681288)
39
+
40
+ With YJIT enabled:
41
+
42
+
43
+ Library | user | system | total| real
44
+ --------------------|----------|----------|---------|----------
45
+ binary_heap | 0.697922 | 0.003981| 0.701903|( 0.702160)
46
+ priority_queue_cxx | 0.707953 | 0.001005| 0.708958|( 0.708970)
47
+ lazy-priority-queue | 5.456912 | 0.027023| 5.483935|( 5.484204)
48
+
49
+
50
+
51
+ ## Development
52
+
53
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
54
+
55
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
56
+
57
+
58
+
59
+ ## Contributing
60
+
61
+ Bug reports and pull requests are welcome on GitHub at https://github.com/skr0504/binary_heap.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+
7
+ Minitest::TestTask.create
8
+
9
+ task default: :test
10
+
11
+ desc "Run benchmarks"
12
+ task :benchmark do
13
+ Dir.glob('./benchmark/bench_*.rb') { |file| require file }
14
+ end
data/Steepfile ADDED
@@ -0,0 +1,32 @@
1
+ # D = Steep::Diagnostic
2
+ #
3
+ target :lib do
4
+ signature "sig"
5
+ # ignore_signature "sig/test"
6
+ #
7
+ check "lib" # Directory name
8
+ # check "path/to/source.rb" # File name
9
+ # check "app/models/**/*.rb" # Glob
10
+ # # ignore "lib/templates/*.rb"
11
+ #
12
+ library "pathname" # Standard libraries
13
+ # # library "strong_json" # Gems
14
+ #
15
+ # # configure_code_diagnostics(D::Ruby.default) # `default` diagnostics setting (applies by default)
16
+ #configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
17
+ # # configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
18
+ # # configure_code_diagnostics(D::Ruby.silent) # `silent` diagnostics setting
19
+ # # configure_code_diagnostics do |hash| # You can setup everything yourself
20
+ # # hash[D::Ruby::NoMethod] = :information
21
+ # # end
22
+ end
23
+
24
+ # target :test do
25
+ # unreferenced! # Skip type checking the `lib` code when types in `test` target is changed
26
+ # signature "sig/test" # Put RBS files for tests under `sig/test`
27
+ # check "test" # Type check Ruby scripts under `test`
28
+ #
29
+ # configure_code_diagnostics(D::Ruby.lenient) # Weak type checking for test code
30
+ #
31
+ # # library "pathname" # Standard libraries
32
+ # end
@@ -0,0 +1,25 @@
1
+ require_relative 'bench_helper'
2
+
3
+
4
+ puts "Comparison with priority_queue_cxx"
5
+
6
+ Benchmark.bmbm do |b|
7
+
8
+ b.report("binary_heap") do
9
+ pq = BinaryHeap::Base.new
10
+ RUNS.times { pq.push(rand(RUNS)) }
11
+ RUNS.times { pq.pop }
12
+ end
13
+
14
+ b.report("priority_queue_cxx") do
15
+ pq = FastContainers::PriorityQueue.new(:min)
16
+ RUNS.times { |i| pq.push(i, rand(RUNS)) }
17
+ RUNS.times { pq.pop }
18
+ end
19
+
20
+ b.report("lazy-priority-queue") do
21
+ pq = MinPriorityQueue.new
22
+ RUNS.times { |i| pq.push(i, rand(RUNS)) }
23
+ RUNS.times { pq.pop }
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ require 'benchmark'
2
+ require 'bundler/setup'
3
+ require 'binary_heap'
4
+ require 'fc'
5
+ require 'lazy_priority_queue'
6
+
7
+ RUNS = 400_000
@@ -0,0 +1,102 @@
1
+ module BinaryHeap
2
+ class Base
3
+
4
+ include Enumerable
5
+
6
+ def initialize(ary=[])
7
+ if ary.is_a? Array
8
+ @heap = ary.dup
9
+ heapify
10
+ else
11
+ raise ArgumentError
12
+ end
13
+ end
14
+
15
+ def length
16
+ @heap.length
17
+ end
18
+
19
+ def each
20
+ @heap.each
21
+ end
22
+
23
+ def <<(el)
24
+ @heap << el
25
+ rebalance_up(@heap.size - 1)
26
+ self
27
+ end
28
+
29
+ def push(*els)
30
+ if els.length < length
31
+ els.each do |el|
32
+ self << el
33
+ end
34
+ else
35
+ @heap.push(*els)
36
+ heapify
37
+ end
38
+ self
39
+ end
40
+
41
+ def pop
42
+ @heap[0], @heap[-1] = @heap[-1], @heap[0]
43
+ res = @heap.pop
44
+ if @heap.size.positive?
45
+ rebalance_down(0)
46
+ end
47
+ res
48
+ end
49
+
50
+ def min
51
+ @heap[0]
52
+ end
53
+
54
+ def replace_min(el)
55
+ @heap[0] = el
56
+ rebalance_down(0)
57
+ end
58
+
59
+ def clear
60
+ @heap.clear
61
+ self
62
+ end
63
+
64
+
65
+ private
66
+
67
+ def heapify
68
+ ((@heap.size >> 1)-1).downto(0).each do |n| # all internal nodes
69
+ rebalance_down(n)
70
+ end
71
+ end
72
+
73
+ def rebalance_up(i)
74
+ while i.positive?
75
+ parent_i = i >> 1
76
+ if @heap[i] < @heap[parent_i]
77
+ @heap[i], @heap[parent_i] = @heap[parent_i], @heap[i]
78
+ i = parent_i
79
+ else
80
+ break
81
+ end
82
+ end
83
+ end
84
+
85
+ def rebalance_down(i)
86
+ while (i << 1).succ < @heap.size
87
+ left_i = (i << 1).succ
88
+ right_i = (i.succ) << 1
89
+
90
+ if @heap[right_i] && @heap[right_i] <= @heap[left_i] && @heap[right_i] < @heap[i]
91
+ @heap[i], @heap[right_i] = @heap[right_i], @heap[i]
92
+ i = right_i
93
+ elsif @heap[left_i] < @heap[i]
94
+ @heap[i], @heap[left_i] = @heap[left_i], @heap[i]
95
+ i = left_i
96
+ else
97
+ break
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BinaryHeap
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+
5
+ require_relative "binary_heap/version"
6
+ require_relative "binary_heap/base"
7
+
8
+
9
+ module BinaryHeap
10
+ class Error < StandardError; end
11
+ # Your code goes here...
12
+
13
+
14
+ end
@@ -0,0 +1,42 @@
1
+ module BinaryHeap
2
+
3
+ VERSION: String
4
+
5
+ class Error
6
+ end
7
+
8
+ interface _Comparable
9
+ def <: (_Comparable) -> bool
10
+ def <=: (_Comparable) -> bool
11
+ end
12
+
13
+ class Base[unchecked out Elem < _Comparable]
14
+ @heap: Array[Elem]
15
+
16
+ def initialize: (?Array[Elem] ary) -> void
17
+
18
+ def length: () -> Integer
19
+
20
+ def each: () -> Enumerator[Elem]
21
+
22
+ def <<: (Elem el) -> self
23
+
24
+ def push: (*Elem els) -> self
25
+
26
+ def pop: () -> Elem?
27
+
28
+ def min: () -> Elem
29
+
30
+ def replace_min: (Elem el) -> self
31
+
32
+ def clear: () -> self
33
+
34
+ private
35
+
36
+ def heapify: () -> untyped
37
+
38
+ def rebalance_up: (untyped i) -> untyped
39
+
40
+ def rebalance_down: (untyped i) -> untyped
41
+ end
42
+ end
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: binary_heap
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Sebastian Krause
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 2025-03-06 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: A binary heap can be used as a priority queue.
13
+ email:
14
+ - skrause216@posteo.de
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - CHANGELOG.md
20
+ - README.md
21
+ - Rakefile
22
+ - Steepfile
23
+ - benchmark/bench_binary_heap.rb
24
+ - benchmark/bench_helper.rb
25
+ - lib/binary_heap.rb
26
+ - lib/binary_heap/base.rb
27
+ - lib/binary_heap/version.rb
28
+ - sig/binary_heap.rbs
29
+ licenses: []
30
+ metadata: {}
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: 3.0.0
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubygems_version: 3.6.0.dev
46
+ specification_version: 4
47
+ summary: A simple implementation of a binary heap in Ruby.
48
+ test_files: []