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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cc2eff6c2450cd9807ab097dd86eebb37420a7b7
4
- data.tar.gz: 470311b19fc70c7ab1a5d405c3aba939f57464e7
3
+ metadata.gz: 3df760b020e177135c9d73e20f455635ca82250c
4
+ data.tar.gz: '0850e990c79b14fa39533e0990d707cb3f1fe7cc'
5
5
  SHA512:
6
- metadata.gz: 37214ed2f4c2fd3f8837f1908fc78b07be79e624ba7f387f40c68aec49f93b1b866589fab0b863e02e6add2d6dcbfe4508c9ae1bdf1864269427dce25fdb15b4
7
- data.tar.gz: 52dc0115e1f44a769da4dc3f1e721624e3963cef0111d098af6ad6beb72728b120905aaaeb45161950c79455810bbf8caab5426fb22aee716f5e7e92f84244a4
6
+ metadata.gz: 8997da4e5f98d35b1250d8feab97d9e46d7a193aec42a89b74e720bfff50608624b054e7e3bb85709230d2a038557919c3a2ce0d6f9f4dc22ddf88e8357d6c8c
7
+ data.tar.gz: 90069e7be2f383c80e0edd09c41ca566ba8481b3659c4aca90c7b23000027c3eaa1139cf980ba74737ca9ba4d20e99bd0591623be7b5872d9d7cb06ac99ce2ad
data/README.md CHANGED
@@ -1,28 +1,70 @@
1
1
  [![Build Status](https://travis-ci.org/rickhull/compsci.svg?branch=master)](https://travis-ci.org/rickhull/compsci)
2
2
 
3
- # Introduction
3
+ # CompSci
4
4
 
5
5
  Provided are some toy implementations for some basic computer science problems.
6
6
 
7
- ## [`Tree`](/lib/compsci/tree.rb) data structures
8
-
9
- * `Node` - references children nodes only
10
- * `ChildNode` - references parent and children nodes
11
- * `Tree` - tracks the `root` node; provides `df_search` and `bf_search`
12
- * `NaryTree` - enforces number of children per node via `child_slots`
13
- * `BinaryTree` - `NaryTree` with `child_slots` == 2; provides `to_s`
14
- * `CompleteBinaryTree` - efficient Array implementation
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
- Implemented with a `CompleteBinaryTree` for storage using simple arithmetic to
19
- determine array indices for parent and children. See the
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
- Both minheaps and maxheaps are supported. The primary operations are
24
- `Heap#push` and `Heap#pop`. My basic Vagrant VM gets around 500k pushes per
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.3.1
1
+ 0.1.0.1
@@ -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
- compsci.gemspec
15
- VERSION
16
- README.md
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
@@ -13,7 +13,7 @@ EOF
13
13
  count = 0
14
14
  start = Timer.now
15
15
  start_1k = Timer.now
16
- tree = BinaryTree.new(ChildNode, rand(99))
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 = BinaryTree.new(ChildNode, vals.shift)
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
- p tree
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
+ }
@@ -13,7 +13,7 @@ EOF
13
13
  count = 0
14
14
  start = Timer.now
15
15
  start_100k = Timer.now
16
- h = BinaryHeap.new
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
- # 99 inserts; display the internal array
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(99) { rand(99).tap { |i| h.push i } }.join(' ')
58
- puts "heap store: #{h.store.inspect}"
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 "heap store: #{h.store.inspect}"
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 "heap store: #{h.store.inspect}"
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
@@ -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
+ }
@@ -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
@@ -1,39 +1,40 @@
1
- require 'compsci'
2
1
  autoload :Matrix, 'matrix'
3
2
 
4
- module CompSci::Fibonacci
5
- def self.classic(n)
6
- n < 2 ? n : classic(n-1) + classic(n-2)
7
- end
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
- 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
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
- 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
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
- # traditional
21
- def self.dynamic(n)
22
- a, b = 0, 1
23
- n.times { a, b = b, a+b }
24
- a
25
- end
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
- # 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
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
- # 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
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