compsci 0.0.3.1 → 0.1.0.1
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 +4 -4
- data/README.md +63 -14
- data/VERSION +1 -1
- data/compsci.gemspec +5 -22
- data/examples/binary_tree.rb +11 -6
- data/examples/complete_tree.rb +47 -0
- data/examples/heap.rb +19 -7
- data/examples/tree.rb +41 -0
- data/lib/compsci.rb +1 -2
- data/lib/compsci/complete_tree.rb +109 -0
- data/lib/compsci/fibonacci.rb +31 -30
- data/lib/compsci/fit.rb +135 -135
- data/lib/compsci/heap.rb +14 -108
- data/lib/compsci/names.rb +132 -0
- data/lib/compsci/node.rb +67 -0
- data/lib/compsci/timer.rb +30 -29
- data/lib/compsci/tree.rb +48 -138
- data/test/bench/tree.rb +2 -2
- data/test/complete_tree.rb +131 -0
- data/test/heap.rb +121 -34
- data/test/names.rb +96 -0
- data/test/node.rb +89 -0
- data/test/tree.rb +49 -237
- metadata +24 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3df760b020e177135c9d73e20f455635ca82250c
|
4
|
+
data.tar.gz: '0850e990c79b14fa39533e0990d707cb3f1fe7cc'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8997da4e5f98d35b1250d8feab97d9e46d7a193aec42a89b74e720bfff50608624b054e7e3bb85709230d2a038557919c3a2ce0d6f9f4dc22ddf88e8357d6c8c
|
7
|
+
data.tar.gz: 90069e7be2f383c80e0edd09c41ca566ba8481b3659c4aca90c7b23000027c3eaa1139cf980ba74737ca9ba4d20e99bd0591623be7b5872d9d7cb06ac99ce2ad
|
data/README.md
CHANGED
@@ -1,28 +1,70 @@
|
|
1
1
|
[](https://travis-ci.org/rickhull/compsci)
|
2
2
|
|
3
|
-
#
|
3
|
+
# CompSci
|
4
4
|
|
5
5
|
Provided are some toy implementations for some basic computer science problems.
|
6
6
|
|
7
|
-
## [`
|
8
|
-
|
9
|
-
* `Node`
|
10
|
-
|
11
|
-
|
12
|
-
* `
|
13
|
-
|
14
|
-
|
7
|
+
## [`Node`](lib/compsci/node.rb) data structure
|
8
|
+
|
9
|
+
* `Node`
|
10
|
+
- `@value`
|
11
|
+
- `@children`
|
12
|
+
* `ChildNode` adds
|
13
|
+
- `@parent`
|
14
|
+
- `#gen`
|
15
|
+
- `#siblings`
|
16
|
+
|
17
|
+
## [`Tree`](lib/compsci/tree.rb) data structures
|
18
|
+
|
19
|
+
* `Tree`
|
20
|
+
- `@root`
|
21
|
+
- `#df_search`
|
22
|
+
- `#bf_search`
|
23
|
+
* `NaryTree`
|
24
|
+
- `@child_slots` (number of children per node)
|
25
|
+
- `#open_parent` O(n) to find a node with open child slots
|
26
|
+
- `#push` append `#open_parent.children`
|
27
|
+
- `#display` if initialized with `ChildNode`
|
28
|
+
* `BinaryTree`
|
29
|
+
- `NaryTree.new(child_slots: 2)`
|
30
|
+
- `#display` for `Node` and `ChildNode`
|
31
|
+
* `TernaryTree`
|
32
|
+
- `NaryTree.new(child_slots: 3)`
|
33
|
+
* `QuaternaryTree`
|
34
|
+
- `NaryTree.new(child_slots: 4)`
|
35
|
+
|
36
|
+
## [`CompleteNaryTree`](lib/compsci/complete_tree.rb) data structure
|
37
|
+
|
38
|
+
Efficient Array implementation of a complete tree.
|
39
|
+
|
40
|
+
* `CompleteNaryTree`
|
41
|
+
- `CompleteNaryTree.parent_idx`
|
42
|
+
- `CompleteNaryTree.children_idx`
|
43
|
+
- `CompleteNaryTree.gen`
|
44
|
+
- `@array`
|
45
|
+
- `@child_slots`
|
46
|
+
- `#push`
|
47
|
+
- `#pop`
|
48
|
+
- `#size`
|
49
|
+
- `#last_idx`
|
50
|
+
- `#display` (alias `#to_s`)
|
51
|
+
* `CompleteBinaryTree`
|
52
|
+
- `CompleteNaryTree.new(child_slots: 2)`
|
53
|
+
* `CompleteTernaryTree`
|
54
|
+
- `CompleteNaryTree.new(child_slots: 3)`
|
55
|
+
* `CompleteQuaternaryTree`
|
56
|
+
- `CompleteNaryTree.new(child_slots: 4)`
|
15
57
|
|
16
58
|
## [`Heap`](lib/compsci/heap.rb) data structure
|
17
59
|
|
18
|
-
|
19
|
-
|
60
|
+
`CompleteNaryTree` implementation. Both minheaps and maxheaps are supported.
|
61
|
+
Any number of children may be provided via `child_slots`. The primary
|
62
|
+
operations are `Heap#push` and `Heap#pop`. See the
|
20
63
|
[heap example](examples/heap.rb) which can be executed (among other examples)
|
21
64
|
via `rake examples`.
|
22
65
|
|
23
|
-
|
24
|
-
|
25
|
-
second, constant up past 1M pushes.
|
66
|
+
My basic Vagrant VM gets around 500k pushes per second, constant up past 1M
|
67
|
+
pushes.
|
26
68
|
|
27
69
|
## [`Fibonacci`](lib/compsci/fibonacci.rb) functions
|
28
70
|
|
@@ -93,3 +135,10 @@ cumulative: 0.828
|
|
93
135
|
* `Fit.linear` - fits `y = a + bx`; returns a, b, r^2
|
94
136
|
* `Fit.exponential` fits `y = ae^(bx)`; returns a, b, r^2
|
95
137
|
* `Fit.power` fits `y = ax^b`; returns a, b, r^2
|
138
|
+
|
139
|
+
## [`Names`](lib/compsci/names.rb) functions
|
140
|
+
|
141
|
+
* `Names.assign`
|
142
|
+
* `Names::Greek.upper`
|
143
|
+
* `Names::Greek.lower`
|
144
|
+
* `Names::Greek.symbol`
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.1.0.1
|
data/compsci.gemspec
CHANGED
@@ -10,28 +10,11 @@ Gem::Specification.new do |s|
|
|
10
10
|
|
11
11
|
s.version = File.read(File.join(__dir__, 'VERSION')).chomp
|
12
12
|
|
13
|
-
s.files = %w[
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
Rakefile
|
18
|
-
lib/compsci.rb
|
19
|
-
lib/compsci/fibonacci.rb
|
20
|
-
lib/compsci/fit.rb
|
21
|
-
lib/compsci/heap.rb
|
22
|
-
lib/compsci/timer.rb
|
23
|
-
lib/compsci/tree.rb
|
24
|
-
examples/binary_tree.rb
|
25
|
-
examples/heap.rb
|
26
|
-
test/fibonacci.rb
|
27
|
-
test/fit.rb
|
28
|
-
test/heap.rb
|
29
|
-
test/timer.rb
|
30
|
-
test/tree.rb
|
31
|
-
test/bench/fibonacci.rb
|
32
|
-
test/bench/heap.rb
|
33
|
-
test/bench/tree.rb
|
34
|
-
]
|
13
|
+
s.files = %w[compsci.gemspec VERSION README.md Rakefile]
|
14
|
+
s.files += Dir['lib/**/*.rb']
|
15
|
+
s.files += Dir['test/**/*.rb']
|
16
|
+
s.files += Dir['examples/**/*.rb']
|
35
17
|
|
36
18
|
s.add_development_dependency "minitest", "~> 5.0"
|
19
|
+
s.add_development_dependency "rake", "~> 0"
|
37
20
|
end
|
data/examples/binary_tree.rb
CHANGED
@@ -13,7 +13,7 @@ EOF
|
|
13
13
|
count = 0
|
14
14
|
start = Timer.now
|
15
15
|
start_1k = Timer.now
|
16
|
-
tree =
|
16
|
+
tree = NaryTree.new(ChildNode, rand(99), child_slots: 2)
|
17
17
|
|
18
18
|
loop {
|
19
19
|
count += 1
|
@@ -47,20 +47,25 @@ puts <<EOF
|
|
47
47
|
|
48
48
|
EOF
|
49
49
|
|
50
|
-
vals =
|
51
|
-
30.times { vals << rand(99) }
|
50
|
+
vals = Array.new(30) { rand 99 }
|
52
51
|
p vals
|
53
52
|
|
54
|
-
tree =
|
53
|
+
tree = NaryTree.new(ChildNode, vals.shift, child_slots: 2)
|
55
54
|
tree.push vals.shift until vals.empty?
|
56
|
-
|
57
55
|
puts tree
|
58
56
|
|
57
|
+
p tree
|
58
|
+
puts
|
59
|
+
|
59
60
|
tree.df_search { |n|
|
60
61
|
puts "visited #{n}"
|
61
62
|
false # or n.value > 90
|
62
63
|
}
|
63
64
|
puts
|
64
65
|
|
65
|
-
|
66
|
+
vals = Array.new(30) { rand 99 }
|
67
|
+
puts "push: #{vals.inspect}"
|
68
|
+
|
69
|
+
tree.push vals.shift until vals.empty?
|
70
|
+
puts tree
|
66
71
|
puts
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'compsci/complete_tree'
|
2
|
+
require 'compsci/timer'
|
3
|
+
|
4
|
+
include CompSci
|
5
|
+
|
6
|
+
puts <<EOF
|
7
|
+
#
|
8
|
+
# Print CompleteBinary-, Ternary-, and QuaternaryTree
|
9
|
+
#
|
10
|
+
|
11
|
+
EOF
|
12
|
+
|
13
|
+
vals = Array.new(30) { rand 99 }
|
14
|
+
|
15
|
+
[CompleteBinaryTree,
|
16
|
+
CompleteTernaryTree,
|
17
|
+
CompleteQuaternaryTree,
|
18
|
+
].each { |tree_class|
|
19
|
+
# start with the same vals for each class
|
20
|
+
my_vals = vals.dup
|
21
|
+
p my_vals
|
22
|
+
tree = tree_class.new
|
23
|
+
tree.push my_vals.shift until my_vals.empty?
|
24
|
+
p tree
|
25
|
+
puts tree.display(width: 80)
|
26
|
+
puts
|
27
|
+
puts
|
28
|
+
puts
|
29
|
+
|
30
|
+
|
31
|
+
# TODO: add CompleteTree#df_search
|
32
|
+
# tree.df_search { |n|
|
33
|
+
# puts "visited #{n}"
|
34
|
+
# false # or n.value > 90
|
35
|
+
# }
|
36
|
+
# puts
|
37
|
+
|
38
|
+
# push different vals for each class
|
39
|
+
my_vals = Array.new(30) { rand 99 }
|
40
|
+
puts "push: #{my_vals.inspect}"
|
41
|
+
|
42
|
+
tree.push my_vals.shift until my_vals.empty?
|
43
|
+
puts tree.display(width: 80)
|
44
|
+
puts
|
45
|
+
puts
|
46
|
+
puts
|
47
|
+
}
|
data/examples/heap.rb
CHANGED
@@ -13,7 +13,7 @@ EOF
|
|
13
13
|
count = 0
|
14
14
|
start = Timer.now
|
15
15
|
start_100k = Timer.now
|
16
|
-
h =
|
16
|
+
h = Heap.new
|
17
17
|
|
18
18
|
loop {
|
19
19
|
count += 1
|
@@ -47,24 +47,36 @@ puts
|
|
47
47
|
|
48
48
|
puts <<EOF
|
49
49
|
#
|
50
|
-
#
|
50
|
+
# display the results of TernaryHeap push and pop
|
51
51
|
#
|
52
52
|
|
53
53
|
EOF
|
54
54
|
|
55
|
-
h = Heap.new
|
55
|
+
h = Heap.new(child_slots: 3)
|
56
56
|
|
57
|
-
puts "push: %s" % Array.new(
|
58
|
-
puts "
|
57
|
+
puts "push: %s" % Array.new(30) { rand(99).tap { |i| h.push i } }.join(' ')
|
58
|
+
puts "array: #{h.array.inspect}"
|
59
59
|
puts "heap: #{h.heap?}"
|
60
|
+
puts h
|
61
|
+
puts
|
60
62
|
puts
|
61
63
|
|
62
64
|
puts "pop: %i" % h.pop
|
63
|
-
puts "
|
65
|
+
puts "array: #{h.array.inspect}"
|
64
66
|
puts "heap: #{h.heap?}"
|
67
|
+
puts h
|
68
|
+
puts
|
65
69
|
puts
|
66
70
|
|
67
71
|
puts "pop: %s" % Array.new(9) { h.pop }.join(' ')
|
68
|
-
puts "
|
72
|
+
puts "array: #{h.array.inspect}"
|
73
|
+
puts "heap: #{h.heap?}"
|
74
|
+
puts h
|
75
|
+
puts
|
76
|
+
puts
|
77
|
+
|
78
|
+
puts "push: %s" % Array.new(30) { rand(99).tap { |i| h.push i } }.join(' ')
|
79
|
+
puts "array: #{h.array.inspect}"
|
69
80
|
puts "heap: #{h.heap?}"
|
81
|
+
puts h
|
70
82
|
puts
|
data/examples/tree.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'compsci/tree'
|
2
|
+
require 'compsci/timer'
|
3
|
+
|
4
|
+
include CompSci
|
5
|
+
|
6
|
+
puts <<EOF
|
7
|
+
#
|
8
|
+
# Try out Binary-, Ternary-, and QuaternaryTree
|
9
|
+
#
|
10
|
+
|
11
|
+
EOF
|
12
|
+
|
13
|
+
vals = Array.new(30) { rand 99 }
|
14
|
+
|
15
|
+
[BinaryTree, TernaryTree, QuaternaryTree].each { |tree_class|
|
16
|
+
# start with the same vals for each class
|
17
|
+
my_vals = vals.dup
|
18
|
+
p my_vals
|
19
|
+
tree = tree_class.new(ChildNode, my_vals.shift)
|
20
|
+
tree.push my_vals.shift until my_vals.empty?
|
21
|
+
p tree
|
22
|
+
puts tree.display(width: 80)
|
23
|
+
puts
|
24
|
+
visited = []
|
25
|
+
tree.df_search { |n|
|
26
|
+
visited << n
|
27
|
+
false # or n.value > 90
|
28
|
+
}
|
29
|
+
puts "df_search visited: %s" % visited.join(' ')
|
30
|
+
puts
|
31
|
+
puts
|
32
|
+
|
33
|
+
# push different vals for each class
|
34
|
+
my_vals = Array.new(30) { rand 99 }
|
35
|
+
puts "push: #{my_vals.inspect}"
|
36
|
+
tree.push my_vals.shift until my_vals.empty?
|
37
|
+
puts
|
38
|
+
puts tree.display(width: 80)
|
39
|
+
puts
|
40
|
+
puts
|
41
|
+
}
|
data/lib/compsci.rb
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
module CompSci
|
2
|
-
end
|
1
|
+
module CompSci; end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module CompSci
|
2
|
+
# A CompleteNaryTree can very efficiently use an array for storage using
|
3
|
+
# simple arithmetic to determine parent child relationships.
|
4
|
+
#
|
5
|
+
# It is kept separate from compsci/tree as it does not require compsci/node
|
6
|
+
#
|
7
|
+
class CompleteNaryTree
|
8
|
+
# integer math maps several children to one parent
|
9
|
+
def self.parent_idx(idx, n)
|
10
|
+
(idx-1) / n
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.children_idx(idx, n)
|
14
|
+
Array.new(n) { |i| n*idx + i + 1 }
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.gen(idx, n)
|
18
|
+
count = 0
|
19
|
+
loop {
|
20
|
+
pidx = self.parent_idx(idx, n)
|
21
|
+
break if pidx < 0
|
22
|
+
count += 1
|
23
|
+
idx = pidx
|
24
|
+
}
|
25
|
+
count
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :array
|
29
|
+
|
30
|
+
def initialize(array: [], child_slots: 2)
|
31
|
+
@array = array
|
32
|
+
@child_slots = child_slots
|
33
|
+
end
|
34
|
+
|
35
|
+
def push val
|
36
|
+
@array.push val
|
37
|
+
end
|
38
|
+
|
39
|
+
def pop
|
40
|
+
@array.pop
|
41
|
+
end
|
42
|
+
|
43
|
+
def size
|
44
|
+
@array.size
|
45
|
+
end
|
46
|
+
|
47
|
+
def last_idx
|
48
|
+
@array.size - 1 unless @array.empty?
|
49
|
+
end
|
50
|
+
|
51
|
+
# or, ya know, just iterate @array
|
52
|
+
def bf_search(&blk)
|
53
|
+
destinations = [0]
|
54
|
+
while !destinations.empty?
|
55
|
+
idx = destinations.shift
|
56
|
+
return idx if yield @array[idx]
|
57
|
+
|
58
|
+
# idx has a val and the block is false
|
59
|
+
# add existent children to destinations
|
60
|
+
self.class.children_idx(idx, @child_slots).each { |cidx|
|
61
|
+
destinations.push(cidx) if cidx < @array.size
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def df_search(&blk)
|
67
|
+
puts "not yet"
|
68
|
+
end
|
69
|
+
|
70
|
+
def display(width: 80)
|
71
|
+
str = ''
|
72
|
+
old_level = 0
|
73
|
+
@array.each_with_index { |val, i|
|
74
|
+
val = val.to_s
|
75
|
+
level = self.class.gen(i, @child_slots)
|
76
|
+
if old_level != level
|
77
|
+
str += "\n"
|
78
|
+
old_level = level
|
79
|
+
end
|
80
|
+
|
81
|
+
# center in block_width
|
82
|
+
slots = @child_slots**level
|
83
|
+
block_width = width / slots
|
84
|
+
space = [(block_width + val.size) / 2, val.size + 1].max
|
85
|
+
str += val.ljust(space, ' ').rjust(block_width, ' ')
|
86
|
+
}
|
87
|
+
str
|
88
|
+
end
|
89
|
+
alias_method :to_s, :display
|
90
|
+
end
|
91
|
+
|
92
|
+
class CompleteBinaryTree < CompleteNaryTree
|
93
|
+
def initialize(array: [])
|
94
|
+
super(array: array, child_slots: 2)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class CompleteTernaryTree < CompleteNaryTree
|
99
|
+
def initialize(array: [])
|
100
|
+
super(array: array, child_slots: 3)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class CompleteQuaternaryTree < CompleteNaryTree
|
105
|
+
def initialize(array: [])
|
106
|
+
super(array: array, child_slots: 4)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/compsci/fibonacci.rb
CHANGED
@@ -1,39 +1,40 @@
|
|
1
|
-
require 'compsci'
|
2
1
|
autoload :Matrix, 'matrix'
|
3
2
|
|
4
|
-
module CompSci
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module CompSci
|
4
|
+
class Fibonacci
|
5
|
+
def self.classic(n)
|
6
|
+
n < 2 ? n : classic(n-1) + classic(n-2)
|
7
|
+
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
def self.cache_recursive(n, cache = {})
|
10
|
+
return n if n < 2
|
11
|
+
cache[n] ||= cache_recursive(n-1, cache) + cache_recursive(n-2, cache)
|
12
|
+
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
def self.cache_iterative(n)
|
15
|
+
cache = [0, 1]
|
16
|
+
2.upto(n) { |i| cache[i] = cache[i-1] + cache[i-2] }
|
17
|
+
cache[n]
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
# traditional
|
21
|
+
def self.dynamic(n)
|
22
|
+
a, b = 0, 1
|
23
|
+
n.times { a, b = b, a+b }
|
24
|
+
a
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
# fails for n == 0
|
28
|
+
def self.dynamic_fast(n)
|
29
|
+
a, b = 0, 1
|
30
|
+
(n-1).times { a, b = b, a+b }
|
31
|
+
b
|
32
|
+
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
# https://gist.github.com/havenwood/02cf291b809327d96a3f
|
35
|
+
# slower than dynamic until around n == 500
|
36
|
+
def self.matrix(n)
|
37
|
+
(Matrix[[0, 1], [1, 1]] ** n.pred)[1, 1].to_i
|
38
|
+
end
|
38
39
|
end
|
39
40
|
end
|